瀏覽代碼

HPCC-10957 Don't include unicode ignore codepoints in hash32 etc

Signed-off-by: Gavin Halliday <gavin.halliday@lexisnexis.com>
Gavin Halliday 11 年之前
父節點
當前提交
32499e7ff6
共有 4 個文件被更改,包括 624 次插入22 次删除
  1. 1 1
      ecl/hql/hqlfold.cpp
  2. 135 21
      rtl/eclrtl/eclrtl.cpp
  3. 56 0
      testing/regress/ecl/issue10957.ecl
  4. 432 0
      testing/regress/ecl/key/issue10957.xml

+ 1 - 1
ecl/hql/hqlfold.cpp

@@ -1579,7 +1579,7 @@ static bool hashElement(node_operator op, IHqlExpression * expr, unsigned __int6
         case type_unicode:
             {
                 const UChar * udata = static_cast<const UChar *>(value->queryValue());
-                size32_t len = rtlTrimUnicodeStrLen(type->getStringLen(), udata);
+                size32_t len = type->getStringLen();
                 hashCode = (op == no_hash32) ? rtlHash32Unicode(len, udata, (unsigned)hashCode) : rtlHash64Unicode(len, udata, hashCode);
                 return true;
             }

+ 135 - 21
rtl/eclrtl/eclrtl.cpp

@@ -122,6 +122,47 @@ ECLRTL_API byte * * rtlLinkRowset(byte * * rowset)
 
 // escape
 
+static bool stripIgnorableCharacters(size32_t & lenResult, UChar * & result, size32_t length, const UChar * in)
+{
+    unsigned numStripped = 0;
+    unsigned lastGood = 0;
+    for (unsigned i=0; i < length; i++)
+    {
+        UChar32 c = in[i];
+        unsigned stripSize = 0;
+        if (U16_IS_SURROGATE(c))
+        {
+            U16_GET(in, 0, i, length, c);
+            if (u_hasBinaryProperty(c, UCHAR_DEFAULT_IGNORABLE_CODE_POINT))
+                stripSize = 2;
+            else
+                i++; // skip the surrogate
+        }
+        else
+        {
+            if (u_hasBinaryProperty(c, UCHAR_DEFAULT_IGNORABLE_CODE_POINT))
+                stripSize = 1;
+        }
+
+        if (stripSize != 0)
+        {
+            if (numStripped == 0)
+                result = (UChar *)rtlMalloc((length-stripSize)*sizeof(UChar));
+
+            //Copy and non ignorable characters skipped up to this point.  (Note result+x is scaled by UChar)
+            memcpy(result + lastGood - numStripped, in+lastGood, (i-lastGood) * sizeof(UChar));
+            lastGood = i+stripSize;
+            numStripped += stripSize;
+            i += (stripSize-1);
+        }
+    }
+    if (numStripped == 0)
+        return false;
+    lenResult = length-numStripped;
+    memcpy(result + lastGood - numStripped, in+lastGood, (length-lastGood) * sizeof(UChar));
+    return true;
+}
+
 void escapeUnicode(unsigned inlen, UChar const * in, StringBuffer & out)
 {
     UCharCharacterIterator iter(in, inlen);
@@ -3380,6 +3421,7 @@ void rtlStrToEStrX(unsigned & tlen, char * & tgt, unsigned slen, const char * sr
 
 #define FNV1_64_INIT HASH64_INIT
 #define FNV_64_PRIME I64C(0x100000001b3U)
+#define APPLY_FNV64(hval, next) { hval *= FNV_64_PRIME; hval ^= next; }
 
 
 hash64_t rtlHash64Data(size32_t len, const void *buf, hash64_t hval)
@@ -3389,8 +3431,7 @@ hash64_t rtlHash64Data(size32_t len, const void *buf, hash64_t hval)
 
     while (bp < be) 
     {
-        hval *= FNV_64_PRIME;
-        hval ^= *bp++;
+        APPLY_FNV64(hval, *bp++);
     }
 
     return hval;
@@ -3404,21 +3445,48 @@ hash64_t rtlHash64VStr(const char *str, hash64_t hval)
 
     while ((c = *s++) != 0) 
     {
-        hval *= FNV_64_PRIME;
-        hval ^= c;
+        APPLY_FNV64(hval, c);
     }
 
     return hval;
 }
 
-hash64_t rtlHash64Unicode(unsigned length, UChar const * k, hash64_t initval)
+hash64_t rtlHash64Unicode(unsigned length, UChar const * k, hash64_t hval)
 {
-    return rtlHash64Data(length*2, k, initval);
+    unsigned trimLength = rtlTrimUnicodeStrLen(length, k);
+    for (unsigned i=0; i < trimLength; i++)
+    {
+        //Handle surrogate pairs correctly, but still hash the utf16 representation
+        const byte * cur = reinterpret_cast<const byte *>(&k[i]);
+        UChar32 c = k[i];
+        if (U16_IS_SURROGATE(c))
+        {
+            U16_GET(k, 0, i, length, c);
+            if (!u_hasBinaryProperty(c, UCHAR_DEFAULT_IGNORABLE_CODE_POINT))
+            {
+                APPLY_FNV64(hval, cur[0]);
+                APPLY_FNV64(hval, cur[1]);
+                APPLY_FNV64(hval, cur[2]);
+                APPLY_FNV64(hval, cur[3]);
+            }
+            //Skip the surrogate pair
+            i++;
+        }
+        else
+        {
+            if (!u_hasBinaryProperty(c, UCHAR_DEFAULT_IGNORABLE_CODE_POINT))
+            {
+                APPLY_FNV64(hval, cur[0]);
+                APPLY_FNV64(hval, cur[1]);
+            }
+        }
+    }
+    return hval;
 }
 
 hash64_t rtlHash64VUnicode(UChar const * k, hash64_t initval)
 {
-    return rtlHash64Data(rtlUnicodeStrlen(k)*2, k, initval);
+    return rtlHash64Unicode(rtlUnicodeStrlen(k), k, initval);
 }
 
 
@@ -3428,6 +3496,7 @@ hash64_t rtlHash64VUnicode(UChar const * k, hash64_t initval)
 
 #define FNV1_32_INIT HASH32_INIT
 #define FNV_32_PRIME 0x1000193
+#define APPLY_FNV32(hval, next) { hval *= FNV_32_PRIME; hval ^= next; }
 
 
 unsigned rtlHash32Data(size32_t len, const void *buf, unsigned hval)
@@ -3437,8 +3506,7 @@ unsigned rtlHash32Data(size32_t len, const void *buf, unsigned hval)
 
     while (bp < be) 
     {
-        hval *= FNV_32_PRIME;
-        hval ^= *bp++;
+        APPLY_FNV32(hval, *bp++);
     }
 
     return hval;
@@ -3452,21 +3520,48 @@ unsigned rtlHash32VStr(const char *str, unsigned hval)
 
     while ((c = *s++) != 0) 
     {
-        hval *= FNV_32_PRIME;
-        hval ^= c;
+        APPLY_FNV32(hval, c);
     }
 
     return hval;
 }
 
-unsigned rtlHash32Unicode(unsigned length, UChar const * k, unsigned initval)
+unsigned rtlHash32Unicode(unsigned length, UChar const * k, unsigned hval)
 {
-    return rtlHash32Data(length*2, k, initval);
+    unsigned trimLength = rtlTrimUnicodeStrLen(length, k);
+    for (unsigned i=0; i < trimLength; i++)
+    {
+        //Handle surrogate pairs correctly, but still hash the utf16 representation
+        const byte * cur = reinterpret_cast<const byte *>(&k[i]);
+        UChar32 c = k[i];
+        if (U16_IS_SURROGATE(c))
+        {
+            U16_GET(k, 0, i, length, c);
+            if (!u_hasBinaryProperty(c, UCHAR_DEFAULT_IGNORABLE_CODE_POINT))
+            {
+                APPLY_FNV32(hval, cur[0]);
+                APPLY_FNV32(hval, cur[1]);
+                APPLY_FNV32(hval, cur[2]);
+                APPLY_FNV32(hval, cur[3]);
+            }
+            //Skip the surrogate pair
+            i++;
+        }
+        else
+        {
+            if (!u_hasBinaryProperty(c, UCHAR_DEFAULT_IGNORABLE_CODE_POINT))
+            {
+                APPLY_FNV32(hval, cur[0]);
+                APPLY_FNV32(hval, cur[1]);
+            }
+        }
+    }
+    return hval;
 }
 
 unsigned rtlHash32VUnicode(UChar const * k, unsigned initval)
 {
-    return rtlHash32Data(rtlUnicodeStrlen(k)*2, k, initval);
+    return rtlHash32Unicode(rtlUnicodeStrlen(k), k, initval);
 }
 
 
@@ -3549,8 +3644,14 @@ unsigned rtlHashString( unsigned length, const char *_k, unsigned initval)
 
 unsigned rtlHashUnicode(unsigned length, UChar const * k, unsigned initval)
 {
-    //Would make more sense to trim here.
-    return rtlHashData(length*2, k, initval);
+    unsigned trimLength = rtlTrimUnicodeStrLen(length, k);
+    //Because of the implementation of HASH we need to strip ignoreable code points instead of skipping them
+    size32_t tempLength;
+    rtlDataAttr temp;
+    if (stripIgnorableCharacters(tempLength, temp.refustr(), trimLength, k))
+        return rtlHashData(tempLength*2, temp.getustr(), initval);
+
+    return rtlHashData(trimLength*sizeof(UChar), k, initval);
 }
 
 unsigned rtlHashVStr(const char * k, unsigned initval)
@@ -3560,7 +3661,7 @@ unsigned rtlHashVStr(const char * k, unsigned initval)
 
 unsigned rtlHashVUnicode(UChar const * k, unsigned initval)
 {
-    return rtlHashData(rtlTrimVUnicodeStrLen(k)*2, k, initval);
+    return rtlHashUnicode(rtlTrimVUnicodeStrLen(k), k, initval);
 }
 
 #define GETWORDNC(k,n) ((GETBYTE0(n)+GETBYTE1(n)+GETBYTE2(n)+GETBYTE3(n))&0xdfdfdfdf)
@@ -3635,7 +3736,7 @@ unsigned rtlCrcVStr( const char * k, unsigned initval)
 
 unsigned rtlCrcVUnicode(UChar const * k, unsigned initval)
 {
-    return crc32((char const *)k, rtlUnicodeStrlen(k)*2, initval);
+    return rtlCrcUnicode(rtlUnicodeStrlen(k), k, initval);
 }
 
 //---------------------------------------------------------------------------
@@ -4617,17 +4718,30 @@ ECLRTL_API void rtlUtf8SpaceFill(unsigned tlen, char * tgt, unsigned offset)
 
 ECLRTL_API unsigned rtlHash32Utf8(unsigned length, const char * k, unsigned initval)
 {
-    return rtlHash32Data(rtlUtf8Size(length, k), k, initval);
+    //These need to hash the same way as a UNICODE string would => convert to UNICODE
+    //It would be hard to optimize to hash the string without performing the conversion.
+    size32_t tempLength;
+    rtlDataAttr temp;
+    rtlUtf8ToUnicodeX(tempLength, temp.refustr(), length, k);
+    return rtlHash32Unicode(tempLength, temp.getustr(), initval);
 }
 
 ECLRTL_API unsigned rtlHashUtf8(unsigned length, const char * k, unsigned initval)
 {
-    return rtlHashData(rtlUtf8Size(length, k), k, initval);
+    //These need to hash the same way as a UNICODE string would => convert to UNICODE
+    size32_t tempLength;
+    rtlDataAttr temp;
+    rtlUtf8ToUnicodeX(tempLength, temp.refustr(), length, k);
+    return rtlHashUnicode(tempLength, temp.getustr(), initval);
 }
 
 ECLRTL_API hash64_t rtlHash64Utf8(unsigned length, const char * k, hash64_t initval)
 {
-    return rtlHash64Data(rtlUtf8Size(length, k), k, initval);
+    //These need to hash the same way as a UNICODE string would => convert to UNICODE
+    size32_t tempLength;
+    rtlDataAttr temp;
+    rtlUtf8ToUnicodeX(tempLength, temp.refustr(), length, k);
+    return rtlHash64Unicode(tempLength, temp.getustr(), initval);
 }
 
 unsigned rtlCrcUtf8(unsigned length, const char * k, unsigned initval)

+ 56 - 0
testing/regress/ecl/issue10957.ecl

@@ -0,0 +1,56 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+//Check consistency of equality and the hash functions.  NOTE: hashcrc and Hashmd5 are not expected to be consistent for ignore characters and trailing spaces
+
+ucompare(unicode a, unicode b) :=
+    [ output('Unicode:'); output(a = b); output(hash(a) = hash(b)); output(hash32(a) = hash32(b)); output(hash64(a) = hash64(b)) ];
+
+vcompare(varunicode a, varunicode b) :=
+    [ output('VarUnicode:'); output(a = b); output(hash(a) = hash(b)); output(hash32(a) = hash32(b)); output(hash64(a) = hash64(b)) ];
+
+compare8(utf8 a, utf8 b) :=
+    [ output('Utf8:'); output(a = b); output(hash(a) = hash(b)); output(hash32(a) = hash32(b)); output(hash64(a) = hash64(b)) ];
+
+compare(unicode a, unicode b) :=
+    [ output('Compare: "' + a + '" with "' + b + '"'); ucompare(a,b); vcompare(a, b), compare8(a,b) ];
+
+compare(U'Gavin', U'Gavin');
+compare(U'Gavin   ', U'Gavin');
+
+compare(U'Gavin\u00ADHalliday', U'GavinHalliday');
+compare(U'Gavin\u200BHalliday', U'GavinHalliday');
+
+compare(U'Gavin\u00AD\u200B\u200B\u200BHalliday', U'GavinHalliday');
+compare(U'Gavin\u200BHalliday', U'Gavin\u200B\u200B\u200BHalliday');
+
+hashes(unicode a) :=
+    [ output('Hashes: "' + a + '"');
+      output(hash(a) = hash((varunicode)a));
+      output(hash32(a) = hash32((varunicode)a));
+      output(hash64(a) = hash64((varunicode)a));
+      output(hash(a) = hash((utf8)a));
+      output(hash32(a) = hash32((utf8)a));
+      output(hash64(a) = hash64((utf8)a));
+      output(hash(a)); output(hash32(a)); output(hash64(a));
+      output(hashcrc(a)); output(hashmd5(a)) ];
+
+
+hashes(U'Gavin');
+hashes(U'Gavin   ');
+hashes(U'G\u00ADav\u200B\u200Bin   ');
+hashes(U'G\U0001D11Eavin   ');		// G clef surrogate pair character

+ 432 - 0
testing/regress/ecl/key/issue10957.xml

@@ -0,0 +1,432 @@
+<Dataset name='Result 1'>
+ <Row><Result_1>Compare: &quot;Gavin&quot; with &quot;Gavin&quot;</Result_1></Row>
+</Dataset>
+<Dataset name='Result 2'>
+ <Row><Result_2>Unicode:</Result_2></Row>
+</Dataset>
+<Dataset name='Result 3'>
+ <Row><Result_3>true</Result_3></Row>
+</Dataset>
+<Dataset name='Result 4'>
+ <Row><Result_4>true</Result_4></Row>
+</Dataset>
+<Dataset name='Result 5'>
+ <Row><Result_5>true</Result_5></Row>
+</Dataset>
+<Dataset name='Result 6'>
+ <Row><Result_6>true</Result_6></Row>
+</Dataset>
+<Dataset name='Result 7'>
+ <Row><Result_7>VarUnicode:</Result_7></Row>
+</Dataset>
+<Dataset name='Result 8'>
+ <Row><Result_8>true</Result_8></Row>
+</Dataset>
+<Dataset name='Result 9'>
+ <Row><Result_9>true</Result_9></Row>
+</Dataset>
+<Dataset name='Result 10'>
+ <Row><Result_10>true</Result_10></Row>
+</Dataset>
+<Dataset name='Result 11'>
+ <Row><Result_11>true</Result_11></Row>
+</Dataset>
+<Dataset name='Result 12'>
+ <Row><Result_12>Utf8:</Result_12></Row>
+</Dataset>
+<Dataset name='Result 13'>
+ <Row><Result_13>true</Result_13></Row>
+</Dataset>
+<Dataset name='Result 14'>
+ <Row><Result_14>true</Result_14></Row>
+</Dataset>
+<Dataset name='Result 15'>
+ <Row><Result_15>true</Result_15></Row>
+</Dataset>
+<Dataset name='Result 16'>
+ <Row><Result_16>true</Result_16></Row>
+</Dataset>
+<Dataset name='Result 17'>
+ <Row><Result_17>Compare: &quot;Gavin   &quot; with &quot;Gavin&quot;</Result_17></Row>
+</Dataset>
+<Dataset name='Result 18'>
+ <Row><Result_18>Unicode:</Result_18></Row>
+</Dataset>
+<Dataset name='Result 19'>
+ <Row><Result_19>true</Result_19></Row>
+</Dataset>
+<Dataset name='Result 20'>
+ <Row><Result_20>true</Result_20></Row>
+</Dataset>
+<Dataset name='Result 21'>
+ <Row><Result_21>true</Result_21></Row>
+</Dataset>
+<Dataset name='Result 22'>
+ <Row><Result_22>true</Result_22></Row>
+</Dataset>
+<Dataset name='Result 23'>
+ <Row><Result_23>VarUnicode:</Result_23></Row>
+</Dataset>
+<Dataset name='Result 24'>
+ <Row><Result_24>true</Result_24></Row>
+</Dataset>
+<Dataset name='Result 25'>
+ <Row><Result_25>true</Result_25></Row>
+</Dataset>
+<Dataset name='Result 26'>
+ <Row><Result_26>true</Result_26></Row>
+</Dataset>
+<Dataset name='Result 27'>
+ <Row><Result_27>true</Result_27></Row>
+</Dataset>
+<Dataset name='Result 28'>
+ <Row><Result_28>Utf8:</Result_28></Row>
+</Dataset>
+<Dataset name='Result 29'>
+ <Row><Result_29>true</Result_29></Row>
+</Dataset>
+<Dataset name='Result 30'>
+ <Row><Result_30>true</Result_30></Row>
+</Dataset>
+<Dataset name='Result 31'>
+ <Row><Result_31>true</Result_31></Row>
+</Dataset>
+<Dataset name='Result 32'>
+ <Row><Result_32>true</Result_32></Row>
+</Dataset>
+<Dataset name='Result 33'>
+ <Row><Result_33>Compare: &quot;Gavin­Halliday&quot; with &quot;GavinHalliday&quot;</Result_33></Row>
+</Dataset>
+<Dataset name='Result 34'>
+ <Row><Result_34>Unicode:</Result_34></Row>
+</Dataset>
+<Dataset name='Result 35'>
+ <Row><Result_35>true</Result_35></Row>
+</Dataset>
+<Dataset name='Result 36'>
+ <Row><Result_36>true</Result_36></Row>
+</Dataset>
+<Dataset name='Result 37'>
+ <Row><Result_37>true</Result_37></Row>
+</Dataset>
+<Dataset name='Result 38'>
+ <Row><Result_38>true</Result_38></Row>
+</Dataset>
+<Dataset name='Result 39'>
+ <Row><Result_39>VarUnicode:</Result_39></Row>
+</Dataset>
+<Dataset name='Result 40'>
+ <Row><Result_40>true</Result_40></Row>
+</Dataset>
+<Dataset name='Result 41'>
+ <Row><Result_41>true</Result_41></Row>
+</Dataset>
+<Dataset name='Result 42'>
+ <Row><Result_42>true</Result_42></Row>
+</Dataset>
+<Dataset name='Result 43'>
+ <Row><Result_43>true</Result_43></Row>
+</Dataset>
+<Dataset name='Result 44'>
+ <Row><Result_44>Utf8:</Result_44></Row>
+</Dataset>
+<Dataset name='Result 45'>
+ <Row><Result_45>true</Result_45></Row>
+</Dataset>
+<Dataset name='Result 46'>
+ <Row><Result_46>true</Result_46></Row>
+</Dataset>
+<Dataset name='Result 47'>
+ <Row><Result_47>true</Result_47></Row>
+</Dataset>
+<Dataset name='Result 48'>
+ <Row><Result_48>true</Result_48></Row>
+</Dataset>
+<Dataset name='Result 49'>
+ <Row><Result_49>Compare: &quot;Gavin​Halliday&quot; with &quot;GavinHalliday&quot;</Result_49></Row>
+</Dataset>
+<Dataset name='Result 50'>
+ <Row><Result_50>Unicode:</Result_50></Row>
+</Dataset>
+<Dataset name='Result 51'>
+ <Row><Result_51>true</Result_51></Row>
+</Dataset>
+<Dataset name='Result 52'>
+ <Row><Result_52>true</Result_52></Row>
+</Dataset>
+<Dataset name='Result 53'>
+ <Row><Result_53>true</Result_53></Row>
+</Dataset>
+<Dataset name='Result 54'>
+ <Row><Result_54>true</Result_54></Row>
+</Dataset>
+<Dataset name='Result 55'>
+ <Row><Result_55>VarUnicode:</Result_55></Row>
+</Dataset>
+<Dataset name='Result 56'>
+ <Row><Result_56>true</Result_56></Row>
+</Dataset>
+<Dataset name='Result 57'>
+ <Row><Result_57>true</Result_57></Row>
+</Dataset>
+<Dataset name='Result 58'>
+ <Row><Result_58>true</Result_58></Row>
+</Dataset>
+<Dataset name='Result 59'>
+ <Row><Result_59>true</Result_59></Row>
+</Dataset>
+<Dataset name='Result 60'>
+ <Row><Result_60>Utf8:</Result_60></Row>
+</Dataset>
+<Dataset name='Result 61'>
+ <Row><Result_61>true</Result_61></Row>
+</Dataset>
+<Dataset name='Result 62'>
+ <Row><Result_62>true</Result_62></Row>
+</Dataset>
+<Dataset name='Result 63'>
+ <Row><Result_63>true</Result_63></Row>
+</Dataset>
+<Dataset name='Result 64'>
+ <Row><Result_64>true</Result_64></Row>
+</Dataset>
+<Dataset name='Result 65'>
+ <Row><Result_65>Compare: &quot;Gavin­​​​Halliday&quot; with &quot;GavinHalliday&quot;</Result_65></Row>
+</Dataset>
+<Dataset name='Result 66'>
+ <Row><Result_66>Unicode:</Result_66></Row>
+</Dataset>
+<Dataset name='Result 67'>
+ <Row><Result_67>true</Result_67></Row>
+</Dataset>
+<Dataset name='Result 68'>
+ <Row><Result_68>true</Result_68></Row>
+</Dataset>
+<Dataset name='Result 69'>
+ <Row><Result_69>true</Result_69></Row>
+</Dataset>
+<Dataset name='Result 70'>
+ <Row><Result_70>true</Result_70></Row>
+</Dataset>
+<Dataset name='Result 71'>
+ <Row><Result_71>VarUnicode:</Result_71></Row>
+</Dataset>
+<Dataset name='Result 72'>
+ <Row><Result_72>true</Result_72></Row>
+</Dataset>
+<Dataset name='Result 73'>
+ <Row><Result_73>true</Result_73></Row>
+</Dataset>
+<Dataset name='Result 74'>
+ <Row><Result_74>true</Result_74></Row>
+</Dataset>
+<Dataset name='Result 75'>
+ <Row><Result_75>true</Result_75></Row>
+</Dataset>
+<Dataset name='Result 76'>
+ <Row><Result_76>Utf8:</Result_76></Row>
+</Dataset>
+<Dataset name='Result 77'>
+ <Row><Result_77>true</Result_77></Row>
+</Dataset>
+<Dataset name='Result 78'>
+ <Row><Result_78>true</Result_78></Row>
+</Dataset>
+<Dataset name='Result 79'>
+ <Row><Result_79>true</Result_79></Row>
+</Dataset>
+<Dataset name='Result 80'>
+ <Row><Result_80>true</Result_80></Row>
+</Dataset>
+<Dataset name='Result 81'>
+ <Row><Result_81>Compare: &quot;Gavin​Halliday&quot; with &quot;Gavin​​​Halliday&quot;</Result_81></Row>
+</Dataset>
+<Dataset name='Result 82'>
+ <Row><Result_82>Unicode:</Result_82></Row>
+</Dataset>
+<Dataset name='Result 83'>
+ <Row><Result_83>true</Result_83></Row>
+</Dataset>
+<Dataset name='Result 84'>
+ <Row><Result_84>true</Result_84></Row>
+</Dataset>
+<Dataset name='Result 85'>
+ <Row><Result_85>true</Result_85></Row>
+</Dataset>
+<Dataset name='Result 86'>
+ <Row><Result_86>true</Result_86></Row>
+</Dataset>
+<Dataset name='Result 87'>
+ <Row><Result_87>VarUnicode:</Result_87></Row>
+</Dataset>
+<Dataset name='Result 88'>
+ <Row><Result_88>true</Result_88></Row>
+</Dataset>
+<Dataset name='Result 89'>
+ <Row><Result_89>true</Result_89></Row>
+</Dataset>
+<Dataset name='Result 90'>
+ <Row><Result_90>true</Result_90></Row>
+</Dataset>
+<Dataset name='Result 91'>
+ <Row><Result_91>true</Result_91></Row>
+</Dataset>
+<Dataset name='Result 92'>
+ <Row><Result_92>Utf8:</Result_92></Row>
+</Dataset>
+<Dataset name='Result 93'>
+ <Row><Result_93>true</Result_93></Row>
+</Dataset>
+<Dataset name='Result 94'>
+ <Row><Result_94>true</Result_94></Row>
+</Dataset>
+<Dataset name='Result 95'>
+ <Row><Result_95>true</Result_95></Row>
+</Dataset>
+<Dataset name='Result 96'>
+ <Row><Result_96>true</Result_96></Row>
+</Dataset>
+<Dataset name='Result 97'>
+ <Row><Result_97>Hashes: &quot;Gavin&quot;</Result_97></Row>
+</Dataset>
+<Dataset name='Result 98'>
+ <Row><Result_98>true</Result_98></Row>
+</Dataset>
+<Dataset name='Result 99'>
+ <Row><Result_99>true</Result_99></Row>
+</Dataset>
+<Dataset name='Result 100'>
+ <Row><Result_100>true</Result_100></Row>
+</Dataset>
+<Dataset name='Result 101'>
+ <Row><Result_101>true</Result_101></Row>
+</Dataset>
+<Dataset name='Result 102'>
+ <Row><Result_102>true</Result_102></Row>
+</Dataset>
+<Dataset name='Result 103'>
+ <Row><Result_103>true</Result_103></Row>
+</Dataset>
+<Dataset name='Result 104'>
+ <Row><Result_104>3800901229</Result_104></Row>
+</Dataset>
+<Dataset name='Result 105'>
+ <Row><Result_105>769280520</Result_105></Row>
+</Dataset>
+<Dataset name='Result 106'>
+ <Row><Result_106>13959046736378758344</Result_106></Row>
+</Dataset>
+<Dataset name='Result 107'>
+ <Row><Result_107>830592</Result_107></Row>
+</Dataset>
+<Dataset name='Result 108'>
+ <Row><Result_108>AE477B3374986D70424A6425E59AF0E4</Result_108></Row>
+</Dataset>
+<Dataset name='Result 109'>
+ <Row><Result_109>Hashes: &quot;Gavin   &quot;</Result_109></Row>
+</Dataset>
+<Dataset name='Result 110'>
+ <Row><Result_110>true</Result_110></Row>
+</Dataset>
+<Dataset name='Result 111'>
+ <Row><Result_111>true</Result_111></Row>
+</Dataset>
+<Dataset name='Result 112'>
+ <Row><Result_112>true</Result_112></Row>
+</Dataset>
+<Dataset name='Result 113'>
+ <Row><Result_113>true</Result_113></Row>
+</Dataset>
+<Dataset name='Result 114'>
+ <Row><Result_114>true</Result_114></Row>
+</Dataset>
+<Dataset name='Result 115'>
+ <Row><Result_115>true</Result_115></Row>
+</Dataset>
+<Dataset name='Result 116'>
+ <Row><Result_116>3800901229</Result_116></Row>
+</Dataset>
+<Dataset name='Result 117'>
+ <Row><Result_117>769280520</Result_117></Row>
+</Dataset>
+<Dataset name='Result 118'>
+ <Row><Result_118>13959046736378758344</Result_118></Row>
+</Dataset>
+<Dataset name='Result 119'>
+ <Row><Result_119>830592</Result_119></Row>
+</Dataset>
+<Dataset name='Result 120'>
+ <Row><Result_120>4E169928A78263FB2E6E490EAC500AA0</Result_120></Row>
+</Dataset>
+<Dataset name='Result 121'>
+ <Row><Result_121>Hashes: &quot;G­av​​in   &quot;</Result_121></Row>
+</Dataset>
+<Dataset name='Result 122'>
+ <Row><Result_122>true</Result_122></Row>
+</Dataset>
+<Dataset name='Result 123'>
+ <Row><Result_123>true</Result_123></Row>
+</Dataset>
+<Dataset name='Result 124'>
+ <Row><Result_124>true</Result_124></Row>
+</Dataset>
+<Dataset name='Result 125'>
+ <Row><Result_125>true</Result_125></Row>
+</Dataset>
+<Dataset name='Result 126'>
+ <Row><Result_126>true</Result_126></Row>
+</Dataset>
+<Dataset name='Result 127'>
+ <Row><Result_127>true</Result_127></Row>
+</Dataset>
+<Dataset name='Result 128'>
+ <Row><Result_128>3800901229</Result_128></Row>
+</Dataset>
+<Dataset name='Result 129'>
+ <Row><Result_129>769280520</Result_129></Row>
+</Dataset>
+<Dataset name='Result 130'>
+ <Row><Result_130>13959046736378758344</Result_130></Row>
+</Dataset>
+<Dataset name='Result 131'>
+ <Row><Result_131>3863689467</Result_131></Row>
+</Dataset>
+<Dataset name='Result 132'>
+ <Row><Result_132>8105639F5B65790DCE903698C56265B3</Result_132></Row>
+</Dataset>
+<Dataset name='Result 133'>
+ <Row><Result_133>Hashes: &quot;G𝄞avin   &quot;</Result_133></Row>
+</Dataset>
+<Dataset name='Result 134'>
+ <Row><Result_134>true</Result_134></Row>
+</Dataset>
+<Dataset name='Result 135'>
+ <Row><Result_135>true</Result_135></Row>
+</Dataset>
+<Dataset name='Result 136'>
+ <Row><Result_136>true</Result_136></Row>
+</Dataset>
+<Dataset name='Result 137'>
+ <Row><Result_137>true</Result_137></Row>
+</Dataset>
+<Dataset name='Result 138'>
+ <Row><Result_138>true</Result_138></Row>
+</Dataset>
+<Dataset name='Result 139'>
+ <Row><Result_139>true</Result_139></Row>
+</Dataset>
+<Dataset name='Result 140'>
+ <Row><Result_140>2837458134</Result_140></Row>
+</Dataset>
+<Dataset name='Result 141'>
+ <Row><Result_141>108645843</Result_141></Row>
+</Dataset>
+<Dataset name='Result 142'>
+ <Row><Result_142>18162734623378106963</Result_142></Row>
+</Dataset>
+<Dataset name='Result 143'>
+ <Row><Result_143>646119128</Result_143></Row>
+</Dataset>
+<Dataset name='Result 144'>
+ <Row><Result_144>126FFAEFE2DE0B88FA2B6AD1C3BFBEB6</Result_144></Row>
+</Dataset>