msgpackr 1.11.2 → 1.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/test.js CHANGED
@@ -967,7 +967,10 @@
967
967
  if (typeof property === 'string') return property;
968
968
  if (typeof property === 'number' || typeof property === 'boolean' || typeof property === 'bigint') return property.toString();
969
969
  if (property == null) return property + '';
970
- throw new Error('Invalid property type for record', typeof property);
970
+ if (currentUnpackr.allowArraysInMapKeys && Array.isArray(property) && property.flat().every(item => ['string', 'number', 'boolean', 'bigint'].includes(typeof item))) {
971
+ return property.flat().toString();
972
+ }
973
+ throw new Error(`Invalid property type for record: ${typeof property}`);
971
974
  }
972
975
  // the registration of the record definition extension (as "r")
973
976
  const recordDefinition = (id, highByte) => {
@@ -992,21 +995,47 @@
992
995
  currentExtensions[0] = () => {}; // notepack defines extension 0 to mean undefined, so use that as the default here
993
996
  currentExtensions[0].noBuffer = true;
994
997
 
995
- currentExtensions[0x42] = (data) => {
996
- // decode bigint
997
- let length = data.length;
998
- let value = BigInt(data[0] & 0x80 ? data[0] - 0x100 : data[0]);
999
- for (let i = 1; i < length; i++) {
1000
- value <<= BigInt(8);
1001
- value += BigInt(data[i]);
998
+ currentExtensions[0x42] = data => {
999
+ let headLength = (data.byteLength % 8) || 8;
1000
+ let head = BigInt(data[0] & 0x80 ? data[0] - 0x100 : data[0]);
1001
+ for (let i = 1; i < headLength; i++) {
1002
+ head <<= BigInt(8);
1003
+ head += BigInt(data[i]);
1004
+ }
1005
+ if (data.byteLength !== headLength) {
1006
+ let view = new DataView(data.buffer, data.byteOffset, data.byteLength);
1007
+ let decode = (start, end) => {
1008
+ let length = end - start;
1009
+ if (length <= 40) {
1010
+ let out = view.getBigUint64(start);
1011
+ for (let i = start + 8; i < end; i += 8) {
1012
+ out <<= BigInt(64n);
1013
+ out |= view.getBigUint64(i);
1014
+ }
1015
+ return out
1016
+ }
1017
+ // if (length === 8) return view.getBigUint64(start)
1018
+ let middle = start + (length >> 4 << 3);
1019
+ let left = decode(start, middle);
1020
+ let right = decode(middle, end);
1021
+ return (left << BigInt((end - middle) * 8)) | right
1022
+ };
1023
+ head = (head << BigInt((view.byteLength - headLength) * 8)) | decode(headLength, view.byteLength);
1002
1024
  }
1003
- return value;
1025
+ return head
1004
1026
  };
1005
1027
 
1006
- let errors = { Error, TypeError, ReferenceError };
1028
+ let errors = {
1029
+ Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, AggregateError: typeof AggregateError === 'function' ? AggregateError : null,
1030
+ };
1007
1031
  currentExtensions[0x65] = () => {
1008
1032
  let data = read();
1009
- return (errors[data[0]] || Error)(data[1], { cause: data[2] })
1033
+ if (!errors[data[0]]) {
1034
+ let error = Error(data[1], { cause: data[2] });
1035
+ error.name = data[0];
1036
+ return error
1037
+ }
1038
+ return errors[data[0]](data[1], { cause: data[2] })
1010
1039
  };
1011
1040
 
1012
1041
  currentExtensions[0x69] = (data) => {
@@ -1017,20 +1046,33 @@
1017
1046
  referenceMap = new Map();
1018
1047
  let token = src[position$1];
1019
1048
  let target;
1020
- // TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
1021
- // ahead past references to record structure definitions
1049
+ // TODO: handle any other types that can cycle and make the code more robust if there are other extensions
1022
1050
  if (token >= 0x90 && token < 0xa0 || token == 0xdc || token == 0xdd)
1023
1051
  target = [];
1052
+ else if (token >= 0x80 && token < 0x90 || token == 0xde || token == 0xdf)
1053
+ target = new Map();
1054
+ else if ((token >= 0xc7 && token <= 0xc9 || token >= 0xd4 && token <= 0xd8) && src[position$1 + 1] === 0x73)
1055
+ target = new Set();
1024
1056
  else
1025
1057
  target = {};
1026
1058
 
1027
1059
  let refEntry = { target }; // a placeholder object
1028
1060
  referenceMap.set(id, refEntry);
1029
1061
  let targetProperties = read(); // read the next value as the target object to id
1030
- if (refEntry.used) // there is a cycle, so we have to assign properties to original target
1031
- return Object.assign(target, targetProperties)
1032
- refEntry.target = targetProperties; // the placeholder wasn't used, replace with the deserialized one
1033
- return targetProperties // no cycle, can just use the returned read object
1062
+ if (!refEntry.used) {
1063
+ // no cycle, can just use the returned read object
1064
+ return refEntry.target = targetProperties // replace the placeholder with the real one
1065
+ } else {
1066
+ // there is a cycle, so we have to assign properties to original target
1067
+ Object.assign(target, targetProperties);
1068
+ }
1069
+
1070
+ // copy over map/set entries if we're able to
1071
+ if (target instanceof Map)
1072
+ for (let [k, v] of targetProperties.entries()) target.set(k, v);
1073
+ if (target instanceof Set)
1074
+ for (let i of Array.from(targetProperties)) target.add(i);
1075
+ return target
1034
1076
  };
1035
1077
 
1036
1078
  currentExtensions[0x70] = (data) => {
@@ -1049,18 +1091,16 @@
1049
1091
  let glbl = typeof globalThis === 'object' ? globalThis : window;
1050
1092
  currentExtensions[0x74] = (data) => {
1051
1093
  let typeCode = data[0];
1094
+ // we always have to slice to get a new ArrayBuffer that is aligned
1095
+ let buffer = Uint8Array.prototype.slice.call(data, 1).buffer;
1096
+
1052
1097
  let typedArrayName = typedArrays[typeCode];
1053
1098
  if (!typedArrayName) {
1054
- if (typeCode === 16) {
1055
- let ab = new ArrayBuffer(data.length - 1);
1056
- let u8 = new Uint8Array(ab);
1057
- u8.set(data.subarray(1));
1058
- return ab;
1059
- }
1099
+ if (typeCode === 16) return buffer
1100
+ if (typeCode === 17) return new DataView(buffer)
1060
1101
  throw new Error('Could not find typed array for code ' + typeCode)
1061
1102
  }
1062
- // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
1063
- return new glbl[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
1103
+ return new glbl[typedArrayName](buffer)
1064
1104
  };
1065
1105
  currentExtensions[0x78] = () => {
1066
1106
  let data = read();
@@ -1088,13 +1128,13 @@
1088
1128
  return new Date(
1089
1129
  ((data[0] << 22) + (data[1] << 14) + (data[2] << 6) + (data[3] >> 2)) / 1000000 +
1090
1130
  ((data[3] & 0x3) * 0x100000000 + data[4] * 0x1000000 + (data[5] << 16) + (data[6] << 8) + data[7]) * 1000)
1091
- else if (data.length == 12)// TODO: Implement support for negative
1131
+ else if (data.length == 12)
1092
1132
  return new Date(
1093
1133
  ((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
1094
1134
  (((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
1095
1135
  else
1096
1136
  return new Date('invalid')
1097
- }; // notepack defines extension 0 to mean undefined, so use that as the default here
1137
+ };
1098
1138
  // registration of bulk record definition?
1099
1139
  // currentExtensions[0x52] = () =>
1100
1140
 
@@ -1698,11 +1738,11 @@
1698
1738
  } else if (type === 'boolean') {
1699
1739
  target[position++] = value ? 0xc3 : 0xc2;
1700
1740
  } else if (type === 'bigint') {
1701
- if (value < (BigInt(1)<<BigInt(63)) && value >= -(BigInt(1)<<BigInt(63))) {
1741
+ if (value < 0x8000000000000000 && value >= -0x8000000000000000) {
1702
1742
  // use a signed int as long as it fits
1703
1743
  target[position++] = 0xd3;
1704
1744
  targetView.setBigInt64(position, value);
1705
- } else if (value < (BigInt(1)<<BigInt(64)) && value > 0) {
1745
+ } else if (value < 0x10000000000000000 && value > 0) {
1706
1746
  // if we can fit an unsigned int, use that
1707
1747
  target[position++] = 0xcf;
1708
1748
  targetView.setBigUint64(position, value);
@@ -1713,22 +1753,46 @@
1713
1753
  targetView.setFloat64(position, Number(value));
1714
1754
  } else if (this.largeBigIntToString) {
1715
1755
  return pack(value.toString());
1716
- } else if (this.useBigIntExtension && value < BigInt(2)**BigInt(1023) && value > -(BigInt(2)**BigInt(1023))) {
1717
- target[position++] = 0xc7;
1718
- position++;
1719
- target[position++] = 0x42; // "B" for BigInt
1720
- let bytes = [];
1721
- let alignedSign;
1722
- do {
1723
- let byte = value & BigInt(0xff);
1724
- alignedSign = (byte & BigInt(0x80)) === (value < BigInt(0) ? BigInt(0x80) : BigInt(0));
1725
- bytes.push(byte);
1726
- value >>= BigInt(8);
1727
- } while (!((value === BigInt(0) || value === BigInt(-1)) && alignedSign));
1728
- target[position-2] = bytes.length;
1729
- for (let i = bytes.length; i > 0;) {
1730
- target[position++] = Number(bytes[--i]);
1756
+ } else if (this.useBigIntExtension || this.moreTypes) {
1757
+ let empty = value < 0 ? BigInt(-1) : BigInt(0);
1758
+
1759
+ let array;
1760
+ if (value >> BigInt(0x10000) === empty) {
1761
+ let mask = BigInt(0x10000000000000000) - BigInt(1); // literal would overflow
1762
+ let chunks = [];
1763
+ do {
1764
+ chunks.push(value & mask);
1765
+ value >>= BigInt(64);
1766
+ } while (value !== empty)
1767
+
1768
+ array = new Uint8Array(new BigUint64Array(chunks).buffer);
1769
+ array.reverse();
1770
+ } else {
1771
+ let invert = value < 0;
1772
+ let string = (invert ? ~value : value).toString(16);
1773
+ if (string.length % 2) {
1774
+ string = '0' + string;
1775
+ } else if (parseInt(string.charAt(0), 16) >= 8) {
1776
+ string = '00' + string;
1777
+ }
1778
+
1779
+ if (hasNodeBuffer$1) {
1780
+ array = Buffer.from(string, 'hex');
1781
+ } else {
1782
+ array = new Uint8Array(string.length / 2);
1783
+ for (let i = 0; i < array.length; i++) {
1784
+ array[i] = parseInt(string.slice(i * 2, i * 2 + 2), 16);
1785
+ }
1786
+ }
1787
+
1788
+ if (invert) {
1789
+ for (let i = 0; i < array.length; i++) array[i] = ~array[i];
1790
+ }
1731
1791
  }
1792
+
1793
+ if (array.length + position > safeEnd)
1794
+ makeRoom(array.length + position);
1795
+ position = writeExtensionData(array, target, position, 0x42);
1732
1796
  return
1733
1797
  } else {
1734
1798
  throw new RangeError(value + ' was too large to fit in MessagePack 64-bit integer format, use' +
@@ -2032,7 +2096,7 @@
2032
2096
  }
2033
2097
  };
2034
2098
 
2035
- extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ];
2099
+ extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, DataView, C1Type ];
2036
2100
  extensions = [{
2037
2101
  pack(date, allocateForWrite, pack) {
2038
2102
  let seconds = date.getTime() / 1000;
@@ -2119,6 +2183,13 @@
2119
2183
  else
2120
2184
  writeBuffer(typedArray, allocateForWrite);
2121
2185
  }
2186
+ }, {
2187
+ pack(arrayBuffer, allocateForWrite) {
2188
+ if (this.moreTypes)
2189
+ writeExtBuffer(arrayBuffer, 0x11, allocateForWrite);
2190
+ else
2191
+ writeBuffer(hasNodeBuffer$1 ? Buffer.from(arrayBuffer) : new Uint8Array(arrayBuffer), allocateForWrite);
2192
+ }
2122
2193
  }, {
2123
2194
  pack(c1, allocateForWrite) { // specific 0xC1 object
2124
2195
  let { target, position} = allocateForWrite(1);
@@ -2749,10 +2820,14 @@
2749
2820
  throw new Error('Could not find typed structure ' + recordId);
2750
2821
  }
2751
2822
  var construct = structure.construct;
2823
+ var fullConstruct = structure.fullConstruct;
2752
2824
  if (!construct) {
2753
2825
  construct = structure.construct = function LazyObject() {
2754
2826
  };
2755
- var prototype = construct.prototype;
2827
+ fullConstruct = structure.fullConstruct = function LoadedObject() {
2828
+ };
2829
+ fullConstruct.prototype = unpackr.structPrototype ?? {};
2830
+ var prototype = construct.prototype = unpackr.structPrototype ? Object.create(unpackr.structPrototype) : {};
2756
2831
  let properties = [];
2757
2832
  let currentOffset = 0;
2758
2833
  let lastRefProperty;
@@ -2953,12 +3028,12 @@
2953
3028
  Object.defineProperty(prototype, property.key, { get: withSource(property.get), enumerable: true });
2954
3029
  let valueFunction = 'v' + i++;
2955
3030
  args.push(valueFunction);
2956
- objectLiteralProperties.push('[' + JSON.stringify(property.key) + ']:' + valueFunction + '(s)');
3031
+ objectLiteralProperties.push('o[' + JSON.stringify(property.key) + ']=' + valueFunction + '(s)');
2957
3032
  }
2958
3033
  if (hasInheritedProperties) {
2959
3034
  objectLiteralProperties.push('__proto__:this');
2960
3035
  }
2961
- let toObject = (new Function(...args, 'return function(s){return{' + objectLiteralProperties.join(',') + '}}')).apply(null, properties.map(prop => prop.get));
3036
+ let toObject = (new Function(...args, 'var c=this;return function(s){var o=new c();' + objectLiteralProperties.join(';') + ';return o;}')).apply(fullConstruct, properties.map(prop => prop.get));
2962
3037
  Object.defineProperty(prototype, 'toJSON', {
2963
3038
  value(omitUnderscoredProperties) {
2964
3039
  return toObject.call(this, this[sourceSymbol]);
@@ -3292,7 +3367,7 @@
3292
3367
  {id: 2, type: 1, labels: {b: 1, c: 2}},
3293
3368
  {id: 3, type: 1, labels: {d: 1, e: 2}}
3294
3369
  ];
3295
-
3370
+
3296
3371
  var alternatives = [
3297
3372
  {useRecords: false}, // 88 bytes
3298
3373
  {useRecords: true}, // 58 bytes
@@ -3304,7 +3379,7 @@
3304
3379
  let packr = new Packr(o);
3305
3380
  var serialized = packr.pack(data);
3306
3381
  var deserialized = packr.unpack(serialized);
3307
- assert.deepEqual(deserialized, data);
3382
+ assert.deepEqual(deserialized, data);
3308
3383
  }
3309
3384
  });
3310
3385
 
@@ -3426,7 +3501,7 @@
3426
3501
  });
3427
3502
 
3428
3503
  test('BigInt', function() {
3429
- let packr = new Packr({useBigIntExtension: true});
3504
+ let packr = new Packr({ useBigIntExtension: true });
3430
3505
  let data = {
3431
3506
  a: 3333333333333333333333333333n,
3432
3507
  b: 1234567890123456789012345678901234567890n,
@@ -3434,7 +3509,21 @@
3434
3509
  d: -352523523642364364364264264264264264262642642n,
3435
3510
  e: 0xffffffffffffffffffffffffffn,
3436
3511
  f: -0xffffffffffffffffffffffffffn,
3512
+ g: (1234n << 123n) ^ (5678n << 56n) ^ 890n,
3513
+ h: (-1234n << 123n) ^ (5678n << 56n) ^ 890n,
3514
+ i: (1234n << 1234n) ^ (5678n << 567n) ^ 890n,
3515
+ j: (-1234n << 1234n) ^ (5678n << 567n) ^ 890n,
3516
+ k: 0xdeadn << 0xbeefn,
3517
+ l: -0xdeadn << 0xbeefn,
3518
+ m: 11n << 0x11111n ^ 111n,
3519
+ n: -11n << 0x11111n ^ 111n,
3520
+ array: [],
3437
3521
  };
3522
+
3523
+ for (let n = 7n; n.toString(16).length * 4 < 150000; n *= n) {
3524
+ data.array.push(n, -n);
3525
+ }
3526
+
3438
3527
  let serialized = packr.pack(data);
3439
3528
  let deserialized = packr.unpack(serialized);
3440
3529
  assert.deepEqual(data, deserialized);
@@ -3661,7 +3750,7 @@
3661
3750
 
3662
3751
  test('extended class pack/unpack proxied', function(){
3663
3752
  function Extended() {
3664
-
3753
+
3665
3754
  }
3666
3755
  Extended.prototype.__call__ = function(){
3667
3756
  return this.value * 4
@@ -3672,7 +3761,7 @@
3672
3761
 
3673
3762
  var instance = function() { instance.__call__();/* callable stuff */ };
3674
3763
  Object.setPrototypeOf(instance,Extended.prototype);
3675
-
3764
+
3676
3765
  instance.value = 4;
3677
3766
  var data = instance;
3678
3767
 
@@ -3750,10 +3839,12 @@
3750
3839
  }
3751
3840
  });
3752
3841
 
3753
- test('moreTyesp: Error with causes', function() {
3842
+ test('moreTypes: Error with causes', function() {
3754
3843
  const object = {
3755
3844
  error: new Error('test'),
3756
- errorWithCause: new Error('test-1', { cause: new Error('test-2')}),
3845
+ errorWithCause: new Error('test-1', { cause: new Error('test-2') }),
3846
+ type: new TypeError(),
3847
+ range: new RangeError('test', { cause: [1, 2] }),
3757
3848
  };
3758
3849
  const packr = new Packr({
3759
3850
  moreTypes: true,
@@ -3766,6 +3857,12 @@
3766
3857
  assert.equal(deserialized.errorWithCause.message, object.errorWithCause.message);
3767
3858
  assert.equal(deserialized.errorWithCause.cause.message, object.errorWithCause.cause.message);
3768
3859
  assert.equal(deserialized.errorWithCause.cause.cause, object.errorWithCause.cause.cause);
3860
+ assert.equal(deserialized.type.message, object.type.message);
3861
+ assert.equal(deserialized.range.message, object.range.message);
3862
+ assert.deepEqual(deserialized.range.cause, object.range.cause);
3863
+ assert(deserialized.error instanceof Error);
3864
+ assert(deserialized.type instanceof TypeError);
3865
+ assert(deserialized.range instanceof RangeError);
3769
3866
  });
3770
3867
 
3771
3868
  test('structured cloning: self reference', function() {
@@ -3800,6 +3897,39 @@
3800
3897
  assert.equal(u8[1], 2);
3801
3898
  });
3802
3899
 
3900
+ test('structured cloning: self reference with more types', function() {
3901
+ let set = new Set();
3902
+ set.add(['hello', 1, 2, { map: new Map([[set, set], ['a', 'b']]) }]);
3903
+
3904
+ let packr = new Packr({
3905
+ moreTypes: true,
3906
+ structuredClone: true,
3907
+ });
3908
+ let serialized = packr.pack(set);
3909
+ let deserialized = packr.unpack(serialized);
3910
+ assert.equal(deserialized.constructor.name, 'Set');
3911
+ let map = Array.from(deserialized)[0][3].map;
3912
+ assert.equal(map.get(deserialized), deserialized);
3913
+
3914
+ let sizeTestMap = new Map();
3915
+ for (let i = 0; i < 50; i++) {
3916
+ sizeTestMap.set(i || sizeTestMap, sizeTestMap);
3917
+ let deserialized = packr.unpack(packr.pack(sizeTestMap));
3918
+ assert.equal(deserialized.size, i + 1);
3919
+ assert(deserialized.has(deserialized));
3920
+ assert(deserialized.has(i || deserialized));
3921
+ }
3922
+
3923
+ let sizeTestSet = new Set();
3924
+ for (let i = 0; i < 50; i++) {
3925
+ sizeTestSet.add(i || sizeTestSet);
3926
+ let deserialized = packr.unpack(packr.pack(sizeTestSet));
3927
+ assert.equal(deserialized.size, i + 1);
3928
+ assert(deserialized.has(deserialized));
3929
+ assert(deserialized.has(i || deserialized));
3930
+ }
3931
+ });
3932
+
3803
3933
  test('structured cloning: types', function() {
3804
3934
  let b = typeof Buffer != 'undefined' ? Buffer.alloc(20) : new Uint8Array(20);
3805
3935
  let fa = new Float32Array(b.buffer, 8, 2);
@@ -3810,7 +3940,9 @@
3810
3940
  set: new Set(['a', 'b']),
3811
3941
  regexp: /test/gi,
3812
3942
  float32Array: fa,
3813
- uint16Array: new Uint16Array([3,4])
3943
+ uint16Array: new Uint16Array([3, 4]),
3944
+ arrayBuffer: new Uint8Array([0xde, 0xad]).buffer,
3945
+ dataView: new DataView(new Uint8Array([0xbe, 0xef]).buffer),
3814
3946
  };
3815
3947
  let packr = new Packr({
3816
3948
  moreTypes: true,
@@ -3827,6 +3959,10 @@
3827
3959
  assert.equal(deserialized.uint16Array.constructor.name, 'Uint16Array');
3828
3960
  assert.equal(deserialized.uint16Array[0], 3);
3829
3961
  assert.equal(deserialized.uint16Array[1], 4);
3962
+ assert.equal(deserialized.arrayBuffer.constructor.name, 'ArrayBuffer');
3963
+ assert.equal(new DataView(deserialized.arrayBuffer).getUint16(), 0xdead);
3964
+ assert.equal(deserialized.dataView.constructor.name, 'DataView');
3965
+ assert.equal(deserialized.dataView.getUint16(), 0xbeef);
3830
3966
  });
3831
3967
  test('big bundledStrings', function() {
3832
3968
  const MSGPACK_OPTIONS = {bundleStrings: true};
@@ -3955,7 +4091,7 @@
3955
4091
  getStructures() {
3956
4092
  return structures
3957
4093
  },
3958
- saveStructures(structures) {
4094
+ saveStructures(structures) {
3959
4095
  },
3960
4096
  maxSharedStructures: 100
3961
4097
  });
@@ -3963,7 +4099,7 @@
3963
4099
  getStructures() {
3964
4100
  return structures2
3965
4101
  },
3966
- saveStructures(structures) {
4102
+ saveStructures(structures) {
3967
4103
  },
3968
4104
  maxSharedStructures: 100
3969
4105
  });
@@ -4245,6 +4381,18 @@
4245
4381
  assert.deepEqual(deserialized, data);
4246
4382
  });
4247
4383
 
4384
+ test('arrays in map keys', function() {
4385
+ const msgpackr = new Packr({ mapsAsObjects: true, allowArraysInMapKeys: true });
4386
+
4387
+ const map = new Map();
4388
+ map.set([1, 2, 3], 1);
4389
+ map.set([1, 2, ['foo', 3.14]], 2);
4390
+
4391
+ const packed = msgpackr.pack(map);
4392
+ const unpacked = msgpackr.unpack(packed);
4393
+ assert.deepEqual(unpacked, { '1,2,3': 1, '1,2,foo,3.14': 2 });
4394
+ });
4395
+
4248
4396
  test('utf16 causing expansion', function() {
4249
4397
  this.timeout(10000);
4250
4398
  let data = {fixstr: 'ᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝ', str8:'ᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝ'};