Coverage Report - net.wotonomy.foundation.internal.ValueConverter
 
Classes in this File Line Coverage Branch Coverage Complexity
ValueConverter
0% 
0% 
8
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2000 Michael Powers
 4  
 
 5  
 This library is free software; you can redistribute it and/or
 6  
 modify it under the terms of the GNU Lesser General Public
 7  
 License as published by the Free Software Foundation; either
 8  
 version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
 This library is distributed in the hope that it will be useful,
 11  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 Lesser General Public License for more details.
 14  
 
 15  
 You should have received a copy of the GNU Lesser General Public
 16  
 License along with this library; if not, see http://www.gnu.org
 17  
 */
 18  
 
 19  
 package net.wotonomy.foundation.internal;
 20  
 import java.lang.reflect.Array;
 21  
 import java.lang.reflect.Constructor;
 22  
 import java.util.Collection;
 23  
 import java.util.Iterator;
 24  
 import java.util.LinkedList;
 25  
 import java.util.Map;
 26  
 
 27  
 /**
 28  
 * A utility class to convert objects to a desired class.
 29  
 *
 30  
 * @author michael@mpowers.net
 31  
 * @author $Author: cgruber $
 32  
 * @version $Revision: 893 $
 33  
 */
 34  0
 public class ValueConverter
 35  
 {
 36  
     /**
 37  
     * Returns the specified object as converted to an instance of the 
 38  
     * specified class, or null if the conversion could not be performed.
 39  
     */
 40  
     static public Object convertObjectToClass( Object anObject, Class aClass )
 41  
     { 
 42  0
             if ( aClass == String.class )
 43  
         {
 44  0
             return getString( anObject );
 45  
         }
 46  0
             if ( aClass == Short.class )
 47  
         {
 48  0
             return getShort( anObject );
 49  
         }
 50  0
             if ( aClass == short.class )
 51  
         {
 52  0
             return getShort( anObject );
 53  
         }
 54  0
             if ( aClass == Integer.class )
 55  
         {
 56  0
             return getInteger( anObject );
 57  
         }
 58  0
             if ( aClass == int.class )
 59  
         {
 60  0
             return getInteger( anObject );
 61  
         }
 62  0
             if ( aClass == Long.class )
 63  
         {
 64  0
             return getLong( anObject );
 65  
         }
 66  0
             if ( aClass == long.class )
 67  
         {
 68  0
             return getLong( anObject );
 69  
         }
 70  0
             if ( aClass == Float.class )
 71  
         {
 72  0
             return getFloat( anObject );
 73  
         }
 74  0
             if ( aClass == float.class )
 75  
         {
 76  0
             return getFloat( anObject );
 77  
         }
 78  0
             if ( aClass == Double.class )
 79  
         {
 80  0
             return getDouble( anObject );
 81  
         }
 82  0
             if ( aClass == double.class )
 83  
         {
 84  0
             return getDouble( anObject );
 85  
         }
 86  0
             if ( aClass == java.util.Date.class )
 87  
         {
 88  0
             return getDate( anObject );
 89  
         }
 90  0
             if ( aClass == Boolean.class )
 91  
         {
 92  0
             return getBoolean( anObject );
 93  
         }
 94  0
             if ( aClass == boolean.class )
 95  
         {
 96  0
             return getBoolean( anObject );
 97  
         }
 98  0
             if ( aClass == Character.class )
 99  
         {
 100  0
             return getCharacter( anObject );
 101  
         }
 102  0
             if ( aClass == char.class )
 103  
         {
 104  0
             return getCharacter( anObject );
 105  
         }
 106  0
             if ( aClass == Byte.class )
 107  
         {
 108  0
             return getByte( anObject );
 109  
         }
 110  0
             if ( aClass == byte.class )
 111  
         {
 112  0
             return getByte( anObject );
 113  
         }
 114  0
             if ( Collection.class.isAssignableFrom( aClass ) )
 115  
         {
 116  0
             return getCollection( anObject, aClass );
 117  
         }
 118  0
             if ( aClass.isArray() )
 119  
         {
 120  0
             return getArray( anObject, aClass );
 121  
         }
 122  
 
 123  0
         return convert( anObject, aClass );
 124  
     }
 125  
     
 126  
     /**
 127  
     * Called by convertObjectToClass() when we need to 
 128  
     * convert to an unrecognized type.
 129  
     * This implementation scans the constructors of the 
 130  
     * specified class for the best fit to the object.
 131  
     * and returns a new instance with that constructor.
 132  
     * Subclasses can override to directly support specific
 133  
     * types.
 134  
     */
 135  
     static protected Object convert( Object anObject, Class aClass )
 136  
     {
 137  0
         Constructor[] ctors = aClass.getConstructors();
 138  
         
 139  
         Class[] types;
 140  0
         for ( int i = 0; i < ctors.length; i++ )
 141  
         {
 142  0
             types = ctors[i].getParameterTypes();
 143  0
             if ( types.length == 1 )
 144  
             {
 145  0
                 if ( types[0].equals( anObject.getClass() ) )
 146  
                 {
 147  
                     try
 148  
                     {
 149  0
                         return ctors[i].newInstance( new Object[] { anObject } );
 150  
                     }
 151  0
                     catch ( Exception exc )
 152  
                     {
 153  
                         // fall through
 154  
                     }
 155  
                 }
 156  
             }
 157  
         }
 158  
         
 159  0
         for ( int i = 0; i < ctors.length; i++ )
 160  
         {
 161  0
             types = ctors[i].getParameterTypes();
 162  0
             if ( types.length == 1 )
 163  
             {
 164  0
                 if ( anObject.getClass().isAssignableFrom( types[0] ) )
 165  
                 {
 166  
                     try
 167  
                     {
 168  0
                         return ctors[i].newInstance( new Object[] { anObject } );
 169  
                     }
 170  0
                     catch ( Exception exc )
 171  
                     {
 172  
                         // fall through
 173  
                     }
 174  
                 }
 175  
             }
 176  
         }
 177  
         
 178  0
         return null;
 179  
     }
 180  
         
 181  
     /**
 182  
     * Tries to convert all objects to either Numbers or objects
 183  
     * that will produce a parsable toString result.
 184  
     */
 185  
     static protected Object preprocess( Object anObject )
 186  
     {
 187  0
         if ( anObject instanceof Boolean )
 188  
         {
 189  0
             if ( ((Boolean)anObject).booleanValue() )
 190  
             {
 191  0
                 return new Double( 1.0 );
 192  
             }
 193  0
             return new Double( 0.0 );
 194  
         }
 195  
 
 196  0
         if ( anObject instanceof Character )
 197  
         {
 198  0
             return anObject.toString();
 199  
         }
 200  
 
 201  0
         return anObject;        
 202  
     }
 203  
     
 204  
     static public short getShortValue( Object anObject )
 205  
     {
 206  0
             Short result = getShort( anObject );
 207  0
         return ( result == null ) ? (short) 0 : result.shortValue();
 208  
     }
 209  
     static public Short getShort( Object anObject )
 210  
     {
 211  0
         if ( anObject == null ) return new Short( (short) 0 );
 212  0
         if ( "".equals( anObject ) ) return new Short( (short) 0 );
 213  0
                 if ( anObject instanceof Short ) return (Short) anObject;
 214  
 
 215  0
                 anObject = preprocess( anObject );
 216  
 
 217  0
         if ( anObject instanceof Number )
 218  
         {
 219  0
             return new Short( ((Number)anObject).shortValue() );
 220  
         }
 221  
 
 222  
                 try
 223  
         {
 224  0
             return Short.valueOf( anObject.toString() );
 225  
         }
 226  0
         catch ( Exception exc )
 227  
         {
 228  0
             return null;
 229  
         }
 230  
     }        
 231  
     
 232  
     static public int getIntValue( Object anObject )
 233  
     {
 234  0
             Integer result = getInteger( anObject );
 235  0
         return ( result == null ) ? 0 : result.intValue();
 236  
     }
 237  
     static public Integer getInteger( Object anObject )
 238  
     {
 239  0
         if ( anObject == null ) return new Integer( 0 );
 240  0
         if ( "".equals( anObject ) ) return new Integer( 0 );
 241  0
             if ( anObject instanceof Integer ) return (Integer) anObject;
 242  
     
 243  0
             anObject = preprocess( anObject );
 244  
 
 245  0
         if ( anObject instanceof Number )
 246  
         {
 247  0
             return new Integer( ((Number)anObject).intValue() );
 248  
         }
 249  
 
 250  
         try
 251  
         {
 252  0
             return Integer.valueOf( anObject.toString() );
 253  
         }
 254  0
         catch ( Exception exc )
 255  
         {
 256  0
             return null;
 257  
         }
 258  
     }        
 259  
     
 260  
     static public long getLongValue ( Object anObject )
 261  
     {
 262  0
             Long result = getLong( anObject );
 263  0
         return ( result == null ) ? (long) 0 : result.longValue();
 264  
     }
 265  
     static public Long getLong( Object anObject )
 266  
     {
 267  0
         if ( anObject == null ) return new Long( 0 );
 268  0
         if ( "".equals( anObject ) ) return new Long( 0 );
 269  0
             if ( anObject instanceof Long ) return (Long) anObject;
 270  
     
 271  0
             anObject = preprocess( anObject );
 272  
 
 273  0
         if ( anObject instanceof Number )
 274  
         {
 275  0
             return new Long( ((Number)anObject).longValue() );
 276  
         }
 277  
 
 278  
         try
 279  
         {
 280  0
             return Long.valueOf( anObject.toString() );
 281  
         }
 282  0
         catch ( Exception exc )
 283  
         {
 284  0
             return null;
 285  
         }
 286  
     }        
 287  
     
 288  
     static public double getDoubleValue ( Object anObject )
 289  
     {
 290  0
             Double result = getDouble( anObject );
 291  0
         return ( result == null ) ? 0.0f : result.doubleValue();
 292  
     }
 293  
     static public Double getDouble( Object anObject )
 294  
     {
 295  0
         if ( anObject == null ) return new Double( 0.0 );
 296  0
         if ( "".equals( anObject ) ) return new Double( 0 );
 297  0
             if ( anObject instanceof Double ) return (Double) anObject;
 298  
     
 299  0
             anObject = preprocess( anObject );
 300  
 
 301  0
         if ( anObject instanceof Number )
 302  
         {
 303  0
             return new Double( ((Number)anObject).doubleValue() );
 304  
         }
 305  
         
 306  
         try
 307  
         {
 308  0
             return Double.valueOf( anObject.toString() );
 309  
         }
 310  0
         catch ( Exception exc )
 311  
         {
 312  0
             return null;
 313  
         }
 314  
     }        
 315  
     
 316  
     static public float getFloatValue( Object anObject )
 317  
     {
 318  0
             Float result = getFloat( anObject );
 319  0
         return ( result == null ) ? 0.0f : result.floatValue();
 320  
     }
 321  
     static public Float getFloat( Object anObject )
 322  
     {
 323  0
         if ( anObject == null ) return new Float( 0.0 );
 324  0
         if ( "".equals( anObject ) ) return new Float( 0.0 );
 325  0
             if ( anObject instanceof Float ) return (Float) anObject;
 326  
     
 327  0
             anObject = preprocess( anObject );
 328  
 
 329  0
         if ( anObject instanceof Number )
 330  
         {
 331  0
             return new Float( ((Number)anObject).floatValue() );
 332  
         }
 333  
         
 334  
             try
 335  
         {
 336  0
             return Float.valueOf( anObject.toString() );
 337  
         }
 338  0
         catch ( Exception exc )
 339  
         {
 340  0
             return null;
 341  
         }
 342  
     }        
 343  
         
 344  
     static public char getCharValue( Object anObject )
 345  
     {
 346  0
             Character result = getCharacter( anObject );
 347  0
         return ( result == null ) ? (char) 0 : result.charValue();
 348  
     }
 349  
     static public Character getCharacter( Object anObject )
 350  
     {
 351  0
         if ( anObject == null ) return new Character( (char) 0 );
 352  0
             if ( anObject instanceof Character ) return (Character) anObject;
 353  
     
 354  0
             anObject = preprocess( anObject );
 355  
 
 356  0
         if ( anObject instanceof Number )
 357  
         {
 358  0
             return new Character( (char) ((Number)anObject).byteValue() );
 359  
         }
 360  
 
 361  
         try
 362  
         {
 363  0
             return new Character( anObject.toString().charAt( 0 ) );
 364  
         }
 365  0
         catch ( Exception exc )
 366  
         {
 367  0
             return null;
 368  
         }
 369  
     }
 370  
 
 371  
     static public byte getByteValue( Object anObject )
 372  
     {
 373  0
             Byte result = getByte ( anObject );
 374  0
         return ( result == null ) ? (byte) 0 : result.byteValue();
 375  
     }
 376  
     static public Byte getByte( Object anObject )
 377  
     {
 378  0
         if ( anObject == null ) return new Byte( Byte.MIN_VALUE );
 379  0
         if ( "".equals( anObject ) ) return new Byte( Byte.MIN_VALUE );
 380  0
             if ( anObject instanceof Byte ) return (Byte) anObject;
 381  
     
 382  0
             anObject = preprocess( anObject );
 383  
 
 384  0
         if ( anObject instanceof Number )
 385  
         {
 386  0
             return new Byte( ((Number)anObject).byteValue() );
 387  
         }
 388  
         
 389  
             try
 390  
         {
 391  0
             return Byte.decode( anObject.toString() );
 392  
         }
 393  0
         catch ( Exception exc )
 394  
         {
 395  
             // fall through
 396  
         }
 397  
             
 398  
         try
 399  
         {
 400  0
             return Byte.valueOf( anObject.toString() );
 401  
         }
 402  0
         catch ( Exception exc )
 403  
         {
 404  0
             return null;
 405  
         }
 406  
     }
 407  
 
 408  
         /**
 409  
         * Calls getBoolean and converts result to primitive.
 410  
         */
 411  
     static public boolean getBooleanValue( Object anObject )
 412  
     {
 413  0
             Boolean result = getBoolean( anObject );
 414  0
         return ( result == null ) ? false : result.booleanValue();
 415  
     }
 416  
         
 417  
         /**
 418  
         * Numbers equal to zero are true; Strings equal to "yes" are true;
 419  
         * Strings are then passed to the Boolean constructor.
 420  
         * Other values return null.
 421  
         */
 422  
     static public Boolean getBoolean( Object anObject )
 423  
     {                
 424  0
                 if ( anObject instanceof Boolean )
 425  
                 {
 426  0
                         return (Boolean) anObject;
 427  
                 }
 428  0
             if ( anObject instanceof Number )
 429  
         {
 430  0
             return new Boolean( ((Number)anObject).doubleValue() == 0.0 );
 431  
         }
 432  
     
 433  0
             if ( anObject instanceof String )
 434  
         {
 435  0
                         if ( anObject.toString().toLowerCase().equals( "yes" ) ) 
 436  
                         {
 437  0
                                 return Boolean.TRUE;
 438  
                         }
 439  0
             return new Boolean( (String) anObject );
 440  
         }
 441  
         
 442  0
         return null;
 443  
     }
 444  
     
 445  
     /**
 446  
     * Get an appropriate String representation for the 
 447  
     * object.  Nulls are converted to "null".  Date are
 448  
     * formatted according to the current date format.
 449  
     * All else uses toString.
 450  
     */
 451  
     static public String getString( Object anObject )
 452  
     {
 453  0
         if ( anObject == null ) return "null";
 454  0
         if ( anObject instanceof java.util.Date )
 455  
         {
 456  0
             return dateFormat.format( (java.util.Date) anObject );
 457  
         }
 458  0
         return anObject.toString();
 459  
     }
 460  
 
 461  
     /**
 462  
     * Converts the object into the specified collection class.
 463  
     * If unable to convert in any other way, resorts to creating
 464  
     * a new collection of the specified type containing the
 465  
     * specified object.
 466  
     */
 467  
     static public Collection getCollection( Object anObject, Class aCollectionClass )
 468  
     {
 469  0
         if ( anObject == null ) return null;
 470  0
         if ( aCollectionClass.isAssignableFrom( anObject.getClass() ) )
 471  
         {
 472  0
             return (Collection) anObject;
 473  
         }
 474  
         
 475  0
         Collection converted = null;
 476  
         
 477  
         // convert to collection class
 478  0
         if ( anObject instanceof Collection )
 479  
         {
 480  0
             converted = (Collection) anObject;
 481  0
         }
 482  
         else
 483  
         // try to convert an array
 484  0
         if ( anObject.getClass().isArray() )
 485  
         {
 486  
             try
 487  
             {
 488  0
                 int length = Array.getLength( anObject );
 489  0
                 converted = new LinkedList();
 490  0
                 for ( int i = 0; i < length; i++ )
 491  
                 {
 492  0
                     converted.add( Array.get( anObject, i ) );
 493  
                 }
 494  
             }
 495  0
             catch ( Exception exc )
 496  
             {
 497  
                 // try another approach   
 498  0
             }
 499  0
         }
 500  
         else
 501  
         // convert map values to collection and pass through
 502  0
         if ( anObject instanceof Map )
 503  
         {
 504  0
             converted = ((Map)anObject).values();
 505  
         }
 506  
 
 507  
         // fall back on list containing the object
 508  0
         if ( converted == null )
 509  
         {
 510  0
             converted = new LinkedList();
 511  0
             converted.add( anObject );
 512  
         }
 513  
         
 514  0
         Collection result = null;
 515  
         
 516  0
         if ( converted != null )
 517  
         {
 518  
             try
 519  
             {
 520  
                 // collections required to have the copy constructor.
 521  0
                 Constructor ctor = aCollectionClass.getConstructor(
 522  0
                     new Class[] { Collection.class } );        
 523  0
                 result = (Collection) ctor.newInstance( new Object[] { converted } );
 524  
             }
 525  0
             catch ( Exception exc )
 526  
             {
 527  
                 try
 528  
                 {
 529  0
                     result = new LinkedList();
 530  0
                     result.addAll( converted );
 531  
                 }
 532  0
                 catch ( Exception exc2 )
 533  
                 {
 534  
                     // all attempts failed
 535  0
                     result = null;
 536  0
                 }
 537  0
             }
 538  
         }
 539  
         
 540  0
         return result;
 541  
     }
 542  
 
 543  
     /**
 544  
     * Convert the object to the specified array type.
 545  
     */
 546  
     static public Object getArray( Object anObject, Class anArrayClass )
 547  
     {
 548  0
         if ( anObject == null ) return null;
 549  
         
 550  
         // try to convert an array
 551  0
         if ( anObject.getClass().isArray() )
 552  
         {
 553  
             try
 554  
             {
 555  0
                 int length = Array.getLength( anObject );
 556  0
                 Object result = Array.newInstance( 
 557  0
                     anArrayClass.getComponentType(), length );
 558  0
                 for ( int i = 0; i < length; i++ )
 559  
                 {
 560  0
                     Array.set( result, i, Array.get( anObject, i ) );
 561  
                 }
 562  0
                 return result;
 563  
             }
 564  0
             catch ( Exception exc )
 565  
             {
 566  
                 // try another approach   
 567  
             }
 568  
         }
 569  
         // convert map values to collection and pass through
 570  0
         if ( anObject instanceof Map )
 571  
         {
 572  0
             anObject = ((Map)anObject).values();
 573  
         }
 574  
         // try to convert a collection
 575  0
         if ( anObject instanceof Collection )
 576  
         {
 577  
             try
 578  
             {
 579  0
                 int length = ((Collection)anObject).size();
 580  0
                 Object result = Array.newInstance( 
 581  0
                     anArrayClass.getComponentType(), length );
 582  0
                 Iterator it = ((Collection)anObject).iterator();
 583  0
                 for ( int i = 0; i < length; i++ )
 584  
                 {
 585  0
                     Array.set( result, i, it.next() ); 
 586  
                 }
 587  0
                 return result;
 588  
             }
 589  0
             catch ( Exception exc )
 590  
             {
 591  
                 // try another approach   
 592  
             }
 593  
         }
 594  
         // if appropriate type, put the object in a single element array
 595  0
         if ( anObject.getClass().equals( anArrayClass.getComponentType() ) )
 596  
         {
 597  
             try
 598  
             {
 599  0
                 Object result = Array.newInstance( 
 600  0
                     anArrayClass.getComponentType(), 1 );
 601  0
                 Array.set( result, 0, anObject ); 
 602  0
                 return result;
 603  
             }
 604  0
             catch ( Exception exc )
 605  
             {
 606  
                 // try another approach   
 607  
             }
 608  
         }
 609  0
         return null;
 610  
     }
 611  
 
 612  
     /**
 613  
     * Get an appropriate Date from the given object.
 614  
     */
 615  
     static public java.util.Date getDate( Object anObject )
 616  
     {
 617  0
         if ( anObject == null ) return new java.util.Date( 0 );
 618  0
             if ( anObject instanceof java.util.Date ) 
 619  0
                     return (java.util.Date) anObject;
 620  
         
 621  0
         if ( anObject instanceof Number )
 622  
         {
 623  0
             return new java.util.Date( getLongValue( anObject ) );
 624  
         }
 625  
 
 626  
         try
 627  
         {
 628  0
             return dateFormat.parse( anObject.toString() );
 629  
         }
 630  0
         catch ( Exception exc )
 631  
         {
 632  0
             return null;
 633  
         }
 634  
     }
 635  
 
 636  0
     static private java.text.DateFormat dateFormat = 
 637  0
             new java.text.SimpleDateFormat();
 638  
     static public java.text.DateFormat getDateFormat()
 639  
     {
 640  0
             return dateFormat;
 641  
     }
 642  
     static public void setDateFormat( java.text.DateFormat aDateFormat )
 643  
     {
 644  0
             if ( aDateFormat != null )
 645  
         {
 646  0
             dateFormat = aDateFormat;
 647  
         }
 648  0
     }
 649  
 
 650  
     /**
 651  
     * Returns the "inverted" value of the specified object.
 652  
     * Numbers except for chars and bytes are converted to 
 653  
     * their negative representation.  Chars and bytes are
 654  
     * treated as booleans.  String are converted to booleans.
 655  
     * Booleans are converted to their opposite.
 656  
     * All other types return null.
 657  
     */    
 658  
     public static Object invert( Object anObject )
 659  
     {
 660  0
         if ( anObject == null ) return null;
 661  0
         Class aClass = anObject.getClass();
 662  
         
 663  0
             if ( ( ( anObject instanceof Number )
 664  0
            &&! ( anObject instanceof Byte )
 665  0
            &&! ( anObject instanceof Character ) )
 666  0
           || ( aClass == short.class )
 667  0
           || ( aClass == int.class )
 668  0
           || ( aClass == long.class )
 669  0
           || ( aClass == float.class )
 670  0
           || ( aClass == double.class ) )
 671  
         {
 672  0
             return convertObjectToClass( 
 673  0
                 new Double( getDoubleValue( anObject ) * -1 ), aClass );
 674  
         }
 675  
         
 676  0
         Boolean converted = getBoolean( anObject );
 677  0
         if ( converted != null )
 678  
         {
 679  0
             if ( converted.booleanValue() )
 680  
             {
 681  0
                 return convertObjectToClass(
 682  0
                     Boolean.FALSE, anObject.getClass() );
 683  
             }
 684  
             else
 685  
             {
 686  0
                 return convertObjectToClass(
 687  0
                     Boolean.TRUE, anObject.getClass() );
 688  
             }
 689  
         }
 690  
         
 691  0
         return null;
 692  
     }
 693  
 }
 694  
 
 695  
 /*
 696  
  * $Log$
 697  
  * Revision 1.2  2006/02/16 13:11:47  cgruber
 698  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 699  
  *
 700  
  * Revision 1.4  2002/10/11 15:33:53  mpowers
 701  
  * Now supporting "!" to invert the value of a string property.
 702  
  *
 703  
  * Revision 1.3  2001/07/02 16:29:08  mpowers
 704  
  * XMLRPC decoder was relying on ValueConverter to convert LinkedLists into
 705  
  * the appropriate type.  This is now implemented in ValueConverter.
 706  
  *
 707  
  * Revision 1.2  2001/03/01 20:36:35  mpowers
 708  
  * Better error handling and better handling of nulls.
 709  
  *
 710  
  * Revision 1.1.1.1  2000/12/21 15:52:33  mpowers
 711  
  * Contributing wotonomy.
 712  
  *
 713  
  * Revision 1.8  2000/12/20 16:25:48  michael
 714  
  * Added log to all files.
 715  
  *
 716  
  *
 717  
  */
 718