001    /*
002    Copyright (c) 1996-2012, Damon Hart-Davis
003    All rights reserved.
004    
005    Redistribution and use in source and binary forms, with or without
006    modification, are permitted provided that the following conditions are
007    met:
008    
009      * Redistributions of source code must retain the above copyright
010        notice, this list of conditions and the following disclaimer.
011    
012      * Redistributions in binary form must reproduce the above copyright
013        notice, this list of conditions and the following disclaimer in the
014        documentation and/or other materials provided with the
015        distribution.
016    
017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028    */
029    /*
030     * Created by IntelliJ IDEA.
031     * User: Administrator
032     * Date: 28-Dec-02
033     * Time: 22:24:51
034     * To change template for new class use
035     * Code Style | Class Templates options (Tools | IDE Options).
036     */
037    package org.hd.d.pg2k.test.dev;
038    
039    import java.awt.Dimension;
040    import java.io.ByteArrayInputStream;
041    import java.io.ByteArrayOutputStream;
042    import java.io.DataInputStream;
043    import java.io.DataOutputStream;
044    import java.io.File;
045    import java.io.IOException;
046    import java.io.InputStream;
047    import java.io.ObjectInputStream;
048    import java.io.ObjectOutputStream;
049    import java.io.OutputStream;
050    import java.io.Serializable;
051    import java.util.ArrayList;
052    import java.util.Arrays;
053    import java.util.HashSet;
054    import java.util.Iterator;
055    import java.util.List;
056    import java.util.Map;
057    import java.util.Properties;
058    import java.util.Random;
059    import java.util.Set;
060    import java.util.TreeMap;
061    import java.util.concurrent.ConcurrentHashMap;
062    import java.util.concurrent.ConcurrentMap;
063    import java.util.concurrent.atomic.AtomicInteger;
064    import java.util.zip.GZIPInputStream;
065    import java.util.zip.GZIPOutputStream;
066    
067    import junit.framework.TestCase;
068    import net.contrapunctus.lzma.LzmaInputStream;
069    import net.contrapunctus.lzma.LzmaOutputStream;
070    
071    import org.apache.tools.bzip2.CBZip2InputStream;
072    import org.apache.tools.bzip2.CBZip2OutputStream;
073    import org.hd.d.pg2k.svrCore.AccessionData;
074    import org.hd.d.pg2k.svrCore.AllExhibitImmutableData;
075    import org.hd.d.pg2k.svrCore.AllExhibitProperties;
076    import org.hd.d.pg2k.svrCore.AllExhibitPropertiesDelta;
077    import org.hd.d.pg2k.svrCore.CS8Bit;
078    import org.hd.d.pg2k.svrCore.Compact7BitString;
079    import org.hd.d.pg2k.svrCore.CompressionLevel;
080    import org.hd.d.pg2k.svrCore.CoreConsts;
081    import org.hd.d.pg2k.svrCore.EPGIDiff;
082    import org.hd.d.pg2k.svrCore.ExhibitPropsComputable;
083    import org.hd.d.pg2k.svrCore.ExhibitPropsGlobalImmutable;
084    import org.hd.d.pg2k.svrCore.ExhibitPropsLoadable;
085    import org.hd.d.pg2k.svrCore.ExhibitStaticAttr;
086    import org.hd.d.pg2k.svrCore.ExhibitThumbnails;
087    import org.hd.d.pg2k.svrCore.FileTools;
088    import org.hd.d.pg2k.svrCore.GenUtils;
089    import org.hd.d.pg2k.svrCore.Name;
090    import org.hd.d.pg2k.svrCore.ROByteArray;
091    import org.hd.d.pg2k.svrCore.TextUtils;
092    import org.hd.d.pg2k.svrCore.Tuple;
093    import org.hd.d.pg2k.svrCore.Tuple.Pair;
094    import org.hd.d.pg2k.svrCore.datasource.ExhibitDataFileSource;
095    import org.hd.d.pg2k.svrCore.datasource.simpleCache.MetaData;
096    import org.hd.d.pg2k.svrCore.location.Location;
097    import org.hd.d.pg2k.svrCore.location.LocationMap;
098    import org.hd.d.pg2k.svrCore.props.GenProps;
099    import org.hd.d.pg2k.svrCore.props.LocalProps;
100    import org.hd.d.pg2k.svrCore.props.PropertiesBundleDiff;
101    import org.hd.d.pg2k.svrCore.props.PropertiesDiff;
102    import org.hd.d.pg2k.svrCore.vars.EventPeriod;
103    import org.hd.d.pg2k.svrCore.vars.EventVariableValue;
104    import org.hd.d.pg2k.svrCore.vars.SimpleVariableDefinition;
105    import org.hd.d.pg2k.svrCore.vars.SimpleVariableValue;
106    import org.hd.d.pg2k.svrCore.vars.SystemVariables;
107    import org.hd.d.pg2k.webSvr.util.FlushableGZIPOutputStream;
108    import org.hd.d.pg2k.webSvr.util.WebUtils;
109    import org.mutabilitydetector.unittesting.AllowedReason;
110    import org.mutabilitydetector.unittesting.MutabilityAssert;
111    import org.mutabilitydetector.unittesting.MutabilityMatchers;
112    
113    /**Test that critical classes can be correctly serialised and deserialised.
114     * This is useful for items that will be:
115     * <ul>
116     * <li>Cached/persisted to disc, especially those that must last a long time and are valuable.
117     * <li>Sent over the wire.
118     * </ul>
119     */
120    public final class SerializationTest extends TestCase
121        {
122        public SerializationTest(final String name)
123            {
124            super(name);
125            }
126    
127        /**If true, print out serialised value in form that can be cut-n-paste back into test code. */
128        private static final boolean PRINT_SER_BYTES = false;
129    
130        /**Maximum bytes to print on each line of serialised form. */
131        private static final int MAX_BYTES_PER_LINE = 8;
132    
133        /**Check that the object passed can be serialised and deserialised.
134         *
135         * @param obj  must implement java.io.Serializable; never null
136         * @return  the deserialised version of the object
137         * @throws IOException
138         * @throws ClassNotFoundException
139         */
140        public static Object checkObjectCanBeSerialisedAndDeserialised(final Object obj)
141            throws IOException,
142                   ClassNotFoundException
143            {
144            assertTrue("Original object does not implement Serializable", obj instanceof Serializable);
145    
146            // Serialise and deserialise to make a deep copy as if sent over the wire...
147            final byte[] data = serialiseToByteArray(obj);
148    
149            if(PRINT_SER_BYTES)
150                { dumpSerData(obj, data); }
151    
152            final Object obj2 = deserialiseFromByteArray(data);
153    
154            assertNotNull("Deserialisation of a class " + obj.getClass() + " resulted in a null object", obj2);
155            return(obj2);
156            }
157    
158        /**Serialise given object to byte array; never null. */
159        public static byte[] serialiseToByteArray(final Object obj)
160                throws IOException
161            {
162            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
163            final ObjectOutputStream oos = new ObjectOutputStream(baos);
164            oos.writeObject(obj);
165            oos.flush();
166            final byte data[] = baos.toByteArray();
167            return data;
168            }
169    
170        /**Dump serialised data in a form suitable to copy-and-paste into code. */
171        private static void dumpSerData(final Object obj, final byte[] data)
172            {
173            System.out.println("***DUMPING DATA FOR " + obj);
174            System.out.println("private static final byte serData[/*"+data.length+"*/] = {");
175            int count = 0;
176            final byte values[] = new byte[MAX_BYTES_PER_LINE];
177            final StringBuilder sbTmp = new StringBuilder(); // Used to build one value to print.
178            for(final byte b : data)
179                {
180                sbTmp.setLength(0);
181                sbTmp.append(Integer.toString(b, 10));
182                while(sbTmp.length() < 4) { sbTmp.insert(0, ' '); }
183                sbTmp.append(", ");
184                System.out.print(sbTmp.toString());
185                values[count] = b;
186                if(++count >= MAX_BYTES_PER_LINE)
187                    {
188                    dumpAsciiComment(sbTmp, count, values);
189                    count = 0;
190                    }
191                }
192            dumpAsciiComment(sbTmp, count, values);
193            System.out.println("};");
194            }
195    
196        /**Dump to System.out "count" characters from values, substituting non-printable-ASCII. */
197        private static void dumpAsciiComment(final StringBuilder sbTmp, final int count, final byte[] values)
198            {
199            sbTmp.setLength(0);
200            sbTmp.append("// ");
201            for(int i = 0; i < count; ++i)
202                {
203                final int bc = values[i];
204                if((bc > 32) && (bc < 127)) { sbTmp.append((char) bc); }
205                else { sbTmp.append('.'); /* Substitute "safe" character. */ }
206                }
207            System.out.println(sbTmp.toString());
208            }
209    
210        /**Deserialise an Object from the supplied serialised form. */
211        static Object deserialiseFromByteArray(final byte[] data)
212            throws IOException, ClassNotFoundException
213            {
214            final ByteArrayInputStream bais = new ByteArrayInputStream(data);
215            final ObjectInputStream ois = new ObjectInputStream(bais);
216            final Object obj2 = ois.readObject();
217            return obj2;
218            }
219    
220        /**Check that the passed (non-null) object compares equals after being serialised/deserialised.
221         * This looks at equals() and hashCode().
222         * <p>
223         * Tests in passing that the object <em>can</em> be (de)serialised.
224         *
225         * @throws Exception  in case of difficulty.
226         * @return deserialised object in case we want to perform extra tests on it
227         */
228        public static Object checkSerialisationPreservesEquality(final Object obj)
229            throws Exception
230            {
231            final Object obj2 = checkObjectCanBeSerialisedAndDeserialised(obj);
232    
233            assertTrue("Equality test fails for orig.equals(copy)", obj.equals(obj2));
234            assertTrue("Equality test fails for copy.equals(orig)", obj2.equals(obj));
235            assertTrue("Hash codes must be equal", obj.hashCode() == obj2.hashCode());
236    
237            return(obj2);
238            }
239    
240        /**Basic tests for those objects whose empty instances should have zero hash and compare equal.
241         * (Empty instances are those made with the default constructor.)
242         * <p>
243         * Most of our persistable and transmittable-across-the-wire objects
244         * should show this property so that we can easily tell empty objects
245         * from ones containing useful data for example.
246         * <p>
247         * These objects should also be Serializable ((de)serializable) and still
248         * compare equal.
249         *
250         * @throws Exception  in case of difficulty.
251         */
252        public static void checkEmptyInstancesAreZeroAndEqualAndSerializable(final Class<? extends Serializable> c)
253            throws Exception
254            {
255            final Object empty = c.newInstance();
256            assertTrue(empty.hashCode() == 0);
257            assertTrue(empty.equals(c.newInstance()));
258            checkSerialisationPreservesEquality(empty);
259            }
260    
261        /**Test AllExhibitImmutableData for (de)serialisability.
262         * We check that:
263         * <ul>
264         * <li>Empty instances are constructed correctly, with a zero timestamp
265         *     (and a zero hash, and compare equal).
266         * <li>Non-empty items can be serialised and deserialised correctly,
267         *     including compute-on-demand cached values.
268         * </ul>
269         */
270        public static void testAllExhibitImmutableData()
271            throws Exception
272            {
273            checkEmptyInstancesAreZeroAndEqualAndSerializable(AllExhibitImmutableData.class);
274            final AllExhibitImmutableData empty = new AllExhibitImmutableData();
275            assertTrue(empty.timestamp == 0);
276            assertTrue(empty.getAllExhibitNamesSorted().isEmpty());
277            assertTrue(empty.getAllStaticAttrs().isEmpty());
278    
279            // TODO: finish!
280            }
281    
282        /**Test AllExhibitProperties for (de)serialisability.
283         * We check that:
284         * <ul>
285         * <li>Empty instances are constructed correctly, with a zero timestamp
286         *     (and a zero hash, and compare equal).
287         * <li>Non-empty items can be serialised and deserialised correctly,
288         *     including compute-on-demand cached values.
289         * </ul>
290         */
291        public static void testAllExhibitProperties()
292            throws Exception
293            {
294            checkEmptyInstancesAreZeroAndEqualAndSerializable(AllExhibitProperties.class);
295            final AllExhibitProperties empty = new AllExhibitProperties();
296            assertTrue(empty.longHash == 0);
297    
298            // Load a real instance from the filesystem...
299            final ExhibitDataFileSource edfs = new ExhibitDataFileSource(null);
300            final AllExhibitProperties aep = edfs.getAllExhibitProperties(-1);
301    Main.getOut().println("Loaded AEP with exhibit count: " + aep.aeid.length);
302            // Check that the AEP can be (de)serialised correctly.
303            final Object aep2 = checkObjectCanBeSerialisedAndDeserialised(aep);
304            // In case of legitimate hash changes from serialised state
305            // we'll check equality based on the reserialising the deserialised instance.
306            checkSerialisationPreservesEquality(aep2);
307            // TODO: finish!
308            }
309    
310        /**Basic tests on ExhibitPropsLoadable. */
311        public static void testExhibitPropsLoadable()
312        throws Exception
313            {
314            checkSerialisationPreservesEquality(ExhibitPropsLoadable.EMPTY);
315            // TODO: finish!
316            }
317    
318        /**Test GenProps for (de)serialisability.
319         * We check that:
320         * <ul>
321         * <li>Empty instances are constructed correctly, with a zero timestamp
322         *     (and a zero hash, and compare equal).
323         * <li>Non-empty items can be serialised and deserialised correctly,
324         *     including compute-on-demand cached values.
325         * </ul>
326         */
327        public static void testGenProps()
328            throws Exception
329            {
330            final GenProps empty = new GenProps();
331            assertTrue(empty.timestamp == 0);
332            final GenProps empty2 =
333                (GenProps) checkObjectCanBeSerialisedAndDeserialised(empty);
334            assertTrue(empty2.timestamp == 0);
335    
336            // TODO: finish!
337            }
338    
339        /**Test ExhibitThumbnails.
340         * We want to check that object resolving works and we discard
341         * duplicate values that equals NO_THUMBNAILS on deserialisation.
342         */
343        public static void testExhibitThumbnails()
344            throws Exception
345            {
346            final Object obj2 = checkSerialisationPreservesEquality(ExhibitThumbnails.NO_THUMBNAILS);
347            assertTrue("ExhibitThumbnails.NO_THUMBNAILS should resolve to itself (ie discard duplicates)",
348                       obj2 == ExhibitThumbnails.NO_THUMBNAILS);
349    
350            // TODO: some tests on more realistic thumbnail objects.
351            }
352    
353        /**Test Location data (esp Estd) can be (de)serialised.
354         * We also test the LocationMap.
355         */
356        public static void testLocation()
357            throws Exception
358            {
359            // Set up some properties as if from a file:
360            //    type=Estd
361            //    # The error in each value is +/- the Err value.
362            //    # Degrees East/North.
363            //    E=-0.29
364            //    EErr=0.01
365            //    N=51.41
366            //    NErr=0.01
367            final Properties p1 = new Properties();
368            p1.setProperty("type", "Estd");
369            p1.setProperty("E", "-0.29");
370            p1.setProperty("EErr", "0.01");
371            p1.setProperty("N", "51.41");
372            p1.setProperty("NErr", "0.01");
373            // Construct a simple example Estd item.
374            final Location.Estd e1 = new Location.Estd(
375                true, // Claim that this data is "specific" to a particular exhibit.
376                "", // No prefix on the property names.
377                p1 // The properties.
378                );
379            // Check that we can (de)serialise this (and preserve equality).
380            checkSerialisationPreservesEquality(e1);
381    
382            // Test behaviour of entire LocationMap.
383            checkEmptyInstancesAreZeroAndEqualAndSerializable(LocationMap.class);
384            }
385    
386        /**Raw value of String variable value for "hills are alive" value. */
387        private static final String hillsAreAlive = " the hills are alive! 87239473075!^%#^";
388    
389        /**Serialised String variable value for "hills are alive" value. */
390        private static final byte serData_hillsAreAlive_20050130[/*482*/] = {
391            -84,  -19,    0,    5,  115,  114,    0,   46, // ....sr..
392            111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
393             46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
394            114,   67,  111,  114,  101,   46,  118,   97, // rCore.va
395            114,  115,   46,   83,  105,  109,  112,  108, // rs.Simpl
396            101,   86,   97,  114,  105,   97,   98,  108, // eVariabl
397            101,   86,   97,  108,  117,  101,  -71,   77, // eValue.M
398             83, -103,  -28,  -60, -107,   95,    2,    0, // S...._..
399              4,   74,    0,    9,  116,  105,  109,  101, // .J..time
400            115,  116,   97,  109,  112,   76,    0,    3, // stampL..
401            100,  101,  102,  116,    0,   53,   76,  111, // deft.5Lo
402            114,  103,   47,  104,  100,   47,  100,   47, // rg/hd/d/
403            112,  103,   50,  107,   47,  115,  118,  114, // pg2k/svr
404             67,  111,  114,  101,   47,  118,   97,  114, // Core/var
405            115,   47,   83,  105,  109,  112,  108,  101, // s/Simple
406             86,   97,  114,  105,   97,   98,  108,  101, // Variable
407             68,  101,  102,  105,  110,  105,  116,  105, // Definiti
408            111,  110,   59,   76,    0,    9,  103,  108, // on;L..gl
409            111,   98,   97,  108,   77,   97,  112,  116, // obalMapt
410              0,   15,   76,  106,   97,  118,   97,   47, // ..Ljava/
411            117,  116,  105,  108,   47,   77,   97,  112, // util/Map
412             59,   76,    0,    5,  118,   97,  108,  117, // ;L..valu
413            101,  116,    0,   18,   76,  106,   97,  118, // et..Ljav
414             97,   47,  108,   97,  110,  103,   47,   79, // a/lang/O
415             98,  106,  101,   99,  116,   59,  120,  112, // bject;xp
416              0,    0,    1,    1,  -60, -115,   49,   29, // ......1.
417            115,  114,    0,   51,  111,  114,  103,   46, // sr.3org.
418            104,  100,   46,  100,   46,  112,  103,   50, // hd.d.pg2
419            107,   46,  115,  118,  114,   67,  111,  114, // k.svrCor
420            101,   46,  118,   97,  114,  115,   46,   83, // e.vars.S
421            105,  109,  112,  108,  101,   86,   97,  114, // impleVar
422            105,   97,   98,  108,  101,   68,  101,  102, // iableDef
423            105,  110,  105,  116,  105,  111,  110,   32, // inition.
424            -60,  -92,   85,  126,   79,  -65,  -35,    2, // ..U~O...
425              0,    8,   90,    0,    5,  101,  118,  101, // ..Z..eve
426            110,  116,   90,    0,    5,  108,  111,   99, // ntZ..loc
427             97,  108,   73,    0,   17,  109,   97,  120, // alI..max
428             68,  105,  102,  102,   69,  118,  101,  110, // DiffEven
429            116,   67,  111,  117,  110,  116,   90,    0, // tCountZ.
430             10,  112,  101,  114,  115,  105,  115,  116, // .persist
431            101,  110,  116,   90,    0,    8,  114,  101, // entZ..re
432             97,  100,   79,  110,  108,  121,   73,    0, // adOnlyI.
433              4,  116,  121,  112,  101,   76,    0,   14, // .typeL..
434            101,  118,   80,  101,  114,  105,  111,  100, // evPeriod
435             83,  117,   98,  115,  101,  116,  116,    0, // Subsett.
436             19,   76,  106,   97,  118,   97,   47,  117, // .Ljava/u
437            116,  105,  108,   47,   69,  110,  117,  109, // til/Enum
438             83,  101,  116,   59,   76,    0,    4,  110, // Set;L..n
439             97,  109,  101,  116,    0,   18,   76,  106, // amet..Lj
440             97,  118,   97,   47,  108,   97,  110,  103, // ava/lang
441             47,   83,  116,  114,  105,  110,  103,   59, // /String;
442            120,  112,    0,    1,    0,    0,    0,    0, // xp......
443              0,    0,    0,    0,    0,    2,  112,  116, // ......pt
444              0,   14,  116,  101,  115,  116,   83,  101, // ..testSe
445            114,   46,  118,   97,  108,  117,  101,   51, // r.value3
446            112,  116,    0,   38,   32,  116,  104,  101, // pt.&.the
447             32,  104,  105,  108,  108,  115,   32,   97, // .hills.a
448            114,  101,   32,   97,  108,  105,  118,  101, // re.alive
449             33,   32,   56,   55,   50,   51,   57,   52, // !.872394
450             55,   51,   48,   55,   53,   33,   94,   37, // 73075!^%
451             35,   94,                                     // #^
452        };
453    
454        /**Test that variables can be correctly serialised/deserialised.
455         * We check all the built-in definitions and
456         * instances/values of several types.
457         */
458        public static void testSimpleVariables()
459            throws Exception
460            {
461            // Test that every definition can be correctly serialised and deserialised.
462            for(final Iterator it = SystemVariables.defs.iterator(); it.hasNext(); )
463                { checkSerialisationPreservesEquality(it.next()); }
464    
465            // Test an instance of TYPE_NONE...
466            final SimpleVariableValue svv1 =
467                new SimpleVariableValue(SystemVariables.KEEP_ALIVE,
468                                        null);
469            checkSerialisationPreservesEquality(svv1);
470    
471            // Test a simple instance of TYPE_NUMBER...
472            final SimpleVariableValue svv2 =
473                new SimpleVariableValue(SystemVariables.ThroughputMonitorFilter_CLIENT_COUNT,
474                                        new Integer(rnd.nextInt(9999)));
475            checkSerialisationPreservesEquality(svv2);
476    
477            // Try this on a few random variable definitions
478            // plus all extant system variable values.
479            final List<SimpleVariableDefinition> testDefSet = new ArrayList<SimpleVariableDefinition>();
480            testDefSet.addAll(SystemVariables.defs);
481            for(int i = 37; --i >= 0; )
482                { testDefSet.add(SystemVariablesTest.makeRandomSimpleVariableDefinition()); }
483    
484            // Try out one possible value for each test definition.
485            for(final Iterator it = testDefSet.iterator(); it.hasNext(); )
486                {
487                final SimpleVariableDefinition def =
488                    (SimpleVariableDefinition) it.next();
489                final SimpleVariableValue svv = SystemVariablesTest.makeRandomSimpleVariableValue(def);
490                checkSerialisationPreservesEquality(svv);
491                }
492    
493            // Check that we can deserialise at least one frozen serialised (String) non-standard value.
494            // This is a test of robustness of both the definition and the value objects.
495            final SimpleVariableDefinition newDef = new SimpleVariableDefinition("testSer.value3",
496                                                                                 SimpleVariableDefinition.TYPE_STRING);
497            final SimpleVariableValue svv3 =
498                new SimpleVariableValue(newDef, hillsAreAlive);
499            checkSerialisationPreservesEquality(svv3);
500            // Now check that deserialising the static data gives an equal value.
501            assertTrue("Deserialised frozen value must be equal to newly constructed one",
502                       svv3.equals(deserialiseFromByteArray(serData_hillsAreAlive_20050130)));
503            }
504    
505    
506        /**First test string value for EVV; has a count of 1. */
507        private static final String evvTestString1 = "45dgjytref";
508    
509        /**Second test string value for EVV; has a count of 2. */
510        private static final String evvTestString2 = "dfgtr67kjhfh";
511    
512        /**Total event count in map. */
513        private static final int evv_TOTAL_EVENT_COUNT = 5;
514    
515        /**Old serialised format of a single EVV with embedded Map&lt;Object, ValueInfo&gt;. */
516        private static final byte serData_evv1_20050130_1748[/*812*/] = {
517         -84,  -19,    0,    5,  115,  114,    0,   45, // ....sr.-
518         111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
519          46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
520         114,   67,  111,  114,  101,   46,  118,   97, // rCore.va
521         114,  115,   46,   69,  118,  101,  110,  116, // rs.Event
522          86,   97,  114,  105,   97,   98,  108,  101, // Variable
523          86,   97,  108,  117,  101,   70,  -78,  -84, // ValueF..
524         102,   92,  -52,   21,  -95,    2,    0,    6, // f\......
525          90,    0,   13,   97,  117,  116,  104,  111, // Z..autho
526         114,   97,  116,  105,  116,  105,  118,  101, // ratitive
527          74,    0,   14,  105,  110,  116,  101,  114, // J..inter
528         118,   97,  108,   78,  117,  109,   98,  101, // valNumbe
529         114,   73,    0,   15,  116,  111,  116,   97, // rI..tota
530         108,   69,  118,  101,  110,  116,   67,  111, // lEventCo
531         117,  110,  116,   76,    0,    3,  100,  101, // untL..de
532         102,  116,    0,   53,   76,  111,  114,  103, // ft.5Lorg
533          47,  104,  100,   47,  100,   47,  112,  103, // /hd/d/pg
534          50,  107,   47,  115,  118,  114,   67,  111, // 2k/svrCo
535         114,  101,   47,  118,   97,  114,  115,   47, // re/vars/
536          83,  105,  109,  112,  108,  101,   86,   97, // SimpleVa
537         114,  105,   97,   98,  108,  101,   68,  101, // riableDe
538         102,  105,  110,  105,  116,  105,  111,  110, // finition
539          59,   76,    0,    4,  105,  110,  102,  111, // ;L..info
540         116,    0,   15,   76,  106,   97,  118,   97, // t..Ljava
541          47,  117,  116,  105,  108,   47,   77,   97, // /util/Ma
542         112,   59,   76,    0,    6,  112,  101,  114, // p;L..per
543         105,  111,  100,  116,    0,   40,   76,  111, // iodt.(Lo
544         114,  103,   47,  104,  100,   47,  100,   47, // rg/hd/d/
545         112,  103,   50,  107,   47,  115,  118,  114, // pg2k/svr
546          67,  111,  114,  101,   47,  118,   97,  114, // Core/var
547         115,   47,   69,  118,  101,  110,  116,   80, // s/EventP
548         101,  114,  105,  111,  100,   59,  120,  112, // eriod;xp
549           1,    0,    0,    0,    0,    0,    0,    0, // ........
550           1,    0,    0,    0,    5,  115,  114,    0, // .....sr.
551          51,  111,  114,  103,   46,  104,  100,   46, // 3org.hd.
552         100,   46,  112,  103,   50,  107,   46,  115, // d.pg2k.s
553         118,  114,   67,  111,  114,  101,   46,  118, // vrCore.v
554          97,  114,  115,   46,   83,  105,  109,  112, // ars.Simp
555         108,  101,   86,   97,  114,  105,   97,   98, // leVariab
556         108,  101,   68,  101,  102,  105,  110,  105, // leDefini
557         116,  105,  111,  110,   32,  -60,  -92,   85, // tion...U
558         126,   79,  -65,  -35,    2,    0,    8,   90, // ~O.....Z
559           0,    5,  101,  118,  101,  110,  116,   90, // ..eventZ
560           0,    5,  108,  111,   99,   97,  108,   73, // ..localI
561           0,   17,  109,   97,  120,   68,  105,  102, // ..maxDif
562         102,   69,  118,  101,  110,  116,   67,  111, // fEventCo
563         117,  110,  116,   90,    0,   10,  112,  101, // untZ..pe
564         114,  115,  105,  115,  116,  101,  110,  116, // rsistent
565          90,    0,    8,  114,  101,   97,  100,   79, // Z..readO
566         110,  108,  121,   73,    0,    4,  116,  121, // nlyI..ty
567         112,  101,   76,    0,   14,  101,  118,   80, // peL..evP
568         101,  114,  105,  111,  100,   83,  117,   98, // eriodSub
569         115,  101,  116,  116,    0,   19,   76,  106, // sett..Lj
570          97,  118,   97,   47,  117,  116,  105,  108, // ava/util
571          47,   69,  110,  117,  109,   83,  101,  116, // /EnumSet
572          59,   76,    0,    4,  110,   97,  109,  101, // ;L..name
573         116,    0,   18,   76,  106,   97,  118,   97, // t..Ljava
574          47,  108,   97,  110,  103,   47,   83,  116, // /lang/St
575         114,  105,  110,  103,   59,  120,  112,    1, // ring;xp.
576           0,    0,    0,    0,  101,    1,    0,    0, // ....e...
577           0,    0,    2,  112,  116,    0,   18,  116, // ...pt..t
578         101,  115,  116,   83,  101,  114,   46,  115, // estSer.s
579         116,  114,  105,  110,  103,   46,  118,   97, // tring.va
580         108,  115,  114,    0,   17,  106,   97,  118, // lsr..jav
581          97,   46,  117,  116,  105,  108,   46,   72, // a.util.H
582          97,  115,  104,   77,   97,  112,    5,    7, // ashMap..
583         -38,  -63,  -61,   22,   96,  -47,    3,    0, // ....`...
584           2,   70,    0,   10,  108,  111,   97,  100, // .F..load
585          70,   97,   99,  116,  111,  114,   73,    0, // FactorI.
586           9,  116,  104,  114,  101,  115,  104,  111, // .thresho
587         108,  100,  120,  112,   63,   64,    0,    0, // ldxp?@..
588           0,    0,    0,    3,  119,    8,    0,    0, // ....w...
589           0,    4,    0,    0,    0,    2,  116,    0, // ......t.
590          10,   52,   53,  100,  103,  106,  121,  116, // .45dgjyt
591         114,  101,  102,  115,  114,    0,   55,  111, // refsr.7o
592         114,  103,   46,  104,  100,   46,  100,   46, // rg.hd.d.
593         112,  103,   50,  107,   46,  115,  118,  114, // pg2k.svr
594          67,  111,  114,  101,   46,  118,   97,  114, // Core.var
595         115,   46,   69,  118,  101,  110,  116,   86, // s.EventV
596          97,  114,  105,   97,   98,  108,  101,   86, // ariableV
597          97,  108,  117,  101,   36,   86,   97,  108, // alue$Val
598         117,  101,   73,  110,  102,  111,   12,   82, // ueInfo.R
599        -114,  -88,   -5,  -45,   19,   93,    2,    0, // .....]..
600           2,   73,    0,    5,   99,  111,  117,  110, // .I..coun
601         116,   73,    0,    4,  114,   97,  110,  107, // tI..rank
602         120,  112,    0,    0,    0,    1,    0,    0, // xp......
603           0,    1,  116,    0,   12,  100,  102,  103, // ..t..dfg
604         116,  114,   54,   55,  107,  106,  104,  102, // tr67kjhf
605         104,  115,  113,    0,  126,    0,   13,    0, // hsq.~...
606           0,    0,    2,    0,    0,    0,    0,  120, // .......x
607         126,  114,    0,   38,  111,  114,  103,   46, // ~r.&org.
608         104,  100,   46,  100,   46,  112,  103,   50, // hd.d.pg2
609         107,   46,  115,  118,  114,   67,  111,  114, // k.svrCor
610         101,   46,  118,   97,  114,  115,   46,   69, // e.vars.E
611         118,  101,  110,  116,   80,  101,  114,  105, // ventPeri
612         111,  100,    0,    0,    0,    0,    0,    0, // od......
613           0,    0,   18,    0,    0,  120,  114,    0, // .....xr.
614          14,  106,   97,  118,   97,   46,  108,   97, // .java.la
615         110,  103,   46,   69,  110,  117,  109,    0, // ng.Enum.
616           0,    0,    0,    0,    0,    0,    0,   18, // ........
617           0,    0,  120,  112,  116,    0,    5,   86, // ..xpt..V
618          76,   79,   78,   71,                         // LONG
619        };
620    
621        /**New (more compact) serialised format of a single EVV with counts[]/values[]. */
622        private static final byte serData_evv1_20050131_1512[/*743*/] = {
623         -84,  -19,    0,    5,  115,  114,    0,   45, // ....sr.-
624         111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
625          46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
626         114,   67,  111,  114,  101,   46,  118,   97, // rCore.va
627         114,  115,   46,   69,  118,  101,  110,  116, // rs.Event
628          86,   97,  114,  105,   97,   98,  108,  101, // Variable
629          86,   97,  108,  117,  101,   70,  -78,  -84, // ValueF..
630         102,   92,  -52,   21,  -95,    3,    0,    8, // f\......
631          90,    0,   13,   97,  117,  116,  104,  111, // Z..autho
632         114,   97,  116,  105,  116,  105,  118,  101, // ratitive
633          74,    0,   14,  105,  110,  116,  101,  114, // J..inter
634         118,   97,  108,   78,  117,  109,   98,  101, // valNumbe
635         114,   73,    0,   15,  116,  111,  116,   97, // rI..tota
636         108,   69,  118,  101,  110,  116,   67,  111, // lEventCo
637         117,  110,  116,   91,    0,    6,   99,  111, // unt[..co
638         117,  110,  116,  115,  116,    0,    2,   91, // untst..[
639          73,   76,    0,    3,  100,  101,  102,  116, // IL..deft
640           0,   53,   76,  111,  114,  103,   47,  104, // .5Lorg/h
641         100,   47,  100,   47,  112,  103,   50,  107, // d/d/pg2k
642          47,  115,  118,  114,   67,  111,  114,  101, // /svrCore
643          47,  118,   97,  114,  115,   47,   83,  105, // /vars/Si
644         109,  112,  108,  101,   86,   97,  114,  105, // mpleVari
645          97,   98,  108,  101,   68,  101,  102,  105, // ableDefi
646         110,  105,  116,  105,  111,  110,   59,   76, // nition;L
647           0,    4,  105,  110,  102,  111,  116,    0, // ..infot.
648          15,   76,  106,   97,  118,   97,   47,  117, // .Ljava/u
649         116,  105,  108,   47,   77,   97,  112,   59, // til/Map;
650          76,    0,    6,  112,  101,  114,  105,  111, // L..perio
651         100,  116,    0,   40,   76,  111,  114,  103, // dt.(Lorg
652          47,  104,  100,   47,  100,   47,  112,  103, // /hd/d/pg
653          50,  107,   47,  115,  118,  114,   67,  111, // 2k/svrCo
654         114,  101,   47,  118,   97,  114,  115,   47, // re/vars/
655          69,  118,  101,  110,  116,   80,  101,  114, // EventPer
656         105,  111,  100,   59,   91,    0,    6,  118, // iod;[..v
657          97,  108,  117,  101,  115,  116,    0,   19, // aluest..
658          91,   76,  106,   97,  118,   97,   47,  108, // [Ljava/l
659          97,  110,  103,   47,   79,   98,  106,  101, // ang/Obje
660          99,  116,   59,  120,  112,    1,    0,    0, // ct;xp...
661           0,    0,    0,    0,    0,    1,    0,    0, // ........
662           0,    5,  117,  114,    0,    2,   91,   73, // ..ur..[I
663          77,  -70,   96,   38,  118,  -22,  -78,  -91, // M.`&v...
664           2,    0,    0,  120,  112,    0,    0,    0, // ...xp...
665           2,    0,    0,    0,    2,    0,    0,    0, // ........
666           1,  115,  114,    0,   51,  111,  114,  103, // .sr.3org
667          46,  104,  100,   46,  100,   46,  112,  103, // .hd.d.pg
668          50,  107,   46,  115,  118,  114,   67,  111, // 2k.svrCo
669         114,  101,   46,  118,   97,  114,  115,   46, // re.vars.
670          83,  105,  109,  112,  108,  101,   86,   97, // SimpleVa
671         114,  105,   97,   98,  108,  101,   68,  101, // riableDe
672         102,  105,  110,  105,  116,  105,  111,  110, // finition
673          32,  -60,  -92,   85,  126,   79,  -65,  -35, // ...U~O..
674           2,    0,    8,   90,    0,    5,  101,  118, // ...Z..ev
675         101,  110,  116,   90,    0,    5,  108,  111, // entZ..lo
676          99,   97,  108,   73,    0,   17,  109,   97, // calI..ma
677         120,   68,  105,  102,  102,   69,  118,  101, // xDiffEve
678         110,  116,   67,  111,  117,  110,  116,   90, // ntCountZ
679           0,   10,  112,  101,  114,  115,  105,  115, // ..persis
680         116,  101,  110,  116,   90,    0,    8,  114, // tentZ..r
681         101,   97,  100,   79,  110,  108,  121,   73, // eadOnlyI
682           0,    4,  116,  121,  112,  101,   76,    0, // ..typeL.
683          14,  101,  118,   80,  101,  114,  105,  111, // .evPerio
684         100,   83,  117,   98,  115,  101,  116,  116, // dSubsett
685           0,   19,   76,  106,   97,  118,   97,   47, // ..Ljava/
686         117,  116,  105,  108,   47,   69,  110,  117, // util/Enu
687         109,   83,  101,  116,   59,   76,    0,    4, // mSet;L..
688         110,   97,  109,  101,  116,    0,   18,   76, // namet..L
689         106,   97,  118,   97,   47,  108,   97,  110, // java/lan
690         103,   47,   83,  116,  114,  105,  110,  103, // g/String
691          59,  120,  112,    1,    0,    0,    0,    0, // ;xp.....
692         101,    1,    0,    0,    0,    0,    2,  112, // e......p
693         116,    0,   18,  116,  101,  115,  116,   83, // t..testS
694         101,  114,   46,  115,  116,  114,  105,  110, // er.strin
695         103,   46,  118,   97,  108,  112,  126,  114, // g.valp~r
696           0,   38,  111,  114,  103,   46,  104,  100, // .&org.hd
697          46,  100,   46,  112,  103,   50,  107,   46, // .d.pg2k.
698         115,  118,  114,   67,  111,  114,  101,   46, // svrCore.
699         118,   97,  114,  115,   46,   69,  118,  101, // vars.Eve
700         110,  116,   80,  101,  114,  105,  111,  100, // ntPeriod
701           0,    0,    0,    0,    0,    0,    0,    0, // ........
702          18,    0,    0,  120,  114,    0,   14,  106, // ...xr..j
703          97,  118,   97,   46,  108,   97,  110,  103, // ava.lang
704          46,   69,  110,  117,  109,    0,    0,    0, // .Enum...
705           0,    0,    0,    0,    0,   18,    0,    0, // ........
706         120,  112,  116,    0,    5,   86,   76,   79, // xpt..VLO
707          78,   71,  117,  114,    0,   19,   91,   76, // NGur..[L
708         106,   97,  118,   97,   46,  108,   97,  110, // java.lan
709         103,   46,   79,   98,  106,  101,   99,  116, // g.Object
710          59, -112,  -50,   88,  -97,   16,  115,   41, // ;..X..s)
711         108,    2,    0,    0,  120,  112,    0,    0, // l...xp..
712           0,    2,  116,    0,   12,  100,  102,  103, // ..t..dfg
713         116,  114,   54,   55,  107,  106,  104,  102, // tr67kjhf
714         104,  116,    0,   10,   52,   53,  100,  103, // ht..45dg
715         106,  121,  116,  114,  101,  102,  120,       // jytrefx
716        };
717    
718        /**Newer serialised format (with Name in place of String on the wire) of a single EVV with counts[]/values[]. */
719        private static final byte serData_evv1_20090806[/*829*/] = {
720        -84,  -19,    0,    5,  115,  114,    0,   45, // ....sr.-
721        111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
722         46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
723        114,   67,  111,  114,  101,   46,  118,   97, // rCore.va
724        114,  115,   46,   69,  118,  101,  110,  116, // rs.Event
725         86,   97,  114,  105,   97,   98,  108,  101, // Variable
726         86,   97,  108,  117,  101,   70,  -78,  -84, // ValueF..
727        102,   92,  -52,   21,  -95,    3,    0,    7, // f\......
728         90,    0,   13,   97,  117,  116,  104,  111, // Z..autho
729        114,   97,  116,  105,  116,  105,  118,  101, // ratitive
730         74,    0,   14,  105,  110,  116,  101,  114, // J..inter
731        118,   97,  108,   78,  117,  109,   98,  101, // valNumbe
732        114,   73,    0,   15,  116,  111,  116,   97, // rI..tota
733        108,   69,  118,  101,  110,  116,   67,  111, // lEventCo
734        117,  110,  116,   91,    0,    6,   99,  111, // unt[..co
735        117,  110,  116,  115,  116,    0,    2,   91, // untst..[
736         73,   76,    0,    3,  100,  101,  102,  116, // IL..deft
737          0,   53,   76,  111,  114,  103,   47,  104, // .5Lorg/h
738        100,   47,  100,   47,  112,  103,   50,  107, // d/d/pg2k
739         47,  115,  118,  114,   67,  111,  114,  101, // /svrCore
740         47,  118,   97,  114,  115,   47,   83,  105, // /vars/Si
741        109,  112,  108,  101,   86,   97,  114,  105, // mpleVari
742         97,   98,  108,  101,   68,  101,  102,  105, // ableDefi
743        110,  105,  116,  105,  111,  110,   59,   76, // nition;L
744          0,    6,  112,  101,  114,  105,  111,  100, // ..period
745        116,    0,   40,   76,  111,  114,  103,   47, // t.(Lorg/
746        104,  100,   47,  100,   47,  112,  103,   50, // hd/d/pg2
747        107,   47,  115,  118,  114,   67,  111,  114, // k/svrCor
748        101,   47,  118,   97,  114,  115,   47,   69, // e/vars/E
749        118,  101,  110,  116,   80,  101,  114,  105, // ventPeri
750        111,  100,   59,   91,    0,    6,  118,   97, // od;[..va
751        108,  117,  101,  115,  116,    0,   19,   91, // luest..[
752         76,  106,   97,  118,   97,   47,  108,   97, // Ljava/la
753        110,  103,   47,   79,   98,  106,  101,   99, // ng/Objec
754        116,   59,  120,  112,    1,    0,    0,    0, // t;xp....
755          0,    0,    0,    0,    1,    0,    0,    0, // ........
756          5,  117,  114,    0,    2,   91,   73,   77, // .ur..[IM
757        -70,   96,   38,  118,  -22,  -78,  -91,    2, // .`&v....
758          0,    0,  120,  112,    0,    0,    0,    2, // ..xp....
759          0,    0,    0,    2,    0,    0,    0,    1, // ........
760        115,  114,    0,   51,  111,  114,  103,   46, // sr.3org.
761        104,  100,   46,  100,   46,  112,  103,   50, // hd.d.pg2
762        107,   46,  115,  118,  114,   67,  111,  114, // k.svrCor
763        101,   46,  118,   97,  114,  115,   46,   83, // e.vars.S
764        105,  109,  112,  108,  101,   86,   97,  114, // impleVar
765        105,   97,   98,  108,  101,   68,  101,  102, // iableDef
766        105,  110,  105,  116,  105,  111,  110,   32, // inition.
767        -60,  -92,   85,  126,   79,  -65,  -35,    2, // ..U~O...
768          0,    8,   90,    0,    5,  101,  118,  101, // ..Z..eve
769        110,  116,   90,    0,    5,  108,  111,   99, // ntZ..loc
770         97,  108,   73,    0,   17,  109,   97,  120, // alI..max
771         68,  105,  102,  102,   69,  118,  101,  110, // DiffEven
772        116,   67,  111,  117,  110,  116,   90,    0, // tCountZ.
773         10,  112,  101,  114,  115,  105,  115,  116, // .persist
774        101,  110,  116,   90,    0,    8,  114,  101, // entZ..re
775         97,  100,   79,  110,  108,  121,   73,    0, // adOnlyI.
776          4,  116,  121,  112,  101,   76,    0,   14, // .typeL..
777        101,  118,   80,  101,  114,  105,  111,  100, // evPeriod
778         83,  117,   98,  115,  101,  116,  116,    0, // Subsett.
779         19,   76,  106,   97,  118,   97,   47,  117, // .Ljava/u
780        116,  105,  108,   47,   69,  110,  117,  109, // til/Enum
781         83,  101,  116,   59,   76,    0,    4,  110, // Set;L..n
782         97,  109,  101,  116,    0,   18,   76,  106, // amet..Lj
783         97,  118,   97,   47,  108,   97,  110,  103, // ava/lang
784         47,   83,  116,  114,  105,  110,  103,   59, // /String;
785        120,  112,    1,    0,    0,    0,    0,  101, // xp.....e
786          1,    0,    0,    0,    0,    2,  112,  116, // ......pt
787          0,   18,  116,  101,  115,  116,   83,  101, // ..testSe
788        114,   46,  115,  116,  114,  105,  110,  103, // r.string
789         46,  118,   97,  108,  126,  114,    0,   38, // .val~r.&
790        111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
791         46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
792        114,   67,  111,  114,  101,   46,  118,   97, // rCore.va
793        114,  115,   46,   69,  118,  101,  110,  116, // rs.Event
794         80,  101,  114,  105,  111,  100,    0,    0, // Period..
795          0,    0,    0,    0,    0,    0,   18,    0, // ........
796          0,  120,  114,    0,   14,  106,   97,  118, // .xr..jav
797         97,   46,  108,   97,  110,  103,   46,   69, // a.lang.E
798        110,  117,  109,    0,    0,    0,    0,    0, // num.....
799          0,    0,    0,   18,    0,    0,  120,  112, // ......xp
800        116,    0,    5,   86,   76,   79,   78,   71, // t..VLONG
801        117,  114,    0,   19,   91,   76,  106,   97, // ur..[Lja
802        118,   97,   46,  108,   97,  110,  103,   46, // va.lang.
803         79,   98,  106,  101,   99,  116,   59, -112, // Object;.
804        -50,   88,  -97,   16,  115,   41,  108,    2, // .X..s)l.
805          0,    0,  120,  112,    0,    0,    0,    2, // ..xp....
806        115,  114,    0,   26,  111,  114,  103,   46, // sr..org.
807        104,  100,   46,  100,   46,  112,  103,   50, // hd.d.pg2
808        107,   46,  115,  118,  114,   67,  111,  114, // k.svrCor
809        101,   46,   78,   97,  109,  101,   38,  -44, // e.Name&.
810        -30,   17,    1,  -80,  121,  -16,    3,    0, // ....y...
811          2,   83,    0,   14,  116,  101,  114,  109, // .S..term
812        105,  110,  105,   76,  101,  110,  103,  116, // iniLengt
813        104,  115,   76,    0,    4,  112,  114,  101, // hsL..pre
814        118,  116,    0,   28,   76,  111,  114,  103, // vt..Lorg
815         47,  104,  100,   47,  100,   47,  112,  103, // /hd/d/pg
816         50,  107,   47,  115,  118,  114,   67,  111, // 2k/svrCo
817        114,  101,   47,   78,   97,  109,  101,   59, // re/Name;
818        120,  112,    0,    0,  112,  119,   13,   12, // xp..pw..
819        100,  102,  103,  116,  114,   54,   55,  107, // dfgtr67k
820        106,  104,  102,  104,  120,  115,  113,    0, // jhfhxsq.
821        126,    0,   19,    0,    0,  112,  119,   11, // ~....pw.
822         10,   52,   53,  100,  103,  106,  121,  116, // .45dgjyt
823        114,  101,  102,  120,  120, // refxx
824       };
825    
826        /**Test that we can succesfully create and (de)serialise event container objects...
827         * In particular we ensure that we can recover data in older formats where necessary
828         * so that we don't lose hard-to-replace historic data.
829         */
830        public static void testEventVariableValues()
831            throws Exception
832            {
833            // Check that we can deserialise at least one frozen serialised (String) non-standard value.
834            // This is a test of robustness of both the definition and the value objects.
835            final SimpleVariableDefinition newDef = new SimpleVariableDefinition("testSer.string.val",
836                                                                                 SimpleVariableDefinition.TYPE_STRING,
837                                                                                 false, // Global.
838                                                                                 true,  // Persistent.
839                                                                                 false, // Read-write.
840                                                                                 true, 101, null);
841            final Object values[] = { evvTestString2, evvTestString1 };
842            final int counts[] = { 2, 1 };
843    //        final Map<Object, EventVariableValue.ValueInfo> map = new HashMap<Object, EventVariableValue.ValueInfo>();
844    //        map.put(evvTestString1, new EventVariableValue.ValueInfo(1, 1));
845    //        map.put(evvTestString2, new EventVariableValue.ValueInfo(0, 2));
846            final EventVariableValue evv = new EventVariableValue(true, // Authoritative...
847                                                                  newDef,
848                                                                  EventPeriod.VLONG,
849                                                                  1,
850                                                                  evv_TOTAL_EVENT_COUNT,
851                                                                  values, counts);
852    
853            // Do some simple tests on the constructed value.
854            assertEquals("rank order should be observed", Arrays.asList(new Object[]{evvTestString2,evvTestString1}), evv.getDistinctValuesInRankOrder());
855            assertEquals("sort order should be observed", Arrays.asList(new Object[]{evvTestString1,evvTestString2}), evv.getDistinctValuesSorted());
856    
857            // Make a deep copy via deserialisation...
858            final EventVariableValue evvDS = (EventVariableValue)
859                    checkSerialisationPreservesEquality(evv);
860            // Reconstruct from byte[] format before the internal format change...
861            final EventVariableValue evvFrozen20050130 = (EventVariableValue)
862                deserialiseFromByteArray(serData_evv1_20050130_1748);
863            // Reconstruct from byte[] more compact format change...
864            final EventVariableValue evvFrozen20050131 = (EventVariableValue)
865                deserialiseFromByteArray(serData_evv1_20050131_1512);
866            // Reconstruct from byte[] even more compact format change (Name in place of String).
867            final EventVariableValue evvFrozen20090806 = (EventVariableValue)
868                deserialiseFromByteArray(serData_evv1_20090806);
869    
870            // Perform the same tests on all copies of the value.
871            final EventVariableValue evvs[] = { evv, evvDS, evvFrozen20050130, evvFrozen20050131, evvFrozen20090806 };
872            for(final EventVariableValue e : evvs)
873                {
874                assertTrue("EVV must equal itself", e.equals(e));
875                assertTrue("EVV must equal main copy", e.equals(evv));
876                assertEquals("Total event count must be correct", evv_TOTAL_EVENT_COUNT, e.getTotalEventCount());
877                assertEquals("Total different events must be correct", 2, e.getTotalDistinctValues());
878                assertEquals("Total count of first value must be correct", 1, e.getCount(evvTestString1));
879                assertEquals("Total count of second value must be correct", 2, e.getCount(evvTestString2));
880                assertEquals("Rank of first value must be correct", 1, e.getRank(evvTestString1));
881                assertEquals("Rank of second value must be correct", 0, e.getRank(evvTestString2));
882                assertEquals("Rank of non-existent value must be correct", Integer.MAX_VALUE, e.getRank("not there"));
883                }
884            }
885    
886        /**Empty ROByteArray (ie wrapping a byte[0]). */
887        private static final byte serData_ROByteArray_EMPTY_20050522[/*92*/] = {
888         -84,  -19,    0,    5,  115,  114,    0,   33, // ....sr.!
889         111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
890          46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
891         114,   67,  111,  114,  101,   46,   82,   79, // rCore.RO
892          66,  121,  116,  101,   65,  114,  114,   97, // ByteArra
893         121,   52,  -45,  -14,   29,  -75,  -97, -121, // y4......
894         -40,    2,    0,    1,   91,    0,    7,  112, // ....[..p
895          97,  121,  108,  111,   97,  100,  116,    0, // ayloadt.
896           2,   91,   66,  120,  112,  117,  114,    0, // .[Bxpur.
897           2,   91,   66,  -84,  -13,   23,   -8,    6, // .[B.....
898           8,   84,  -32,    2,    0,    0,  120,  112, // .T....xp
899           0,    0,    0,    0, // ....
900        };
901    
902        /**Value to check compression is working and can be correctly undone even on non-ASCII/non-8-bit text. */
903        private static final String ROBA_compS1 = "The quick Brown fox jumped over the PM Blair [satire over, Ed] " +
904            "over and over and over and over and over again until he got bored... " +
905            "(And now here is the news in English: \u7777\u9231\u0000\r\n\t...)";
906    
907        /**On-the-wire format on ROBA_compS1. */
908        private static final byte serData_ROBA_compS1_20050522[/*233*/] = {
909         -84,  -19,    0,    5,  115,  114,    0,   33, // ....sr.!
910         111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
911          46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
912         114,   67,  111,  114,  101,   46,   82,   79, // rCore.RO
913          66,  121,  116,  101,   65,  114,  114,   97, // ByteArra
914         121,   52,  -45,  -14,   29,  -75,  -97, -121, // y4......
915         -40,    2,    0,    1,   91,    0,    7,  112, // ....[..p
916          97,  121,  108,  111,   97,  100,  116,    0, // ayloadt.
917           2,   91,   66,  120,  112,  117,  114,    0, // .[Bxpur.
918           2,   91,   66,  -84,  -13,   23,   -8,    6, // .[B.....
919           8,   84,  -32,    2,    0,    0,  120,  112, // .T....xp
920           0,    0,    0, -115,   99,  -40,   25, -110, // ....c...
921        -111,  -86,   80,   88, -102, -103, -100,  -83, // ..PX....
922         -32,   84, -108,   95,  -98,  -89, -112, -106, // .T._....
923          95,  -95, -112,   85, -102,   91, -112, -102, // _..U.[..
924         -94, -112,   95, -106,   90,  -92,   80,    2, // .._.Z.P.
925        -108,   15,  -16,   85,  112,  -54,   73,  -52, // ...Up.I.
926          44,   82, -120,   46,   78,   44,  -55,   44, // ,R..N,.,
927          74,    5,  -53,  -24,   40,  -72,  -90,  -60, // J...(...
928          66,  -44,   36,  -26,  -91,   16,  102,  -92, // B.$...f.
929          39,  102,  -26,   41, -108,  -26, -107,  100, // 'f.)...d
930         -26,   40,    0, -115,   76,  -49,   47,   81, // .(..L./Q
931          72,  -54,   47,   74,   77,  -47,  -45,  -45, // H./JM...
932          83,  -48,  112,    4,  -86,  -54,  -53,   47, // S.p..../
933           7,   74,    0,   13,  -49,   44,    6,   91, // .J...,.[
934        -102, -105,   90,   94,  -84,    0,  -44,  -30, // ..Z^....
935        -102, -105,  -98, -109,   89, -100,   97,  -91, // ....Y.a.
936         -16,  124,  -18,  -10, -105,   29,   27,   15, // .|......
937          52,  -16,  114,  113,    2,   53,  105,    2, // 4.rq.5i.
938           0, // .
939        };
940    
941        /**Test handling of ROByteArray.
942         */
943        public static void testROByteArray()
944            throws Exception
945            {
946            //assertImmutable(ROByteArray.class);
947    
948            // Check empty instance can be deserialised and is instance controlled!
949            assertEquals("EMPTY ROByteArray must be deserialised correctly.",
950                         ROByteArray.EMPTY, checkSerialisationPreservesEquality(ROByteArray.EMPTY));
951            assertSame("EMPTY ROByteArray must be deserialised as itself!",
952                         ROByteArray.EMPTY, checkSerialisationPreservesEquality(ROByteArray.EMPTY));
953            // Reconstruct from byte[] format.
954            final ROByteArray emptyDeSer = (ROByteArray)
955                deserialiseFromByteArray(serData_ROByteArray_EMPTY_20050522);
956            assertEquals("Must be able to deserialise original on-the-wire format (EMPTY)",
957                         ROByteArray.EMPTY, emptyDeSer);
958            assertEquals("Must get back empty array on deserialisation", 0, emptyDeSer.length());
959    
960            // Check non-empty instance can be (de)serialised and (de)compressed.
961            final ROByteArray c1 = ROByteArray.compressFromString(ROBA_compS1);
962            assertEquals("Compressable String in ROByteArray must be deserialised correctly.",
963                         c1, checkSerialisationPreservesEquality(c1));
964            final ROByteArray c1DeSer = (ROByteArray)
965                deserialiseFromByteArray(serData_ROBA_compS1_20050522);
966            assertEquals("Must be able to deserialise original on-the-wire format (non-empty, compressed String)",
967                         c1, c1DeSer);
968            assertEquals("Must be able to extract String from serialised form",
969                         ROBA_compS1, ROByteArray.uncompressToString(c1DeSer));
970            }
971    
972        /**Tests of accessions of serialisation of AccessionData.
973         * This is both for Java serialisation and XML format.
974         */
975        public static void testAccessionDataSer()
976            throws Exception
977            {
978            assertSame("deserialising EMPTY should give object == EMPTY",
979                       checkSerialisationPreservesEquality(AccessionData.EMPTY),
980                       AccessionData.EMPTY);
981    
982            // Check that we can (de)serialise via Java native and XML formats.
983            final int NUM_TESTS = 10;
984            for(int i = NUM_TESTS; --i >= 0; )
985                {
986                final byte[] dummyMD5Data = new byte[16];
987                rnd.nextBytes(dummyMD5Data);
988                final boolean b1 = rnd.nextBoolean();
989                final boolean b2 = rnd.nextBoolean();
990                final boolean b3 = rnd.nextBoolean();
991                final boolean b4 = rnd.nextBoolean();
992                final AccessionData ad = new AccessionData(
993                    b1 ? null : (System.currentTimeMillis()),
994                    b2 ? null : (new Long((rnd.nextLong() >>> 1) | 1)),
995                    b3 ? null : (new Integer(rnd.nextInt())),
996                    b4 ? null : (new ROByteArray(dummyMD5Data)));
997    
998                // Test native-format (de)serialisation...
999                checkSerialisationPreservesEquality(ad);
1000    
1001                // Test serialisation via XML format.
1002                final String xml = TextUtils.toXML(ad.getAsDOM(), false, true);
1003    if(i == 0) { System.out.println("[AccessionData XML example: "+xml+".]"); }
1004                assertEquals("conversion to XML and back should preserve equality",
1005                             ad,
1006                             AccessionData.parseFromXML(xml));
1007                }
1008            }
1009    
1010        /**On-the-wire format of Thumbnail. */
1011        private static final byte serData_Thumbnail_20060704[/*199*/] = {
1012            -84,  -19,    0,    5,  115,  114,    0,   49, // ....sr.1
1013            111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1014             46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1015            114,   67,  111,  114,  101,   46,   69,  120, // rCore.Ex
1016            104,  105,   98,  105,  116,   84,  104,  117, // hibitThu
1017            109,   98,  110,   97,  105,  108,  115,   36, // mbnails$
1018             84,  104,  117,  109,   98,  110,   97,  105, // Thumbnai
1019            108,  -18,   63,  -36,   92,   71,   75,   76, // l.?.\GKL
1020            -46,    2,    0,    2,   91,    0,    4,  100, // ....[..d
1021             97,  116,   97,  116,    0,    2,   91,   66, // atat..[B
1022             76,    0,    5,  120,  121,   68,  105,  109, // L..xyDim
1023            116,    0,   20,   76,  106,   97,  118,   97, // t..Ljava
1024             47,   97,  119,  116,   47,   68,  105,  109, // /awt/Dim
1025            101,  110,  115,  105,  111,  110,   59,  120, // ension;x
1026            112,  117,  114,    0,    2,   91,   66,  -84, // pur..[B.
1027            -13,   23,   -8,    6,    8,   84,  -32,    2, // .....T..
1028              0,    0,  120,  112,    0,    0,    0,    3, // ..xp....
1029              1,    2,    3,  115,  114,    0,   18,  106, // ...sr..j
1030             97,  118,   97,   46,   97,  119,  116,   46, // ava.awt.
1031             68,  105,  109,  101,  110,  115,  105,  111, // Dimensio
1032            110,   65, -114,  -39,  -41,  -84,   95,   68, // nA...._D
1033             20,    2,    0,    2,   73,    0,    6,  104, // ....I..h
1034            101,  105,  103,  104,  116,   73,    0,    5, // eightI..
1035            119,  105,  100,  116,  104,  120,  112,    0, // widthxp.
1036              0,    0,    4,    0,    0,    0,    3, // .......
1037            };
1038    
1039        /**Test that we can (de)serialise Thumbnail data OK. */
1040        public static void testThumbnailSer()
1041            throws Exception
1042            {
1043            //assertImmutable(ExhibitThumbnails.Thumbnail.class);
1044    
1045            final Dimension dim1 = new Dimension(3, 4);
1046            final ExhibitThumbnails.Thumbnail tn1 =
1047                new ExhibitThumbnails.Thumbnail(new byte[]{1,2,3}, dim1);
1048            checkSerialisationPreservesEquality(tn1);
1049    
1050            final ExhibitThumbnails.Thumbnail tn1Frozen20060704 = (ExhibitThumbnails.Thumbnail)
1051                deserialiseFromByteArray(serData_Thumbnail_20060704);
1052            assertEquals("Must preserve equality when deserialised", tn1, tn1Frozen20060704);
1053            }
1054    
1055        /**Test the robustness of our decompression routines in conjunction with deserialization.
1056         * We expect clean failures rather than hangs or messy crashes,
1057         * whatever junk is thrown at the decompressors.
1058         */
1059        public static void testDecompDeserRobustness()
1060            {
1061            // We construct various badly-broken samples of input data.
1062            final byte randomRubbish[] = new byte[rnd.nextInt(1<<18)];
1063            rnd.nextBytes(randomRubbish);
1064            final byte[][] testData = {
1065                            new byte[0] /* Empty. */ ,
1066                            new byte[1] /* Impossible/invalid single zero byte for compressed results. */ ,
1067                            randomRubbish
1068                                     };
1069    
1070            for(final byte[] data : testData)
1071                {
1072                for(final CompressionLevel cl : CompressionLevel.values())
1073                    {
1074                    if(cl.getLevel() > GenUtils.MAX_SUPPORTED_COMPRESSION_LEVEL.getLevel())
1075                        {
1076                        Main.getOut().println("[Skipping test on unsupported compression level "+cl+"...]");
1077                        continue;
1078                        }
1079                    try
1080                        {
1081                        final ByteArrayInputStream bais = new ByteArrayInputStream(data);
1082                        final InputStream wis = GenUtils.wrapForDecompression(bais, cl);
1083                        final ObjectInputStream ois = new ObjectInputStream(wis);
1084                        ois.readObject();
1085                        }
1086                    catch(final IOException e)
1087                        {
1088                        // IOException is OK in face of garbage input.
1089                        }
1090                    catch(final ClassNotFoundException e)
1091                        {
1092                        // ClassNotFoundException is OK though rare in face of garbage input.
1093                        }
1094                    }
1095                }
1096            }
1097    
1098        /**Empty AEP delta instance. */
1099        private static final byte serData_AllExhibitPropertiesDelta_empty[/*408*/] = {
1100                -84,  -19,    0,    5,  115,  114,    0,   47, // ....sr./
1101                111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1102                 46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1103                114,   67,  111,  114,  101,   46,   65,  108, // rCore.Al
1104                108,   69,  120,  104,  105,   98,  105,  116, // lExhibit
1105                 80,  114,  111,  112,  101,  114,  116,  105, // Properti
1106                101,  115,   68,  101,  108,  116,   97,  119, // esDeltaw
1107                118, -113,   43,   63,  120,   56,   79,    3, // v.+?x8O.
1108                  0,    8,   74,    0,   24,  104,   97,  115, // ..J..has
1109                104,   78,  111,  116,   67,  104,   97,  110, // hNotChan
1110                103,  101,  100,   83,  105,  110,   99,  101, // gedSince
1111                 65,  102,  116,  101,  114,   73,    0,   15, // AfterI..
1112                108,  101,  110,  103,  116,  104,   65,   69, // lengthAE
1113                 73,   68,   65,  102,  116,  101,  114,   73, // IDAfterI
1114                  0,   16,  108,  101,  110,  103,  116,  104, // ..length
1115                 65,   69,   73,   68,   66,  101,  102,  111, // AEIDBefo
1116                114,  101,   74,    0,   16,  108,  111,  110, // reJ..lon
1117                103,   72,   97,  115,  104,   65,   69,   80, // gHashAEP
1118                 65,  102,  116,  101,  114,   74,    0,   17, // AfterJ..
1119                108,  111,  110,  103,   72,   97,  115,  104, // longHash
1120                 65,   69,   80,   66,  101,  102,  111,  114, // AEPBefor
1121                101,   74,    0,   18,  116,  105,  109,  101, // eJ..time
1122                115,  116,   97,  109,  112,   65,   69,   73, // stampAEI
1123                 68,   65,  102,  116,  101,  114,   74,    0, // DAfterJ.
1124                 19,  116,  105,  109,  101,  115,  116,   97, // .timesta
1125                109,  112,   65,   69,   73,   68,   66,  101, // mpAEIDBe
1126                102,  111,  114,  101,   76,    0,    9,  101, // foreL..e
1127                112,  103,  105,   65,  102,  116,  101,  114, // pgiAfter
1128                116,    0,   51,   76,  111,  114,  103,   47, // t.3Lorg/
1129                104,  100,   47,  100,   47,  112,  103,   50, // hd/d/pg2
1130                107,   47,  115,  118,  114,   67,  111,  114, // k/svrCor
1131                101,   47,   69,  120,  104,  105,   98,  105, // e/Exhibi
1132                116,   80,  114,  111,  112,  115,   71,  108, // tPropsGl
1133                111,   98,   97,  108,   73,  109,  109,  117, // obalImmu
1134                116,   97,   98,  108,  101,   59,  120,  112, // table;xp
1135                  0,    0,    0,    0,    0,    0,    0,    0, // ........
1136                  0,    0,    0,    0,    0,    0,    0,    0, // ........
1137                  0,    0,    0,    0,    0,    0,    0,    0, // ........
1138                  0,    0,    0,    0,    0,    0,    0,    0, // ........
1139                  0,    0,    0,    0,    0,    0,    0,    0, // ........
1140                  0,    0,    0,    0,    0,    0,    0,    0, // ........
1141                112,  117,  114,    0,   57,   91,   76,  111, // pur.9[Lo
1142                114,  103,   46,  104,  100,   46,  100,   46, // rg.hd.d.
1143                112,  103,   50,  107,   46,  115,  118,  114, // pg2k.svr
1144                 67,  111,  114,  101,   46,   65,  108,  108, // Core.All
1145                 69,  120,  104,  105,   98,  105,  116,   80, // ExhibitP
1146                114,  111,  112,  101,  114,  116,  105,  101, // ropertie
1147                115,   68,  101,  108,  116,   97,   36,   67, // sDelta$C
1148                104,   97,  110,  103,  101,   59,  -39,  -39, // hange;..
1149                 14,  -36,   97,   70,  -99,  -85,    2,    0, // ..aF....
1150                  0,  120,  112,    0,    0,    0,    0,  120, // .xp....x
1151               };
1152    
1153        /**Simple AllExhibitPropertiesDelta (de)serialisation tests.
1154         * While it is not promised that the serialised format for
1155         * AllExhibitPropertiesDelta will be stable indefinitely,
1156         * we want to make sure that we don't change it inadvertently,
1157         * which would prevent clients and servers exchanging it for example.
1158         */
1159        public static void testSerAllExhibitPropertiesDelta()
1160            throws Exception
1161            {
1162            final AllExhibitPropertiesDelta empty = new AllExhibitPropertiesDelta();
1163            checkObjectCanBeSerialisedAndDeserialised(empty);
1164    
1165            // Check that we can deserialise a frozen instance.
1166            final AllExhibitPropertiesDelta aepd1 = (AllExhibitPropertiesDelta)
1167                deserialiseFromByteArray(serData_AllExhibitPropertiesDelta_empty);
1168            // Test sample field(s).
1169            assertEquals("Fields must have correct value", 0, aepd1.hashNotChangedSinceAfter);
1170            assertEquals("Fields must have correct value", 0, aepd1.lengthAEIDBefore);
1171            assertEquals("Fields must have correct value", 0, aepd1.lengthAEIDAfter);
1172            }
1173    
1174        /**Sample input String values for Compact7BitString tests.
1175         * These values include hard/edge cases and realistic sample data.
1176         * <p>
1177         * These are tested individually and all together in one stream.
1178         */
1179        private static final String[] TEST_C7BS_DATA =
1180            {
1181            "prefix1 prefix1suffix prefix2 prefix2suffix prefix2suffix" /* Frozen in serialsed test cases.  Hard case for partial token matching. */,
1182            "" /* The empty string is one edge case. */,
1183            "\0" /* A single null/control character is potentially tricky. */,
1184            "abc abc" /* Short text with one repeat. */,
1185            "abc abc abc abc  abc  abc" /* Short text with some repeats. */,
1186            "Repeated internal    sequences\r\n\r\nof various sorts.\r\nBanana, banadana?\r\n------\r\n              0,    0,    0,    0,    0,    0,    0,    0, // ........",
1187            "compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression compression" /* Highly compressable text. */,
1188            "Some simple English text.",
1189            "Some simple English text\r\ncontaining line-\r\nbreaks and\t\ttabs but no easy repeats.",
1190            "<sample><tag name=\"X Resolution\" value=\"72 dots per inch\"/><tag name=\"t2\" value=\"3.141\"/><tag name=\"Y Resolution\" value=\"72 dots per inch\"/><tag name=\"Exposure Program\" value=\"Program normal\"></sample>",
1191            "<sample><tag name=\"X Resolution\" value=\"72 dots per inch\"/><tag name=\"t2\" value=\"2.1828\"/><tag name=\"Y Resolution\" value=\"72 dots per inch\"/><tag name=\"Exposure Program\" value=\"Program normal\"></sample>",
1192            "<p class=MsoNormal><span lang=EN-US style='mso-ansi-language:EN-US'>Simp<o:p></o:p></span></p><p class=MsoNormal><span style='font-family:Arial'>Asia Pac &#20122; &#22826; &#21306;<o:p></o:p></span></p><p class=MsoNormal><span style='font-family:Arial'><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></span></p>",
1193            "<h2>Metadata</h2><dl compact><dt><b>metadata</b><dd><dl compact><dt><b>image</b><dd><dl compact><dt><b>javax_imageio_1.0</b><dd><dl compact><dt><b>Chroma</b><dd><dl compact><dt><b>ColorSpaceType</b> name=\"YCbCr\"</dl><dl compact><dt><b>NumChannels</b> value=\"3\"</dl></dl><dl compact><dt><b>Compression</b><dd><dl compact><dt><b>CompressionTypeName</b> value=\"JPEG\"</dl><dl compact><dt><b>Lossless</b> value=\"false\"</dl><dl compact><dt><b>NumProgressiveScans</b> value=\"1\"</dl></dl><dl compact><dt><b>Dimension</b><dd><dl compact><dt><b>ImageOrientation</b> value=\"normal\"</dl></dl></dl></dl><dl compact><dt><b>native</b><dd><dl compact><dt><b>EXIF</b><dd><dl compact><dt><b>tag</b> name=\"Make\" value=\"SONY\"</dl><dl compact><dt><b>tag</b> name=\"Model\" value=\"DSC-F828\"</dl><dl compact><dt><b>tag</b> name=\"Orientation\" value=\"top, left side\"</dl><dl compact><dt><b>tag</b> name=\"X Resolution\" value=\"72 dots per inch\"</dl><dl compact><dt><b>tag</b> name=\"Y Resolution\" value=\"72 dots per inch\"</dl><dl compact><dt><b>tag</b> name=\"Resolution Unit\" value=\"Inch\"</dl><dl compact><dt><b>tag</b> name=\"Date/Time\" value=\"2005:11:22 13:35:58\"</dl><dl compact><dt><b>tag</b> name=\"YCbCr Positioning\" value=\"Datum point\"</dl><dl compact><dt><b>tag</b> name=\"Exposure Time\" value=\"1/60 sec\"</dl><dl compact><dt><b>tag</b> name=\"F-Number\" value=\"F3.2\"</dl><dl compact><dt><b>tag</b> name=\"Exposure Program\" value=\"Program normal\"</dl><dl compact><dt><b>tag</b> name=\"ISO Speed Ratings\" value=\"64\"</dl><dl compact><dt><b>tag</b> name=\"Exif Version\" value=\"2.20\"</dl><dl compact><dt><b>tag</b> name=\"Date/Time Original\" value=\"2005:11:22 13:35:58\"</dl><dl compact><dt><b>tag</b> name=\"Date/Time Digitized\" value=\"2005:11:22 13:35:58\"</dl><dl compact><dt><b>tag</b> name=\"Components Configuration\" value=\"YCbCr\"</dl><dl compact><dt><b>tag</b> name=\"Compressed Bits Per Pixel\" value=\"8 bits/pixel\"</dl><dl compact><dt><b>tag</b> name=\"Exposure Bias Value\" value=\"0\"</dl><dl compact><dt><b>tag</b> name=\"Max Aperture Value\" value=\"F2\"</dl><dl compact><dt><b>tag</b> name=\"Metering Mode\" value=\"Center weighted average\"</dl><dl compact><dt><b>tag</b> name=\"Light Source\" value=\"Unknown\"</dl><dl compact><dt><b>tag</b> name=\"Flash\" value=\"Unknown (16)\"</dl><dl compact><dt><b>tag</b> name=\"Focal Length\" value=\"9.5 mm\"</dl><dl compact><dt><b>tag</b> name=\"FlashPix Version\" value=\"1.00\"</dl><dl compact><dt><b>tag</b> name=\"Color Space\" value=\"sRGB\"</dl><dl compact><dt><b>tag</b> name=\"Exif Image Width\" value=\"3264 pixels\"</dl><dl compact><dt><b>tag</b> name=\"Exif Image Height\" value=\"2448 pixels\"</dl><dl compact><dt><b>tag</b> name=\"File Source\" value=\"Digital Still Camera (DSC)\"</dl><dl compact><dt><b>tag</b> name=\"Scene Type\" value=\"Directly photographed image\"</dl><dl compact><dt><b>tag</b> name=\"Unknown tag (0xa401)\" value=\"0\"</dl><dl compact><dt><b>tag</b> name=\"Unknown tag (0xa402)\" value=\"0\"</dl><dl compact><dt><b>tag</b> name=\"Unknown tag (0xa403)\" value=\"0\"</dl><dl compact><dt><b>tag</b> name=\"Unknown tag (0xa406)\" value=\"0\"</dl><dl compact><dt><b>tag</b> name=\"Unknown tag (0xa408)\" value=\"0\"</dl><dl compact><dt><b>tag</b> name=\"Unknown tag (0xa409)\" value=\"0\"</dl><dl compact><dt><b>tag</b> name=\"Unknown tag (0xa40a)\" value=\"0\"</dl><dl compact><dt><b>tag</b> name=\"Unknown tag (0xc4a5)\" value=\"PrintIM\"</dl><dl compact><dt><b>tag</b> name=\"Compression\" value=\"JPEG compression\"</dl><dl compact><dt><b>tag</b> name=\"Thumbnail Offset\" value=\"2486 bytes\"</dl><dl compact><dt><b>tag</b> name=\"Thumbnail Length\" value=\"9657 bytes\"</dl><dl compact><dt><b>tag</b> name=\"Thumbnail Data\" value=\"[9657 bytes of thumbnail data]\"</dl></dl></dl></dl><dl compact><dt><b>accessionData</b><dd><dl compact><dt><b>date</b> value=\"1132678851000\"</dl><dl compact><dt><b>size</b> value=\"3464887\"</dl><dl compact><dt><b>hash-CRC32</b> value=\"e697175\"</dl><dl compact><dt><b>hash-MD5</b> value=\"2fc4e2c7fd8ea3047d6bf9ae22df8f44\"</dl></dl>",
1194            "The Indian way apparently takes years of practice, whereas for the Irish version one may only need strong booze... Arrived over the Net by email.",
1195            "Even the drawstrings [draw-strings] are quite interesting in close-up [closeup].",
1196            "Hac&#305; Bekta&#351;-&#305 Veli is a famous 13th century Islamic mystic, philosopher and dervish.&nbsp;&nbsp; His tomb and monestary are in the town of Hacibekta&#351;, which is named after him.&nbsp;&nbsp; Hac&#305; Bekta&#351;-&#305 Veli was born and educated in Khorasan (north-east Iran); he was the grandson of Sheik Ahmet.&nbsp;&nbsp; After his pilgrimage to Mecca, he travelled around the middle east, finally coming to Anatolia in a period of political and economic turmoil.&nbsp;&nbsp; Wishing to help restore unity he settled here and developed and taught his own approach to being a pure Moslem.&nbsp;&nbsp; This approach was based on four tenets: love of God (the only way to attain maturity and peace); focus on substance rather than on the superficial (e.g. God does not see your actions, he sees your intentions); love and unity among people (the only things that illuminate your way are devine and human love); and the power of sanctity (you should seek God within, not externally).&nbsp;&nbsp; He particularly taught tolerance and equality for all through love, and at it's heart his philosophy incorporates the same substance as the Universal Declaration of Human Rights of 1948.&nbsp;&nbsp; Through the work of Hac&#305; Bekta&#351;-&#305 Veli unity was restored to the Turks of Anatolia, and the Turkish language became the language of scholarship and law (instead of Arabic or Persian).<BR> The interior of Hac&#305; Bekta&#351;-&#305 Veli's tomb chamber is an interesting shape.&nbsp;&nbsp; At the bottom the room is square; higher up it is octagonal; and at the top there is a circular dome.&nbsp;&nbsp; This is essentially the same shape as the Pharos, the ancient lighthouse at Alexandria, Egypt.&nbsp;&nbsp; I've seen this shape in other places too, but I don't know whether the Pharos was the original use of this shape, or whether the shape is older than that.&nbsp;&nbsp; I'm certain that there must be some meaning behind the shape, but I'm afraid I don't know it.",
1197            "<image><javax_imageio_1.0><Chroma><ColorSpaceType name=\"RGB\"/><NumChannels value=\"4\"/><Gamma value=\"0.45453998\"/><BlackIsZero value=\"true\"/><Palette><PaletteEntry alpha=\"255\" blue=\"255\" green=\"255\" index=\"0\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"255\" index=\"1\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"255\" index=\"2\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"255\" index=\"3\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"255\" index=\"4\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"255\" index=\"5\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"204\" index=\"6\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"204\" index=\"7\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"204\" index=\"8\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"204\" index=\"9\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"204\" index=\"10\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"204\" index=\"11\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"153\" index=\"12\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"153\" index=\"13\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"153\" index=\"14\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"153\" index=\"15\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"153\" index=\"16\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"153\" index=\"17\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"102\" index=\"18\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"102\" index=\"19\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"102\" index=\"20\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"102\" index=\"21\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"102\" index=\"22\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"102\" index=\"23\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"51\" index=\"24\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"51\" index=\"25\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"51\" index=\"26\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"51\" index=\"27\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"51\" index=\"28\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"51\" index=\"29\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"0\" index=\"30\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"0\" index=\"31\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"0\" index=\"32\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"0\" index=\"33\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"0\" index=\"34\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"0\" index=\"35\" red=\"255\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"255\" index=\"36\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"255\" index=\"37\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"255\" index=\"38\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"255\" index=\"39\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"255\" index=\"40\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"255\" index=\"41\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"204\" index=\"42\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"204\" index=\"43\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"204\" index=\"44\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"204\" index=\"45\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"204\" index=\"46\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"204\" index=\"47\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"153\" index=\"48\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"153\" index=\"49\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"153\" index=\"50\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"153\" index=\"51\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"153\" index=\"52\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"153\" index=\"53\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"102\" index=\"54\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"102\" index=\"55\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"102\" index=\"56\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"102\" index=\"57\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"102\" index=\"58\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"102\" index=\"59\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"51\" index=\"60\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"51\" index=\"61\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"51\" index=\"62\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"51\" index=\"63\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"51\" index=\"64\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"51\" index=\"65\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"0\" index=\"66\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"0\" index=\"67\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"0\" index=\"68\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"0\" index=\"69\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"0\" index=\"70\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"0\" index=\"71\" red=\"204\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"255\" index=\"72\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"255\" index=\"73\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"255\" index=\"74\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"255\" index=\"75\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"255\" index=\"76\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"255\" index=\"77\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"204\" index=\"78\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"204\" index=\"79\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"204\" index=\"80\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"204\" index=\"81\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"204\" index=\"82\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"204\" index=\"83\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"153\" index=\"84\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"153\" index=\"85\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"153\" index=\"86\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"153\" index=\"87\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"153\" index=\"88\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"153\" index=\"89\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"102\" index=\"90\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"102\" index=\"91\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"102\" index=\"92\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"102\" index=\"93\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"102\" index=\"94\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"102\" index=\"95\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"51\" index=\"96\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"51\" index=\"97\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"51\" index=\"98\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"51\" index=\"99\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"51\" index=\"100\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"51\" index=\"101\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"0\" index=\"102\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"0\" index=\"103\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"0\" index=\"104\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"0\" index=\"105\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"0\" index=\"106\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"0\" index=\"107\" red=\"153\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"255\" index=\"108\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"255\" index=\"109\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"255\" index=\"110\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"255\" index=\"111\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"255\" index=\"112\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"255\" index=\"113\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"204\" index=\"114\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"204\" index=\"115\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"204\" index=\"116\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"204\" index=\"117\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"204\" index=\"118\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"204\" index=\"119\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"153\" index=\"120\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"153\" index=\"121\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"153\" index=\"122\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"153\" index=\"123\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"153\" index=\"124\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"153\" index=\"125\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"102\" index=\"126\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"102\" index=\"127\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"102\" index=\"128\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"102\" index=\"129\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"102\" index=\"130\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"102\" index=\"131\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"51\" index=\"132\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"51\" index=\"133\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"51\" index=\"134\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"51\" index=\"135\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"51\" index=\"136\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"51\" index=\"137\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"0\" index=\"138\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"0\" index=\"139\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"0\" index=\"140\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"0\" index=\"141\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"0\" index=\"142\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"0\" index=\"143\" red=\"102\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"255\" index=\"144\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"255\" index=\"145\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"255\" index=\"146\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"255\" index=\"147\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"255\" index=\"148\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"255\" index=\"149\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"204\" index=\"150\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"204\" index=\"151\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"204\" index=\"152\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"204\" index=\"153\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"204\" index=\"154\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"204\" index=\"155\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"153\" index=\"156\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"153\" index=\"157\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"153\" index=\"158\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"153\" index=\"159\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"153\" index=\"160\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"153\" index=\"161\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"102\" index=\"162\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"102\" index=\"163\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"102\" index=\"164\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"102\" index=\"165\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"102\" index=\"166\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"102\" index=\"167\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"51\" index=\"168\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"51\" index=\"169\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"51\" index=\"170\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"51\" index=\"171\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"51\" index=\"172\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"51\" index=\"173\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"0\" index=\"174\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"0\" index=\"175\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"0\" index=\"176\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"0\" index=\"177\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"0\" index=\"178\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"0\" index=\"179\" red=\"51\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"255\" index=\"180\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"255\" index=\"181\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"255\" index=\"182\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"255\" index=\"183\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"255\" index=\"184\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"255\" index=\"185\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"204\" index=\"186\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"204\" index=\"187\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"204\" index=\"188\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"204\" index=\"189\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"204\" index=\"190\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"204\" index=\"191\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"153\" index=\"192\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"153\" index=\"193\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"153\" index=\"194\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"153\" index=\"195\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"153\" index=\"196\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"153\" index=\"197\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"102\" index=\"198\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"102\" index=\"199\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"102\" index=\"200\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"102\" index=\"201\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"102\" index=\"202\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"102\" index=\"203\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"51\" index=\"204\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"51\" index=\"205\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"51\" index=\"206\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"51\" index=\"207\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"51\" index=\"208\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"51\" index=\"209\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"0\" index=\"210\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"204\" green=\"0\" index=\"211\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"153\" green=\"0\" index=\"212\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"102\" green=\"0\" index=\"213\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"51\" green=\"0\" index=\"214\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"0\" green=\"0\" index=\"215\" red=\"0\"/><PaletteEntry alpha=\"255\" blue=\"255\" green=\"254\" index=\"216\" red=\"254\"/><PaletteEntry alpha=\"255\" blue=\"7\" green=\"6\" index=\"217\" red=\"6\"/><PaletteEntry alpha=\"255\" blue=\"1\" green=\"6\" index=\"218\" red=\"6\"/><PaletteEntry alpha=\"255\" blue=\"1\" green=\"14\" index=\"219\" red=\"2\"/><PaletteEntry alpha=\"255\" blue=\"46\" green=\"15\" index=\"220\" red=\"46\"/><PaletteEntry alpha=\"255\" blue=\"201\" green=\"184\" index=\"221\" red=\"201\"/><PaletteEntry alpha=\"255\" blue=\"72\" green=\"51\" index=\"222\" red=\"69\"/><PaletteEntry alpha=\"255\" blue=\"232\" green=\"219\" index=\"223\" red=\"221\"/><PaletteEntry alpha=\"255\" blue=\"78\" green=\"16\" index=\"224\" red=\"11\"/><PaletteEntry alpha=\"255\" blue=\"46\" green=\"13\" index=\"225\" red=\"10\"/><PaletteEntry alpha=\"255\" blue=\"78\" green=\"39\" index=\"226\" red=\"36\"/><PaletteEntry alpha=\"255\" blue=\"91\" green=\"81\" index=\"227\" red=\"79\"/><PaletteEntry alpha=\"255\" blue=\"201\" green=\"183\" index=\"228\" red=\"179\"/><PaletteEntry alpha=\"255\" blue=\"24\" green=\"13\" index=\"229\" red=\"10\"/><PaletteEntry alpha=\"255\" blue=\"127\" green=\"83\" index=\"230\" red=\"71\"/><PaletteEntry alpha=\"255\" blue=\"217\" green=\"210\" index=\"231\" red=\"208\"/><PaletteEntry alpha=\"255\" blue=\"141\" green=\"136\" index=\"232\" red=\"132\"/><PaletteEntry alpha=\"255\" blue=\"178\" green=\"171\" index=\"233\" red=\"165\"/><PaletteEntry alpha=\"255\" blue=\"248\" green=\"247\" index=\"234\" red=\"246\"/><PaletteEntry alpha=\"255\" blue=\"173\" green=\"153\" index=\"235\" red=\"132\"/><PaletteEntry alpha=\"255\" blue=\"92\" green=\"70\" index=\"236\" red=\"33\"/><PaletteEntry alpha=\"255\" blue=\"207\" green=\"200\" index=\"237\" red=\"184\"/><PaletteEntry alpha=\"255\" blue=\"47\" green=\"43\" index=\"238\" red=\"14\"/><PaletteEntry alpha=\"255\" blue=\"42\" green=\"74\" index=\"239\" red=\"38\"/><PaletteEntry alpha=\"255\" blue=\"13\" green=\"42\" index=\"240\" red=\"12\"/><PaletteEntry alpha=\"255\" blue=\"8\" green=\"24\" index=\"241\" red=\"9\"/><PaletteEntry alpha=\"255\" blue=\"113\" green=\"129\" index=\"242\" red=\"125\"/><PaletteEntry alpha=\"255\" blue=\"184\" green=\"201\" index=\"243\" red=\"200\"/><PaletteEntry alpha=\"255\" blue=\"15\" green=\"45\" index=\"244\" red=\"45\"/><PaletteEntry alpha=\"255\" blue=\"38\" green=\"69\" index=\"245\" red=\"82\"/><PaletteEntry alpha=\"255\" blue=\"117\" green=\"151\" index=\"246\" red=\"175\"/><PaletteEntry alpha=\"255\" blue=\"148\" green=\"162\" index=\"247\" red=\"172\"/><PaletteEntry alpha=\"255\" blue=\"178\" green=\"181\" index=\"248\" red=\"184\"/><PaletteEntry alpha=\"255\" blue=\"19\" green=\"29\" index=\"249\" red=\"77\"/><PaletteEntry alpha=\"255\" blue=\"181\" green=\"184\" index=\"250\" red=\"201\"/><PaletteEntry alpha=\"255\" blue=\"8\" green=\"9\" index=\"251\" red=\"229\"/><PaletteEntry alpha=\"255\" blue=\"11\" green=\"11\" index=\"252\" red=\"45\"/><PaletteEntry alpha=\"255\" blue=\"8\" green=\"8\" index=\"253\" red=\"24\"/><PaletteEntry alpha=\"255\" blue=\"8\" green=\"8\" index=\"254\" red=\"8\"/><PaletteEntry alpha=\"0\" blue=\"255\" green=\"255\" index=\"255\" red=\"255\"/></Palette></Chroma><Compression><CompressionTypeName value=\"deflate\"/><Lossless value=\"true\"/><NumProgressiveScans value=\"1\"/></Compression><Data><PlanarConfiguration value=\"PixelInterleaved\"/><SampleFormat value=\"Index\"/><BitsPerSample value=\"8 8 8 8\"/></Data><Dimension><PixelAspectRatio value=\"1.0\"/><ImageOrientation value=\"Normal\"/><HorizontalPixelSize value=\"0.35273367\"/><VerticalPixelSize value=\"0.35273367\"/></Dimension><Transparency><Alpha value=\"nonpremultipled\"/><TransparentColor/></Transparency></javax_imageio_1.0></image>",
1198            "<image><javax_imageio_1.0><Chroma><ColorSpaceType name=\"YCbCr\"/><NumChannels value=\"3\"/></Chroma><Compression><CompressionTypeName value=\"JPEG\"/><Lossless value=\"false\"/><NumProgressiveScans value=\"1\"/></Compression><Dimension><PixelAspectRatio value=\"1.0\"/><ImageOrientation value=\"normal\"/><HorizontalPixelSize value=\"0.254\"/><VerticalPixelSize value=\"0.254\"/></Dimension></javax_imageio_1.0></image>",
1199            "<image><javax_imageio_1.0><Chroma><ColorSpaceType name=\"YCbCr\"/><NumChannels value=\"3\"/></Chroma><Compression><CompressionTypeName value=\"JPEG\"/><Lossless value=\"false\"/><NumProgressiveScans value=\"1\"/></Compression><Dimension><ImageOrientation value=\"normal\"/></Dimension></javax_imageio_1.0></image><native><EXIF><tag name=\"Color Space\" value=\"sRGB\"/><tag name=\"Components Configuration\" value=\"YCbCr\"/><tag name=\"Compressed Bits Per Pixel\" value=\"8 bits/pixel\"/><tag name=\"Compression\" value=\"JPEG (old-style)\"/><tag name=\"Contrast\" value=\"None\"/><tag name=\"Custom Rendered\" value=\"Normal process\"/><tag name=\"Date/Time\" value=\"2005:04:18 17:19:32\"/><tag name=\"Date/Time Digitized\" value=\"2005:04:18 17:19:32\"/><tag name=\"Date/Time Original\" value=\"2005:04:18 17:19:32\"/><tag name=\"Exif Image Height\" value=\"480 pixels\"/><tag name=\"Exif Image Width\" value=\"640 pixels\"/><tag name=\"Exif Version\" value=\"2.20\"/><tag name=\"Exposure Bias Value\" value=\"0 EV\"/><tag name=\"Exposure Mode\" value=\"Auto exposure\"/><tag name=\"Exposure Program\" value=\"Program normal\"/><tag name=\"Exposure Time\" value=\"1/60 sec\"/><tag name=\"F-Number\" value=\"F4\"/><tag name=\"File Source\" value=\"Digital Still Camera (DSC)\"/><tag name=\"Flash\" value=\"Flash did not fire, auto\"/><tag name=\"FlashPix Version\" value=\"1.00\"/><tag name=\"Focal Length\" value=\"7.1 mm\"/><tag name=\"ISO Speed Ratings\" value=\"64\"/><tag name=\"Light Source\" value=\"Unknown\"/><tag name=\"Make\" value=\"SONY\"/><tag name=\"Max Aperture Value\" value=\"F2\"/><tag name=\"Metering Mode\" value=\"Center weighted average\"/><tag name=\"Model\" value=\"DSC-F828\"/><tag name=\"Orientation\" value=\"Top, left side (Horizontal / normal)\"/><tag name=\"Resolution Unit\" value=\"Inch\"/><tag name=\"Saturation\" value=\"None\"/><tag name=\"Scene Capture Type\" value=\"Standard\"/><tag name=\"Scene Type\" value=\"Directly photographed image\"/><tag name=\"Sharpness\" value=\"None\"/><tag name=\"Thumbnail Data\" value=\"[3071 bytes of thumbnail data]\"/><tag name=\"Thumbnail Length\" value=\"3071 bytes\"/><tag name=\"Thumbnail Offset\" value=\"2486 bytes\"/><tag name=\"Unknown tag (0xc4a5)\" value=\"80 114 105 110 116 73 77 0 48 50 53 48 0 0 2 0 2 0 1 0 0 0 1 1 0 0 0 0\"/><tag name=\"White Balance\" value=\"Auto white balance\"/><tag name=\"X Resolution\" value=\"72 dots per inch\"/><tag name=\"Y Resolution\" value=\"72 dots per inch\"/><tag name=\"YCbCr Positioning\" value=\"Datum point\"/></EXIF></native>",
1200            "<image><javax_imageio_1.0><Chroma><ColorSpaceType name=\"YCbCr\"/><NumChannels value=\"3\"/></Chroma><Compression><CompressionTypeName value=\"JPEG\"/><Lossless value=\"false\"/><NumProgressiveScans value=\"1\"/></Compression><Dimension><ImageOrientation value=\"normal\"/></Dimension></javax_imageio_1.0></image><native><EXIF><tag name=\"Color Space\" value=\"sRGB\"/><tag name=\"Components Configuration\" value=\"YCbCr\"/><tag name=\"Compression\" value=\"JPEG (old-style)\"/><tag name=\"Contrast\" value=\"None\"/><tag name=\"Custom Rendered\" value=\"Normal process\"/><tag name=\"Date/Time\" value=\"0000:00:00 00:00:00\"/><tag name=\"Date/Time Digitized\" value=\"0000:00:00 00:00:00\"/><tag name=\"Date/Time Original\" value=\"0000:00:00 00:00:00\"/><tag name=\"Digital Zoom Ratio\" value=\"1\"/><tag name=\"Exif Image Height\" value=\"1920 pixels\"/><tag name=\"Exif Image Width\" value=\"2560 pixels\"/><tag name=\"Exif Version\" value=\"2.20\"/><tag name=\"Exposure Bias Value\" value=\"0.3 EV\"/><tag name=\"Exposure Mode\" value=\"Manual exposure\"/><tag name=\"Exposure Program\" value=\"Program normal\"/><tag name=\"Exposure Time\" value=\"1/60 sec\"/><tag name=\"F-Number\" value=\"F3.2\"/><tag name=\"File Source\" value=\"Digital Still Camera (DSC)\"/><tag name=\"Flash\" value=\"Flash did not fire, auto\"/><tag name=\"FlashPix Version\" value=\"1.00\"/><tag name=\"Focal Length\" value=\"9.42 mm\"/><tag name=\"Gain Control\" value=\"Low gain down\"/><tag name=\"ISO Speed Ratings\" value=\"320\"/><tag name=\"Image Description\" value=\"OLYMPUS DIGITAL CAMERA         \"/><tag name=\"Light Source\" value=\"Unknown\"/><tag name=\"Make\" value=\"OLYMPUS OPTICAL CO.,LTD\"/><tag name=\"Max Aperture Value\" value=\"F2.8\"/><tag name=\"Metering Mode\" value=\"Multi-segment\"/><tag name=\"Model\" value=\"X-2,C-50Z       \"/><tag name=\"Orientation\" value=\"Top, left side (Horizontal / normal)\"/><tag name=\"Resolution Unit\" value=\"Inch\"/><tag name=\"Saturation\" value=\"None\"/><tag name=\"Scene Capture Type\" value=\"Standard\"/><tag name=\"Sharpness\" value=\"None\"/><tag name=\"Software\" value=\"28-1008                        \"/><tag name=\"Thumbnail Data\" value=\"[6228 bytes of thumbnail data]\"/><tag name=\"Thumbnail Length\" value=\"6228 bytes\"/><tag name=\"Thumbnail Offset\" value=\"7206 bytes\"/><tag name=\"Unknown tag (0xc4a5)\" value=\"80 114 105 110 116 73 77 0 48 50 53 48 0 0 20 0 1 0 20 0 20 0 2 0 1 0 0 0 3 0 -120 0 0 0 7 0 0 0 0 0 8 0 0 0 0 0 9 0 0 0 0 0 10 0 0 0 0 0 11 0 -48 0 0 0 12 0 0 0 0 0 13 0 0 0 0 0 14 0 -24 0 0 0 0 1 1 0 0 0 1 1 -1 0 0 0 2 1 -125 0 0 0 3 1 -128 0 0 0 4 1 -125 0 0 0 5 1 -125 0 0 0 6 1 -125 0 0 0 7 1 -128 -128 -128 0 16 1 -126 0 0 0 9 17 0 0 16 39 0 0 11 15 0 0 16 39 0 0 -105 5 0 0 16 39 0 0 -80 8 0 0 16 39 0 0 1 28 0 0 16 39 0 0 94 2 0 0 16 39 0 0 -117 0 0 0 16 39 0 0 -53 3 0 0 16 39 0 0 -27 27 0 0 16 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\"/><tag name=\"White Balance\" value=\"Auto white balance\"/><tag name=\"X Resolution\" value=\"72 dots per inch\"/><tag name=\"Y Resolution\" value=\"72 dots per inch\"/><tag name=\"YCbCr Positioning\" value=\"Datum point\"/></EXIF></native>",
1201            "I.A.N.A. is as I.A.N.A. does..." /* Repeated 1-char token sequences. */,
1202            "<dl compact><dt><b>metadata</b><dd><dl compact><dt><b>image</b><dd><dl compact><dt><b>javax_imageio_1.0</b><dd><dl compact><dt><b>Chroma</b><dd><dl compact><dt><b>ColorSpaceType</b> name=\"YCbCr\"</dl><dl compact><dt><b>NumChannels</b> value=\"3\"</dl></dl><dl compact><dt><b>Compression</b><dd><dl compact><dt><b>CompressionTypeName</b> value=\"JPEG\"</dl><dl compact><dt><b>Lossless</b> value=\"false\"</dl><dl compact><dt><b>NumProgressiveScans</b> value=\"1\"</dl></dl><dl compact><dt><b>Dimension</b><dd><dl compact><dt><b>PixelAspectRatio</b> value=\"1.0\"</dl><dl compact><dt><b>ImageOrientation</b> value=\"normal\"</dl><dl compact><dt><b>HorizontalPixelSize</b> value=\"0.26458332\"</dl><dl compact><dt><b>VerticalPixelSize</b> value=\"0.26458332\"</dl></dl></dl></dl><dl compact><dt><b>native</b><dd><dl compact><dt><b>EXIF</b><dd><dl compact><dt><b>tag</b> name=\"Color Space\" value=\"sRGB\"</dl><dl compact><dt><b>tag</b> name=\"Components Configuration\" value=\"YCbCr\"</dl><dl compact><dt><b>tag</b> name=\"Compressed Bits Per Pixel\" value=\"4 bits/pixel\"</dl><dl compact><dt><b>tag</b> name=\"Compression\" value=\"JPEG (old-style)\"</dl><dl compact><dt><b>tag</b> name=\"Custom Rendered\" value=\"Normal process\"</dl><dl compact><dt><b>tag</b> name=\"Date/Time\" value=\"2006:01:15 15:38:56\"</dl><dl compact><dt><b>tag</b> name=\"Date/Time Digitized\" value=\"2006:01:15 15:38:56\"</dl><dl compact><dt><b>tag</b> name=\"Date/Time Original\" value=\"2006:01:15 15:38:56\"</dl><dl compact><dt><b>tag</b> name=\"Exif Image Height\" value=\"960 pixels\"</dl><dl compact><dt><b>tag</b> name=\"Exif Image Width\" value=\"1280 pixels\"</dl><dl compact><dt><b>tag</b> name=\"Exif Version\" value=\"2.20\"</dl><dl compact><dt><b>tag</b> name=\"Exposure Bias Value\" value=\"0 EV\"</dl><dl compact><dt><b>tag</b> name=\"Exposure Mode\" value=\"Auto exposure\"</dl><dl compact><dt><b>tag</b> name=\"Exposure Program\" value=\"Program normal\"</dl><dl compact><dt><b>tag</b> name=\"Exposure Time\" value=\"1/200 sec\"</dl><dl compact><dt><b>tag</b> name=\"F-Number\" value=\"F5.2\"</dl><dl compact><dt><b>tag</b> name=\"File Source\" value=\"Digital Still Camera (DSC)\"</dl><dl compact><dt><b>tag</b> name=\"Flash\" value=\"Flash did not fire\"</dl><dl compact><dt><b>tag</b> name=\"FlashPix Version\" value=\"1.00\"</dl><dl compact><dt><b>tag</b> name=\"Focal Length\" value=\"23.7 mm\"</dl><dl compact><dt><b>tag</b> name=\"ISO Speed Ratings\" value=\"100\"</dl><dl compact><dt><b>tag</b> name=\"Light Source\" value=\"Unknown\"</dl><dl compact><dt><b>tag</b> name=\"Make\" value=\"SONY\"</dl><dl compact><dt><b>tag</b> name=\"Max Aperture Value\" value=\"F2.8\"</dl><dl compact><dt><b>tag</b> name=\"Metering Mode\" value=\"Multi-segment\"</dl><dl compact><dt><b>tag</b> name=\"Model\" value=\"DSC-P10\"</dl><dl compact><dt><b>tag</b> name=\"Orientation\" value=\"Top, left side (Horizontal / normal)\"</dl><dl compact><dt><b>tag</b> name=\"Resolution Unit\" value=\"Inch\"</dl><dl compact><dt><b>tag</b> name=\"Scene Capture Type\" value=\"Standard\"</dl><dl compact><dt><b>tag</b> name=\"Scene Type\" value=\"Directly photographed image\"</dl><dl compact><dt><b>tag</b> name=\"Thumbnail Data\" value=\"[4198 bytes of thumbnail data]\"</dl><dl compact><dt><b>tag</b> name=\"Thumbnail Length\" value=\"4198 bytes\"</dl><dl compact><dt><b>tag</b> name=\"Thumbnail Offset\" value=\"2342 bytes\"</dl><dl compact><dt><b>tag</b> name=\"Unknown tag (0xc4a5)\" value=\"80 114 105 110 116 73 77 0 48 50 53 48 0 0 2 0 2 0 1 0 0 0 1 1 0 0 0 0\"</dl><dl compact><dt><b>tag</b> name=\"White Balance\" value=\"Auto white balance\"</dl><dl compact><dt><b>tag</b> name=\"X Resolution\" value=\"72 dots per inch\"</dl><dl compact><dt><b>tag</b> name=\"Y Resolution\" value=\"72 dots per inch\"</dl><dl compact><dt><b>tag</b> name=\"YCbCr Positioning\" value=\"Datum point\"</dl></dl></dl></dl><dl compact><dt><b>accessionData</b><dd><dl compact><dt><b>date</b> value=\"1155636545000\"</dl><dl compact><dt><b>size</b> value=\"122672\"</dl><dl compact><dt><b>hash-CRC32</b> value=\"6cb4f395\"</dl><dl compact><dt><b>hash-MD5</b> value=\"1a8a965611c8171dca007b13937cd0d8\"</dl></dl>" /* Example HTML form of metadata. */ ,
1203            "<table cellpadding=0 border=1 cols=6 width=396><tr height=64 align=center><td width=64><a href=\"/_c/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-1-BG.jpg.html\"><img src=\"/_tn/sml/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-1-BG.jpg\" border=0 width=43 height=64 alt=\"Norway ~ -1-BG.jpg\"></a></td><td width=64><small>JPEG image<br /><a href=\"/_c/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-tweaked-1-BG.jpg.html\"><i>Norway ~  tweaked 1 BG.jpg</i></a></small></td><td width=64><a href=\"/_c/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-2-BG.jpg.html\"><img src=\"/_tn/sml/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-2-BG.jpg\" border=0 width=64 height=43 alt=\"Norway ~ -2-BG.jpg\"></a></td><td width=64><small>JPEG image<br /><a href=\"/_c/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-tweaked-2-BG.jpg.html\"><i>Norway ~  tweaked 2 BG.jpg</i></a></small></td><td width=64><a href=\"/_c/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-3-BG.jpg.html\"><img src=\"/_tn/sml/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-3-BG.jpg\" border=0 width=43 height=64 alt=\"Norway ~ -3-BG.jpg\"></a></td><td width=64><a href=\"/_c/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-tweaked-3-BG.jpg.html\"><img src=\"/_tn/sml/places-and-sights/_more2002/_more04/Norway-Flam-Myrdal-railway-Flamsbana-Kjosfossen-waterfall-tweaked-3-BG.jpg\" border=0 width=43 height=64 alt=\"Norway ~ -tweaked-3-BG.jpg\"></a></td></tr></table>",
1204            "<table cellpadding=0 border=1 cols=10 width=660><tr height=64 align=center><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-1-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-1-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -1-DHD.jpg\"></a></td><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-2-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-2-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -2-DHD.jpg\"></a></td><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-3-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-3-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -3-DHD.jpg\"></a></td><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-4-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-4-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -4-DHD.jpg\"></a></td><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-5-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-5-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -5-DHD.jpg\"></a></td><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-6-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-6-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -6-DHD.jpg\"></a></td><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-7-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-7-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -7-DHD.jpg\"></a></td><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-8-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-8-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -8-DHD.jpg\"></a></td><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-9-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-9-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -9-DHD.jpg\"></a></td><td width=64><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-10-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-10-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -10-DHD.jpg\"></a></td></tr><tr height=64 align=center><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-11-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-11-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -11-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-12-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-12-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -12-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-13-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-13-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -13-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-14-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-14-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -14-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-15-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-15-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -15-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-16-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-16-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -16-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-17-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-17-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -17-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-18-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-18-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -18-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-19-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-19-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -19-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-20-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-20-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -20-DHD.jpg\"></a></td></tr><tr height=64 align=center><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-21-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-21-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -21-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-22-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-22-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -22-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-23-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-23-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -23-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-24-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-24-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -24-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-25-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-25-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -25-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-26-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-26-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -26-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-27-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-27-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -27-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-28-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-28-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -28-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-29-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-29-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -29-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-30-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-30-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -30-DHD.jpg\"></a></td></tr><tr height=64 align=center><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-31-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-31-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -31-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-32-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-32-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -32-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-33-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-33-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -33-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-34-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-34-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -34-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-35-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-35-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -35-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-36-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-36-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -36-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-37-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-37-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -37-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-38-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-38-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -38-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-39-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-39-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -39-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-40-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-40-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -40-DHD.jpg\"></a></td></tr><tr height=64 align=center><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-41-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-41-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -41-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-42-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-42-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -42-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-43-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-43-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -43-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-44-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-44-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -44-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-45-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-45-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -45-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-46-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-46-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -46-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-47-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-47-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -47-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-48-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-48-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -48-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-49-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-49-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -49-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-50-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-50-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -50-DHD.jpg\"></a></td></tr><tr height=64 align=center><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-51-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-51-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -51-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-52-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-52-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -52-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-53-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-53-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -53-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-54-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-54-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -54-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-55-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-55-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -55-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-56-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-56-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -56-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-57-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-57-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -57-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-58-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-58-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -58-DHD.jpg\"></a></td><td><a href=\"/_c/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-59-DHD.jpg.html\"><img src=\"/_tn/sml/money/_more2004/_more12/sale-sales-posters-in-shop-windows-in-Kingston-upon-Thames-just-after-Christmas-2004-after-a-poor-retail-month-59-DHD.jpg\" border=0 width=64 height=48 alt=\"sale ~ -59-DHD.jpg\"></a></td></tr></table>",
1205            };
1206    
1207        /**Forced serialised form to check deserialisation is not broken.
1208         * Encoded value: "prefix1 prefix1suffix prefix2 prefix2suffix prefix2suffix".
1209         */
1210        private static final byte serData_C7BS_20060803[/*109*/] = {
1211            -84,  -19,    0,    5,  115,  114,    0,   39, // ....sr.'
1212            111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1213             46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1214            114,   67,  111,  114,  101,   46,   67,  111, // rCore.Co
1215            109,  112,   97,   99,  116,   55,   66,  105, // mpact7Bi
1216            116,   83,  116,  114,  105,  110,  103,  -81, // tString.
1217              2,   23,   50,  -72, -120,   34,   44,    3, // ..2..",.
1218              0,    0,  120,  112,  119,   46,   45,  112, // ..xpw.-p
1219            114,  101,  102,  105,  120,   49,   32,  112, // refix1.p
1220            114,  101,  102,  105,  120,   49,  115,  117, // refix1su
1221            102,  102,  105,  120,   32,  112,  114,  101, // ffix.pre
1222            102,  105,  120,   50,   32,  112,  114,  101, // fix2.pre
1223            102,  105,  120,   50,  115,  117,  102,  102, // fix2suff
1224            105,  120,   32,   -2,  120,                   // ix..x
1225           };
1226    
1227        /**Forced serialised form after allowing for partial token (prefix) matching.
1228         * Encoded value: "prefix1 prefix1suffix prefix2 prefix2suffix prefix2suffix".
1229         */
1230        private static final byte serData_C7BS_20060804[/*103*/] = {
1231            -84,  -19,    0,    5,  115,  114,    0,   39, // ....sr.'
1232            111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1233             46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1234            114,   67,  111,  114,  101,   46,   67,  111, // rCore.Co
1235            109,  112,   97,   99,  116,   55,   66,  105, // mpact7Bi
1236            116,   83,  116,  114,  105,  110,  103,  -81, // tString.
1237              2,   23,   50,  -72, -120,   34,   44,    3, // ..2..",.
1238              0,    0,  120,  112,  119,   40,   39,  112, // ..xpw('p
1239            114,  101,  102,  105,  120,   49,   32,   -2, // refix1..
1240            115,  117,  102,  102,  105,  120,   32,  112, // suffix.p
1241            114,  101,  102,  105,  120,   50,   32,  112, // refix2.p
1242            114,  101,  102,  105,  120,   50,  115,  117, // refix2su
1243            102,  102,  105,  120,   32,   -2,  120,       // ffix..x
1244           };
1245    
1246        /**Test of serialisation and other behaviour of Compact7BitString.
1247         * The aim is that Compact7BitString should usually be significant smaller than String
1248         * in memory and serialised for 7-bit ASCII text,
1249         * especially when multiple similar values are serialised to a single stream.
1250         * <p>
1251         * We take the (maximally) compressed serialised stream to be our target usage.
1252         */
1253        public static void testCompact7BitString()
1254            throws Exception
1255            {
1256            // Check deserialistion of our frozen values.
1257            // The encoded value should be our first test text.
1258            final Compact7BitString frozen1 = (Compact7BitString) (new ObjectInputStream(new ByteArrayInputStream(serData_C7BS_20060803))).readObject();
1259            assertEquals("must be able to extract correct value from frozen instance",
1260                            TEST_C7BS_DATA[0], frozen1.toString());
1261            final Compact7BitString frozen2 = (Compact7BitString) (new ObjectInputStream(new ByteArrayInputStream(serData_C7BS_20060804))).readObject();
1262            assertEquals("must be able to extract correct value from frozen instance",
1263                            TEST_C7BS_DATA[0], frozen2.toString());
1264    
1265            // Use all the fixed cases in the tests.
1266            final ArrayList<String> testData = new ArrayList<String>(Arrays.asList(TEST_C7BS_DATA));
1267    
1268            // Create one nasty-but-legal block of random 7-bit ASCII values.
1269            // This (eventually!) covers all possible legal input values.
1270            final byte[] r = new byte[rnd.nextInt(Short.MAX_VALUE+1)];
1271            rnd.nextBytes(r);
1272            final StringBuffer rsb = new StringBuffer(r.length);
1273            for(final byte b : r) { rsb.append((char) (b & 0x7f)); }
1274            // Add it to the test set.
1275            testData.add(rsb.toString());
1276    
1277            // Set of static compression dictionaries that we will test against.
1278            final Compact7BitString.StaticDictionary dicts[] = new Compact7BitString.StaticDictionary[]{
1279                     ExhibitPropsComputable.sDict,
1280                     ExhibitPropsLoadable.sDict,
1281                     WebUtils.sDictMD,
1282                };
1283    
1284            final ByteArrayOutputStream allStrings = new ByteArrayOutputStream();
1285            final ObjectOutputStream aSoos = new ObjectOutputStream(allStrings);
1286            final ByteArrayOutputStream allC7BSs = new ByteArrayOutputStream();
1287            final ObjectOutputStream aCoos = new ObjectOutputStream(allC7BSs);
1288    
1289            boolean didCompress = false; // True if any input was compressed.
1290            boolean didBetterWithDict = false; // True if any input was better compressed against any dictionary.
1291            for(final String t : testData)
1292                {
1293                final Compact7BitString c7bs = Compact7BitString.convertToCompact7BitString(t, null);
1294                final long nt1 = System.nanoTime();
1295                final String asString = c7bs.toString();
1296                final long nt2 = System.nanoTime();
1297                final long nt = nt2-nt1;
1298                // Estimate nanoseconds per char to decompress.
1299                final long nspc = nt / Math.max(1, asString.length());
1300                assertEquals("must be able to recover String value correctly",
1301                                t, asString);
1302                assertEquals("must be able to recover String value after (de)serialisation",
1303                                t, checkObjectCanBeSerialisedAndDeserialised(c7bs).toString());
1304    
1305                // Internal format must be no more bytes than the String has chars,
1306                // ie half the memory space or less for most JVMs.
1307                final byte cd[] = c7bs.getInternalBytes();
1308                final int cl = ((null == cd) ? 0 : cd.length);
1309                Main.getOut().println("[chars => bytes (toString() ~"+nt+"ns, ~"+nspc+"ns/char): "+(t.length())+" => "+cl+": "+TextUtils.sanitiseForXML(t, 40, true)+"]");
1310                assertTrue("internal format must be no more bytes than the String has chars",
1311                                cl <= t.length());
1312                // We expect at least one of the sample inputs to compress further...
1313                if(cl < t.length()) { didCompress = true; }
1314    
1315                // Now compress sample input with static dictionaries we use.
1316                for(final Compact7BitString.StaticDictionary d : dicts)
1317                    {
1318                    final Compact7BitString c7bsA = Compact7BitString.convertToCompact7BitString(t, d);
1319                    assertEquals("must be able to recover String value correctly: dictionary="+d,
1320                                    t, c7bsA.toString());
1321                    assertEquals("must be able to recover String value after (de)serialisation: dictionary="+d,
1322                                    t, checkObjectCanBeSerialisedAndDeserialised(c7bsA).toString());
1323                    final byte[] cdAlt = c7bsA.getInternalBytes();
1324                    final int lenWithDict = (null == cdAlt) ? 0 : cdAlt.length;
1325                    assertTrue("compression with static dictionary must be no worse than with no dictionary: dictionary="+d,
1326                                    lenWithDict <= cl);
1327                    // Note if we do better with this compression dictionary.
1328                    if(lenWithDict < cl)
1329                        {
1330                        didBetterWithDict = true;
1331                        Main.getOut().println("  [with dictionary "+d.name+" => bytes: "+lenWithDict+".]");
1332                        }
1333                    }
1334    
1335                aSoos.writeObject(t);
1336                aCoos.writeObject(c7bs);
1337                final Pair<CompressionLevel, byte[]> uS = GenUtils.compressObject(new Object[]{Compact7BitString.EMPTY, t}, CompressionLevel.NONE, false);
1338    
1339                final Pair<CompressionLevel, byte[]> uC7BS = GenUtils.compressObject(new Object[]{Compact7BitString.EMPTY, c7bs}, CompressionLevel.NONE, false);
1340    //            Main.getOut().println("[String/C7BS adjusted uncompressed serialised size: "+uS.second.length+"/"+uC7BS.second.length+".]");
1341                assertTrue("uncompressed form must be similar in size ("+uS.second.length+" vs "+uC7BS.second.length+") " + t,
1342                                (4*uS.second.length)/3 + 32 >= uC7BS.second.length);
1343    
1344                // Compute moderately-compressed serialised forms...
1345                final Pair<CompressionLevel, byte[]> cS = GenUtils.compressObject(new Object[]{Compact7BitString.EMPTY, t}, CompressionLevel.ZIP, false);
1346                final Pair<CompressionLevel, byte[]> cC7BS = GenUtils.compressObject(new Object[]{Compact7BitString.EMPTY, c7bs}, CompressionLevel.ZIP, false);
1347    //            Main.getOut().println("[String/C7BS adjusted compressed serialised size: "+cS.second.length+"/"+cC7BS.second.length+".]");
1348                assertTrue("compressed form must be similar in size: S/C7BS="+cS.second.length+"/"+cC7BS.second.length,
1349                                (4*cS.second.length)/3 + 32 >= cC7BS.second.length);
1350                }
1351            aSoos.close();
1352            aCoos.close();
1353    
1354            assertTrue("at least one input should have compressed (fewer bytes than chars)", didCompress);
1355    
1356            // Serialising all the test objects as C7BS should beat serialising them as plain Strings when compressed.
1357            final Pair<CompressionLevel, byte[]> aScomp = GenUtils.compressObject(allStrings.toByteArray(), GenUtils.MAX_SUPPORTED_COMPRESSION_LEVEL, false);
1358            final Pair<CompressionLevel, byte[]> aCcomp = GenUtils.compressObject(allC7BSs.toByteArray(), GenUtils.MAX_SUPPORTED_COMPRESSION_LEVEL, false);
1359    //        Main.getOut().println("[Serialised String/C7BS compressed sequences: "+aScomp.second.length+"/"+aCcomp.second.length+".]");
1360            assertTrue("serialised sequence of (similar) C7BS instances should be not much larger than serialised plain Strings ("+aScomp.second.length+" vs "+aCcomp.second.length+")",
1361                            (4*aScomp.second.length)/2 + 32 >=
1362                            aCcomp.second.length);
1363    
1364            assertTrue("at least one input should have compressed better with at least one of the static dictionaries!",
1365                            didBetterWithDict);
1366            }
1367    
1368        /**Test (de)serialisation of LocationMap.
1369         */
1370        public static void testLocationMap()
1371            throws Exception
1372            {
1373            checkEmptyInstancesAreZeroAndEqualAndSerializable(LocationMap.class);
1374            checkSerialisationPreservesEquality(new LocationMap());
1375    
1376            final ExhibitPropsGlobalImmutable epgi = ExhibitPropsGlobalImmutable.loadFromDataDir(new File(LocalProps.getDataDir()));
1377    //        final LocationMap lm = epgi.getLocationMap();
1378    
1379            // Note size of simple ZIPped (quickly-compressed) serialised form
1380            // of realistic map (wrapped in EPGI).
1381            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
1382            final GZIPOutputStream gos = new GZIPOutputStream(baos);
1383            final ObjectOutputStream oos = new ObjectOutputStream(gos);
1384            oos.writeObject(epgi);
1385            oos.close();
1386            Main.getOut().println("Compressed serialised ExhibitPropsGlobalImmutable size (bytes) ~ " + baos.size());
1387            }
1388    
1389        /**Test correctness of some of our (de)compressors often used with serialisation.
1390         * This ensures that they correctly handle some sample data streams
1391         * and that they work correctly in the face of a mid-stream flush().
1392         */
1393        public static void testCompressors()
1394            throws Exception
1395            {
1396            // We'll use a variety of existing and new test data.
1397            final List<byte[]> testData = new ArrayList<byte[]>(64);
1398    
1399            // Some synthetic edge/hard cases.
1400            testData.add(new byte[0]);
1401            testData.add(new byte[101]);
1402            final byte randomRubbish[] = new byte[rnd.nextInt(1<<16)];
1403            rnd.nextBytes(randomRubbish);
1404            testData.add(randomRubbish);
1405    
1406            // Test some of the frozen serialised data streams as realistic samples.
1407            testData.add(serData_AllExhibitPropertiesDelta_empty);
1408            testData.add(serData_C7BS_20060803);
1409            testData.add(serData_ROBA_compS1_20050522);
1410            testData.add(serData_evv1_20050131_1512);
1411    
1412            // Compressors to test (represented by their "levels" here).
1413            final CompressionLevel compressors[] =
1414                { CompressionLevel.LZMA, CompressionLevel.BZIP2, CompressionLevel.ZIP };
1415    
1416            // Try all the compressors in turn...
1417            for(final CompressionLevel comp : compressors)
1418                {
1419                // Try each data sample in turn...
1420                for(final byte[] data : testData)
1421                    {
1422                    // Compress once with no flush()es and once with at least one.
1423                    for(final boolean doFlush : new boolean[]{ false, true } )
1424                        {
1425                        final ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
1426                        final OutputStream cos1;
1427                        switch(comp)
1428                            {
1429                            /** Note that we actually test our flushable GZIP here... */
1430                            case ZIP: cos1 = new FlushableGZIPOutputStream(baos1); break;
1431                            case BZIP2: cos1 = new CBZip2OutputStream(baos1); break;
1432                            case LZMA: cos1 = new LzmaOutputStream(baos1); break;
1433                            default: throw new Error("unexpected/unsupported compression type");
1434                            }
1435                        if(doFlush && rnd.nextBoolean()) { cos1.flush(); }
1436                        if(!doFlush || (data.length < 2))
1437                            { cos1.write(data.clone()); }
1438                        else
1439                            {
1440                            // Break the write into two pieces with a flush() between.
1441                            final int flushAfter = rnd.nextInt(data.length - 1);
1442                            final byte d1[] = new byte[flushAfter];
1443                            final byte d2[] = new byte[data.length - flushAfter];
1444                            System.arraycopy(data, 0, d1, 0, flushAfter);
1445                            System.arraycopy(data, flushAfter, d2, 0, d2.length);
1446                            cos1.write(d1);
1447                            cos1.flush();
1448                            cos1.write(d2);
1449                            }
1450                        if(doFlush && rnd.nextBoolean()) { cos1.flush(); }
1451                        cos1.close();
1452                        final byte compressed[] = baos1.toByteArray();
1453    //Main.getOut().println("[Input length / method / doFlush / output length = "+data.length+" / "+comp+" / "+doFlush+" / "+compressed.length+".]");
1454    
1455                        // Check that decompressing reproduces the original input.
1456                        final ByteArrayInputStream bais = new ByteArrayInputStream(compressed);
1457                        final InputStream dcis;
1458                        switch(comp)
1459                            {
1460                            case ZIP: dcis = new GZIPInputStream(bais); break;
1461                            case BZIP2: dcis = new CBZip2InputStream(bais); break;
1462                            case LZMA: dcis = new LzmaInputStream(bais); break;
1463                            default: throw new Error("unexpected/unsupported compression type");
1464                            }
1465                        final DataInputStream dis = new DataInputStream(dcis);
1466                        final byte decompData[] = new byte[data.length];
1467                        dis.readFully(decompData);
1468                        assertTrue("must be able to recover data after decompression", Arrays.equals(data, decompData));
1469                        assertEquals("must be no trailing garbage in decompressed input", -1, dis.read());
1470                        }
1471                    }
1472                }
1473            }
1474    
1475        /**Old-style String keys and values PropertiesDiff value. */
1476        private static final byte serData_pdS16_20090714[/*212*/] = {
1477            -84,  -19,    0,    5,  115,  114,    0,   42, // ....sr.*
1478            111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1479             46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1480            114,   67,  111,  114,  101,   46,  112,  114, // rCore.pr
1481            111,  112,  115,   46,   80,  114,  111,  112, // ops.Prop
1482            101,  114,  116,  105,  101,  115,   68,  105, // ertiesDi
1483            102,  102,   59,  -58,  -64,  -15,  -69,   -1, // ff;.....
1484             91,  -18,    3,    0,    2,   73,    0,    9, // [....I..
1485            115,  105,  122,  101,   65,  102,  116,  101, // sizeAfte
1486            114,   73,    0,   10,  115,  105,  122,  101, // rI..size
1487             66,  101,  102,  111,  114,  101,  120,  112, // Beforexp
1488              0,    0,    0,    3,    0,    0,    0,    3, // ........
1489            116,    0,    7,  100,  101,  108,  101,  116, // t..delet
1490            101,  100,  117,  114,    0,   19,   91,   76, // edur..[L
1491            106,   97,  118,   97,   46,  108,   97,  110, // java.lan
1492            103,   46,   83,  116,  114,  105,  110,  103, // g.String
1493             59,  -83,  -46,   86,  -25,  -23,   29,  123, // ;..V...{
1494             71,    2,    0,    0,  120,  112,    0,    0, // G...xp..
1495              0,    2,  116,    0,    7,   99,  104,   97, // ..t..cha
1496            110,  103,  101,  100,  116,    0,    3,  110, // ngedt..n
1497            101,  119,  117,  113,    0,  126,    0,    3, // ewuq.~..
1498              0,    0,    0,    2,  116,    0,   26,  110, // ....t..n
1499            101,  119,  118,   97,  108,  117,  101,   44, // ewvalue,
1500             32,  121,  101,   97,  104,   32,   98,   97, // .yeah.ba
1501             98,  121,   44,   32,  121,  101,   97,  104, // by,.yeah
1502             33,  116,    0,    7,  119,  111,  116,   99, // !t..wotc
1503            104,   97,   33,  120, // ha!x
1504           };
1505    
1506        /**New-style String keys and values PropertiesDiff value. */
1507        private static final byte serData_pdvar_20090714[/*342*/] = {
1508         -84,  -19,    0,    5,  115,  114,    0,   42, // ....sr.*
1509         111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1510          46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1511         114,   67,  111,  114,  101,   46,  112,  114, // rCore.pr
1512         111,  112,  115,   46,   80,  114,  111,  112, // ops.Prop
1513         101,  114,  116,  105,  101,  115,   68,  105, // ertiesDi
1514         102,  102,   59,  -58,  -64,  -15,  -69,   -1, // ff;.....
1515          91,  -18,    3,    0,    2,   73,    0,    9, // [....I..
1516         115,  105,  122,  101,   65,  102,  116,  101, // sizeAfte
1517         114,   73,    0,   10,  115,  105,  122,  101, // rI..size
1518          66,  101,  102,  111,  114,  101,  120,  112, // Beforexp
1519           0,    0,    0,    3,    0,    0,    0,    3, // ........
1520         115,  114,    0,   26,  111,  114,  103,   46, // sr..org.
1521         104,  100,   46,  100,   46,  112,  103,   50, // hd.d.pg2
1522         107,   46,  115,  118,  114,   67,  111,  114, // k.svrCor
1523         101,   46,   78,   97,  109,  101,   38,  -44, // e.Name&.
1524         -30,   17,    1,  -80,  121,  -16,    3,    0, // ....y...
1525           2,   83,    0,   14,  116,  101,  114,  109, // .S..term
1526         105,  110,  105,   76,  101,  110,  103,  116, // iniLengt
1527         104,  115,   76,    0,    4,  112,  114,  101, // hsL..pre
1528         118,  116,    0,   28,   76,  111,  114,  103, // vt..Lorg
1529          47,  104,  100,   47,  100,   47,  112,  103, // /hd/d/pg
1530          50,  107,   47,  115,  118,  114,   67,  111, // 2k/svrCo
1531         114,  101,   47,   78,   97,  109,  101,   59, // re/Name;
1532         120,  112,    0,    0,  112,  119,    8,    7, // xp..pw..
1533         100,  101,  108,  101,  116,  101,  100,  120, // deletedx
1534         117,  114,    0,   25,   91,   76,  106,   97, // ur..[Lja
1535         118,   97,   46,  108,   97,  110,  103,   46, // va.lang.
1536          67,  104,   97,  114,   83,  101,  113,  117, // CharSequ
1537         101,  110,   99,  101,   59,   11,  -36,  -59, // ence;...
1538         -43,    2,  -39,   89, -121,    2,    0,    0, // ...Y....
1539         120,  112,    0,    0,    0,    4,  116,    0, // xp....t.
1540           7,   99,  104,   97,  110,  103,  101,  100, // .changed
1541         116,    0,    3,  110,  101,  119,  115,  113, // t..newsq
1542           0,  126,    0,    2,    0,    3,  115,  113, // .~....sq
1543           0,  126,    0,    2,    0,    0,  112,  119, // .~....pw
1544           4,    3,  110,  101,  119,  120,  119,   24, // ..newxw.
1545          23,  118,   97,  108,  117,  101,   44,   32, // .value,.
1546         121,  101,   97,  104,   32,   98,   97,   98, // yeah.bab
1547         121,   44,   32,  121,  101,   97,  104,   33, // y,.yeah!
1548         120,  115,  113,    0,  126,    0,    2,    0, // xsq.~...
1549           0,  112,  119,    8,    7,  119,  111,  116, // .pw..wot
1550          99,  104,   97,   33,  120,  120, // cha!xx
1551        };
1552    
1553        /**Test behaviour of PropertiesDiff object.
1554         * This is primarily used to allow efficient transmission of
1555         * properties values/updates over the wire.
1556         */
1557        public static void testPropertiesDiff()
1558            throws Exception
1559            {
1560            // Test that empty object is valid.
1561            final PropertiesDiff emptyDiff = PropertiesDiff.EMPTY_DIFF;
1562            (emptyDiff).validateObject();
1563    
1564            // Test that an (empty) object can survive (de)serialisation intact.
1565            checkEmptyInstancesAreZeroAndEqualAndSerializable(PropertiesDiff.class);
1566    
1567            // Check that the diff from one empty Properties set to another is empty.
1568            final Properties emptyProps = new Properties();
1569            assertEquals("Diff between empty Properties sets must be empty",
1570                emptyDiff, PropertiesDiff.createDiff(emptyProps, emptyProps, true, rnd.nextBoolean()));
1571            checkSerialisationPreservesEquality(emptyProps);
1572    
1573            // Check that the diff between an empty property set and a non-empty one is NOT empty.
1574            final Properties oneEntry = new Properties();
1575            oneEntry.setProperty("hello", "world");
1576            assertFalse("Diff between empty Properties and non-empty sets must not be empty",
1577                emptyDiff.equals(PropertiesDiff.createDiff(oneEntry, emptyProps, true, rnd.nextBoolean())));
1578            assertFalse("Diff between empty Properties and non-empty sets must not be empty",
1579                emptyDiff.equals(PropertiesDiff.createDiff(emptyProps, oneEntry, true, rnd.nextBoolean())));
1580            checkSerialisationPreservesEquality(oneEntry);
1581    
1582            // Construct simple properties set with one of each pertinent type:
1583            //   * unchanged
1584            //   * deleted
1585            //   * new/added
1586            //   * changed
1587            final Properties p1 = new Properties();
1588            p1.setProperty("deleted", "byebye, baby, byebye");
1589            p1.setProperty("changed", "oldvalue");
1590            final Properties p2 = new Properties();
1591            p1.setProperty("unchanged", "sameold");
1592            p2.setProperty("unchanged", "sameold");
1593            p2.setProperty("changed", "newvalue, yeah baby, yeah!");
1594            p2.setProperty("new", "wotcha!");
1595            final PropertiesDiff diff1 = PropertiesDiff.createDiff(p1, p2, true, rnd.nextBoolean());
1596            assertFalse("This diff should not be empty", diff1.isEmpty());
1597            assertFalse("This diff should not be empty (==emptyDiff)", emptyDiff.equals(diff1));
1598            assertNotSame("This diff's hash should not be zero", 0, diff1.hashCode());
1599            final Properties synthP2 = PropertiesDiff.applyDiff(p1, diff1);
1600            assertEquals("Must be able to reconstruct 'p2' Properties using diff",
1601                            p2, synthP2);
1602            // Check that the diff survives (de)serialisation.
1603            checkSerialisationPreservesEquality(diff1);
1604            // Check that older/current frozen formats can be read...
1605            final PropertiesDiff frozen1a = (PropertiesDiff) (new ObjectInputStream(new ByteArrayInputStream(serData_pdS16_20090714))).readObject();
1606            assertEquals("Must be able to deserialise old-style pure-String (16-bit) instance", diff1, frozen1a);
1607            final PropertiesDiff frozen1b = (PropertiesDiff) (new ObjectInputStream(new ByteArrayInputStream(serData_pdvar_20090714))).readObject();
1608            assertEquals("Must be able to deserialise new-style compacted instance", diff1, frozen1b);
1609    
1610    if(PRINT_SER_BYTES) { Main.getErr().println("WARNING: stopping tests early because of volume of output..."); return; } // TOO MUCH GARBAGE PRINTED OTHERWISE...
1611    
1612    
1613            // Create some random-ish Properties sets, diff them, etc.
1614            // Generally check for sensible behaviour.
1615            // We have one unique key in each the before and after set
1616            // to help check for correct behaviour.
1617            final String uniqueBeforeKey = "_unique_before_";
1618            final String uniqueAfterKey = "_unique_after_";
1619            // About half the time have a property and key each with 16-bit characters in them.
1620            final String key16Bit = "16bit\u3456";
1621            final String value16Bit = "abdc\u6723yasd the quick brown\nforx jumps!";
1622            try { Name.create(key16Bit); fail("key is pure 8-bit but shouldn't be"); }
1623            catch(final IllegalArgumentException e) { /* Correctly rejected non-8-bit value. */ }
1624            try { Name.create(value16Bit); fail("value is pure 8-bit but shouldn't be"); }
1625            catch(final IllegalArgumentException e) { /* Correctly rejected non-8-bit value. */ }
1626    
1627            // Test (exponentially) increasing set sizes,
1628            // up to something reasonably representative.
1629            for(int i = 0; i <= 12; i += 2)
1630                {
1631                final Properties before = new Properties();
1632                before.setProperty(uniqueBeforeKey, "U" + rnd.nextLong());
1633                final Properties after = new Properties();
1634                after.setProperty(uniqueAfterKey, "U" + rnd.nextLong());
1635                for(int j = rnd.nextInt(1 + (1<<i)); --j >= 0; )
1636                    {
1637                    // We aim to have the "before" and "after" values very similar,
1638                    // with a few deletions and additions/changes,
1639                    // with the "after" value on average very slightly larger
1640                    // to represent realistic slow growth/change of a Properties set.
1641                    final String key = "key." + (rnd.nextLong() >>> 1);
1642                    final String beforeValue = "val" + rnd.nextLong();
1643                    // The "before" value is usually set.
1644                    if(rnd.nextInt(17) != 0) { before.setProperty(key, beforeValue); }
1645                    // The "after" value is usually the same as the before value.
1646                    final String afterValue = (rnd.nextInt(101) != 0) ? beforeValue : "val" + rnd.nextLong();
1647                    // The "after" value is usually set.
1648                    if(rnd.nextInt(19) != 0) { after.setProperty(key, afterValue); }
1649                    }
1650    
1651                // About half the time have a property and key each with 16-bit characters in them.
1652                final boolean test16Bit = rnd.nextBoolean();
1653                if(test16Bit)
1654                    { after.setProperty(key16Bit, value16Bit); }
1655    
1656                // Simplest and most basic test.
1657                // Force reconstruction of "after" vaue from "before" + diff.
1658                final PropertiesDiff basicDiff = PropertiesDiff.createDiff(before, after, true, rnd.nextBoolean());
1659                assertFalse("This diff should not be empty", basicDiff.isEmpty());
1660                final Properties synthAfter = PropertiesDiff.applyDiff(before, basicDiff);
1661                assertEquals("Must be able to reconstruct 'after' Properties with correct size using diff",
1662                                after.size(), synthAfter.size());
1663                assertEquals("Must be able to reconstruct 'after' Properties with correct key set using diff",
1664                                after.keySet(), synthAfter.keySet());
1665                assertEquals("Must be able to reconstruct 'after' Properties with correct value set using diff",
1666                                new HashSet<Object>(after.values()), new HashSet<Object>(synthAfter.values()));
1667                assertEquals("Must be able to reconstruct 'after' Properties using diff",
1668                                after, synthAfter);
1669    
1670                // Force reconstruction of "after" from empty.
1671                final PropertiesDiff eDiff = PropertiesDiff.createDiff(emptyProps, after, true, rnd.nextBoolean());
1672                final Properties synthAfterE = PropertiesDiff.applyDiff(emptyProps, eDiff);
1673                assertEquals("Must be able to reconstruct 'after' Properties from diff from empty Properties",
1674                                after, synthAfterE);
1675    
1676                // Force reverse diff of "before" from "after".
1677                final PropertiesDiff rDiff = PropertiesDiff.createDiff(after, before, true, rnd.nextBoolean());
1678                final Properties synthBefore = PropertiesDiff.applyDiff(after, rDiff);
1679                assertEquals("Must be able to reconstruct 'before' Properties from (reverse) diff from 'after'",
1680                                before, synthBefore);
1681    
1682                // Check that the diff survives (de)serialisation.
1683                final PropertiesDiff bdS = (PropertiesDiff)checkSerialisationPreservesEquality(basicDiff);
1684                checkSerialisationPreservesEquality(eDiff);
1685                checkSerialisationPreservesEquality(rDiff);
1686    
1687                // Check that even 16-bit keys and values survive (de)serialisation.
1688                if(test16Bit)
1689                    {
1690                    final Properties sAdS = PropertiesDiff.applyDiff(before, bdS);
1691                    assertEquals("16-bit keys and values must be viable", value16Bit, sAdS.get(key16Bit));
1692                    }
1693                }
1694            }
1695    
1696        /**Test behaviour of PropertiesBundleDiff object.
1697         * This is primarily used to allow efficient transmission of
1698         * properties values/updates over the wire.
1699         */
1700        public static void testPropertiesBundleDiff()
1701            throws Exception
1702            {
1703            // Test that empty object is valid.
1704            final PropertiesBundleDiff emptyBundleDiff = PropertiesBundleDiff.EMPTY_DIFF;
1705            (emptyBundleDiff).validateObject();
1706    
1707            // Test that an (empty) object can survive (de)serialisation intact.
1708            checkEmptyInstancesAreZeroAndEqualAndSerializable(PropertiesBundleDiff.class);
1709    
1710            // Hand-crafted small properties sets representative of small system.
1711            // Version 1.
1712            final Properties v1_treedec_properties = new Properties();
1713            final Properties v1_treedec_fr_properties = new Properties();
1714            final Properties v1_treedec_ERROR_properties = new Properties();
1715            final Map<String,Properties> v1 = new TreeMap<String,Properties>();
1716            v1.put("", v1_treedec_properties);
1717            v1_treedec_properties.setProperty("deleted", "byebye");
1718            v1_treedec_properties.setProperty("changed", "oldvalue");
1719            v1_treedec_properties.setProperty("unchanged", "sameold");
1720            v1.put("_fr", v1_treedec_fr_properties);
1721            v1_treedec_fr_properties.setProperty("world", "monde");
1722            v1.put("_ERROR", v1_treedec_ERROR_properties);
1723    
1724            // Version 2, after update.
1725            final Map<String,Properties> v2 = new TreeMap<String,Properties>();
1726            final Properties v2_treedec_properties = new Properties();
1727            final Properties v2_treedec_fr_properties = new Properties();
1728            final Properties v2_treedec_zh_properties = new Properties();
1729            v2.put("", v2_treedec_properties);
1730            v2_treedec_properties.setProperty("unchanged", "sameold");
1731            v2_treedec_properties.setProperty("changed", "newvalue");
1732            v2_treedec_properties.setProperty("new", "wotcha!");
1733            v2.put("_fr", v2_treedec_fr_properties);
1734            v2_treedec_fr_properties.setProperty("world", "monde");
1735            v2.put("_zh", v2_treedec_zh_properties);
1736    
1737            assertFalse("Modified properties set should not compare equal", v1.equals(v2));
1738    
1739            final PropertiesBundleDiff pbDiff = PropertiesBundleDiff.createDiff(v1, v2, true, rnd.nextBoolean());
1740            assertFalse("Bundle diff should not be empty", pbDiff.isEmpty());
1741            assertNotSame("Bundle diff hash should not be zero", 0, pbDiff.hashCode());
1742            checkSerialisationPreservesEquality(pbDiff);
1743    
1744            // Check that we can correctly recreate v2 from v1 + diff.
1745            final Map<String,Properties> v2Synth = PropertiesBundleDiff.applyDiff(v1, pbDiff);
1746            assertEquals("Reconstricted bundle should equal original", v2, v2Synth);
1747            }
1748    
1749        /**Basic serialisation tests of EPGI and its diff.
1750         */
1751        public static void testEPGIBasic()
1752            throws Exception
1753            {
1754            // Check (de)serialisation of empty EPGI.
1755            checkObjectCanBeSerialisedAndDeserialised(new ExhibitPropsGlobalImmutable());
1756    
1757            // Test that an (empty) EPGL object can survive (de)serialisation intact.
1758            checkEmptyInstancesAreZeroAndEqualAndSerializable(ExhibitPropsGlobalImmutable.class);
1759    
1760            // Check (de)serialisation of realistic EPGI.
1761            final ExhibitPropsGlobalImmutable epgi = ExhibitPropsGlobalImmutable.loadFromDataDir(new File(LocalProps.getDataDir()));
1762            checkSerialisationPreservesEquality(epgi);
1763    
1764            // Very basic EPGIDiff tests.
1765            checkObjectCanBeSerialisedAndDeserialised(new EPGIDiff());
1766            }
1767    
1768    
1769        /**Original String field format serialisation of ExhibitStaticAttr("a/a-A.a", 1, CoreConsts.GALLERY_EPOC_START). */
1770        private static final byte serData_esa1a_20090711[/*139*/] = {
1771         -84,  -19,    0,    5,  115,  114,    0,   39, // ....sr.'
1772         111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1773          46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1774         114,   67,  111,  114,  101,   46,   69,  120, // rCore.Ex
1775         104,  105,   98,  105,  116,   83,  116,   97, // hibitSta
1776         116,  105,   99,   65,  116,  116,  114, -115, // ticAttr.
1777         -69,  -98,  -10, -103,   64,  -92,  113,    2, // ....@.q.
1778           0,    3,   74,    0,    6,  108,  101,  110, // ..J..len
1779         103,  116,  104,   74,    0,    9,  116,  105, // gthJ..ti
1780         109,  101,  115,  116,   97,  109,  112,   76, // mestampL
1781           0,    8,  102,  105,  108,  101,   80,   97, // ..filePa
1782         116,  104,  116,    0,   18,   76,  106,   97, // tht..Lja
1783         118,   97,   47,  108,   97,  110,  103,   47, // va/lang/
1784          83,  116,  114,  105,  110,  103,   59,  120, // String;x
1785         112,    0,    0,    0,    0,    0,    0,    0, // p.......
1786           1,    0,    0,    0,  -65,    6,  -28,  -96, // ........
1787           0,  116,    0,    7,   97,   47,   97,   45, // .t..a/a-
1788          65,   46,   97, // A.a
1789        };
1790    
1791        /**CharSequence field format serialisation of ExhibitStaticAttr("a/a-A.a", 1, CoreConsts.GALLERY_EPOC_START) with run-time String field type. */
1792        private static final byte serData_esa1b_20090711[/*145*/] = {
1793        -84,  -19,    0,    5,  115,  114,    0,   39, // ....sr.'
1794        111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1795         46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1796        114,   67,  111,  114,  101,   46,   69,  120, // rCore.Ex
1797        104,  105,   98,  105,  116,   83,  116,   97, // hibitSta
1798        116,  105,   99,   65,  116,  116,  114, -115, // ticAttr.
1799        -69,  -98,  -10, -103,   64,  -92,  113,    2, // ....@.q.
1800          0,    3,   74,    0,    6,  108,  101,  110, // ..J..len
1801        103,  116,  104,   74,    0,    9,  116,  105, // gthJ..ti
1802        109,  101,  115,  116,   97,  109,  112,   76, // mestampL
1803          0,    8,  102,  105,  108,  101,   80,   97, // ..filePa
1804        116,  104,  116,    0,   24,   76,  106,   97, // tht..Lja
1805        118,   97,   47,  108,   97,  110,  103,   47, // va/lang/
1806         67,  104,   97,  114,   83,  101,  113,  117, // CharSequ
1807        101,  110,   99,  101,   59,  120,  112,    0, // ence;xp.
1808          0,    0,    0,    0,    0,    0,    1,    0, // ........
1809          0,    0,  -65,    6,  -28,  -96,    0,  116, // .......t
1810          0,    7,   97,   47,   97,   45,   65,   46, // ..a/a-A.
1811         97, // a
1812        };
1813    
1814        /**CharSequence field format serialisation of ExhibitStaticAttr("a/a-A.a", 1, CoreConsts.GALLERY_EPOC_START) with run-time Name.ExhibitFull field type. */
1815        private static final byte serData_esa1c_20090711[/*300*/] = {
1816        -84,  -19,    0,    5,  115,  114,    0,   39, // ....sr.'
1817        111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1818         46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1819        114,   67,  111,  114,  101,   46,   69,  120, // rCore.Ex
1820        104,  105,   98,  105,  116,   83,  116,   97, // hibitSta
1821        116,  105,   99,   65,  116,  116,  114, -115, // ticAttr.
1822        -69,  -98,  -10, -103,   64,  -92,  113,    2, // ....@.q.
1823          0,    3,   74,    0,    6,  108,  101,  110, // ..J..len
1824        103,  116,  104,   74,    0,    9,  116,  105, // gthJ..ti
1825        109,  101,  115,  116,   97,  109,  112,   76, // mestampL
1826          0,    8,  102,  105,  108,  101,   80,   97, // ..filePa
1827        116,  104,  116,    0,   24,   76,  106,   97, // tht..Lja
1828        118,   97,   47,  108,   97,  110,  103,   47, // va/lang/
1829         67,  104,   97,  114,   83,  101,  113,  117, // CharSequ
1830        101,  110,   99,  101,   59,  120,  112,    0, // ence;xp.
1831          0,    0,    0,    0,    0,    0,    1,    0, // ........
1832          0,    0,  -65,    6,  -28,  -96,    0,  115, // .......s
1833        114,    0,   38,  111,  114,  103,   46,  104, // r.&org.h
1834        100,   46,  100,   46,  112,  103,   50,  107, // d.d.pg2k
1835         46,  115,  118,  114,   67,  111,  114,  101, // .svrCore
1836         46,   78,   97,  109,  101,   36,   69,  120, // .Name$Ex
1837        104,  105,   98,  105,  116,   70,  117,  108, // hibitFul
1838        108,  124,  -48,  -33, -108,   52,  -93,  -31, // l|...4..
1839          9,    2,    0,    0,  120,  114,    0,   26, // ....xr..
1840        111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1841         46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1842        114,   67,  111,  114,  101,   46,   78,   97, // rCore.Na
1843        109,  101,   38,  -44,  -30,   17,    1,  -80, // me&.....
1844        121,  -16,    3,    0,    2,   83,    0,   14, // y....S..
1845        116,  101,  114,  109,  105,  110,  105,   76, // terminiL
1846        101,  110,  103,  116,  104,  115,   76,    0, // engthsL.
1847          4,  112,  114,  101,  118,  116,    0,   28, // .prevt..
1848         76,  111,  114,  103,   47,  104,  100,   47, // Lorg/hd/
1849        100,   47,  112,  103,   50,  107,   47,  115, // d/pg2k/s
1850        118,  114,   67,  111,  114,  101,   47,   78, // vrCore/N
1851         97,  109,  101,   59,  120,  112,    0,    0, // ame;xp..
1852        112,  119,    8,    7,   97,   47,   97,   45, // pw..a/a-
1853         65,   46,   97,  120, // A.ax
1854       };
1855    
1856        /**Basic serialisation tests of ExhibitStaticAttrs. */
1857        public static void testESABasic()
1858            throws Exception
1859            {
1860            //assertImmutable(ExhibitStaticAttr.class);
1861            MutabilityAssert.assertInstancesOf(ExhibitStaticAttr.class, MutabilityMatchers.areImmutable(), AllowedReason.provided(Name.ExhibitFull.class).isAlsoImmutable());
1862    
1863            final ExhibitStaticAttr esa1 = new ExhibitStaticAttr("a/a-A.a", 1, CoreConsts.GALLERY_EPOC_START);
1864            checkSerialisationPreservesEquality(esa1);
1865            // Check that we are able to extract this value from cold-store in old String field format.
1866            final ExhibitStaticAttr frozen1a = (ExhibitStaticAttr) (new ObjectInputStream(new ByteArrayInputStream(serData_esa1a_20090711))).readObject();
1867            assertEquals(esa1, frozen1a);
1868            // Check that we are able to extract this value from cold-store in CharSequence field format (with String run-time field type).
1869            final ExhibitStaticAttr frozen1b = (ExhibitStaticAttr) (new ObjectInputStream(new ByteArrayInputStream(serData_esa1b_20090711))).readObject();
1870            assertEquals(esa1, frozen1b);
1871            // Check that we are able to extract this value from cold-store in CharSequence field format (with Name.ExhibitFull run-time field type).
1872            final ExhibitStaticAttr frozen1c = (ExhibitStaticAttr) (new ObjectInputStream(new ByteArrayInputStream(serData_esa1c_20090711))).readObject();
1873            assertEquals(esa1, frozen1c);
1874            }
1875    
1876        /**Serialisation of ExhibitFullName("a/a-A.a"). */
1877        private static final byte serData_efn1_20090711[/*169*/] = {
1878                -84,  -19,    0,    5,  115,  114,    0,   38, // ....sr.&
1879                111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1880                 46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1881                114,   67,  111,  114,  101,   46,   78,   97, // rCore.Na
1882                109,  101,   36,   69,  120,  104,  105,   98, // me$Exhib
1883                105,  116,   70,  117,  108,  108,  124,  -48, // itFull|.
1884                -33, -108,   52,  -93,  -31,    9,    2,    0, // ..4.....
1885                  0,  120,  114,    0,   26,  111,  114,  103, // .xr..org
1886                 46,  104,  100,   46,  100,   46,  112,  103, // .hd.d.pg
1887                 50,  107,   46,  115,  118,  114,   67,  111, // 2k.svrCo
1888                114,  101,   46,   78,   97,  109,  101,   38, // re.Name&
1889                -44,  -30,   17,    1,  -80,  121,  -16,    3, // .....y..
1890                  0,    2,   83,    0,   14,  116,  101,  114, // ..S..ter
1891                109,  105,  110,  105,   76,  101,  110,  103, // miniLeng
1892                116,  104,  115,   76,    0,    4,  112,  114, // thsL..pr
1893                101,  118,  116,    0,   28,   76,  111,  114, // evt..Lor
1894                103,   47,  104,  100,   47,  100,   47,  112, // g/hd/d/p
1895                103,   50,  107,   47,  115,  118,  114,   67, // g2k/svrC
1896                111,  114,  101,   47,   78,   97,  109,  101, // ore/Name
1897                 59,  120,  112,    0,    0,  112,  119,    8, // ;xp..pw.
1898                  7,   97,   47,   97,   45,   65,   46,   97, // .a/a-A.a
1899                120, // x
1900               };
1901    
1902        /**Frozen pair of long values with common prefix and suffix. */
1903        private static final byte serData_efnpair_20090711[/*538*/] = {
1904                -84,  -19,    0,    5,  115,  114,    0,   32, // ....sr..
1905                111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
1906                 46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
1907                114,   67,  111,  114,  101,   46,   84,  117, // rCore.Tu
1908                112,  108,  101,   36,   80,   97,  105,  114, // ple$Pair
1909                -78,   -8,  -87, -112,   47,   28,  102,   56, // ..../.f8
1910                  2,    0,    2,   76,    0,    5,  102,  105, // ...L..fi
1911                114,  115,  116,  116,    0,   18,   76,  106, // rstt..Lj
1912                 97,  118,   97,   47,  108,   97,  110,  103, // ava/lang
1913                 47,   79,   98,  106,  101,   99,  116,   59, // /Object;
1914                 76,    0,    6,  115,  101,   99,  111,  110, // L..secon
1915                100,  113,    0,  126,    0,    1,  120,  112, // dq.~..xp
1916                115,  114,    0,   38,  111,  114,  103,   46, // sr.&org.
1917                104,  100,   46,  100,   46,  112,  103,   50, // hd.d.pg2
1918                107,   46,  115,  118,  114,   67,  111,  114, // k.svrCor
1919                101,   46,   78,   97,  109,  101,   36,   69, // e.Name$E
1920                120,  104,  105,   98,  105,  116,   70,  117, // xhibitFu
1921                108,  108,  124,  -48,  -33, -108,   52,  -93, // ll|...4.
1922                -31,    9,    2,    0,    0,  120,  114,    0, // .....xr.
1923                 26,  111,  114,  103,   46,  104,  100,   46, // .org.hd.
1924                100,   46,  112,  103,   50,  107,   46,  115, // d.pg2k.s
1925                118,  114,   67,  111,  114,  101,   46,   78, // vrCore.N
1926                 97,  109,  101,   38,  -44,  -30,   17,    1, // ame&....
1927                -80,  121,  -16,    3,    0,    2,   83,    0, // .y....S.
1928                 14,  116,  101,  114,  109,  105,  110,  105, // .termini
1929                 76,  101,  110,  103,  116,  104,  115,   76, // LengthsL
1930                  0,    4,  112,  114,  101,  118,  116,    0, // ..prevt.
1931                 28,   76,  111,  114,  103,   47,  104,  100, // .Lorg/hd
1932                 47,  100,   47,  112,  103,   50,  107,   47, // /d/pg2k/
1933                115,  118,  114,   67,  111,  114,  101,   47, // svrCore/
1934                 78,   97,  109,  101,   59,  120,  112,    0, // Name;xp.
1935                  0,  112,  122,    0,    0,    1,    8,   -1, // .pz.....
1936                 -1,   -2,   -4,  116,  114,   97,  118,  101, // ...trave
1937                108,   47,   95,  109,  111,  114,  101,   50, // l/_more2
1938                 48,   48,   54,   47,   95,  109,  111,  114, // 006/_mor
1939                101,   49,   48,   47,  116,  114,  101,  107, // e10/trek
1940                 45,   52,   45,  100,   97,  121,  115,   45, // -4-days-
1941                102,  114,  111,  109,   45,   71,   97,  110, // from-Gan
1942                100,  101,  110,   45,  109,  111,  110,   97, // den-mona
1943                115,  116,  101,  114,  121,   45,   52,   53, // stery-45
1944                 48,   48,  109,   45,  118,  105,   97,   45, // 00m-via-
1945                 83,  104,  117,  103,   97,   45,   76,   97, // Shuga-La
1946                 45,  112,   97,  115,  115,   45,   67,  104, // -pass-Ch
1947                105,  116,  117,   45,   76,   97,   45,  112, // itu-La-p
1948                 97,  115,  115,   45,   53,   49,   48,   48, // ass-5100
1949                109,   45,  116,  114,  101,  107,  107,  101, // m-trekke
1950                114,  115,   45,  108,  111,   99,   97,  108, // rs-local
1951                 45,  103,  117,  105,  100,  101,  115,   45, // -guides-
1952                103,  114,   97,  115,  115,  121,   45,  115, // grassy-s
1953                108,  111,  112,  101,  115,   45,  121,   97, // lopes-ya
1954                107,  115,   45,  115,  110,  111,  119,   45, // ks-snow-
1955                 98,  108,  105,  122,  122,   97,  114,  100, // blizzard
1956                115,   45,  108,   97,  107,  101,  115,   45, // s-lakes-
1957                115,   97,  110,  100,   45,  100,  117,  110, // sand-dun
1958                101,  115,   45,  109,   97,  103,  105,   99, // es-magic
1959                 97,  108,   45,  115,   99,  101,  110,  101, // al-scene
1960                114,  121,   45,  114,  111,  111,  102,   45, // ry-roof-
1961                111,  102,   45,  116,  104,  101,   45,  119, // of-the-w
1962                111,  114,  108,  100,   45,  118,  105,  101, // orld-vie
1963                119,  115,   45,   98,  105,  122,   97,  114, // ws-bizar
1964                114,  101,   45,  116,  114,   97,  110,  115, // re-trans
1965                112,  111,  114,  116,   45,  110,  101,   97, // port-nea
1966                114,   45,   76,  104,   97,  115,   97,   45, // r-Lhasa-
1967                 84,  105,   98,  101,  116,   45,   56,   45, // Tibet-8-
1968                 67,   75,   66,   46,  106,  112,  103,  120, // CKB.jpgx
1969                115,  113,    0,  126,    0,    3,   16,   -5, // sq.~....
1970                113,    0,  126,    0,    6,  119,    2,    1, // q.~..w..
1971                 57,  120, // 9x
1972               };
1973    
1974        /**Basic serialisation tests of ExhibitFullName.
1975         */
1976        public static void testExhibitFullNameBasic()
1977            throws Exception
1978            {
1979            //assertImmutable(Name.ExhibitFull.class);
1980    
1981            // Test a short value (suitable for shorter on-the-wire encoding).
1982            final Name.ExhibitFull efn1 = Name.ExhibitFull.create("a/a-A.a");
1983            checkSerialisationPreservesEquality(efn1);
1984            // Check that we are able to extract this value from cold-store.
1985            final Name.ExhibitFull frozen1 = (Name.ExhibitFull) (new ObjectInputStream(new ByteArrayInputStream(serData_efn1_20090711))).readObject();
1986            assertEquals(efn1, frozen1);
1987    
1988            final String ln1 = "travel/_more2006/_more10/trek-4-days-from-Ganden-monastery-4500m-via-Shuga-La-pass-Chitu-La-pass-5100m-trekkers-local-guides-grassy-slopes-yaks-snow-blizzards-lakes-sand-dunes-magical-scenery-roof-of-the-world-views-bizarre-transport-near-Lhasa-Tibet-8-CKB.jpg";
1989            final String ln2 = "travel/_more2006/_more10/trek-4-days-from-Ganden-monastery-4500m-via-Shuga-La-pass-Chitu-La-pass-5100m-trekkers-local-guides-grassy-slopes-yaks-snow-blizzards-lakes-sand-dunes-magical-scenery-roof-of-the-world-views-bizarre-transport-near-Lhasa-Tibet-9-CKB.jpg";
1990    
1991            // Test a long value (suitable for shorter on-the-wire encoding).
1992            final Name.ExhibitFull efn2a = Name.ExhibitFull.create(ln1);
1993            checkSerialisationPreservesEquality(efn2a);
1994    
1995            // Test a couple pf values sharing a common prefix.
1996            final Name.ExhibitFull efn2b = Name.ExhibitFull.create(ln2, efn2a);
1997            final Tuple.Pair<Name.ExhibitFull,Name.ExhibitFull> pair = new Tuple.Pair<Name.ExhibitFull,Name.ExhibitFull>(efn2a, efn2b);
1998            checkSerialisationPreservesEquality(pair);
1999            // Check that we are able to extract this value from cold-store.
2000            final Tuple.Pair<Name.ExhibitFull,Name.ExhibitFull> frozenpair = (Tuple.Pair<Name.ExhibitFull,Name.ExhibitFull>) (new ObjectInputStream(new ByteArrayInputStream(serData_efnpair_20090711))).readObject();
2001            assertEquals(pair, frozenpair);
2002            }
2003    
2004        /**Check that the current AEP serialisation is not less compact (when compressed) than the last one persisted.
2005         * This is a useful test for tuning the serialised format
2006         * against a realistic/large AEP instance.
2007         * <p>
2008         * This is quiet-ish unless the AEP changes in size significantly
2009         * when re-serialised and GZIPped.  A big enough bloat is an error.
2010         * <p>
2011         * Often serialisation formats will compress slightly better
2012         * when less compact at the micro level
2013         * (ie if we avoid internally (over-)compressing each component first).
2014         * <p>
2015         * We only test with the last captured AEP, assumed to be the nearest to current.
2016         * <p>
2017         * This also measures code performance in the (de)serialisation path.
2018         */
2019        public static void testAEPSerialisationSize()
2020            throws Exception
2021            {
2022            final File lastAEPFile = new File(BackCompatTest.frozenAEPs.get(BackCompatTest.frozenAEPs.size()-1));
2023            final long lastAEPSize = lastAEPFile.length();
2024    
2025            Main.getOut().println("Using captured AEP " + lastAEPFile);
2026            Main.getOut().println("  Size (compressed) on disc (bytes): " + lastAEPSize);
2027            final AllExhibitProperties lastAEP =
2028                (AllExhibitProperties) FileTools.deserialiseFromFile(lastAEPFile, true);
2029    
2030    ////FIXME: TEMPORARY
2031    //    // Extract and dump the largest current single XML and description values.
2032    //    // We use these in other tests.
2033    //    String biggestDesc = "";
2034    //    String biggestMetaData = "";
2035    //    for(final String e : lastAEP.aeid.getAllExhibitNamesSet())
2036    //        {
2037    //        final ExhibitPropsComputable epc = lastAEP.getExhibitPropsComputable(e);
2038    //        if(epc != null)
2039    //            {
2040    //            final String md = epc.getMetadataAsXML();
2041    //            if((null != md) && (md.length() > biggestMetaData.length()))
2042    //                { biggestMetaData = md; }
2043    //            }
2044    //        final ExhibitPropsLoadable epl = lastAEP.getExhibitPropsLoadable(e);
2045    //        if(epl != null)
2046    //            {
2047    //            final String desc = epl.getDescription();
2048    //            if((null != desc) && (desc.length() > biggestDesc.length()))
2049    //                { biggestDesc = desc; }
2050    //            }
2051    //        }
2052    //    System.out.println("Biggest desc length="+biggestDesc.length());
2053    //    System.out.println(biggestDesc);
2054    //    System.out.println("Biggest metadata length="+biggestMetaData.length());
2055    //    System.out.println(biggestMetaData);
2056    
2057            final AllExhibitProperties newAEP = /* AllExhibitProperties.canonicalise */ (lastAEP);
2058            // Force to usual compact form in memory.
2059            final long cStart = System.nanoTime();
2060            newAEP.compact();
2061            final long cEnd = System.nanoTime();
2062            final long cNs = cEnd - cStart;
2063            Main.getOut().println("[AEP.compress() took "+cNs+"ns; mean ms/exhibit = " + (cNs / (newAEP.aeid.length * 1000))+"]");
2064            // Serialise to a byte[].
2065            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2066            // We may gzip the stream to remove some of the redundancy.
2067            final GZIPOutputStream gos = new GZIPOutputStream(baos);
2068            final DataOutputStream dos = new DataOutputStream(gos);
2069            final ObjectOutputStream oos = new ObjectOutputStream(dos);
2070            oos.writeObject(newAEP);
2071            oos.flush();
2072            gos.finish();
2073            oos.close();
2074            final byte data[] = baos.toByteArray();
2075    
2076            Main.getOut().println("  SIZE NOW: " + data.length + ", uncompressed: " + dos.size());
2077            if(data.length > lastAEPSize)
2078                {
2079                Main.getErr().println("  FILE NOW LARGER, WHOOPS!");
2080                assertTrue("compressed serialised AEP size has grown significantly",
2081                                data.length <= 8192 + ((11*lastAEPSize)/10));
2082                }
2083    
2084            // Deserialise to try to verify that we really didn't break anything.
2085            final ByteArrayInputStream bais = new ByteArrayInputStream(data);
2086            final GZIPInputStream gis = new GZIPInputStream(bais);
2087            final ObjectInputStream ois = new ObjectInputStream(gis);
2088            final AllExhibitProperties newAEPSerDeser = (AllExhibitProperties) ois.readObject();
2089            assertEquals("AEP must survive (de)serialisation in new format", newAEP, newAEPSerDeser);
2090    
2091            // Compute optimal static dictionaries for EPC and EPL (etc)
2092            // given the number of *unique* instances of each text held in memory,
2093            // ie assuming that we intern() duplicates
2094            // and so only save memory for the first instance compressed.
2095            if(ExhibitPropsComputable.sDict.isStatsEnabled() || ExhibitPropsLoadable.sDict.isStatsEnabled())
2096                {
2097                // Find all the unique EPL and EPC texts.
2098                final Set<String> uniqueEPLTexts = new HashSet<String>(newAEP.aeid.length);
2099                final Set<String> uniqueEPCTexts = new HashSet<String>(newAEP.aeid.length);
2100    
2101                for(final Name.ExhibitFull name : newAEP.aeid.getAllExhibitNamesSorted())
2102                    {
2103                    final ExhibitPropsComputable epc = newAEP.getExhibitPropsComputable(name);
2104                    if(epc != null)
2105                        {
2106                        // Capture what the class is internally trying to store/compress.
2107                        final String s = epc.getMetadataAsXMLTrimmed().toString();
2108                        if(s != null) { uniqueEPCTexts.add(s); }
2109                        }
2110                    final ExhibitPropsLoadable epl = newAEP.getExhibitPropsLoadable(name);
2111                    if(epl != null)
2112                        {
2113                        final String s = epl.getDescription();
2114                        if(s != null) { uniqueEPLTexts.add(s); }
2115                        }
2116                    }
2117    
2118                // Zero out any stats for the static (de)compression dictionaries.
2119                ExhibitPropsComputable.sDict.resetStats();
2120                ExhibitPropsLoadable.sDict.resetStats();
2121                WebUtils.sDictMD.resetStats();
2122    
2123                // Collect/dump stats to help generate good static dictionaries, etc.
2124                // Note that with a non-empty dictionary in place this shows residual "noise".
2125                // Skip/ignore items that cannot be compressed with Compact7BitString.
2126    
2127                for(final String s : uniqueEPCTexts)
2128                    { try { Compact7BitString.convertToCompact7BitString(s, ExhibitPropsComputable.sDict); } catch(final IllegalArgumentException e) { } }
2129                ExhibitPropsComputable.sDict.dumpStats(System.out);
2130    
2131                for(final String s : uniqueEPLTexts)
2132                    { try { Compact7BitString.convertToCompact7BitString(s, ExhibitPropsLoadable.sDict); } catch(final IllegalArgumentException e) { } }
2133                ExhibitPropsLoadable.sDict.dumpStats(System.out);
2134    
2135                for(final Name.ExhibitFull name : newAEP.aeid.getAllExhibitNamesSorted())
2136                    { WebUtils.getCatPageExhibitMetaDataHTMLRaw(name, newAEP); }
2137                WebUtils.sDictMD.dumpStats(System.out);
2138                }
2139    
2140            // See how well we can compress a serialised AEP.
2141            final Pair<CompressionLevel, byte[]> squished = GenUtils.compressObject(newAEP, GenUtils.MAX_SUPPORTED_COMPRESSION_LEVEL, false);
2142    Main.getOut().println("Maximal compression of AEP: scheme="+squished.first+", size="+squished.second.length);
2143    
2144            // Profile total cost of maximal decompression and deserialisation.
2145            // This reflects the costs at the (more common) client end.
2146            final ConcurrentHashMap<StackTraceElement, AtomicInteger> perfCounts = new ConcurrentHashMap<StackTraceElement, AtomicInteger>(1001);
2147            final ConcurrentMap<StackTraceElement, ConcurrentMap<StackTraceElement, AtomicInteger>> parentPerfCounts = new ConcurrentHashMap<StackTraceElement, ConcurrentMap<StackTraceElement, AtomicInteger>>(1001);
2148            final Thread perfMonitorThread = GenUtils.startThreadPerfMonitor(
2149                Thread.currentThread(),
2150                perfCounts,
2151                parentPerfCounts,
2152                "org.hd.", // Capture our code. // "org." ... and Apache (BZIP2) code.
2153                // Monitor thread for at most 1000s.
2154                System.currentTimeMillis() + 1000000, 50); // Sample relatively slowly, esp for WinTel development machine.
2155            try
2156                {
2157                final ObjectInputStream ois2 = new ObjectInputStream(GenUtils.wrapForDecompression(new ByteArrayInputStream(squished.second), squished.first));
2158                assertEquals("AEP must survive (de)serialisation after maximal compression", newAEP, ois2.readObject());
2159                }
2160            finally
2161                {
2162                GenUtils.stopPerfMonitorandDumpSamples(
2163                    perfMonitorThread,
2164                    "AEP (de)serialisation profile",
2165                    perfCounts,
2166                    parentPerfCounts,
2167                    20, GenUtils.systemOutLogger);
2168                }
2169            }
2170    
2171        /**Test text for CS8 (de)serialisation. */
2172        private static final String THE_HILLS_ARE_ALIVE = "The hills are alive...";
2173    
2174        /**Serialised CS8 form. */
2175        private static final byte serData_CS8Bit[/*75*/] = {
2176                -84,  -19,    0,    5,  115,  114,    0,   28, // ....sr..
2177                111,  114,  103,   46,  104,  100,   46,  100, // org.hd.d
2178                 46,  112,  103,   50,  107,   46,  115,  118, // .pg2k.sv
2179                114,   67,  111,  114,  101,   46,   67,   83, // rCore.CS
2180                 56,   66,  105,  116,   -7,  103,  -38,  -32, // 8Bit.g..
2181                 46,  -21,  -50,   91,    3,    0,    0,  120, // ...[...x
2182                112,  119,   23,   22,   84,  104,  101,   32, // pw..The.
2183                104,  105,  108,  108,  115,   32,   97,  114, // hills.ar
2184                101,   32,   97,  108,  105,  118,  101,   46, // e.alive.
2185                 46,   46,  120, // ..x
2186               };
2187    
2188        /**Test behaviour of CS8Bit object.
2189         * This is primarily used to allow efficient transmission of
2190         * properties values/updates over the wire.
2191         */
2192        public static void testCS8Bit()
2193            throws Exception
2194            {
2195            //assertImmutable(CS8Bit.class);
2196    
2197            // Test that an (empty) object can survive (de)serialisation intact.
2198            checkSerialisationPreservesEquality(CS8Bit.EMPTY);
2199            // Check for a non-empty instance.
2200            final CS8Bit v1 = new CS8Bit(THE_HILLS_ARE_ALIVE);
2201            checkSerialisationPreservesEquality(v1);
2202            // Check that we are able to extract this value from cold-store.
2203            final CS8Bit frozen1 = (CS8Bit) (new ObjectInputStream(new ByteArrayInputStream(serData_CS8Bit))).readObject();
2204            assertEquals(v1, frozen1);
2205            // Check (de)serialisation for long enough text to require alternate form...
2206            final CS8Bit long1 = new CS8Bit("A long text to force alternate form of length value.  The quick brown fox jumps over the lazy dog.  Rats live on no evil star.  Madam, I'm Adam.");
2207            assert(long1.length() > 128);
2208            checkSerialisationPreservesEquality(long1);
2209            }
2210    
2211        /**Test that MetaData lightweight copy serialises the same as the original.
2212         * This allows a quick copy to be taken
2213         * and then saving to continue in parallel with further updates.
2214         */
2215        public static void testMetaDataLWCopy()
2216            throws Exception
2217            {
2218            final MetaData e = MetaData.createMetaData();
2219            final byte[] eb = serialiseToByteArray(e);
2220            assertNotNull(eb);
2221            final byte[] ecb = serialiseToByteArray(e.createLightweightCopy());
2222            assertTrue("serialising lightweight copy (of empty instance) should be identical to serialising original", Arrays.equals(eb, ecb));
2223    
2224            // Check that old serialised MetaData can be loaded
2225            // and that serialising/deserialising a lightweight copy gives the same result.
2226            final File oldMDser = new File(BackCompatTest.testDataDir, "20110926._metadata.data");
2227            final MetaData md = (MetaData) FileTools.deserialiseFromFile(oldMDser, true);
2228            final MetaData mdc = md.createLightweightCopy();
2229            assertEquals("set of names should be same", md.getKnownExhibits(), mdc.getKnownExhibits());
2230            final byte[] mdcb = serialiseToByteArray(mdc.createLightweightCopy());
2231            final MetaData mdcd = (MetaData) deserialiseFromByteArray(mdcb);
2232            assertEquals("set of names should be same", md.getKnownExhibits(), mdcd.getKnownExhibits());
2233            // TODO: test content beyond just set of names...
2234            }
2235    
2236    
2237        /**Private source of OK pseudo-random numbers. */
2238        private static final Random rnd = new Random();
2239        }