diff options
Diffstat (limited to 'vanilla/node_modules/@exodus/bytes')
75 files changed, 8036 insertions, 0 deletions
diff --git a/vanilla/node_modules/@exodus/bytes/LICENSE b/vanilla/node_modules/@exodus/bytes/LICENSE new file mode 100644 index 0000000..9971d41 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024-2025 Exodus Movement + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vanilla/node_modules/@exodus/bytes/README.md b/vanilla/node_modules/@exodus/bytes/README.md new file mode 100644 index 0000000..d14b0ae --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/README.md @@ -0,0 +1,925 @@ +# @exodus/bytes + +[](https://npmjs.org/package/@exodus/bytes) +[](https://github.com/ExodusOSS/bytes/releases) +[](https://www.npmcharts.com/compare/@exodus/bytes?minimal=true) +[](https://github.com/ExodusOSS/bytes/blob/HEAD/LICENSE) +[](https://github.com/ExodusOSS/bytes/actions/workflows/test.yml?query=branch%3Amain) + +`Uint8Array` conversion to and from `base64`, `base32`, `base58`, `hex`, `utf8`, `utf16`, `bech32` and `wif` + +And a [`TextEncoder` / `TextDecoder` polyfill](#textencoder--textdecoder-polyfill) + +See [documentation](https://exodusoss.github.io/bytes/). + +## Strict + +Performs proper input validation, ensures no garbage-in-garbage-out + +Tested in CI with [@exodus/test](https://github.com/ExodusMovement/test#exodustest) on: + +[](https://nodejs.org/api/test.html) +[](https://deno.com/) +[](https://bun.sh/) +[](http://electronjs.org/) +[](https://github.com/cloudflare/workerd)\ +[](https://www.chromium.org/Home/) +[](http://webkit.org/) +[](https://github.com/mozilla-firefox) +[](https://servo.org/)\ +[](https://hermesengine.dev) +[](https://v8.dev/docs/d8) +[](https://docs.webkit.org/Deep%20Dive/JSC/JavaScriptCore.html) +[](https://spidermonkey.dev/)\ +[](https://github.com/quickjs-ng/quickjs) +[](https://github.com/Moddable-OpenSource/moddable) +[](https://github.com/oracle/graaljs) + +## Fast + +* `10-20x` faster than `Buffer` polyfill +* `2-10x` faster than `iconv-lite` + +The above was for the js fallback + +It's up to `100x` when native impl is available \ +e.g. in `utf8fromString` on Hermes / React Native or `fromHex` in Chrome + +Also: +* `3-8x` faster than `bs58` +* `10-30x` faster than `@scure/base` (or `>100x` on Node.js <25) +* Faster in `utf8toString` / `utf8fromString` than `Buffer` or `TextDecoder` / `TextEncoder` on Node.js + +See [Performance](./Performance.md) for more info + +## TextEncoder / TextDecoder polyfill + +```js +import { TextDecoder, TextEncoder } from '@exodus/bytes/encoding.js' +import { TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding.js' // Requires Streams +``` + +Less than half the bundle size of [text-encoding](https://npmjs.com/text-encoding), [whatwg-encoding](https://npmjs.com/whatwg-encoding) or [iconv-lite](https://npmjs.com/iconv-lite) (gzipped or not).\ +Also [much faster](#fast) than all of those. + +> [!TIP] +> See also the [lite version](#lite-version) to get this down to 10 KiB gzipped. + +Spec compliant, passing WPT and covered with extra tests.\ +Moreover, tests for this library uncovered [bugs in all major implementations](https://docs.google.com/spreadsheets/d/1pdEefRG6r9fZy61WHGz0TKSt8cO4ISWqlpBN5KntIvQ/edit).\ +Including all three major browser engines being wrong at UTF-8.\ +See [WPT pull request](https://github.com/web-platform-tests/wpt/pull/56892). + +It works correctly even in environments that have native implementations broken (that's all of them currently).\ +Runs (and passes WPT) on Node.js built without ICU. + +> [!NOTE] +> [Faster than Node.js native implementation on Node.js](https://github.com/nodejs/node/issues/61041#issuecomment-3649242024). +> +> The JS multi-byte version is as fast as native impl in Node.js and browsers, but (unlike them) returns correct results. +> +> For encodings where native version is known to be fast and correct, it is automatically used.\ +> Some single-byte encodings are faster than native in all three major browser engines. + +See [analysis table](https://docs.google.com/spreadsheets/d/1pdEefRG6r9fZy61WHGz0TKSt8cO4ISWqlpBN5KntIvQ/edit) for more info. + +### Caveat: `TextDecoder` / `TextEncoder` APIs are lossy by default per spec + +_These are only provided as a compatibility layer, prefer hardened APIs instead in new code._ + + * `TextDecoder` can (and should) be used with `{ fatal: true }` option for all purposes demanding correctness / lossless transforms + + * `TextEncoder` does not support a fatal mode per spec, it always performs replacement. + + That is not suitable for hashing, cryptography or consensus applications.\ + Otherwise there would be non-equal strings with equal signatures and hashes — the collision is caused by the lossy transform of a JS string to bytes. + Those also survive e.g. `JSON.stringify`/`JSON.parse` or being sent over network. + + Use strict APIs in new applications, see `utf8fromString` / `utf16fromString` below.\ + Those throw on non-well-formed strings by default. + +### Lite version + +Alternate exports exist that can help reduce bundle size, see comparison: + +| import | size | +| - | - | +| [@exodus/bytes/encoding-browser.js](#exodusbytesencoding-browserjs-) | <sub></sub> | +| [@exodus/bytes/encoding-lite.js](#exodusbytesencoding-litejs-) | <sub></sub> | +| [@exodus/bytes/encoding.js](#exodusbytesencodingjs-) | <sub></sub> | +| `text-encoding` | <sub></sub> | +| `iconv-lite` | <sub></sub> | +| `whatwg-encoding` | <sub></sub> | + +Libraries are advised to use single-purpose hardened `@exodus/bytes/utf8.js` / `@exodus/bytes/utf16.js` APIs for Unicode. + +Applications (including React Native apps) are advised to load either `@exodus/bytes/encoding-lite.js` or `@exodus/bytes/encoding.js` +(depending on whether legacy multi-byte support is needed) and use that as a global polyfill. + +#### `@exodus/bytes/encoding-lite.js` + +If you don't need support for legacy multi-byte encodings. + +Reduces the bundle size ~12x, while still keeping `utf-8`, `utf-16le`, `utf-16be` and all single-byte encodings specified by the spec. +The only difference is support for legacy multi-byte encodings. + +See [the list of encodings](https://encoding.spec.whatwg.org/#names-and-labels). + +This can be useful for example in React Native global TextDecoder polyfill, +if you are sure that you don't need legacy multi-byte encodings support. + +#### `@exodus/bytes/encoding-browser.js` + +Resolves to a tiny import in browser bundles, preferring native `TextDecoder` / `TextEncoder`. + +For non-browsers (Node.js, React Native), loads a full implementation. + +> [!NOTE] +> This is not the default behavior for `@exodus/bytes/encoding.js` because all major browser implementations have bugs, +> which `@exodus/bytes/encoding.js` fixes. Only use if you are ok with that. + +## API + +### @exodus/bytes/utf8.js <sub><sub> + +UTF-8 encoding/decoding + +```js +import { utf8fromString, utf8toString } from '@exodus/bytes/utf8.js' + +// loose +import { utf8fromStringLoose, utf8toStringLoose } from '@exodus/bytes/utf8.js' +``` + +_These methods by design encode/decode BOM (codepoint `U+FEFF` Byte Order Mark) as-is._\ +_If you need BOM handling or detection, use `@exodus/bytes/encoding.js`_ + +#### `utf8fromString(string, format = 'uint8')` + +Encode a string to UTF-8 bytes (strict mode) + +Throws on invalid Unicode (unpaired surrogates) + +This is similar to the following snippet (but works on all engines): +```js +// Strict encode, requiring Unicode codepoints to be valid +if (typeof string !== 'string' || !string.isWellFormed()) throw new TypeError() +return new TextEncoder().encode(string) +``` + +#### `utf8fromStringLoose(string, format = 'uint8')` + +Encode a string to UTF-8 bytes (loose mode) + +Replaces invalid Unicode (unpaired surrogates) with replacement codepoints `U+FFFD` +per [WHATWG Encoding](https://encoding.spec.whatwg.org/) specification. + +_Such replacement is a non-injective function, is irreversable and causes collisions.\ +Prefer using strict throwing methods for cryptography applications._ + +This is similar to the following snippet (but works on all engines): +```js +// Loose encode, replacing invalid Unicode codepoints with U+FFFD +if (typeof string !== 'string') throw new TypeError() +return new TextEncoder().encode(string) +``` + +#### `utf8toString(arr)` + +Decode UTF-8 bytes to a string (strict mode) + +Throws on invalid UTF-8 byte sequences + +This is similar to `new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(arr)`, +but works on all engines. + +#### `utf8toStringLoose(arr)` + +Decode UTF-8 bytes to a string (loose mode) + +Replaces invalid UTF-8 byte sequences with replacement codepoints `U+FFFD` +per [WHATWG Encoding](https://encoding.spec.whatwg.org/) specification. + +_Such replacement is a non-injective function, is irreversable and causes collisions.\ +Prefer using strict throwing methods for cryptography applications._ + +This is similar to `new TextDecoder('utf-8', { ignoreBOM: true }).decode(arr)`, +but works on all engines. + +### @exodus/bytes/utf16.js <sub><sub> + +UTF-16 encoding/decoding + +```js +import { utf16fromString, utf16toString } from '@exodus/bytes/utf16.js' + +// loose +import { utf16fromStringLoose, utf16toStringLoose } from '@exodus/bytes/utf16.js' +``` + +_These methods by design encode/decode BOM (codepoint `U+FEFF` Byte Order Mark) as-is._\ +_If you need BOM handling or detection, use `@exodus/bytes/encoding.js`_ + +#### `utf16fromString(string, format = 'uint16')` + +Encode a string to UTF-16 bytes (strict mode) + +Throws on invalid Unicode (unpaired surrogates) + +#### `utf16fromStringLoose(string, format = 'uint16')` + +Encode a string to UTF-16 bytes (loose mode) + +Replaces invalid Unicode (unpaired surrogates) with replacement codepoints `U+FFFD` +per [WHATWG Encoding](https://encoding.spec.whatwg.org/) specification. + +_Such replacement is a non-injective function, is irreversible and causes collisions.\ +Prefer using strict throwing methods for cryptography applications._ + +#### `utf16toString(arr, format = 'uint16')` + +Decode UTF-16 bytes to a string (strict mode) + +Throws on invalid UTF-16 byte sequences + +Throws on non-even byte length. + +#### `utf16toStringLoose(arr, format = 'uint16')` + +Decode UTF-16 bytes to a string (loose mode) + +Replaces invalid UTF-16 byte sequences with replacement codepoints `U+FFFD` +per [WHATWG Encoding](https://encoding.spec.whatwg.org/) specification. + +_Such replacement is a non-injective function, is irreversible and causes collisions.\ +Prefer using strict throwing methods for cryptography applications._ + +Throws on non-even byte length. + +### @exodus/bytes/single-byte.js <sub></sub> + +Decode / encode the legacy single-byte encodings according to the +[Encoding standard](https://encoding.spec.whatwg.org/) +([§9](https://encoding.spec.whatwg.org/#legacy-single-byte-encodings), +[§14.5](https://encoding.spec.whatwg.org/#x-user-defined)), +and [unicode.org](https://unicode.org/Public/MAPPINGS/ISO8859) `iso-8859-*` mappings. + +```js +import { createSinglebyteDecoder, createSinglebyteEncoder } from '@exodus/bytes/single-byte.js' +import { windows1252toString, windows1252fromString } from '@exodus/bytes/single-byte.js' +import { latin1toString, latin1fromString } from '@exodus/bytes/single-byte.js' +``` + +> [!WARNING] +> This is a lower-level API for single-byte encodings. +> It might not match what you expect, as it supports both WHATWG and unicode.org encodings under +> different names, with the main intended usecase for the latter being either non-web or legacy contexts. +> +> For a safe WHATWG Encoding-compatible API, see `@exodus/bytes/encoding.js` import (and variants of it). +> +> Be sure to know what you are doing and check documentation when directly using encodings from this file. + +Supports all single-byte encodings listed in the WHATWG Encoding standard: +`ibm866`, `iso-8859-2`, `iso-8859-3`, `iso-8859-4`, `iso-8859-5`, `iso-8859-6`, `iso-8859-7`, `iso-8859-8`, +`iso-8859-8-i`, `iso-8859-10`, `iso-8859-13`, `iso-8859-14`, `iso-8859-15`, `iso-8859-16`, `koi8-r`, `koi8-u`, +`macintosh`, `windows-874`, `windows-1250`, `windows-1251`, `windows-1252`, `windows-1253`, `windows-1254`, +`windows-1255`, `windows-1256`, `windows-1257`, `windows-1258`, `x-mac-cyrillic` and `x-user-defined`. + +Also supports `iso-8859-1`, `iso-8859-9`, `iso-8859-11` as defined at +[unicode.org](https://unicode.org/Public/MAPPINGS/ISO8859) +(and all other `iso-8859-*` encodings there as they match WHATWG). + +> [!NOTE] +> While all `iso-8859-*` encodings supported by the [WHATWG Encoding standard](https://encoding.spec.whatwg.org/) match +> [unicode.org](https://unicode.org/Public/MAPPINGS/ISO8859), the WHATWG Encoding spec doesn't support +> `iso-8859-1`, `iso-8859-9`, `iso-8859-11`, and instead maps them as labels to `windows-1252`, `windows-1254`, `windows-874`.\ +> `createSinglebyteDecoder()` (unlike `TextDecoder` or `legacyHookDecode()`) does not do such mapping, +> so its results will differ from `TextDecoder` for those encoding names. + +```js +> new TextDecoder('iso-8859-1').encoding +'windows-1252' +> new TextDecoder('iso-8859-9').encoding +'windows-1254' +> new TextDecoder('iso-8859-11').encoding +'windows-874' +> new TextDecoder('iso-8859-9').decode(Uint8Array.of(0x80, 0x81, 0xd0)) +'€\x81Ğ' // this is actually decoded according to windows-1254 per TextDecoder spec +> createSinglebyteDecoder('iso-8859-9')(Uint8Array.of(0x80, 0x81, 0xd0)) +'\x80\x81Ğ' // this is iso-8859-9 as defined at https://unicode.org/Public/MAPPINGS/ISO8859/8859-9.txt +``` + +All WHATWG Encoding spec [`windows-*` encodings](https://encoding.spec.whatwg.org/#windows-874) are supersets of +corresponding [unicode.org encodings](https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/), meaning that +they encode/decode all the old valid (non-replacement) strings / byte sequences identically, but can also support +a wider range of inputs. + +#### `createSinglebyteDecoder(encoding, loose = false)` + +Create a decoder for a supported one-byte `encoding`, given its lowercased name `encoding`. + +Returns a function `decode(arr)` that decodes bytes to a string. + +#### `createSinglebyteEncoder(encoding, { mode = 'fatal' })` + +Create an encoder for a supported one-byte `encoding`, given its lowercased name `encoding`. + +Returns a function `encode(string)` that encodes a string to bytes. + +In `'fatal'` mode (default), will throw on non well-formed strings or any codepoints which could +not be encoded in the target encoding. + +#### `latin1toString(arr)` + +Decode `iso-8859-1` bytes to a string. + +There is no loose variant for this encoding, all bytes can be decoded. + +Same as: +```js +const latin1toString = createSinglebyteDecoder('iso-8859-1') +``` + +> [!NOTE] +> This is different from `new TextDecoder('iso-8859-1')` and `new TextDecoder('latin1')`, as those +> alias to `new TextDecoder('windows-1252')`. + +#### `latin1fromString(string)` + +Encode a string to `iso-8859-1` bytes. + +Throws on non well-formed strings or any codepoints which could not be encoded in `iso-8859-1`. + +Same as: +```js +const latin1fromString = createSinglebyteEncoder('iso-8859-1', { mode: 'fatal' }) +``` + +#### `windows1252toString(arr)` + +Decode `windows-1252` bytes to a string. + +There is no loose variant for this encoding, all bytes can be decoded. + +Same as: +```js +const windows1252toString = createSinglebyteDecoder('windows-1252') +``` + +#### `windows1252fromString(string)` + +Encode a string to `windows-1252` bytes. + +Throws on non well-formed strings or any codepoints which could not be encoded in `windows-1252`. + +Same as: +```js +const windows1252fromString = createSinglebyteEncoder('windows-1252', { mode: 'fatal' }) +``` + +### @exodus/bytes/multi-byte.js <sub></sub> + +Decode / encode the legacy multi-byte encodings according to the +[Encoding standard](https://encoding.spec.whatwg.org/) +([§10](https://encoding.spec.whatwg.org/#legacy-multi-byte-chinese-(simplified)-encodings), +[§11](https://encoding.spec.whatwg.org/#legacy-multi-byte-chinese-(traditional)-encodings), +[§12](https://encoding.spec.whatwg.org/#legacy-multi-byte-japanese-encodings), +[§13](https://encoding.spec.whatwg.org/#legacy-multi-byte-korean-encodings)). + +```js +import { createMultibyteDecoder, createMultibyteEncoder } from '@exodus/bytes/multi-byte.js' +``` + +> [!WARNING] +> This is a lower-level API for legacy multi-byte encodings. +> +> For a safe WHATWG Encoding-compatible API, see `@exodus/bytes/encoding.js` import (and variants of it). +> +> Be sure to know what you are doing and check documentation when directly using encodings from this file. + +Supports all legacy multi-byte encodings listed in the WHATWG Encoding standard: +`gbk`, `gb18030`, `big5`, `euc-jp`, `iso-2022-jp`, `shift_jis`, `euc-kr`. + +#### `createMultibyteDecoder(encoding, loose = false)` + +Create a decoder for a supported legacy multi-byte `encoding`, given its lowercased name `encoding`. + +Returns a function `decode(arr, stream = false)` that decodes bytes to a string. + +The returned function will maintain internal state while `stream = true` is used, allowing it to +handle incomplete multi-byte sequences across multiple calls. +State is reset when `stream = false` or when the function is called without the `stream` parameter. + +#### `createMultibyteEncoder(encoding, { mode = 'fatal' })` + +Create an encoder for a supported legacy multi-byte `encoding`, given its lowercased name `encoding`. + +Returns a function `encode(string)` that encodes a string to bytes. + +In `'fatal'` mode (default), will throw on non well-formed strings or any codepoints which could +not be encoded in the target encoding. + +### @exodus/bytes/bigint.js <sub></sub> + +Convert between BigInt and Uint8Array + +```js +import { fromBigInt, toBigInt } from '@exodus/bytes/bigint.js' +``` + +#### `fromBigInt(bigint, { length, format = 'uint8' })` + +Convert a BigInt to a Uint8Array or Buffer + +The output bytes are in big-endian format. + +Throws if the BigInt is negative or cannot fit into the specified length. + +#### `toBigInt(arr)` + +Convert a Uint8Array or Buffer to a BigInt + +The bytes are interpreted as a big-endian unsigned integer. + +### @exodus/bytes/hex.js <sub></sub> + +Implements Base16 from [RFC4648](https://datatracker.ietf.org/doc/html/rfc4648) +(no differences from [RFC3548](https://datatracker.ietf.org/doc/html/rfc4648)). + +```js +import { fromHex, toHex } from '@exodus/bytes/hex.js' +``` + +#### `fromHex(string, format = 'uint8')` + +Decode a hex string to bytes + +Unlike `Buffer.from()`, throws on invalid input + +#### `toHex(arr)` + +Encode a `Uint8Array` to a lowercase hex string + +### @exodus/bytes/base64.js <sub></sub> + +Implements base64 and base64url from [RFC4648](https://datatracker.ietf.org/doc/html/rfc4648) +(no differences from [RFC3548](https://datatracker.ietf.org/doc/html/rfc4648)). + +```js +import { fromBase64, toBase64 } from '@exodus/bytes/base64.js' +import { fromBase64url, toBase64url } from '@exodus/bytes/base64.js' +import { fromBase64any } from '@exodus/bytes/base64.js' +``` + +#### `fromBase64(string, { format = 'uint8', padding = 'both' })` + +Decode a base64 string to bytes + +Operates in strict mode for last chunk, does not allow whitespace + +#### `fromBase64url(string, { format = 'uint8', padding = false })` + +Decode a base64url string to bytes + +Operates in strict mode for last chunk, does not allow whitespace + +#### `fromBase64any(string, { format = 'uint8', padding = 'both' })` + +Decode either base64 or base64url string to bytes + +Automatically detects the variant based on characters present + +#### `toBase64(arr, { padding = true })` + +Encode a `Uint8Array` to a base64 string (RFC 4648) + +#### `toBase64url(arr, { padding = false })` + +Encode a `Uint8Array` to a base64url string (RFC 4648) + +### @exodus/bytes/base32.js <sub></sub> + +Implements base32 and base32hex from [RFC4648](https://datatracker.ietf.org/doc/html/rfc4648) +(no differences from [RFC3548](https://datatracker.ietf.org/doc/html/rfc4648)). + +```js +import { fromBase32, toBase32 } from '@exodus/bytes/base32.js' +import { fromBase32hex, toBase32hex } from '@exodus/bytes/base32.js' +``` + +#### `fromBase32(string, { format = 'uint8', padding = 'both' })` + +Decode a base32 string to bytes + +Operates in strict mode for last chunk, does not allow whitespace + +#### `fromBase32hex(string, { format = 'uint8', padding = 'both' })` + +Decode a base32hex string to bytes + +Operates in strict mode for last chunk, does not allow whitespace + +#### `toBase32(arr, { padding = false })` + +Encode a `Uint8Array` to a base32 string (RFC 4648) + +#### `toBase32hex(arr, { padding = false })` + +Encode a `Uint8Array` to a base32hex string (RFC 4648) + +### @exodus/bytes/bech32.js <sub></sub> + +Implements bech32 and bech32m from +[BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#specification) +and [BIP-0350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki#specification). + +```js +import { fromBech32, toBech32 } from '@exodus/bytes/bech32.js' +import { fromBech32m, toBech32m } from '@exodus/bytes/bech32.js' +import { getPrefix } from '@exodus/bytes/bech32.js' +``` + +#### `getPrefix(string, limit = 90)` + +Extract the prefix from a bech32 or bech32m string without full validation + +This is a quick check that skips most validation. + +#### `fromBech32(string, limit = 90)` + +Decode a bech32 string to bytes + +#### `toBech32(prefix, bytes, limit = 90)` + +Encode bytes to a bech32 string + +#### `fromBech32m(string, limit = 90)` + +Decode a bech32m string to bytes + +#### `toBech32m(prefix, bytes, limit = 90)` + +Encode bytes to a bech32m string + +### @exodus/bytes/base58.js <sub></sub> + +Implements [base58](https://www.ietf.org/archive/id/draft-msporny-base58-03.txt) encoding. + +Supports both standard base58 and XRP variant alphabets. + +```js +import { fromBase58, toBase58 } from '@exodus/bytes/base58.js' +import { fromBase58xrp, toBase58xrp } from '@exodus/bytes/base58.js' +``` + +#### `fromBase58(string, format = 'uint8')` + +Decode a base58 string to bytes + +Uses the standard Bitcoin base58 alphabet + +#### `toBase58(arr)` + +Encode a `Uint8Array` to a base58 string + +Uses the standard Bitcoin base58 alphabet + +#### `fromBase58xrp(string, format = 'uint8')` + +Decode a base58 string to bytes using XRP alphabet + +Uses the XRP variant base58 alphabet + +#### `toBase58xrp(arr)` + +Encode a `Uint8Array` to a base58 string using XRP alphabet + +Uses the XRP variant base58 alphabet + +### @exodus/bytes/base58check.js <sub></sub> + +Implements [base58check](https://en.bitcoin.it/wiki/Base58Check_encoding) encoding. + +```js +import { fromBase58check, toBase58check } from '@exodus/bytes/base58check.js' +import { fromBase58checkSync, toBase58checkSync } from '@exodus/bytes/base58check.js' +import { makeBase58check } from '@exodus/bytes/base58check.js' +``` + +On non-Node.js, requires peer dependency [@noble/hashes](https://www.npmjs.com/package/@noble/hashes) to be installed. + +#### `async fromBase58check(string, format = 'uint8')` + +Decode a base58check string to bytes asynchronously + +Validates the checksum using double SHA-256 + +#### `async toBase58check(arr)` + +Encode bytes to base58check string asynchronously + +Uses double SHA-256 for checksum calculation + +#### `fromBase58checkSync(string, format = 'uint8')` + +Decode a base58check string to bytes synchronously + +Validates the checksum using double SHA-256 + +#### `toBase58checkSync(arr)` + +Encode bytes to base58check string synchronously + +Uses double SHA-256 for checksum calculation + +#### `makeBase58check(hashAlgo, hashAlgoSync)` + +Create a base58check encoder/decoder with custom hash functions + +### @exodus/bytes/wif.js <sub></sub> + +Wallet Import Format (WIF) encoding and decoding. + +```js +import { fromWifString, toWifString } from '@exodus/bytes/wif.js' +import { fromWifStringSync, toWifStringSync } from '@exodus/bytes/wif.js' +``` + +On non-Node.js, requires peer dependency [@noble/hashes](https://www.npmjs.com/package/@noble/hashes) to be installed. + +#### `async fromWifString(string[, version])` + +Decode a WIF string to WIF data + +Returns a promise that resolves to an object with `{ version, privateKey, compressed }`. + +The optional `version` parameter validates the version byte. + +Throws if the WIF string is invalid or version doesn't match. + +#### `fromWifStringSync(string[, version])` + +Decode a WIF string to WIF data (synchronous) + +Returns an object with `{ version, privateKey, compressed }`. + +The optional `version` parameter validates the version byte. + +Throws if the WIF string is invalid or version doesn't match. + +#### `async toWifString({ version, privateKey, compressed })` + +Encode WIF data to a WIF string + +#### `toWifStringSync({ version, privateKey, compressed })` + +Encode WIF data to a WIF string (synchronous) + +### @exodus/bytes/array.js <sub></sub> + +TypedArray utils and conversions. + +```js +import { typedView } from '@exodus/bytes/array.js' +``` + +#### `typedView(arr, format = 'uint8')` + +Create a view of a TypedArray in the specified format (`'uint8'` or `'buffer'`) + +> [!IMPORTANT] +> Does not copy data, returns a view on the same underlying buffer + +### @exodus/bytes/encoding.js <sub></sub> + +Implements the [Encoding standard](https://encoding.spec.whatwg.org/): +[TextDecoder](https://encoding.spec.whatwg.org/#interface-textdecoder), +[TextEncoder](https://encoding.spec.whatwg.org/#interface-textencoder), +[TextDecoderStream](https://encoding.spec.whatwg.org/#interface-textdecoderstream), +[TextEncoderStream](https://encoding.spec.whatwg.org/#interface-textencoderstream), +some [hooks](https://encoding.spec.whatwg.org/#specification-hooks). + +```js +import { TextDecoder, TextEncoder } from '@exodus/bytes/encoding.js' +import { TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding.js' // Requires Streams + +// Hooks for standards +import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding.js' +``` + +#### `new TextDecoder(label = 'utf-8', { fatal = false, ignoreBOM = false })` + +[TextDecoder](https://encoding.spec.whatwg.org/#interface-textdecoder) implementation/polyfill. + +Decode bytes to strings according to [WHATWG Encoding](https://encoding.spec.whatwg.org) specification. + +#### `new TextEncoder()` + +[TextEncoder](https://encoding.spec.whatwg.org/#interface-textencoder) implementation/polyfill. + +Encode strings to UTF-8 bytes according to [WHATWG Encoding](https://encoding.spec.whatwg.org) specification. + +#### `new TextDecoderStream(label = 'utf-8', { fatal = false, ignoreBOM = false })` + +[TextDecoderStream](https://encoding.spec.whatwg.org/#interface-textdecoderstream) implementation/polyfill. + +A [Streams](https://streams.spec.whatwg.org/) wrapper for `TextDecoder`. + +Requires [Streams](https://streams.spec.whatwg.org/) to be either supported by the platform or +[polyfilled](https://npmjs.com/package/web-streams-polyfill). + +#### `new TextEncoderStream()` + +[TextEncoderStream](https://encoding.spec.whatwg.org/#interface-textencoderstream) implementation/polyfill. + +A [Streams](https://streams.spec.whatwg.org/) wrapper for `TextEncoder`. + +Requires [Streams](https://streams.spec.whatwg.org/) to be either supported by the platform or +[polyfilled](https://npmjs.com/package/web-streams-polyfill). + +#### `labelToName(label)` + +Implements [get an encoding from a string `label`](https://encoding.spec.whatwg.org/#concept-encoding-get). + +Convert an encoding [label](https://encoding.spec.whatwg.org/#names-and-labels) to its name, +as a case-sensitive string. + +If an encoding with that label does not exist, returns `null`. + +All encoding names are also valid labels for corresponding encodings. + +#### `normalizeEncoding(label)` + +Convert an encoding [label](https://encoding.spec.whatwg.org/#names-and-labels) to its name, +as an ASCII-lowercased string. + +If an encoding with that label does not exist, returns `null`. + +This is the same as [`decoder.encoding` getter](https://encoding.spec.whatwg.org/#dom-textdecoder-encoding), +except that it: + 1. Supports [`replacement` encoding](https://encoding.spec.whatwg.org/#replacement) and its + [labels](https://encoding.spec.whatwg.org/#ref-for-replacement%E2%91%A1) + 2. Does not throw for invalid labels and instead returns `null` + +It is identical to: +```js +labelToName(label)?.toLowerCase() ?? null +``` + +All encoding names are also valid labels for corresponding encodings. + +#### `getBOMEncoding(input)` + +Implements [BOM sniff](https://encoding.spec.whatwg.org/#bom-sniff) legacy hook. + +Given a `TypedArray` or an `ArrayBuffer` instance `input`, returns either of: +- `'utf-8'`, if `input` starts with UTF-8 byte order mark. +- `'utf-16le'`, if `input` starts with UTF-16LE byte order mark. +- `'utf-16be'`, if `input` starts with UTF-16BE byte order mark. +- `null` otherwise. + +#### `legacyHookDecode(input, fallbackEncoding = 'utf-8')` + +Implements [decode](https://encoding.spec.whatwg.org/#decode) legacy hook. + +Given a `TypedArray` or an `ArrayBuffer` instance `input` and an optional `fallbackEncoding` +encoding [label](https://encoding.spec.whatwg.org/#names-and-labels), +sniffs encoding from BOM with `fallbackEncoding` fallback and then +decodes the `input` using that encoding, skipping BOM if it was present. + +Notes: + +- BOM-sniffed encoding takes precedence over `fallbackEncoding` option per spec. + Use with care. +- Always operates in non-fatal [mode](https://encoding.spec.whatwg.org/#textdecoder-error-mode), + aka replacement. It can convert different byte sequences to equal strings. + +This method is similar to the following code, except that it doesn't support encoding labels and +only expects lowercased encoding name: + +```js +new TextDecoder(getBOMEncoding(input) ?? fallbackEncoding).decode(input) +``` + +### @exodus/bytes/encoding-lite.js <sub></sub> + +The exact same exports as `@exodus/bytes/encoding.js` are also exported as +`@exodus/bytes/encoding-lite.js`, with the difference that the lite version does not load +multi-byte `TextDecoder` encodings by default to reduce bundle size ~12x. + +```js +import { TextDecoder, TextEncoder } from '@exodus/bytes/encoding-lite.js' +import { TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding-lite.js' // Requires Streams + +// Hooks for standards +import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding-lite.js' +``` + +The only affected encodings are: `gbk`, `gb18030`, `big5`, `euc-jp`, `iso-2022-jp`, `shift_jis` +and their [labels](https://encoding.spec.whatwg.org/#names-and-labels) when used with `TextDecoder`. + +Legacy single-byte encodingds are loaded by default in both cases. + +`TextEncoder` and hooks for standards (including `labelToName` / `normalizeEncoding`) do not have any behavior +differences in the lite version and support full range if inputs. + +To avoid inconsistencies, the exported classes and methods are exactly the same objects. + +```console +> lite = require('@exodus/bytes/encoding-lite.js') +[Module: null prototype] { + TextDecoder: [class TextDecoder], + TextDecoderStream: [class TextDecoderStream], + TextEncoder: [class TextEncoder], + TextEncoderStream: [class TextEncoderStream], + getBOMEncoding: [Function: getBOMEncoding], + labelToName: [Function: labelToName], + legacyHookDecode: [Function: legacyHookDecode], + normalizeEncoding: [Function: normalizeEncoding] +} +> new lite.TextDecoder('big5').decode(Uint8Array.of(0x25)) +Uncaught: +Error: Legacy multi-byte encodings are disabled in /encoding-lite.js, use /encoding.js for full encodings range support + +> full = require('@exodus/bytes/encoding.js') +[Module: null prototype] { + TextDecoder: [class TextDecoder], + TextDecoderStream: [class TextDecoderStream], + TextEncoder: [class TextEncoder], + TextEncoderStream: [class TextEncoderStream], + getBOMEncoding: [Function: getBOMEncoding], + labelToName: [Function: labelToName], + legacyHookDecode: [Function: legacyHookDecode], + normalizeEncoding: [Function: normalizeEncoding] +} +> full.TextDecoder === lite.TextDecoder +true +> new full.TextDecoder('big5').decode(Uint8Array.of(0x25)) +'%' +> new lite.TextDecoder('big5').decode(Uint8Array.of(0x25)) +'%' +``` + +### @exodus/bytes/encoding-browser.js <sub><sub> + +Same as `@exodus/bytes/encoding.js`, but in browsers instead of polyfilling just uses whatever the +browser provides, drastically reducing the bundle size (to less than 2 KiB gzipped). + +```js +import { TextDecoder, TextEncoder } from '@exodus/bytes/encoding-browser.js' +import { TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding-browser.js' // Requires Streams + +// Hooks for standards +import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding-browser.js' +``` + +Under non-browser engines (Node.js, React Native, etc.) a full polyfill is used as those platforms +do not provide sufficiently complete / non-buggy `TextDecoder` APIs. + +> [!NOTE] +> Implementations in browsers [have bugs](https://docs.google.com/spreadsheets/d/1pdEefRG6r9fZy61WHGz0TKSt8cO4ISWqlpBN5KntIvQ/edit), +> but they are fixing them and the expected update window is short.\ +> If you want to circumvent browser bugs, use full `@exodus/bytes/encoding.js` import. + +### @exodus/bytes/whatwg.js <sub></sub> + +WHATWG helpers + +```js +import '@exodus/bytes/encoding.js' // For full legacy multi-byte encodings support +import { percentEncodeAfterEncoding } from '@exodus/bytes/whatwg.js' +``` + +#### `percentEncodeAfterEncoding(encoding, input, percentEncodeSet, spaceAsPlus = false)` + +Implements [percent-encode after encoding](https://url.spec.whatwg.org/#string-percent-encode-after-encoding) +per WHATWG URL specification. + +> [!IMPORTANT] +> You must import `@exodus/bytes/encoding.js` for this API to accept legacy multi-byte encodings. + +Encodings `utf16-le`, `utf16-be`, and `replacement` are not accepted. + +[C0 control percent-encode set](https://url.spec.whatwg.org/#c0-control-percent-encode-set) is +always percent-encoded. + +`percentEncodeSet` is an addition to that, and must be a string of unique increasing codepoints +in range 0x20 - 0x7e, e.g. `' "#<>'`. + +This method accepts [DOMStrings](https://webidl.spec.whatwg.org/#idl-DOMString) and converts them +to [USVStrings](https://webidl.spec.whatwg.org/#idl-USVString). +This is different from e.g. `encodeURI` and `encodeURIComponent` which throw on surrogates: +```js +> percentEncodeAfterEncoding('utf8', '\ud800', ' "#$%&+,/:;<=>?@[\\]^`{|}') // component +'%EF%BF%BD' +> encodeURIComponent('\ud800') +Uncaught URIError: URI malformed +``` + +## Changelog + +See [GitHub Releases](https://github.com/ExodusOSS/bytes/releases) tab + +## License + +[MIT](./LICENSE) diff --git a/vanilla/node_modules/@exodus/bytes/array.d.ts b/vanilla/node_modules/@exodus/bytes/array.d.ts new file mode 100644 index 0000000..c81d16f --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/array.d.ts @@ -0,0 +1,62 @@ +/** + * TypedArray utils and conversions. + * + * ```js + * import { typedView } from '@exodus/bytes/array.js' + * ``` + * + * @module @exodus/bytes/array.js + */ + +/// <reference types="node" /> + +// >= TypeScript 5.9 made Uint8Array templated with <> and defaulted to ArrayBufferLike +// which would incorrectly accept SharedArrayBuffer instances. +// < TypeScript 5.7 doesn't support templates for Uint8Array. +// So this type is defined as a workaround to evaluate to Uint8Array<ArrayBuffer> on all versions of TypeScript. + +/** + * This is `Uint8Array<ArrayBuffer>` + * (as opposed to `Uint8Array<SharedArrayBuffer>` and `Uint8Array<ArrayBufferLike>`) + * on TypeScript versions that support that distinction. + * + * On TypeScript < 5.7, this is just `Uint8Array`, as it's not a template there. + */ +export type Uint8ArrayBuffer = ReturnType<typeof Uint8Array.from>; + +/** + * This is `Uint16Array<ArrayBuffer>` + * (as opposed to `Uint16Array<SharedArrayBuffer>` and `Uint16Array<ArrayBufferLike>`) + * on TypeScript versions that support that distinction. + * + * On TypeScript < 5.7, this is just `Uint16Array`, as it's not a template there. + */ +export type Uint16ArrayBuffer = ReturnType<typeof Uint16Array.from>; + +/** + * This is `Uint32Array<ArrayBuffer>` + * (as opposed to `Uint32Array<SharedArrayBuffer>` and `Uint32Array<ArrayBufferLike>`) + * on TypeScript versions that support that distinction. + * + * On TypeScript < 5.7, this is just `Uint32Array`, as it's not a template there. + */ +export type Uint32ArrayBuffer = ReturnType<typeof Uint32Array.from>; + +/** + * Output format for typed array conversions + */ +export type OutputFormat = 'uint8' | 'buffer'; + +/** + * Create a view of a TypedArray in the specified format (`'uint8'` or `'buffer'`) + * + * > [!IMPORTANT] + * > Does not copy data, returns a view on the same underlying buffer + * + * @param arr - The input TypedArray + * @param format - The desired output format (`'uint8'` or `'buffer'`) + * @returns A view on the same underlying buffer + */ +export function typedView(arr: ArrayBufferView, format: 'uint8'): Uint8Array; +export function typedView(arr: ArrayBufferView, format: 'buffer'): Buffer; +export function typedView(arr: ArrayBufferView, format: OutputFormat): Uint8Array | Buffer; diff --git a/vanilla/node_modules/@exodus/bytes/array.js b/vanilla/node_modules/@exodus/bytes/array.js new file mode 100644 index 0000000..b97c06a --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/array.js @@ -0,0 +1,17 @@ +import { assertTypedArray } from './assert.js' + +const Buffer = globalThis.Buffer // Buffer is optional + +export function typedView(arr, format) { + assertTypedArray(arr) + switch (format) { + case 'uint8': + if (arr.constructor === Uint8Array) return arr // fast path + return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength) + case 'buffer': + if (arr.constructor === Buffer && Buffer.isBuffer(arr)) return arr + return Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength) + } + + throw new TypeError('Unexpected format') +} diff --git a/vanilla/node_modules/@exodus/bytes/assert.js b/vanilla/node_modules/@exodus/bytes/assert.js new file mode 100644 index 0000000..fee83fc --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/assert.js @@ -0,0 +1,26 @@ +export function assertEmptyRest(rest) { + if (Object.keys(rest).length > 0) throw new TypeError('Unexpected extra options') +} + +// eslint-disable-next-line sonarjs/no-nested-template-literals +const makeMessage = (name, extra) => `Expected${name ? ` ${name} to be` : ''} an Uint8Array${extra}` + +const TypedArray = Object.getPrototypeOf(Uint8Array) + +export function assertTypedArray(arr) { + if (arr instanceof TypedArray) return + throw new TypeError('Expected a TypedArray instance') +} + +export function assertUint8(arr, options) { + if (!options) { + // fast path + if (arr instanceof Uint8Array) return + throw new TypeError('Expected an Uint8Array') + } + + const { name, length, ...rest } = options + assertEmptyRest(rest) + if (arr instanceof Uint8Array && (length === undefined || arr.length === length)) return + throw new TypeError(makeMessage(name, length === undefined ? '' : ` of size ${Number(length)}`)) +} diff --git a/vanilla/node_modules/@exodus/bytes/base32.d.ts b/vanilla/node_modules/@exodus/bytes/base32.d.ts new file mode 100644 index 0000000..bf7c2fc --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/base32.d.ts @@ -0,0 +1,83 @@ +/** + * Implements base32 and base32hex from [RFC4648](https://datatracker.ietf.org/doc/html/rfc4648) + * (no differences from [RFC3548](https://datatracker.ietf.org/doc/html/rfc4648)). + * + * ```js + * import { fromBase32, toBase32 } from '@exodus/bytes/base32.js' + * import { fromBase32hex, toBase32hex } from '@exodus/bytes/base32.js' + * ``` + * + * @module @exodus/bytes/base32.js + */ + +/// <reference types="node" /> + +import type { OutputFormat, Uint8ArrayBuffer } from './array.js'; + +/** + * Options for base32 encoding + */ +export interface ToBase32Options { + /** Whether to include padding characters (default: false) */ + padding?: boolean; +} + +/** + * Padding mode for base32 decoding + * - `true`: padding is required + * - `false`: padding is not allowed + * - `'both'`: padding is optional (default) + */ +export type PaddingMode = boolean | 'both'; + +/** + * Options for base32 decoding + */ +export interface FromBase32Options { + /** Output format (default: 'uint8') */ + format?: OutputFormat; + /** Padding mode */ + padding?: PaddingMode; +} + +/** + * Encode a `Uint8Array` to a base32 string (RFC 4648) + * + * @param arr - The input bytes + * @param options - Encoding options + * @returns The base32 encoded string + */ +export function toBase32(arr: Uint8Array, options?: ToBase32Options): string; + +/** + * Encode a `Uint8Array` to a base32hex string (RFC 4648) + * + * @param arr - The input bytes + * @param options - Encoding options (padding defaults to false) + * @returns The base32hex encoded string + */ +export function toBase32hex(arr: Uint8Array, options?: ToBase32Options): string; + +/** + * Decode a base32 string to bytes + * + * Operates in strict mode for last chunk, does not allow whitespace + * + * @param string - The base32 encoded string + * @param options - Decoding options + * @returns The decoded bytes + */ +export function fromBase32(string: string, options?: FromBase32Options): Uint8ArrayBuffer; +export function fromBase32(string: string, options: FromBase32Options & { format: 'buffer' }): Buffer; + +/** + * Decode a base32hex string to bytes + * + * Operates in strict mode for last chunk, does not allow whitespace + * + * @param string - The base32hex encoded string + * @param options - Decoding options + * @returns The decoded bytes + */ +export function fromBase32hex(string: string, options?: FromBase32Options): Uint8ArrayBuffer; +export function fromBase32hex(string: string, options: FromBase32Options & { format: 'buffer' }): Buffer; diff --git a/vanilla/node_modules/@exodus/bytes/base32.js b/vanilla/node_modules/@exodus/bytes/base32.js new file mode 100644 index 0000000..1c45766 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/base32.js @@ -0,0 +1,39 @@ +import { assertEmptyRest } from './assert.js' +import { typedView } from './array.js' +import { E_STRING } from './fallback/_utils.js' +import * as js from './fallback/base32.js' + +// See https://datatracker.ietf.org/doc/html/rfc4648 + +// 8 chars per 5 bytes + +export const toBase32 = (arr, { padding = false } = {}) => js.toBase32(arr, false, padding) +export const toBase32hex = (arr, { padding = false } = {}) => js.toBase32(arr, true, padding) + +// By default, valid padding is accepted but not required +export function fromBase32(str, options) { + if (!options) return fromBase32common(str, false, 'both', 'uint8', null) + const { format = 'uint8', padding = 'both', ...rest } = options + return fromBase32common(str, false, padding, format, rest) +} + +export function fromBase32hex(str, options) { + if (!options) return fromBase32common(str, true, 'both', 'uint8', null) + const { format = 'uint8', padding = 'both', ...rest } = options + return fromBase32common(str, true, padding, format, rest) +} + +function fromBase32common(str, isBase32Hex, padding, format, rest) { + if (typeof str !== 'string') throw new TypeError(E_STRING) + if (rest !== null) assertEmptyRest(rest) + + if (padding === true) { + if (str.length % 8 !== 0) throw new SyntaxError(js.E_PADDING) + } else if (padding === false) { + if (str.endsWith('=')) throw new SyntaxError('Did not expect padding in base32 input') + } else if (padding !== 'both') { + throw new TypeError('Invalid padding option') + } + + return typedView(js.fromBase32(str, isBase32Hex), format) +} diff --git a/vanilla/node_modules/@exodus/bytes/base58.d.ts b/vanilla/node_modules/@exodus/bytes/base58.d.ts new file mode 100644 index 0000000..f4297a0 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/base58.d.ts @@ -0,0 +1,62 @@ +/** + * Implements [base58](https://www.ietf.org/archive/id/draft-msporny-base58-03.txt) encoding. + * + * Supports both standard base58 and XRP variant alphabets. + * + * ```js + * import { fromBase58, toBase58 } from '@exodus/bytes/base58.js' + * import { fromBase58xrp, toBase58xrp } from '@exodus/bytes/base58.js' + * ``` + * + * @module @exodus/bytes/base58.js + */ + +/// <reference types="node" /> + +import type { OutputFormat, Uint8ArrayBuffer } from './array.js'; + +/** + * Encode a `Uint8Array` to a base58 string + * + * Uses the standard Bitcoin base58 alphabet + * + * @param arr - The input bytes + * @returns The base58 encoded string + */ +export function toBase58(arr: Uint8Array): string; + +/** + * Decode a base58 string to bytes + * + * Uses the standard Bitcoin base58 alphabet + * + * @param string - The base58 encoded string + * @param format - Output format (default: 'uint8') + * @returns The decoded bytes + */ +export function fromBase58(string: string, format?: 'uint8'): Uint8ArrayBuffer; +export function fromBase58(string: string, format: 'buffer'): Buffer; +export function fromBase58(string: string, format?: OutputFormat): Uint8ArrayBuffer | Buffer; + +/** + * Encode a `Uint8Array` to a base58 string using XRP alphabet + * + * Uses the XRP variant base58 alphabet + * + * @param arr - The input bytes + * @returns The base58 encoded string + */ +export function toBase58xrp(arr: Uint8Array): string; + +/** + * Decode a base58 string to bytes using XRP alphabet + * + * Uses the XRP variant base58 alphabet + * + * @param string - The base58 encoded string + * @param format - Output format (default: 'uint8') + * @returns The decoded bytes + */ +export function fromBase58xrp(string: string, format?: 'uint8'): Uint8ArrayBuffer; +export function fromBase58xrp(string: string, format: 'buffer'): Buffer; +export function fromBase58xrp(string: string, format?: OutputFormat): Uint8ArrayBuffer | Buffer; diff --git a/vanilla/node_modules/@exodus/bytes/base58.js b/vanilla/node_modules/@exodus/bytes/base58.js new file mode 100644 index 0000000..c032aba --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/base58.js @@ -0,0 +1,220 @@ +import { typedView } from './array.js' +import { assertU8, E_STRING } from './fallback/_utils.js' +import { nativeDecoder, nativeEncoder, isHermes } from './fallback/platform.js' +import { encodeAscii, decodeAscii } from './fallback/latin1.js' + +const alphabet58 = [...'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'] +const alphabetXRP = [...'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz'] +const codes58 = new Uint8Array(alphabet58.map((x) => x.charCodeAt(0))) +const codesXRP = new Uint8Array(alphabetXRP.map((x) => x.charCodeAt(0))) + +const _0n = BigInt(0) +const _1n = BigInt(1) +const _8n = BigInt(8) +const _32n = BigInt(32) +const _58n = BigInt(58) +const _0xffffffffn = BigInt(0xff_ff_ff_ff) + +let table // 15 * 82, diagonal, <1kb +const fromMaps = new Map() + +const E_CHAR = 'Invalid character in base58 input' + +const shouldUseBigIntFrom = isHermes // faster only on Hermes, numbers path beats it on normal engines + +function toBase58core(arr, alphabet, codes) { + assertU8(arr) + const length = arr.length + if (length === 0) return '' + + const ZERO = alphabet[0] + let zeros = 0 + while (zeros < length && arr[zeros] === 0) zeros++ + + if (length > 60) { + // Slow path. Can be optimized ~10%, but the main factor is /58n division anyway, so doesn't matter much + let x = _0n + for (let i = 0; i < arr.length; i++) x = (x << _8n) | BigInt(arr[i]) + + let out = '' + while (x) { + const d = x / _58n + out = alphabet[Number(x - _58n * d)] + out + x = d + } + + return ZERO.repeat(zeros) + out + } + + // We run fast mode operations only on short (<=60 bytes) inputs, via precomputation table + if (!table) { + table = [] + let x = _1n + for (let i = 0; i < 15; i++) { + // Convert x to base 58 digits + const in58 = [] + let y = x + while (y) { + const d = y / _58n + in58.push(Number(y - _58n * d)) + y = d + } + + table.push(new Uint8Array(in58)) + x <<= _32n + } + } + + const res = [] + { + let j = 0 + // We group each 4 bytes into 32-bit chunks + // Not using u32arr to not deal with remainder + BE/LE differences + for (let i = length - 1; i >= 0; i -= 4) { + let c + if (i > 2) { + c = (arr[i] | (arr[i - 1] << 8) | (arr[i - 2] << 16) | (arr[i - 3] << 24)) >>> 0 + } else if (i > 1) { + c = arr[i] | (arr[i - 1] << 8) | (arr[i - 2] << 16) + } else { + c = i === 1 ? arr[i] | (arr[i - 1] << 8) : arr[i] + } + + const row = table[j++] + if (c === 0) continue + const olen = res.length + const nlen = row.length + let k = 0 + for (; k < olen; k++) res[k] += c * row[k] + while (k < nlen) res.push(c * row[k++]) + } + } + + // We can now do a single scan over regular numbers under MAX_SAFE_INTEGER + // Note: can't use int32 operations on them, as they are outside of 2**32 range + // This is faster though + { + let carry = 0 + let i = 0 + while (i < res.length) { + const c = res[i] + carry + carry = Math.floor(c / 58) + res[i++] = c - carry * 58 + } + + while (carry) { + const c = carry + carry = Math.floor(c / 58) + res.push(c - carry * 58) + } + } + + if (nativeDecoder) { + const oa = new Uint8Array(res.length) + let j = 0 + for (let i = res.length - 1; i >= 0; i--) oa[j++] = codes[res[i]] + return ZERO.repeat(zeros) + decodeAscii(oa) + } + + let out = '' + for (let i = res.length - 1; i >= 0; i--) out += alphabet[res[i]] + return ZERO.repeat(zeros) + out +} + +function fromBase58core(str, alphabet, codes, format = 'uint8') { + if (typeof str !== 'string') throw new TypeError(E_STRING) + const length = str.length + if (length === 0) return typedView(new Uint8Array(), format) + + const zeroC = codes[0] + let zeros = 0 + while (zeros < length && str.charCodeAt(zeros) === zeroC) zeros++ + + let fromMap = fromMaps.get(alphabet) + if (!fromMap) { + fromMap = new Int8Array(256).fill(-1) + for (let i = 0; i < 58; i++) fromMap[alphabet[i].charCodeAt(0)] = i + fromMaps.set(alphabet, fromMap) + } + + const size = zeros + (((length - zeros + 1) * 3) >> 2) // 3/4 rounded up, larger than ~0.73 coef to fit everything + const res = new Uint8Array(size) + let at = size // where is the first significant byte written + + if (shouldUseBigIntFrom) { + let x = _0n + + // nativeEncoder gives a benefit here + if (nativeEncoder) { + const codes = encodeAscii(str, E_CHAR) + for (let i = zeros; i < length; i++) { + const c = fromMap[codes[i]] + if (c < 0) throw new SyntaxError(E_CHAR) + x = x * _58n + BigInt(c) + } + } else { + for (let i = zeros; i < length; i++) { + const charCode = str.charCodeAt(i) + const c = fromMap[charCode] + if (charCode > 255 || c < 0) throw new SyntaxError(E_CHAR) + x = x * _58n + BigInt(c) + } + } + + while (x) { + let y = Number(x & _0xffffffffn) + x >>= 32n + res[--at] = y & 0xff + y >>>= 8 + if (!x && !y) break + res[--at] = y & 0xff + y >>>= 8 + if (!x && !y) break + res[--at] = y & 0xff + y >>>= 8 + if (!x && !y) break + res[--at] = y & 0xff + } + } else { + for (let i = zeros; i < length; i++) { + const charCode = str.charCodeAt(i) + let c = fromMap[charCode] + if (charCode > 255 || c < 0) throw new SyntaxError(E_CHAR) + + let k = size - 1 + for (;;) { + if (c === 0 && k < at) break + c += 58 * res[k] + res[k] = c & 0xff + c >>>= 8 + k-- + // unroll a bit + if (c === 0 && k < at) break + c += 58 * res[k] + res[k] = c & 0xff + c >>>= 8 + k-- + if (c === 0 && k < at) break + c += 58 * res[k] + res[k] = c & 0xff + c >>>= 8 + k-- + if (c === 0 && k < at) break + c += 58 * res[k] + res[k] = c & 0xff + c >>>= 8 + k-- + } + + at = k + 1 + if (c !== 0 || at < zeros) /* c8 ignore next */ throw new Error('Unexpected') // unreachable + } + } + + return typedView(res.slice(at - zeros), format) // slice is faster for small sizes than subarray +} + +export const toBase58 = (arr) => toBase58core(arr, alphabet58, codes58) +export const fromBase58 = (str, format) => fromBase58core(str, alphabet58, codes58, format) +export const toBase58xrp = (arr) => toBase58core(arr, alphabetXRP, codesXRP) +export const fromBase58xrp = (str, format) => fromBase58core(str, alphabetXRP, codesXRP, format) diff --git a/vanilla/node_modules/@exodus/bytes/base58check.d.ts b/vanilla/node_modules/@exodus/bytes/base58check.d.ts new file mode 100644 index 0000000..9e6c29a --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/base58check.d.ts @@ -0,0 +1,131 @@ +/** + * Implements [base58check](https://en.bitcoin.it/wiki/Base58Check_encoding) encoding. + * + * ```js + * import { fromBase58check, toBase58check } from '@exodus/bytes/base58check.js' + * import { fromBase58checkSync, toBase58checkSync } from '@exodus/bytes/base58check.js' + * import { makeBase58check } from '@exodus/bytes/base58check.js' + * ``` + * + * On non-Node.js, requires peer dependency [@noble/hashes](https://www.npmjs.com/package/@noble/hashes) to be installed. + * + * @module @exodus/bytes/base58check.js + */ + +/// <reference types="node" /> + +import type { OutputFormat, Uint8ArrayBuffer } from './array.js'; + +/** + * Hash function type that takes Uint8Array and returns a Promise of Uint8Array + */ +export type HashFunction = (data: Uint8Array) => Promise<Uint8Array>; + +/** + * Synchronous hash function type that takes Uint8Array and returns Uint8Array + */ +export type HashFunctionSync = (data: Uint8Array) => Uint8Array; + +/** + * Base58Check encoder/decoder instance with async methods + */ +export interface Base58CheckAsync { + /** + * Encode bytes to base58check string asynchronously + * + * @param arr - The input bytes to encode + * @returns A Promise that resolves to the base58check encoded string + */ + encode(arr: Uint8Array): Promise<string>; + + /** + * Decode a base58check string to bytes asynchronously + * + * @param string - The base58check encoded string + * @param format - Output format (default: 'uint8') + * @returns A Promise that resolves to the decoded bytes + */ + decode(string: string, format?: 'uint8'): Promise<Uint8ArrayBuffer>; + decode(string: string, format: 'buffer'): Promise<Buffer>; + decode(string: string, format?: OutputFormat): Promise<Uint8ArrayBuffer | Buffer>; +} + +/** + * Base58Check encoder/decoder instance with both async and sync methods + */ +export interface Base58CheckSync extends Base58CheckAsync { + /** + * Encode bytes to base58check string synchronously + * + * @param arr - The input bytes to encode + * @returns The base58check encoded string + */ + encodeSync(arr: Uint8Array): string; + + /** + * Decode a base58check string to bytes synchronously + * + * @param string - The base58check encoded string + * @param format - Output format (default: 'uint8') + * @returns The decoded bytes + */ + decodeSync(string: string, format?: 'uint8'): Uint8ArrayBuffer; + decodeSync(string: string, format: 'buffer'): Buffer; + decodeSync(string: string, format?: OutputFormat): Uint8ArrayBuffer | Buffer; +} + +/** + * Create a base58check encoder/decoder with custom hash functions + * + * @param hashAlgo - Async hash function (typically double SHA-256) + * @param hashAlgoSync - Optional sync hash function + * @returns Base58Check encoder/decoder instance + */ +export function makeBase58check(hashAlgo: HashFunction | HashFunctionSync, hashAlgoSync: HashFunctionSync): Base58CheckSync; +export function makeBase58check(hashAlgo: HashFunction | HashFunctionSync, hashAlgoSync?: undefined): Base58CheckAsync; + +/** + * Encode bytes to base58check string asynchronously + * + * Uses double SHA-256 for checksum calculation + * + * @param arr - The input bytes to encode + * @returns A Promise that resolves to the base58check encoded string + */ +export function toBase58check(arr: Uint8Array): Promise<string>; + +/** + * Decode a base58check string to bytes asynchronously + * + * Validates the checksum using double SHA-256 + * + * @param string - The base58check encoded string + * @param format - Output format (default: 'uint8') + * @returns A Promise that resolves to the decoded bytes + */ +export function fromBase58check(string: string, format?: 'uint8'): Promise<Uint8ArrayBuffer>; +export function fromBase58check(string: string, format: 'buffer'): Promise<Buffer>; +export function fromBase58check(string: string, format?: OutputFormat): Promise<Uint8ArrayBuffer | Buffer>; + +/** + * Encode bytes to base58check string synchronously + * + * Uses double SHA-256 for checksum calculation + * + * @param arr - The input bytes to encode + * @returns The base58check encoded string + */ +export function toBase58checkSync(arr: Uint8Array): string; + +/** + * Decode a base58check string to bytes synchronously + * + * Validates the checksum using double SHA-256 + * + * @param string - The base58check encoded string + * @param format - Output format (default: 'uint8') + * @returns The decoded bytes + */ +export function fromBase58checkSync(string: string, format?: 'uint8'): Uint8ArrayBuffer; +export function fromBase58checkSync(string: string, format: 'buffer'): Buffer; +export function fromBase58checkSync(string: string, format?: OutputFormat): Uint8ArrayBuffer | Buffer; diff --git a/vanilla/node_modules/@exodus/bytes/base58check.js b/vanilla/node_modules/@exodus/bytes/base58check.js new file mode 100644 index 0000000..7b2f911 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/base58check.js @@ -0,0 +1,18 @@ +import { sha256 } from '@noble/hashes/sha2.js' +import { makeBase58check } from './fallback/base58check.js' + +// Note: while API is async, we use hashSync for now until we improve webcrypto perf for hash256 +// Inputs to base58 are typically very small, and that makes a difference + +// Note: using native WebCrypto will have to have account for SharedArrayBuffer + +const hash256sync = (x) => sha256(sha256(x)) +const hash256 = hash256sync // See note at the top + +const b58c = /* @__PURE__ */ makeBase58check(hash256, hash256sync) +export const toBase58check = /* @__PURE__ */ (() => b58c.encode)() +export const fromBase58check = /* @__PURE__ */ (() => b58c.decode)() +export const toBase58checkSync = /* @__PURE__ */ (() => b58c.encodeSync)() +export const fromBase58checkSync = /* @__PURE__ */ (() => b58c.decodeSync)() + +export { makeBase58check } from './fallback/base58check.js' diff --git a/vanilla/node_modules/@exodus/bytes/base58check.node.js b/vanilla/node_modules/@exodus/bytes/base58check.node.js new file mode 100644 index 0000000..ea8d58b --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/base58check.node.js @@ -0,0 +1,14 @@ +import { hash } from 'node:crypto' +import { makeBase58check } from './fallback/base58check.js' + +const sha256 = (x) => hash('sha256', x, 'buffer') +const hash256 = (x) => sha256(sha256(x)) +const { + encode: toBase58check, + decode: fromBase58check, + encodeSync: toBase58checkSync, + decodeSync: fromBase58checkSync, +} = makeBase58check(hash256, hash256) + +export { makeBase58check } from './fallback/base58check.js' +export { toBase58check, fromBase58check, toBase58checkSync, fromBase58checkSync } diff --git a/vanilla/node_modules/@exodus/bytes/base64.d.ts b/vanilla/node_modules/@exodus/bytes/base64.d.ts new file mode 100644 index 0000000..064b18f --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/base64.d.ts @@ -0,0 +1,96 @@ +/** + * Implements base64 and base64url from [RFC4648](https://datatracker.ietf.org/doc/html/rfc4648) + * (no differences from [RFC3548](https://datatracker.ietf.org/doc/html/rfc4648)). + * + * ```js + * import { fromBase64, toBase64 } from '@exodus/bytes/base64.js' + * import { fromBase64url, toBase64url } from '@exodus/bytes/base64.js' + * import { fromBase64any } from '@exodus/bytes/base64.js' + * ``` + * + * @module @exodus/bytes/base64.js + */ + +/// <reference types="node" /> + +import type { OutputFormat, Uint8ArrayBuffer } from './array.js'; + +/** + * Options for base64 encoding + */ +export interface ToBase64Options { + /** Whether to include padding characters (default: true for base64, false for base64url) */ + padding?: boolean; +} + +/** + * Padding mode for base64 decoding + * - `true`: padding is required + * - `false`: padding is not allowed (default for base64url) + * - `'both'`: padding is optional (default for base64) + */ +export type PaddingMode = boolean | 'both'; + +/** + * Options for base64 decoding + */ +export interface FromBase64Options { + /** Output format (default: 'uint8') */ + format?: OutputFormat; + /** Padding mode */ + padding?: PaddingMode; +} + +/** + * Encode a `Uint8Array` to a base64 string (RFC 4648) + * + * @param arr - The input bytes + * @param options - Encoding options + * @returns The base64 encoded string + */ +export function toBase64(arr: Uint8Array, options?: ToBase64Options): string; + +/** + * Encode a `Uint8Array` to a base64url string (RFC 4648) + * + * @param arr - The input bytes + * @param options - Encoding options (padding defaults to false) + * @returns The base64url encoded string + */ +export function toBase64url(arr: Uint8Array, options?: ToBase64Options): string; + +/** + * Decode a base64 string to bytes + * + * Operates in strict mode for last chunk, does not allow whitespace + * + * @param string - The base64 encoded string + * @param options - Decoding options + * @returns The decoded bytes + */ +export function fromBase64(string: string, options?: FromBase64Options): Uint8ArrayBuffer; +export function fromBase64(string: string, options: FromBase64Options & { format: 'buffer' }): Buffer; + +/** + * Decode a base64url string to bytes + * + * Operates in strict mode for last chunk, does not allow whitespace + * + * @param string - The base64url encoded string + * @param options - Decoding options (padding defaults to false) + * @returns The decoded bytes + */ +export function fromBase64url(string: string, options?: FromBase64Options): Uint8ArrayBuffer; +export function fromBase64url(string: string, options: FromBase64Options & { format: 'buffer' }): Buffer; + +/** + * Decode either base64 or base64url string to bytes + * + * Automatically detects the variant based on characters present + * + * @param string - The base64 or base64url encoded string + * @param options - Decoding options + * @returns The decoded bytes + */ +export function fromBase64any(string: string, options?: FromBase64Options): Uint8ArrayBuffer; +export function fromBase64any(string: string, options: FromBase64Options & { format: 'buffer' }): Buffer; diff --git a/vanilla/node_modules/@exodus/bytes/base64.js b/vanilla/node_modules/@exodus/bytes/base64.js new file mode 100644 index 0000000..e8625f7 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/base64.js @@ -0,0 +1,178 @@ +import { assertEmptyRest } from './assert.js' +import { typedView } from './array.js' +import { assertU8, E_STRING } from './fallback/_utils.js' +import { isHermes } from './fallback/platform.js' +import { decodeLatin1, encodeLatin1 } from './fallback/latin1.js' +import * as js from './fallback/base64.js' + +// See https://datatracker.ietf.org/doc/html/rfc4648 + +// base64: A-Za-z0-9+/ and = if padding not disabled +// base64url: A-Za-z0-9_- and = if padding enabled + +const { Buffer, atob, btoa } = globalThis // Buffer is optional, only used when native +const haveNativeBuffer = Buffer && !Buffer.TYPED_ARRAY_SUPPORT +const { toBase64: web64 } = Uint8Array.prototype // Modern engines have this + +const { E_CHAR, E_PADDING, E_LENGTH, E_LAST } = js + +// faster only on Hermes (and a little in old Chrome), js path beats it on normal engines +const shouldUseBtoa = btoa && isHermes +const shouldUseAtob = atob && isHermes + +// For native Buffer codepaths only +const isBuffer = (x) => x.constructor === Buffer && Buffer.isBuffer(x) +const toBuffer = (x) => (isBuffer(x) ? x : Buffer.from(x.buffer, x.byteOffset, x.byteLength)) + +function maybeUnpad(res, padding) { + if (padding) return res + const at = res.indexOf('=', res.length - 3) + return at === -1 ? res : res.slice(0, at) +} + +function maybePad(res, padding) { + return padding && res.length % 4 !== 0 ? res + '='.repeat(4 - (res.length % 4)) : res +} + +const toUrl = (x) => x.replaceAll('+', '-').replaceAll('/', '_') +const haveWeb = (x) => web64 && x.toBase64 === web64 + +export function toBase64(x, { padding = true } = {}) { + assertU8(x) + if (haveWeb(x)) return padding ? x.toBase64() : x.toBase64({ omitPadding: !padding }) // Modern, optionless is slightly faster + if (haveNativeBuffer) return maybeUnpad(toBuffer(x).base64Slice(0, x.byteLength), padding) // Older Node.js + if (shouldUseBtoa) return maybeUnpad(btoa(decodeLatin1(x)), padding) + return js.toBase64(x, false, padding) // Fallback +} + +// NOTE: base64url omits padding by default +export function toBase64url(x, { padding = false } = {}) { + assertU8(x) + if (haveWeb(x)) return x.toBase64({ alphabet: 'base64url', omitPadding: !padding }) // Modern + if (haveNativeBuffer) return maybePad(toBuffer(x).base64urlSlice(0, x.byteLength), padding) // Older Node.js + if (shouldUseBtoa) return maybeUnpad(toUrl(btoa(decodeLatin1(x))), padding) + return js.toBase64(x, true, padding) // Fallback +} + +// Unlike Buffer.from(), throws on invalid input (non-base64 symbols and incomplete chunks) +// Unlike Buffer.from() and Uint8Array.fromBase64(), does not allow spaces +// NOTE: Always operates in strict mode for last chunk + +// By default accepts both padded and non-padded variants, only strict base64 +export function fromBase64(str, options) { + if (typeof options === 'string') options = { format: options } // Compat due to usage, TODO: remove + if (!options) return fromBase64common(str, false, 'both', 'uint8', null) + const { format = 'uint8', padding = 'both', ...rest } = options + return fromBase64common(str, false, padding, format, rest) +} + +// By default accepts only non-padded strict base64url +export function fromBase64url(str, options) { + if (!options) return fromBase64common(str, true, false, 'uint8', null) + const { format = 'uint8', padding = false, ...rest } = options + return fromBase64common(str, true, padding, format, rest) +} + +// By default accepts both padded and non-padded variants, base64 or base64url +export function fromBase64any(str, { format = 'uint8', padding = 'both', ...rest } = {}) { + const isBase64url = !str.includes('+') && !str.includes('/') // likely to fail fast, as most input is non-url, also double scan is faster than regex + return fromBase64common(str, isBase64url, padding, format, rest) +} + +function fromBase64common(str, isBase64url, padding, format, rest) { + if (typeof str !== 'string') throw new TypeError(E_STRING) + if (rest !== null) assertEmptyRest(rest) + const auto = padding === 'both' ? str.endsWith('=') : undefined + // Older JSC supporting Uint8Array.fromBase64 lacks proper checks + if (padding === true || auto === true) { + if (str.length % 4 !== 0) throw new SyntaxError(E_PADDING) // JSC misses this + if (str[str.length - 3] === '=') throw new SyntaxError(E_PADDING) // no more than two = at the end + } else if (padding === false || auto === false) { + if (str.length % 4 === 1) throw new SyntaxError(E_LENGTH) // JSC misses this in fromBase64 + if (padding === false && str.endsWith('=')) { + throw new SyntaxError('Did not expect padding in base64 input') // inclusion is checked separately + } + } else { + throw new TypeError('Invalid padding option') + } + + return typedView(fromBase64impl(str, isBase64url, padding), format) +} + +// ASCII whitespace is U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE +const ASCII_WHITESPACE = /[\t\n\f\r ]/ // non-u for JSC perf + +function noWhitespaceSeen(str, arr) { + const at = str.indexOf('=', str.length - 3) + const paddingLength = at >= 0 ? str.length - at : 0 + const chars = str.length - paddingLength + const e = chars % 4 // extra chars past blocks of 4 + const b = arr.length - ((chars - e) / 4) * 3 // remaining bytes not covered by full blocks of chars + return (e === 0 && b === 0) || (e === 2 && b === 1) || (e === 3 && b === 2) +} + +let fromBase64impl +if (Uint8Array.fromBase64) { + // NOTICE: this is actually slower than our JS impl in older JavaScriptCore and (slightly) in SpiderMonkey, but faster on V8 and new JavaScriptCore + fromBase64impl = (str, isBase64url, padding) => { + const alphabet = isBase64url ? 'base64url' : 'base64' + + let arr + if (padding === true) { + // Padding is required from user, and we already checked that string length is divisible by 4 + // Padding might still be wrong due to whitespace, but in that case native impl throws expected error + arr = Uint8Array.fromBase64(str, { alphabet, lastChunkHandling: 'strict' }) + } else { + try { + const padded = str.length % 4 > 0 ? `${str}${'='.repeat(4 - (str.length % 4))}` : str + arr = Uint8Array.fromBase64(padded, { alphabet, lastChunkHandling: 'strict' }) + } catch (err) { + // Normalize error: whitespace in input could have caused added padding to be invalid + // But reporting that as a padding error would be confusing + throw ASCII_WHITESPACE.test(str) ? new SyntaxError(E_CHAR) : err + } + } + + // We don't allow whitespace in input, but that can be rechecked based on output length + // All other chars are checked natively + if (!noWhitespaceSeen(str, arr)) throw new SyntaxError(E_CHAR) + return arr + } +} else if (haveNativeBuffer) { + fromBase64impl = (str, isBase64url, padding) => { + const arr = Buffer.from(str, 'base64') + // Rechecking by re-encoding is cheaper than regexes on Node.js + const got = isBase64url ? maybeUnpad(str, padding === false) : maybePad(str, padding !== true) + const valid = isBase64url ? arr.base64urlSlice(0, arr.length) : arr.base64Slice(0, arr.length) + if (got !== valid) throw new SyntaxError(E_PADDING) + return arr // fully checked + } +} else if (shouldUseAtob) { + // atob is faster than manual parsing on Hermes + fromBase64impl = (str, isBase64url, padding) => { + let arr + if (isBase64url) { + if (/[\t\n\f\r +/]/.test(str)) throw new SyntaxError(E_CHAR) // atob verifies other invalid input + str = str.replaceAll('-', '+').replaceAll('_', '/') // from url to normal + } + + try { + arr = encodeLatin1(atob(str)) + } catch { + throw new SyntaxError(E_CHAR) // convert atob errors + } + + if (!isBase64url && !noWhitespaceSeen(str, arr)) throw new SyntaxError(E_CHAR) // base64url checks input above + + if (arr.length % 3 !== 0) { + // Check last chunk to be strict if it was incomplete + const expected = toBase64(arr.subarray(-(arr.length % 3))) // str is normalized to non-url already + const end = str.length % 4 === 0 ? str.slice(-4) : str.slice(-(str.length % 4)).padEnd(4, '=') + if (expected !== end) throw new SyntaxError(E_LAST) + } + + return arr + } +} else { + fromBase64impl = (str, isBase64url, padding) => js.fromBase64(str, isBase64url) // validated in js +} diff --git a/vanilla/node_modules/@exodus/bytes/bech32.d.ts b/vanilla/node_modules/@exodus/bytes/bech32.d.ts new file mode 100644 index 0000000..67d6476 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/bech32.d.ts @@ -0,0 +1,76 @@ +/** + * Implements bech32 and bech32m from + * [BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#specification) + * and [BIP-0350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki#specification). + * + * ```js + * import { fromBech32, toBech32 } from '@exodus/bytes/bech32.js' + * import { fromBech32m, toBech32m } from '@exodus/bytes/bech32.js' + * import { getPrefix } from '@exodus/bytes/bech32.js' + * ``` + * + * @module @exodus/bytes/bech32.js + */ + +/// <reference types="node" /> + +import type { Uint8ArrayBuffer } from './array.js'; + +/** + * Result of decoding a bech32 or bech32m string + */ +export interface Bech32DecodeResult { + /** The human-readable prefix */ + prefix: string; + /** The decoded bytes */ + bytes: Uint8ArrayBuffer; +} + +/** + * Encode bytes to a bech32 string + * + * @param prefix - The human-readable prefix (e.g., 'bc' for Bitcoin) + * @param bytes - The input bytes to encode + * @param limit - Maximum length of the encoded string (default: 90) + * @returns The bech32 encoded string + */ +export function toBech32(prefix: string, bytes: Uint8Array, limit?: number): string; + +/** + * Decode a bech32 string to bytes + * + * @param string - The bech32 encoded string + * @param limit - Maximum length of the input string (default: 90) + * @returns The decoded prefix and bytes + */ +export function fromBech32(string: string, limit?: number): Bech32DecodeResult; + +/** + * Encode bytes to a bech32m string + * + * @param prefix - The human-readable prefix (e.g., 'bc' for Bitcoin) + * @param bytes - The input bytes to encode + * @param limit - Maximum length of the encoded string (default: 90) + * @returns The bech32m encoded string + */ +export function toBech32m(prefix: string, bytes: Uint8Array, limit?: number): string; + +/** + * Decode a bech32m string to bytes + * + * @param string - The bech32m encoded string + * @param limit - Maximum length of the input string (default: 90) + * @returns The decoded prefix and bytes + */ +export function fromBech32m(string: string, limit?: number): Bech32DecodeResult; + +/** + * Extract the prefix from a bech32 or bech32m string without full validation + * + * This is a quick check that skips most validation. + * + * @param string - The bech32/bech32m encoded string + * @param limit - Maximum length of the input string (default: 90) + * @returns The lowercase prefix + */ +export function getPrefix(string: string, limit?: number): string; diff --git a/vanilla/node_modules/@exodus/bytes/bech32.js b/vanilla/node_modules/@exodus/bytes/bech32.js new file mode 100644 index 0000000..8f9c6b5 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/bech32.js @@ -0,0 +1,257 @@ +import { assertU8, E_STRING } from './fallback/_utils.js' +import { nativeEncoder } from './fallback/platform.js' +import { decodeAscii, encodeAscii, encodeLatin1 } from './fallback/latin1.js' + +const alphabet = [...'qpzry9x8gf2tvdw0s3jn54khce6mua7l'] +const BECH32 = 1 +const BECH32M = 0x2b_c8_30_a3 + +const E_SIZE = 'Input length is out of range' +const E_PREFIX = 'Missing or invalid prefix' +const E_MIXED = 'Mixed-case string' +const E_PADDING = 'Padding is invalid' +const E_CHECKSUM = 'Invalid checksum' +const E_CHARACTER = 'Non-bech32 character' + +// nativeEncoder path uses encodeAscii which asserts ascii, otherwise we have 0-255 bytes from encodeLatin1 +const c2x = new Int8Array(nativeEncoder ? 128 : 256).fill(-1) +const x2c = new Uint8Array(32) +for (let i = 0; i < alphabet.length; i++) { + const c = alphabet[i].charCodeAt(0) + c2x[c] = i + x2c[i] = c +} + +// checksum size is 30 bits, 0x3f_ff_ff_ff +// The good thing about the checksum is that it's linear over every bit +const poly0 = new Uint32Array(32) // just precache all possible ones, it's only 1 KiB +const p = (x) => ((x & 0x1_ff_ff_ff) << 5) ^ poly0[x >> 25] +for (let i = 0; i < 32; i++) { + poly0[i] = + (i & 0b0_0001 ? 0x3b_6a_57_b2 : 0) ^ + (i & 0b0_0010 ? 0x26_50_8e_6d : 0) ^ + (i & 0b0_0100 ? 0x1e_a1_19_fa : 0) ^ + (i & 0b0_1000 ? 0x3d_42_33_dd : 0) ^ + (i & 0b1_0000 ? 0x2a_14_62_b3 : 0) +} + +// 7 KiB more for faster p6/p8 +const poly1 = new Uint32Array(32) +const poly2 = new Uint32Array(32) +const poly3 = new Uint32Array(32) +const poly4 = new Uint32Array(32) +const poly5 = new Uint32Array(32) +const poly6 = new Uint32Array(32) +const poly7 = new Uint32Array(32) +for (let i = 0; i < 32; i++) { + // poly0[i] === p(p(p(p(p(p(i)))))) + poly1[i] = p(poly0[i]) // aka p(p(p(p(p(p(i << 5)))))) + poly2[i] = p(poly1[i]) // aka p(p(p(p(p(p(i << 10)))))) + poly3[i] = p(poly2[i]) // aka p(p(p(p(p(p(i << 15)))))) + poly4[i] = p(poly3[i]) // aka p(p(p(p(p(p(i << 20)))))) + poly5[i] = p(poly4[i]) // aka p(p(p(p(p(p(i << 25)))))) + poly6[i] = p(poly5[i]) + poly7[i] = p(poly6[i]) +} + +function p6(x) { + // Same as: return p(p(p(p(p(p(x)))))) + const x0 = x & 0x1f + const x1 = (x >> 5) & 0x1f + const x2 = (x >> 10) & 0x1f + const x3 = (x >> 15) & 0x1f + const x4 = (x >> 20) & 0x1f + const x5 = (x >> 25) & 0x1f + return poly0[x0] ^ poly1[x1] ^ poly2[x2] ^ poly3[x3] ^ poly4[x4] ^ poly5[x5] +} + +function p8(x) { + // Same as: return p(p(p(p(p(p(p(p(x)))))))) + const x0 = x & 0x1f + const x1 = (x >> 5) & 0x1f + const x2 = (x >> 10) & 0x1f + const x3 = (x >> 15) & 0x1f + const x4 = (x >> 20) & 0x1f + const x5 = (x >> 25) & 0x1f + return poly2[x0] ^ poly3[x1] ^ poly4[x2] ^ poly5[x3] ^ poly6[x4] ^ poly7[x5] +} + +// p(p(p(p(p(p(chk) ^ x0) ^ x1) ^ x2) ^ x3) ^ x4) ^ x5 === p6(chk) ^ merge(x0, x1, x2, x3, x4, x5) +const merge = (a, b, c, d, e, f) => f ^ (e << 5) ^ (d << 10) ^ (c << 15) ^ (b << 20) ^ (a << 25) + +const prefixCache = new Map() // Cache 10 of them + +function pPrefix(prefix) { + if (prefix === 'bc') return 0x2_31_80_43 // perf + const cached = prefixCache.get(prefix) + if (cached !== undefined) return cached + + // bech32_hrp_expand(s): [ord(x) >> 5 for x in s] + [0] + [ord(x) & 31 for x in s] + // We can do this in a single scan due to linearity, but it's not very beneficial + let chk = 1 // it starts with one (see def bech32_polymod in BIP_0173) + const length = prefix.length + for (let i = 0; i < length; i++) { + const c = prefix.charCodeAt(i) + if (c < 33 || c > 126) throw new Error(E_PREFIX) // each character having a value in the range [33-126] + chk = p(chk) ^ (c >> 5) + } + + chk = p(chk) // <= for + [0] + for (let i = 0; i < length; i++) { + const c = prefix.charCodeAt(i) + chk = p(chk) ^ (c & 0x1f) + } + + if (prefixCache.size < 10) prefixCache.set(prefix, chk) + return chk +} + +function toBech32enc(prefix, bytes, limit, encoding) { + if (typeof prefix !== 'string' || !prefix) throw new TypeError(E_PREFIX) + if (typeof limit !== 'number') throw new TypeError(E_SIZE) + assertU8(bytes) + const bytesLength = bytes.length + const wordsLength = Math.ceil((bytesLength * 8) / 5) + if (!(prefix.length + 7 + wordsLength <= limit)) throw new TypeError(E_SIZE) + prefix = prefix.toLowerCase() + const out = new Uint8Array(wordsLength + 6) + + let chk = pPrefix(prefix) + let i = 0, j = 0 // prettier-ignore + + // This loop is just an optimization of the next one + for (const length4 = bytesLength - 4; i < length4; i += 5, j += 8) { + const b0 = bytes[i], b1 = bytes[i + 1], b2 = bytes[i + 2], b3 = bytes[i + 3], b4 = bytes[i + 4] // prettier-ignore + const x0 = b0 >> 3 + const x1 = ((b0 << 2) & 0x1f) | (b1 >> 6) + const x2 = (b1 >> 1) & 0x1f + const x3 = ((b1 << 4) & 0x1f) | (b2 >> 4) + const x4 = ((b2 << 1) & 0x1f) | (b3 >> 7) + const x5 = (b3 >> 2) & 0x1f + const x6 = ((b3 << 3) & 0x1f) | (b4 >> 5) + const x7 = b4 & 0x1f + chk = merge(x2, x3, x4, x5, x6, x7) ^ poly0[x1] ^ poly1[x0] ^ p8(chk) + out[j] = x2c[x0] + out[j + 1] = x2c[x1] + out[j + 2] = x2c[x2] + out[j + 3] = x2c[x3] + out[j + 4] = x2c[x4] + out[j + 5] = x2c[x5] + out[j + 6] = x2c[x6] + out[j + 7] = x2c[x7] + } + + let value = 0, bits = 0 // prettier-ignore + for (; i < bytesLength; i++) { + value = ((value & 0xf) << 8) | bytes[i] + bits += 3 + const x = (value >> bits) & 0x1f + chk = p(chk) ^ x + out[j++] = x2c[x] + if (bits >= 5) { + bits -= 5 + const x = (value >> bits) & 0x1f + chk = p(chk) ^ x + out[j++] = x2c[x] + } + } + + if (bits > 0) { + const x = (value << (5 - bits)) & 0x1f + chk = p(chk) ^ x + out[j++] = x2c[x] + } + + chk = encoding ^ p6(chk) + out[j++] = x2c[(chk >> 25) & 0x1f] + out[j++] = x2c[(chk >> 20) & 0x1f] + out[j++] = x2c[(chk >> 15) & 0x1f] + out[j++] = x2c[(chk >> 10) & 0x1f] + out[j++] = x2c[(chk >> 5) & 0x1f] + out[j++] = x2c[(chk >> 0) & 0x1f] + + return prefix + '1' + decodeAscii(out) // suboptimal in barebones, but actually ok in Hermes for not to care atm +} + +function assertDecodeArgs(str, limit) { + if (typeof str !== 'string') throw new TypeError(E_STRING) + if (typeof limit !== 'number' || str.length < 8 || !(str.length <= limit)) throw new Error(E_SIZE) +} + +// this is instant on 8-bit strings +const NON_LATIN = /[^\x00-\xFF]/ // eslint-disable-line no-control-regex + +function fromBech32enc(str, limit, encoding) { + assertDecodeArgs(str, limit) + const lower = str.toLowerCase() + if (str !== lower) { + if (str !== str.toUpperCase()) throw new Error(E_MIXED) + str = lower + } + + const split = str.lastIndexOf('1') + if (split <= 0) throw new Error(E_PREFIX) + const prefix = str.slice(0, split) + const charsLength = str.length - split - 1 + const wordsLength = charsLength - 6 + if (wordsLength < 0) throw new Error(E_SIZE) + const bytesLength = (wordsLength * 5) >> 3 + const slice = str.slice(split + 1) + if (!nativeEncoder && NON_LATIN.test(slice)) throw new SyntaxError(E_CHARACTER) // otherwise can't use encodeLatin1 + const c = nativeEncoder ? encodeAscii(slice, E_CHARACTER) : encodeLatin1(slice) // suboptimal, but only affects non-Hermes barebones + const bytes = new Uint8Array(bytesLength) + + let chk = pPrefix(prefix) + let i = 0, j = 0 // prettier-ignore + + // This loop is just an optimization of the next one + for (const length7 = wordsLength - 7; i < length7; i += 8, j += 5) { + const c0 = c[i], c1 = c[i + 1], c2 = c[i + 2], c3 = c[i + 3], c4 = c[i + 4], c5 = c[i + 5], c6 = c[i + 6], c7 = c[i + 7] // prettier-ignore + const x0 = c2x[c0], x1 = c2x[c1], x2 = c2x[c2], x3 = c2x[c3], x4 = c2x[c4], x5 = c2x[c5], x6 = c2x[c6], x7 = c2x[c7] // prettier-ignore + if (x0 < 0 || x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || x5 < 0 || x6 < 0 || x7 < 0) throw new SyntaxError(E_CHARACTER) // prettier-ignore + chk = merge(x2, x3, x4, x5, x6, x7) ^ poly0[x1] ^ poly1[x0] ^ p8(chk) + bytes[j] = (x0 << 3) | (x1 >> 2) + bytes[j + 1] = (((x1 << 6) | (x2 << 1)) & 0xff) | (x3 >> 4) + bytes[j + 2] = ((x3 << 4) & 0xff) | (x4 >> 1) + bytes[j + 3] = ((((x4 << 5) | x5) << 2) & 0xff) | (x6 >> 3) + bytes[j + 4] = ((x6 << 5) & 0xff) | x7 + } + + let value = 0, bits = 0 // prettier-ignore + for (; i < wordsLength; i++) { + const x = c2x[c[i]] + if (x < 0) throw new SyntaxError(E_CHARACTER) + chk = p(chk) ^ x + value = (value << 5) | x + bits += 5 + if (bits >= 8) { + bits -= 8 + bytes[j++] = (value >> bits) & 0xff + } + } + + if (bits >= 5 || (value << (8 - bits)) & 0xff) throw new Error(E_PADDING) + + // Checksum + { + const c0 = c[i], c1 = c[i + 1], c2 = c[i + 2], c3 = c[i + 3], c4 = c[i + 4], c5 = c[i + 5] // prettier-ignore + const x0 = c2x[c0], x1 = c2x[c1], x2 = c2x[c2], x3 = c2x[c3], x4 = c2x[c4], x5 = c2x[c5] // prettier-ignore + if (x0 < 0 || x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || x5 < 0) throw new SyntaxError(E_CHARACTER) + if ((merge(x0, x1, x2, x3, x4, x5) ^ p6(chk)) !== encoding) throw new Error(E_CHECKSUM) + } + + return { prefix, bytes } +} + +// This is designed to be a very quick check, skipping all other validation +export function getPrefix(str, limit = 90) { + assertDecodeArgs(str, limit) + const split = str.lastIndexOf('1') + if (split <= 0) throw new Error(E_PREFIX) + return str.slice(0, split).toLowerCase() +} + +export const toBech32 = (prefix, bytes, limit = 90) => toBech32enc(prefix, bytes, limit, BECH32) +export const fromBech32 = (str, limit = 90) => fromBech32enc(str, limit, BECH32) +export const toBech32m = (prefix, bytes, limit = 90) => toBech32enc(prefix, bytes, limit, BECH32M) +export const fromBech32m = (str, limit = 90) => fromBech32enc(str, limit, BECH32M) diff --git a/vanilla/node_modules/@exodus/bytes/bigint.d.ts b/vanilla/node_modules/@exodus/bytes/bigint.d.ts new file mode 100644 index 0000000..3a50dfa --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/bigint.d.ts @@ -0,0 +1,48 @@ +/** + * Convert between BigInt and Uint8Array + * + * ```js + * import { fromBigInt, toBigInt } from '@exodus/bytes/bigint.js' + * ``` + * + * @module @exodus/bytes/bigint.js + */ + +/// <reference types="node" /> + +import type { OutputFormat, Uint8ArrayBuffer } from './array.js'; + +/** + * Options for converting BigInt to bytes + */ +export interface FromBigIntOptions { + /** The length in bytes of the output array */ + length: number; + /** Output format (default: 'uint8') */ + format?: OutputFormat; +} + +/** + * Convert a BigInt to a Uint8Array or Buffer + * + * The output bytes are in big-endian format. + * + * Throws if the BigInt is negative or cannot fit into the specified length. + * + * @param bigint - The BigInt to convert (must be non-negative) + * @param options - Conversion options + * @returns The converted bytes in big-endian format + */ +export function fromBigInt(bigint: bigint, options: { length: number; format?: 'uint8' }): Uint8ArrayBuffer; +export function fromBigInt(bigint: bigint, options: { length: number; format: 'buffer' }): Buffer; +export function fromBigInt(bigint: bigint, options: FromBigIntOptions): Uint8ArrayBuffer | Buffer; + +/** + * Convert a Uint8Array or Buffer to a BigInt + * + * The bytes are interpreted as a big-endian unsigned integer. + * + * @param arr - The bytes to convert + * @returns The BigInt representation + */ +export function toBigInt(arr: Uint8Array): bigint; diff --git a/vanilla/node_modules/@exodus/bytes/bigint.js b/vanilla/node_modules/@exodus/bytes/bigint.js new file mode 100644 index 0000000..a51f909 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/bigint.js @@ -0,0 +1,14 @@ +import { toHex, fromHex } from '@exodus/bytes/hex.js' +import { assert } from './fallback/_utils.js' + +const _0n = BigInt(0) + +export function fromBigInt(x, { length, format } = {}) { + assert(Number.isSafeInteger(length) && length > 0, 'Expected length arg to be a positive integer') + assert(typeof x === 'bigint' && x >= _0n, 'Expected a non-negative bigint') + const hex = x.toString(16) + assert(length * 2 >= hex.length, `Can not fit supplied number into ${length} bytes`) + return fromHex(hex.padStart(length * 2, '0'), format) +} + +export const toBigInt = (a) => BigInt('0x' + (toHex(a) || '0')) diff --git a/vanilla/node_modules/@exodus/bytes/encoding-browser.browser.js b/vanilla/node_modules/@exodus/bytes/encoding-browser.browser.js new file mode 100644 index 0000000..e8333b4 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/encoding-browser.browser.js @@ -0,0 +1,55 @@ +import { getBOMEncoding } from './fallback/encoding.api.js' + +// Lite-weight version which re-exports existing implementations on browsers, +// while still being aliased to the full impl in RN and Node.js + +// WARNING: Note that browsers have bugs (which hopefully will get fixed soon) + +const { TextDecoder, TextEncoder, TextDecoderStream, TextEncoderStream } = globalThis + +export { getBOMEncoding } from './fallback/encoding.api.js' +export { TextDecoder, TextEncoder, TextDecoderStream, TextEncoderStream } + +export function normalizeEncoding(label) { + if (label === 'utf-8' || label === 'utf8' || label === 'UTF-8' || label === 'UTF8') return 'utf-8' + if (label === 'windows-1252' || label === 'ascii' || label === 'latin1') return 'windows-1252' + if (/[^\w\t\n\f\r .:-]/i.test(label)) return null + const l = `${label}`.trim().toLowerCase() + try { + return new TextDecoder(l).encoding + } catch {} + + if (l === 'x-user-defined') return l + if ( + l === 'replacement' || + l === 'csiso2022kr' || + l === 'hz-gb-2312' || + l === 'iso-2022-cn' || + l === 'iso-2022-cn-ext' || + l === 'iso-2022-kr' + ) { + return 'replacement' + } + + return null +} + +export function legacyHookDecode(input, fallbackEncoding = 'utf-8') { + const enc = getBOMEncoding(input) ?? normalizeEncoding(fallbackEncoding) + if (enc === 'replacement') return input.byteLength > 0 ? '\uFFFD' : '' + return new TextDecoder(enc).decode(input) +} + +export function labelToName(label) { + const enc = normalizeEncoding(label) + if (enc === 'utf-8') return 'UTF-8' + if (!enc) return enc + const p = enc.slice(0, 3) + if (p === 'utf' || p === 'iso' || p === 'koi' || p === 'euc' || p === 'ibm' || p === 'gbk') { + return enc.toUpperCase() + } + + if (enc === 'big5') return 'Big5' + if (enc === 'shift_jis') return 'Shift_JIS' + return enc +} diff --git a/vanilla/node_modules/@exodus/bytes/encoding-browser.d.ts b/vanilla/node_modules/@exodus/bytes/encoding-browser.d.ts new file mode 100644 index 0000000..565b43b --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/encoding-browser.d.ts @@ -0,0 +1,24 @@ +/** + * Same as `@exodus/bytes/encoding.js`, but in browsers instead of polyfilling just uses whatever the + * browser provides, drastically reducing the bundle size (to less than 2 KiB gzipped). + * + * ```js + * import { TextDecoder, TextEncoder } from '@exodus/bytes/encoding-browser.js' + * import { TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding-browser.js' // Requires Streams + * + * // Hooks for standards + * import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding-browser.js' + * ``` + * + * Under non-browser engines (Node.js, React Native, etc.) a full polyfill is used as those platforms + * do not provide sufficiently complete / non-buggy `TextDecoder` APIs. + * + * > [!NOTE] + * > Implementations in browsers [have bugs](https://docs.google.com/spreadsheets/d/1pdEefRG6r9fZy61WHGz0TKSt8cO4ISWqlpBN5KntIvQ/edit), + * > but they are fixing them and the expected update window is short.\ + * > If you want to circumvent browser bugs, use full `@exodus/bytes/encoding.js` import. + * + * @module @exodus/bytes/encoding-browser.js + */ + +export * from './encoding.js' diff --git a/vanilla/node_modules/@exodus/bytes/encoding-browser.js b/vanilla/node_modules/@exodus/bytes/encoding-browser.js new file mode 100644 index 0000000..47c1090 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/encoding-browser.js @@ -0,0 +1 @@ +export * from './encoding.js' diff --git a/vanilla/node_modules/@exodus/bytes/encoding-browser.native.js b/vanilla/node_modules/@exodus/bytes/encoding-browser.native.js new file mode 100644 index 0000000..47c1090 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/encoding-browser.native.js @@ -0,0 +1 @@ +export * from './encoding.js' diff --git a/vanilla/node_modules/@exodus/bytes/encoding-lite.d.ts b/vanilla/node_modules/@exodus/bytes/encoding-lite.d.ts new file mode 100644 index 0000000..8a6550d --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/encoding-lite.d.ts @@ -0,0 +1,62 @@ +/** + * The exact same exports as `@exodus/bytes/encoding.js` are also exported as + * `@exodus/bytes/encoding-lite.js`, with the difference that the lite version does not load + * multi-byte `TextDecoder` encodings by default to reduce bundle size 10x. + * + * ```js + * import { TextDecoder, TextEncoder } from '@exodus/bytes/encoding-lite.js' + * import { TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding-lite.js' // Requires Streams + * + * // Hooks for standards + * import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding-lite.js' + * ``` + * + * The only affected encodings are: `gbk`, `gb18030`, `big5`, `euc-jp`, `iso-2022-jp`, `shift_jis` + * and their [labels](https://encoding.spec.whatwg.org/#names-and-labels) when used with `TextDecoder`. + * + * Legacy single-byte encodingds are loaded by default in both cases. + * + * `TextEncoder` and hooks for standards (including `labelToName` / `normalizeEncoding`) do not have any behavior + * differences in the lite version and support full range if inputs. + * + * To avoid inconsistencies, the exported classes and methods are exactly the same objects. + * + * ```console + * > lite = require('@exodus/bytes/encoding-lite.js') + * [Module: null prototype] { + * TextDecoder: [class TextDecoder], + * TextDecoderStream: [class TextDecoderStream], + * TextEncoder: [class TextEncoder], + * TextEncoderStream: [class TextEncoderStream], + * getBOMEncoding: [Function: getBOMEncoding], + * labelToName: [Function: labelToName], + * legacyHookDecode: [Function: legacyHookDecode], + * normalizeEncoding: [Function: normalizeEncoding] + * } + * > new lite.TextDecoder('big5').decode(Uint8Array.of(0x25)) + * Uncaught: + * Error: Legacy multi-byte encodings are disabled in /encoding-lite.js, use /encoding.js for full encodings range support + * + * > full = require('@exodus/bytes/encoding.js') + * [Module: null prototype] { + * TextDecoder: [class TextDecoder], + * TextDecoderStream: [class TextDecoderStream], + * TextEncoder: [class TextEncoder], + * TextEncoderStream: [class TextEncoderStream], + * getBOMEncoding: [Function: getBOMEncoding], + * labelToName: [Function: labelToName], + * legacyHookDecode: [Function: legacyHookDecode], + * normalizeEncoding: [Function: normalizeEncoding] + * } + * > full.TextDecoder === lite.TextDecoder + * true + * > new full.TextDecoder('big5').decode(Uint8Array.of(0x25)) + * '%' + * > new lite.TextDecoder('big5').decode(Uint8Array.of(0x25)) + * '%' + * ``` + * + * @module @exodus/bytes/encoding-lite.js + */ + +export * from './encoding.js' diff --git a/vanilla/node_modules/@exodus/bytes/encoding-lite.js b/vanilla/node_modules/@exodus/bytes/encoding-lite.js new file mode 100644 index 0000000..9f8738e --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/encoding-lite.js @@ -0,0 +1,10 @@ +export { + TextDecoder, + TextEncoder, + TextDecoderStream, + TextEncoderStream, + normalizeEncoding, + getBOMEncoding, + labelToName, + legacyHookDecode, +} from './fallback/encoding.js' diff --git a/vanilla/node_modules/@exodus/bytes/encoding.d.ts b/vanilla/node_modules/@exodus/bytes/encoding.d.ts new file mode 100644 index 0000000..7e59b73 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/encoding.d.ts @@ -0,0 +1,140 @@ +/** + * Implements the [Encoding standard](https://encoding.spec.whatwg.org/): + * [TextDecoder](https://encoding.spec.whatwg.org/#interface-textdecoder), + * [TextEncoder](https://encoding.spec.whatwg.org/#interface-textencoder), + * [TextDecoderStream](https://encoding.spec.whatwg.org/#interface-textdecoderstream), + * [TextEncoderStream](https://encoding.spec.whatwg.org/#interface-textencoderstream), + * some [hooks](https://encoding.spec.whatwg.org/#specification-hooks). + * + * ```js + * import { TextDecoder, TextEncoder } from '@exodus/bytes/encoding.js' + * import { TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding.js' // Requires Streams + * + * // Hooks for standards + * import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding.js' + * ``` + * + * @module @exodus/bytes/encoding.js + */ + +/// <reference types="node" /> + +/** + * Convert an encoding [label](https://encoding.spec.whatwg.org/#names-and-labels) to its name, + * as an ASCII-lowercased string. + * + * If an encoding with that label does not exist, returns `null`. + * + * This is the same as [`decoder.encoding` getter](https://encoding.spec.whatwg.org/#dom-textdecoder-encoding), + * except that it: + * 1. Supports [`replacement` encoding](https://encoding.spec.whatwg.org/#replacement) and its + * [labels](https://encoding.spec.whatwg.org/#ref-for-replacement%E2%91%A1) + * 2. Does not throw for invalid labels and instead returns `null` + * + * It is identical to: + * ```js + * labelToName(label)?.toLowerCase() ?? null + * ``` + * + * All encoding names are also valid labels for corresponding encodings. + * + * @param label - The encoding label to normalize + * @returns The normalized encoding name, or null if invalid + */ +export function normalizeEncoding(label: string): string | null; + +/** + * Implements [BOM sniff](https://encoding.spec.whatwg.org/#bom-sniff) legacy hook. + * + * Given a `TypedArray` or an `ArrayBuffer` instance `input`, returns either of: + * - `'utf-8'`, if `input` starts with UTF-8 byte order mark. + * - `'utf-16le'`, if `input` starts with UTF-16LE byte order mark. + * - `'utf-16be'`, if `input` starts with UTF-16BE byte order mark. + * - `null` otherwise. + * + * @param input - The bytes to check for BOM + * @returns The encoding ('utf-8', 'utf-16le', 'utf-16be'), or null if no BOM found + */ +export function getBOMEncoding( + input: ArrayBufferLike | ArrayBufferView +): 'utf-8' | 'utf-16le' | 'utf-16be' | null; + +/** + * Implements [decode](https://encoding.spec.whatwg.org/#decode) legacy hook. + * + * Given a `TypedArray` or an `ArrayBuffer` instance `input` and an optional `fallbackEncoding` + * encoding [label](https://encoding.spec.whatwg.org/#names-and-labels), + * sniffs encoding from BOM with `fallbackEncoding` fallback and then + * decodes the `input` using that encoding, skipping BOM if it was present. + * + * Notes: + * + * - BOM-sniffed encoding takes precedence over `fallbackEncoding` option per spec. + * Use with care. + * - Always operates in non-fatal [mode](https://encoding.spec.whatwg.org/#textdecoder-error-mode), + * aka replacement. It can convert different byte sequences to equal strings. + * + * This method is similar to the following code, except that it doesn't support encoding labels and + * only expects lowercased encoding name: + * + * ```js + * new TextDecoder(getBOMEncoding(input) ?? fallbackEncoding).decode(input) + * ``` + * + * @param input - The bytes to decode + * @param fallbackEncoding - The encoding to use if no BOM detected (default: 'utf-8') + * @returns The decoded string + */ +export function legacyHookDecode( + input: ArrayBufferLike | ArrayBufferView, + fallbackEncoding?: string +): string; + +/** + * Implements [get an encoding from a string `label`](https://encoding.spec.whatwg.org/#concept-encoding-get). + * + * Convert an encoding [label](https://encoding.spec.whatwg.org/#names-and-labels) to its name, + * as a case-sensitive string. + * + * If an encoding with that label does not exist, returns `null`. + * + * All encoding names are also valid labels for corresponding encodings. + * + * @param label - The encoding label + * @returns The proper case encoding name, or null if invalid + */ +export function labelToName(label: string): string | null; + +/** + * [TextDecoder](https://encoding.spec.whatwg.org/#interface-textdecoder) implementation/polyfill. + * + * Decode bytes to strings according to [WHATWG Encoding](https://encoding.spec.whatwg.org) specification. + */ +export const TextDecoder: typeof globalThis.TextDecoder; + +/** + * [TextEncoder](https://encoding.spec.whatwg.org/#interface-textencoder) implementation/polyfill. + * + * Encode strings to UTF-8 bytes according to [WHATWG Encoding](https://encoding.spec.whatwg.org) specification. + */ +export const TextEncoder: typeof globalThis.TextEncoder; + +/** + * [TextDecoderStream](https://encoding.spec.whatwg.org/#interface-textdecoderstream) implementation/polyfill. + * + * A [Streams](https://streams.spec.whatwg.org/) wrapper for `TextDecoder`. + * + * Requires [Streams](https://streams.spec.whatwg.org/) to be either supported by the platform or + * [polyfilled](https://npmjs.com/package/web-streams-polyfill). + */ +export const TextDecoderStream: typeof globalThis.TextDecoderStream; + +/** + * [TextEncoderStream](https://encoding.spec.whatwg.org/#interface-textencoderstream) implementation/polyfill. + * + * A [Streams](https://streams.spec.whatwg.org/) wrapper for `TextEncoder`. + * + * Requires [Streams](https://streams.spec.whatwg.org/) to be either supported by the platform or + * [polyfilled](https://npmjs.com/package/web-streams-polyfill). + */ +export const TextEncoderStream: typeof globalThis.TextEncoderStream; diff --git a/vanilla/node_modules/@exodus/bytes/encoding.js b/vanilla/node_modules/@exodus/bytes/encoding.js new file mode 100644 index 0000000..3703d71 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/encoding.js @@ -0,0 +1,16 @@ +import { createMultibyteDecoder } from '@exodus/bytes/multi-byte.js' +import { multibyteEncoder } from './fallback/multi-byte.js' +import { setMultibyte } from './fallback/encoding.js' + +setMultibyte(createMultibyteDecoder, multibyteEncoder) + +export { + TextDecoder, + TextEncoder, + TextDecoderStream, + TextEncoderStream, + normalizeEncoding, + getBOMEncoding, + labelToName, + legacyHookDecode, +} from './fallback/encoding.js' diff --git a/vanilla/node_modules/@exodus/bytes/fallback/_utils.js b/vanilla/node_modules/@exodus/bytes/fallback/_utils.js new file mode 100644 index 0000000..4783abd --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/_utils.js @@ -0,0 +1,20 @@ +export * from './platform.js' + +const Buffer = /* @__PURE__ */ (() => globalThis.Buffer)() + +export function assert(condition, msg) { + if (!condition) throw new Error(msg) +} + +export function assertU8(arg) { + if (!(arg instanceof Uint8Array)) throw new TypeError('Expected an Uint8Array') +} + +// On arrays in heap (<= 64) it's cheaper to copy into a pooled buffer than lazy-create the ArrayBuffer storage +export const toBuf = (x) => + x.byteLength <= 64 && x.BYTES_PER_ELEMENT === 1 + ? Buffer.from(x) + : Buffer.from(x.buffer, x.byteOffset, x.byteLength) + +export const E_STRING = 'Input is not a string' +export const E_STRICT_UNICODE = 'Input is not well-formed Unicode' diff --git a/vanilla/node_modules/@exodus/bytes/fallback/base32.js b/vanilla/node_modules/@exodus/bytes/fallback/base32.js new file mode 100644 index 0000000..5488b4b --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/base32.js @@ -0,0 +1,233 @@ +import { assertU8 } from './_utils.js' +import { nativeEncoder, nativeDecoder, isHermes } from './platform.js' +import { encodeAscii, decodeAscii } from './latin1.js' + +// See https://datatracker.ietf.org/doc/html/rfc4648 + +const BASE32 = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'] // RFC 4648, #6 +const BASE32HEX = [...'0123456789ABCDEFGHIJKLMNOPQRSTUV'] // RFC 4648, #7 +const BASE32_HELPERS = {} +const BASE32HEX_HELPERS = {} + +export const E_CHAR = 'Invalid character in base32 input' +export const E_PADDING = 'Invalid base32 padding' +export const E_LENGTH = 'Invalid base32 length' +export const E_LAST = 'Invalid last chunk' + +const useTemplates = isHermes // Faster on Hermes and JSC, but we use it only on Hermes + +// We construct output by concatenating chars, this seems to be fine enough on modern JS engines +export function toBase32(arr, isBase32Hex, padding) { + assertU8(arr) + const fullChunks = Math.floor(arr.length / 5) + const fullChunksBytes = fullChunks * 5 + let o = '' + let i = 0 + + const alphabet = isBase32Hex ? BASE32HEX : BASE32 + const helpers = isBase32Hex ? BASE32HEX_HELPERS : BASE32_HELPERS + if (!helpers.pairs) { + helpers.pairs = [] + if (nativeDecoder) { + // Lazy to save memory in case if this is not needed + helpers.codepairs = new Uint16Array(32 * 32) + const u16 = helpers.codepairs + const u8 = new Uint8Array(u16.buffer, u16.byteOffset, u16.byteLength) // write as 1-byte to ignore BE/LE difference + for (let i = 0; i < 32; i++) { + const ic = alphabet[i].charCodeAt(0) + for (let j = 0; j < 32; j++) u8[(i << 6) | (j << 1)] = u8[(j << 6) | ((i << 1) + 1)] = ic + } + } else { + const p = helpers.pairs + for (let i = 0; i < 32; i++) { + for (let j = 0; j < 32; j++) p.push(`${alphabet[i]}${alphabet[j]}`) + } + } + } + + const { pairs, codepairs } = helpers + + // Fast path for complete blocks + // This whole loop can be commented out, the algorithm won't change, it's just an optimization of the next loop + if (nativeDecoder) { + const oa = new Uint16Array(fullChunks * 4) + for (let j = 0; i < fullChunksBytes; i += 5) { + const a = arr[i] + const b = arr[i + 1] + const c = arr[i + 2] + const d = arr[i + 3] + const e = arr[i + 4] + const x0 = (a << 2) | (b >> 6) // 8 + 8 - 5 - 5 = 6 left + const x1 = ((b & 0x3f) << 4) | (c >> 4) // 6 + 8 - 5 - 5 = 4 left + const x2 = ((c & 0xf) << 6) | (d >> 2) // 4 + 8 - 5 - 5 = 2 left + const x3 = ((d & 0x3) << 8) | e // 2 + 8 - 5 - 5 = 0 left + oa[j] = codepairs[x0] + oa[j + 1] = codepairs[x1] + oa[j + 2] = codepairs[x2] + oa[j + 3] = codepairs[x3] + j += 4 + } + + o = decodeAscii(oa) + } else if (useTemplates) { + // Templates are faster only on Hermes and JSC. Browsers have TextDecoder anyway + for (; i < fullChunksBytes; i += 5) { + const a = arr[i] + const b = arr[i + 1] + const c = arr[i + 2] + const d = arr[i + 3] + const e = arr[i + 4] + const x0 = (a << 2) | (b >> 6) // 8 + 8 - 5 - 5 = 6 left + const x1 = ((b & 0x3f) << 4) | (c >> 4) // 6 + 8 - 5 - 5 = 4 left + const x2 = ((c & 0xf) << 6) | (d >> 2) // 4 + 8 - 5 - 5 = 2 left + const x3 = ((d & 0x3) << 8) | e // 2 + 8 - 5 - 5 = 0 left + o += `${pairs[x0]}${pairs[x1]}${pairs[x2]}${pairs[x3]}` + } + } else { + for (; i < fullChunksBytes; i += 5) { + const a = arr[i] + const b = arr[i + 1] + const c = arr[i + 2] + const d = arr[i + 3] + const e = arr[i + 4] + const x0 = (a << 2) | (b >> 6) // 8 + 8 - 5 - 5 = 6 left + const x1 = ((b & 0x3f) << 4) | (c >> 4) // 6 + 8 - 5 - 5 = 4 left + const x2 = ((c & 0xf) << 6) | (d >> 2) // 4 + 8 - 5 - 5 = 2 left + const x3 = ((d & 0x3) << 8) | e // 2 + 8 - 5 - 5 = 0 left + o += pairs[x0] + o += pairs[x1] + o += pairs[x2] + o += pairs[x3] + } + } + + // If we have something left, process it with a full algo + let carry = 0 + let shift = 3 // First byte needs to be shifted by 3 to get 5 bits + for (; i < arr.length; i++) { + const x = arr[i] + o += alphabet[carry | (x >> shift)] // shift >= 3, so this fits + if (shift >= 5) { + shift -= 5 + o += alphabet[(x >> shift) & 0x1f] + } + + carry = (x << (5 - shift)) & 0x1f + shift += 3 // Each byte prints 5 bits and leaves 3 bits + } + + if (shift !== 3) o += alphabet[carry] // shift 3 means we have no carry left + if (padding) o += ['', '======', '====', '===', '='][arr.length - fullChunksBytes] + + return o +} + +// TODO: can this be optimized? This only affects non-Hermes barebone engines though +const mapSize = nativeEncoder ? 128 : 65_536 // we have to store 64 KiB map or recheck everything if we can't decode to byte array + +export function fromBase32(str, isBase32Hex) { + let inputLength = str.length + while (str[inputLength - 1] === '=') inputLength-- + const paddingLength = str.length - inputLength + const tailLength = inputLength % 8 + const mainLength = inputLength - tailLength // multiples of 8 + if (![0, 2, 4, 5, 7].includes(tailLength)) throw new SyntaxError(E_LENGTH) // fast verification + if (paddingLength > 7 || (paddingLength !== 0 && str.length % 8 !== 0)) { + throw new SyntaxError(E_PADDING) + } + + const alphabet = isBase32Hex ? BASE32HEX : BASE32 + const helpers = isBase32Hex ? BASE32HEX_HELPERS : BASE32_HELPERS + + if (!helpers.fromMap) { + helpers.fromMap = new Int8Array(mapSize).fill(-1) // no regex input validation here, so we map all other bytes to -1 and recheck sign + alphabet.forEach((c, i) => { + helpers.fromMap[c.charCodeAt(0)] = helpers.fromMap[c.toLowerCase().charCodeAt(0)] = i + }) + } + + const m = helpers.fromMap + + const arr = new Uint8Array(Math.floor((inputLength * 5) / 8)) + let at = 0 + let i = 0 + + if (nativeEncoder) { + const codes = encodeAscii(str, E_CHAR) + for (; i < mainLength; i += 8) { + // each 5 bits, grouped 5 * 4 = 20 + const x0 = codes[i] + const x1 = codes[i + 1] + const x2 = codes[i + 2] + const x3 = codes[i + 3] + const x4 = codes[i + 4] + const x5 = codes[i + 5] + const x6 = codes[i + 6] + const x7 = codes[i + 7] + const a = (m[x0] << 15) | (m[x1] << 10) | (m[x2] << 5) | m[x3] + const b = (m[x4] << 15) | (m[x5] << 10) | (m[x6] << 5) | m[x7] + if (a < 0 || b < 0) throw new SyntaxError(E_CHAR) + arr[at] = a >> 12 + arr[at + 1] = (a >> 4) & 0xff + arr[at + 2] = ((a << 4) & 0xff) | (b >> 16) + arr[at + 3] = (b >> 8) & 0xff + arr[at + 4] = b & 0xff + at += 5 + } + } else { + for (; i < mainLength; i += 8) { + // each 5 bits, grouped 5 * 4 = 20 + const x0 = str.charCodeAt(i) + const x1 = str.charCodeAt(i + 1) + const x2 = str.charCodeAt(i + 2) + const x3 = str.charCodeAt(i + 3) + const x4 = str.charCodeAt(i + 4) + const x5 = str.charCodeAt(i + 5) + const x6 = str.charCodeAt(i + 6) + const x7 = str.charCodeAt(i + 7) + const a = (m[x0] << 15) | (m[x1] << 10) | (m[x2] << 5) | m[x3] + const b = (m[x4] << 15) | (m[x5] << 10) | (m[x6] << 5) | m[x7] + if (a < 0 || b < 0) throw new SyntaxError(E_CHAR) + arr[at] = a >> 12 + arr[at + 1] = (a >> 4) & 0xff + arr[at + 2] = ((a << 4) & 0xff) | (b >> 16) + arr[at + 3] = (b >> 8) & 0xff + arr[at + 4] = b & 0xff + at += 5 + } + } + + // Last block, valid tailLength: 0 2 4 5 7, checked already + // We check last chunk to be strict + if (tailLength < 2) return arr + const ab = (m[str.charCodeAt(i++)] << 5) | m[str.charCodeAt(i++)] + if (ab < 0) throw new SyntaxError(E_CHAR) + arr[at++] = ab >> 2 + if (tailLength < 4) { + if (ab & 0x3) throw new SyntaxError(E_LAST) + return arr + } + + const cd = (m[str.charCodeAt(i++)] << 5) | m[str.charCodeAt(i++)] + if (cd < 0) throw new SyntaxError(E_CHAR) + arr[at++] = ((ab << 6) & 0xff) | (cd >> 4) + if (tailLength < 5) { + if (cd & 0xf) throw new SyntaxError(E_LAST) + return arr + } + + const e = m[str.charCodeAt(i++)] + if (e < 0) throw new SyntaxError(E_CHAR) + arr[at++] = ((cd << 4) & 0xff) | (e >> 1) // 4 + 4 + if (tailLength < 7) { + if (e & 0x1) throw new SyntaxError(E_LAST) + return arr + } + + const fg = (m[str.charCodeAt(i++)] << 5) | m[str.charCodeAt(i++)] + if (fg < 0) throw new SyntaxError(E_CHAR) + arr[at++] = ((e << 7) & 0xff) | (fg >> 3) // 1 + 5 + 2 + // Can't be 8, so no h + if (fg & 0x7) throw new SyntaxError(E_LAST) + return arr +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/base58check.js b/vanilla/node_modules/@exodus/bytes/fallback/base58check.js new file mode 100644 index 0000000..f4ec8cc --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/base58check.js @@ -0,0 +1,53 @@ +import { typedView } from '@exodus/bytes/array.js' +import { toBase58, fromBase58 } from '@exodus/bytes/base58.js' +import { assertU8 } from './_utils.js' + +const E_CHECKSUM = 'Invalid checksum' + +// checksum length is 4, i.e. only the first 4 bytes of the hash are used + +function encodeWithChecksum(arr, checksum) { + // arr type in already validated in input + const res = new Uint8Array(arr.length + 4) + res.set(arr, 0) + res.set(checksum.subarray(0, 4), arr.length) + return toBase58(res) +} + +function decodeWithChecksum(str) { + const arr = fromBase58(str) // checks input + const payloadSize = arr.length - 4 + if (payloadSize < 0) throw new Error(E_CHECKSUM) + return [arr.subarray(0, payloadSize), arr.subarray(payloadSize)] +} + +function assertChecksum(c, r) { + if ((c[0] ^ r[0]) | (c[1] ^ r[1]) | (c[2] ^ r[2]) | (c[3] ^ r[3])) throw new Error(E_CHECKSUM) +} + +export const makeBase58check = (hashAlgo, hashAlgoSync) => { + const apis = { + async encode(arr) { + assertU8(arr) + return encodeWithChecksum(arr, await hashAlgo(arr)) + }, + async decode(str, format = 'uint8') { + const [payload, checksum] = decodeWithChecksum(str) + assertChecksum(checksum, await hashAlgo(payload)) + return typedView(payload, format) + }, + } + if (!hashAlgoSync) return apis + return { + ...apis, + encodeSync(arr) { + assertU8(arr) + return encodeWithChecksum(arr, hashAlgoSync(arr)) + }, + decodeSync(str, format = 'uint8') { + const [payload, checksum] = decodeWithChecksum(str) + assertChecksum(checksum, hashAlgoSync(payload)) + return typedView(payload, format) + }, + } +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/base64.js b/vanilla/node_modules/@exodus/bytes/fallback/base64.js new file mode 100644 index 0000000..02e4ec8 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/base64.js @@ -0,0 +1,191 @@ +import { nativeEncoder, nativeDecoder } from './platform.js' +import { encodeAscii, decodeAscii } from './latin1.js' + +// See https://datatracker.ietf.org/doc/html/rfc4648 + +const BASE64 = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'] +const BASE64URL = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'] +const BASE64_HELPERS = {} +const BASE64URL_HELPERS = {} + +export const E_CHAR = 'Invalid character in base64 input' +export const E_PADDING = 'Invalid base64 padding' +export const E_LENGTH = 'Invalid base64 length' +export const E_LAST = 'Invalid last chunk' + +// We construct output by concatenating chars, this seems to be fine enough on modern JS engines +// Expects a checked Uint8Array +export function toBase64(arr, isURL, padding) { + const fullChunks = (arr.length / 3) | 0 + const fullChunksBytes = fullChunks * 3 + let o = '' + let i = 0 + + const alphabet = isURL ? BASE64URL : BASE64 + const helpers = isURL ? BASE64URL_HELPERS : BASE64_HELPERS + if (!helpers.pairs) { + helpers.pairs = [] + if (nativeDecoder) { + // Lazy to save memory in case if this is not needed + helpers.codepairs = new Uint16Array(64 * 64) + const u16 = helpers.codepairs + const u8 = new Uint8Array(u16.buffer, u16.byteOffset, u16.byteLength) // write as 1-byte to ignore BE/LE difference + for (let i = 0; i < 64; i++) { + const ic = alphabet[i].charCodeAt(0) + for (let j = 0; j < 64; j++) u8[(i << 7) | (j << 1)] = u8[(j << 7) | ((i << 1) + 1)] = ic + } + } else { + const p = helpers.pairs + for (let i = 0; i < 64; i++) { + for (let j = 0; j < 64; j++) p.push(`${alphabet[i]}${alphabet[j]}`) + } + } + } + + const { pairs, codepairs } = helpers + + // Fast path for complete blocks + // This whole loop can be commented out, the algorithm won't change, it's just an optimization of the next loop + if (nativeDecoder) { + const oa = new Uint16Array(fullChunks * 2) + let j = 0 + for (const last = arr.length - 11; i < last; i += 12, j += 8) { + const x0 = arr[i] + const x1 = arr[i + 1] + const x2 = arr[i + 2] + const x3 = arr[i + 3] + const x4 = arr[i + 4] + const x5 = arr[i + 5] + const x6 = arr[i + 6] + const x7 = arr[i + 7] + const x8 = arr[i + 8] + const x9 = arr[i + 9] + const x10 = arr[i + 10] + const x11 = arr[i + 11] + oa[j] = codepairs[(x0 << 4) | (x1 >> 4)] + oa[j + 1] = codepairs[((x1 & 0x0f) << 8) | x2] + oa[j + 2] = codepairs[(x3 << 4) | (x4 >> 4)] + oa[j + 3] = codepairs[((x4 & 0x0f) << 8) | x5] + oa[j + 4] = codepairs[(x6 << 4) | (x7 >> 4)] + oa[j + 5] = codepairs[((x7 & 0x0f) << 8) | x8] + oa[j + 6] = codepairs[(x9 << 4) | (x10 >> 4)] + oa[j + 7] = codepairs[((x10 & 0x0f) << 8) | x11] + } + + // i < last here is equivalent to i < fullChunksBytes + for (const last = arr.length - 2; i < last; i += 3, j += 2) { + const a = arr[i] + const b = arr[i + 1] + const c = arr[i + 2] + oa[j] = codepairs[(a << 4) | (b >> 4)] + oa[j + 1] = codepairs[((b & 0x0f) << 8) | c] + } + + o = decodeAscii(oa) + } else { + // This can be optimized by ~25% with templates on Hermes, but this codepath is not called on Hermes, it uses btoa + // Check git history for templates version + for (; i < fullChunksBytes; i += 3) { + const a = arr[i] + const b = arr[i + 1] + const c = arr[i + 2] + o += pairs[(a << 4) | (b >> 4)] + o += pairs[((b & 0x0f) << 8) | c] + } + } + + // If we have something left, process it with a full algo + let carry = 0 + let shift = 2 // First byte needs to be shifted by 2 to get 6 bits + const length = arr.length + for (; i < length; i++) { + const x = arr[i] + o += alphabet[carry | (x >> shift)] // shift >= 2, so this fits + if (shift === 6) { + shift = 0 + o += alphabet[x & 0x3f] + } + + carry = (x << (6 - shift)) & 0x3f + shift += 2 // Each byte prints 6 bits and leaves 2 bits + } + + if (shift !== 2) o += alphabet[carry] // shift 2 means we have no carry left + if (padding) o += ['', '==', '='][length - fullChunksBytes] + + return o +} + +// TODO: can this be optimized? This only affects non-Hermes barebone engines though +const mapSize = nativeEncoder ? 128 : 65_536 // we have to store 64 KiB map or recheck everything if we can't decode to byte array + +export function fromBase64(str, isURL) { + let inputLength = str.length + while (str[inputLength - 1] === '=') inputLength-- + const paddingLength = str.length - inputLength + const tailLength = inputLength % 4 + const mainLength = inputLength - tailLength // multiples of 4 + if (tailLength === 1) throw new SyntaxError(E_LENGTH) + if (paddingLength > 3 || (paddingLength !== 0 && str.length % 4 !== 0)) { + throw new SyntaxError(E_PADDING) + } + + const alphabet = isURL ? BASE64URL : BASE64 + const helpers = isURL ? BASE64URL_HELPERS : BASE64_HELPERS + + if (!helpers.fromMap) { + helpers.fromMap = new Int8Array(mapSize).fill(-1) // no regex input validation here, so we map all other bytes to -1 and recheck sign + alphabet.forEach((c, i) => (helpers.fromMap[c.charCodeAt(0)] = i)) + } + + const m = helpers.fromMap + + const arr = new Uint8Array(Math.floor((inputLength * 3) / 4)) + let at = 0 + let i = 0 + + if (nativeEncoder) { + const codes = encodeAscii(str, E_CHAR) + for (; i < mainLength; i += 4) { + const c0 = codes[i] + const c1 = codes[i + 1] + const c2 = codes[i + 2] + const c3 = codes[i + 3] + const a = (m[c0] << 18) | (m[c1] << 12) | (m[c2] << 6) | m[c3] + if (a < 0) throw new SyntaxError(E_CHAR) + arr[at] = a >> 16 + arr[at + 1] = (a >> 8) & 0xff + arr[at + 2] = a & 0xff + at += 3 + } + } else { + for (; i < mainLength; i += 4) { + const c0 = str.charCodeAt(i) + const c1 = str.charCodeAt(i + 1) + const c2 = str.charCodeAt(i + 2) + const c3 = str.charCodeAt(i + 3) + const a = (m[c0] << 18) | (m[c1] << 12) | (m[c2] << 6) | m[c3] + if (a < 0) throw new SyntaxError(E_CHAR) + arr[at] = a >> 16 + arr[at + 1] = (a >> 8) & 0xff + arr[at + 2] = a & 0xff + at += 3 + } + } + + // Can be 0, 2 or 3, verified by padding checks already + if (tailLength < 2) return arr // 0 + const ab = (m[str.charCodeAt(i++)] << 6) | m[str.charCodeAt(i++)] + if (ab < 0) throw new SyntaxError(E_CHAR) + arr[at++] = ab >> 4 + if (tailLength < 3) { + if (ab & 0xf) throw new SyntaxError(E_LAST) + return arr // 2 + } + + const c = m[str.charCodeAt(i++)] + if (c < 0) throw new SyntaxError(E_CHAR) + arr[at++] = ((ab << 4) & 0xff) | (c >> 2) + if (c & 0x3) throw new SyntaxError(E_LAST) + return arr // 3 +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/encoding.api.js b/vanilla/node_modules/@exodus/bytes/fallback/encoding.api.js new file mode 100644 index 0000000..8dc5243 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/encoding.api.js @@ -0,0 +1,38 @@ +// TODO: make this more strict against Symbol.toStringTag +// Is not very significant though, anything faking Symbol.toStringTag could as well override +// prototypes, which is not something we protect against + +function isAnyArrayBuffer(x) { + if (x instanceof ArrayBuffer) return true + if (globalThis.SharedArrayBuffer && x instanceof SharedArrayBuffer) return true + if (!x || typeof x.byteLength !== 'number') return false + const s = Object.prototype.toString.call(x) + return s === '[object ArrayBuffer]' || s === '[object SharedArrayBuffer]' +} + +export function fromSource(x) { + if (x instanceof Uint8Array) return x + if (ArrayBuffer.isView(x)) return new Uint8Array(x.buffer, x.byteOffset, x.byteLength) + if (isAnyArrayBuffer(x)) { + if ('detached' in x) return x.detached === true ? new Uint8Array() : new Uint8Array(x) + // Old engines without .detached, try-catch + try { + return new Uint8Array(x) + } catch { + return new Uint8Array() + } + } + + throw new TypeError('Argument must be a SharedArrayBuffer, ArrayBuffer or ArrayBufferView') +} + +// Warning: unlike whatwg-encoding, returns lowercased labels +// Those are case-insensitive and that's how TextDecoder encoding getter normalizes them +export function getBOMEncoding(input) { + const u8 = fromSource(input) // asserts + if (u8.length >= 3 && u8[0] === 0xef && u8[1] === 0xbb && u8[2] === 0xbf) return 'utf-8' + if (u8.length < 2) return null + if (u8[0] === 0xff && u8[1] === 0xfe) return 'utf-16le' + if (u8[0] === 0xfe && u8[1] === 0xff) return 'utf-16be' + return null +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/encoding.js b/vanilla/node_modules/@exodus/bytes/fallback/encoding.js new file mode 100644 index 0000000..fab1080 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/encoding.js @@ -0,0 +1,359 @@ +// We can't return native TextDecoder if it's present, as Node.js one is broken on windows-1252 and we fix that +// We are also faster than Node.js built-in on both TextEncoder and TextDecoder + +import { utf16toString, utf16toStringLoose } from '@exodus/bytes/utf16.js' +import { utf8fromStringLoose, utf8toString, utf8toStringLoose } from '@exodus/bytes/utf8.js' +import { createSinglebyteDecoder } from '@exodus/bytes/single-byte.js' +import labels from './encoding.labels.js' +import { fromSource, getBOMEncoding } from './encoding.api.js' +import { unfinishedBytes, mergePrefix } from './encoding.util.js' + +export { getBOMEncoding } from './encoding.api.js' + +export const E_ENCODING = 'Unknown encoding' +const E_MULTI = "import '@exodus/bytes/encoding.js' for legacy multi-byte encodings support" +const E_OPTIONS = 'The "options" argument must be of type object' +const replacementChar = '\uFFFD' +const multibyteSet = new Set(['big5', 'euc-kr', 'euc-jp', 'iso-2022-jp', 'shift_jis', 'gbk', 'gb18030']) // prettier-ignore +let createMultibyteDecoder, multibyteEncoder + +let labelsMap +// Warning: unlike whatwg-encoding, returns lowercased labels +// Those are case-insensitive and that's how TextDecoder encoding getter normalizes them +// https://encoding.spec.whatwg.org/#names-and-labels +export function normalizeEncoding(label) { + // fast path + if (label === 'utf-8' || label === 'utf8' || label === 'UTF-8' || label === 'UTF8') return 'utf-8' + if (label === 'windows-1252' || label === 'ascii' || label === 'latin1') return 'windows-1252' + // full map + if (/[^\w\t\n\f\r .:-]/i.test(label)) return null // must be ASCII (with ASCII whitespace) + const low = `${label}`.trim().toLowerCase() + if (Object.hasOwn(labels, low)) return low + if (!labelsMap) { + labelsMap = new Map() + for (const [name, aliases] of Object.entries(labels)) { + for (const alias of aliases) labelsMap.set(alias, name) + } + } + + const mapped = labelsMap.get(low) + if (mapped) return mapped + return null +} + +const uppercasePrefixes = new Set(['utf', 'iso', 'koi', 'euc', 'ibm', 'gbk']) + +// Unlike normalizeEncoding, case-sensitive +// https://encoding.spec.whatwg.org/#names-and-labels +export function labelToName(label) { + const enc = normalizeEncoding(label) + if (enc === 'utf-8') return 'UTF-8' // fast path + if (!enc) return enc + if (uppercasePrefixes.has(enc.slice(0, 3))) return enc.toUpperCase() + if (enc === 'big5') return 'Big5' + if (enc === 'shift_jis') return 'Shift_JIS' + return enc +} + +export const isMultibyte = (enc) => multibyteSet.has(enc) +export function setMultibyte(createDecoder, createEncoder) { + createMultibyteDecoder = createDecoder + multibyteEncoder = createEncoder +} + +export function getMultibyteEncoder() { + if (!multibyteEncoder) throw new Error(E_MULTI) + return multibyteEncoder +} + +const define = (obj, key, value) => Object.defineProperty(obj, key, { value, writable: false }) + +function isAnyUint8Array(x) { + if (x instanceof Uint8Array) return true + if (!x || !ArrayBuffer.isView(x) || x.BYTES_PER_ELEMENT !== 1) return false + return Object.prototype.toString.call(x) === '[object Uint8Array]' +} + +function unicodeDecoder(encoding, loose) { + if (encoding === 'utf-8') return loose ? utf8toStringLoose : utf8toString // likely + const form = encoding === 'utf-16le' ? 'uint8-le' : 'uint8-be' + return loose ? (u) => utf16toStringLoose(u, form) : (u) => utf16toString(u, form) +} + +export class TextDecoder { + #decode + #unicode + #multibyte + #chunk + #canBOM + + constructor(encoding = 'utf-8', options = {}) { + if (typeof options !== 'object') throw new TypeError(E_OPTIONS) + const enc = normalizeEncoding(encoding) + if (!enc || enc === 'replacement') throw new RangeError(E_ENCODING) + define(this, 'encoding', enc) + define(this, 'fatal', !!options.fatal) + define(this, 'ignoreBOM', !!options.ignoreBOM) + this.#unicode = enc === 'utf-8' || enc === 'utf-16le' || enc === 'utf-16be' + this.#multibyte = !this.#unicode && isMultibyte(enc) + this.#canBOM = this.#unicode && !this.ignoreBOM + } + + get [Symbol.toStringTag]() { + return 'TextDecoder' + } + + decode(input, options = {}) { + if (typeof options !== 'object') throw new TypeError(E_OPTIONS) + const stream = !!options.stream + let u = input === undefined ? new Uint8Array() : fromSource(input) + const empty = u.length === 0 // also can't be streaming after next line + if (empty && stream) return '' // no state change + + if (this.#unicode) { + let prefix + if (this.#chunk) { + const merged = mergePrefix(u, this.#chunk, this.encoding) + if (u.length < 3) { + u = merged // might be unfinished, but fully consumed old u + } else { + prefix = merged // stops at complete chunk + const add = prefix.length - this.#chunk.length + if (add > 0) u = u.subarray(add) + } + + this.#chunk = null + } else if (empty) { + this.#canBOM = !this.ignoreBOM // not streaming + return '' + } + + // For non-stream utf-8 we don't have to do this as it matches utf8toStringLoose already + // For non-stream loose utf-16 we still have to do this as this API supports uneven byteLength unlike utf16toStringLoose + let suffix = '' + if (stream || (!this.fatal && this.encoding !== 'utf-8')) { + const trail = unfinishedBytes(u, u.byteLength, this.encoding) + if (trail > 0) { + if (stream) { + this.#chunk = Uint8Array.from(u.subarray(-trail)) // copy + } else { + // non-fatal mode as already checked + suffix = replacementChar + } + + u = u.subarray(0, -trail) + } + } + + let seenBOM = false + if (this.#canBOM) { + const bom = this.#findBom(prefix ?? u) + if (bom) { + seenBOM = true + if (prefix) { + prefix = prefix.subarray(bom) + } else { + u = u.subarray(bom) + } + } + } else if (!stream && !this.ignoreBOM) { + this.#canBOM = true + } + + if (!this.#decode) this.#decode = unicodeDecoder(this.encoding, !this.fatal) + try { + const res = (prefix ? this.#decode(prefix) : '') + this.#decode(u) + suffix + // "BOM seen" is set on the current decode call only if it did not error, in "serialize I/O queue" after decoding + if (stream && (seenBOM || res.length > 0)) this.#canBOM = false + return res + } catch (err) { + this.#chunk = null // reset unfinished chunk on errors + // The correct way per spec seems to be not destroying the decoder state (aka BOM here) in stream mode + // See also multi-byte.js + throw err + } + + // eslint-disable-next-line no-else-return + } else if (this.#multibyte) { + if (!createMultibyteDecoder) throw new Error(E_MULTI) + if (!this.#decode) this.#decode = createMultibyteDecoder(this.encoding, !this.fatal) // can contain state! + return this.#decode(u, stream) + } else { + if (!this.#decode) this.#decode = createSinglebyteDecoder(this.encoding, !this.fatal) + return this.#decode(u) + } + } + + #findBom(u) { + switch (this.encoding) { + case 'utf-8': + return u.byteLength >= 3 && u[0] === 0xef && u[1] === 0xbb && u[2] === 0xbf ? 3 : 0 + case 'utf-16le': + return u.byteLength >= 2 && u[0] === 0xff && u[1] === 0xfe ? 2 : 0 + case 'utf-16be': + return u.byteLength >= 2 && u[0] === 0xfe && u[1] === 0xff ? 2 : 0 + } + + /* c8 ignore next */ + throw new Error('Unreachable') + } +} + +export class TextEncoder { + constructor() { + define(this, 'encoding', 'utf-8') + } + + get [Symbol.toStringTag]() { + return 'TextEncoder' + } + + encode(str = '') { + if (typeof str !== 'string') str = `${str}` + const res = utf8fromStringLoose(str) + // match new Uint8Array (per spec), which is non-pooled + return res.byteOffset === 0 && res.length === res.buffer.byteLength ? res : res.slice(0) + } + + encodeInto(str, target) { + if (typeof str !== 'string') str = `${str}` + if (!isAnyUint8Array(target)) throw new TypeError('Target must be an Uint8Array') + if (target.buffer.detached) return { read: 0, written: 0 } // Until https://github.com/whatwg/encoding/issues/324 is resolved + + const tlen = target.length + if (tlen < str.length) str = str.slice(0, tlen) + let u8 = utf8fromStringLoose(str) + let read + if (tlen >= u8.length) { + read = str.length + } else if (u8.length === str.length) { + if (u8.length > tlen) u8 = u8.subarray(0, tlen) // ascii can be truncated + read = u8.length + } else { + u8 = u8.subarray(0, tlen) + const unfinished = unfinishedBytes(u8, u8.length, 'utf-8') + if (unfinished > 0) u8 = u8.subarray(0, u8.length - unfinished) + + // We can do this because loose str -> u8 -> str preserves length, unlike loose u8 -> str -> u8 + // Each unpaired surrogate (1 charcode) is replaced with a single charcode + read = utf8toStringLoose(u8).length // FIXME: Converting back is very inefficient + } + + try { + target.set(u8) + } catch { + return { read: 0, written: 0 } // see above, likely detached but no .detached property support + } + + return { read, written: u8.length } + } +} + +const E_NO_STREAMS = 'TransformStream global not present in the environment' + +// https://encoding.spec.whatwg.org/#interface-textdecoderstream +export class TextDecoderStream { + constructor(encoding = 'utf-8', options = {}) { + if (!globalThis.TransformStream) throw new Error(E_NO_STREAMS) + const decoder = new TextDecoder(encoding, options) + const transform = new TransformStream({ + transform: (chunk, controller) => { + const value = decoder.decode(fromSource(chunk), { stream: true }) + if (value) controller.enqueue(value) + }, + flush: (controller) => { + // https://streams.spec.whatwg.org/#dom-transformer-flush + const value = decoder.decode() + if (value) controller.enqueue(value) + // No need to call .terminate() (Node.js is wrong) + }, + }) + + define(this, 'encoding', decoder.encoding) + define(this, 'fatal', decoder.fatal) + define(this, 'ignoreBOM', decoder.ignoreBOM) + define(this, 'readable', transform.readable) + define(this, 'writable', transform.writable) + } + + get [Symbol.toStringTag]() { + return 'TextDecoderStream' + } +} + +// https://encoding.spec.whatwg.org/#interface-textencoderstream +// Only UTF-8 per spec +export class TextEncoderStream { + constructor() { + if (!globalThis.TransformStream) throw new Error(E_NO_STREAMS) + let lead + const transform = new TransformStream({ + // https://encoding.spec.whatwg.org/#encode-and-enqueue-a-chunk + // Not identical in code, but reuses loose mode to have identical behavior + transform: (chunk, controller) => { + let s = String(chunk) // DOMString, might contain unpaired surrogates + if (s.length === 0) return + if (lead) { + s = lead + s + lead = null + } + + const last = s.charCodeAt(s.length - 1) // Can't come from previous lead due to length check + if ((last & 0xfc_00) === 0xd8_00) { + lead = s[s.length - 1] + s = s.slice(0, -1) + } + + if (s) controller.enqueue(utf8fromStringLoose(s)) + }, + // https://encoding.spec.whatwg.org/#encode-and-flush + flush: (controller) => { + if (lead) controller.enqueue(Uint8Array.of(0xef, 0xbf, 0xbd)) + }, + }) + + define(this, 'encoding', 'utf-8') + define(this, 'readable', transform.readable) + define(this, 'writable', transform.writable) + } + + get [Symbol.toStringTag]() { + return 'TextEncoderStream' + } +} + +// https://encoding.spec.whatwg.org/#decode +// Warning: encoding sniffed from BOM takes preference over the supplied one +// Warning: lossy, performs replacement, no option of throwing +// Completely ignores encoding and even skips validation when BOM is found +// Unlike TextDecoder public API, additionally supports 'replacement' encoding +export function legacyHookDecode(input, fallbackEncoding = 'utf-8') { + let u8 = fromSource(input) + const bomEncoding = getBOMEncoding(u8) + if (bomEncoding) u8 = u8.subarray(bomEncoding === 'utf-8' ? 3 : 2) + const enc = bomEncoding ?? normalizeEncoding(fallbackEncoding) // "the byte order mark is more authoritative than anything else" + + if (enc === 'utf-8') return utf8toStringLoose(u8) + if (enc === 'utf-16le' || enc === 'utf-16be') { + let suffix = '' + if (u8.byteLength % 2 !== 0) { + suffix = replacementChar + u8 = u8.subarray(0, -unfinishedBytes(u8, u8.byteLength, enc)) + } + + return utf16toStringLoose(u8, enc === 'utf-16le' ? 'uint8-le' : 'uint8-be') + suffix + } + + if (!Object.hasOwn(labels, enc)) throw new RangeError(E_ENCODING) + + if (isMultibyte(enc)) { + if (!createMultibyteDecoder) throw new Error(E_MULTI) + return createMultibyteDecoder(enc, true)(u8) + } + + // https://encoding.spec.whatwg.org/#replacement-decoder + // On non-streaming non-fatal case, it just replaces any non-empty input with a single replacement char + if (enc === 'replacement') return input.byteLength > 0 ? replacementChar : '' + + return createSinglebyteDecoder(enc, true)(u8) +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/encoding.labels.js b/vanilla/node_modules/@exodus/bytes/fallback/encoding.labels.js new file mode 100644 index 0000000..62b8224 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/encoding.labels.js @@ -0,0 +1,50 @@ +// See https://encoding.spec.whatwg.org/#names-and-labels + +/* eslint-disable @exodus/export-default/named */ +// prettier-ignore +const labels = { + 'utf-8': ['unicode-1-1-utf-8', 'unicode11utf8', 'unicode20utf8', 'utf8', 'x-unicode20utf8'], + 'utf-16be': ['unicodefffe'], + 'utf-16le': ['csunicode', 'iso-10646-ucs-2', 'ucs-2', 'unicode', 'unicodefeff', 'utf-16'], + 'iso-8859-2': ['iso-ir-101'], + 'iso-8859-3': ['iso-ir-109'], + 'iso-8859-4': ['iso-ir-110'], + 'iso-8859-5': ['csisolatincyrillic', 'cyrillic', 'iso-ir-144'], + 'iso-8859-6': ['arabic', 'asmo-708', 'csiso88596e', 'csiso88596i', 'csisolatinarabic', 'ecma-114', 'iso-8859-6-e', 'iso-8859-6-i', 'iso-ir-127'], + 'iso-8859-7': ['csisolatingreek', 'ecma-118', 'elot_928', 'greek', 'greek8', 'iso-ir-126', 'sun_eu_greek'], + 'iso-8859-8': ['csiso88598e', 'csisolatinhebrew', 'hebrew', 'iso-8859-8-e', 'iso-ir-138', 'visual'], + 'iso-8859-8-i': ['csiso88598i', 'logical'], + 'iso-8859-16': [], + 'koi8-r': ['cskoi8r', 'koi', 'koi8', 'koi8_r'], + 'koi8-u': ['koi8-ru'], + 'windows-874': ['dos-874', 'iso-8859-11', 'iso8859-11', 'iso885911', 'tis-620'], + ibm866: ['866', 'cp866', 'csibm866'], + 'x-mac-cyrillic': ['x-mac-ukrainian'], + macintosh: ['csmacintosh', 'mac', 'x-mac-roman'], + gbk: ['chinese', 'csgb2312', 'csiso58gb231280', 'gb2312', 'gb_2312', 'gb_2312-80', 'iso-ir-58', 'x-gbk'], + gb18030: [], + big5: ['big5-hkscs', 'cn-big5', 'csbig5', 'x-x-big5'], + 'euc-jp': ['cseucpkdfmtjapanese', 'x-euc-jp'], + shift_jis: ['csshiftjis', 'ms932', 'ms_kanji', 'shift-jis', 'sjis', 'windows-31j', 'x-sjis'], + 'euc-kr': ['cseuckr', 'csksc56011987', 'iso-ir-149', 'korean', 'ks_c_5601-1987', 'ks_c_5601-1989', 'ksc5601', 'ksc_5601', 'windows-949'], + 'iso-2022-jp': ['csiso2022jp'], + replacement: ['csiso2022kr', 'hz-gb-2312', 'iso-2022-cn', 'iso-2022-cn-ext', 'iso-2022-kr'], + 'x-user-defined': [], +} + +for (const i of [10, 13, 14, 15]) labels[`iso-8859-${i}`] = [`iso8859-${i}`, `iso8859${i}`] +for (const i of [2, 6, 7]) labels[`iso-8859-${i}`].push(`iso_8859-${i}:1987`) +for (const i of [3, 4, 5, 8]) labels[`iso-8859-${i}`].push(`iso_8859-${i}:1988`) +// prettier-ignore +for (let i = 2; i < 9; i++) labels[`iso-8859-${i}`].push(`iso8859-${i}`, `iso8859${i}`, `iso_8859-${i}`) +for (let i = 2; i < 5; i++) labels[`iso-8859-${i}`].push(`csisolatin${i}`, `l${i}`, `latin${i}`) +for (let i = 0; i < 9; i++) labels[`windows-125${i}`] = [`cp125${i}`, `x-cp125${i}`] + +// prettier-ignore +labels['windows-1252'].push('ansi_x3.4-1968', 'ascii', 'cp819', 'csisolatin1', 'ibm819', 'iso-8859-1', 'iso-ir-100', 'iso8859-1', 'iso88591', 'iso_8859-1', 'iso_8859-1:1987', 'l1', 'latin1', 'us-ascii') +// prettier-ignore +labels['windows-1254'].push('csisolatin5', 'iso-8859-9', 'iso-ir-148', 'iso8859-9', 'iso88599', 'iso_8859-9', 'iso_8859-9:1989', 'l5', 'latin5') +labels['iso-8859-10'].push('csisolatin6', 'iso-ir-157', 'l6', 'latin6') +labels['iso-8859-15'].push('csisolatin9', 'iso_8859-15', 'l9') + +export default labels diff --git a/vanilla/node_modules/@exodus/bytes/fallback/encoding.util.js b/vanilla/node_modules/@exodus/bytes/fallback/encoding.util.js new file mode 100644 index 0000000..a53cefb --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/encoding.util.js @@ -0,0 +1,64 @@ +// Get a number of last bytes in an Uint8Array `u` ending at `len` that don't +// form a codepoint yet, but can be a part of a single codepoint on more data +export function unfinishedBytes(u, len, enc) { + switch (enc) { + case 'utf-8': { + // 0-3 + let p = 0 + while (p < 2 && p < len && (u[len - p - 1] & 0xc0) === 0x80) p++ // go back 0-2 trailing bytes + if (p === len) return 0 // no space for lead + const l = u[len - p - 1] + if (l < 0xc2 || l > 0xf4) return 0 // not a lead + if (p === 0) return 1 // nothing to recheck, we have only lead, return it. 2-byte must return here + if (l < 0xe0 || (l < 0xf0 && p >= 2)) return 0 // 2-byte, or 3-byte or less and we already have 2 trailing + const lower = l === 0xf0 ? 0x90 : l === 0xe0 ? 0xa0 : 0x80 + const upper = l === 0xf4 ? 0x8f : l === 0xed ? 0x9f : 0xbf + const n = u[len - p] + return n >= lower && n <= upper ? p + 1 : 0 + } + + case 'utf-16le': + case 'utf-16be': { + // 0-3 + const p = len % 2 // uneven byte length adds 1 + if (len < 2) return p + const l = len - p - 1 + const last = enc === 'utf-16le' ? (u[l] << 8) ^ u[l - 1] : (u[l - 1] << 8) ^ u[l] + return last >= 0xd8_00 && last < 0xdc_00 ? p + 2 : p // lone lead adds 2 + } + } + + throw new Error('Unsupported encoding') +} + +// Merge prefix `chunk` with `u` and return new combined prefix +// For u.length < 3, fully consumes u and can return unfinished data, +// otherwise returns a prefix with no unfinished bytes +export function mergePrefix(u, chunk, enc) { + if (u.length === 0) return chunk + if (u.length < 3) { + // No reason to bruteforce offsets, also it's possible this doesn't yet end the sequence + const a = new Uint8Array(u.length + chunk.length) + a.set(chunk) + a.set(u, chunk.length) + return a + } + + // Slice off a small portion of u into prefix chunk so we can decode them separately without extending array size + const t = new Uint8Array(chunk.length + 3) // We have 1-3 bytes and need 1-3 more bytes + t.set(chunk) + t.set(u.subarray(0, 3), chunk.length) + + // Stop at the first offset where unfinished bytes reaches 0 or fits into u + // If that doesn't happen (u too short), just concat chunk and u completely (above) + for (let i = 1; i <= 3; i++) { + const unfinished = unfinishedBytes(t, chunk.length + i, enc) // 0-3 + if (unfinished <= i) { + // Always reachable at 3, but we still need 'unfinished' value for it + const add = i - unfinished // 0-3 + return add > 0 ? t.subarray(0, chunk.length + add) : chunk + } + } + + // Unreachable +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/hex.js b/vanilla/node_modules/@exodus/bytes/fallback/hex.js new file mode 100644 index 0000000..b3d92d0 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/hex.js @@ -0,0 +1,126 @@ +import { E_STRING } from './_utils.js' +import { nativeDecoder, nativeEncoder, decode2string } from './platform.js' +import { encodeAscii, decodeAscii } from './latin1.js' + +let hexArray // array of 256 bytes converted to two-char hex strings +let hexCodes // hexArray converted to u16 code pairs +let dehexArray +const _00 = 0x30_30 // '00' string in hex, the only allowed char pair to generate 0 byte +const _ff = 0x66_66 // 'ff' string in hex, max allowed char pair (larger than 'FF' string) +const allowed = '0123456789ABCDEFabcdef' + +export const E_HEX = 'Input is not a hex string' + +// Expects a checked Uint8Array +export function toHex(arr) { + if (!hexArray) hexArray = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0')) + const length = arr.length // this helps Hermes + + // Only old browsers use this, barebone engines don't have TextDecoder + // But Hermes can use this when it (hopefully) implements TextDecoder + if (nativeDecoder) { + if (!hexCodes) { + hexCodes = new Uint16Array(256) + const u8 = new Uint8Array(hexCodes.buffer, hexCodes.byteOffset, hexCodes.byteLength) + for (let i = 0; i < 256; i++) { + const pair = hexArray[i] + u8[2 * i] = pair.charCodeAt(0) + u8[2 * i + 1] = pair.charCodeAt(1) + } + } + + const oa = new Uint16Array(length) + let i = 0 + for (const last3 = arr.length - 3; ; i += 4) { + if (i >= last3) break // loop is fast enough for moving this here to be useful on JSC + const x0 = arr[i] + const x1 = arr[i + 1] + const x2 = arr[i + 2] + const x3 = arr[i + 3] + oa[i] = hexCodes[x0] + oa[i + 1] = hexCodes[x1] + oa[i + 2] = hexCodes[x2] + oa[i + 3] = hexCodes[x3] + } + + for (; i < length; i++) oa[i] = hexCodes[arr[i]] + return decodeAscii(oa) + } + + return decode2string(arr, 0, length, hexArray) +} + +export function fromHex(str) { + if (typeof str !== 'string') throw new TypeError(E_STRING) + if (str.length % 2 !== 0) throw new SyntaxError(E_HEX) + + const length = str.length / 2 // this helps Hermes in loops + const arr = new Uint8Array(length) + + // Native encoder path is beneficial even for small arrays in Hermes + if (nativeEncoder) { + if (!dehexArray) { + dehexArray = new Uint8Array(_ff + 1) // 26 KiB cache, >2x perf improvement on Hermes + const u8 = new Uint8Array(2) + const u16 = new Uint16Array(u8.buffer, u8.byteOffset, 1) // for endianess-agnostic transform + const map = [...allowed].map((c) => [c.charCodeAt(0), parseInt(c, 16)]) + for (const [ch, vh] of map) { + u8[0] = ch // first we read high hex char + for (const [cl, vl] of map) { + u8[1] = cl // then we read low hex char + dehexArray[u16[0]] = (vh << 4) | vl + } + } + } + + const codes = encodeAscii(str, E_HEX) + const codes16 = new Uint16Array(codes.buffer, codes.byteOffset, codes.byteLength / 2) + let i = 0 + for (const last3 = length - 3; i < last3; i += 4) { + const ai = codes16[i] + const bi = codes16[i + 1] + const ci = codes16[i + 2] + const di = codes16[i + 3] + const a = dehexArray[ai] + const b = dehexArray[bi] + const c = dehexArray[ci] + const d = dehexArray[di] + if ((!a && ai !== _00) || (!b && bi !== _00) || (!c && ci !== _00) || (!d && di !== _00)) { + throw new SyntaxError(E_HEX) + } + + arr[i] = a + arr[i + 1] = b + arr[i + 2] = c + arr[i + 3] = d + } + + while (i < length) { + const ai = codes16[i] + const a = dehexArray[ai] + if (!a && ai !== _00) throw new SyntaxError(E_HEX) + arr[i++] = a + } + } else { + if (!dehexArray) { + // no regex input validation here, so we map all other bytes to -1 and recheck sign + // non-ASCII chars throw already though, so we should process only 0-127 + dehexArray = new Int8Array(128).fill(-1) + for (let i = 0; i < 16; i++) { + const s = i.toString(16) + dehexArray[s.charCodeAt(0)] = dehexArray[s.toUpperCase().charCodeAt(0)] = i + } + } + + let j = 0 + for (let i = 0; i < length; i++) { + const a = str.charCodeAt(j++) + const b = str.charCodeAt(j++) + const res = (dehexArray[a] << 4) | dehexArray[b] + if (res < 0 || (0x7f | a | b) !== 0x7f) throw new SyntaxError(E_HEX) // 0-127 + arr[i] = res + } + } + + return arr +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/latin1.js b/vanilla/node_modules/@exodus/bytes/fallback/latin1.js new file mode 100644 index 0000000..dc734d8 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/latin1.js @@ -0,0 +1,151 @@ +import { + nativeEncoder, + nativeDecoder, + nativeDecoderLatin1, + nativeBuffer, + encodeCharcodes, + isHermes, + isDeno, + isLE, +} from './platform.js' + +const atob = /* @__PURE__ */ (() => globalThis.atob)() +const web64 = /* @__PURE__ */ (() => Uint8Array.prototype.toBase64)() + +// See http://stackoverflow.com/a/22747272/680742, which says that lowest limit is in Chrome, with 0xffff args +// On Hermes, actual max is 0x20_000 minus current stack depth, 1/16 of that should be safe +const maxFunctionArgs = 0x20_00 + +// toBase64+atob path is faster on everything where fromBase64 is fast +const useLatin1atob = web64 && atob + +export function asciiPrefix(arr) { + let p = 0 // verified ascii bytes + const length = arr.length + // Threshold tested on Hermes (worse on <=48, better on >=52) + // Also on v8 arrs of size <=64 might be on heap and using Uint32Array on them is unoptimal + if (length > 64) { + // Speedup with u32 + const u32start = (4 - (arr.byteOffset & 3)) % 4 // offset start by this many bytes for alignment + for (; p < u32start; p++) if (arr[p] >= 0x80) return p + const u32length = ((arr.byteLength - u32start) / 4) | 0 + const u32 = new Uint32Array(arr.buffer, arr.byteOffset + u32start, u32length) + let i = 0 + for (const last3 = u32length - 3; ; p += 16, i += 4) { + if (i >= last3) break // loop is fast enough for moving this here to be _very_ useful, likely due to array access checks + const a = u32[i] + const b = u32[i + 1] + const c = u32[i + 2] + const d = u32[i + 3] + // "(a | b | c | d) & mask" is slower on Hermes though faster on v8 + if (a & 0x80_80_80_80 || b & 0x80_80_80_80 || c & 0x80_80_80_80 || d & 0x80_80_80_80) break + } + + for (; i < u32length; p += 4, i++) if (u32[i] & 0x80_80_80_80) break + } + + for (; p < length; p++) if (arr[p] >= 0x80) return p + return length +} + +// Capable of decoding Uint16Array to UTF-16 as well as Uint8Array to Latin-1 +export function decodeLatin1(arr, start = 0, stop = arr.length) { + start |= 0 + stop |= 0 + const total = stop - start + if (total === 0) return '' + + if ( + useLatin1atob && + total >= 256 && + total < 1e8 && + arr.toBase64 === web64 && + arr.BYTES_PER_ELEMENT === 1 + ) { + const sliced = start === 0 && stop === arr.length ? arr : arr.subarray(start, stop) + return atob(sliced.toBase64()) + } + + if (total > maxFunctionArgs) { + let prefix = '' + for (let i = start; i < stop; ) { + const i1 = Math.min(stop, i + maxFunctionArgs) + prefix += String.fromCharCode.apply(String, arr.subarray(i, i1)) + i = i1 + } + + return prefix + } + + const sliced = start === 0 && stop === arr.length ? arr : arr.subarray(start, stop) + return String.fromCharCode.apply(String, sliced) +} + +// Unchecked for well-formedness, raw. Expects Uint16Array input +export const decodeUCS2 = + nativeBuffer && isLE && !isDeno + ? (u16, stop = u16.length) => { + // TODO: fast path for BE, perhaps faster path for Deno. Note that decoder replaces, this function doesn't + if (stop > 32) return nativeBuffer.from(u16.buffer, u16.byteOffset, stop * 2).ucs2Slice() // from 64 bytes, below are in heap + return decodeLatin1(u16, 0, stop) + } + : (u16, stop = u16.length) => decodeLatin1(u16, 0, stop) + +// Does not check input, uses best available method +// Building an array for this is only faster than proper string concatenation when TextDecoder or native Buffer are available +export const decodeAscii = nativeBuffer + ? (a) => + // Buffer is faster on Node.js (but only for long enough data), if we know that output is ascii + a.byteLength >= 0x3_00 && !isDeno + ? nativeBuffer.from(a.buffer, a.byteOffset, a.byteLength).latin1Slice(0, a.byteLength) // .latin1Slice is faster than .asciiSlice + : nativeDecoder.decode(a) // On Node.js, utf8 decoder is faster than latin1 + : nativeDecoderLatin1 + ? (a) => nativeDecoderLatin1.decode(a) // On browsers (specifically WebKit), latin1 decoder is faster than utf8 + : (a) => + decodeLatin1( + a instanceof Uint8Array ? a : new Uint8Array(a.buffer, a.byteOffset, a.byteLength) + ) + +/* eslint-disable @exodus/mutable/no-param-reassign-prop-only */ + +export function encodeAsciiPrefix(x, s) { + let i = 0 + for (const len3 = s.length - 3; i < len3; i += 4) { + const x0 = s.charCodeAt(i), x1 = s.charCodeAt(i + 1), x2 = s.charCodeAt(i + 2), x3 = s.charCodeAt(i + 3) // prettier-ignore + if ((x0 | x1 | x2 | x3) >= 128) break + x[i] = x0 + x[i + 1] = x1 + x[i + 2] = x2 + x[i + 3] = x3 + } + + return i +} + +/* eslint-enable @exodus/mutable/no-param-reassign-prop-only */ + +// Warning: can be used only on checked strings, converts strings to 8-bit +export const encodeLatin1 = (str) => encodeCharcodes(str, new Uint8Array(str.length)) + +// Expects nativeEncoder to be present +const useEncodeInto = /* @__PURE__ */ (() => isHermes && nativeEncoder?.encodeInto)() +export const encodeAscii = useEncodeInto + ? (str, ERR) => { + // Much faster in Hermes + const codes = new Uint8Array(str.length + 4) // overshoot by a full utf8 char + const info = nativeEncoder.encodeInto(str, codes) + if (info.read !== str.length || info.written !== str.length) throw new SyntaxError(ERR) // non-ascii + return codes.subarray(0, str.length) + } + : nativeBuffer + ? (str, ERR) => { + // TextEncoder is slow on Node.js 24 / 25 (was ok on 22) + const codes = nativeBuffer.from(str, 'utf8') // ascii/latin1 coerces, we need to check + if (codes.length !== str.length) throw new SyntaxError(ERR) // non-ascii + return new Uint8Array(codes.buffer, codes.byteOffset, codes.byteLength) + } + : (str, ERR) => { + const codes = nativeEncoder.encode(str) + if (codes.length !== str.length) throw new SyntaxError(ERR) // non-ascii + return codes + } diff --git a/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.encodings.cjs b/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.encodings.cjs new file mode 100644 index 0000000..114710b --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.encodings.cjs @@ -0,0 +1 @@ +module.exports = () => require('./multi-byte.encodings.json') // lazy-load diff --git a/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.encodings.json b/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.encodings.json new file mode 100644 index 0000000..bb2d7e9 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.encodings.json @@ -0,0 +1,546 @@ +{ + "$C": [6,1040,1,-21,26,20], + "$c": [6,1072,1,27,26,-28], + "$1": [17,913,7,1], + "$2": [17,945,7,1], + "$3": ["AAEJAwf7Bw_3DwfEAQsDB_sLD_cPD9QO-A4H3RL0EgklAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"], + "$4": [1,9490,1,-2,1,8,1,-2,1,-4,1,-2,1,-8,1,-2,2,16,2,1,2,3,2,1,2,2,2,2,2,2,2,2,2,2,2,1], + "$5": ["Bv7FA_74_tr-Ev4mAP8AAAAAAAAAAA"], + "$6": ["$5",1,9661,1,-2], + "$7": [2,12541,2,-98,1,-156,1,7897,3,-7897,1,244], + "$8": ["E9UxzELB4htgpd4feI7ZJNwBAQEfAf8B_wH_Af8B_wH_Af8B_wEAAAD_"], + "$9": [1,26142,4,2,1,1,4,2,1,1,1,1], + "$j": [ + "ipErP1Ps8XWWMAFJ4rgaAwI1HDv3D_k4cuHcHicp0VFf43EZOCAtKIYJGRokBhxNIB4qMI3tHlWG0gtGG_5HAI0TWEcHAQVAFZtpbqgTMYcTOjErvTAqSgAWUBIyTyZ-JwRT9krRHiX4Z3qSTmo8MH-xFCXNJO8FQPEBuGAlBhEMOhMaPFSWbUBCikNUq4NJTTraLApjAfFoHCnoaimC5yYVIij5CTwiyhSCyCw_DwEgXCVj9FfpAM2rPLIMZfFgRQsMDO407TAD_gQzJhVhbRIZAfwKcC5ocSwVFbV-Cwr_8ssh9gIq1PnvAAABAAAAAAAAAAABAP8BAAAAAAAAAQAAAAABAAAAAAEAAAAAAACnWgAAAAECAAAAAKMAXgABAAAAAAAAAgAa5gABAAAAAQCdYwAAAAACAAAAAAEAAAAAAf8BAAAAAQABAQAAAQEAAAAAAAAAAACUbAAAAAAAAZJuAAH_AQAAkm-RbwABAAAAAAAAAQEAAAAAAQAAAAAAAAAAAQAAAAABAAABAAAAAAEAAAAAiXcAAQABh3kAAAAAAAH_AQAAAAAAAAEAAQAAAACEfdsmAAAAAQ", + 3,32999, + "lIZ_NRU0zrJ-KhNa6DV79Fl84mAcRy5Ra54FEbOQbwDl7RwkQS0WIELTXCtwAx1jrKtUAEF2R-4RsvwGDgD1ACAJ-S8F-xEK9-ctP88Abu8B9latCvJR-9ks9eAd5G3mTCEXGTgTAklJTHMRgwcHCQEBAwENxAD7BHGvigKY_BwhCURv-sHrt3mBfwEAgIABf4MAAAAAAQEAe4kAAAAAAQABAAB1i3UAjgACAAAAAABwkAEAAQABAG2UbACWAGqXAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAABomAAAAQD_aJn_AQAAAAAAAAABAAABZAGcAAEAAAAAAAABAGIAn2GfAQAAAQAAAAABAQBdpAA" + ], + "jis0208": [ + 3,12288,"DAHsHgAD4ZkAF4tnlaRb_wAxzwAAADEA0P8B_wAA","$7","Ffr-LCHGNsn-8gACAOoACgAlAR0BIADfAAAj3SEAAAAAAN8AMQDPAAAA",10,-53078, + "CwGjJR8lQrsBRwC2FQ39b4EAz-Ee2wAj_QIDFYb_AAEAAP8j3QAjAAAABADaIAAB3gAAAAAAAAAAAQ","$6","O9Z__QABfyAQ8QAAAA8",0,11,1,-3596,-2,2,122,2,-6,1,-90,1,-2,0,8,2,-3,"4u8BKwL_IgABAA",0,11, + "IIRs7wRZ8BcAriLfF_UAIgAB_wAAAAAAAAAAAAAA",0,7,"KwQ-_fy1AJQh_wYAAPoA4A",0,4,1,9528,0,15,10,55584,0,7,26,7,0,6,26,6,0,4,83,-53018,0,11,86,13,0,8,"$1",0,8,"$2",0,38,"$C",0,15,"$c",0,13,"$3",0,438, + 20,-3223,10,-788,0,1,"ScoNKsoO2zIaBbUY_Ace8DMAAAAAAAAAAAAAAAAAAAA",3,96,2,-17,1,52,1,-36,0,8,"e6EB9rZTM_0A8RLu",5,4482,2,-120,"OUT-_tUOyQLiCIp6_p918wAyAQAA7wAAAAAAAAAAAAAAAA",0,190, + "nHnsO4BaDM0rUqYzWTZDx3g_Tp2Tec8pNKp4bVvPh4gX0StTjbB-xcGVJEJPq6hEnCwH1S9govG0lCCKsUHTSlSeUiTAWQ850g4tEPCwlfn1YqMRLkwj_hoZ3Pj4SDQNL1oP55NH7QQlhuxdVoFoKfHrGPwgqcO8dbKyTrmmXLzU1HlArtIQM7o1MWyF5bxpBIzE-B764FqIJ9se2IsdE29BMYBKylR5hUR7acF0WsXI-r9NUp3K0zQ2GlvfPS_8jNY1lNXhtdz05IhGag-v6vegffC_JaMXCtdm52PRLE4ZBbH0Ku-1FBmVZrdWyjB9SikpKHJ345JLdn49Z89rOSMoR-Gp10DBBE3B9U7I-mt_MO8-ac1tQb1oByRJxvjbOe4vU5ECDlPMV5z_YlEZLN09ixo0ELM7MMlbzj90A3zODdeC-4K2R7AuN5iX6bXw1PxMyc8ATIQKUzZWURIq0ntOy8mJtDPPJLwkHkmlMWbuKa_OzPniK3NivCCXBBwxN80OE56Pu6ULQpYGKXtDWhyGboGmQxQDynStamfKJ_Ohf8dMuazINxQY3tjMQf0Qwm1U7x_yjBPcou9sQR-1T0IDqAxiKsuRTMG6y3txTSFLnAo8q_ia0JRRZQHIGpz_vNGIm8JUUMQrLUP8gpIIklBrTWXwtWFRwLM7HdVo-aeoAxe2TVemLXc1tREsgUm4bXVkESvrBC9wlIpyN1kR42eAc1-JoukNOAY51qsaCKSzTQIA7gQwda56hF3MXWvA1l1VEuQgHLE58XUAKgEIDAJFqOkdVwKV7E9T69KxghPGMEMeYrYnfX4Z9kw7jX7uErLf2Zf_TWDc2K5UnL5S_MgWAQmkokNRyftccz2sqAtp9k8G8-DsSN_9-ZRY4BqFKI9nkCgThCG4gPtSMg7ZvKDFECHwAPBBCIcxAtLQUta9UEyxH6I7gjpaApYcdCgVGZ6XYzzYp0-OWdkf2-_i5O1C7D4WuypDZ_XGLbdF-n6pDFMugeVaCZKc4Y3I75ARBNq9ZMpbE8eq9HTzeUTzyPlV_bzYl33Wkoy5exAMaaZ5-ensPw5dOGBOj5-rgP16OgD08FwU_QfmyyYcBdIYzWra1zJp_DIiMhlEm0gt_HrHUNrWCDFVAQ-AChYcYDn5SkDOk8ZAsHizdTOTyj7FbZRU5NKgJBJFUmPtqwGiOpon-RS5hlnNqvvNvKeot5M-Yh9PSxDMIeiJ9FmR7w6yQjbocXHEZqDr3M0y4KeexiVzWZsNXkf2MndF3WQz01i0eDxodgcMndmOTUVIcFaDifbgcsiUXPS441ObNZR0SbiUEEYgoavkR5HIwycZNhKN5w9PKf1b7ZhkYe1Asunr4I7RywwsUIvfcKynFrc3RozuJ75FdbmkE5K2jimudqnQ-4bjWHPqEu1XnJeb_t9J_mVEur358PcP3_01UPy0KKtF6ScsUg0qtMQYkzUDdzYgEXZf8KLHCvwlYdgU7y9yG7BQwgaiTbhA3qnvgn4W7HjRJrapCbEuj0jSzv2UXRftBTmX2uT1hrcrtGDfkYGow-jT74pqY_010c_Y7Reso1jidNo_GCi4Fntiudxux0GascLlWF72TTw3rkN7xJKUiLByU9nzmS6ZrA8S_DONCnYKhBoxcLUrHeO6ARkgWdUjjvX7UXrFbMlXwqa1UESlEYvQbOIgWlic2TAphjY44sbjQYIZaaLNmRXMkxF-3zYiUEdAmxufhbZHALAvmRsAxI5_Ume9Qiak-13q5VBVfXhQCAEIaQVVjw4EVrDqjwQgSAcjfBWGy4BO4-lAXzlbo2OK7zCVkVw_tL0TlSscFx7tfMXBF5mD-3H9FTg_2F1ll1UVjDhi9O1xvO9UuUVnEMIJ7h-IVmYi-nP4dVuJ_KjTURi8C9mK4ICaoqzceEGFZT6HTK_L-v-PcO-WqimyBkFxdh4OIhC7up0Jt6k4WZC0biFIooKLVdYpVI_REbsHds5lQmEGMQUyktrPq1GoPYX1fR0VMNGUcavwraXoLjSqVH0jTKFsrLvil5kMgSDyN1F0vwYvhPe0ca49im57Yln_8Muht3x9SV3Ry5xVlFU86z2LlTyPbvocQl4TxkggaGIglHvRu4jxLk2zLSxvXdGgHWzHXyaC_jXj8SqeNrP9MRzPXRp9BFYBU_5cfrX-f0eIt4gjwiwGJb7GjVYVJqBDYO1N2LjFD2gmu3sRGw_p6S8Xz6NfDppL78zE5w4TTz7JqpBrKYT1vMf2RGHSF6Kw0iv72RXMhmu3hmsEyrdD30yUEp4CQwp5Qw9F4OzWj0pibXMf6oNjKrL3EaB9VZoq6Mrw7e-wVLYsRy1bUP8HDDYEYL6s40kr8EDSRTTOTDL0IIg8Oa4Q8f5cDVu5xsvs1BpcwE_0cogerV9e3ENnknlRPwG6EIGIBMnFh-N2bujpNIGPXMBK6kkU5ZMlU4UjLG0VkpxXckvYqKOqXuzEpkbcfrT2ggvDEqTcRg4DvG9XUUSEv2kgHE2SIDVIPR6QelDj5_85xD79SByobabciuLfkZwgckT16sSxdnG9MJxAPj-nsUZH6Kviao2f6jD5jDT__d_Y0PigDRjNWqnbdYJ3F0knbCiEld6QRgZ81Ga6413OpHSqNdZyiZJ-j5ZNZ-g3xuqon1Yz8r0rQWOTjJ8leF1jofF-ylLBJCFUszEExMRZYw0m6E_XFG_7eFSd_0dRIDIPQwP-PWCUMNiXQ9F4IvcAlivTWIqEntEK_YOavjIFein1QcjzCwlctgKn9Ac29QuY9n-UMQ4PTjFaJjdXG-jc6Vsk7RnAVV2WiLIVq_TZg9RZ9leeJc3m0T11RTpa4cecrnRJIdAWUU9y3wh-A3kur9PYGM6374XljfEcvK4MjkK_U86xhIm5hcKAhR4o1Kq4TpDFBhlJ7zWL8uQMT5Ui2e9qW_f9ES43_kbPGbTEF1OIf-1uI7_rmPLt8Ji5Ou2JrmVkAkEFNfRyAfqyFgCgTWbxQuUUjxXkVrPARc7An3gqxA4K9intHFIlXyuyVUOQ3orXd-8lgg0qJWTtvg_5Zj1m7Oq8vxoBoqjcTSsAeetyqjsm1FwD9DWWLzHkQ_fl--JG8qstBQ0Bw958LyxgpG_YUFzThKyOTCFRYXg2U6ajiJzj9SqDr3Rtrch0rh3K34X_7CNl7_UMBFDJqVA_k6ofz7iRK2cTphbKB0o6ZdtamHlfAC_G_8fvKUn-wkNFjacnafy6t0IIfRhRVNHct185m8eB6Y1-biE9YhaZKHM0OD7wyatTGlQ81JbWulv_yiIPlrlhFkvRF435xZRQfX9rdMi5PX8g0Rl4cQlf16svOdIYURPBsDctnLPBtKMecak51AxA6hdTUv45bBq11npRyQsXOPiy1FjfFQ8XH1srKvV44lHryPNdlJoAZXRmtAG_joj9V4syvrPtC-q9hksJgTL-35_c3eR5SwfXzuXkon5rZg_tbXIzGu97RvgUU1MKSDzk8HF_GOi_UUdaHarnX7YaraEWGVUthkLzkPODDrhI_j17Szmpc5iMZ2-Q0BegW_VyZ4d79Sx1V72o4IHaez_Wv2SBmPWwFHOcBR4WQjGeZlR0gF1WZR37l1a8ofSKp4ZZyJy6pLX-sJiaSvYh2JwD2dci4VMy0IwkqQD5HoTCsUZjzsiHctC0erXQnM4ZIv4hH8YabY0yqt2Thtp1SH-3n-haF4xzEqBQ8Fcvw8Q0PWxLirojRdssBgPas-bhX3mB5VXoWV18XuwR6hWVEvtDglHEI7dabE8RJvNVsCi3VpYpJytGqiGq5zpiImpuyodiqVKlooI1WWz-MwRitEF4s0fA4FeVLoVRVCv5CGGViZZggj4TjMpDzaKLJPkGgUSSJfS1en40CBUsY7U4LEKBjIg5EmQX1aRSmfATfMyCniXwBqajVl7k-FlCyc5Rpv53WlWml30YvU4HBTy-DQL2N_T_9-YDC_cf_hnN7w79-f4tEuUAHscaDNMDBQMCLQLQ5wEAAAEGAwABAgQBAAUDBwUABAQAAwQEAwUAw_sACSkQ6NYKFiLqCf8atQIBAAIDBjnVEwURAAABvf8IFQ8QB71K3dQqCe3o_xYaF736GgchwfhCBu0WugIGBAcAAgQAAQcCBB7qBgII2wgBI8crAgjU6v4GAQECAwIDAAkDAQEAAAILBAADCwILuw0HCdwIAAYAAwMFAQAIDAoUAAG-EBfOCwUg5wrcAQQNDgwdtwX7AQAAAAMBAwMBAQAe7QEABAEEAwYAAQEHAAEAAAAEA8w2AwEH78kNBhADDAEEBgoDALUBOs0CAAYBAQAAAQEAAzbLAgUDBQEHBQUOAfbFAQf7BwIECAQLDAQCCQfTLO3REB8MwAT-CgQCBAADCAUCDwAEAgEFAQHEAQ0vAMsY7wD-NNPjAwsCCwEAFgUGv063FgEt0ekpCg0Cw0fLGwH41jDy2gECCvcAAAv4AwECAAADAAIBAAACAgIBAAMAAQMAAAUBAQEDAQEBAgABAgEGAQIEBAEAAAEBAunMBggBFgMB5SMOCQIAALcABAIBAQICAAECAAEEBP4AAgEAAvQNAQAJBOIfA-IqAQIBAQEJAgGzAgEIAgcAAgcHAwQGCAMB2CAUvQABEwIg7u83tQgmBQq-AAABBAEHBAEFAgUAAAQEBgABAv8B6A3hCQEFAAELGAQDBd0KIrMAAAEAAQEp1wACAAAAAgMEAwABAAADAgUCBgAFCQEBAwsDBAIBtAMLCgPzCgMK9RTUAgUGNtIGAAkFAAICBQEFAQIEAsM-vAIDAB8BBAsMCwAAuBAlzyXWCzUGuBwnywAHF_Ir-Ov3JebsFuorvwIxBfUPAsM18dYBAv8EAhzkAgYAAQEAAAIBAQECBgcFAgEAAQEEAAMEAAEDCgXlDQy3EAILJ9LoGwEDCwMLAt3nAgAAAQEAAwIBAgQDAAEBBgEIAAEFAAX6CQkCAQICAwMCAgSzAgALAQ8ABQAKBQgADLgCAwECAwICAQEDAwIHBAoM-AADAwQDBQQCB68AAQQBAAYFAAEIAgoEEgABBr1NswEAAQABAAEAAAEAAQABAgACAgAAAgAAAQAAAAEBAQEAAQIBAAABAQABAwEAAQAHAQICAgEAAAADAAAAAQABAQUAAwEABAEB5hoDAQIBAQO1AAEBBAoNHQMPswECAiQXDAHV_BL06gE62B3cLbYIAQECBgEFAAIABQgIBRmzAQQCCAAACgUIBBIJ9c8HBe0AARbtBAECBAMBBQMDAiHhBgAB7BgGBQcHvAUQGA3FBj_CERfUCfohJbIDAhACAQATAQIW1TPg2P4BCQcCAAMEGhHgJcgwCNvw6AIDCQQEAQMJAgIGAwgFAQUIzAEF4wABAAMBAAIBAgEAAAIBAgABAQMC9goAAAIEAAEHBgADAQADAQAIAQAAAAACAAoC0-MBAAIKAAYCAwUD_gYCAQMBBwABAwvdMsEsEt0UzTu4BQQCAQEFDgEGF88q9tUXG9op-QTPCwcq2AwIBAMLAwL2CsACCgsJAh8AAu_ZBAHuBQgHBQQHAQcHDAQIuAIBBwgHExq__QEHAQHyEgELDAAEAQECAQIEAQIDAQEBAAX7vQECAgwDBQUCBQsTAcEGAhIMBf7cGeA3B8ANChEDCBe4DgYEAgIBAQcH4DMBB7kBEAQACPAfAucfAAXIAQYFAQEyBLoBAQEAAAEBAAEDAAEBAQAAAAIAAAEDAAABAAMAAAABAQIAAgEBAAMAAAQCAQEAAAEBAQEDAwEBAwACAAAAAgAFAQEBAgG3AAAAAwEFAQADAwIEAwAGBQMFCgcGAsMBQcoHAgYNAgIHD-8IzfMAAAYFAQAEAgICAQIBBAAIAAICAAQEAQMEAQQBAQEGtwAEBgAEGeclCQUHAeQPDvnF_T3EAwcFCQQHBQMJCAECAAPeJsMACAImCc0EAhoV_vLn9ffzIgXx6wEABwYBAgMAAQACAAMDBAMBBgTYMAEBAAAGAQYAzhUHFcgCAgMBARADAgIDCwEAAeraEAEB_ijwAQ8M5wUFxwMCAAgBAAEFAAIEAAQBAPoIAgD0FQECAQECAQADBQIBAwACAAMGtwMaAuAoBQP72gIEBwMAAwkDAAQAAAMBAAkEDPoPsQIBAP0FAwEZ6QH3DQADAAAAAQEB9wwABgLdJwEEAgEAAwMAAQABAwUDAAMEA7YICSAECAO_AQIBDQMEBx8Dvw0w2RjWNckS-AABCAMpvgsAEx7LAwEHAgUb5y0DAbUJAyXcAgEBAQEEBgISAQEGBAQABgj9swUGIhYHBdEC4wIGBwAACgMFFgrbG_nONc0A_EH_yijcHRXZJOYqziDEBQMBCwECBgIBAgcDAQIDAAYECcMCBwYBBAEKFcYn4AgBBgYJBQUCBgkJ4voFAQkM6QEJ1x3XAA0EAwQBBRoCAgcBB9EGAw8CCMIDAAQGAwAAAQAAAAICAwEIAwMCCQEABgMAAwAFAwMEthET8QUHGQcD1-sRACYE4hvIEPsG5iD4KPb4FtYG6AEDIvXiPQyxAQEAAjrIBAMDAAAAAQECAQAFBAwBAQMFCAAEAgABAA7N-AABCQgFFQPb5gsFKwADvwcBAwIPEfcXAgrY3xwEBiG7AwQAAQMDBgIHCA0JBAAD5QDaDPkCB_ABAAABAwMAAQIBAQMCAgMBAAAO9wH_AwHuFgQCAAABAdUyAQAFAQECAgAEAgIC-7sCAgQEBQMJCgMGBAwCykG2DAAOBQUCAvAHGN4C5ynv80Dm2Tbf5gYEBQcgBAi8EizHN8H9AzQG5fMw1jDl994WJQjW4g4DMMQ59AbYB-kDCAM7twsGK-UKAOIp7_7tAQQBDQvSEPAJ_woPDgMBAA76_dcFAiXeBQEHBOIlAxe2DwQBAgIP_A4ADwK_BwMOAQgBGsw0Cvr38v4NywMBDwUFCgUBBgMK1wkDDAUWBbMq_QMF--_0IvUA3EHcCBsJtTDjGRoHugIuELkDAQAACwYBAgUABgABAgkEAwfvFuAnAMsDDwECDQHNAAEFBQEBAgAAAwYBCQECAQQCAQgCAgQHAdIS1AwDCAQJAwggyBPZIiXFIgL93wAWBhXY8QEj-RXEEAsCAwUFDwIC0gUSBAkR__ICFrgLBggDHAAMzQ_aAAkCAQH2DQACAgMAAQcFCQYAAQkBAAEJALkVBxcCAQvMDS_sAcoDDf8JEggIAOTyAwriJCm3AgICCQEP6CMAARnPG84BAgcGAAEI5zcQAeYcuAgeAtolDvbVCRkJAhIAAb8DCAU4uDMQxQwIChMH69gGCQEEBREHzf8EAQQBAgEAAQEEAQIAAgUABAgGAgICAAMCAQIEAgYEAbEAAgIFAgUBAAMEAQAB6SwDAQoBAAYEvkS7_QMFDAMLBQMXwRr_7Qb7DhjSJe4UIwO5Ag0BBOkV9SPmNMw1zOYBBA8FBSPALyCwEw0BFs8TNMIe4f8s5xb2B9gj8AvbBxgBBSAGzPEA9wMAEhAZAwq9GfzjFxUAGgfGBhnWAhAIAwcDBM0WN9jx60fDBhoQyQsdGL77AwgZDhHOGNwMHggFBAnQHg_NAAsKFAXG-gIBAQgDAgECBAAH_wYAAgQPAgYAAAbx0vUB_zwFCbgO-wIDBQABAgMABAEDBAUFAQQABQIDAgYDyAEJAQESAO4SCAHfHBX-1xAHDb0FCg4EFgEDyQIICwEMAAETAAkFAMkUBwrfEt0bAQYBAwQa5CWwEgQhyAAC_gMKCgMFBgMBAwIGCAYBBQK6K9MDFAYEAw0OBwYC1uQVEBu2AQACAQsDEwYJEAQAAQcBxwXnAB4Y1gIBDgILAQMEDAPBR88GHAEKuwgEAQgCAAQCAwAJBQAHCcFN2wcT98YENuEh9d8HNrEATu77AOQFCgk", + 0,43,"DAMEFAYEBQICEwEpAuUeh_qAX-8AAAAAAAAAAAAAAD7CNN3v",3,15, + "og0CAhf-9gH7FAYO8RcRUNUqAfnvLhEGCOLtBiDdFg-BuwruCQL1CPUTADQN6xX63xbZKgcC0fAh9DwDu1H69xH7FQsHGeou_RYA6A4TBwYH9QoK-xP3ABP-_gUGGPwE_gMAEfkHDZVwAAMRAVWz_AUBAQEADQH7TgAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAC_gAAAAAAAAAAAAEAAAAAAP8AAQAA_wABAAAAF-kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAACnXAAAAAAX7AAAAAAAAAAAA", + 3,6, + "s_0A_QQHBwMRBHSTAwIECAUGCPkYAgMEBRX0BgAR9RUJ9AkL_Q8G_d4WCBb-BAAO-AsLCQYEAgbyEgECAAwBL9QC_gUECAsBAQQHBf7RMQOIhwoEqWL7ChMJBf4IAQUMTsYFHPH_-QQMBjsC6wAO8Qfy8zBA5RjQEQX4IegE9Q0L9UDaFewGFwPfAhbhGf0bDAAoBOjw_gznVgYi6OEt6BAA4PopO-Yu2hTbAhkFD80GJd0gMeoZ5BcH7z_iHuf-Hd1UAY5UAfsFMvjKPP0b-QkV8_oVCAf9DfkEAfwHBQIBAxYKBv4EBP4CAQUE_bBUCRAAFewEDhlWx9gdCQkMEvAFBRICDf0ANssMJw0DVK5A6CRPkeo7CzPlCw4j3Pz1Fg39BQH-DPYH-g8K_lEAAAAAAAAAAAA1ywAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9AMMAAAAAAAAAAABGugAAAAABACLeAAAAAAAAAAAAAAAA-wUA_gIAAAb6AAAAAAAAAAAAACkavRML4gAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQD_AAAAAAEAAAAAAAAAAAAAAAAA_wEAAAAAAAAAAAAAAAAAAAAAAAAB_wH_AAH_AQAb5QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_AQAAAAAAAAD-AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_AAEAAAAAAAAAE-0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + 3,1, + "AgcFCop-BgAEBQWTgvr9C_0J_QYE_A4IG8BM9w4TIfOwSwBK-fEK7BAlK9zrACsHLyEBDPb6JfMOAuwjABD-ChudWQsHBAH6EAMEAAkDBgIBAg_xBQIiEQoDAQr7EwH7-wYFBAX8EQEABAUMAQUPAAcEBwT8_iH6AfMTAhIEAgYPD_oF-g34CBEPE_zynl0gCQFEwvv1Ag33_v4zBfv8IAYCEPz9H_oOAQ7SJgQMAwX-AwQPBgIVDv73CRoADP78DQj8CgIB4i0AA0HCICAABQf-Bgz5_AAG_gYAAgQB_AMDBQQFU_6uBQQSAwoIBgMB4CEEAAEHCwUDC_78Cv0I9Rb6_gcHBA4ZJOgT-OvVSyE-uPYY5CLp-RX66Cof5igM5-r7BhXfIN0p_u0nC1mbFukW-gD6FONV1ify4DvMCO4idMfw7wAI8wUIHdn1GwA49un-IvT87wcIBAEuA1kAAAAP8QAAAAAAId8AAAAAAAAAAAAAAAD2AAoAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA_wEAAAAAAAAAAAAAAAAAAAAK9gAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAD_AQDyDgAAAAD9AwAAAAAAAAAAAAAAAAH_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAABAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD_AQAAAAEAAP8AAf8AAQD_AAEAAAAAAAAAAAAAAAAAAAA", + 3,-32, + "awj69Qvt_fUhI_zwJOcF7wYZAh39_i3Q-gLzEK1TGPwSA_kK_f4BAQcAA_4HBgICCAMBAQANDA8E9wQHEwUG9BMAAj2uEEL56RMvxg3zE-_99wTTLULhAjXaBeYFWu0OzjJG9_Eqyizr-RUVtf1UKtYFHOUII81RHdEMEg_m-RDmVwcG19tq_RED3jMd9_IB8xzpLvUh1gDKNgs8yf39BwX8GgPoHv4HCAAB_gES_A3-9woF_hQFCQAGEAMLCwsC-gIHBQj9BgAPgJf493fBAP3nMvQE9xz-BgIA9gINEgQF-voTBCP3D_T9B_MdAwVepgIGBAEXBgcHABD1EPYK9v4OFwH4CQAk5jjS7SH-GvrjMTfEN8Y1ziv5_gQLyhT3ILSBJ-IWDOQbZHctCRMHH-8d5gj95yoKukDqGVR98ILIPc9JA7oqwAYS7WDb8dILQdPmDjgB7wj9pLL95Bvy6CnvyjrIG9Yw_P4j6Ef7Ie4BEeoPGeES3QfjhmIO-_geKQkZGOMK7vj0HatszibWHgeuYe8wx2XDQc4a9gzh7-lt_BLjHQDzf6MH_vX6-DHyDcovDxAJEOMXAxrtGP6kXLRY-wUGCPoGAwEWAAUAA_4JCvwIBQUAAwL-AQMECQQHCwz-B_vOSQoABgj-OvYMBxcKDOYZ4ukKHv0zLOHpGe0X0AIM-yAT6RA0Lej0EfrgG_3e-VYv0PUe3zQGTqBzG_SqER7RDSXx7Rvp8jTeCvAUAz5Av-pY7N7kR79K1tEj9hPV2h0aSSftMO0b6fEU7SEAuRUc3KHPOp8LBUCyPr1CmXHU447z_Qj-7uuXeRT52zUCMKNM7_0CFAzjNPUW5wMY_OwtAe4W7w3uHP5ZqPoGEA3zHhE1-BxBugv6-jDrEfsv8x78S-8y3fvpCRUia4gQEgMq4QQT9gr5EQv6DQb8BQ0CCgwE_gMBCAACAAUEDBsJA_4FCgMLBBH4EAL9CQMP_QAX_RcH8hH5Bhb6-fsYDwCIfhL9Bwf8Bf5N6hrsBCQI78NiabXSOQca6R_55xoMBvIGCwcMEggiBAQc7gIDAQQD_QAG_gz-AQYB_gf9CgcFDwcI_P4R6hMO-gIDAQr9DwDsFf74EQUCB_0e8A_xB_oD9Bv8BwYJ-h8A_ATuCfcAFwH7FQdhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHuIAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv4AAAAAAAAAAf8AAQAA_wABAAAB_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAH_AAAAAAAAAf8AAAAAAAAAAAAAAAAAAB7iAP4CAAH_AAAAAf8BAAAAAAAAAAAAABDwAAAAAAAAAAAAACbaAAAAAAAAAAAAAAAAAAAC_wD_Av8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAMNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_4AAAAAAAAAAAAAAAAAAAAAAAAAAv4AAAAAAf8AAf8B_wEA_wH_AAAAAQAA_wAB_wAAAQAAAAD_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyDgAAAAAB_wAAAAAAAAEA_wL-AAAB_wH_Af8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc5AAAAAAAAAAAAAAAAAEb5AEAMNAAAAv1LdMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADPOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEb5QAAAAAAAAAAAAAAAAAAAAAC_gABAP8AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAB_gAAAf8B_wH_AQD_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA_wEAAP8BAP8BAAAAAAAAAAAAAAAAAAAAAAAAAAH_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3iMAAAAAAAAAAAAAACvVAAAAAAAAAAAAAAAAAAAAAQAAAP8BAAAAAAAAAAAAAAAAAAAAAAAAAP8BAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAABAAAAAA", + 3,-8,-1,1,15,1,-5,1,10,2,11,1,-3,1,21,1,-5,2,8,3,5,1,-4,1,4,-3,-1,-3,-1,-3,-3,-2,1,4,-2,-2,1,7,1,-4,2,5,1,21,-3,3,3, + "wgoI-wsCAwECRMsM_vwk-vkGAPQbAA4SDQLvCRn--hT8BQ79EQUCBfwA_QsFCQIBBgoNDwUT-QkaSOUR9R3xFhH0BCH0BAjp_QgEIfryIvYSCv4HEv4UH_YH-vr9JgQKEgmjXgMEBQAOCxEE9AEkBAoABv5gsAkC-AsT8RcABjPSCAMKDv0C_RIe5wUO_vrDQwICAQX9BQACAwADBgIRDPr7LOQABBbyDRkpiUi9QPgv7w7yCAD6AS76Bu0O_fAG_M07MfUKAuQRFgsnAtH-ep8GC98DH_XoLAMC9BfzEQ72EPrwDwcGBPEOBggNDBMI9Aj1Bgr-_vwKAwIE_BX5CQVYswIBAQML-xn49DoF4gMM9RAs4vcj9QXgEy_10TPtHR7z9BER9e2RZAws2-YQJwQG-Rz27iMEGP3wHu3pARYjH9T5Awnz-gcs9fgH-gAe8P4S_gdRpzDQCAACBf0CAAH3DACbAQp2AAAAAAAAAAAQ8AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH_Af8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAACbaAAAAAAAAAAAAAAEAAAAAAP8BAAAAAAAAAAAAJdsAAAAAAAAAAAAAAAAAABbqAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA_wABAAAA_wABAP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_hAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_AAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8BEe8AAAAAAAAAAAAAAAEAAA", + 3,6,2,1, + "Vf4DBgAHAP0QCQP8BP4EBwn-_AgLAgb0BwG4UwADCv4MBAIJBeIp_QYGBQACBAYW-w77CwUBBAIFCv79BQIDAQQB_hX3BhLiGy4J8wPmFfsy5QEpDfkLGz-69xT9qnT89gANDgQB9QEd9A7-uzMVBgQI-QQCAfcOAwMH_u8RBAAGEgACAgACAQICAgUSAQz6DBj-BPwEBP0FAQDCQgUABQ4EGPMb8DQB-_Ih_gaYb_f95CfVLM9b_uEb_g74FvTp--sAbBQP9ALzjGr4AvE4vQEq6B5LHtfiLgXUMrU1D9gRGhT9nHrN9HG8ER0p8vNBwBPm3OVCCbuUl1YF3znz7R718AQPyn_d9CIAE_L1_udDIvTv-MBICSoj4wj4HcQmBk6cFNoGETjwFOkWBAcH9hwQCPfy-wsb9xUODQf-CgcJIQ8FAOAAKfgUAekYWYcoCQoC8vsTIvMB9wL3FfcD6xApCvcD6QPwRf4Y0wEl4hAF6vkPBpqc_OIsG_ECDwXUGO4T_vQzAu0u_fD3ABbDPgT-DP4PBALtEwj9DwYEAwgV_B_WBze8DxT6G-oI6hYLDvERAA8DAAMbCPn38wkRB_0IL9oGBAAVAvb6ARPQQv0H_Qj8BAQCBgQEAQgECAf8BQICBwIBABkBAAkMAwoS-fsOAQcQChn28wEz8P71IvwBI_jvEwDzCCAI9BcQB_P8DCLLARTm_DD6EsY0-QYIEnd6BBLpGAoC_voMBP4Q8wwCBAgCCwEDAAICAJ8G_QgDAQEEDAkLAQcG-wQCAAXnG4SP_BL0APoHEfgi_vYi_AAIAAT8B_0CPcS5RgFQBQMBDRco-_sUCvv1Du8eAPMDGAsA9R0A8Q4i8voDFfwBAgP3EAr7yTjxIPsJBAX9_gb-CP0CBBD2CgMV6gwGAgIPBxj-7xIL-g_8BvkIAvvwGQwH_Qv8-w38_AcIBH8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADPQAAAAAAAAAAAAZ6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0S8AAAAAAAAAAf8AAQAAAAAV6wAAAP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQD_AAAB_wH_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_AAAB_wH_AAH_AAEAAP8BAf4BAAAB_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wABAAAAAAD_AQAAAAAB_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA_wABAAAAAADIOAAAAAAAAAAAAAAAAAAAAAL-AAAAAAAAAAEAAAAA_wEAAP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wAAAAAAAAAP8QAAAAAAAAAAAQD_AAAB_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_AAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wAAAAABAAD_AQAAAAAM9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAADWKgAAAAAAAAAAAAAAAAAAAQAAAAAAABLu_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + 3,5,"nAIDCQEHIgr8BwSXbBDzABYDC-sQ9_QbDv4Dvo8AAAAAAAAAAAAAAf8B_wABAAAAAAAAAAAAAP8",4,86, + "Djr0FwEFCQYGMckP-gP-Cf4FGAYBAywBY5ImDwYY_RkLAQoBAwn-GP34HwgD-gr-BQUABwEEBQgB-SD4ACfgFBfo-0z47QMa40ypCwRL-fwHvnTp_TEl6knp6gj3CBb6BSADG_HnWfsA5iQcABD88uoZ8vcbNfn-7wMIJfQJ6xgGEPEWBAH7C75GBAEF3CEBAv0CBAIJAQEABgf-BQ7-_QQLK8wJ_gj-AQUEA_w-BgUAEgkC-yvkAf4BBgv5IAr8ARL8CQD9AwEBABT8_QN_jjDHIwoBAQr6Av0GAgoFBQgDAAUBAfkGEgMDAQFpmAUHC_YE-AsEAwALC_38DwAOAgECEBBhouwW_hn8K-v8FQUICPsfkAAAAAAAAAAABvoAAAAAAAAAAAAAAAAA0i4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAP4CAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA2iYAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADzDQH_AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7RQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI-OMdAAEAAAAAAAAAAAAA", + 3,3,-2,1,-2,1,54,1,4,-1,1,4,1,13,1,-2,-2,1,34,-1,1,23,1,5,1,8,-1,-3,1,8,2,-5,1,5,1,-5,1,11,-1,2,14,-3,1,6,1,-5,1,10,1,-6,2,5,1,-7,1,8,2,65,1,12,2,7,1,13,1,34,1,-5,-1,1,-6,1,-8,2,27,2,2,1,8,1,-4, + 1,8,1,13,1,-11,1,-36,1,54,1,17,1,11,1,13,1,-4,1,-3,-2,1,-6,1,22,1,-9,1,13,1,-5,1,7,-2,-2,1,-2,1,4,-1,1,-2,1,66,-2,1,11,-3,1,14,-1,2,1,2,9,2,2,-2,1,8,1,-5,-2,1,5,1,-4,1,5,-3,1,10,1,17,-1,1,4,2,2, + -1,4,1,2,3, + "MhH-C_0AAgYbHu8NBAAHAAcLCwnuDAgBABD-Ae8MWLf-_iT-9An4-QEJ9_kp7An-_A4W6hP3GwUGDgFuBAMY_uIXAiP7iHP7JND8Lv3-BwEUAAXs_ggYFv0jwwofCQQIEfz5_AELCPIW-STtBgENHAACVgMDAwYCAAUC-wsHAw7xArNqmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAPkH", + 3,1,-3,1,7,-1,1,-2,-2,1,4,-2,1,6,1,4,2,1,-1,3,1,2,9,"t10LChELBwEOdikAAAAAAAAA",3,-5,2,4,"bP0M-gMeBgOOl5EKd7yfAAAAAAAAALkRJ-TdIA",0,464,"$j",0,2,10,-20522,"4gEi-v8AAAA",0,2068,10,-56723, + 10,-26,"4gEi-i7kChP_AAAAM-8AAQ","$j" + ], + "jis0212": [ + 0,108,"2O7wIAPRK_6DJQACAP4CAP4CAP0EAA",0,8,1,-741,1,4,1,24,0,38,"uu_-BHOBcQAAAAAh3yE",0,359,1,-7569,3,1,1,31,0,1,1,-31,0,1,-1,1,28,0,1,1,-29,0,4,4,28,"ysU79Qr95B0DAAAAAAAAAA",0,35,11,51,2,1,0,35, + 11,66,2,1,0,94,1,-922,1,73,0,1,1,21,0,1,1,11,0,1,1,14,1,-3,0,1,"So15Af8B",0,1,1,19,1,-137,0,16,"5ireNgkBBAn9CAGsWouHlgAB_wEAAAAAAAAA_wH_Af8",0,46, + "wf4D_T_KMgPA_UIBA7pCA7r-Av5P-_sFAAAAAAEAAAD_AAEAAP8BAP8AAAABAAAA",0,1, + "HAED_QOo_gL-AGD5A_kLAQID_QcD_YsB_gP9_H77iH4D_QMBA_0F_Xf-Av6QZpz5B_v5bgP9-55omv0CA_0BAAAAAP8AAAABAAAAAAAAAAAAAAAA_wAAAAABAAD_AQAAAAAAAAAA_wAAAAEAAAAAAAAAAAAAAP8BAAAAAA",0,7, + "4f4D_SDKMgPf_SMBA9kjA9n-Av4w-_sF2ycBAAAAAAEAAAD_AAEAAP8BAP8AAAABAAAAAAAA",0,1,-1,-3,1,-57,1,-2,-2,1,-2,1,225,0,1, + "KwP5CwECA_0HA_2qAf4D_d1--6dfA_0DAQP9Bf2W_gL-cWac-Qf7-W4D_fuehwF3AgP9AQAAAAAAAAAAAAD_AAAAAAEAAP8BAAAAAAAAAAD_AAAAAQAAAAAAAAAAAAAA_wABAAAA",0,383,1,19589,2,1,1,6,1,5,1,12,2,3,-3,-2,3,2,1,4,2,10,-2, + -2,1,9,1,8,-1,1,6,2,4,2,10,-3,1,5,1,13,2,8,1,5,1,17,1,9,1,9,1,12,2,9,3,4,1,5,1,6,-1,-1,-1,4,7,2,1,1,4,2,2,1,5,3,2,-1,1,20,-2,1,46,1,-46,-1,-1,-1,-1,-2,-1,-1,2,5,2,1,1,5,-1,-1,-1,1,6,-3,1,6,-1,-1, + -2,4,5,2,2,2,2,2,1,2,3,-1,-1,-1,3,1,-2,2,1,2,3,1,18,1,4,-1,4,1,2,1,2,3,2,1,3,1,-1,-2,1,9,-3,-1,1,13,-1,2,9,3,1,-2,-2,-2,-1,-1,-1,-2,2,3,4,2,-3,1,4,1,6,-1,2,1,-1,3,10,2,2,-3,-1,-1,3,2,-3,-1,2,5, + 2,1,2,2,-2,-2,2,2,1,-55,1,69,2,1,-1,-3,3,3,3,1,-1,2,4,5,1,1,7,2,4,2,8,-2,-2,2,2,-2,1,4,-1,-1,2,2,-3,2,3,-1,-2,-1,-1,2,1,1,5,-1,1,4,-3,-3,1,4,3,2,4,2,1,-29,1,29,1,6,-1,4,1,1,4,2,3,2,3,-1,-1,3,1, + 2,2,1,8,1,7,1,4,-3,-1,2,1,1,6,1,4,-1,1,23,2,4,1,6,-2,1,9,1,4,-3,-1,1,9,1,10,-1,-1,2,1,-2,1,5,1,6,3,1,-1,-2,1,5,-3,-2,1,8,3,3,-2,2,9,-2,2,12,2,1,-1,1,9,1,5,2,8,-2,1,6,1,8,-3,1,11,2,1,-1,-1,3,2,1,4, + 1,7,3,8,1,6,-1,-2,1,4,-1,1,6,4,1,-1,-1,4,7,2,7,3,5,2,1,-1,-2,-3,-1,-1,-3,-2,-1,-2,-1,2,4,1,4,-3,3,2,-1,2,3,-2,2,1,1,8,-2,3,6,1,4,-1,1,4,2,2,2,1,1,5,3,1,3,1,-2,-1,-2,3,6,-3,1,9,1,-2,1,13,-1,1,5,-1, + -1,2,6,1,4,1,6,1,4,1,4,2,3,1,5,2,4,1,4,-3,-3,-2,2,5,-3,-2,2,1,2,1,-1,-2,-2,1,4,1,9,2,2,-1,1,4,2,2,-1,2,5,1,13,1,12,1,16,1,6,1,6,2,5,-1,1,4,-1,2,2,2,13,-2,1,5,-1,1,14,-3,-1,2,1,-1,-1,2,1,1,5,1,10, + -1,-1,-1,2,2,-3,-3,2,3,1,5,-2,-1,2,4,2,1,2,2,-2,1,5,3,1,-3,1,6,-3,2,2,1,17,1,9,-1,-2,1,6,1,5,4,1,-3,2,2,3,2,1,6,2,20,1,6,2,2,3,4,-3,1,5,2,1,-2,2,2,1,6,2,1,-2,2,1,-2,-1,1,24,2,1,-3,-1,2,5,4,1,-2, + 2,11,1,8,1,4,1,12,-1,-1,-2,-2,2,1,-1,3,2,2,3,-2,-2,-3,1,6,1,12,1,8,1,5,-2,-1,6,2,1,6,1,18,-3,-2,-1,-1,-1,3,1,3,1,2,1,-1,-2,-1,-1,-1,1,4,1,9,4,1,-2,-2,-3,-1,2,1,-2,2,14,-2,2,2,1,8,2,3,3,2,4,6,3,1, + -3,-1,-3,1,6,1,6,3,3,2,3,2,-5,1,11,2,2,-1,-1,5,2,1,8,1,-7,-1,2,8,2,9,1,4,-2,-1,1,4,-3,2,4,-1,-2,4,1,2,3,-1,2,1,2,3,3,8,2,5,2,5,1,4,1,15,-2,2,1,-2,5,1,3,1,-1,4,1,-1,-2,-1,1,8,1,7,-2,2,1,4,1,-1, + 1,-13,3,17,-2,1,11,1,4,2,9,-3,-2,1,5,2,7,1,5,2,1,-1,-3,-2,2,4,-1,3,4,2,3,2,3,1,-41,2,42,1,13,3,2,2,5,1,5,1,4,1,6,1,5,1,9,2,2,2,1,1,4,1,9,-1,-2,2,2,1,15,-3,3,2,4,5,2,1,2,1,-3,-1,1,6,3,2,-3,-2,2,7, + 1,17,1,-9,1,5,1,5,2,4,-1,-1,-1,-1,-3,-2,2,3,1,6,1,9,2,17,2,4,3,5,1,11564,1,-11557,-3,2,1,-3,2,6,-2,2,1,1,8,-3,-2,2,11,1,5,-1,3,1,-1,-1,1,7,-1,-1,-2,2,2,-2,2,1,2,14,-1,-3,-2,-1,1,7,1,4,-2,4,5,-2, + -3,-2,-1,1,4,2,1,-3,-1,-2,1,4,3,10,2,3,-2,2,6,2,1,-1,-2,1,8,-3,3,7,2,3,1,10,2,4,2,2,-1,-2,-2,2,19,2,1,-3,-3,1,4,1,8,1,4,-1,-1,1,5,1,9,2,2,-2,1,12,1,4,-2,-2,-2,-2,3,1,-1,1,4,1,4,3,4,-1,-2,2,1,-3, + 1,4,-1,-1,1,6,1,10,-1,-3,1,4,1,4,-3,2,6,1,6,2,2,1,6,1,14,1,28,1,-28,-1,-1,-3,-3,1,7,1,10,1,8,2,9,1,5,-3,1,7,1,9,2,5,4,12,-1,-2,-1,-3,-3,2,1,2,1,-1,2,17,2,2,-1,2,1,1,4,-2,-1,2,3,1,11,-1,5,6,1,5, + 1,14,-1,-2,1,8,1,14,1,10,2,6,-3,-2,-2,2,1,-1,-1,-1,2,2,2,34,-1,2,5,3,3,-3,-2,2,3,4,4,2,9,-1,1,4,-2,1,10,2,1,2,1,-2,-3,1,7,2,1,1,4,1,14,-1,1,6,1,10,1,-7,1,22,2,2,-1,1,12,1,4,1,6,1,4,1,24,2,-9,2,1, + 1,9,-2,1,4,-3,-1,2,2,-2,-1,1,12,1,-5,1,7,1,-16,4,20,-1,1,5,-2,-2,2,8,2,3,-1,-1,1,4,-1,4,7,-3,-1,2,3,1,6,-3,1,4,-3,2,3,1,9,-3,-3,1,4,1,-3,2,9,1,6,-3,1,4,2,14,1,6,1,6,1,5,1,4,2,1,-2,2,6,1,13,1,-7, + 1,9,-2,1,8,1,12,1,4,1,-8,1,7,1,4,-1,2,2,-1,1,9,5,1,-1,1,15,1,10,-2,1,19,2,1,-2,-1,-1,1,4,-1,3,9,1,6,1,5,1,-2,-2,2,2,2,1,1,6,-1,1,6,1,5,1,22,3,3,1,5,1,10,2,2,4,3,-3,2,2,-1,-1,-3,-1,1,4,-1,2,1,2,3, + -1,1,5,-2,-3,-3,-2,1,4,2,2,-2,1,7,-2,2,1,-2,-1,2,2,1,10,-3,-1,1,6,2,5,1,4,1,4,-3,1,-8,1,7,3,2,1,6,1,11,3,2,-1,5,4,1,9,2,2,3,5,4,1,2,2,-2,-3,-1,1,10,-2,-2,2,5,2,2,-1,1,4,1,4,1,8,1,5,-1,1,10,3,6,-2, + 1,4,-2,2,1,1,5,-3,1,5,1,9,2,12,-2,-3,-1,-1,-3,-2,-1,-1,-2,2,4,-3,2,1,-2,2,7,1,5,-3,-2,-3,-1,4,3,2,2,2,4,-3,-1,2,1,-3,-2,1,12,-2,-2,2,3,1,4,1,4,-2,-1,5,3,2,1,-1,-2,-1,-3,2,7,2,4,3,3,-1,1,7,2,3,-2, + 1,20,-1,1,11,1,5,1,5,2,2,3,2,2,1,1,6,-1,2,4,2,3,2,3,2,1,1,4,-2,-1,-2,2,10,-2,3,3,2,11,1,5,4,6,2,1,1,4,-1,1,-5,2,6,-1,1,17,2,1,-2,1,11,-1,1,6,-3,2,1,-3,-1,-1,1,13,-3,3,4,-1,1,5,3,3,-1,-1,-3,-1,1,7, + 1,8,-1,-3,1,6,-2,4,15,1,21,-1,1,10,2,2,-2,2,3,1,4,1,9,2,6,-3,1,15,1,7,-1,2,7,2,5,2,5,-1,-2,-2,-2,-1,2,16,-2,2,7,-2,-2,4,4,-1,2,3,-2,3,3,-3,-2,2,9,2,5,-3,2,2,-2,2,3,-1,-2,-1,-2,-2,1,5,2,3,2,3,-3, + 1,5,-1,3,6,1,13,-3,-3,-2,1,5,-2,3,1,1,6,-3,1,4,1,4,-1,2,5,-1,2,2,2,15,1,5,-1,-1,-3,1,5,-1,-1,2,1,2,3,2,4,1,4,1,7,-1,1,11,-3,4,1,4,5,3,1,-1,1,9,2,5,1,6,-1,1,7,-1,3,7,2,6,-1,-1,-1,-1,-1,-2,-1,-3, + 1,6,3,9,1,4,4,4,-1,2,1,-3,-1,2,12,2,3,-2,-2,1,4,-1,-3,-3,-1,-2,3,3,1,4,2,3,-1,-2,-1,2,2,-2,-3,-2,1,4,-2,1,8,2,1,1,5,-3,-1,1,6,-1,-1,2,10,1,6,-3,1,14,-2,-3,-3,1,4,1,7,-2,-2,1,4,-2,-2,-2,1,7,3,3, + 1,10,-2,2,5,1,4,-1,-3,-1,-1,1,6,1,16,-1,2,1,-3,3,4,-3,2,3,-3,2,3,2,2,1,6,"$9",1,19,-1,1,5,1,-3,1,8,2,4,-3,-1,1,4,1,-4,3,8,2,1,2,3,1,153,3,-146,1,17,1,-12,-1,1,9,3,-9,-1,1,4,1,-5,3,14,-2,-1,4,6, + 2,2,-3,1,8,2,3,-2,1,5,2,3,2,1,1,4,-3,2,1,1,4,1,6,-3,1,8,2,2,-1,1,11,1,10,-1,1,6,1,4,1,5,-2,-3,-1,1,16,1,10,1,6,2,1,-3,2,7,1,7,1,8,1,5,-1,1,5,-1,1,4,1,5,-2,2,9,-1,-1,-2,2,1,-1,3,20,-2,3,5,1,59, + 1,-58,2,1,-1,2,2,1,8,1,4,-1,-2,1,4,1,4,1,9,-1,2,3,1,90,1,-63,1,4,-3,-1,1,8,1,-2,2,4,3,1,-1,1,7,-3,2,4,1,4,-1,1,8,2,1,-2,1,15,5,2,-2,4,3,1,5,-1,-1,-1,1,13,-1,-1,-1,1,4,-1,-1,2,3,-3,-3,1,8,1,9,-2, + -3,3,2,-1,-2,-2,2,2,1,7,-2,4,1,2,2,2,3,3,4,1,8,2,2,2,5,-1,2,2,1,25,-1,-1,-2,-2,1,6,-2,-3,1,4,1,8,-3,4,7,2,1,-2,3,3,2,7,2,3,1,12,1,4,-3,-1,1,8,2,3,-1,-2,-1,-1,2,7,-1,-1,1,8,-2,1,8,2,4,1,10,-2,2,8, + -1,-1,-1,1,8,2,1,-1,1,11,-1,-3,1,4,-2,-2,-3,-3,1,7,-1,-1,-2,-3,2,2,2,5,2,2,-3,3,1,2,2,1,4,1,8,-2,-2,1,6,-1,1,10,-2,-1,2,2,-1,-1,1,5,1,9,3,1,1,5,1,5,3,3,-2,3,8,1,6,-2,1,-2,-3,-3,3,3,2,5,1,6,-2,1,4, + 3,3,2,9,2,4,2,2,-1,3,5,1,5,-3,-2,1,5,-3,2,2,-2,2,5,1,4,-3,1,6,-3,-2,1,4,-3,-1,1,4,-2,1,6,-3,-2,-1,1,4,2,7,-3,-2,1,17,-3,2,3,2,1,2,4,3,2,-1,2,7,2,3,2,4,1,4,-2,1,9,-3,1,6,-1,2,2,1,6,-2,1,5,-1,1,5, + -2,2,1,-3,2,3,-1,-1,1,6,1,5,3,6,-3,-1,1,4,2,1,2,3,-3,2,10,-1,-1,-2,-1,1,4,2,1,1,14,-1,-1,1,4,-1,2,1,-1,3,9,-1,2,10,2,1,-3,-2,1,16,-1,-1,1,13,-3,1,6,4,1,-1,-1,-3,-1,-3,1,6,-1,2,1,-1,-3,-1,1,15,-2, + -2,2,3,-1,-1,1,6,3,11,1,-194,2,198,-1,1,7,-2,-2,1,23,2,6,-1,-3,-1,2,7,1,11,1,5,1,4,2,9,-1,3,1,1,17,-1,1,7,-2,-1,-3,-1,1,4,-3,-1,2,3,1,6,1,4,-1,2,1,-1,-2,-3,2,5,-3,-1,1,5,-3,-3,1,25,-3,1,4,1,10,-3, + -2,2,1,2,7,2,2,-1,-3,4,1,-2,3,4,2,3,1,4,1,10,1,7,-1,1,15,1,5,1,5,1,6,1,6,2,5,-2,-1,1,7,3,3,-1,2,3,-1,3,2,1,27,2,1,1,10,-1,-1,1,6,-3,-1,2,1,1,8,-1,2,1,1,10,2,2,2,4,-2,-2,2,4,1,-16,1,33,3,1,-3,2,1, + 2,2,2,2,1,5,-3,2,16,1,4,2,3,3,2,-2,3,1,-1,-3,2,4,4,4,3,5,2,4,1,5,1,8,2,1,-1,1,15,-3,2,9,1,6,1,4,-3,2,2,-2,3,4,1,5,1,9,1,8,-2,1,11,1,4,-2,-1,-2,2,6,4,3,2,8,2,7,1,-17,2,21,1,6,-1,2,6,1,7,-2,2,3, + 5,13,-2,1,8,1,6,2,4,-2,-2,1,18,1,6,4,1,-1,-3,1,7,1,21,5,8,2,3,-2,1,14,-1,1,10,-1,3,1,1,6,1,8,3,3,2,2,1,4,-1,1,4,-2,-1,-1,-1,1,7,1,16,1,6,1,4,-1,1,4,1,5,2,7,1,4,-1,2,12,2,1,1,6,3,4,-2,2,6,1,6,-2, + 2,2,-1,1,27,1,5,-1,3,6,1,9,-3,-2,-2,-1,1,4,1,6,-3,1,4,2,3,3,7,-1,3,8,-2,2,1,-3,-1,-1,-1,-2,1,4,-2,2,2,-1,2,5,2,2,-2,1,4,1,4,2,3,1,4,1,7,1,12,2,4,-2,-2,1,9,-2,1,5,-1,-2,2,8,-1,1,6,1,5,2,13,2,5,-2, + -3,2,1,-1,-3,-1,2,4,2,4,1,4,-3,-1,2,2,-3,2,4,-2,2,4,-1,1,5,1,9,-2,-1,-3,-1,4,4,2,5,-1,2,1,2,1,-1,1,5,-1,-2,2,3,-1,2,1,1,7,-1,-2,-1,2,1,-3,3,1,-1,2,2,2,3,-1,1,7,-1,-1,2,2,-1,2,5,-2,2,1,-2,2,2,-2, + -2,-3,-3,-1,2,2,-1,2,10,-1,3,1,-1,3,1,-2,-2,-2,1,6,2,8,1,8,-1,10,1,1,7,1,6,2,2,2,1,-3,-1,2,3,1,4,1,5,1,4,3,3,-2,2,1,2,2,2,13,3,3,-1,4,5,3,5,-1,3,2,-1,-2,4,1,2,2,2,1,-2,-3,-1,-3,2,8,-2,-3,-2,1,4, + 2,1,2,2,1,4,-3,2,1,-3,1,4,3,5,-2,1,6,1,11,2,3,2,8,-2,-2,2,1,1,4,1,6,-2,4,3,-2,2,3,1,5,-1,-1,1,4,2,6,-1,1,13,-1,6,7,-2,-3,1,10,2,1,-1,-3,-2,1,5,-1,1,15,1,5,3,4,-2,-1,1,5,2,1,1,7,1,4,3,2,-2,-2,1,4, + 2,1,-1,1,7,1,6,3,1,2,2,-1,-1,-2,2,2,2,1,-2,4,1,1,4,2,1,-2,-3,2,4,-1,3,2,-1,1,13,2,-11,3,1,-3,-1,1,9,-3,1,5,2,4,3,7,-1,-2,1,12,-3,2,6,1,7,3,5,2,1,7,1,-1,-2,1,15,-3,-3,-3,2,1,-1,1,5,1,4,1,6,1,5,-1, + -3,2,3,1,4,-2,-2,-3,1,5,-3,-3,-3,2,1,-1,2,1,-1,1,5,1,5,3,4,3,4,-2,2,3,-3,2,2,-3,3,2,-2,2,3,1,4,3,1,-1,-1,-2,-2,-1,-3,3,1,1,5,-2,-2,-3,2,7,3,6,-3,1,4,-2,1,4,-2,2,3,-1,-3,1,8,1,4,1,5,2,7,-2,-3,3,4, + -3,-1,-3,-1,2,3,-2,-3,-2,2,9,-2,2,3,-2,1,11,3,3,2,9,-1,1,4,-1,2,11,2,2,-3,-1,-3,1,9,-1,2,1,2,1,-3,-1,-3,1,11,-3,1,11,1,4,1,4,-3,1,8,3,-5,1,4,-3,2,3,4,2,1,7,-1,-1,3,7,-2,-1,2,3,2,1,1,13,1,-10,3,3, + 1,4,-3,2,7,1,12,2,-11,2,2,-3,1,6,1,5,-3,1,9,-1,3,1,1,4,-1,-1,-3,-3,2,2,1,5,-1,-1,3,4,2,3,-3,-1,-2,-3,2,2,1,10,-1,-1,1,6,1,6,2,1,-1,2,12,1,4,4,1,-1,2,2,1,4,2,6,-1,-3,-1,-2,-3,-2,1,6,-1,2,2,-1,1,4, + 1,4,-1,-3,2,2,-1,-1,-2,2,4,-1,-3,1,6,-3,2,5,-3,2,1,-1,1,4,-3,1,5,-2,-2,1,5,-3,-1,2,1,2,3,3,2,2,9,2,1,-3,2,8,-2,2,2,2,1,1,4,-1,-2,-2,1,7,-2,1,5,-1,-1,2,2,2,3,2,4,-2,1,9,-1,-2,1,8,1,6,-1,-3,2,1,1,9, + -2,-2,-1,-2,1,9,2,12,2,1,1,4,-2,1,6,2,1,1,8,1,12,1,10,-3,-3,3,1,5,1,-2,1,8,3,1,1,5,1,6,1,6,1,10,-3,-1,2,2,-2,-1,2,2,-3,1,12,1,4,1,4,2,1,1,4,1,4,-2,-1,1,4,1,6,2,2,-1,2,2,4,3,1,4,-2,-2,-1,1,9,2,1, + 3,1,1,12,-1,1,7,2,1,3,2,-1,-1,4,2,-1,-2,2,1,2,1,1,9,-1,1,4,2,4,-1,-3,1,4,2,1,-1,2,2,1,11,-3,1,10,3,-5,6,5,-2,-1,-3,-1,2,3,-1,-1,1,6,2,2,2,8,1,7,1,4,1,9,-1,1,5,1,9,2,5,3,2,-2,1,4,3,2,-3,-1,3,3,-1, + 2,1,-2,1,8,-2,-1,1,9,1,13,3,3,1,5,3,1,-2,2,6,1,4,-2,-3,-2,-3,3,10,2,1,2,5,1,4,-3,-1,-3,2,1,2,1,1,7,-1,-2,1,5,1,7,2,1,-3,3,1,2,1,-1,3,2,-3,2,4,2,5,2,7,-2,1,8,2,2,-1,5,8,3,5,1,8,-1,1,38,1,-31,2,2, + 2,3,-1,-3,2,3,2,2,1,13,2,7,-3,-1,2,4,-2,2,6,2,3,-1,-3,-2,1,8,2,4,-1,1,6,-1,-1,1,5,1,6,2,1,-2,1,5,2,2,-3,1,4,1,5,-2,2,4,-2,-2,-3,-3,-2,-1,2,2,1,157,1,-2,3,1,2,3,-2,1,7,2,2,3,7,-3,4,1,1,6,-3,4,11, + 1,10,-1,3,1,2,4,1,4,2,4,-3,-3,-2,1,6,1,7,2,2,-2,1,4,2,5,1,11,-3,-3,-1,-2,-3,2,1,-2,1,7,3,2,2,7,-1,3,2,-1,2,1,-1,4,6,-3,-1,1,5,-1,-1,2,3,-1,2,1,-1,-1,-1,-3,1,27,-3,-1,1,6,-3,-3,1,11,1,6,1,5,1,13, + -1,2,7,-3,2,12,1,14,1,4,-1,-2,2,1,2,1,1,7,2,12,-1,2,1,-2,2,2,-3,1,4,1,7,3,10,-3,-1,-1,-3,-2,1,4,-3,1,4,1,4,-1,1,8,-1,-2,-1,1,5,1,4,2,8,3,5,-3,-1,1,7,1,9,1,14,3,-13,1,4,-2,1,7,-1,-2,-2,-3,1,11,-3, + -1,1,6,1,15,1,-9,-1,1,4,2,3,1,5,-1,-3,2,1,-2,-2,2,6,3,3,2,2,2,1,-3,2,1,-2,1,11,2,3,2,4,-2,2,3,1,5,1,9,-1,1,5,4,8,1,4,2,2,-1,1,4,1,5,-3,-2,-3,1,5,1,6,1,6,-1,3,1,2,1,-2,2,1,-3,-2,-2,-1,-1,2,1,2,4, + 2,1,4,2,-3,-1,-1,-1,-2,-2,-1,2,1,1,6,1,9,1,4,1,4,1,5,-1,-1,-3,-1,-2,-1,2,6,2,5,2,1,2,5,2,1,1,72,1,-58,3,1,2,1,3,9,-1,-2,-3,-2,2,1,3,4,-2,2,5,-2,3,3,1,24,1,7,1,4,2,1,-1,-1,-1,1,6,1,4,2,1,2,2,3,1, + 2,8,-1,-2,3,17,1,6,-1,3,5,-2,1,8,1,-139,1,148,-1,1,11,2,1,-2,1,4,1,4,-3,1,4,-1,-3,-3,1,-109,1,129,1,9,1,11,2,1,-1,-2,-1,2,1,-3,3,1,-1,-3,2,3,-1,-2,1,5,2,2,-1,-1,2,3,-3,-3,2,12,-1,1,8,1,7,3,1,1,4, + -1,-2,1,5,2,2,-1,-1,2,4,-3,-2,-3,1,8,1,10,-2,4,4,1,4,1,58,2,-57,-1,2,4,-3,1,4,-1,-1,1,11,-1,4,3,-1,2,2,-3,2,3,-1,1,8,1,6,5,8,-2,-2,7,2,-1,1,6,-3,3,9,-1,-1,-1,2,3,-2,2,1,-2,-3,1,4,1,4,2,1,-1,-2,-1, + 1,12,3,1,4,3,-2,1,4,2,2,-2,1,-34,1,42,-1,2,4,1,5,-1,1,4,1,5,-2,1,5,2,2,2,3,2,7,3,1,2,5,-1,-2,-2,1,5,-1,1,12,-1,-1,2,1,-2,-1,-3,2,11,4,2,-3,5,2,1,4,-2,-2,3,5,-2,1,18,-3,1,4,-1,-1,-1,1,4,3,4,1,4,-3, + 3,1,3,1,3,5,-1,-1,2,11,-2,-1,-2,-1,-3,-2,-1,-1,1,-96,1,113,2,1,2,6,-1,-3,3,2,2,2,1,4,2,4,-1,-1,1,4,2,5,2,1,2,6,3,1,-1,-2,-1,1,7,1,10,1,4,-3,2,2,1,9,2,1,1,8,7,7,2,1,-3,-2,-1,3,1,1,4,-1,-2,-3,3,4, + -2,-3,2,8,-1,3,6,-3,2,6,2,2,-1,-2,3,2,2,5,-1,-3,-1,1,4,-1,1,4,-1,-1,-2,3,2,1,4,1,8,3,-8,-3,3,1,2,1,1,8,2,4,-1,-1,-2,1,4,-1,1,4,-1,-1,4,2,-2,-2,2,3,-1,-1,-1,2,2,-3,1,4,1,7,1,7,-1,1,4,1,23,3,1,2,2, + 1,7,-1,1,15,2,2,-1,5,9,3,2,1,7,-2,1,8,3,7,-3,-1,1,9,1,4,3,6,2,5,3,1,-1,-3,3,5,3,7,-2,2,3,-3,-1,-1,2,2,-2,1,5,-2,1,4,3,2,3,4,1,7,-2,-1,-2,-1,4,4,1,11,-3,-2,2,3,2,5,2,2,1,4,1,10,4,3,1,4,5,23,1,12, + -3,-1,-1,-3,-1,-2,-2,-3,-1,2,4,-1,1,7,2,1,2,1,1,8,-1,-1,-1,-1,2,4,-2,1,5,-1,2,5,-1,-2,-1,-1,-1,2,3,1,4,3,2,2,3,-3,-3,-1,3,13,3,1,3,2,-2,-2,1,4,2,3,-1,2,3,-1,1,5,1,7,-1,2,4,-3,2,2,-3,-2,1,4,-2,3,1, + 1,6,3,1,-1,1,5,-1,1,12,-3,3,3,1,5,-2,2,5,1,4,1,5,1,10,2,1,1,-22,1,34,-2,1,6,1,4,5,5,-1,3,9,1,4,1,-13,1,16,1,4,1,9,1,8,2,1,-2,-1,-2,2,2,1,5,-1,-1,2,4,1,6,2,1,2,152,2,3,1,6,-1,-1,-1,-3,-1,2,1,2,2, + -2,-1,1,-5,2,9,-1,2,1,-3,1,5,2,1,1,4,-2,2,7,-3,1,4,2,1,1,5,2,1,1,7,2,20,2,10,-2,-1,-3,1,6,1,-2,-3,-3,-3,1,6,-3,2,2,-1,-2,2,1,2,5,-1,-1,1,5,1,8,1,4,-3,1,73,-3,-2,-1,1,16,-2,-1,-3,1,4,2,2,-3,3,8, + 1,5,2,4,-2,-2,-2,-1,-1,-1,1,4,4,4,-1,-3,-2,2,2,-1,-1,2,10,-1,1,4,-3,1,-53,2,52,-1,1,8,-3,3,2,1,4,1,5,-2,-1,4,9,2,2,1,9,-1,4,2,-3,2,2,1,9,3,1,1,4,4,6,2,2,1,6,2,2,3,1,3,7,2,6,1,5,1,6,-1,-2,2,4,2,1, + -3,1,4,-1,2,3,1,4,-1,2,4,2,4,2,1,-2,1,7,-1,-2,1,7,1,11,1,5,2,1,1,5,2,1,1,-14,1,18,-1,2,4,2,6,3,5,1,5,2,1,-1,-1,2,1,3,3,4,5,-2,2,5,-1,-3,1,7,5,1,-2,2,4,1,6,1,55,2,2,3,2,2,14,-1,1,5,2,1,1,4,2,3,-1, + -2,2,1,-1,1,10,2,2,-3,1,5,-2,2,3,1,4,-2,-3,-1,-3,-3,1,11,-2,2,12,1,5,1,-6,2,1,2,5,-2,1,7,2,3,1,7,1,14,-1,1,4,2,3,1,4,-3,-3,1,4,1,11,-2,2,2,-1,-1,1,4,3,1,-1,3,4,-2,1,10,3,1,-1,1,6,1,14,1,-15,3,4, + 2,1,1,12,3,1,2,2,-1,1,5,1,-20,1,35,1,-12,2,3,-3,3,9,3,3,-1,1,4,-2,-3,3,1,-1,-1,-1,-1,1,4,2,-4,-3,-1,2,4,-1,-2,2,1,2,1,2,1,1,5,2,3,1,6,-3,-3,3,1,1,5,-2,-2,1,5,1,6,3,4,1,5,-1,2,1,-3,-3,-2,3,1,-2, + 1,5,-2,1,4,-1,3,3,4,1,-2,3,4,-1,2,2,-1,2,13,-2,2,1,-3,2,5,2,3,6,1,1,5,-1,-1,-1,2,2,4,2,2,1,-1,-3,2,1,-2,-1,2,3,4,5,-1,3,5,-2,2,1,3,1,-1,-1,-1,2,1,2,2,-2,3,2,-1,2,6,2,2,2,2,-3,3,1,3,4,5,4,3,1,-1, + 3,8,2,2,-3,1,4,-1,2,5,2,3,2,1,-2,-3,-2,-3,-1,4,1,5,1,4,1,4,2,-1,-2,-1,3,1,2,2,3,1,-1,-1,2,1,-3,-1,-1,1,8,-1,2,3,-1,1,5,1,4,-3,2,2,4,6,-1,2,2,-1,2,1,2,8,2,1,3,15,3,6,-2,2,1,-1,-3,2,5,-1,2,1,-2,3,1, + 2,1,-1,-3,-2,4,1,1,5,2,1,-1,-1,-2,-2,-2,-2,-2,-2,2,1,-1,-1,-2,3,8,-3,1,-18,1,23,4,2,5,1,1,5,1,5,-2,2,1,-2,2,3,1,17,2,-3,2,1,-1,2,3,-1,2,3,3,3,3,5,1,7,2,14,4,1,1,6,-3,1,-3,1,5,-1,-2,-1,-1,1,8,-3, + -2,-2,-1,-1,1,4,-2,3,1,2,1,1,17,1,-2,2,244,1,4,1,5,-3,3,3,3,14,-1,1,4,-2,2,1,1,7,-1,-3,-2,-1,1,6,2,1,-1,4,4,2,5,4,2,-3,-1,2,54,-3,3,1,1,5,1,4,-1,4,3,2,1,-3,1,16,-1,3,1,1,8,1,12,1,5,2,6,2,1,4,1, + 1,4,1,7,1,4,-3,-2,-1,3,4,-2,2,4,-3,1,6,1,15,1,7,1,-14625,1,14629,-1,3,2,1,9,1,5,-1,1,8,2,7,-1,-3,2,16,-1,3,3,1,4,1,8,-1,1,13,-1,1,6,2,3,1,5,2,1,2,1,1,7,-3,-2,-3,1,4,3,2,-2,-1,2,1,1,8,3,11,2,1,2,3, + -2,1,9,-1,2,2,2,2,3,1,-1,2,1,-1,2,2,-1,2,1,3,1,2,1,-2,3,2,2,3,-1,1,-6,1,5,-2,1,10,-1,-2,2,2,-1,1,12,-2,1,14,2,-13,1,5,-1,1,5,-1,-1,-2,-2,1,4,3,2,2,1,-1,1,-17,1,24,1,5,-2,-2,3,6,2,2,2,1,2,7,2,1,-3, + -1,1,62,2,1,-1,-3,2,2,2,1,-3,-2,-2,-2,-3,1,20,-1,3,1,-2,1,8,-2,1,11,2,4,1,8,3,3,3,2,-2,-2,2,3,-3,5,5,4,3,2,3,3,4,2,4,1,5,2,3,2,1,3,1,1,58,-1,-1,1,6,3,9,-2,2,3,-2,-1,-3,1,5,2,9,2,4,-1,-1,1,8,3,2, + -3,2,3,-3,2,3,3,3,2,6,2,3,1,4,1,7,-1,3,1,-2,2,5,1,4,2,1,-1,1,14,1,-7,-2,3,5,-1,-2,-2,-1,1,6,1,76,-1,2,1,-2,3,1,-2,-1,2,2,-1,-1,-2,-1,1,5,-1,-1,3,2,2,3,-3,2,3,-1,-1,-2,2,5,-1,2,3,-2,7,1,2,2,4,1,-1, + -1,-3,-2,2,1,-3,1,5,1,4,-1,3,5,-1,2,1,-2,1,10,2,2,3,8,-3,-2,-2,-1,2,1,-1,5,1,1,4,-1,3,1,2,5,4,3,3,1,-1,2,1,-3,1,5,2,2,2,7,-1,-2,3,3,2,4,2,2,2,1,-1,2,5,1,5,-1,2,6,1,4,-1,1,5,-1,2,2,-3,-3,4,3,-2, + 2,1,-1,1,8,-3,-1,1,4,3,1,-1,-1,2,3,5,2,1,6,3,3,1,5,-3,3,1,2,3,3,3,2,2,-1,-1,-2,3,1,-3,2,5,1,-15,1,14,1,-4,1,5,-1,-1,-2,-1,-3,1,106,1,11,1,4,-1,1,17,1,-10,1,14,2,5,3,3,2,16,3,1,1,5,-1,1,8,1,-9,2,4, + -3,-2,2,8,1,10,-3,1,-2,-2,3,3,1,4,2,5,2,3,-1,2,4,-1,-3,2,2,2,3,4,1,1,8,1,8,-1,-1,-2,-3,-3,-2,-2,-3,-3,2,1,4,9,-2,3,3,1,4,-1,-1,-1,-2,-1,2,2,1,9,1,11,1,-9,1,4,1,6,3,1,2,2,-2,2,2,3,92,-3,4,1,-1,2,6, + 1,6,-1,-2,-2,1,5,-3,-3,3,1,3,2,1,16,-1,-2,1,9,1,9,1,4,-2,3,4,3,1,-2,-2,1,6,2,2,1,5,4,5,-1,2,1,3,1,-3,-2,-3,2,3,-3,2,1,-1,-2,2,1,2,1,-1,-1,5,1,1,11,4,1,-1,2,2,2,9,5,3,-1,-1,1,4,-2,4,17,-1,2,1,1,6, + 3,2,-1 + ], + "euc-kr": [ + 2,44034,2,1,5,4,1,8,2,5,3,1,7,1,-2,3,3,0,6,3,0,2,2,3,1,10,1,-1,6,1,-1,0,6,2,0,3,1,19,1,2,2,2,1,-2,5,1,-2,2,4,3,4,3,1,7,1,-2,6,3,-3,2,1,7,2,-2,3,3,2,1,3,1,3,1,8,1,-1,8,1,2,2,2,1,-2,-1,2,1,-3,-1, + 5,2,2,2,3,1,-1,5,1,-2,-1,6,1,3,1,3,1,8,1,2,1,6,2,0,6,2,2,3,1,7,1,-2,-1,6,1,3,1,3,1,0,6,8,1,-1,8,1,2,2,2,1,4,4,-3,-1,5,2,2,2,3,1,11,1,6,2,18,1,8,1,2,2,3,1,7,1,-2,8,1,3,1,3,1,19,1,2,2,2,1,6,3,-2,-1, + 6,1,8,1,0,6,19,0,2,2,2,1,-2,2,1,0,6,3,0,-2,-1,3,2,-1,-3,3,1,-1,5,1,-2,3,3,2,1,2,2,3,1,7,1,-2,6,3,6,2,47,1,-3,3,1,7,1,-2,6,3,2,2,11,1,2,1,-1,6,1,3,1,3,1,9,1,0,6,1,0,4,2,2,1,19,1,0,6,8,0,2,2,-1,-1, + 7,1,-2,-1,4,3,6,2,11,1,6,2,19,2,6,1,3,1,3,1,7,1,3,2,6,1,27,1,2,2,3,1,6,1,-3,-1,5,2,7,1,5,1,0,6,6,0,6,2,2,2,3,1,7,1,2,2,0,6,7,1,3,1,3,1,7,1,10,2,27,1,2,2,-1,-1,-1,4,1,-3,-1,3,1,30,1,2,2,3,1,7,1,-2, + -1,6,1,-3,2,1,5,4,-2,1,5,-1,2,3,3,1,7,1,-2,6,3,-2,0,6,1,0,3,1,7,1,4,1,11,1,0,6,23,0,-2,3,2,-1,4,2,-2,5,3,2,3,3,1,7,1,-2,6,3,2,2,3,1,7,1,2,2,2,2,3,1,3,1,23,1,2,2,3,1,-1,5,1,-2,-1,4,1,3,3,3,1,11,1, + 16,1,0,6,19,0,3,1,3,1,-1,0,6,6,0,-2,8,1,2,2,3,1,8,1,-1,-1,6,1,2,2,2,1,7,2,-2,-1,6,1,19,1,7,1,27,1,3,1,3,1,7,1,10,2,6,2,7,1,3,2,5,1,0,6,1,0,2,2,3,1,5,3,-2,-1,3,2,-1,3,1,3,1,3,1,0,6,16,0,2,2,3,1,-1, + 5,1,-2,-1,4,1,-1,-3,2,1,3,5,-3,3,5,2,3,3,1,7,1,-2,6,3,55,1,-3,2,1,-2,4,2,-2,-1,-1,2,1,-1,2,2,3,1,7,1,-2,6,3,-1,0,6,2,0,3,1,11,1,6,2,3,1,-1,0,6,22,0,2,2,2,1,-2,-1,3,1,-2,-1,-1,-1,2,1,3,1,3,1,19,1, + 19,1,7,1,3,1,3,1,7,1,-2,8,1,27,1,2,2,3,1,7,1,-2,-1,-1,0,6,5,0,19,1,2,1,0,6,5,0,20,1,6,1,3,1,3,1,8,1,-1,-1,6,1,3,1,3,1,7,1,4,1,6,1,2,2,2,1,-2,5,1,-2,-1,6,1,27,1,2,2,2,1,7,2,-2,5,4,2,2,3,1,7,1,-2, + -3,0,6,4,0,2,3,3,1,7,1,-2,9,3,0,6,53,0,2,2,3,1,-1,4,2,-2,5,3,2,3,3,1,7,1,-2,6,3,19,1,35,1,2,2,3,1,5,1,0,6,7,0,6,1,7,1,6,1,0,6,13,0,27,1,3,1,51,1,2,2,3,1,6,1,4,2,34,1,9,1,0,6,18,0,3,1,3,1,2,1,0,6, + 5,0,3,2,34,1,2,2,2,1,7,2,-2,8,1,3,1,3,1,7,1,10,2,3,1,3,1,7,1,-2,-1,6,1,2,2,3,1,7,1,-2,3,4,2,4,3,1,7,1,-2,6,3,2,2,9,1,0,6,5,0,-1,20,1,0,6,14,0,2,2,3,1,7,1,-2,5,3,2,3,3,1,7,1,-2,-1,6,1,2,2,3,1,7,1, + -2,6,3,3,1,12,1,-1,8,1,2,2,3,1,7,1,-2,-1,6,1,3,1,16,1,18,1,0,6,8,0,7,1,3,1,3,1,5,1,0,6,2,0,-2,-1,6,1,3,1,3,1,8,1,-1,-1,6,1,2,2,3,1,7,1,-2,-1,6,1,19,1,7,1,27,1,2,2,3,1,7,1,2,1,-1,6,1,2,2,3,1,7,1, + -2,-1,6,1,2,2,3,1,-1,0,6,6,0,-2,-1,2,2,16,2,0,6,13,0,2,2,3,1,7,1,-2,-1,6,1,2,2,-1,5,5,-2,-1,2,2,-1,2,3,3,1,7,1,-2,5,4,6,2,12,1,34,1,2,2,3,1,-1,5,1,-2,-1,4,2,2,3,3,1,7,1,-2,6,3,0,6,2,2,3,1,10,1,-3, + 4,1,6,1,0,6,21,0,-2,3,2,-1,5,1,-2,-1,6,1,3,1,15,1,34,2,3,1,3,1,8,1,-1,-1,6,1,3,1,3,1,8,1,-1,8,1,-3,2,1,5,4,-2,-1,3,1,-1,2,2,0,6,1,0,3,1,8,1,-1,8,1,5,1,0,6,22,0,3,1,3,1,19,1,3,1,3,1,7,1,2,1,8,1, + 3,1,3,1,7,1,2,1,36,1,2,2,2,1,-2,5,1,-2,-3,-1,2,1,2,5,4,5,-2,-1,3,1,2,1,2,2,-1,0,6,2,0,7,1,-2,3,3,2,1,2,2,9,1,0,6,3,0,38,1,2,2,2,1,-2,5,1,-2,-1,5,2,2,2,2,1,7,2,-2,6,3,2,2,3,1,8,1,-1,3,3,2,1,3,1, + 23,1,-3,3,1,7,1,-2,-1,6,1,3,1,9,1,0,6,6,0,7,1,13,1,0,6,6,0,7,1,2,2,3,1,7,1,10,2,3,1,23,1,2,2,2,1,5,4,-2,-1,3,1,-2,7,1,11,1,7,1,27,1,2,2,3,1,12,1,6,1,-1,0,6,2,0,3,1,7,1,2,1,-1,6,1,2,2,3,1,0,6,7,1, + -2,36,1,2,2,3,1,-1,5,1,-2,-1,4,3,2,2,3,1,-1,5,1,-2,5,3,2,3,3,1,7,1,-2,6,3,14,2,39,1,2,2,0,6,2,1,7,2,2,1,6,3,9,1,0,6,11,0,6,1,14,2,-2,34,3,2,2,3,1,7,1,3,2,62,1,9,1,0,6,18,0,8,1,0,6,12,0,6,1,2,2, + 3,1,7,1,2,1,-1,90,1,20,1,6,1,3,1,0,6,3,1,7,1,16,2,0,6,22,0,2,2,3,1,7,1,-2,-1,6,1,-2,2,2,5,4,-2,3,3,2,1,2,2,3,1,7,1,-2,6,3,2,2,3,1,7,1,-2,-1,6,1,3,1,3,1,7,1,4,1,6,1,2,5,-2,4,2,-2,4,3,-1,2,2,3,1, + 7,1,-2,6,3,2,2,0,6,3,1,7,1,-2,6,3,3,1,3,1,3,1,0,6,9,0,6,1,-3,3,1,-1,5,1,-2,-1,3,1,2,1,2,2,3,1,12,1,6,1,3,1,3,1,7,1,2,1,7,2,3,1,3,1,7,1,-2,8,1,2,2,3,1,7,1,-2,-1,6,1,2,2,2,1,7,2,-2,-1,-1,-1,-2,17,1, + 0,6,2,0,7,1,2,2,3,1,7,1,4,1,-1,0,6,5,0,2,2,3,1,7,1,-2,-1,6,1,6,2,7,1,2,1,-1,6,1,2,2,3,1,6,2,-2,-1,34,1,2,2,2,1,6,2,-3,-1,4,1,-1,-2,3,2,7,1,2,2,5,2,2,3,3,1,7,1,2,2,9,2,0,6,18,0,8,1,0,6,26,0,2,2, + 3,1,-1,5,1,2,2,6,2,3,1,3,1,51,1,23,1,2,2,2,1,-2,5,1,3,2,6,1,2,2,6,1,0,6,9,0,7,1,10,1,0,6,9,0,7,1,3,1,3,1,7,1,10,2,27,1,2,2,3,1,7,1,3,2,6,1,19,1,7,1,27,1,3,1,9,1,0,6,26,0,0,6,9,0,6,1,2,2,3,1,-1, + 4,1,10,3,3,1,3,1,7,1,11,1,2,2,3,1,7,1,-2,-1,6,1,2,2,-3,4,3,-3,3,3,-2,2,2,3,1,7,1,-2,6,3,2,2,3,1,2,1,4,1,-2,-1,3,1,-1,3,2,3,1,8,1,10,1,-2,0,6,1,0,-2,5,4,1,7,-1,-1,2,2,3,1,7,1,-2,-1,2,1,0,6,4,0,-3, + 3,1,-1,4,2,3,6,3,4,3,1,7,1,-2,7,2,2,2,3,1,-3,2,1,-3,-1,-1,4,1,2,2,3,1,7,1,-2,6,3,2,2,11,1,2,1,-1,6,1,2,2,3,1,7,1,-2,-1,6,1,2,2,3,1,7,1,-2,-1,6,1,2,2,3,1,5,3,-2,-1,6,1,-2,0,6,1,0,3,1,7,1,2,2,6,2, + 2,2,3,1,2,1,0,6,5,0,3,2,6,1,2,2,3,1,7,1,-2,-1,6,1,2,2,3,1,7,1,-2,-1,-1,4,1,2,2,3,1,5,1,-1,-2,-1,3,8,3,1,7,1,2,1,8,1,2,2,3,1,4,3,-3,3,4,-1,2,2,-1,-3,5,1,-2,5,4,2,2,3,1,7,1,-2,6,3,2,2,-1,-1,7,1,4,1, + 0,6,6,1,3,1,3,1,14,1,0,6,5,0,2,2,3,1,-1,5,1,-2,-1,5,2,2,2,3,1,7,1,-2,-1,6,1,3,1,3,1,7,1,2,2,6,2,27,1,2,2,3,1,-1,5,1,-2,-1,3,3,6,3,8,1,-1,-1,6,1,19,1,4,2,0,6,2,0,3,1,3,1,7,1,-2,-1,6,1,2,2,-1,0,6, + 15,0,6,1,2,2,3,1,5,3,-2,3,-39183,"t20AgVqpZw8W_9sAAgD2AAAgAOAw0CAC3SP-AAAAEAA",10,-14,"sSUfaAMAuBV7gQDPJ7QAA1z934Rs7wRZ8FSTAAAAIgAAAADeIAABAN4AACcA_AAB_wAAAN4g","$6", + "kv0AAQB-VgCuIt8X9QDbAnoA-gCm_v0AuS0hAAAAAA_yAAAAAAAAAAAAAAAAAAAAAADdyg",6,1,19,1,0,6,7,1,19,1,0,6,8,0,2,2,3,1,7,1,-2,8,1,3,1, + "0gErArCpaBAE_P7eIsUdEF3i_ZRkJpD-9v6t-wADAfs1LtosAMARAAL-_gK-pv4NAZdpAHMBAfwB1PsAARKc-bBanxVIigEhAAEA3v8DAAAAAP4C_gACIAAA3iH_BQAAAAEAAAAAAPwDAAAAAAAAAAAAAAEAAAAA2iAAAQAAAAAFAAAADADvEu4SAO7_4A", + 0,23,3,51394,7,1,11,1,2,2,3,1,0,6,7,1,-2,-1,17,1,0,6,17,0,2,2,2,1,-2,5,1,-2,-1,2,2,-2,59,13605,1,170,33,-170,1,133,2,-13830,-1,-1,2,1,4,1,-2,6,3,2,2,3,1,4,1,0,6,3,0,-2,6,3,3,1,13,1,0,6,3,0,29,1, + 94,-39190,5,39096,2,2,3,1,7,1,-2,6,3,2,1,0,6,18,0,6,1,2,1,0,6,17,0,15,1,10,-43320,0,5,10,-26,0,7,"$1",0,8,"$2",0,6,20,43326,2,2,3,1,-1,0,6,6,0,-2,-1,-1,4,1,6,2,7,1,0,6,4,0,7,1,19,1,2,1,"$3","$4", + 8,-42440,0,26,5,42432,3,1,3,1,7,1,8,2,0,6,23,0,3,1,0,6,3,0,2,2,3,1,7,1,3,2,6,1,8,1,3,-38872,"E4QrIRIA",4,-34,10,-14,1,39,3,-62,1,63,2,-72,1,62,2,-34,10,7,5,-58,6,53,5,-48,1,-4719,2,4761,3,-56, + 1,73,1,-18,3,-25,1,43,4,-51,"3fIC7wUS6TMAAAAAAAA",0,15,11,38822,15,2,0,6,19,0,7,1,0,6,20,0,12,1,"xgnZewAAAAE",0,1,1,11,0,1,"PwGWeWcjh-MBAP8B_wABAA",0,1,28,12565,26,-3500,15,-138,"vZUAZwEAIQDfAA", + 4,8348,15,43622,11,1,0,6,4,0,2,1,-1,19,1,0,6,15,0,2,2,3,1,7,1,3,2,2,2,"5ireNgkBBAcBtVqLHmjj_QAB_wEAAAAAAP8B_wABAAA",28,12470,26,-3456,15,-66,1,-9162,2,-8,1,8128,1,10,4,1,2,43936,2,3,-1,-1,7,1,-2, + 5,4,2,2,3,1,2,1,0,6,5,0,-2,6,3,3,1,-1,-1,7,1,2,1,0,6,2,0,30,1,83,-40019,0,11,4,39936,2,2,3,1,7,1,-2,6,3,2,2,-1,0,6,2,0,7,1,-2,-1,6,1,3,1,6,1,0,6,9,0,7,1,3,1,13,1,86,-40029,0,8,3,39943,6,1,2,2,3,1, + 7,1,-2,-1,3,1,0,6,3,0,3,1,3,1,12,1,5,1,0,6,29,0,3,1,"$C",0,15,"$c",0,13,3,1,7,1,-2,-1,6,1,8,1,0,6,7,0,11,1,2,2,3,1,3,1,0,6,4,0,-2,-1,6,1,19,1,-1,0,94,6,0,3,1,17,1,0,6,6,0,3,1,3,1,7,1,-2,-1,5,1, + 0,6,1,0,3,1,3,1,7,1,4,1,6,1,2,2,3,1,3,1,0,94,4,0,-2,-1,20,1,0,6,14,0,2,2,2,1,6,3,-2,-1,0,6,6,1,2,2,3,1,7,1,-2,-1,6,1,2,2,3,1,-1,0,94,6,0,-2,6,3,13,2,0,6,6,0,20,1,0,6,14,0,2,2,2,1,7,2,-2,6,3, + 2,-8960,-2,4,2,8,5,5,1,-2,-3,2,7,3,1,2,6,-2,-3,1,10,-1,1,6,-3,-3,2,19,-2,2,2,-1,2,5,4,1,4,2,-3,-3,2,7,3,1,3,6,-1,2,2,2,7,3,1,-3,-2,-3,-3,1,8,-1,2,8,-2,2,2,-1,-1,3,2,-1,2,1,2,5,-2,-3,-1,2,8699,3,1, + 7,1,-2,-1,6,1,3,1,3,1,0,6,7,1,-2,6,3,12,1,0,6,15,0,2,2,3,1,7,1,-2,-1,3,1,2,-8801,-1,-1,1,6,-3,-3,1,8,2,2,2,6,-2,-3,2,7,-1,-1,1,6,-3,-3,1,8,-1,2,8,-2,4,2,3,4,-1,2,1,2,5,-2,-3,2,11,1,6,1,18,2,8,-2, + -3,2,7,-1,1,8,-3,-3,2,19,-2,3,2,2,6,-1,-1,1,6,2,27,-2,2,2,-1,2,5,-1,2,1,-3,3,1,-1,-3,-1,2,5,3,1,-3,2,2,-2,-3,1,7,3,8436,2,2,3,1,7,1,4,1,6,1,-1,0,6,19,0,6,1,-1,0,6,6,0,19,1,7,1,1,-8531,3,1,2,6,1,6, + 3,47,-1,-3,2,7,3,1,2,6,-2,1,11,-2,-1,1,6,-3,-3,2,10,1,4,-2,2,27,-2,-1,-1,2,7,-1,3,1,2,4,1,6,2,11,2,6,1,19,1,6,-3,-3,2,7,-3,1,6,2,27,-2,-3,3,6,-1,2,1,1,5,1,7,2,11,2,6,-2,-3,2,7,-2,1,7,-3,-3,2,7, + 1,10,2,27,-2,-1,-1,-1,3,4,-1,-1,20,8050,2,2,3,1,-1,0,6,6,0,-2,-1,6,1,3,1,3,1,6,1,0,6,6,0,6,1,20,1,1,-8144,2,30,-2,-3,2,7,-1,-1,3,6,-1,4,2,2,5,5,1,-1,3,1,-2,-3,2,7,3,1,2,6,-2,-3,1,7,1,4,2,34,2,1, + -3,2,1,2,4,3,1,3,5,-2,-3,2,7,3,1,2,6,-2,-3,2,7,2,2,-2,-3,-3,2,23,-2,-3,-1,2,5,-1,-1,3,4,-3,-3,1,11,1,35,-3,-3,2,7,6,7760,2,2,3,1,7,1,-2,-1,6,1,0,6,3,1,3,1,7,1,11,1,2,2,0,6,3,1,7,1,3,2,19,1, + 1,-7862,2,8,-2,-3,1,8,-1,-1,2,6,-2,2,2,2,7,-1,-1,1,6,1,19,1,7,1,27,-3,-3,2,7,2,10,1,6,2,7,-3,2,6,-2,3,3,2,5,-1,2,1,-3,-1,-3,-3,2,19,-2,-3,-1,2,5,-1,-1,1,4,3,1,-1,5,2,3,3,5,1,3,3,-2,-3,2,7,3,1,1,6, + 3,55,-1,2,2,2,1,2,4,15,7471,2,2,3,1,6,1,0,6,1,0,-2,-1,6,1,2,2,3,1,6,2,-2,5,3,0,6,1,0,2,2,3,1,7,1,-2,6,3,12,1,1,-7582,-1,-1,-2,2,1,-2,-3,2,7,3,1,1,6,-3,-3,2,11,1,6,-3,2,23,-2,2,2,-1,-1,2,3,-1,-1, + -1,-1,-2,-3,-3,1,19,1,19,1,7,-3,-3,2,7,-1,1,8,2,27,-2,-3,2,7,-1,-1,1,6,1,19,1,7,1,20,1,6,-3,-3,1,8,-1,-1,1,6,-3,-3,1,7,1,4,2,6,-2,2,2,-1,2,5,-1,-1,1,6,2,27,-2,2,2,2,7,4,1,2,5,-2,-3,8,7116,18,1, + 0,6,16,0,2,2,3,1,-1,4,1,0,6,1,0,-2,6,3,2,2,3,1,7,1,-2,-1,6,1,3,1,-1,2,-7214,3,1,3,5,-2,-3,2,7,3,1,2,62,-2,-3,2,1,2,4,3,1,3,5,-2,-3,2,7,3,1,1,6,1,19,2,35,-2,-3,1,12,1,6,1,7,1,19,1,27,-3,2,51,-2,-3, + 2,6,1,4,1,34,1,27,-3,-3,2,7,-3,2,34,-2,2,2,2,7,-1,1,8,-3,-3,2,7,1,10,-3,-3,2,7,-1,-1,2,6,-2,-3,2,7,4,1,2,3,14,6614,7,1,3,1,2,1,0,6,21,0,2,2,3,1,0,6,7,1,-2,-1,4,1,-1,3,1,15,1,2,-6712,-2,-3,2,7,3,1, + 2,6,-2,1,14,-1,2,34,-2,-3,2,7,3,1,3,5,-2,-3,2,7,-1,-1,2,6,-2,-3,2,7,3,1,1,6,-3,1,12,-1,2,8,-2,-3,2,7,-1,-1,1,6,-3,1,16,1,26,1,7,-3,-3,2,7,-1,-1,1,6,-3,-3,1,8,-1,-1,2,6,-2,-3,2,7,-1,-1,1,6,1,19, + 1,7,2,27,-2,-3,1,7,-2,-1,2,6,-2,-3,2,7,8,6246,18,1,0,6,9,0,3,1,14,1,0,6,-1,6,1,25,1,1,-6335,-1,2,6,-2,-3,2,7,-1,2,1,2,2,2,29,-2,-3,2,7,-1,-1,2,6,-2,5,1,2,5,-1,2,1,-2,3,1,-2,-3,2,7,4,1,2,5,1,6, + 1,12,2,34,-2,-3,-1,2,5,-1,2,1,3,4,-2,-3,2,7,3,1,2,6,-2,-3,3,10,-1,1,4,2,27,2,1,-3,-1,2,5,-1,-1,1,6,-3,2,15,1,34,2,5933,2,2,3,1,7,1,-2,-1,6,1,4,1,0,6,15,0,7,1,4,1,0,6,23,0,2,2,3,1,4,1,1,-6029,-3, + 1,8,-1,-1,1,6,-3,-3,1,8,-1,3,8,-1,4,2,2,5,-1,-1,-3,2,1,-3,-3,1,8,-1,1,8,1,27,-3,-3,1,19,-3,-3,1,7,-2,1,8,-3,-3,1,7,-2,2,36,-2,2,2,-1,2,5,3,1,-1,-1,5,2,5,2,2,4,-1,-1,-3,2,2,-2,-3,2,7,3,1,-3,2,2,-2, + 1,12,2,38,-2,2,2,-1,2,5,-1,3,5621,3,2,6,1,3,1,3,1,7,1,-1,0,6,3,0,6,1,2,2,2,1,-2,5,1,-2,6,1,0,6,2,0,3,1,3,1,7,1,10,2,2,2,3,1,2,1,2,-5730,2,5,-2,2,2,2,7,3,1,2,6,-2,-3,1,8,3,1,-3,-2,-3,3,23,-1,-3, + 2,7,-1,-1,1,6,-3,1,15,1,7,1,19,2,7,-2,-3,2,7,1,10,-3,2,23,-2,4,2,2,5,-1,-1,2,3,-1,1,7,1,11,1,7,2,27,-2,-3,1,12,1,6,-3,-3,1,7,-2,-1,2,6,-2,-3,2,7,-1,2,36,-2,-3,-1,2,5,-1,3,1,2,4,-2,5,5270,-2,-1, + 6,1,-3,3,1,-1,5,1,-2,2,3,0,6,1,0,2,1,2,2,3,1,7,1,-2,6,3,4,2,0,6,32,0,1,-5378,-1,2,5,3,1,3,5,-2,-3,2,7,3,1,2,6,1,14,2,39,-2,2,2,1,7,3,2,1,6,1,20,2,6,2,14,3,1,2,34,-2,-3,2,7,-3,1,62,1,27,1,20,2,6, + -2,-3,1,7,-2,-1,1,90,1,20,1,6,-3,-3,2,7,2,38,-2,-3,2,7,-1,-1,2,6,2,1,4,2,2,5,3,1,-3,2,2,-2,-3,2,7,3,1,1,6,18,4741,2,2,3,1,3,1,0,6,4,0,-2,6,3,2,2,3,1,7,1,-2,-1,-1,0,6,5,0,3,1,3,1,7,1,2,2,6,2,6,1, + 1,-4850,-2,-3,2,7,-1,-1,1,6,-3,-3,1,7,1,4,5,6,2,2,2,1,2,4,3,1,1,4,2,1,-2,-3,2,7,3,1,2,6,-2,-3,2,7,3,1,1,6,-3,-3,1,12,3,6,-1,-3,-1,2,5,-1,-1,-3,2,2,-2,-3,1,12,1,6,-3,-3,1,7,2,2,1,7,-3,-3,2,7,-1, + 2,8,-2,-3,2,7,-1,-1,2,6,-2,2,2,2,7,-1,-1,1,4521,8,1,-1,8,1,2,2,3,1,3,1,0,6,4,0,-2,-1,6,1,14,1,0,6,6,0,26,1,1,-4617,2,1,-1,1,19,2,7,-2,-3,1,7,1,4,2,6,-2,-3,2,7,-1,-1,2,6,1,6,1,7,-2,-1,2,6,-2,2,3, + 2,6,-1,-1,2,34,-2,2,2,3,6,-1,-1,1,4,2,1,2,1,-3,2,7,2,2,3,5,-2,-3,2,7,2,2,1,27,2,34,-2,-3,-1,2,5,2,2,1,6,-3,-3,1,51,2,23,-2,2,2,-1,2,5,-3,2,6,-2,1,15,1,7,1,19,1,7,-3,8,4103,3,1,15,1,0,6,8,0,3,1, + 3,1,8,1,-1,3,1,0,6,5,0,2,2,2,1,-2,5,1,-2,-1,6,1,9,1,1,-4202,2,7,1,10,2,27,-2,-3,2,7,-3,1,6,1,19,1,7,1,27,-3,1,44,2,6,-2,-3,-1,3,4,1,10,-3,-3,1,7,2,11,-2,-3,2,7,-1,-1,2,6,3,2,3,1,3,4,3,1,2,3,2,1, + -2,-3,2,7,3,1,2,6,-2,-3,-2,2,4,-1,-1,-3,2,1,-3,-3,1,8,2,10,2,2,4,1,7,5,-1,-1,11,3791,15,1,0,6,19,0,3,1,3,1,-1,0,6,6,0,2,1,8,1,3,1,3,1,7,1,2,1,-1,2,-3885,-2,-3,2,7,-1,-1,3,6,-1,-3,2,1,6,4,4,3,-3, + -3,2,7,2,1,2,7,-2,3,3,-1,3,2,-1,-1,-1,2,4,-2,-3,2,7,3,1,2,6,-2,1,11,-2,-1,2,6,-2,-3,2,7,-1,-1,2,6,-2,-3,2,7,-1,-1,2,6,-2,3,3,2,5,-1,-1,2,6,-2,-3,2,7,2,2,1,6,6,3605,3,1,3,1,7,1,-2,6,1,0,6,26,0,0,6, + 4,0,2,2,3,1,7,1,-2,-1,6,1,2,2,3,1,3,1,1,-3707,-2,-3,2,7,-3,2,6,-2,-3,2,7,-1,-1,2,6,-2,-3,2,7,-1,-1,-1,2,4,-2,-3,1,5,2,1,-1,8,1,-3,-3,1,7,-2,2,8,-2,3,3,3,4,4,1,-3,2,1,-2,3,1,-1,2,5,4,1,2,5,-2,-3, + 2,7,3,1,2,6,-2,-1,-1,1,7,1,4,1,6,-3,-3,2,19,-2,-3,-1,1,3417,2,1,-2,-1,6,1,2,2,3,1,7,1,-2,2,3,0,6,4,0,20,1,2,1,0,6,32,0,2,-3512,-1,2,1,2,5,-2,-3,2,7,-1,-1,1,6,-3,-3,2,7,2,2,1,6,2,27,-2,-3,-1,2,5, + -1,3,1,3,3,1,6,1,8,-1,-1,1,6,2,19,1,6,-3,-3,2,7,-1,-1,2,6,-2,1,16,2,6,-2,3,3,2,5,-1,-1,1,6,1,19,1,7,2,27,-2,-3,2,7,-1,1,8,-3,-3,1,7,2,11,-2,-3,2,7,-1,-1,2,34,-2,2,2,-1,2,5,-1,2,3062,3,1,-1,5,1,-2, + -1,6,1,2,2,3,1,2,1,0,6,5,0,-2,-1,6,1,2,2,3,1,7,1,-2,0,6,6,3,3,1,3,1,8,1,10,1,2,2,2,-3175,2,2,2,1,-2,-1,-1,-2,2,4,3,1,2,6,-2,-3,2,7,3,1,1,6,-3,1,16,2,34,-2,-3,2,7,3,1,1,6,1,20,1,6,1,19,2,35,-2,-3, + 2,7,-1,-1,-1,2,4,1,6,1,11,1,7,1,19,1,7,-3,-3,2,7,1,31,2,6,-2,-3,2,7,-3,1,6,2,19,1,34,1,27,1,27,1,15,-2,-1,2,34,-2,-3,2,7,2,3,3,4,-2,-1,-1,2,7,-1,3,2561,4,1,2,1,-2,-1,3,1,2,1,2,2,3,1,5,1,0,6,5,0, + -1,6,1,2,2,12,1,0,6,2,0,-1,6,1,2,2,3,1,8,1,-1,-1,6,1,2,1,3,-2671,2,5,-2,-3,2,7,3,1,1,6,-3,-1,-1,1,7,1,4,2,34,-2,-3,2,7,3,1,2,6,-2,-3,2,7,-1,-1,1,6,-3,1,15,1,7,-3,1,16,2,6,-2,-3,2,7,-1,-1,1,6,-3, + -3,1,12,1,34,-3,-3,2,7,-1,-1,1,6,1,15,2,11,-2,-3,2,7,-1,-1,1,6,1,19,1,7,-3,1,23,-3,-3,2,7,-1,-1,1,6,-3,-3,1,7,1,4,2,6,-2,-3,2,7,-1,-1,1,2165,3,1,8,1,-1,8,1,2,2,3,1,0,6,4,1,2,1,2,1,-1,6,1,3,1,3,1, + 5,1,0,6,2,0,4,1,6,1,2,2,3,1,12,1,3,1,2,-2237,-2,3,2,2,6,-1,-1,2,6,-2,-3,2,7,-1,-1,2,6,-2,-3,2,7,3,1,2,6,1,19,2,34,-2,2,2,2,7,3,1,2,6,-2,-3,2,7,-1,-1,1,6,-3,-3,2,7,3,1,1,6,2,27,-2,-3,2,7,-1,-1,2,6, + -2,-3,1,7,1,4,1,6,1,20,1,6,1,7,1,19,2,27,-2,-3,2,7,-1,-1,1,6,-3,-3,1,12,1,6,1,20,2,6,-2,-3,3,1752,2,2,3,1,7,1,-2,-1,6,1,2,2,-1,0,6,2,0,7,1,2,1,-1,6,1,2,2,-1,5,4,0,6,1,0,-2,-1,3,1,2,1,3,1,3,1,7,1, + 3,2,6,1,2,2,2,-1864,-1,-1,1,6,-3,-3,1,7,2,11,-2,-3,2,7,-3,2,34,-2,-3,2,7,-1,-1,2,6,-2,2,3,2,6,3,1,2,6,-2,-3,2,7,3,1,1,6,1,20,2,34,-2,-3,-1,2,5,3,1,2,6,-2,-3,2,7,-1,-1,1,6,-3,1,15,1,7,-3,2,23,-2, + -3,2,7,-1,-1,1,4,-1,-3,1,23,1,27,-3,1,14,-1,1,6,2,27,-2,-3,2,7,-1,-1,1,6,1,19,3,1328,7,1,-2,-1,6,1,0,78,1,-1344,2,27,-2,-3,2,7,-3,1,6,-3,-3,1,7,1,4,2,6,-2,2,2,-1,2,5,-1,1,8,-3,-3,2,7,2,10,-2,-3, + 2,7,-1,-1,3,6,-1,-3,-1,2,5,3,1,-3,2,2,-2,-3,2,7,3,1,2,6,2,54,-2,-3,2,7,3,1,2,6,-2,-3,2,7,-1,-1,1,6,-3,-3,2,7,2,2,1,6,1,7,1,8,-1,2,8,-2,-3,2,7,-1,-1,0,96,1,6,1,20,1,34,-3,1,23,-3,-3,1,8,-1,2,8,-2, + 2,2,-1,2,5,-1,-1,1,6,1,20,1,34,-3,-3,1,7,-2,1,8,-3,-3,1,7,-2,-1,1,6,-3,-3,2,7,-1,2,36,-2,-3,2,7,-1,-1,2,6,-2,-3,1,4,2,2,-1,-1,2,6,-2,-3,2,7,3,1,1,6,1,20,2,34,-2,-3,-1,2,5,-1,-1,2,6,-2,-3,2,7,-1, + -1,2,6,-2,-3,2,7,3,1,1,6,-3,0,96,-3,1,8,2,10,-2,-3,1,4,2,2,-1,-1,-3,2,2,-2,-3,1,10,-1,2,6,-2,1,14,-1,2,6,-2,-3,1,8,-1,-1,1,6,-3,-3,1,8,-1,2,8,-2,-3,1,4,-2,-2,-1,1,6,-3,-3,1,7,1,4,2,6,-2,-3,1,12, + 2,6,-2,-3,2,7,-1,-1,2,6,-2,-3,1,7,-2,-1,2,6,-2,4,1,2,6,-1,-1,-3,-2,-3,-3,2,7,-3,2,6,-2,-3,2,7,-1,-1,0,286, + "PTXTsaZOhW8jt_TQLgA3XHX_eZ4oUjCtkQYr6u5lOI9l-VcSSp8X0N-Gs7ltiwZN-IWlkhe2vOkS9iF70AJ5p9cxWTxuSW20PVkvddsh0p5iQG5y1vyaL8yJdKEAQk8AAQACAQEAAgQBCwEAAAQIAgUIAQUAAgIBAQEKuQEBDAEKCA4IAAy6AwYBAAUAAwIEAAEHBwEBAgACBAIACAu5BxEICgIKBf4QuwUBBQQAAQMCAwQHAAEBBhMEAAs", + 0,96,"I4iFqGRXwqzTxHWfgg8s5xoLWZI92sfMb6_Z4FD5gysT5V3nBinQsCaT4E-wHSU0puP0Ia6vsQX7cpKJoumbaww4i66BQON6x7KFd26Y-wtQGeLyLbUyMt7PyIMED1MJGQsSA70GAQMBAQEAAgsJAAcBAAICAQMEAgcEBrIAAgEHCQAABAQGBgEABQcCdZoCwAb8ooMDEr8DCQEFAQEACgIJFAFrlwIAvAACDQEDCBgFCAUHtAIXAekBABg", + 0,96,"vFPD1oPCVWBD3HFHO8cY8nB3Lld08zvh6O7tN_DZ--noWM1Sez00HyZKn0e6C7HwEhb25DUhnQJLOKLv_WutBSQOkn_yFk5NgSnbes-u_8shNCGN2ZDmFhHicVkvbXcbDLQOL8ERAgEEAgUSCA3CGgADCAECCQIFDcUKAw4CC8cQGhAHAbsBAQABAQABBAEGAQIAAwEBAAACBQMABAAAAQMAAgADAAMAAQIIBAEDBQACAbQGAwECAQQCBgA", + 0,96,"6MGhK1VuvW8Qi5idTjUfBGAmiNaS1m9LPw0sLQ4R-z6T7cBUbp3tVhby0G-C8F2YkZifcDrZrVacsPYoj3Os9KobMCl1RYObo_LQBC20kGocg7WTnaAo_uyiriaTP2gGBwECAgICAAwAAgoHtgABAAIDAgECBAMAAAEBAgMJAQEDBQEAAQEAAQIDAAJvlgQDAgIFtREBAhISEbkBBgkCAAYGFBPRjaG1AgABCQIDAAIBAg4HDAYLtw0HBQ0", + 0,96,"0QGzKjVl_PqMFBbtF5r3U3aWQw3iqMiudPrqMEsFLo4Vh77Xtwn8V2EnE3mgaQo0z-opyZNL_Kj_cE2ImK1ELNr_X5NGQiPSKZWsYG6apq2QI0p7OFFVbCwXaSmFhnkKBwADAwMFxgscC2lYCgAGBwMFBAAHBAQGAwkEuQ4CLr8CAgUGCAcDAgEIBRS_EBzPAggACAEBBzLAIgMPvwIEAQYCAAgAAwIIBAEGAgIEAQkAAQkBAbMAAAABAgE", + 0,96,"QKIBqIVgLCS_SCvbeGYw4YR1JVVa2l6-bLspjAiJ8ggE1ILQyMNQn7JRG3Kj7cRuNInVCghmfAs08xMeR08GDmRlNN8deRG_fpDqfpe4c22xEA1eZIis_F5-unAAO1MAAAECAQAEAgEDAQMCAAICAAABAgICAQEDAAMDAwEBAAAGAwECAgACAAcBAgECuAUnFAAHtiYFCQYCyAQHF-EEGwAIDMICAAEECwEIAgrcIBIJB9IDBRsEC2BtBSE", + 0,96,"PMrjQSB3NO5adAo4dhnjwXJSS_8Ya1HpT_L_O5e4nCMr3j_e4JTFfsxtMcaGl3e_wMw6PnylTDvr1ADfqhvkvlpLAKdLMcl50lEMZwlbi9K-ARcySzDLfeKMTbNWC5teWgQCCgYKBQIAAggFBAMFvQUeBggPZ3HnAQAQBgEtugIADwQDAQsHBwEGAgQKYFULCwIECgUACQYAAXCavAQNAgoRANEDJgnPAAIABAEBAAACAAACAQEAAQEDAwA", + 0,96,2,314,"Xmz4mtroWQRE0I0DVyDUBgFtUQUAMRpquc19Jl6LNvguqQK9brwAVSw3q5LkZXzZjtAAD8kmwS9nAQACAQEAAAEGAQAAAAEAAwABAAAAAgIAAgEAAAoBAQEGAAUBAQAABN_SBQ4GKcT8qABhB5hpAA",6,38414,1,-26737,5,26736,1,-28187,4,28186,"loY4xwDDPC4q3Mlt0BKuFGaTeIgAnWNqAPCmbgIFi3w",3,33771, + 0,96,"DRgASldNfXwAj84E",5,40719,"Q-k54KcfHUQAJS8qdluya-_ShES06E6rWAgOGXlgBQYV5gECAfgA96dgBgE",3,39197,1,-34010,6,34009,1,-24424,11,24423,"w4AAefI-VAAe4QD1b4oAiA7RmQCIeABj",8,40202,"6TtVlFow3RY",6,31809,"_VoA4qhZel8bgHkAYxDnG-sq", + 0,96,"OXyPZ2mujmAumTSXnwEuv-zGnyhfArs9mwH2bBnyGXkRSzZSeYNBQ5LEc78Auk2y8VUJpJZBlV_cNPqk5bjlo4ROrqzRRpAs0VCpMfte7S_lHiG2UZWUGuspVHeNK04AAQYCAQcGAAUBAwkDAgEJAgkC0QsEAhvFAgoDAgcBAQAGCwEEBAEBCNkJBhMCxQMABgQCBA0HCxewCQACAwACAQMCDw4HBAoIvQQB8AIABQEABAAAAQEBAQMAAQQ", + 0,96,"-cgVSLIPGd2cN4nIpEMFVLoQPqlPKGX1M1FJxfpbJLbkKB2elsDNkaqQuFkTW84gBzaayd6OPl0_9jEObiHWOsQ2RO6r5uvQFUFQ2aYtnYkFu26yzZofIghWbmQNG2gCAwEAAQIFAQIBCgUDAQECAAAAAwMB1AUCAAEEAgIDDc0IBQABBgUAGwy2LNQDAAECDQYBAAUCBgIDBgQOvxQCAA4FCXaTBAjEJQEOAALN_g0HBQUKBgYJuwyYfQk", + 0,96,"P3o9lsy-vQSC2x8Mhmwj8o4NK9wR8C1WrJRG6dRXWDCWWAsORqpMUpEIaRJbp4aSaazoxEhXYl-3j5wCNYdiSLPmgL1MqYHPhhQjK7FGibQHLDbMKrClDTbfTW8i_4YBAQhpdAMDCgd1mAhgVQUYAAUCFBi0Pc4HAQYEDQIHBADZHwfWCQYFAgATCb8OAiXNEhLZAgEAFwISAAAGCAUCvgIBAgoDAQMFBQoMAw0FAAQAtBQFBQkWCMoBAwo", + 0,96,"ST9qen43_CZyWYtou_kGuCsTezZuUcJlWv9hlXpsM3fXFcFRz0gpGwYFAiaBJzsOirn31hkEVZIVLDyKehbyICg6ehNCCCQi_6eQHaIGOWf3FxkCjlMT58I0c2qcsXEDCQMECwEDvgEAGwMY1gcGBA332wEHo2MBAxMIBAABEAIEAQEHsCAKGAW8p2sABgUBAgQKBgAHAggEAgHaAQQGEAsA7M4HCAkECATRHwIGFAAACrgCCwMHDAUBCQQ", + 0,96,"fKplSmggsMY0K_MH5hmrZj1IIMCMWnL5VvjKRsAxDsBJHZTt0M1xYLjSSSRLuFDvkb2hMoNkTm52_lZBplnDFHYNfN5_iQw-0EUR6gMR5lNgUcdhr_izR_czZ7QtFZALBLkCAg4DAgcHAQcECgO8EwICBAECBAABAQITDbkRNLkBDRAQEtACB5GdvC7RABgRAwYTuQMBAQEHBAcBBQUAAgCFfAcDAAQFAAkABQW5GwIDEQkIBgLJBgcNFuE", + 0,96,"y1Rx1gCHySvDp2Yidsp7Dtx-RduoexPaK5ICKzc6jeYn1zH14Jxxf11gDybiUwBBlqE9mJFgejHt2D1WcupJlBBBK53DwoHB82S5swfW7Cyd6LlHM__KbxueLHVSD3oBAegQAQMAIQIDvQMREgINvgUHAwICAgMACAEBBw0BAwcKA7kNBQUXBg63CwYACBYCAwEADAHHAgEBCwEBAwYODQAEC-YLCgQEvREHAwAOzTjIAAEWBAsABgAaB9A", + 0,96,"EZNnb5COiXcf0YWq3MkuW40r40zmdhciADQhUKsNgwHf9qI7pEj6J2ObZ9aGd99i1RKPA3LVIwVF72Q-xvCr_1CwEcIcPrzjNHgMZFXVZejX42c4G2c5Ri84_CwTN4XMAwASAAMFCAEMAQMKAQrsxwIBBwUDAwACAQMBAAcAAgMACQIBCAAB2wUGBAEDI84B7Q4dzwUBBQUDAQcFBwgRvwsEAAEAAgEEAgAGAgIJBAECBQILBrtGsgICARA", + 0,96,"dpMAUiv1bg-V0wkmowwAYXuLrNgHxGka-IboaZLC_lado6sAFN2vKReyMVXzTPxyQaKBA5H13fUAhW6rTWYNx3IVgg3wX9OQMSpplGbNwRfTKjAZ5bPzPdzTENB-LGwRAAMGDwG8GgbiBgIBAgAIAQEFAAkFAwYGBAgHvgQBAAQAAAcABwAKGMYsBMcBDwIAAwMCBwEHAQIDAQMKBwO2BAAADwIBAAQDAwQCAQAAAgABBAUFCAkAuhACCgE", + 0,96,"fE7lsItU32m8XX8eL8f-egdHgRAlAluI1aqH7eqd7I6LXXzlb5WeQ7Xc09WpCA0ZACPGSCMcxECqs1JaAMUcqF5qlfncAaXyMz4gNDskrogPjNMUPtFkwIw4Fr4PrnYXBAEIAbUABwIDAgEDAwAAAQECBQoFAwEBAAICBAEFBgmx_6peCAMBBAcDBQoACAABAwMCBbkADwkBDgAlwwwHAASEhQcAE7csBBa8DQoEAAAGCQjpCNwCBgwGCgI", + 0,96,"p2_KViv4oogdBtqaf6O-EOhy5RumG4kA7U3DAxNJ-OfUQw_Ed_araAJmRr3yNki3-sU6SzYVY4HpteTyfrIBaWwZSYFQt-0AdmoqpIj_wBUfryAZyhaV0Bi2aU9KOngODwJiWgwsBAABwiUlA68CAQsCCAABAQgFAAQBFQoBtQkAAwsFAgEBBAIOBQECBMABAwAIBAgSCAICBAAGAAoDy-cBCgMAAAcFCAEDCgYDCQIKsgABAQIAAgADAgE", + 0,96,"WhpWz8kPAC_GNpDvGPYZAEilWA9ZnEUUeEUt8z8nlA0v7iJKPqAZkKTJoW2bq8JUPJAULnbzu2dCZuHOocYoqIN7FCYx3iQq174vFvYfLFsAAAObaQMACAEECQEDAgAAAQABBwIAAAEAAwEFAAMDt_8CAgIBAAYCAQQGBQUGAAEFCgpjVhAAA_sKARAGH7ECAwAABgEEAgEBAAMCAgI",3,1,"uK_MxBd-QwKqRxXDbI17AQMAAQADAQIB", + 0,96,"PoMvJ83Qsk5dRHxfcH1BHyb7rJQjR0_5K2dVpSCoSz0POWQBQl8f8gUN3PcPdq7ZDgnuN22DSjMSRgSxzR09S-U7vDsBH2AnLVoThoBC9RdwDb6-iUb8UeK9rB6qVYEAAgQBAgEBBQYBB7cFBAYFAQICAQIBGQAMyQsUGrQAAAABAAAAAQMAAgABAgEBAQABAQEBAQMCAAIAAQMBAAICAwUBAAAAAgIAAwIBAQICAgABAQECAQgBBbSnbpI", + 0,96,"mJFG8fF0WHn5BNu3Rhono0pfYd2kKId4UouJkJxarBdPJmNsKNjGV1EVITBdD_bkAn83bEsiHgB-7Xw9QV4_yaT0wE__rAVHq2t1wNIm2cQ87M1DRx4d243dD_9nm1ACCgkHBwIABgkNBrcWBwYUyatuAQYUAwPbDCMGtgIAAQQAAQUBAAIAAAACCAIEBAAABAMCBAkBAQIAC8EcGMmkgQMF8AMAhILdAAUBAAEBAgECAQAAAgAKAgcCAAI", + 0,96,"5SyczxOJxuhS9Fe_rjdeHL90mZO1HARfrfB9O4aXozZMZkqDQkI3rD0velLROIXg0YhtlBiTJ2C56AJvZAHgjp_xfD98-Vf442cOddm_a2R_XwTYetIVDj_Jz-ElaoACAwQBBgIMAboABQIGAAEFAQIIAQwNArsCAQQGAAcDAAkDAwAAAAIDBAEBAgABBAEDAwMCAgUCuAkNAwEBFAMEAQAMCbMUBRMJBggBzwgEiF4CAgUAAgQADQADAQQ", + 0,96,"VhvyOvGDy4-k7TP2PkA7QiFjWQHQXUKQGIUIyyZvhC1TaP6K985K9BjyQJks2FNTAT5An5TyMQ3sif8IS5EPspuEpQMO419AhloKKjjgPAfZZhboJdynesTFIhRk24AAAQkHvQQZAg0BAnyTxwMCAwEAAQUBAQICBAEBAgABBAAAAQUAAQEACAABBAYAAAIFA7UNCwYPAg0CA8sCByAMCNvoBQcGHQAGCLqndwgb9Qm-BAIBAQECAQEAAgM", + 0,96,"DT08kxlBwFCp5Be1AY6OqnM6XpaSztUctDyKB15JD6sZ36cJQOgpItEbAC0pB408RrmpmlZOEYhEgZfLd-OlIpepJVzjNau97xqtoMYO-COzbv5hwpbnrVdGnHShH2IAAQEBAAUBAQECAgEBAQACAQIBAAIBAAEBAgIBAAEDAgEEAQABAQAEAAAAAQEBAQG4BQECABICAgMADAPaAgABBQMBAQECAAYDAQQCBAEBAQEFAAcCBQHJJgcDywA", + 0,96,"afU9ymwo02M7qzmO9Wk3h2GbWC6LHJTYkxX-tA4xeXESezUnxVeKzjjIzwJ3cyR53zpffR-IxSdNggKl4B45SF-ZpJeDc7eTNirUGpS0ESM0BqDv1VNrckGiXyG3vV0XDQbo8x0KAMUAAgIBDwQYCg65BAMDAQIAAAIBAQUBAAEADAQCBgUABQEAAAIAywQEAQIHAgMDCgwEAwoAtwAABQYBBgQBCwQEBAQAAgIAAgMEAWqWygIABfsBAw0", + 0,96,"cn4ZDpRGyYAxZTWOJY0LxsIoR2PsU1rDIYVN9VOsqAmGnDPLICLcUfnBZhEuUEX484TLxkoBX8nweHMs3uG0p9IL6BFZxz3gK0djPmwsAlIEutjd8BmrP_cZG1dAAfl0AwUNCMQFpp3W4gECBAUCBhAQAQMCAgwAAwQAuwQBAQIBAgcEIwIFBAO8AQcDAg8fAQEDyiYDB8AHAQEIEA0SwwoQK7ELBwYFDiS2AQMGBAUHCwoUAbwPAQoRAxc", + 0,96,"-1BiakTbemXc_DkJ-z1ZYkMAjeCJSymn6fcIAGpeFYA9VCrhz9jn9WplOqW8Cg7xxzgVLLwAi_mcGkT-pfcOrBGXsdr7OHzsNaL2-YGZ40F3j2RPsMIYAdBqFR4BsAIBCAcDBgkOeZjOmgCEBQIAAQlrVqoAXwMFAwIAAZNwAQMDAQQBAwF_hnqQcJIGBWOgvggGCgcDEQ8CBLIQAQgXzwgHEhkA0SvJAgUDCgrwDOj9AQ",3,43557,"gv9ZoA", + 0,96,"g9v9JjBgboE98wUdKJH5cgGNewWAiQABDABqoA",3,24686,"puNUmZl3AB7N9R14VEmB0CaU2WeYAL_qVatJN84EYR59TFYiOS8RvrofJd9tsphntZFOq14IB5MAfAkNbpcKvAIBAQGeZZsAagCWcAMAAQAAAop3AQCIeACIfwCBggJ8hXuPBg",3,27320,"Wz9akmej",3,23717,"hf8ZEe4AD_tgDYx4iACcvg",3,42484,"09Hoof9FW2eSdwEDDgA", + 0,96,"phQpl0biGYdeAKFeAAy4OnNt6jSJukIKmEATII6QPK1SJfOFRBsAQG5t4pZpZpkAjeeKUtgReVw_dOJLLiSzHY4Z7Uv7BFr8g3i76JX19KaHV6yzyLoZEIuoZEKyWPmcBQTIk3gTdQBfoQBkApptAAMAAwACAQABAAEAAoZ7hXsCBAR7AIkIBWqaZp5iAFUCqVkBEwYDBAQDCAMBc48CAQFtmWeeAbYBAAEDAQABAwABAQEFmWgEAAECBAM", + 0,96,"z9ylKoqbjdRDN8BEsHC5uUmr9DWE-ywmWlDTN4bRv8IAOvOeoi1CDgVeYkVpGGpRASw8SK3h4t6PeY7gIKHVZoMnVWBXKWoAKRM1_WhDCtYA5DQ-fGq_HeKIdz5kXHABAggMAxIDvRAHAB_cBgIEBAjLBwwQAQEJEQYD1QYGAAcFAQPQAQANAQQGAQAEBQICAAIJCgLO-QYCBQfdChEM4gQAFgKEAFcBBwEAAAKeAGQFAgAAlW2TcY94A4U", + 0,96,"iCaXFqFvUSyRnjhpvNErs0GqBYsf2-kv_8Ev_olS9tpO3c3FA0bEkECJSeXJwiSznQInk0tQ9WdxZjuogY1AJ0y2zUmIY4St9JpiAOyQhUP9LNmKSIYzjEvx-I6fmnoABAACAXiOAgIFaZcJyAoCEQsGwAEBAQUBAwMDCAQBAAMDAQALAwEKBQBmVQEBAQIAAAgAAQUABA0BAQIDAAAEAgMDAQkBAAEFAAC8DQYBAgkJFgi2q3EBBAIPAgM", + 0,96,"S0lcCB4WXvk5fltBMf6Q9yj-ZBa0kLM4HZ8OF3mvwxplm_XC7IHT7vuUkpvGLAdmH5wEGKPTSlfYH_u86VJ1gyMdgFdcZ3nQKtYAQOE-KAC6c9C-CwXulwBWbaJtkpAGAAHuFrMjJbsCAQMAAAMAAQUBAgkBAQAEAQEOBgcBaZ0CBcomBb0BAAMEAgECBQUIBAIJAwQAAQIBAQIFBwSzAQIAqFwABgADAAACAAEAAgICkm4AknAAAwGMdYs", + 0,96,"4VQAlI_Um4R7AN1QOZzCQhFCEQfzO85_pGEAN8gAtSggAGwpzZsAjUI8Is8_d28EAIZ7AYR9gwCEBAMEAgAABAACAAABAAJmAF-hchUAeQBYCAOdAHYEDQ1smQM",4,25672,"f44NSyROw8jdbwbBMKfFy0FCgvrnDK1L6_A-o3zlm3Lv7Bi_y1HFuiprZ1iA4g4NCnJeCQEKHwgEuAYZGBEBAcsJJMEQIByyAQEKBgADBQIKAggDAwIBAg", + 0,96,"cDrgWCTSAFiw9hIoP8WLBr0AAaoAYACgZAIAAQ",4,39358,"Pqb-i1wXFeolJlBcb5UA1PXTYQAJF94ASpL_AS8dnwZBbHzPIhrJT7egfwB6yrqi-WN7CXoADFkjeuu8lXcIQfCdTmeyAB7hWHOh3nIBhnwAhICAhwAAAgF2AJMABGkAnwFgAHcGCQAADMMABAGmWwIDAgQAD4sAhAZ2jQRvngBiAFUBAAkNCSIDBrUKAQAHmQCBf4oJxQI", + 0,96,3,42674,"zZvraRRlbSA1UAYEBuSCzdQXcL0LadnkPe6xJNgEj53B7nxTO3yHz75zsf51sOFjshmvWHULpSvOSBOGM3yaK1CwViWjyINoMgazVTpUxtBmB6LhtnA6DTWYyk4ECSfMBAIFAAIAAAUBDQIBAgEBAwUDAQICAAUCCrkDBA8BCgACCwUPBQe-DQMEB-YKCQwBDA64AAUFAAABAwIAAQQDAQMAAQQDh3oBBgIFAAACAQEAAAMFBAQ", + 0,96,"nPA7XoecAuxVqZWpo5_fZ0EC3mE9TCwG401PxB-_-KiWa75Qkvp8sRFdn2NT15GeFZCDJtbglRx-zzaIyM0x8KCbr56ZfH2KDm9ncTY4tA_UHPYa46dMhb-U4qtIqJa7AwMEBwUBAAYAAg4KBAMQANMJDwm8AAIDBQUEBQIBAgIEAQIGAgUBAQEFAgICAAYJswIGAQkBCQSHfQQBAQIBBAgBAQABAQABA7wAAQEAAQAGAAEDAAICAgYDAQM", + 0,96,"TtEPBxgg2T4hGMjezwr1U44Iz14QsugibcAKZfW16V3YoIDeeHxPxtT7ipMXrhjSetalbEmJQ3QENFepAYVpINncfyc2Pr-C7G48ICsGfHFAz7i657OOHI2NZVPlT3EDAQAAAQUAAAADDAUAAwABAQICAAG5EAALCQQBAtYJAhEBDBsEA8UBI8cAAAIABAUCAwAAAQEDAgAAAQABAgEBAQEAAQACAAMAAgIBAQEAAgEFCAACBQAAAQABBAA", + 0,96,"XKULJ1rqp_gBbEPeL42-oOxC-ktI1jahDv2Dd4TdiOFWPiIbV7j-I385JRdY-H1Ef48bA4RAdAFHZCsWc6ivatnnnkx1V5kP6TerD5SxR4ZDCW8GEbppA1T_E1mUOZcBB7MAAwMGAQEDBQcKAgYEAwIEAwUAAQEHsAIAAQQJAAQBAQEAAAEBAAEGAAIAAQIDAgAAAQACAAEBAgUBBAADAQIAAQUABskXEQbIAfcPEd0LBAEBBwUHBgMAAQM", + 0,96,"KgpImTf_lcCDPtATP8qC5qX9lVBJRPuC0784vUkXQikopsS1KXV8u19J6hmo_RwD8YsoqyQ2xAEmC13jHDtVH2JzPv5TVTMBK8RThq9dj9U4I-9v8O0ztYplkL5Cno4ABQG7CAYBBRzPAQABCSfUAAEEAgIBCAEAAQQBAQEBAwIHAQAABQQEAAMBAQEBAAMF4QLTAgAGBAEKBAMBAQIEBQ4IAAYD6ssAOgnCF_8DGNQJBfwOBQAJBgcCwQU", + 0,96,"q4QPlikFZ7-4kSIVrv05kbg_Iw3BiF_wqRlgc28HubOBJB0cIo_MoLnyJgEhLeigixuaOLldJzxsWiIT3TNnopYZxIF6tQ-TfGz43k80d_cqqBBJ_OEgsXXn-V-FUVQDAAgEAAEBAAEBAAQBAAMIAQEABAMBAAEABQNvlAAD5gQABALVAAMLAQIAAgECAgEFAQABAAEBAAIFAAMEAwICAgEBAwMAAbgEBgEECgwBBAEHBQYBAtYCkl4YDhI", + 0,96,"9s_uPJGPg4apFY9-MkJmzmNKgKPa9AFDqk_qRf42wTHpTW8v5QFvcpI77KUGRgC-1bXeAKCxLLgDchdTuwqjj8MprSlrKvZt4wpxpR985fg6zyeAN4SOJkSlLZRqYJMDyQIO3wEBAwIIAA4ADQN-lQAC0wETAxkBC8ULAgMABgIC_gINAgcFALkJCQMW0wMFCQAABBURAMUAAgMFBAECBAEAAAMFAQQDBAcBAQHMBwQABAQVBQYCDADAFhQ", + 0,96,"rBf2AZfG4lTlQpy4HrImU-lV_lsjY1SQs-cDMJnqm4o9K2Zv-T-kMfmTMurjK2ot55NMpzwfn4EmFEhbn1dg2jfgcN9V4ICDhEMJhYQpQruVWfAFRy91SGFoq-9WxozFCAcmyqlZCgUBAAIBCQgLDQgAuAUCBAQHCAEGBwgDBwICAQQBAboDAQoFCw4SAAW8DBABCAIFAA4AzgEFBQ8DAhMCA88IBxMDBw0EX1gUBwEPDQYACrgAAg0BAAY", + 0,96,"EkfaXJM2owzDOojhXHP_OALcKCIUDRvpKPf_3XpWOXeartze3DK0XSr9Z-ubIOplaaVMThDvbaXYVBQ4UHMHgUBa1gNKAJxWd2SVlBqDFxQZA7YzrWiatVtqGTwATWkAAQYBBwEAAAEGAgABAgcBBAAAvgcbBhAC0gQIKcMFAwUBAxoCBQ3S7A0K8QoBBgABBAgDCQIGAwICAAACAAADBAKyJwQBAQADBgoAAALWAwvdFjezDg0bAQDYIQM", + 0,96,"BdBi-gH6WFV5q-a15dWSgU_bWjA3I5u_9IUFLiYI-RUfbLgufTNyhbRyrOme9H0nvFjOM64ssvLvogu1nkcfTLnqzZlv9kpigl8e3wpwK04m8DeEVqnfiHHjLTIV3o3GAQIEAhQPAQEADAQJA7P-BQ0O7vMBBQcCAggEAQQEAAEEAAMAAgIFCQcDBrMARvHFGQjgDAwFAQcEGQL08gHl7wYBAwEHAgAFAhkUAwC3AwICo2iYagIBCAAFABY", + 0,96,"OBi0X-FRswlUDdnUwHZlNGyp2I3Ze12TZeKjOfUqOul_La8F8ekAUsLc7HJJwQ7uUBaO1XYeqOvFsqrVOD7eVOh5GjIbXIrkrZUiTHxqW-0J_UI1LTsMHTzImsX8apTAAgEIAgoFAA0NzyjiFAkMzAwF8gMQjIvMAgYHAQoBAA8FAgsDCGJqC_UB7AMDM9cHknsGAhPIERgIBwi4CQAJLgvGESPCAwMFAgADBQEFAgQHAwsLugUQCwIYAwM", + 0,96,"KkCBXhyakcBD48ywGW8VzyBqrmWwj_EFfyAAY19rnLMIPFxHyvVMfid4NoJL0ey8BwF2cwj_EoQVo7DahEqAq1CuglDahPjeEpOzbigz9ADth-zo_8Xo34X_EE38fpa7AhDsBgsFBwEFAAgPA9MQARHg7gESEAkCAhEHA_LLBwkdBsoHAwABBhsFEAG5BAAAAQADBwICAAGXcgEIAwgBAQIABAEHAgYDwwgACgKIVQMNAgYDBQUFDwQMAAI", + 0,96,"wV0zo1JdBc0uBvv808L2AogG_5UoureesezOSVBouGeCoSHuWY_N9rum18OfHZUkY2XKgHY6mqAAvYKe0bgtjKomMPkijTXaAY6_CRG_L4dFZuT3EFpE1dNEqAhijlQm7yECDAHGAxMBEggGvQwADQcCAAYHF7VCvgEEBgUIBggPBAUEBwW8AysFEr4FAAUHAwABDwAWAAEBuz3CAwABABUDEAUQBAi2ACIQDwABuAEKAQMDAgUBBAIRAQI", + 0,96,2,30685,"BZ-vXd_GDkkUrv-r1emOdJpqygV53WHW9wReZZw3LukJTUG5S7vVgEOEVnRirP2qav1qHzHRYo-_2DREKiP1HsATGrfXZiXhIsvAyhNz6b5AOn8LAZosYHebzHmYtgIEAwICAAYIBAMXAgEABgkBuBboDgkcBcYGAh0eBgIAAL0CLgTXCQkb3SsEvxkbCrgNAwIFBgQDAAAEAAYAAQQGcpIGBsMfDhDC9QQGAwcKBQ8AAg8GtgMBBQ", + 0,96,"Yl8LNkpe4lZ_4Fe-ppkABMXoiIZLpfBk28JD6VgkgjdxDhHBXIN9ZYahm0sIc3JUNIWyyG1TwsTEU44QFALyQVNka0Rg4rTnRgACutw0tFNFdFatLHOSLtp1eDQwCV8NAgIAAAECAQ8EAQgAAwa4DgEBBR8JAwa3AAYEAAEDAwMABAAFAgABAAEAAAECAgAAAgMDAgICAgACAAEEAQcFAMgCL8kMBwEGJ8QBG9kLDQABAw0JBBO2AQcPBgU", + 0,96,"jTDyPYHPZsuW6DaOAK_MYbVV1Cc3hQPtxUtKV3vkuxWVbAKIJVtbpKg5G_YAYBudaZjpT-o5ZSoE-Ts1a64cjtcxYm6cmFG_wfn_U3Wf0xu-7iPUmOmX1uo8Q9XtOHkACQEHAQELY2oBEwAC1AcEAgMCAwj7AgYDAwkTCgLRAQUZCbwNAQEAAQAFAAMDAgABAgMCBQEHBAkGCLUDCAEBAAEFAQMDAgEDCwMCAwQCxiHoDyrAAgUKAAECBQA", + 0,96,"O3jA12FpgHMtTDt5TLAodifVF3BpNYprtGJ0H_7cxeYXTyeXYzCavakroFIokJoA_OmpTq4RLcHYQw10PC11jQ4JHAjxN8yXMs0Hvc5hHhwCjP6YLIeyHwDs_1ixvXIOEQm1AQMBAAEACQEICgIdwgAGABkAABQF3B_QEQsTzwIW9AAEAwsZBQ-xFQwFEdorErQAAhoTHsgFBQXfCCEN4QAA6QwNEgPOAQQBAAMCAwMAAQQACwAAAQcBBQs" + ], + "iso-2022-jp-katakana":[12290,9,0,-13,249,-10,-82,1,1,1,1,57,1,1,-37,56,-91,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,1,1,1,0,0,0,0,0,1,3,-89,0], + "gb18030-ranges": [0,128,36,37,2,4,7,9,5,6,31,32,8,10,6,9,1,3,4,6,3,4,1,3,1,2,4,5,17,18,7,8,15,16,24,25,3,4,4,5,29,30,98,99,1,2,1,2,1,2,1,2,1,2,1,2,1,2,28,29,87,88,15,16,101,102,1,4,13,14,183,200,1,8,7,24,1,8,55,56,14,78,1,2,7102,7103,2,6,1,3,2,4,7,9,9,10,1,3,1,2,5,6,112,113,86,87,1,2,3,4,12,13,10,11,62,74,4,14,22,26,2,6,110,111,6,7,1,2,3,4,4,5,2,6,2,3,1,2,1,6,2,3,5,9,5,6,10,11,3,4,5,6,13,15,2,6,6,8,37,38,3,4,11,12,25,26,82,83,333,343,10,50,100,176,4,40,13,28,3,6,10,12,16,18,8,10,8,10,3,4,2,4,18,22,31,33,2,3,54,55,1,2,2110,2111,2,3,3,4,2,4,10,11,15,16,2,3,3,4,4,5,2,4,3,4,14,15,293,305,4,8,1,20,5,7,2,11,20,21,2,85,7,11,2,88,5,8,6,43,246,256,7,8,113,114,234,236,12,15,2,3,34,35,9,10,2,4,2,3,113,114,43,44,298,299,111,112,11,12,765,766,85,86,96,98,14,15,147,148,218,219,287,288,113,114,885,886,264,265,471,472,116,117,4,5,43,44,248,249,373,374,20,21,193,194,5,6,82,83,16,17,441,442,50,51,2,3,4,6,1,3,20,21,3,4,22,24,703,704,39,44,111,118,148,149,81,20983,14426,18374,1,92,1,31,13,46,1,4,5,6,7,8,4,6,4,6,8,9,7,8,16,18,14,15,4295,4296,76,77,27,28,81,82,9,10,26,30,1,2,1,3,3,4,6,9,1,3,2,5,1030,1032,1,19,4,14,1,5,1,15,1,5,149,243,129,135,149606,26], + "gb18030": [ + 1,19970,3,1,1,8,-2,1,4,3,7,-1,-2,-2,2,4,-1,-1,-1,-1,1,4,3,3,-1,-1,-3,1,6,-3,-1,2,2,4,6,2,1,6,1,-2,10,1,7,1,-1,-2,1,5,2,5,-1,3,2,1,4,1,6,3,4,-2,4,1,3,2,1,9,-3,2,2,-1,3,7,-3,-1,2,3,-1,3,3,-1,-2,3,3, + -1,-1,-1,7,1,2,2,5,5,2,5,-3,-1,2,4,3,2,-2,-1,-1,-1,-1,-1,5,2,2,1,6,1,1,5,-1,-1,2,10,-3,-1,2,1,2,1,2,2,-2,4,1,-2,3,2,3,2,-2,-1,-1,-1,2,1,2,1,3,1,-1,2,1,2,1,-1,1,6,-1,5,2,9,1,3,1,4,3,3,1,5,4,-2,-1, + 1,4,-1,2,1,-1,2,3,-3,-1,4,1,-1,3,1,13,1,-2,2,1,-1,3,1,-3,2,1,-1,3,1,-2,-3,11,3,-1,-1,4,1,3,1,3,2,-1,5,2,4,1,-1,8,1,6,1,9,1,3,2,2,1,4,3,2,1,4,1,21,1,-1,-1,2,3,5,1,7,1,19,2,6,1,3,1,11,1,4,2,4,3,-1, + 5,1,10,1,3,2,6,1,14,1,29,1,-3,1,4,-2,-1,3,1,2,1,3,3,-1,5,1,2,1,2,1,2,1,1,4,-2,1,7,2,3,2,3,2,1,2,2,4,2,2,1,-3,-1,3,2,-1,-1,5,2,2,2,1,5,3,3,2,3,3,1,-1,-2,-1,2,2,-1,9,1,-1,2,1,2,2,6,1,-1,-1,2,2,-1, + -2,1,6,2,5,-3,2,1,2,2,3,2,1,6,2,1,3,1,3,1,-2,-1,-2,2,1,2,1,1,6,-1,6,5,-1,2,2,2,2,-1,5,1,-1,2,1,3,1,-1,-1,4,2,2,1,10,1,-1,-1,5,2,7,1,2,1,7,1,-1,4,7,3,6,10,3,3,2,3,1,-1,-1,4,1,-1,3,1,-1,6,1,4,1, + 11,1,8,1,3,2,4,3,-2,4,1,-1,4,2,-3,2,2,2,1,-2,2,1,3,1,3,1,10,1,2,3,-2,-1,-1,-1,3,4,-2,-3,2,3,-1,-1,1,7,-2,-1,2,1,1,4,-3,-2,4,1,2,1,-1,2,3,-1,7,3,2,1,-1,2,1,-1,2,1,-2,-2,4,2,7,1,4,1,3,1,-1,5,2,3,6, + 2,1,-1,1,4,3,1,2,2,1,4,1,12,1,5,3,3,-1,-2,-1,-3,1,8,3,3,-1,1,5,2,1,1,4,1,5,-2,2,2,-2,-2,-1,2,1,2,1,-1,-1,4,2,-1,1,8,5,2,-1,-1,-1,8,1,-3,2,4,2,3,-1,-1,-1,4,1,-2,-3,-1,2,3,-3,5,1,-2,1,8,-1,-1,3,2, + 2,1,-1,-1,1,4,-1,2,4,1,10,-1,-2,5,4,2,6,3,2,6,2,-1,-2,-1,4,1,-2,5,1,2,3,6,1,4,1,-1,2,3,2,1,-1,-1,1,4,3,1,4,1,-1,-2,-1,-2,2,1,5,2,4,1,5,2,4,1,2,1,2,4,-1,6,3,2,4,-2,-1,2,5,3,5,-1,2,1,3,1,2,2,-2,7,1, + 9,1,-1,-1,-1,-1,-1,-1,5,2,3,2,2,1,3,2,1,4,5,1,-2,-1,-1,1,4,-1,2,3,2,1,-2,-1,5,1,-2,6,2,2,2,-1,8,2,2,1,2,1,3,2,2,2,4,1,3,2,-2,-1,2,1,-1,3,1,12,1,5,3,2,1,2,3,5,1,-1,3,1,4,5,4,1,4,1,8,2,7,2,3,2,15,1, + 11,1,7,1,4,1,13,1,9,1,2,1,2,1,-2,1,6,6,1,-1,2,1,2,2,3,2,2,2,3,3,-2,-1,17,3,2,1,3,1,4,1,-3,2,5,5,1,2,3,-1,-1,4,1,2,1,-1,5,6,2,1,2,8,-1,-1,1,4,-1,3,1,2,1,3,2,5,2,4,5,5,2,7,2,4,1,1,5,-2,-1,-1,3,2,-1, + 3,1,9,1,7,2,2,1,2,2,-1,2,2,2,3,-1,3,2,8,1,-1,4,1,3,1,2,3,2,1,-1,3,1,3,2,-1,3,1,3,1,3,1,4,1,-1,2,2,5,1,5,1,4,1,14,1,7,1,3,2,2,1,3,1,5,1,6,1,5,1,17,2,-1,-2,-1,3,1,8,1,5,2,3,2,8,2,18,2,4,1,3,1,11,1, + 3,1,14,1,6,1,-2,-1,2,1,2,1,2,1,8,1,-1,2,1,5,1,-1,4,1,2,3,-2,2,1,4,1,-2,-1,-3,-3,2,1,2,1,1,4,4,1,-2,2,1,-3,2,1,-2,2,1,1,5,5,1,-1,2,1,13,1,-2,-1,3,2,3,1,1,4,-3,2,1,4,1,2,2,-2,4,1,4,1,2,3,2,4,2,2, + 6,1,-1,2,1,7,1,3,1,4,2,2,5,-2,-1,5,2,-1,2,1,3,1,12,1,-1,3,1,-1,-1,2,7,4,1,-1,4,1,3,1,2,1,2,2,-1,3,1,7,1,-2,-1,5,1,3,1,5,1,2,1,10,2,4,1,7,1,4,1,2,1,9,1,2,4,4,1,18,1,7,1,14,2,7,1,-2,2,1,5,1,2,1,6,2, + 2,1,5,1,-1,-1,-1,3,1,3,1,-2,2,1,2,1,-1,5,1,23,1,12,1,26,2,-1,2,1,8,1,15,1,-2,-3,1,7,2,1,2,5,-2,3,1,-2,-1,4,1,2,1,2,1,-2,-3,-3,2,2,3,1,-1,-1,1,8,3,7,4,2,2,1,1,4,3,2,2,3,-1,4,4,3,1,-1,9,2,-3,2,1, + 2,2,5,1,-1,7,1,2,5,-1,2,1,-1,2,1,4,2,-1,2,1,-3,-1,-1,4,2,-1,-2,4,1,4,1,2,1,3,1,2,11,2,1,2,4,3,4,3,1,4,1,-1,-2,-1,7,2,-2,7,1,4,2,-1,5,2,3,1,2,2,2,2,-1,5,7,5,2,-1,3,3,-1,-1,-1,4,2,-1,-1,2,1,6,1,6,1, + 6,1,7,1,2,1,-3,-1,2,1,2,1,10,1,6,1,2,2,6,2,5,1,-1,4,1,2,1,5,1,-1,-2,3,1,5,2,8,1,8,2,2,1,11,3,2,1,-1,11,1,-1,2,2,4,1,13,1,22,1,3,1,25,1,13,1,7,1,13,1,-1,2,2,2,2,1,5,2,1,-2,2,4,5,1,2,2,-3,-2,3,1, + 2,1,2,3,-3,8,6,5,2,2,2,5,1,2,2,4,3,-1,6,2,7,1,5,2,2,1,2,1,15,2,-3,-1,-1,1,4,3,2,-1,2,2,3,2,-3,1,5,-2,-1,4,3,5,3,5,1,-1,4,5,10,1,6,2,2,3,4,1,12,1,-1,9,1,-1,2,2,3,1,3,7,-1,3,2,-1,-1,-1,-1,2,2,3,1, + 4,2,-3,2,2,-1,-1,7,1,-2,3,1,15,1,-1,-2,4,4,3,1,-2,-1,2,1,-2,2,2,-2,3,1,-1,-1,3,2,-3,-2,3,6,-1,2,1,-1,2,3,4,1,6,1,-1,2,1,6,2,-1,4,1,5,2,2,4,2,1,-2,3,4,3,4,2,1,2,2,2,1,2,1,-2,2,2,3,1,2,1,2,1,-1, + 3,10,2,1,2,3,-1,2,3,-1,2,3,3,2,3,7,5,1,5,1,2,2,-1,7,3,-1,2,1,-1,2,1,3,1,2,2,4,1,2,3,1,7,2,2,2,1,-1,1,6,3,1,4,2,2,1,4,2,-1,-1,3,1,-2,-1,2,2,2,1,-1,2,1,-3,-1,-2,3,1,2,1,8,2,3,2,5,2,3,1,2,1,-1,-1,-2, + 5,2,1,4,2,6,-2,2,1,5,2,4,2,-1,3,2,5,3,4,1,4,1,2,2,-2,3,2,19,1,8,1,-1,-1,-1,2,1,3,1,7,1,4,1,4,1,7,2,4,1,-1,19,1,2,1,5,1,8,1,9,1,2,3,10,1,6,1,3,1,5,1,-1,5,2,-2,17,1,14,1,9,1,6,1,-1,-1,2,9,1,4,3,2, + -1,-2,4,2,-1,-1,4,1,2,2,5,1,1,5,3,1,-3,2,4,3,4,2,1,7,1,2,1,-2,2,8,2,1,2,1,2,1,-1,3,3,4,1,6,2,-3,1,4,3,2,1,4,2,2,2,1,4,2,3,1,3,1,-1,-3,2,1,-1,1,7,-3,-1,-3,2,7,2,1,-2,2,5,1,4,-1,-2,4,2,1,4,4,2,4,3, + 2,1,4,1,3,1,-2,2,9,-1,3,2,2,1,6,1,2,2,4,1,-2,2,2,-1,4,6,8,1,-2,3,3,-1,3,1,2,2,4,1,2,2,4,2,-1,4,1,1,4,-1,-3,3,1,-1,7,1,-1,-2,-1,1,4,-3,2,1,2,2,-2,-1,-1,5,1,-1,2,1,3,1,1,4,3,1,7,1,-1,-2,5,1,2,2,4,1, + -1,-1,-1,4,1,-1,2,4,5,1,2,2,2,2,6,2,-2,-1,4,2,3,1,-1,6,2,5,1,2,1,-1,-1,2,1,1,5,7,1,-1,3,1,5,1,8,1,-1,3,1,10,1,7,3,-1,-2,9,1,2,2,2,2,4,1,5,1,4,1,2,1,-3,4,1,-1,-2,-1,3,1,-1,2,1,7,1,-2,-1,4,1,5,2, + 3,1,-1,-1,25,1,8,1,8,1,5,1,12,1,5,1,2,1,4,2,-3,-2,2,1,5,2,2,1,2,2,2,1,-1,3,1,2,2,-1,-1,3,2,2,2,4,1,3,2,-1,-1,2,1,15,1,3,1,3,2,-2,3,1,-1,-1,2,2,-1,2,1,-2,-1,-1,-1,-1,8,2,2,1,3,2,-1,4,4,-2,2,2,3,1, + 8,2,-1,2,1,2,5,4,6,2,2,5,1,-1,2,2,3,1,-1,-1,3,2,3,3,3,1,"$9",2,21,5,3,-1,2,1,-1,7,1,2,2,2,1,2,6,4,1,-1,2,1,-1,-1,5,1,3,3,-1,2,2,3,1,3,1,-1,2,1,4,1,4,1,4,1,5,2,9,1,5,2,5,1,4,1,4,1,26,1,-1,8,3,2,1, + 6,1,-1,2,3,-1,2,1,-1,7,3,1,4,2,1,3,1,-2,3,1,-1,-1,6,1,-1,-1,1,4,-1,2,1,4,2,2,1,2,1,-1,2,2,-1,2,2,-1,1,4,2,1,5,1,-1,3,4,2,1,2,3,-1,-2,-2,-1,4,1,-1,-2,2,1,2,1,-1,-1,4,1,4,1,-1,-2,-1,3,3,-2,-1,-2,-2, + -1,2,2,-1,8,4,-1,10,2,3,6,-3,-3,-1,2,1,3,1,2,1,2,1,-3,8,2,-1,4,2,-1,1,6,-2,-1,2,1,5,2,3,1,7,1,7,2,3,2,2,3,-3,1,7,-3,-1,-1,-2,10,3,1,10,8,1,-1,9,2,-1,-1,8,2,3,1,3,1,10,1,3,1,4,3,-1,2,2,-1,10,1,-1, + 6,1,-1,-1,4,1,2,1,2,1,-1,5,1,2,1,10,1,-1,3,2,3,1,-2,4,1,3,1,5,1,-1,-2,-1,12,1,3,2,8,1,2,1,3,1,4,1,3,1,-1,2,1,17,1,2,1,2,1,2,1,-2,2,1,2,1,4,1,2,1,2,1,5,1,2,3,3,1,-1,-1,-1,3,4,6,1,2,2,2,1,10,2,2,2, + -1,3,1,2,1,2,1,3,1,5,1,8,1,-1,-1,-1,3,1,6,1,3,1,12,2,4,1,10,1,-1,10,1,12,1,6,2,-1,6,1,-1,4,1,-1,3,1,7,1,5,2,2,1,8,1,7,1,-2,5,1,3,1,11,1,7,1,2,1,3,1,3,1,9,1,-1,5,2,8,1,8,1,-1,115,2,2,5,10,1,4,1,-1, + 3,2,4,1,2,1,-2,2,1,12,1,8,1,2,6,14,1,-1,4,2,1,4,-2,-3,4,1,2,2,3,1,5,2,8,1,8,1,-3,7,1,-1,2,2,5,1,-1,-1,2,1,1,6,-1,5,1,8,1,3,2,3,1,-1,3,1,3,1,7,1,5,3,-1,-3,1,4,3,4,-1,-2,-1,3,5,-3,-1,2,2,4,1,2,1, + 3,3,-2,5,2,3,1,-2,3,1,2,7,3,1,5,3,-1,-1,-1,2,1,3,1,2,2,-3,-2,2,2,2,1,2,2,4,2,-1,3,1,-1,-1,1,5,-3,2,2,4,3,-2,4,5,3,2,-2,3,1,2,1,3,5,2,1,-1,1,4,2,1,-1,2,2,1,4,-1,1,4,2,5,2,1,2,1,3,1,-2,3,1,4,1,-1, + 2,3,6,1,-1,2,1,2,2,2,1,-3,3,1,-1,2,4,-1,-1,1,4,-2,-3,4,4,-2,-1,-1,2,1,2,1,2,1,3,2,4,2,2,1,3,2,5,1,2,1,2,1,2,2,-1,2,1,-1,5,3,-1,1,5,-2,2,6,2,2,2,1,2,1,6,1,3,2,3,4,4,2,4,1,-1,3,2,-2,2,2,-1,4,1,-2, + 2,1,-1,3,1,-1,-1,8,2,4,1,-1,-3,2,2,-1,2,2,2,1,2,1,-2,3,3,-1,-1,-1,2,1,-1,3,1,-1,8,1,8,2,4,2,-2,-1,2,1,3,1,11,1,2,1,15,1,3,2,-1,2,2,5,1,7,2,3,1,2,1,2,1,2,1,-1,2,1,4,1,-1,-2,-1,2,2,-2,3,1,4,2,3,1, + 3,1,-1,-1,-3,2,1,3,1,1,5,-3,10,2,4,1,8,1,3,1,2,1,5,1,3,1,10,3,3,1,4,1,-3,-1,-1,-1,2,1,7,1,7,1,3,2,-1,10,1,3,1,-1,3,1,3,1,6,1,3,2,-1,3,1,-1,-1,7,1,3,1,2,2,13,3,4,1,5,1,11,1,2,1,2,1,6,1,-1,6,1,7,1, + 11,2,-1,12,2,33,2,8,1,7,2,17,1,3,1,18,1,2,1,14,1,12,1,-3,4,2,-2,3,1,-1,4,3,3,1,3,2,3,1,-1,2,3,2,1,13,2,1,5,-1,3,1,-3,2,3,4,4,-1,13,1,-2,3,1,4,1,-1,1,4,-3,7,1,-1,3,1,11,1,5,2,2,1,-1,-2,11,3,8,1, + 4,3,14,1,4,1,-1,-1,13,1,-1,5,1,-1,5,3,3,1,4,2,-1,2,1,6,1,5,1,4,1,4,1,3,1,5,2,7,2,3,1,6,1,-1,3,1,9,1,10,1,5,1,10,2,4,1,-1,6,1,10,1,12,1,22,1,10,1,-1,-1,3,1,3,2,1,5,-1,-1,7,1,3,2,4,2,3,1,2,1,-1,-1, + -1,-1,3,2,-2,4,1,2,2,2,1,3,1,3,2,2,4,5,1,-2,-1,2,1,12,1,12,1,-2,3,2,-1,7,4,3,4,4,1,-2,-1,4,1,-1,2,1,96,29162,3,-46374,"txH94FoBDkm3D_EAAgD2AAACAP4wAPDfIQAAAAAAEAA",8,-14,2,6,2,-8, + "sSUfPvAA6P0a_t4u4op_-vGGkQIy6vv030INAPQAuBb-Df1vgQDPAJ87AE52bgAAACIAAAAAAAAAAAAAAAAB_wAAAAAAAAAAAAAAAAAAAAQA2iAAAd4B_wAh4CE","$5",1,-220,1,342,2,-3,-1,1,3711,96,46354,10,-50198,6,50668,20,-49892, + 20,-40,10,-40,"rMAgxw",10,-46414,2,46404,12,-50704,2,50692,95,-492,1,-46565,3,52992,1,225,89,-225,1,133,96,-6654,83,-46597,11,46814,96,-311,86,-46597,8,46726,96,-223,"$1",8,127,"$2",1,5763,-1, + 1,-2,4,1,2,30,2,2,2,4,2,-4,4,2,2,-46,2,34,2,-6,1,-8,1,-25,2,25,9,-5790,96,-154,"$C",15,58,"$c",13,0,2,-58610,"2TkBDw_PAwIeAAAAAQA",4,140,1,123,1,9,-3,1,46,2,19,1,87,36,656,15,13,3,3,2,38,4,36, + 1,35,1,-885,1,3452,2,10,11,47005,"Ad_sEQH_Af8","$8","6mbtBAOwZwACHOMAAAE",4,58727,37,-46792,21,46755,9,-47041,1,633,2,234,3,12,"oSIJAgACWrEB_T4PsSwzAAAAAADLAQDoOhG1OQ",3,51155,1,-46827,2,-98,2,96, + 1,-249,2,150,10,52650,4,1,14,1,4,1,1,-52782,12,-79,1,11,13,47084,76,-49921,15,49845,2,-30004,-1,6,2,2,2,2,9,-2,4,3,-1,6,1,3,1,4,1,-1,3,3,2,4,2,2,3,1,1,4,2,1,2,1,2,1,4,3,13,2,2,1,-1,4,1,8,1,11,1, + -2,2,1,94,27790,12,-27884,5,1,2,1,-1,-1,2,1,2,1,4,1,4,1,3,1,2,1,6,1,-1,2,1,-3,3,2,2,1,4,2,-1,5,1,2,3,-1,7,3,4,1,-1,4,1,-1,-1,3,1,4,1,5,1,94,27750,11,-27844,-1,2,2,4,2,9,2,6,2,2,1,-2,-1,-1,-1,-1, + 2,1,5,4,4,1,19,1,-1,-1,1,4,13,2,2,1,5,1,3,2,94,27713,3,-27807,-1,-2,3,1,3,1,2,1,-1,11,1,-1,8,1,16,3,23,1,9,1,-1,-1,-1,-3,7,1,3,2,94,27687,1,-27781,-1,7,2,4,1,8,1,-1,-1,-1,4,1,-3,2,1,5,1,2,1,-2,-3, + 1,5,-1,-2,2,2,-1,4,1,2,1,2,1,-2,4,2,4,1,8,4,3,2,7,1,-1,3,1,5,2,3,1,2,1,-1,94,27632,3,-27726,3,1,-1,-2,-1,-2,2,2,-1,-3,5,3,-2,2,8,2,2,3,3,1,4,2,4,4,1,-1,-3,2,1,2,1,3,1,-3,-3,4,2,2,2,4,1,2,1,2,1,-3, + -1,4,1,-1,3,1,4,1,-1,-3,3,1,-2,-1,2,3,-3,2,1,2,1,2,3,3,1,-1,2,3,-1,94,27537,7,-27631,6,2,-1,5,1,-1,4,1,7,1,3,1,8,1,2,1,-1,3,2,-1,-1,2,3,2,1,2,1,-1,2,1,2,1,10,1,9,1,2,1,-2,10,1,2,1, + "w4b0g2SlOrbQuu-xjw6jZvSaYHAOjSBBTWVTyypcVUSSLbJk6PmeBZo53mQ4T9_2qhOOQ9op1URRrscptLY6eVs-RrhU_cglXWeuZlMr24dXFeNQAPLGxDuWuf8mDFJeAgEBAAYBAwB230HBDPEB_yIAD_IL9vokAdXv9BQD9iToGOYQ2xQMDgnICQgOE-H_8QEn1iToBSsKyx7XQOjzBPEP7us-1RjrDvH-IBbPC_AA7SXf_ywSzgoBGP3qEA4Puzz2_tM2ySQAAAAAAAAAAA", + 3,1,5,1,8,1,-2,-2,3,1,2,2,-1,2,1,2,1,2,1,-3,-1,11,1,4,2,-2,3,1,-1,3,2,-1,5,1,1,4,-1,3,1,-2,3,1,8,1,8,2, + "XCd040NPKxPzDsQTeGghIJ7FcENQg2u6PuMtkaiaPPsAzTXHcJFD_phE-mcqLmaXA_wqhXHzb6y62SEAvNtRC1wVFH0YhUkAAaG5Yi3PbbSf_kEfRRXViSw6E1SvsjZ3DhG5CUHCBwAEJhDW9RHo8wA88Q0HvCLnBxEX0SnlFOIh9_ciAQEPzCbq5BkMAeYAAPMAFyDQ-gAwySkPBgH48A7V7QQAPAAAAdj3IgcUxfEk6QYK_-0J7QAW5ysg1w", + 4,1705,-3,-2,2,1,12,2,3,1,3,4,6,2,2,3,12,2,-2,2,1,-1,-1,-2,3,1,2,1,-1,5,1,-1,-1,13,1,9,1,3,1,5,2, + "5OCwRCTMOswsd2hLstGa6xrfc5mlqOEGnWp6LPVh2agtzzWkjvzUSbydoXJE7rHS9WH6lk1jodMn_Qsj-09LwFDkvvYqZPZiCa7OiKG0WfjeLYWFuY5BiwjRtGiTZwnPAQF3_ukVEOH-Mtjn_xIw59QPJP8A7f4uyfABNM_3EA0RFNAEDxXf-yvqFwPOJAIUujPl9QAQEgDMHhnfGO39HdAo1AIc7zLV8DAA5BHs9wEBLtcFJdj_JBLz8xW6SALODQQAAA", + 4,4,2,1,-1,4,1,6,6,2,1,3,2,-2,-1,-3,-1,-2,3,1,-1,-3,2,1,2,2,3,1,2,1,1,6,-1,4,1,-1,4,1,-1,-1,-1,2,1,5,3,12,1,8,5,4,1,7,1, + "OuIaRv8g4dvm6-9j_hl-FDtzUlzTCDT-1wxr7sxnT4iXvjjqJF7dirY3D7LdmlWknmxYHvAMF0Z-O1TKQwixKWDfF4dsuJuYHK4HlxPgd00wjIvbL9x2Nt58yvGi9VcFAje7MNMSEOD7PdUy0-8Z7vccH9MC__wQIfEOzQr5DSr3-9wV3hP48vos5g8c1y4K39sh7vAZI9A75h-wDTHy5gvhADXX_gcv5Bns5xrTMPnXM9H_Gek7BwHYKNM", + 3,3881,-1,2,1,2,3,-1,3,1,-2,2,3,-1,-1,-1,-1,8,1,4,5,4,1,2,1,3,1,3,1,4,3,3,1,3,2,14,1,3,1,5,1,-1,2,1,2,1,6,1,3,1,7,1, + "QGcuONUd3vmhveIYXpl76MonZCsdUOutXaIZR3_ru3IQvMRymArRqa7VltUV0EgGfxTHTLXF83u7u2G6yqyXWfq3MvNwBp_S4mSWgO0TkJXUKdMeMimQ8V9cU1P5qHjYJ-0l0Ar6He_mM9P5JwXkADe9AhzzMsIPAyjEGBEK2hz3DvUe-dITF-DnO94VBNL9-wADKxXr0z_t_-r58zH1BvES6PQAHewA_wAyzyvs--z3-xflEvwN4z_71zE", + 6,-5922,10,1,5,1,15,1,5,1,-3,-1,4,2,-1,9,2,2,1,2,2,1,7,2,1,-1,4,2,-1,7,1,-2,5,1,2,2,4,2,4,1,3,1, + "IByHcxuivw0fRxen8vxakYfNOAYBnGLkyYjbhDMKgJaD39_s5wILzWBIn5AppfVhzqjfOgHT35pRqfAB8gGL4UTQIL7iT4kN9F5OeV_-yXLY9TWHgIhvyGxl1nYf0mAg4uwFPdMd5QfjEQ0e1CfZBO4y5eoRK8IMHeL3KOYw5ukAFxjiBgX82j_I9x8h1hb3-xLbCPz5LffjATHvGcsLCvjhRsAe2ibpAvkU_g3bQ7sBEfFA-AHlBg8I_cc", + 7,9650,12,1,11,1,5,1,-3,-2,-2,2,1,2,1,-1,-1,3,1,2,2,2,1,6,1,3,1,-2,-2,-1,-1,-1,7,2,2,1,-1,2,1,-1,2,2,4,1,-1,5,2,2,1,2,1,2,1, + "Ae3-muyXHmwHf_mPtl7lYovTT2I9OQDJ5NDAJGVut2EOOUPSD-NZC3pwXP1Nefdg90rN2a9-SfMYZLhgQkU-Ux9gFoLEOguuJOjpXH7YG2tQDffSsnzpojLz4GC7WpABAQBOKN1BBAf2xjDDAAMz3fEW5xHxHOQRAzH2BOUb5_QHABnNHxbaLuveEOsh_R7W-hrZ-UXF_fw61zO-PuIa0_EFAP432Sb10A74LtZCsUnzzwbzDy4BCMcg0S_cPdThLAAAAA", + 15,1,3,1,-1,-1,-3,6,1,10,1,5,1,24,1,3,1,-1,4,5,-3,-2,-1,4,1,3,1,2,2,3,4, + "ngIAjaCI9MA-sNT6GBxjkA7zk66fBOYGLiWFvW1uaAXwlPJ1Vr_6g7NrAnzGhNIimeQYgHKtzvHqsKe6YwrBsQEkhYXQqVbtGsLgTSSMbZ-LmnbKBEss0ABLzbTZBujINJUAAnoAABPGLPzU_0jWBxLZFwrrDR3q0x_jPPQK5SfT6yvjG-I0w_U98-ceFL5D6NM4ySzeDiH1D8MY5izZGvsQ3fURAhvSDgsg1TkD3fsgwS4Mzvj-BQUMG9sHAC3PDg_UABgTAAA", + 3,1,5,2,11,1,11,1,10,1,2,1,4,1,2,3,-1,6,2,-1,9,1,2,2,-1,3,1,-2,-1,-1,3,2,-1,2,1,3,2,-1,2,1,-1,3,1, + "JwEDQDvkIWUTbupp7MqHIUqzI_oWxMF3UkMZQqWs1qBCknXll9ZTSBY8suilLYotndioppsAJJGHlWIW5JcweLFMtgRASDHuCppmtAY0taXY9vHgpxySVz3Z1F-lNd6lHnUAAXsAAPIADA_XFu0twELUHADdIwzFNwTM9_5I3A8MzjALwybVAgA12gQr4vjwF_IAEwYN1BjsKMQBQusB_t4S-RT7JOf-_egx5doAF_n-POL13UXt5B4QAP66BirqJfPm-CH8AAA", + 4,1,-1,-1,-1,6,1,-1,-1,-1,2,2,1,4,-1,-1,-1,-2,2,1,-1,11,1,2,1,2,2,-1,-1,-1,2,1,-1,4,1,7,1,2,1,3,1,-2,4,1,3,2,3,2,3,8,2,1,3,1,8,1,3,1, + "wnxXTVVjzSwAEL8-Z9V0ki9PN1SgP_fK4ajxfCrN96KMpmxB0OXdjmmjOHvMZq1zkCD_U3lZz3gkByHe5MmeXOIZNZtUU2gXDExabdOklsmZDUoHTE_yN-cPnlzNAPxXKej1CO0OP7A_wwoE_g_2K8RDvhoW8OUQJsw29NEn1B3v_ka0MxTy9OUzvkC8It4JCCbFFP4I6Qr2OPIe5uEQHcQNMuQVziHnQPb6DPDr8v8mAMU93_ot-8YRIQfFJw", + 4,2,4,1,-1,5,1,2,2,3,1,3,1,3,2,3,1,2,1,5,1,4,1,-1,8,1,3,1,2,2,6,1,8,1,6,1,2,2,13,1,6,1, + "QnWwDa5-DdPbRAY5QYkcKozKmsuQo8zOfEzx5T28qrjbgPGfmd9xCyfZV2iFzciyybZ4sASypFPVBJEDsleHk6uBNvAdUxOgxepkiInmJYQHXX70bdGuXJt0dZJb-Yt8HsES_-INP_fQLwe9Ge72BCoA5f8C_P8R-wDtDhvW_jbfJckn0xrnAS4A5RHb-wUiFgrWASD8Fe_JSNfqE-70-hwe2C_FHBYYz-4EH9f6JOH__QQA-hEV5Cz8B-sK8g", + 10,3564,37,1,6,2,11,3,7,1,2,2,-1,3,2,2,4,-1,4,2,3,1,2,1,5,3,2,1, + "Jybdd-0XjHkldu-SadYDxvK5de1g0oyjhDpOQIDFd7KNAtTW-Xc1XM9faAVV9ggAwGG0YzOkcQni0tLhloXYvRzOXWs-5YuqSucOpUn53VFLXro7GVCCQrs_PcSxpSkAXyfPDewe9iDS_yD7B90BON72AQ3qFAj1J_Dk_fUgF-X87gMl3j3aD_X62w8R9fgCLOTzLNABJtAV9QHyDQYn7NYh_B8A8wXj9EHSAB_h4iET3_439uzYBgAQDgX_AgEA", + 3,1,-1,-2,-1,7,2,-3,2,1,2,1,7,2,6,1,8,1,2,1,14,1,21,1,-1,4,1,3,1,3,1,7,1, + "jNiTxuR7yvwf_3dWuLt4A1qYswBV3Xy7KebtoP_iql7UdZV1_d4OMel4TVPCXq2BOULpuS-z84uI9Lq-x0K6VIi7I7lZLSzGB4simCvExWt9Hmx8ZICKmIA7j2x-SIAZ9uAcE7slAdUTASftGr0NFffnByTl7jDcJ97vCvQq2Q4N7gAwANr6N8MlANgR8vYM9zEV9egfvCrUGTPAEQvhBR8a3OAvAtcmBOX_EQDqARjUA_8y5in7APwM5tM", + 55,11840,8,1,33,1, + "ZcogHaB0IVL65ik_GCYE3O1bbVDb-8juJM-tJXw8grRI6vq5dMbwp7mpoNkbCQNnqla34HFe3vOA1tEbBvOBE9EP7EG226bSq9lFXrNMWCz4WjnH_p5ispfXNU8ai1Ay0EfVAP_x8gkDEf8JD-TxMsg-Be_kEPgPzkLdLcD8DjDj2DLxFxDm_9QTLP4AxCfpABMDDw7M8DDm__wUA_MRC9AJI_3z2_4nFtEBHuosvR8c9Bi5PgMIzxMW4f0", + 13,4128,7,1,76,1, + "PXSTG6tMGkHzHfP0G8XQCBjQKejvJ0SMiP7h7uhRiyn1Vlcy5PRWp5UUCIiiaAU3AOOHM1B1P2hUb6t3m3mOZUAQwfMBxLro8tsGED9qoqVdDnsgk-kMHGmE2vN_31z2Mc4y9O82shIcAALQPdsy_8ENMMoWIuMA1x8K6RcE9SS3It5DwhIAHAHSCBkiyxAD5z7p2fgj1x4U4gH69DwBB7oEDRDiETu89ifcK-YB_QHtIhfIOvPZLBG9Awg", + 64,8447,5,1,5,1,22,1, + "yhh2hq3wFcpNUOiNd3ihH611vv2rv2h6OwrybfPsexZjEwXfwTkhvztEFu9mW7CTYszd20zVA1L4Qn9j5z2xRpAbUFN1X9kGZx8xQdGA4i5xg7g2wL3ZROrlz9jyPk8r8yMKu___AQsEBugQ8Qb6BSH_5wMb5gDsIhDiDifAK-UBECDh3_z_G-MBCTD11QIJ9_0m5vsI__EP-QztJggPzSrR_gwq89ck1BD8EOgo9_YPAO7s_SjmHgrVQrU", + 36,11741,24,1,3,1,1,15,1,5,2,6,1,25,1,13,1,7,1,12,1,16,1,5,1,13,1,24,-1,7,1,-1,10,2,2,2, + "iJ5b4KE_qft8aUBuRb2ZKFjCSrPwhoyk1gciXiuTzMoJM7siH45nzQNIUvNUrp5qeIRuwzR9pnUQS2TxcC_I724GbFjgD9hMIgbCV_JHfdeXTMq6ByVLJ4xHol4CRIUCmcgN6Q_98wwA_DjBC_My-g7GLuQm99YO-hkbux4d1ybYHvH-BvUJ7DLXBvbvIA7PCjjf_eX8SP_w8wXUBg0c_PD8AegCFQos3fcH9gXzKgvdCgDRFOYF_ybb__7_ADAA", + 4,1,-1,5,2,3,3,2,1,-2,4,1,4,1,2,1,8,1,-1,-1,5,1,5,1,2,1,-3,2,1,2,1,7,1,-2,5,1,2,2,-2,-1,3,1,4,1,-1,-1,5,1,2,2,6,1,2,3, + "4ujGEhDk52X_al0rkVhSgnhC3MVMcAbqGrcvvbRhSK4vVqOgj7w2FteoH_vgcsJ9qgXaaiRjXx4dhiLsD2XbsOM-BI0-cmMxqP832F_9t2yqtiPJvgscsXkrsU2igiQCAHUFAvAqvCLg-zEDDAbJAg3xBxwTzBAO_tUXFAbMQQLV6D7YHNAl_Oo04N8WMckH7Tbo4iEB8xEft0IM0eQ8xw4REBMJ9bsw0h8mxjy7-yAG9Q8h3N0k9_rqTuHUJ_8FAAA", + 4,1,-1,-2,7,1,3,2,-2,4,4,2,3,-1,-1,2,6,3,1,-1,2,1,6,6,-1,-1,2,4,-1,-1,2,1,2,2,3,1,4,4,-1,3,1,-1,14,1,6,2,12,1, + "hv1dZDSH_dA7O1q7Igr4KbDqMRH4pbxSPN4l0PDnRaDHxSGf-7M73Vv7XBrmNE57jvsuxDvMt6rUDwNinJzj54X3VkTdalWrMt9lgOkVmPuzpDWvcUCI_1vyMehlyFICAAICAZbBCzTT8QoX9Cfs0UXGEvPwMxYC2h_2ABHRCuY3zDi6QLsW9wAjB-bzFPsQ3gf4E-X7FRLtLcD_HhIN-QP4EQXmH-786S3k20XVBQ4UALz-A_dQtTzy9iLt6Bfh-w4RAAAAAAA", + 6,2,2,1,-1,-1,1,4,1,4,3,2,-3,-3,-2,2,1,2,1,-1,1,9,5,1,7,3,-2,2,6,2,1,-2,1,7,1,6,-1,-1,-1,4,2,3,1,2,1,2,2,1,8,-1,-1,3,1,13,1,2,1,-1,3,2,-1,5,1, + "P-lomMYgxeNt2RTA_-qoko-qTqsPYu7q8JJaPGeIro2-mKjo4E0O9B-MEjJQ6oq4z2rGehokCE1k7AZPqXuGVtSft3tf21x097RLAWde_3dbo63_j19NEJCDyR9vrkuBC_YB8_bzJPAQEtYMHb8wzg0uAcEl9AEpBtr7C-M71hTn9f4BOwC5NgDmDB_e9fMcGgblE_3THf0Q4xvUAwoPB9MAAQglGOvhFA709fD7LOv89hTv-zXRIRf2wAA42A", + 6,7367,-1,-1,3,3,-2,3,3,5,2,4,1,-1,-1,3,1,-2,2,2,4,1,1,8,5,1,-1,4,1,-1,6,1,2,1,5,3,2,1,-1,-1,8,1,6,1,4,2,2,4,3,1,-1,7,1, + "eZcPekuA6mRxf_wv0nS9bb5TcPaZRxwGxRqmiXXSxXcA3rjqZU8CeJZiLDKZNw7fhgtV8Gp83IseA2MTsGQWulaigN47irNwnKtJ9sV5ImafHw_yOvDbAjciN_3-o2Qi5Bf37DfHBRzVRs4D7Dv25vX7ENwLEu0O-PQPBg8B-wjo8gBA_Mok7uILJ9n6IiHADR7fNdjnRbgJJtk-uRzwBu0ELg_eF938Guz__Ps3Db4HHdv6QADY8wcL3wo", + 15,9810,3,1,2,1,-1,5,2,6,2,-2,-1,-3,5,3,2,2,-1,-1,6,1,-2,-2,4,3,-1,1,4,-3,1,7,2,1,5,1,2,1,-1,-1,3,1,8,1,-1,4,1,8,1, + "aX32fBFADlU_SGdvNWdgIrlOirsICutA_Y4gfyAtxUl36P8glsS5S6r6wVd_9ytXz7Z3SiJoq8TqoYXeQw-WYR76XxXiGzEbDml3UJTefu2herBiQxdIvqImPzHcrKGC4AoG8DLqA-zkDvr5DvkNIO_u_hsPyRczzRrP_BzpOOXsAhTuAQ_tD__4CgcC_v_dAfsQBxsA4vL-HhgF3-gs1zEFCfu-HekhAuoO__Al5BADBuY3xRXfIR_LAPAi9w", + 4,5778,-3,4,3,2,2,2,3,-1,3,1,-1,-2,-3,4,2,2,3,-2,-1,2,1,-3,1,10,2,2,3,3,2,2,2,1,2,1,-2,1,6,1,5,2,2,-2,1,4,4,4,3,1,-1,2,1,2,1,-1,-1,5,1,2,9,-1,-2,2,1,-2,2,1,10,3,2,2, + "LgEBBAMBJtlz-4qkHEUqWof3T0Ap34UeHVaUmZWW-ReOE2V5CM2KEZqKvu0PpqnA-qjLv9qHyCFfzmr3yqszDRrbA6BHwEHLvOZUex_-pwE_hnD4T-UK26ItIbpbq68-eWXH5K0AAQABAAKDAAAAAADSLPQB3SLbDC_w1SIo_tcFBesT6zb1xyzOCSsC2vMjF9H7FSzCHiP07dYQMro1Af8B0xDwDwcf2gr3BP369_UDHvgF5RfxEgroJB7GFAAh88_yAQUFH94WI9ANAB_YIAAAAAAAAA", + 5,1,1,4,5,1,-3,1,4,7,13,2,2,7,3,2,2,4,1,3,1,4,2,2,1,-2,-1,7,1,4,4,1,5,1,5,2,2,3,2,-1,2,1,-1,2,1,4,1,-1,-1,3,1,-2,3,3,3,1,3,2, + "cMw38Cc2fX28YEZXVdwBmQ4G4e7cOtMoYLD4NwydAmek8TgR4EGsUz6wEysU4b15_A8aUyIO_DNNr9QY6h-j0CimG0CFyKW7lLF_jrU6U0yYUT6XcHnFrosrvJgors0AYA0F8DIAvzzs0z7CUPYAvh0h3R_MBQ4A_O0t_tkt2gMIK9D7CA_XAQ46zRvd8yvYMcsSGhq7_yv73jDiFeIRK_jd5AMb9gIG9Djz0xYG_9VC5PjqO9shxjPgKM4-1BUA", + 5,3,3,2,3,1,-1,-2,4,1,1,5,6,1,3,1,6,2,8,5,6,1,3,1,8,2,10,1,5,1,-1,4,4,-1,5,1,-1,3,3, + "cgECAQEAWV9UFxdMnptXLZ5hKLiLZJxZozvVbLZRGMqRjMVJEP8znvHM-WQj8_7U-BIZE6hehiCoeBcoKZCZKQYhAhjEMQq0r9v8ZwcuwekHv0m-GxOx37U-S2B_FUVUmvytt4QAAAAAAM8HRe7GBEHPKtvlJO0Q4AAt8QbdS8sPHvL38gDgFg3kDfE1Dskc4hDo9gAROLc9xwcl5OwX_SEB_wTq_e0j0xIEGQMFyQr-Nr8e5TgGB-_vIQDYFd0FCRf9G7w1wQU", + 5,12475,4,1,-3,-2,8,1,-1,2,1,4,1,13,1,2,1,-1,3,1,2,3,-1,-1,2,1,4,1,2,2,2,1,-2,2,1,6,1,-1,2,2,-1,5,2,3,1,11,1,2,1,3,1, + "HkTtgVPshdBWnBI2RPimcz34XxcJqfj89ncgXSeuXO1-am-bUdDQ8eZjkSEI_L0P2K6rvtmlbPsa1swXlOd8RABY3b9MN7R_ePtHvHJFLqSYKRjUo6OPyNguBUzUq08WA-35FjbI-BoO6_voM_Xv6xoS0gUcCusND-X19h8XDQHOKfTUF_Yd2fcGONnoDizg-xf2EtBFxfg87ts0-fwAC9f4BQwMEu393_s_3-0k-_Pv_xsL4Q3qHQD94Ss", + 9,1551,4,1,-1,3,1,2,1,4,1,-1,9,1,10,2,5,7,4,1,11,3,2,1,4,1,5,1,3,1,9,1,-1,4,1,2,3,3,1, + "AdmNckbkKLzOwVdgOM-xCvfJHqAdJyvvnM4nVEMqsCroi2GliaFvrI-V0rc8pZ7yQGAhDmAUSvF2iKWoTlaudRDWBwBAPb691uchLg_hR5iNzFI90MAgTa3IrjC5wFAAAnf_3C7XB_sZ8wkd0SrNJOsD6Uru1TDIJNgNPr8GGt_2GecUKAbCFO8BOr4BQgjT8gL7LgLa_TfCAAjy_iPbNOIBA_ctxC_rCNk_zhYU4QAZCBcBvQso2f_7GN4GBwoWAAA", + 7,1,11,1,7,2,3,1,-1,3,1,6,3,-1,7,1,7,1,5,1,2,2,-1,6,1,7,1,4,1,15,1, + "VeHVRhu42w3gJ69wwzIsrB99zaHXYL6s7eWg5qM2JF0Kc-j3XgE1gIq5yX9-iTA4JjuFHtGVcUj-f1NdXQ8JufQj-uUNA1XtuvLV6mS3-QWrxdtYIuYR3j4Liaz12qQAYPIu5CTt6Qr6NbwfGuALA9ojIeoJ7e8J9f_yChna-x0V2_oB-QBKxAoZ4Dj4yzAA2R7i8S0Pvi4T7NQIFu0w9RHz9wsQAOgc3uQeFgbj4ggYCeTtKvUJGM329g3-_y0A", + 3,1,5,1,11,1,4,1,16,1,-1,14,1,3,1,16,1,2,5,5,1,3,1,3,1,8,1, + "bbAsw74F10P_bcvWbtz83wC9cSRvfL_aXYiiIO5Ws7bz0dfdunTFQaER0kujCzgRHT6_1J0xriFqmT3NJKTN7r7HqzfWq49Fv60F39FvxOtPpzHKT4BXuECMVG6mlqkBAHPwKwDyAuDxGSXIBwzrDSnp-OkTC_odAMsUHfDr8B387Az0EBnUJ9Q-3yDj8woBEAbkKN0p9c4ZE_z0Fd7qPAfONfbH-hfwCg3lCv0U6x0A6yL_4gQo6BYAB8r1ARwWAAA", + 7,1,7,10,5,4,-1,6,1,5,2,2,2,1,4,2,1,2,3,3,3,5,1,3,1,-1,-2,2,3,2,4,3,1,-2,2,1,4,2,4,1,3,1,-2,3,5,4,2,-1,-1,3,2,2,4,4,1, + "FAEptmRQ_4wM0jUdRFjPh4CQzgyM-5sdntroyr18k4Ft3b7wQ_iUxerrlRTVHVBQFYHYAwotDbB3LWrXsBFixuK1zas14k4q07q-lAqlHDs0z629TRQgFefHLnkgvKt8FwEBAQADhwDl8vL-EAUfDtgp5t1Ayxvu-xgD99sS9zfBKAHcCTHd7_v9_R3oDTXpBgIHxAgl4QAfHfgEAM_wCfMO8TLn7RoU4-4z0w8FJbYi6x3rAxDq-__0M-sH2xkY4AYC-PoBLQAAAAAA", + 3,1,4,1,2,1,2,1,2,1,3,1,2,1,7,2,2,3,-1,4,1,3,1,-1,6,1,2,1,8,3,-1,3,1,-1,4,1,3,4,-2,2,1,2,1,-1,5,1,3,1,7,1,5,1, + "zeDCdPZnrjqvWhKm0kbFSgoTbX3vWNtzvsz93-X1ZvqzCWD8c72B99bj8t8sLvmJ-3OPxXmhZ3BLoxSKXpS7Cpb1lpotrQXV7qCvq_NlBJWh_U8khPbu0qpyyvzoWF0C9ET42e7_C-4hDwQC1fYADSLpHs8hC9VGtB8e0AXyI_gY3zDp1iYDGMAq9e8k5g3oA-4QCfH3QLoeH9EJHebsABcA4xXwL80ACAs00AzgAA4r2wv2Iu__7_D-Qd0", + 3,5418,2,1,-3,3,1,-1,4,1,2,1,2,1,5,1,3,1,5,2,7,3,4,1,4,1,4,1,3,1,10,1,4,1,4,1,6,1,8,1,-1,4,2,5,1, + "I9xunHwTd8anarqlLwMofzJS6EYz4511tsfvpPp38Fm-TB2aaANspx-QwgcTay_iupuXpXEqRn2QugobCMzYbjip0yIXkhMIcpCADNndzX1pbUFPxTWmRaO0XIcsEIyI8ub-AiHYBxH__v4G-B7W8Az7P9kPGswc-Q_NRPjX9vMj3AUG-w8yvP1O4tY5-_oT2PL7DDDdAOAuGObcOwDo-N1CBOIO5eAx-hLV9PpKxQ3mBDj49B-7AgI_2O4S-Q", + 14,8656,6,1,2,1,3,1,3,1,6,2,6,2,2,1,-1,7,1,2,5,-2,-2,-1,-1,4,1,5,1,-3,-2,2,2,2,1,-1,4,1,3,1,5,1,5,1,-1,6,1, + "D03DdOGYNgtGqwY8w88ab_EkTogWx4DO-zYmLlgEXBZ3FErHHWPZRcPQeZx51j-pReXW16twsQEPcErFhtyvnodCt9VMu2zzWb1iFCcLkoETocwHCRBqAns9-wgeuCdc_w0Y1SbqBOUdHBC8EAEs1RsMxRfrNNoLACDQKf0T1iTW-gDwOd4b8u3xAQUIMfgJzQn5-fgAL9MZKtveADDo7kDkD_baCjXv0ELHLPkNwhL5F-sd3SQAEcYGBQUOFQ", + 3,1,5,1,4,1,4,1,2,2,2,2,4,1,3,1,-1,2,2,5,2,2,1,2,4,7,1,-2,3,2,2,2,-1,3,1,7,1,5,1,-1,5,2,5,3,3,1,4,1,4,2,3,1, + "NQHRWcWwmSbKDXVVisMaQfUYc3Gn0VEBWrrFMGkGEuqRm0J5QlUVC8gbUrNL1RnWVO79lkwJm3F_MIRkkhDGXrykto2mP2TJg2Vx9qoAt4ADAjHogCfzyOGouwZB7yXfiQAH5gEHGe7WHxzyyh_uBibQP8MOAR8ABf_EDzwAtvo08BTXK-Upvvo95uNC2v0J2CoP1QIsDv7a_O0KFBHnE9YZ4iUevwoS6jEO0e5F2-777SYK7inW4ifcFwch8dgb", + 9,5313,2,1,25,1,6,2,20,1,3,1,-1,-1,2,1,27,1, + "R989K5G20VNuEX4vHecAlueoFSCD2_xX0JVN-EGaGqtsWCymH6PuBaDwGUt0p3uY12aJAZQWgX3nRblMcUsm-i06tQCCgNdAylvGMPnPAWY1dNY7QMYj1vTZqMrbemT4NOoSzfsuAQb36e0q8h_A_UrL6wUTG9gU4Qr7EDG7ADkQwTfp1TL19-_-Bgodyg3xKdc04AQqzPIRIg_w9dk62Qr07yj4HQAB_9QgAP8FANMVLP_D-0DZ7j7DAzc", + 31,-3311,-2,1,9,3,5,3,1,-1,-1,4,1,-1,4,2,3,1,3,1,12,1,6,1,22,1, + "cIA_Qvsjk5BqAEHfhpNlqCTVs74FfV8E7xQ87pVjmKtGR2BUmodGPAx8Efj_fhC_wSdddyfWs0UhqTPD17vrUoRfPYwT9nACqLYlcDnNZc_LVas1P0VzLrZmKb7A1lMv6PBEwCEEAQD_BAj-6ek54O7uDu0y9Ok4-PjOGAH_9PIj6fER__0ZGwTe-gIj1uwA_EL6yAsx3uEo8x3bIc0AQQzFDQAouAw8uA4d4jD09OQrDsQ8xQcDAgoHDgo", + 32,-108,9,1,48,1,7,1, + "dF4BruYBxdaZnl_dHVSgV2qtOFCHw_Rt6DmNteM44Q3wY51eEnhVGGfYjqPo959fxxoJ-ou0McwPmohgb9vky1wAcR_7p0W3AtzotWHzbj3FL-M-0Y_vb2HtZG8JOW3uLRD0DgTQ4wAGMcsQLMf-Axz7ERDz3_820BgPAAfIIOv5NurOQsNDuz72DNUxxPgl7wHsHOs0wgb9EQEnAPQDDOzVNOL-ChcIyDrm-gEc1fAaIdP4CQUn1fMZ-Sg", + 8,-1255,8,2,80,1, + "4RYv3KLiwWoPjzL5_rWt0iWXHiUQ2e2VJ-LPV7fAgaEhwI_C7GsbrbEHFbDoc2c-UVA9uPEB3EBkgSlZ_ahrEf_Bf3PRf-Qi0yJpHe4jEDwnF-2Cah0_bpiKX3pz25QB4vEB6_oiG9kB9h_WCxz0H_LwCu8qzv8q4usPGPQQ7BDlEPAECvrnEC_BMvYgzAT8CiHkDtIv0z3S8jIJ8RXwCt4G8hL-AwkMB7sYDhYMzDIB7t8U6BPcEgX9Cfo", + 35,9636,30,1,31,1, + "J58J79v_kQHmzLxfPgl7hKcYiNDUR7vGWlsr_c8eQpw7AHmtvFxDbjANcDoJ3Naalxq-11AE8Q0kJAdIdVOZ2M4jgXce56JnO0mwVfjN4jTo4ZJV5IcJG5m3Fm3JWF4XG_v35f7vM_AJAeviMAL28wL37v8IDAgixhIZ4QQAHgD-3_72FBMBE-MF-f4O1CjpNfT2-wcRvQEz0gkQHvET8d72IuULNNn1HuEMGAAF6vYB8RXf-Dbj6zQHB-c", + 32,4084,5,1,51,1, + "rAQJCwgZHhQwmHQdF5bSFQJVQ6lrohpAwBdPx1cW11oHnwW_go95-NXeSvf7O80uLpu6y_iXzqioVXyZIkmr0VRsZD55A7befRHTnnyGbnWI9saxVHZpn2qyvWmNewHzVosAAAAAAAEAwx0NIcgQ8OwqF9Up7u32KtEL9Br3LPr-yigNxRL_8RUMDw7EIvn95AM5zBX_7iLRLvLtJu3tQM0mzSPiHhL9zAoWFMYSFBIL6Bbq2DvWGN001vfyGOn_CAc", + 5,35176,9,-23517,4,1,-2,2,1,8,1,4,1,6,1,7,2,7,2,4,1,7,3,2,1,3,1,-2,7,1,3,1,21,1, + "jX4zz-5Fz4KFEzn8vpGE1THlDTKhzgSyO6qYHmhwSwwp9NIQorTIDwUBCLb3vNowBw8dCfyeBQUeBQsACxEC-lLNBP4OAu7RZgcF-CX4CfI81y5BkC8B4SEyCNAhAk4AA_0Q9fsAAE3A-_gr1QX7CxnhGeoqGdIMKK8AUa8AADTZ-gH4BQAAAABE9sYAAAAAOsYA_wAAAAAAAAAAAAAyzgAAAAD_Ls8AAAAAAAAAAf8BAP8BAAAAAAAW6gA", + 96,15696, + "X_faCjj9HPf5C-78LtEv51EBAdoUCPj0DRgwIqY44h7-0B3vGAJVxBHyBR0OKQEBEBsv5v75BxgD0V8aDGjRpS35jsvO6JLkE_kI2i07SrVcujUQXr2ts8608gUL_k8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQD_AQAAAP8BAAAAAAAAAAAAAAAAAAAAAf8AAAABAP0e4wAAUM0Q1QxB-7gI-QE3yf4I-P0D_ToAxjMH8eIt99IAAAA", + 15,15185,-3,2,48,1,4,1,7,1,5,3,2,-1,2,1,2,1,9,5,2,1,4,2,5,2,2,1,10,1,3,1,13,1,-1,2,3,-1,-1,-1,3,2,-2,4,1,-2,-2,3,1,1,-15374,1,-50,1,11,-2,1,14842,2,5,-2,2,9,-1,2,10,1,7,-3,1,-2,3,3,-1,2,1,-2,2,2, + -3,2,3,1,4,-1,-2,-2,-2,-2,2,2,-1,-1,-2,1,4,-2,2,1,3,1,-2,-1,1,-4,1,4,3,1,-3,-1,2,2,2,2,2,2,2,1,1,-14542,1,16,1,17058,1,4,1,-2,1,15,1,-8,1,18,1,-2,1,5,1,6,1,10,1,10,1,7,1,4,1,5,-1,1,19,1,4,1,9, + 1,24,1,-1562,-3,-1,1,-5,1,18,1,-12,1,18,1,-2,-2,-3,1,-742,2,2,-2,3,3,3,2,-1,2,3,3,1,-1,-1,1,5,7,1,3,1,-2,2,1,4,1,8,1,2,3,5,2,-2,-1,-2,3,1,3,1,2,2,2,1,-3,2,1,5,5,6,2,12,1,2,1,2,1, + "bgJG9x71-BHzAgsS-_n6Aw8DDgUd-wQN_QkJAsY0XwkAEEDQBRnuDt4mAAYyhkpYlFxc99w9CAtXAv0IBfQALN4GJhvlGvX-7AQI_Dn25yUc1wzeDDQCAf745Tv6COv4lQGOAAIAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAwQf5AAAAAv4AAAEeBufzAEq4DBbo-gAAAQAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3AA", + 5,1,2,1,-1,3,1,-1,7,1,3,2,7,1,-1,12,1,2,2,2,1,7,1,19,1,22,1, + "CwHv7xId-irbRAYUBxDlJ3DleQMBD_od2wkCBQERDAXxFwEYtB72HAD05wrsCPQkCdU8J-3sKvfUF90FM-7XPQjrDQDK9EY0CQCrian3_GnC0B_3-xvg1kjMDPgy_lgA_wABAAAAAAAAAAAAAEEGwiEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_AAEA_wAAAAH_AAEAAAAA_wABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + 96,2943, + "aLJNAv0CAEHHOgDrCegI6PY58tM6whwFCREBBD_j8i4Q8tEf2EUb2PTNCi_z9ADw2vplyfB69Aj-GRMA8Q7uwwkiDBUBojtTCwIV1hX29PolwBf64k39KAAqt0jlGoMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wDVLAD_AAABAAAA_wABAP8AAAAAAf8AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwEP8BAAA", + 33,2570,1,4,1,21,1,11,1,5,1,10,3,2,4,1,-2,4,1,4,2,2,1,3,1,2,2,-2,-2,5,2,-1,-2,2,3,-2,2,5,-1,-3,1,4,-2,2,1,3,1,3,3,2,1,2,7, + "DAEEAQI95MP8XO4f-_kbJ6AuCCgD3gfpNO3oM_34Iu0aIifdI-wlwQkzBPUdBP22EgIGBxcdNBsOD_wWM9NCEfdpSHoIEyW4Pt3eRA01BecexBnvg3P3hvvJDwTrGfo8JegoggKQAAAAAPUA_wABAAAAAADyDgAAAAAAAAAAAAAAAAAAAAAAAQAAAADYAfoAJ9kAAPoJAAAABgAAAAAAAAAB_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wABAAAAAAAAAAAAAAAsAA", + 3,6,6,1,5,3,-2,2,1,-2,2,1,-2,2,1,5,1,-1,3,5,2,2,6,1,-2,2,1,4,1,5,2,7,2,-1,-2,4,2,2,1,5,1,-1,-1,-1,-1,-1,-1,3,1,2,3,3,1, + "qwEEBAQAAQC5PADgIAUPBgz9JhsI3MZG902RC-v-EhYD70SQAAAAAAAAANQAAAAAAAAAAAABAAD6ABbq9AAAAAAAAQAAAA",3,6, + "VuzdNQHJDk8R4vnyNQDo8e82MtwU8R3U_iwAnTAx5QMMDAABzAD5OPEOPMs43BbeLgDrARUCPCclkyPTE-kQ64UAAgEAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8B_wH_AQAAAAAAAAAAAAAAAAAAADsAAAAA",3,1,1,4, + 3,1,3,1,3,3,3,2,2,3,-1,-1,4,1,3,1,4,1,3,2,-1,20,1,4,1,3,1,11,2,-1,7,1,9,1,"RPIekcQA",3,30, + "M_wrLkawLQfO-B3eV7rpY90A1QRQDNFVsRkA5xH25ir1DADYABoM7q-J6QP0Iv7aASYFKuAd1CAU9gLvBzHdDPkPAAgNGyQCBQMT9Q0FBAX-EvIJ-vwfCQAIAQAIVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wAAAAAAAAAAAAAAAAAAADrHAAAAAAD_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAcAAAAAAAAzAAAA", + 4,1,2,1,2,1,2,2,3,5,-2,-1,1,5,3,6,5,3,-1,-1,-1,2,3,7,3,6,2,6,2,2,1,4,3,4,2,12,1,-1,-2,1,4,10,1,9,1, + "NwwPBgICKu0SAgXxDwD3CAEY7Bru_gXxHfUMDRHmGRwAI_4H9fnnFDzl9Qgu7hPtDd_-HgoNFgPVQw2tAwoEAQIIAwILBAcGpf5LAgMCAAr9DP4EFQb5CAECCfEP9l4AAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL9EAAgAAAAAAAAAAAAAAACnXEwAAAAAAAAAAAAAAAAAAAAH_Af8", + 96,7915,"-xv7DegT_vcMFusGC_ge_AkICwIOnAnBPN1gcgEAAAAAAAAAAAAAAAAAAAAAAAAAD9c_wQBA",6,3,1,7,-2,1,5,-2,-3,-2,-2,-2,2,2,3,1, + "gBD5Cg76GPsI9J9-_gkMAc8JBAz4M-oV3AIZBgDjAgogG_D08_0bAd404VYAAf7HXgAAAAAAAAAAAC_RAAAAACPeAAAAAf8B_wAAAQD_AAABAAAAAAAAAAAAAAAAAAAA",46,12803,25,1,25,1, + "ahIYAxLv5Q75DlDO9Sv67RPZawXuDdALDRweKjbnEg8cIOfVNQEFAQEABQEEAAEBYAAAAAAAAAAAAAAAAAAAAAAAAQAAAP8BAAAAAAAAAAAAAP43_wAAAAAAAAABAAAA",4,1,-1,-2,3,2,2,1, + "LBLVHx4H7VjhCgP32wAKAQ8iJgPYSQD45dot9SPwAsIhGw5OJPAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",6,9641,25,1,65,1, + "Oe3kNgS-_BT0HCHgBuQ0AgHeXd0uAb00AMcDG-a2rP0YL7AgMNT2-zyUYKF8Qt8cRqwmzADd8h6a0eZHTLTCARX9-x_cGr8y3MLjANzw4zUGFCi13h9fA_7r-Qn9Vm0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAH_AAH_AAAB_wH_AQAAAAAAAAAAAAAAAAAAAAH_AAAAAAAAAAAAAAABAAAAAP8BAAAAAAAAAAAAAAAAAAA", + 52,9016,43,1, + "a13dEfwLHgzvAQ4qCPcd-xkOIQMQ_RESdm6VrwlBv1a_rhwBDwj1BPwM9Bz-Bhrq-wgKEwD2ARQMAP0X7wn4XboIBAX6B8QG_gHib6QIF_ECVW3-A0bH_jISAQkbAPiT3AAAAAAAAAAAAAEAAAAAAADrAAAAAAAaJcr3AC7SM_0EAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAADWKgAAAAAAzwAAAP34CAD_AQAj4AAAI908wf0AAAAAAA", + 35,14792,58,1,3,1, + "lzLg8gUt3_wn5kYA1ira9CAS_CgB3BHvLCbiCuYlEna98NsCQyzGHwHjJwIN5A_xAywN_hsECNQGPQoN3QEOEgEAAQT9AgADAgEFAQACAVkAAAAAAAAAAAABAP8B_wAAAQAAAAAAAAAAAAAAAAAm2gAAAAAAAAAAAAAAAAAAAAABAAAAAAABAP8AAAAAAD8AAAAAAAAAAAAAAAAAAAA", + 3,2,2,1,2,1,-1,-1,1,-7177,-1,-1,-1,2,2,8,5412,88,1,1,-5506,-2,1,13,3,1,1,6,2,1,-3,-3,-2,-3,2,4,1,6,-2,2,2,2,1,1,26,1,-24,2,3,-2,3,2,2,3,2,2,-2,2,1,1,4,-1,-2,1,-2,-3,7,1,4,2,5,1, + "NUQEW2JW-AIc8_wv8g7l-wwI_hzzoo3e_fbbNxwaMMr-Agf9_X_fF-gYG-MAAAAAAAAAAAAAAAAAACXc_wAAAAABAAAAAAAAAAA",15,8194,44,1,25,1, + "kQQBLgcDAAULFCAD-v4mGvr9Ax31EB3x8QAFAxIJAOYWKueUAAAAAAAAAAAAAQDfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",3,9007, + "TAYK6SA74eIIJA7NMvUO3esEcxjOMd7GW8zbJNgpIsL0KSuyOzQALADsE-EfHpk3ENol2P0L_t-L2eQCG9dWq40iANgtCwkFBAIJBAUNBQBnAAAAAAAAAAAAAAAAAAAAAAAAAf8B_wAB_wAAAAAB_wAAAf8AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wEA_y0AAAAAAAAAAAAAAA", + 8,1,76,1, + "JMsa9VWLLGDHJuEaJuYUF9-7l7oARbrc_BUhCxPvASbcDwgUtUqscS-9KQBMjFH5Ya8K2Vjqw-ovIxT-GO0TixouAAT8DQD5DAAFCMABaf8BAAD_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_AQAA_wEAAAAAAAAAAAAAAAAAAAAACQD4AAAAAAAAAAAAACQA", + 3,3,2,1,-1,1,-2,2,1,-1,-1,2,2,-1,-2,-3,28,1600,1,4,1,18,1,7,1,11,1,4,-2,-2,-1,7,2,3,1,2,1,4,6,-3,-2,-1,1,6,2,3,3,1,5,2,3,1,-1,-2,2,1,1,4,5,1,-1,13,4,-2,2,1,3,-1790, + "mAEzPAsDAwL-A_4HugcECg8BASCPAP_UAAAAAAAAAAAf8wAAAQAA8A",3,185,"Cg5YkBHqhHElFvwE_tBY9OwNBgr1HwwHGvUgHAAJAkgAAgQBAgQAAQD9BQcDbWYAAf8AAAr2AAAAAAAa5gAAAAAAAAAAAAAAAAAAAAAnAAAAAAAAAAAAAAAAAPw",3,2, + 4,1,"bjC9CAgOAAQGAQECdSl92wFyAAAAAAAAAAAAAADxAAAzAA",3,2,2,1,2,3,10,1,8,1,2,1,2,1,2,1,2,1,-3,2,2,1,4,2,1,2,4,2,1,10,1,7,1,4,3,3,1,2,1,-2,4,1,-1,2,2,-1,3,4,3,3,2,1,5,1, + "HQEAHpgr5QgJ9wMLAf4GB5cAAM0AHOsAAAAAAQAAAAA",3,2,"IQf6BQcCHxXhBAPZMbOI_PYoTbLz-QEGAmwAAAAA-QAADQAAABTMLgAAAOcZAAAAAAA",4,47, + "2-YBFPMJOMwNBQL4HwDjCRj8R9vnDesZFQMGIOQAFu4IEgDv-eVn0vkOQ80GIVmj8IAAAAAAAOcZAAAAAAEA_wDnGgv1AAAAAAAAAAAAAAAAAAAAAADXAicAAO0TAADmGgA",9,5477,2,1,2,1,-1,5,1,4,2,19,1,2,2,2,1,-1,2,1,-1,2,3,3,1,9,1, + -2,5,1,8,1,5,1,-1,3,1,-2,3,1,5,1,"weR9EgEJAhKBAOoAAAAAAA",3,11639, + "1QMA2IyBMJzAQSgJ_f4IAQMDqRv5Bh0E9vMFNuFFAgIYAUHoC9ws1y0BHRoB8vc_8xIRIwpDq01ShP4FBADxBAUCEQD2Bgf0CA73EgoEDwwLHf7NAAEAmAAA0_QMHtw6xgAAAAAAAAAACwAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQD-AQAA8QAAAAAXAAAAAAAAAAAAAAAAAAAAAAAA5gA4AAAA", + 7,1,-1,-1,2,1,-1,49,1,-2,5,5,-1,24,2,"PCD8DNkXCUdaBk9L8y0FNHn-E2IF-QEHCA0A-JmB7gBgAAAAAAAAAAEAAAAAAAABHgDsAAEKAAEAAAAA7RMAAA",3,27, + "HxzoBvYFJB7oAM4p9gQdMPcG7BQEAQ4G6y4E7yIFEu4eEPkVZl0BAPQSCOsNABEH9hP4DgIXAPX7Fg14AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wEAAAAm_wAA2AEA_wEAAAAAAAAAAAAAAAAAAA",96,8358, + "YgIZDe8CCwQNAA8EB3wFDfz8EhYGCdQI_egfC_wHB_xOF0x3AAAAAAAAAAAAAAAA_gAAAAAAAAAACgAAC_UAAAAAAPcAEg",3,3154,-3,1,-2,2,1,2,1,-3,-2,1,-3,3,4,2,6,1,6,1,-2,-2,1,-2,2,2,-1,-1,5,1,2,1,-1,1,4,7,3,3,1,3,2,-1, + 1,-2,-2,3,2,-1,2,1,2,1,-1,6,900,1,22,-2,-3,-2,-3,1,9,38,4,2,1,-3,2,1,3,3,7,2,31,2,1,-1055,-1,2,2,3,3,-1,-1,2,2,-1,-3,1,-2,2,3,2,1,3,2,5,2,-1,-2,3,1,-2,2,7,1,-3,-2,2,4,-1,3,1,-3,2,1,-2,1,-14,3,14, + -2,-2,2,1,3,2,4,1,-1,2,2,1,-3,2,3,9,1,-2,3,1,"OqwE3AsX9QcaQLv-G_WV4gAf4wAAAAHjHQAAAA",5,7923,2,1,29,1,37,1,13,2,"ZAEMBAABAgMABa_9GX3VyhcFBAUKOQFL8wGZAAAAAAAAAAAA4QAAJPvh_AAAAAD-AAEpAA",5,5,1,5, + 1,-2,1,4,-1,1,-2,2,1,-3,2,2,-1,4,1,2,1,-1,-2,-3,-1,3,2,-1,1,4,7,2,"cfsFHgEBCfwO9g8AAwvs_hL-E_YVBP39Bvsb7QoCEO8EBgryGvL8A3IBngAA1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB_wAAAQAAAAAAAAAAACMA",11,11,2,1,81,1, + "GyDl_R_sAg71Dfr0GRD1B_kUA1obkQAGBQEMEPkL-wQFsAQICgECHyPwBAwY6xQBCyjh6xXxMPf5B-4p9goKJBQPWcwBJzUBAQUDAXYAAAAAAAAAAAAAAAAAAAAAAAAJ-wAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAB_wAAAAEAAAAAAAAAAAAA7Av2AAEJAAAAAAA", + 3,2,"Kf4I2SkNAgYEFgcR9AcCgAAAAAAAAAAAAAAJDwAA",96,374, + "iQIAAQQFAAIAAQACAKYGFwEQ-gH-LOT9IPAJ-wboFQwN8BjhCfb9GQXkNAcA-gXcQsoV6vj4MQPwDwEC-xkX4gYI6yMJ6_z3DQdCn1oA_OQP2yEcxw8Y5_QLLRv4KZgAAAAAAAAAAAAAAADuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_AAAAAAEA_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + 18,4743,1,6,1,16,1,5,2,3,2,5,-3,1,12,7,2,4,2,-3,-1,3,1,2,3,5,1,4,2,-1,4,1,6,1,-1,4,1,4,1,-1,-1,9,1,-1,7,1,3,1, + "xsH8J-nrJznGCP0XB-kT7gkQDvUNJ_zqCxAFFwL5CwEAyukCCvoAEPQg4zfw8e4UAu4E_g4K3zkB6i_WEAINDOYP_h4VABDz8ArcJPEFCAgc7woQ_AoAAyHx_RIG9PuHAAAAAAAAAAAAAAAAAAAAAAAAAAABAP8BAAAAAPcAAAAD-AABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8AAQAAHw", + 6,1,3,1,11,1,3,1,11,1,2,1,8,1,4,2,1,5,3,3,-1,-1,2,1,39,1,"Hwr7EQj-vQIAAedXfAAAAAAABQEAAP8H",3,-1572, + "LQH4AgwC9wAJBQQBAwoECBUGAk8Gfj4BBwcAAcnMRwv-AQMPCQADBQQA-vwREIU5Fg4GD_sEAgQEBH4uB5hTHPu-EA_8H7UF2QEABf0AFIIAAAAAAAAAAAAAAAAAAAAGAAAAAAH2AAAAAAD96RcAAAAAAAAAAAAAAAAAAAAG5BkAAAAAAAAAAP0BAAABACAA7wAAAAAAAP8ABQAAAAA", + 96,2583,"Yv4O-AUNAPMBBBL4CvwDEAAGkQAAAAAAAAAAAAAAAAAAAAAA",3,2, + "tf4Fmig5MhlTD0sJ_P0JEQACA-8AC-olCgDqFQHoJPMWCAEMAfQLCgX4-wfzF_cADgD3JQUF8gQQCQT7CwHZCQf6EvsGOgf7AZEAAPsS7wABAAD_AAAAAAAAAAAAAAAAAAAAAAAAAAH_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_gAAAAAA2SQAAAA", + 96,4607,"5QUDTucslQn7FvoGBv4bAgINQQKJAAABAQz_AAABAAAAAAAAAAAIAA",6,1,"jHEMAasCABAD7CCtHxl1K1_EriwTAp__AQD3AAAAAOEf_AAAAQAAAAEACAA",4,2,"I2cCeiIA",3,1,2,1,2,4,6,2,5,1,-1,2,1,8,1,4,2,4,6,2,2, + 64,-144,2,1,-1,2,2,2,4,-1,-2,-3,4,2,-3,1,12,-1,-2,1,9,5,4,2,5,2,7,2,7,2,4,5,-22,3,2,3,1,2,2, + "3wKZCAsAARr79w4B_P4GoF0DAQT-BPwIAARz_QMB_gQDliQgJv6KAQQI-w_xCw4GAwsDmQB8RgQAAgZDxgGcAPsAAAAAAAAAAAADAAAE_AAAAAAAAAAAAAEAAAAAAAD9AQAAAAEAAAAAAAAAAQAAAAADAOAgAAAAAPULAA",3,59,-2,1,-2,-2,1,6,1,-3, + 1,-3,1,4,1,4,1,50,1,9,-2,1,9,1,-3,2,5,1,5,96,-610,94,17649,96,-17743,94,17647,96,-17741,94,17645,28,-17739,1,5,-2,1,6,-1,-3,2,6,-3,1,12,-2,3,1,-1,-2,-3,4,1,-2,2,8,-2,10,1,2,2,4,1,2,2,6,1,9,2,-1, + 6,1,4,1,94,17571,9,-17665,3,1,2,1,-1,5,2,4,1,3,1,-3,2,1,3,1,2,1,-3,-2,2,1,-1,-1,4,2,9,1,-1,-2,12,1,-1,-2,2,1,3,1,-1,6,1,-1,9,1,2,1,2,1,94,17530,5,-17624,-1,-1,-1,5,2,11,1,45,2,2,2,12,10,3,3,5,2, + "LEwbUQn5AAAAAA",94,-5608,4,5540,-1,2,1,-3,3,6,2,1,3,2,1,-52137,3,47508, + "hO7TQAIo6XvzfQrWqZwZD5Nc5QCWH3HGiYbxqwhOiHsCAIN1-g4h-IrqbGkFUhA8fDICBAABABj7G_4Dmk0uBgD6AHGWAQD4AAsAZpoAAf9mAJwBAPK6t48SAe0V6wAAulsA6xUBAgBZqAAAAOcbAAAAAAAAAAAAAFZJZA",3,-5,1,-43,1,42,7,112, + "rgxNUg",94,17580 + ], + "big5": [ + 0,942,"8EHQotHjCg87q1EwfGXPoA0C-A9ujclE9Qgv0HWEEOj9iqrZDJqc_LjIATD98RzrtkgR661DCfr_AJMGb_iTBHCMBF8MAAUAjAb6BvoH-Qb6BHCMB2j-B4wEcf38kgeTZgb6BvoG-geH8A",0,1, + "lYdEVjo_KZDraxZFgEFIIOVEcSTS3hs719EL-VC5yMpphxYGmrgQAKo-nVdHwRGreRGYAOKCs823YS3Ic654vKki9p_dkmEMAOt7HOQbQIlZ6wYpHqws-NVBFJpyC4B3h39_gvw6SG34FRaJk8GsXH3cfwdeWkEHfH0FfdyiBnwBAQseUwWXAMSgBfsG-gRimgReQCU5BfsF-wX7BvoGZUEb9bU90j_75wHsBB7sB-wT2D6kP2UFlyu48gvtlwZ6Il4HrLuSBmOXBZ5dBMM5BPwE_ATD5lMFY1-llAWFDi8", + 0,31,5,-28172,"QMu4epBujPgAeIp7oN93idgFVKcE_ARVAKcE_AdSpwQ",4,-118530,"QM2-ADHAC_JRtlCtg4b9ANgFVADQ_wH_Af8B_wH_Af8",0,1,1,7659,0,1,"wAk23-wRcB7iAf8B_wI","$8",0,1,1,7277,0,1,-1,1,-7640,1,374, + 2,8568,0,84,1,163789,1,-37477,0,1,"CmU",0,2,"PZ9wkE4gL_Q",0,2, + "XddbiA1_rR0nR7wGkhKCBgkNEwIqATE3APrrtE10BWDobXhuBw0MBw8mMEJUn1b3I4MABqLq0HiCXdgHhesAAAIAAAABAAEAAAADAgEAAAACAAABAgIFAgEABQMFCQAAAAAAAQADAAEGAgAEAADlCAHsEdg",0,4,"jCulXZHnGe8",0,1,"C-pLpI3zWAU", + 0,2,"nycF-0IxKI5lsftdyo2AHq5RAa6MBfsEwjoFWA",0,1,"mqPabhTz",0,1, + "EVoiCe3ZCtqCdo55mz1c_gY3K0sUcIq6hPQVEeB-1SAIg-8Wlp_hp16ibmBJBA4RDxAEFh4oCgRvpmUZF-2ZJKBJUQAF2l8E_AX7BfsGcAAAAAAAAeUb7xIA5AAAHQj4AAH8BAAB4h7iHuIeAeEAAR4AAAAAAAEAAOAg4AAg4KMFeA",0,1, + "Q_4A0T7WZLp6JVMABAxkrH9tDF270Oz7oIr8_JdglvJlOMZwjpFur5jwxFKsxzcg5l229fqB2AT8BfsFeIMEXZ8Hr0oF-wRkmASbYQReDZEF-wX7BYd0BfsH-QT8BIgqSgb6BPwH-QT8BvoE",0,1, + "QwIf5hKICl5To3bvtP2O-BhNcp1uiWmC-Cmm2AX7BvoEa5EG-gS-oJ4FYvajBvoH-QT8BcD7",0,1,"2X5MDi5nAP1_eTKDSCrpgH68R0FJaf3w_yTfWMDp9O9DlQSI8IQF-wf5BF2fBPwG-gf5BYd0BPwEskoF-wf5Bw",0,1,"CzRoUHjXQUiQBWIZgAU", + 0,1,"UXZ4uls-qwj2UuJB_tgF-wT8BPwH-QV46wM",0,1,"tJUb3VgMSk1Y3IRKK0rg2sZKjgb6BKUXQAWG1p8HrskO2g",0,1,1,157629,1,-38905,1,7365,1,505,0,1, + "RIOFc89zWTrc3vH-forw7RlmsrqbgBXn2AT8BVwBngZXowb6BHqCB_kE_AdVOGwG",0,2,"XRbWP7y_YPEHaXU2yPAlwXawinq4Ru7BWI5fSLZJtWbor-wSA_wK8wjYBfsG-gb6BvoE_Ab6BPwEo1kE_AT8BVijBfsG-gf5BmGZB_kF-wX7Bg",0,1, + "Q2eWZpkE-3uD-LtPTJsQaZ6naNsQg3Q6xDvLBfkJwipUq4J76jrIJ_USbpA1yWbfIff02Ab6B_kF-wT8BWKZBoZ0B_kH-Qb6B_kF-wX7BPwEXp4G-gT8B_kG-gf5BPwF-wS5vy7T",0,1, + "Z1tij6YA7KJRLH4vPBjBYscAXPiMtkjLMzPLt-F1lx05ktiZa46EecwyNMszywMXpj0P7TXZ_PpYr-_YJtklsE6xpabNSzbLbHVxjTfYKYQ_co0704OPVJSHa_MVJugbHM6xOud0tZcr-r83bcgd1_C99pae2UN6vPnY7kXUX4LkLXI1UehEugQxvgCApJZo6L1ZBBFW2Aa-_j4H-QWUEP_cfAWkthyFBLVHBvoG-gb6BlejBVmiBHqCB_kE_Ab6BvoE_AX7BvoE_Ab6BvoFfX4E_AT8BPwEe4EG-gb6BvoH-Qb6BVqhB_kF-wb6BvoF-wT8BfsGevrkogec4O0DVKpT_z0H-QV44CH4C38H-QS7QQRyAOcnAwDZKgMGAQAEAtwkZgSj-gMDWQZW", + 0,1,"WPK2fdi4R_YLBlycU-18Z_IGaHqr1o5YD4QCqWuipKqXLwhGlRlq2AehAFgG-gV2NQFPBK8CBwEAAEMGuQEAAAE_BMACAM2OVYoEuswy",0,1, + "O8JoCzIixcD9KH0qM3iL_djxP890TpqHoJE05p6DujmP0x2rsq35WQRRaOsyLLo74BqHavfWIzV15IiAwzXFTMty55CLVgY9dm7bBiiGyHjArB8pCxObUB1rBMOeS1AFk-zvjQVYowWEdwaxAuD2DGUG-gVfnAVuLfzdhwdhKm4GZERSBpxeBfsGudnjhQS342IFwtjXAQH-AVC1KdsAgAWBAAF5B4ZzB4oBbgSQ", + 0,1,"AFCzhk52wAGjydNMsD_9WNaoi54R5hkO8SOPgECKtlWL-TEwd3JmBZbLmgZ9GRdNBPwGnAEBAgQDGukX7xHw9hT5DTkF-wRkAhg",0,3,"aAIKxpjP2xU",0,1, + "1nsoQ5ywc9kYBt66RWLuAOcYN3P7cr06iAnyTAObhVMFpVYFb4wFgHsH-QfAALxExxjwC8QHlAb6B2QC",0,1,"1XjL3n6ZOgMmOaQA95ta21MA0fVjtuWK54v4hazpD5NABlxcfAer0uGbBYBC0tSTBPwGbu37pAX7BK7FiQZ7KBdABIN5Bw",0,1, + "SHigCpS4qBSNq7RMQt0gY-o15FCpom1mgETGuW3x-nPdibxRfN4vUAkNpRKUFGYXCXpnXYQLKg2JZaejLQEV6HNjVDLfuFHeGAtS8HRUC3337jZBU56fj_MrYVtX8Tnt_gmNORgHOuU2GQaHDvwQaaxYuAkeIYo_KIo0IDYDH1pttAxjAhBc2136JvekaAA6DxEI8T88qwpB4fChZL4DGg8JtuSbL1GUdofmnHdqFoptU7-GitQMioNzixfYVQ70EQANhzM8DwIMBMKkqQlJ0yq5SKajzCy5XaYjUFBwJZ7IjKkNLGcLLiFpgj7OLyPW0yZQ_R6NfgHYmLU96Bj9erb7IYl9Hn0GANC6LuFPs-t6DK86yDYBEyOYQLoYAAXuIXcQtcD4UaEb3ifz8BicXNm_Xi97AhQKBjge02d3ACTnynTPzCiTdY48gbrlvhKVmKyI2T66ZC5dRI0tF_T-EuxC5K4Yykz3_C56S7fkf_evR1Sl4hQt26ixcGIVRm-ESSjSLm4MijDPDCBmNTY7z0e2qlQ8tYDwXc6YhU9JBhQRqtx4ggI7xOYIo2j9jYxhEMKiBGWiT7E7xBvj55owgQ7yUHI5rhZogvC9aD2NS6KoVkrDO9mFmit5QjzZcLAzt70f_VtUZD3j8vaP9VzbiSg0UQrpuDUAFoJuaaOGeT2-WAALA7HlsXcCGwL9FKXCwXbFOV7e9mqRzfqPdNsUP4NK2UOPEjXaJA_ZDABbqCcVChOVmTU5S8P0Ci_uVVA584KIOMZdVPBCycqAtEF1BqYxtqFBzz038eNbn6_axQgMEEQTMgT7sJJdZDaiDWJ2N3uC2xFrPFMVlm6rTFqkn0bcWtp7XynaIV-i_wr0qZy4sbCchMdOaYi4Gue10BNBhJChIPJj_6hjiEvGqUiFZ-36PvZ-gIijM55_f4J_3h2JdtUonHPnYMggf3lVwo8w5nZrN9LesDxeGtU2t3kE2z5sfdwO1LlchzPktlNKtIBsfnTONr0mEPPYLUfMlovL2UAHcIHyGYZzxap7apRvzBURDAERDXQWgS1Izcv1b7dAG1Zi_hcap00Y2-_uHwv4sMPsEP43W8sdjdwwBAWLwBjWSPPwDp7vFi7UR_zPnp9MtG4KAYOe7hkFGDOeM_8lTRqIMNLvJtYGABwqwfq2_AxaAGuST7Ap1UK8eIa6RHaeBOTL2Xk7gxIMKtS3JfQsygUuUK5L2wQIA5F1BKATXJ6ENxSLpMfWBY2NNkZ0_iJl6rpyqyZmjOIGcrGHp5Mi3Gi72qVX9wn-TMN3a7Okwhvk0jKJbuGnlEmWCeRnXdOG0IyAIdynhcaps6J3jkstfj7P2RWyKSK1SvKnYy7RioXz1yF6mvbSHrlFY5uBfnBMSVhcUfxBxwjp4SMG8qtg9aFYoHc2vcrSOeHRhNnb7Ub18RCQbjrEvkvFqdK6V-Cwm2Jlmsm4m7CIWzLtN-SFhCPaPss-yvsW12qUis2myTbSIPMWf6JPjDRkZcuLND-UYE67QDq36z0UShhyo1wBAQAX1ke56RVvstM9yjkeGn2e_GNhnVCuT-jnOaTMSkqdMG2MCxHDO7bcMVmXn-xx2VtkunpBQfXDaZM8QrOKQHjqiwSHdINWP5Zxdq_xvozNyOP-tEop1cobi9buUEJD7_-sUhruRF8PPd01K_3gdGnRzKu3vgFslVmYweJ9f7_p_U-vNdGf3oH2vEK9_ERZPGe41FY35P9ykiTvRWMBN-AdZb_Z9QjPSJ9iHcsV6OGv3JBlmXSlI9IXTH_9AQUC0X3-3NVPr7tJgo_oI98T5B--INcqAhWDYCy-MfFaep-AkGcbPKZVmS8GgVdBvWCkNsJeYT6TZZKL2Y59PMJmLK_ELt2_Mjm1tlgF-c_IXbZC4yHnL-fCPDXNeMTMyEYnnC0R1qN36IV5lDw3G1586xJu3LNUqbHRxfjB2Itnpfmk6Yd7NasedjtAy_6Gs4qi3PdwjkoFUW-Hd2i91r1DeYo9ZUaZeucvD3RL6wDMPNwd-BTJNSV6XjYMvD3B01PYUZypjtSoVBHy9wfEP4kkqqCMg78r5XFL2G9Kr2e7jmYx3--FebJR_B31XFJO-WmFWKY7bNGE-7BScoygBjcPH4BiHXp0zDKSkNPl2wBr1UW1M9zznUdiI5Jnl3QAiUPBVVhNK5xu-kn9iAPjE40qjPoOhyGqP7l51qBLArtRCAU5s1i1aoooKNMEOZWTbsnUdu-rYFimRXAyGpQ5K283-mMPo0Rco2SaTiaEpktq3e0xAykqy3oJCPYDAelOvyrn7xrM079pDf6B9JS4RZ9ZD3pJGukpkm3ryEq2114duDDxom-kYVNxOUbf28ozdRhMysNCOBZaDpbnHwL09gEHS2hLvmr4xvnqGlpCYZHH3T2SP50vxN9r1kE3Jn7nBy3QCCfXJt2SbHaIOcWWs_VR2SJK3kjiBN0kM09UmoH-JzFJdXy9KCx9ZVV8q7UmGaljYozYed0RuZQOy5zci9vZlLRIXegW_5kqO7lF16lFbQ3v_szQEHyPrFLvDZn8ZNhp04N7AvwBZoWaZCXWniNYkEQiS5bVRi7BiX0K-SbZwjvMKGX7VlfSvFbKf9XGCuKaoGKMX2xFdBtucQ3aoe0BFPoBd4Xiuin67iYREKf2ndM6sQUC8HHGkdwwNoqe1eFzANnl9NG9Hy9ljKJbBNUvaAy32s4o-DfIIJtHAye52m5Pl8VxyIxylSKMobMTl1tbS7OEeopyyHUXnbZIg3oneTYnSLYo1pQvzWykTImAC31qTrDy7CSLg3jiifd--b3Vllsj8AffFmGU-RH0fIjuWNdn_kT_9TtkBTeWi8BceqBbPm_kEkOQHG-s5sLBPLCUNqNO5pm-_I2PbNlU6GSEzTypUNopcNK6Z6HnZq8C_EutZpg41pfq_AbKrQDiWEFwYCQaB9p76xNBsJN4E9lmnd4tkmIJw46sIw1heOG8MjBrk7Nv24Rtf18sH-jm8P-7pJzYJ6hXdEnBgLQDRnyP_fUL29IIV12RWgKVeIY82SYcQGwLVK4Z6B7EGxFYdHHh82l04vdX2IVkt_ZUfwZrB-8XRyZ4nWHd1Ali0LRbagu3WZZSqc8CIbg9ZVG1DW4Mq1ER7x7Zl2Brl3T7rdxTtJd4lViRgiDJiHWtWEt6Ml-tW4ag7ozKNPUJJtiCOESsMwf0sm0k2_bxla34wm2tD9S-SqswwVX2isYBCbVUyLwkQpcjqWPYGgn0eVIyCAh-zqrMmY58kO0CbE5DBe2_oYwcmLs5nqYs_BWFQ8No9QrnmcSBXsirUbM_02nDkmvXy2FWyU1MYPYUHkOO9gu6px7lQk2VQwAboEoGYLS5U4hcn-4U00HE0FobBADCDQMF2DpE7ioEGu5LE-OMiZxnndgIK5pc6LMl9SfjlbzRBO5fDCYloGKLkA0JFOEM3_3PLtAFhwchSrWqKSAJvEoKC_NRQAkOlghEGQAg7yvbWKUsgov_BPsssAXq94gEE_QCInfn6xYxAx4d4wNNs-w3HAIAuCZBB6BtmXdJ0SJvOhbPUw0msKYRIHrvbn6ke7kiFhcnGegzAG-W-h8fPFVFehCWUCQiScwIwQ5bH5yCHSl7xmMpAEudexyDuoaWEwEIBMQJCAFmkOgyMgoJLxJF_BAjBwcACEVAKJcLbVfpGw8QK-kks3QETD6xuoMb9HwPkY8D0F_XUskKmmcaChoEDVTXntJz5RdbEwJ4sk7We4bww1FCKQI7-b_EMAQLCBUFDgbPe_tTq3aIX3mo6JSVaID3h5Nr0ys0znScG85_f4p0fKoTvAaI0qO4R_cHD-8h3ThqW0nsyHGNmWWpVSvTbpCEjNl1ncA-yjSTa0yy6RUvrCJ4TjgX5wr0MaclNshDu1Gw_HqEjnDqFPYoSJaeYDDO8UrDMc3TK32BgbBCiuYYI9vmGP4B4hwo1mSagPqDjXHNgrzy_KPefzPLjnCxTuAfJtgErUwc4ki2is-knbepw6mR9Ad1jQDYBfsFZAWSBGNgOQVj9w-SBGWXBvoHZvOgBGkACP8B-PqZB1cOAP0cAADg-yUA2wAmAAEA2gAAACcB-90oAADYKQAAAdYd5CkAAQDWKvn5SZsr1SsB1CzVLNQsAdMtANMAAC4ACfcAANIu0i8AAADRL9EvAAAAAQAAAQDQMQAAAM8xAAEAAABqBZEAADHPAAEAzpsHkADOADTr4TPNMwAAAABoB2Tyowb6BnmBBpNnB1czbwd8H14E_ASeAF4FnQAAAPdnBGU5AADHE4QEnwAAXQf5BJ8ACFUH-QSfCfcAXQVgmwSo9wEAXASgAFwEoOpyBZ8AAAAAAAACx5MGn1sGlgkA9AwAWwT8BKHAQFsHnlsHn1oF-wWhAMVR6gEAAPpfBrvmWQegWQb6BGmTB2aTB6BZBKQAAAAAWAT8BKQAAFgHao8G-gX7BokZWAajANeABo5sBPwHhXQEplYEjm4G-gZmPlYH-Qb6BXKJBKj_VQf5BfsF-wf5BaXnbwVkRP0BVQb6B1eiBfsFpQABVQb6BfsH-Qf5BWBG0i7CkwWmAACxpAaMG6-kBvoGplQHpbkHJhpUBJ0LVAf5BvoGpgD_wUAAVARmlgRpQNV-BmdAwCIfUgb6BqdTBKpSBfsE_AVoQbCiBHeFB6cBUQSrUQSrAAHOMOLeQgBQBfsF-wWrAL5CANsl72EHqgAAAAAATwarTwX7BqztGvlOBpxeB_kHaJEHkhoATQT8Ba4AAP9OBq0A_04GaEIETAX7BfsFWqEFr0wF-wWwAEsFr-QdSwRiTwBLBPwE_AVenQX7BZ0UAAAE_QBJB_kEswRFBvoGsbqPBfsF-wWBegaxSQT8BvoF-wdanwaySAX7BrJIBfsGskgHsUgGsgABqVcA61wF-wa02iYARgW1Rgb6BPwH-QX7BbYARQb6B5Hqfgb6BmtJRgf5BPwHtAH6BwD_AdrTlgb6BvoG-gZrIyoAq1VCBoM14mAGuL32jwT8BvoE_AT8BPwG-gX7B7jvEbP7AJMGkus8AEEFusR9Bbr9vIgE_AS7AAAAAAAAQQS73WQEuwBBBPwFbU4AAACjnQVgmwb6BfsHuQAAALKOBfsGd0MAAPsGPwZtjQT8BbwBAAAAPgdXogT8B7sAPge7sk8APQZySz0FW6AEvwA9BX1-BL89Br7_ATwGvzsH-QX7BfsE_AX7BcAAOwXByjU7BfsF-wb6BfsGvzsE_AbAAAAAr1EAOge_nf4EEuihBMMArElEBcIAALcASfo_BLvtGwDbJdPZjQX7BZRnBfsH-QaVZQf5BJ1fBfsGtQBFBrQBAEUF-wSWzDkD9mgE_AeSZweRaAT8BWGaBPwE_AdYoQb6BFqiB_kE_AdYoQZ5gQb6B_kG-gf5BKlTBqf_VAX7BfsG-gX7BvoEaJQG-gX7B4jQBQEbgAWL2JgH-QT8BPwF-wR4AoIGeIIH-Qf5BrVFB7S7A-egBHKKBPwHcACJBnx-BfsHWp8H-QRYG4kG-gb6BqxOBnACAf4AiQb6BnEBAAD_AAEAAQAAAB1qBfsG-gaPawT8BnMAhwVnlAT8BPwEsUsG-gdzAIYEdkGzK2cH-QT8BfsEjW8Glso2AAD_2I0G-gR34j1mBHmDB3WEB3g7BP3EAADfIgJ-BvoG-gf5B3v_OcgAAH4F-wX7BPwGWDcH5n4GfH4H-QS34WQHkthLRAW2pCUAAgB6BfsF-waA_X0F-wVaoQRaogZYS1cG-gX7BPwFggB5BfsHe34HfCtSBavYeAT8BoHfmgX7BfsE_AeCdwT8BPwGgwD_eAT8BfsG-gWHdAb6B1ueB_kE_AT8BoV1BIj_AHUF-wWFdgSIAQTSnQT8BvoF-wZ3gwb6BPwEinIG-gVdB5cF-wf5BfsG-gX7BJxgBfsE_AZWpAb6BfsGiHIFieUbcgT8BYlyBvoGiHIEXKAE_AdcnQf5B5XHLHEGigDTL86gB_kEjgAAAW0FiAMC0S8BbQf5BLf_Rgf5BrRGBPwFt9kCaQWQawdeMWoEfhTqFQv5Zwf5BpICAABmB_kHcocG-gWXZAb6BvoG-gX7B2D_mgb6BPwHgd42AB_h0JQFaDDKmQT8BWI2AWIFXjlkBvoF-wVdA5sGYJoF-wS1xjxFBvoEdIgG-gWaYQaZAABhBvoHW54EmADKmgb6BmKYBvoFtkUFmwAAAPsGXwf5BmM4C_Xxbgac_8iXBmNR518F-wX7BvoF-wdWIOABogX7BJ7gfgb6BvoGfH4GmuJ-B5vHOwDGlgf5BvoGnlwF-wedAADuEwH_AlkG-gX7B55bBmSWB_kFinEE_AV6gQT8B_kFovxdBPwG-gWeXQa77RTQbgRdnwX7Bb0-BadUBfsEaD3DPAEAVwe5QAakAFYGplQFqVIGfOeXBH99BH5-BKpSBfsFq1AEfi7HOQAAAQBPBqtPB_kH-Qf5B_kH-QVhRsIA8VMATgSDM0YGhwz_aATB7wBMBXwe4urzWABKBLMAsyoDaQdpJ_9qB7ybogWzAMX0SANEBmKYBrZEBPwEqAYLAAAAQwWXypoE_Ab6B1-aBrhCBvoG-gZgmgX7BvoHlQDKWUEEjOKOBPwHuPxFBfsE_Af5B7PJML4qZQa5AAI_B357B_kGukAEtkYFtLOUB_kG-ge5QAZhU7c7FQA_B15csk4BPgf5BI4wwEA-BG-NBbyyAEjFgAd5gAX7BJxgB_kFi9VXpSh3B_kFhDsAAAAA_wA9Br09BfsEwa-MBcGuUTsF-wT8BPwFwOdUBvoH-QemwJMF-wb6BacBUwb6B_kEnV8F-wZrjwVgVv8BRQaaGgK75VxIBZsAAABgB_kF-wVZGSAAAQDkhAV6Af9GuhrDpAWUZwT8B3x9B_kGg_kA6JYEWxSNBbYARQT8B6VUBPwE_Ab6BPwHen8F-weeWwX7BPwF-wX7BbXhyzZkB_kEYpoGjAkAy5oG-gb6B_kG-gf5BPwFl2QFk2gFteEgRQS3RQb6BrVFB_kFbI8Gk2cF-wR6ggb6B_kEeSRfB55bBvoG-gRpT6OhBvoFfH8E_AT8BH7cogVZXMh-BvoEt6mcBmzvF-0AmweS0ZYGkGoEaClrBpL80JwH-QaQAc6bB5bB_hL4ChE5t0ZJBPwHef_fogSUaAf5BvoH-Qb6B4kBbwf5BPwH-Qb6BvoH-Qf5BI5uBvoEqMAAlAX7BfsE_AeQaQWmVQekVQT8BPwHegF-B3sAfgX7BVoifwdXOyLTcgZ8AH4GjG4G-gf5BPwGk2cG-gVyiQV_fAT8BvoHi24G-geRAWcHXi9sBPwGoNsE4CJ5BvoHngfQhAb6B_kGeYEE_AZhmQf5BpJoBYAWCVwG-gRzMPMBZQaVAGUGlQDLmgex4WcElw69Occu6h4AAMoAAAA2ywA2AAAAyjYAyjfJN8k3YgeS5TPP6DfJJ9n1QskAHBsA4SD4CMg4AAAADFQFnO8RyAA4ABbrFbI5xzkIvzkAxw0tAAABAMYAOgDGOsY6E-FoBKEAAAACAPPRPQD7BQAAvRoZEADDPvIOAPQMw_dGAADDFCkAwz3DPdYqAAHCPgAAAADCPxPTG-wU3CTBPwAAAQAAwEAAAMBBAAAAEPG_AEIAAQAATwWtAAAAAgAAAboRNboHQMcCN8c5ukYAAAAAAQAAAAEJr1D6t0kAAAAAAAAAAAAAAQAAtgBV9r9BAAC1SwABALRMAbMe402zTQC_9BY4s03AQQC4SAAAAACyTrJPAd8hAAAAALFQm6EHvv8CuEcAAAD3-w8AAAAA9goAANwlOQT8BvoHiivFfwR8PKOhBfsG-gb6BnkaZwb6BvoHdYQE_Ad1hAf5BPwE_AT8BIR4BHqCBPwE_AT8BfsF-wWMM-tRBvoG-gb6B_kH-QZ-fAd_egT8BPwEi3EE_AT8BFqiBPwE_AX7BXYxVAb6B_kHrE0F-wb6B_kHbyJoBPwF-wb6BvoE_AT8BPwGhHYG-geS93AEjc2iBvoH-Qf5B_kE_AWlVgX7BfsGq08GsUkHuEEHuQI-BA", + 0,1, + "SzzCa56RYrxCxjhrk0m19ggo1oB_5hgZ5dIskdKWdp4a0xnlpQ1QZxx1zDLIcLgFblgJNVi1-f-KbME9aaOgSVE155fISDe1nWG8QuoU4xtFu_L7iAduz42nYBWQr1GyTISxyCImtd0xhn1imOV6mgPrh3u_P6hWwvNIbYI07O1RrTK6N2B512KvMeJEu8M1-gdUFJjwDhjr94Ge4ekd1CIIuTwM8hDucYrsFgYIlFB_EXeseOXlDVenMs2uQEgQr2ShqVyyQwFZoEbH9qhW8BD-nD4iKsHVzWejYi7Gn2m4rZhlmVuT0Unvi7ORVk7t_ZfPN6Jt5-EhOMthWl7hP8AT6rdIA4B6bHohW4HOSMvdVd4LqmmfKzPSMfkP1uBh1tklANAgy7WKQjKKSJYp9VIHZSxDzu4QcIYHI9so-8Yx4S6kK4lrfWhlvfLytC7NVNs6EdFrBpnXG9mDFFbSW3awRbg9nhlukfl9CGXElqvhMIdbgOe4936GQ75PpFKySLKeYKtTrFMG6SnIOuGoq7J2I1y3ibirt3YmAg7wwjZajqhe4jDnPN3MLyKRDT7mYaY1NRb8f1KpMY8kKS_Pk2vNGFm-7hAo1k6wuUWlWc4wKT-WBvhIT-t787FMDFU5b4T3goV54xtxI2qlAVdhnodkEqtT17ps-fN3Bb772YF9g3tKtFKszDNqlOIcA_tcosE9p1jyDDMDx5Buu4CiICoOxZaRgFZh0KZYIQL4jmYImEB1ddZaOPl9yTE-nEXEr2rDPQn1NsTfGlU7cff5Z53fIP9DvCnW_2aDKaBe4TjKSj_xdLBPNLT8KfLPOby0oDDkpPsqDYCc2fAvqyamWAUDbFxGuSIJCGqL7BWuLQzlpCx34NIsWTA26_9ugUoGu8nc2tD9AVI5g_P6MtQW4F4IroNlMCfPJjgof4W8RGrg-C7YZ-ZEY2P_pdD0UsYsLyYETYFA7mUnfCoXTLSJek44582qas8gUrsT53SLWbnTlC5GrGw_mWiWtWzgWqsEbpyZSacOYsErVFJdjoYUxqhWxlf6RZ-p2AT8BPwH-QX7BfsF-wX7BvoH-Qf5BPwE_Af5B4AHAHIG-gX7BZVmBZphBvoHn1oHeQ8Cbwb6BvoH-Qb6BvoF-wRsAo4F-wb6BvoH-QT8B_kH-Qb6BXSHBnt_Bl2dBPwE_AR7gQZbnwf5BfsFWqEFrk0Huj8E_AT8BpRmBvoEfX8G-gf5B69KBHYFGmcG-gT8B_kGd4ME_AT8B7KjpAX7BvoFapEF-wX7B_kF-wR05KQHgXgFapEF-wb6B_kE_AV6Gv5pBfsEtEgF-wesTQT8BIF7B7BJBPwFrU4F-wT8B_kFbo0F-wb6B7VEB4L5fgRzB4IF-wZwigW512sEWlNPB_kE_AT8BJVnBJ9dBPwG-gW0RwWdIzsFvT4GWKIE_ASdXwb6B357BaZVB2eSBJkTUAV736EF-wT8BV-cBvoGtEYF-wa1RQb6BY8oRAT8BqoAUAX7BPwHj2oG-gRd_SYdzCFyBPwErU8H-QR66pgGW58H-QT8B5ISVQX7BX3yjAT8BfsF-wb6B_kF-wWe_l8Ek2kGjG4HdIUGtdUvQQX7BPwF-wf5BvoEgXsE_AR7QUAFgHsFiATqhQb6B10rcQT8BPwF-wf5BfsF-wX7BvoH-Qf5B1ajBPwGaht1BZsaRgVmlQVmlQX7B_kHen8Es0kH-QSfXQX7BWCbBfsGsePkggT8BfsF-wX7B_kE_AX7BfsF-wb6B_kF-wWhWgb6B21JQwaTZwZvQ0gFcIsEs8Y6SQSzSQZnOfH75OakB_kEW1dKB_kE_Af5B_kG-gZfmwb6BPwG-gVxigb6BniCBrDNfQb6BIf_dgf5BInxggR4hAdemwVvCgApWQZ7fwWqx4oH-QX7BqMc8Okm2gEcwS0B1CsD_NUk3f6EBlch_xFyBlg_4AD_AYME_ASCegX7BvoE_AbA39iDBIY1vTjlINIAAPKDB708BnPjpAV0AwEAIRhKBJkLCP8B-QNUBGgvZQd8KFUEeoIG-gX7BfsF-wb6BrNHBbVGBPwG-gb6BpRmBGuRB_kH-QdhXMlzBWuQB_kF-wf5BoJ4BfsH", + 0,1,"WO_7QhvqwcnpcpWktEQvoCerxoG3G74dXqs-rDbYBPwFlA0fsQDnJhHn4wMa46IGeoAHo9IDgQb6BQ",0,1, + "UvYbDvJEXONhrmjIKvdVuzjIdn3yZqVVplmZ0g32KadX3P3dw6cFbldMsa9ScsPkzngXvA7o3xTKUFsXAR0yjXWhOp4El2UGb049BPwHbYwH-QX7B6VUBfsG-gf5B4QaWwb6BlxWwuz4D5MEmuR-BppgB3noFkXCGWIEwq4pwip3BPwH",0,1, + "XeZk_aoQA54tJ1H-nDHZ4qRmJuZ_kWqH3CYHSJXkMsYvj2AtVoIGeYEF-wZ0hgRZNzHfH7yBB30IdAT8B_kFqVIF-wX7BvoF",0,1, + "_kjHfnRDia_K0uLO0cTMyc9aU68TQ47mDA0DNusbGE85mlltpcqV7mBateKwDEqLeXED-60v9zgFPiWf_idsmFGHB346QQXB8usgwR_nATfhIOEf4QAg3yAE_TwFwrYG9E-xA-wUBfkJBTkG8sVDAv68DgjqSQGvStPnJWMHurk",0,1,"WSfakQX7",0,1, + "UREz59vHpkZ86wq6u1Ig5sktrZFHBoV1BY3sO-TtdgeUCVwE_AQ",0,1,"Usa8xowYkOmD2AWZJbOKBKcF",0,1,"SnUsjKTV2GIOsUZiPb_new3mXA3nB_sL8R5sBXIFAP47qCrW",0,1,"Uiko8ZaFBe3b9ZlrJg78_QACBADTCg",0,1,"-h1fax33",0,1, + "IEjgLNtWggawEQ",0,1,"1HrM5IDdHKpMXX4kxpkRfJ9a98unB-ykSaAqwcvVjrvU7vlmaHOK5RaNARDw1HYHrwDsXgac_vQe7GIGwc0b7mMGmmAEseUBGOgBGEwGqNkpvA",0,1,1,119683,1,21961,0,1,"fsrRik4F",0,1,"_WlvbCkgZWAWJAP2COw", + 0,1,"D-c09I4l21RJ-A0A_6qR5ogE5yQEmj3aMB0_BYTrUsM",0,1,"Xw82kpSNhcehqG6dz4QKXxeI1VcKAQAA2CfyhQeEBc0oewewSQY",0,1,"2W3-vysFCvcpUIgFnNpDQgdh",0,1,1,14232,0,1, + "wpTCv1I4_Om37KGF8VX6KNSUEiBkz3KGB3XXJPnDvGOV58zhWnzzfFwHnf4GAP34_xX55RlYBKT0DfYSTweWYwapAPoGAwL_7P0QsjMk",0,1,"qb5QB47A1fOaLfc0kBSJ6_kaUQSYyTTvAds17w",0,1, + "cfDKIpiUofc2d49_hfj-2xT9_7lnnFeAf1ATllS0rD0pyK1r6wy6U7w48wNVsRKUC_QACxjz_gThLvX-f1kHk-7rB-qcBPwG-gb6BfsF-wb6BfsF-wSAfAX7BvoG-gT8BPwHZhZ9B8D_OgZSzzEAzyHfAAAA_yIA",3,56874,1,-64924,4,64924, + "XLYd4h5Avxq4ACsAJAHZANsAIwDVACkAzQAxAMkANQDLADMAywAzAP8h3iLeJ9kAAQD_AAEA_wAyAM4AMgDOADIAzgAyAM4AMgDOADIAzgA",6,20,2,-56903,2,2,2,4095, + "NfzQAgMwa1vHA-P-Gzf-wf7a_hz-5mGpM1uNewACAPwAIADfAAAh4DD1AAAAAAEA_wAAAAAADe_f_wAD_AAAAAAA",3,18,"CwHJH7loAQH-SAD4vTMO_wABAAAi3QAAIwAAAAAA",5,56320, + "XsoAenr-nxL-WQIG_gsBUgP3AfwBAwAB_oz96yzYUpvgLM0AIxriBf8jAAAAAAARAO8AAAAEAPwA_wAAAAAAAAABAN0AI9wBADHPAAAAIgA",3,56671,1,-51863,3,-58,"ztLsADTrqAEC_gMBgwHkMwAAAADNUQAAAAAABB8I",8,-22350, + "j_7-_v7-_rL39_f3d2sBknYDAwNUAAH-4A0L9oAAAf4lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",3,-116,10,55708,10,-56762,9,3767,1,8983,2,2,26,43995,26,6,"$1","$2",37,-52822,1,-11857,2,-17,1,-4,-3, + 32,8500,-1,1,-886,0,29,"AFinAT8ZKAUthCUFdB8AmXkrGmtAAfwBIAyoYwIW_i8SnsL2SIUZO8spEUvcAAGkFhIVOGsHTgAAAAAAAAAAAwAAAAEAAAEAAAD7AAAAAAAD_QAAAAAAAwEAAQAABAEBAAACAAAAAQAAAAEA",3,11, + "_nOLDAc5w_78HwIIEe1OCAP8AQ0e_gICAAX8APh-_SUFAP0qXl0BAAEAA-wAAAAAAAAO8gAAAAAAAAAAAAAAAAAAAwAAAAAAAAA",3,15, + "-wIAFiIO_v0YJUb-Ah48Af4CJrwSFTSEhoMUAK1ELRQC4FcPDBQrChcf90EWUQgGMyQ2vgsECxEBUN6N_P7-AyIRAf6W8lIAAAEAAAAAAAAAAAAFAQAAAAIBAAAAAQEAAQAAAwAAAAMAAAAAAAEBAAQAAAAAAAEABAIAAAAAAAAB2wAAAAAAAAAAAAA",4,-5, + 2,11, + "2QRm_kQAIUwA_RGV_mUAEAXBav4X_g7-TDP0DvgB-v4T-_z1-gMH_v70Bw3f_jsXAkIB3i24q_7-GwBvCIQW_q1ESAD9_lNAR_39AAE1aUP-Jwj-_XDUBFIJMQYIAE4AAwAAAAAAAAABAAABAAAA-wUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwADAAAAAAIAAQEAAAEAAAABAAAAAwAAAAADAAIAAAAABAABAAAAAAAGAQABAAEAAAA", + 4,6, + "i_EwEC7sBhBGg7VWUgAyABUvCgH-WQkP8Ar3AgD94gME9AIJAwk9_f4BHwgbImb5APsHjGQY_k8AlwX8_QXwCfgM-_r6CvcLzf3-Vfz3BP4C-e8AHABL8wr5-wj-1QAuAPwDcBtiZCdv_ZoLvfw3_QACUvf83bL-AwAEABUz9vwD60IWmkb5AQUA7wQL-fEAIe79IHp5hD1TMkMBCAUgSwkBAFYGCAgPDgNOAwvs1AsWG6EQdaQB9w8G1Sb52h8A6_z9ChDnCRz4A84e5yID6hHx_gEnQABt_gQA_YL9AAF2TwGnD_Af5yfYHvzvFPnYDSDuAfz1BgDpGwPw-fMMvQXzBl4G7gz5Bu8R_uuzTl70FfUE9fz2Fu72Grf-_QAw_gOcEwD9_lEAAvdeIIL3AmwMGkT9FAFe8wr1I_kM8Sf-chL-6fUS4xzxAfr5Htwo1Sb9_fSyAfy4Amp1AQAAAAEAAAIAAQDUAAAAAAAAAAAAAQAAAAAAAAD_AAAAAAABAAIAAAAAAAAAAQAAAAAAAQAAAAABAAAAAAAAAAAAAAAAAAACAAABAAAAAAAAAgAAAAAAAAAAAAACAAAAAAAAAQABAQAAAQAAAAMAAAAAAAADAAAAAAEAAQAAAAAEAAABAAAAAAAAAAAAAAAEAgAEBAIAAwAAAQAAAAAAAAAAAQAAAAEAAAAAAAQCAAABDbgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAEAAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAQAAAAAAAAAAAAEBAAAAAAAAAAAAAAAAAgAAAAAAAAEAAAAAAAAAAAEBAAAAAAEAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAABAQ", + 4,-18, + "XPkH6vwZ8gMNaXIbOucGAPsVzg8V3xvbLfvqBe4L9RHvFgYD6fMFAPrp_v5j_dOV_gsASWzz3f7-toRZQPwJ-gL-F7wi-AH9Ri02Dg5HxgtC9x7QFBED_v4crxAH-_ylfAVl-wL4AfkvHBcPAgwAwi3v5QvsLu_6_OwEEuARGucQAejZ_QITDf4BRD89_P4C9f0HCnz8lgH-_RRnAAAAAAAAAAQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAIAAAAAAQIAAAABAAECAAABAgMBAAAAAAAAAgAAAAcAAQIAAAABAAABAAEAAAAAAM4zAAAAAAEAAAUAAAAAuAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAABAAAAAA", + 3,16, + "1v0CmwEg4Rzq-vsMDfP1E-AEFQ3HBSLxEGuI8_L-9wT9F58s_QD7D2n8GOT0IvQJ_P0H9uQDHvKZBP4zAv0D_AF-LfwAcOkW8AEFAWQB-_4F9WYh_AT4AF8vAAFWAP38YAIc9wkPBBoF4BPqCwUBAe_6_in-AT5JAvf6AvYYCM8nAPb83xT-EwjtBeck1ib9AO7lIW9oFD0Z_vj5-wvxDgX0_AX9YR0J2yrWAw8V-dcADgn0EeQk-OjtB7BCABeTB8cECr0aGM0JAP0lyCn95Av0B-wo7SvN-yX57uFC7PkJtPgD9w6SAAoPHgFWDQr9-Nj-9gv5l1_7AOk9LwHwF0ABAIf-sf6AA1U3_nm06vwO7wn9CvUENRgOpen7Ew_hGff6-AkI6gwN-JYiq0piAgX84wL4BBAJpQibI_77CP12LmkLQA0AMtP5DyDw_Q3l8iEG6gzWIfP9F_MP2J86_g6t9AYC_v77fwH5_UtJIx5A0BPnJfru7QwT-vrsFgID5vsFCe39Fz-CCBQC_ivf5MH7_f4Bi_sm4wQa4QTvCxr5bTkC_f0CW0wA_f2N-CQlB_ldIgVTDSQ3IvwEAPsE_IgKAgToGSQi9_nj_Cj-_vncmjny8vAT7A4J6QX3_BH1HPA8BWURJEIH8gYH7wgI8tIH0x3i-xvJ-EXzBdQM4iUK0hYOFLwoCPr0lxgCLhwER6lBJvcW4-Yk7PgjAQD35NlD7RDwBAbYHH8O-PgC_Qr19YtB_AR09gDVEvD2GvLyZhIh_AH8X_gA_ADUUwAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAABAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAACAAAAAAAAAAAAAAEAAAAAAgAAAAEAAAABAAIAAAAAAQAAAgMAAAEAAAAAAAAAAAAAAQABAAAAAAAAAAAAAAAAAAAAAAQAzDYGAQAAAQAAAAEABAABAAAAAAAAAAEAtwAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAABAAAAAAAAAAAAAAEAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAAAAAAAAAAIAAAAAAAAAAAAB_wAAAAH_AgAAAAAAAQAAAAAAAAEBAAAAAAAAAQAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAACAAEA_wAB_wAB_wAAAAAAAQACAAAAAAEAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAQABAAAAAAAAAAAAAAAAAP8BAAAAAAAAAAMAAAAAAAAAAAIAAAAAAAABAAAAAAAAAgAAAAAAAAAAAAAB", + 3,13, + "yP38ATv3_hAB8v0K1CUR9wA4Av7-cQAWAPizAX39f4QC-gj9_AExVTBEC_wDJJ8O9OgABxT58g8F-BYtxBsB3fcKHeAcBsgEGQ_a9_wM9AsPFkkoAf7SHRVSM_kAmgHT_kAY_iP1-wf6B_34A-ED8gGH_oK0zXYAAAAB_wABAP8AAQABAAAAAQAAAAAAAAAAAQAAAAIBAAAAAAAAAgAAAQAAAAAAAAAAAAAAAAAAAAABAQABAP8AAAH_AQD_AAAB_wAAAAAAAAEDAAAAAgABAAEAAAIAAQAAAQABAAAAAAAAAAABAAAAAQAABAE", + 3,-6, + "YgZhIQUNpjIDtgK-WlgAFcs2_tIw7O814vr3_ugFExPIL-kN_tr6PvzTLN1yJwD8Kv75BIoF9wYBzFQf_UEIJ_A1xOgME_MZ1APzJ-T7-0Df9RHzAL0R9vdFBUcAAbYGAwL799gzAgX75vxh7FcCAv35BgP-S0wD-pwP_e79BwUK8vk-_X8B-Ylg_v7ICQHqBBf7BRQa-vIG9_gQsKsU9k7v8CXsAwj58BXs7AD8JP77AE8nA3wGBfMO-fj7thsAAQkWD_0M5QgR1IljNATrtlvv-wbmGs0EKEj-LWsDAP39y3kq8v7eEf7hOdgc5OsZ9CL97gvfLjUNC_TuBmk_gvwD-v6OZhvk8QnzdQj-_f5kBgHqAAn-_Aj10iQZAgBa9QAHwEb2EOQWAu0H8v4SIvoP_vYH_vkCif4D9wYC7qsDUCwKd5f18_4VAfH7BAQB8AsBHiQ0MPtEEfwD_SUBsRDtFOcGEfH6FPQM8fL9_hMPGQD8A45vJgH17Rf46_4a4gb84Cjw9hoQNR_oEATiFvjTBgkA-vue9_39CPQM-wL4ATYx_icA1DQlAfrhTwTwCPn5DvkH8pxL-wRv-v6LBPkE_KneAP35AQbzBVwmyfsvTAwJQfsC3ur7CA3uGxDXBh_-Ate_X_3uOFp5BGIG_vw6_gklAP2EOEkj-90ZAuEG5iT4Bdk00_UtzzbPDRWwAv3VJQT72QMVBzLBASZB0woHHAPV-yX36wMlVv3-_fwGQv7-WPsAqf4HDPoL7hfqBAoC78pV_fwDfwD9_gh2AR8U_AErAQT5CP774iPlFgci6DHWB_X5Jt8b_PAY2CHsUgAsVwbKIwsC0e8wEcY33_kXzzzbAxAHCuX88Prt_hHi-PoH_QfvCPz-R_4QIvsAAY78CQP995rdQ2Ut8vAhyfY69e8Y0kDo2P4OCAr2AeCvhzAAPmItNuXYLuoXFv4KwQPjIdwvGr4-_c8MR5okEOwRBvz53f3lQdImEg8A8vFNPwOa_vr8BW19BPgC9w7SFQAkBUIA-w0eRADfFALARf0IWwb9-QEBMNcKFgIEjZYCigfyEPnyBA9jBP2w_C28CgID7wIQ6hLv_gtg-zEBA0kt--jmDAf9BvPdMgH-AlQP-d8p8ybt5vcI9RbWAwAJIK0UXPj1DfAQBOX9GYlK6SLmA_b9B_ua8gUBC_vx-wYmEE4C_vwB_L_-V_sgAznzDPwL-_3yBAgB7hLzBPjTBA9Zdibw_AMF-5_gCv0E9wMBAPRTKf72_iIAVoqPCSUV5ur3E_fuFQEBZfCAAQDzdP79fkrVBCbUDRL66RkN6fID9y_68J5z5yDwBMwKIe1zIfoJ7wsA7_sC2ABlFiLkEggLy_1g-Qb8OQAlGgPjErVH9wICOkv2AAF3MDsA_SgP0AMpOwbWGtoK-HOIHOcS9hEMKVnoQvAo3_wGBBDsEPQWAId99fB2hx5kB_sALf4evgEDAfgh6AP4hgAf_dzaCvf-LdkV-PgR2B_w5wE_BPu6EJOMQvsCWv0lMj4A_AIIG8wQNOLVBP33P_zLMRe--EjEGOzxFtkgjL2PNBTgLfb1uQALCfAUN60vN_u17g70EO8I7gIPAP366woB_ABE_nf4B_X-BQGaABn8ICdynW8OAp36Avn6l_7-Tv1lDO8JAQH4_QMBTQW48Rfs1UID7gT7DQIQTwA1RjLP_vYF_OoM9w0GIJ0JzBn0FNLkRbUtAQJisuUbvzD0123V9dcqzAp7g_kT5gYI6w14aQDu0RKkJPQI3QQSBvT17QX7HwogLAz2CQP5BPMC_gj40fr7TA7tDvb6Duo0_AOfkQb7BvkDy_IT9GQBaUQADeUU7gL2CYL6-wUB_vv7A_zxBwAG5BE8A_4BACcC2TgAAd4CBPkI-sD-FQkDsCoH_AAR-O0KA_MXt_cFYQb9_QBLrwjqEucN6gkRAArqBuMAHuNIAEryBv4C-RbgINwX7_gbWQcC8f7-9g7vtgXcLE_-SUZSAWv0ONbTJ90HBkX99wjw9fLl-DDpAPAq3wsCD-7iDPf4KN8A7mUyEObx_QAN7RP0dZDY7Bzo8yC6UccdAvL0JQzWBffrKk3-EymkDCPiC80MKf3f8iP98CXEBScP1fwMmQoP-uQd9A_55Rj45yHt4xfkDfn-MOr6Cf7i_RkBABkBh-8Q8P4IBPT-6gB7D_r3BBXwAe8IAvmLnyHmAPP88hQB6_oEAaqQXv0F8wr-gADWSJ8N-EkBAd3lF-8NyxL6AAc2_vuxAS397P4H7AgE9w0A655BOvTF80PwBN0i7uD4KwEFA9gX_QKZGfT--P38BgACA06F9AQC-wQD6Ar8yUaHBgDyAgYW9OY80BPn9Av9DAHCKfkn_kD8APvtEP4CG_0IBgMG7_kBy1AF9AuUEpj-CO4R5xj69gf-_gPsAtAEVP3-X20f4AQC_RzvGOziFAP38wUaPf_7ADf9_QAsA_38Xx0BmQAB9gf57_cIALT9AiwHmIsEDMYG9vAW7Pr5AR_cGniQj_6ue1ABGvvlFvECAwDoHgjoB-Uh_V4IBA_27gv3fyf8AUX-dwQC7f4BCpFoCPkDAAH5AfotVCEC0wfxAfx-AjM7KUiN9wsr6gD7-v0ctFzQ-0_T5hrWFcw4DfYuNf7LBfT-C-wr7CT3zxsD7wgb_N8e2RzfpQLm_-DpFOA0FOEL4vIf3O8WKgb58PEVA1ihwRTw2SqcBOMM-Q2rUwOtCxP-BgX8loyV5f39Cc0BoPgB4V_dBwv1-eoA_aACeP5DAbHz9ekhBfb6KM78NAMA_PTrIADhKen9_gjnHPUC9CT05MNvAP1--yzILw74AfQCZBIMDAksffUG_dQEE-ku7AcSvCsU-HTcHuYCDuM84fHJDvEE_gTqMdS25REE6RPxEAX6Au_4CAzCIv5G_QCYLftmF_0C_Y-89wMG9QQD-v29_gVWAv78AwcEEv3kFwgL0xQPBgD5Af70Av4wBS17CHAgAJYBUQEG_LftADVaALEB_Mh-Drn7-vkDCAUA-9aXAAAAAAEAAAABALUAAgAA_wEA_wEAAAAAAAAA_wEAAP8BAAAA_wABAP8BAAEAAAAAAAAAAQAAAAABAAAAAAEBAAD_AAAB_wH_AAAB_wAAAQD_AQIAAAAAAAEBAAAAAQAAAAAA_wEAAAAAAAEB_wAAAAAAAAABAAAAAAAAAAAAAAH_AQEAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAACAAH_AQAAAAAAAAAAAAAAAAAAAAIAAAAAAQAAAAAAAAAAAQAAAQAAAAAAAAAAAAAAAAD_AQAAAAAAAAAAAwAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAgAAAAAAAAEAAf8AAAACAAAAAAAAAAAAAAAAAAABAAAAAAEAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAQABAQAAAAAAAAAAAAAAAAACAAAAAAEAAAAAAAAAAf8B_wAB_wAB_wH_AAEAAQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAIAAAAAAAIAAAAAAAAAAAAAAgAAAAABAQAAAAEBAP8B_wAB_wH_AQAAAAEAAAAAAAAABAEAAAAAAAAAAAIBAQABAACzAgAAAAAAAAAAAAAAAAAAAAAAAAEAAAEAAAAAAAEAAAAAAAAT7wAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAABAAD_AAABAP8AAgABAAAAAAAAAAAAAAEAAAAAAAABAAAAAAABAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAACAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAA8BAAAAAAAAAAAAAAAQAAAAAAAOwVAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAABAQAAAAAAAAAAAAH_AAAAAAAAAAAAAAAB_wAAAAAAAAAAAAAAAAADAQD_AAIAAAEAAAAAAAEAAAD_AQAAAAEAAAAAAAAAAAAAAAEAAAABAAAAAAABAAABAAAAAQABAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAgAAAAAAAQAAAQAAAAAAAAEAAAAAAQAAAAAAAAAAAAAAAAAAAAAAA9knAAAAAAAAAAAAAgAAAAAAAAABAAEAAAAAAAAAAAIAAAAAAAAAAQAAAAEAAgAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAABAEAAAAAAAAAAAAAAOQAHgADAQIAAACyAAAAAAAAAAAX6gEAAAAAAAABAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAAAAAAAAAAAAAAEBAAAAAAABAAAAAAABAAABAAAAAAEAAAAAAAAAAAEAAAAAAQAAAAABAP8B_wAAAf8B_wEAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAH_AAIAAAAAAAABAAAAAAAAAAAAAAEAAQAAAAAB_wAAAAAAAAAAAAEAAP8AAf8DAAAAAAAAAQAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAEAAAEAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAEAAQAAAgAAAAAAAAAAAAEAAAAAAAAAAAABAAEAAAAAAAAAAAAAANgqAAEAAAEAAAAAAAAAAAAAAQABAf8B_wAB_wAAAAEA_wH_AAAAAQAA_wH_AAMAAAAAAAAAAAIAAAABAAEAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAEBAAAAAAAB_wH_AQAAAQAAAAAAAAAAAwAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAQAAAAAAAAAAAQAFAACwAgAAAAAAAAAAAAACAAAAAAAAAAECAAAAAAAAAAAAAAAAAAAAAAIAAQAAAAAAAAAAAAAAAAEBAAAAAAAAAAADAAEAAAABAAAAAgAAAP8B_wEAAAAAAAAAAAAAAAEAAgAAAAAAAAAAAAAAAAAAAQAAAQAAAAAAAAABAgAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAABAAEAAAABAAAAAAAAAAAAAQAB_wH_AAAAAAABAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAQAAC_UBAAAAAAAAAAEAAAAAAQAAAQAAAAAAAgAAAAAAAAEAAAABAAAAAAAAAAAAAQACAAAAAAAAAAAAAAAAAAAAAAIAAAABAAAA_wABAAAAAQAAAAAAAAAAAAABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAABAAAAAAAAAAABAQD_AQAAAQAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAADAQAAAAAAAAAAAAABAAABAAAAAAAAAAAAAQAAAQICAQAAsQAAAAAAAAAAAAAAAQABAAEAAgEAAP8BAAAAAP8BAAAA_wIAAQAAAAAAAAAAAQAAAAABAAAAAAAAAQAAAAAAAAAAAAEAAQABAAAAAAAAAQAAAAIAAAAAAAAAAAABAgAAAAAAAAAAAAAAAQAAAAEAAAMAAAAAAAAAAAAAAAAAAAAAAAACAAEDAP8B_wEAAAAAAAD_AAEAAAAAAAAAAAD_Af8AAAMAAAAAAAEAAAEAAQAAAAABAAEAAAAAAAABAAAAAQAAAAAAAQAAAQAAAAAAAQAAAAAAAAAAAAABAAABAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAEAAAEAAAAAAAAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAEB_wAAAAAB_wIAAAAAAAAAAAAAAAAAAAIAAAAAAAEAAAACAAAAAAEAAAAAAAAAAAEAAAAAAAABAAAAAAAAAAAAAAMAAAAAAAEAAAAAAQAAAAEAAAABAAAAAAEAAAEAAQAAAgEAsgD_AAABAAAAAA", + 3,170, + "jfxlwXsM_fgM9PQp-ggcwfgATx7-FOgR-vzGm_EP6Rb75f38AXgAN_bN_AGA9wT9BfxnKEX9wPAG7vcs-fP6EijoGuId7QnvGX86BQkkE9UHH_TtARPoG_797hHsCBDBAQA1_Aj8cfvIGBz64yPx9ugOAucjPv1VIAB4PAfMFO0x5u0c9R_r9fMywHyZ8P4_DAT2rUSyCBEh9_oB_qAI9QQB-gB3Hymp-AQE-T_59A_zFuYTbvwD_PkDc_7-AxLvEQD53iv9FRP6C9wT8Ar69gMKtDoYBnsBNzk8UgAAAQMAAAAAAAAAAAAAAAAAAgAAAAAAAAABAv8B_wEAAAAAAAEAAQABAAAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAABAAABAAAABAD_AQAA_wEAAP8BAP8BAQAAAAAEAAAAAAAAAAAAAAAAAAAAAP8BAAACAAAAAQABAAEAAAAAAQEAAAAAAAAAAAABAAAAAAEAAAAAAAAAAgAAAAAAAAABAAAAAAAAAAABAQAAAAAAAAAAAAAAAAAAAAIAAAAB", + 3,372, + "oPn9fiXc0z0A5f0R_fLXONkGe_EB6QUR7_D99AYHAbL2CgAB9LEV9PzQNSy5Fvj88CX26AIhcAEdc_0H_QcA9AD4DfaLMQOH5AwE7Bn1AfybYv0DCfwD8QEGQwT5BAm4_PkJVQEB90H1-zLBN9zxCBX0KMH6A1IBAAFWLP0DkQnwllYI_gXE8g779QP8Bt02ADcd_jL3lgL5pRQP2am_Bfv7BGopMrMBX2URDe_6E_H9_Av9_PUTSvwI_aiuFkN3HTtn3hfgQugHC_1nlPsJ7wAd6QL6CvESAem1UQLvCgLwhPoBHhHs4Aod_un77SnoEB2NvO7vIeAc5QsM-Pzv-RMJCgYB9QzjFAoC5gCjMwb0Bv5DKQAmAwGs_br9AAVC8RH6vqYA9wX-bh43txr2BQf87gAzBvYSB_r-6wZoOD0A_DmK9f5SDE8A8A7uHwDZBSP88yQb_gPq08gH8gX1iPs_E_AFDtsKBg8CAPT1BQIFbgElYE_sAg32-wXzCPp0_c7-A_kJ_bldjRXBOvvy2S7YFfUV-vMY6qHrAAEqOAIE9gX7SwAJMZcHAvv1C-rrF_X8BfjS9A7GAz7xOmiDDQIB6Qi8-7gOjfQBEMKY8Q_0AQdF_f38Yfn5VbwwU_0C-rLgcAv4BB7kZgGZ-w0HD_UFBPAKlABV_KkT7x35PsfaGPgPu1ErLc8Y7QD6CAYDkGv0B-sYAfb3Dvf-B_4H61QQKQE2BvUBnfsJncj2Bfv6BUEHAvn6EaUCrGdHBfD4FNP_-wED_PkDUA8H8PoQ5xHzE_vyBA7sCe8Urgh0AP3-A1L89gf9_v0L9CkgZzjZ-R30Ahrr6yDh3FgQ4R7z5A_-DQJv-g3zBG5hCAEB7hX85gsw_TOGAv77AqygAfwB-fkDAvk__Qb8AP24afr9sDSlTNQa5cxl7e4U6fmBAAAEAAD_AQAAAAAAAP8B_wECAAAAAAAAAAAAAAEAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAEAAAEAAAAAAAAAAAABAAAAAAAAAAABAAAAAAEAAAAAAAAAAQAAAAAAAAAAAAAAAAMAAgAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAQAAAQAAAAACAAABAAC6R7IAAAAAAAAAAQAABAAAAAAAAAAAAAAAAAACAAAAAQIAAAABAwIAAAAAAAAAAAECAAAAAAAAAAAAAAAAAAEBAAAAAAAEAAAAAAAAAAAAAAAAAAABAAEDAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAIBAAAAAAABAAEAAAAAAQAAAAEAAAABAQAAAAAAAQH_AAAAAAABAAIAAAAAAAAAAAEAAAAAAQEAAAABAAADAAAAAAAAAAAAAgAAAAABAQAAAAAAAAEAAAAB_wAAAAEA_wAAAAACAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQACAP8BAAD_AQAAAAAAAAAAAgEAAAABAAAAAAAAAAAAAQAAAAAAAAEAAAAAAAAAAAEAAAABAAIAAAAAAAEAAQCyAAAAAQQAAAAAAAIAAAADAAAAAQABAAAAAQEAAgAAAAABAAIAAAAAAAAAAAABAAEABAAAAAAAAAAAAAABAAABAwAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAQABAAEAAAACAAAAAQAAAAAAAAEAAAABAAABAAIA_wAB_wEAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAEAAAEAAAAAAQAAAAAAAAAAAAEAAwAAAAAAAAAAAAABAQAAAAAAAAAAAAIAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAQEAAAABAAAAAAEAAAAAAAEAAAACAAAAAAAAAAAAAAAAAA", + 3,629, + "yP3qBh1FAYEycm9-y_2u_P4CjQNLQw79AP1iDJayGCr-XySFT8D9CwfzAPu_JEmM-Bb3_AnrAK8YNlkB8gfzFv3rAAH5fv0xF1VAAflqAfsAUZ-yAP1jAGX7AvME_cVsAAj7BvAG7rABe_5WATrE2SMC-OYJ_uxI_AXtpStBMxDy_iS0UwkC_fr1aogDOfsEIgAjw_ULCxD6_QPnAfw8AfkEDPn8AQJFfgIGS1MB_AEEZoMA_fB2aLJBAkj-_nz-M8r3kAsCfzQWBnE4AAISmlsFBP7-Cg7Q_Af3_PhHAwjxAvcC7QZKSdUBQgwYo_7YAWVRl7n91AD4BPkIKgEL7wAa7UIC_h8Q8wzqDgARAwkH6wRh_vYH4hr78BDzAPYSrgFx9RTu9Q353_le3AAl_DLvDeMEEwD4C-oKC_IQ89cuRvw5eh5i-QJgiAPMAvPa_u4ErdcQ9wElBPsgQ68O_v0HJ1sCOXjSLgEd-wTMQMRR8QHdalOSAsADAf6bLlX2CaEAvc7-Bcmz2YuU_RfoCwT7AgkATlU9d_v5CO8Lo_179wP8MRZM6vnjTpON_laCBAb93flrOzJGLwP91QCI_gFRV2AuAR7-eFMRCPW3mc6LLv2UaXw-_C9aFewI_v79SgFQtgIFlXYC_dNPCnMEAQT9-fi2VQD4zGf98e39_P2QhPzb94kEDfXkUSlCCQDU_owB_rVU_XuwJOVW7wYnY6Xj_Uas_h7-YZL8jIOVAHkBzeb7DADqAIT9qen_94RHLucM_JcDXDf9KTcJKSIH_sEjye-Z_gEtAv1NVQbxWAX-0_wDAwbs_QD7ewD8ggL-jrlU3BdCMRIAZHg3rQIoMP4D4KOkqdcF-4Gp7sI1BpkAgQCJb_qAIkwIAcyE4B-w_QDsd0yol3W_3FGYAjb_DRq3AP36AH5cKpoNQcbpAlOVAAEAAAEAAAABAAEB_wIAAAACAAEAAAAAAAEAtAMAAgADBAIBAgAAAf8AAAEBAQMAAAAAAAAAAQAABQD_Af8BAAEAAAACAAEAAQEAAAEAAAACAAEAAAAAAgAAAAAAAAIAAAAAAAABAAABAAEAAQMAAAAAAAAAAAIAAAACAAACAAAAAQEBAAAAAAAAAQABAAABAAACAAAAAAAAAAAAAAIAAAABAAAAAAEAAAAAAQAAAAAAAQAAAAABAAEAAAAAAAAAAAACAAABAQCyBQIAAANEvwMAAAAEAAEABAAAAAYAAAAAAAACAAAAAQABAAABAAEAAQIAAQACAAAAAAACAAAAAAH_AQAAAgQAAAAAAAACAQD_AAIAAAACAAAAAAAAAAACAAEAAAAAAAABAAABAAEAAgAAAAAAAAAAAAAAAAACAQABAAAAAAEAAAABAAEAAQAAAAACAAAAAAEAAAC0BAAAAAACAwAAAAIEAAQAAAEBAwYAAAIBAQIAAwAAAAEAAgAAAAAT7wAAAQEBAQMAAf8BAAAAAgABAAACAAAAAAACAAEAAAADAAMA_wICAQEAAAEAAAACAAIAAAEAAACyAAUAAAMDAQQABAAAAQQB_wEFAgACAAIBBQIAAQcAAAIAAAABAAACAAACAQAAAQACAwAAAAAAAAECAAAAAQABAQAAAAABAAEAAQAAAAEAAQAAALIABQAABQIAAgIEBgAFAAMBAQEAAwMABAABCAAAAgIAAQABAgMAAAMAAAABAQEAAAEBAAAAAQACAAAAtwcFAwAAAQUJBgIAAAIAAAMFAAIDBQAEAAADAQEBAAAAAAACAAABAQC4Ag0LBgABCAAJAAADAAD3CwQDAwAAAAECAQABAQABAAEAAL8NBQwADAEFAwMABAEBAQPSBxQJAwMA5A0DAwMAAAgAAu4ICtQoAQMA3g", + 10,-22547,10,10,10,-782,"NghFGuETFE0-MExTdVpXS3RbENKrseM-APEdTgAAAAMAAAEBAAAGAgLSLwABAAYAEAEZB2oC","$7","OwH__wAo",83,2307,86,13,"$C","$c","59AAFXCLjeVJd44e1yirqSEAABCnBHKKBHbyW7JOOQY",0,40, + "4gEi-i7kCnkA4wP_AAAAM-8ADwD-AA",3,1,-1,2,1,1,7,2,6,1,7,-1,-2,-1,-1,1,7,1,5,-1,1,7,-3,2,1,-1,2,6,1,6,1,4,0,3, + "g8wK-CDdpFI-39cZmCRnhAQ6RUk0YQSbd4YfZC4G_s9jb0xm4ijj7uHRGEcq8Qqr8wz3-_wxDy_VAPMXUQKNKDj-kHsBRj9GxCAM-_tyAdkt0ZPvCRPIHtwO9hAU5AIc8PDvHZ5h9QaVe_wtPHzZ_U77CQdD-wj1AvgH1r4PVv0AAmCVDn0XWWD--owBBfwE-_YG-QqJ_k_6_gL-BPz25C0LCfL6CfYAJOxVANibVPXbJgMD_AHNMBr9AAL4jQH7AjLkJuYJENko6gzhFtQFCyEtKWIBAosAWlkOGwCgBvIp8NMCCPIkEfHm-yKm-P1bAwb8AQazOWXxB_b2E-3-F_nsA5UBYgH4Av0I9_sMAUopA3z9AvsEdxda_Vv-_hz6BQTtAv4W9AcDBPNFSAgBAATy6Qn-9RAG7gX0AcK4A_7-Ak8BEfv2-xTvDPCESABd7gMYBgPh_fkw0hkNBskM8RUS5QXoW_0FAvr4Cs8B-wD9p_5aAOu79mAD9gEJ8_71CAIB9vgA81D13wED-Aj4j_cG_QVk4wj3Agbu_RT68tRK0i_eB_YXC_cJ8-8S1QIvHQF2_AAS6opNADBVAfL3AQ_wBeIOA-YGB_Em4fH-N8oD_JIBdQL6_QX-BQn0BfcA7QUUjjhvBBT-4xn09AUGEtoLAgfrEpoCLQGuAmb1-xT5-APyAwn0B_z1BxD59XD8BA4CAAAAAP__AQEATAADAgD7AAAACKRiA-8D_QAAAAAAAwEBAAQCAAMBCAYAAQbcAAAAAAAAAAQBAAQAAgACAAEAAAACAAABAwAKAAAAAAYAAQYHFrkAAP8B_wH_AQAAAAAAAP8BAgEAAAABAAAAAQIAAQAAAgAAAAAAAAACAQAAAAAAAQEAAQAAAAAAAwAAAAAAAAAAAAMAAgAAAAAAAAAFAAAAAAAAAAAEAgAAAQIBBAUDAAAAAAQDBwAAAAAGAAAAuQAAAAAAAAAAAAAAAAAAAAIAAQAAAAABAAAAAAEAAAAAAAAAAAAAAAAAAAIAAAEAAAAAAAIAAAAAAAAAAAAAAAIAAQAAAAAAAAAAAAAAAQEAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAB_wMAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAgAAAAAAAAAAAAQBAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAIAAAAAAAAAAQAAAAACAAAAAQMHAAAAAAACAAAAAAAAAAAKAwABAAAAAAAGAAAAuAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAEAAAAAAAEAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAgABAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAQ", + 3,-7, + "VC37_mAGR_jyGNgo1Qwb5gMN9eoCHeT9-vwS9yhvBhzs6wsT4wT7C-0GB4RqEk3yBw318gcHAff3E_7lE3rmIQPjBBzt_e8Y_u0k8Qfp-QP2ABqQWv1fPnVY_gLq3B3YOc8Y8fcIAiYE3wrW1RLiXeFvnPnoSNUZ58ID7A3y_QwE6xfo5mv0DPAS9QEF8QTS_Av4-_0L8D8KVgD9TQsWQ_3-BAID_AH-_Er8hbICf3mHN1ke9BT893J_H-ru_QIZ8QYN4Rv58_gHGOEe8uvN_v0A53v4B_kI_gHaAfoD_IgD_v0IifcN3hYB9RIH_OH3J-sO4wX4MlcEdgF6Phr-Av4h5gv3KfNJqfYn3w4A2c9L5Ruza9EE6AAE5woF_fgD9gkL9PpeGEWN_A8R8OscAv757Q0E4w0JAeod9fi6o4MH8wrzDwL77v0CC_wA-vj9BxAYAF8AAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAB_wEAAP8BAAAA_wEAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAAAAEAAAAAAAAAAAAAAIAAAAAAAAAAAAAAQAAAAAAAAABAAEAAAAAAQAAAAABAAAAAAACAAABAAACAAQAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAYDAAAAAAAAAQAAAAAGAAAAALkAAAAAAAAAAAAAAAAAAAAAAAADAAAAAQAAAAAAAQAAAAAAL9EAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAQEAAAAAAf8AAAAAAAAAAAAAAAAAAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAE", + 3,39, + "IAOL8_34BwFhJicvsAEaHevmDfMBEfDzARzEHxMNB9MAiz396Rj05w0V_Ov9CRIA5Rrl9FABZhR26hAC5gn7EPcO4hYE9OAAsDDV8SHePN_n9g0l-PrVF-VD_vf03vYUGAjBSckm3uE39B7OAPgm4FxZATEfAQc_AAYL-PEcAtL3z1jQFCDf9u4cJL4WHssLMMYYC9sZ5gam5x7y_vASAPOXBwAhAwL6WxkDAvMK-_yhRvUF_PP8_v420wf2BALxEiABPxgAXgLOSkNeAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAgAAAQD_AQD_AAEA_wABAAD_Af8AAwAAAAEAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAEAAQAAAAAAAAD_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAQABAAAAAAEAAQ", + 3,-6,"CuwD_uwAHQoA8gr-_vr5DzYB_vn-kPcBBvex_VIuAHj9AHf_AAABAAEAAAAAAAAAAAABAAAAAAAAAAAAAQAAAQABAAA",3,5, + "AwT4Vjj7MEgGAAQioO4Y8Pb5DfQd9QLtCvMFBw7mMSFyRCT6DeAX1GSw6h339BACFu76-fn5-xn4-Yn8B_bNDBgC_mkwAmpw_QzxEMsBFe_4CAP8C_6A-gEB9gPP5gELDg3q2f4-A_TJAB8EAwYN-QHcSzn-NvkAAgWS-PcLAPUMakCPh7s0-tQL8DXkBAPiJfPrGPD7AOct9Af1AMllovznC_b--_0IBwjoB0w7zvwWAOb5B_ITFDg6Bf5WUv2XEu4CBQj4L_5_BfsBhvw29fwM2WDl9xHuG-URBfvvFPGKLKsdRdUXAPAMoFQR_vHsF_Ij-wTTGesm9uYe6AcB-3_8AP2HFOcJwAAL-i7oAAcPA8Ya6hj1AQEe9e_o9AERAQUe7Or6CwL9AwI4FAVd_QP6_gQ9VOgAEZZTMMUJCgEh-2GPBtcI-DbYC-IiFZY4IvIBA5Fs9wH3Gkv2_Qvtbaj0-gsB8_h9AAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQAAAAAB_wH_Af8AAAAAAAAB_wAAAAAAAAAABAAAAAIAAAAAAQEAAwIAAAABAAAAAAAAAAABAAUAAAAAALoAAAAAAAD_AAEAAP8AAQAAAAAAAAABAAAAAAAAAAEAAAAAAAAAAQAC_wEA_wAAAf8BAP8BAP8B_wAAAAEAAAIAAAH_AAAAAAAAAAAAAAAAAgABAAAAAAAAAAAAAQAAAAEAAAAAAAAAAf8CAAAAAAABAAABAAAAAAAAAAAAAAAAAAAAAAIAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAEAAAABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAV6wAAAAAAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAP8QAAAAAAAA", + 3,-9, + "2vMSYDX-_on5-Qn3_AcF0QUL8OUq-wXy9Qj4CPz8AA_1ABQAKzkDUBD5CPv-9gPPPlP99AL-EO0DAwAHBPsI9RL5-AX89QcJ9gYiBvMM9v7-mQDzDf788QH-qAL7BQD9_FA38w7xCfgBA_oIcQz4AfsE95j-8_wJ_fwL8vz8TwT8Afz9Ovsw_v1VJ_rA9wb7C_kEAC31DfkW1DfTMOgB5PUFHwvMDt0zEMgN-xb3-R39BgbKDR7bIAr-TwXt9gMM6A_uBA7qH_MHBe0C9Q7yA64AKAcA-w3wDe8T-vUHlTQPIyj-0gE8Af4aASr2DPz7CPf53wn4AAj7BfIC-wQHa_0AhQz3gQJcJvtPT_D59vwB8vcRFNUE8xnuF7IvGQkB9wDh-S0E4_l-mgH-AWf8WW7YAMUQAuP1JhDT_voh8sYlMujqDuQNBAq-_PMYzRPlFwvsDwrvEufbN-b0DvIG9CztE9YZCuT3Bhz2VwP3_BH22fw34g4FBuYQ8usZ9PEW7EWvDusSI_jdCQTrGRX7Uv6YxOwR_AXrG-QY_ukg4RD7Dg_1fAIE-ACCAWL6COoF9TfxCRgA-hT0A-roKdsS9AMJ8nEyJPf6P-AO7_kT4uAXCN1AxSbQQM0nlmPYDPsP--LieZf7-f0CBbVgDQgL0AA__KoYMwj8y_493Oca6e4GN9XwDBz69BToGtMCFfr98rj8AwBY_f0A_Z2V6gj-wDc8-NQ-3SvHF_725yb2AP0Y1fIvAska7Az5BiHgKdn1Fdc-Eukf3BfjE-4c6wIGDOz3_RT2C2_8AAKd-e8JBvH99g8OaW0B_A78-wn4-QECDP7oE1v-agP8-wAE_r75SWX1_QMAAf4J5xX5Egn2A_wB2R4KEwIBAPgH9Vk-_f0AlwT7pBHs8ArxAQ7kEfIT-QEBAgXhCHAD_QyRB_r9Awrm_BcF9gAK8Ow6MQYA_S4AAQIA9Qf5Vf78K_sEzwzzARHxDPEC8xH1BO4m-gb5_UEbEgTk7PgwzxrxEwPbHhTTBQgQ_Q7g8iYJ2A4YzibgJscjvvxo9wr-A_T1F_D5BBPnBgAG-QCTNgsS-Qfv9g_9-A7xAfsMB98G-vNTAvta9gTxGgEgAB8n1_39QgX2BQEWBf7--ggAQuYFCu8UzfoFA_0A4BYA_GwBAfgBlgf8AQTrFPAAC_AFiwsB8_D9Bf1PqpngsQP5_gnsF98IAQ7KM_XvBNd0Pf6SAukW_AfJzVzw9AYlyyHuEdgOGdgVC-x9HA3hBAj7BMxS3Pb-Fwv29wr-9P4OJU3kCton-9kt1SgG6BiITAUM6wcd0QEOD_IDCUzi_Qj8-AM9IwYLJ9UJ8_Ub_AbdBhfq8yfo9g_uA_UDCQT-_BZN_gUd7xIV6_VP3RcL7u8d5AMBwkEUBPLuBAY-SRz-HRYCBtPZVdYVFd4cAmt93h7-5xP67gQE_vwn5gFYNAL59wv8JhAADyEBqe8OBPAH8AeOCsYw103B_QYdxiDz-BEc_OLtJcQ7Z0Nc3dZN49cs_usi_gy2-RQABw3cNM0UKw-hcQED_FcCAfsnMgEAPMtJANcpPrMABxzIEwEbFagWF_QQ6ccqLwnzBM_2NxD5zegNIhHBUOsS3SPYE84AI8X9EMsyAvEB_A_sCBHgLw4tAPz-BYb4JPEOAfMK-vj8EdYh_QP66gMGCwPy_vkL9hHIMz_8evIGBPYBBPK9_EdrAPwI9wQD_ACRDXMDAPYQA_gDAfj-9QMR_v79kQf4CPeUTP1l8AgDAwHxF-xc-wn4thbz7wIQAuQd7g7mARTnDe7vACUAO_0ANXn9AK3VbgYH_Pf1D-yrB3AAAAIAAAAB_wAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAQABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAAAAAEAAAAAAAABAAAAAAAAAAAAAAIAAAAAAAAAAAAAAQAAAAAAAAH_AQEAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAICAAAAAAEAAAAAAQABAAH_AAH_AAEAAAAAAAAAAAAAAAEAAAAAAAUAAAICAbMCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAAEAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAf8AAAAB_wAB_wH_AAH_AAAAAAAB_wH_AQD_AAABAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgABAAAAAAABAQAAAAAAAAAB_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAABAQAAAAH_AAAAAAAB_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwH_Af8B_wH_Af8AAQAA_wABAAABAAAAAQAAAAAAAP8BAAAAAAABAP8BAP8AAAEA_wEBAAAAAAAAAAABAAABAAAAAAAAAAAAAAEAAAAAAAAAAAEAAAAAAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAEAAAAAAAEAAAAAAAAAAAAAAAABAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAIAAAAAAAEAAAAAAAAAAQAAAAAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAQAAAEAAAAAAAEBAAG3AAAAAAAAAAAAAAAAAAABAAIAAAACAAAAAAH_AAAAAAAAAAAAAAAAAAAAAgEAAAAAAAD_AQAAAAAAAAAAAAAAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAAAAQAAAAAAAf8BAAD_Af8AAAABAAAA_wEAAQEAAAAAAAAAAf8AAAAAAAAB_wAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAEAAAAAAAAAAQL_Af8B_wAAAf8AAAAAAQD_AAH_AQD_Af8AAf8AAAAAAQAA_wAAAAAAAAH_AAEA_wMAAAAAAAAAAAAAAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAD_AQAAAAAAAAAAAAEAAAAAAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAQAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAQAAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAABAAAAAAEAAAAAAAAAAAA", + 3,8, + "BDcAATXFkykpnCcp1PwX-Rm1ASL320HbB_Im4ekCBx7TPwXOMvS7MOEkzAkYKK8oAdU22wo4vyLZCQPsD_YP8g3wD_ztEOh2Df5kHOH-B_33BfoF9E7HywL-RfwAcv7rH-YWAOsADPUI-AECDyH-OQPxCPvO-whO-vn5DgXyBQPuDu0pBwL-7Af2D_EADfQF-gf0Qwb61iXX-vwL8AEF_gb9_V0C-gL9oAga3RYL6PzzEez9CP0i2hkH9P3tEGQR_gP29gkA-fxBBfot_nsD_ZihQfoSiQAxBgEG5xUF6RP57RD49hn97AEeov0CAEYX8AP6_hLiE-8k1RK6QQUM8_Ep2gvoUT4U--r9-yXl-A77C_XhJQ2KyvwG7v34A_oOCPIK8AgJ6QEW69ZFAQBFEz3x5hoM-fEJ_vqNXv77Av15BvkE-3hu_UlRAOAZ8Pv7F-gf2RbfR7oB_qAr-SQB9hYDDg_b9QIg_eoA6BkJ9xjz-doPJeQB49szEvLsYCJAsgUI-vr-Dvrjp0X42BUTDs0FJM4IFAEgzQDrNsYJJ4qHuzTWLtQx4egy1-4P6yTyAeAf3EvACf79_gX4WXHtAPz9AKI68cYw3vMACxAHDAvqA9wq7fgc2CjiCwQY-8D4-_4W_B3zHPnMFvSjDP0Q_OAbBA8F8fbgFeoHJO7wAvAIDPQ9_gT-_a0F-P4FCf76BQAG_gXoDgD98wMGBowd_v4fW_0Lax_z8wb9_P4X6vr2BwebGyd3CQDxAwMO_ewEE3KmEvn69BDvABrh9R_mFeQABfr7lwYA-AT9DPAH9JL--0x6_QgG9AjyDf3-8Bb97E4B-tj9-QzxBfQT7Af4Dwfv-BTa_fsAAzn-ATMAREL7FuQM8QYPrjwX8AfUHLsr-vsBAqtNFh8CFf3X6-5F4MgcL9z-Gv7pqVbYAvlFyDS5EuOvceMS6jEQyBT9BRxVyKwL7vw0FcXmNPMZ4br48hTt2x5XqhX69_QW99D0AQAP_P7xA7QVQwX-_P4B-QmPD_jh3TcKAfAN_fIFwQ7-Gv4BH_0ARpsAJ_oBAP0FAPsBXe8LBPzhGPn-BAr4CBH4Af4EAQD5CEbsBATz0vwBAQT99gJfANgJ3QkrzDH4JKob-yb-4hAGB8YqDsAiDuwh2wT4Cdts_AH89gD9BTYrAvr8fQMA-Zz9AJ1JArUC_QT3_a-OAvmYfOjtAhAK5w7yBu4YA_7z_PenAGcBRHt67fYF6RIM5BHu9yLm-vmP8hMH7fr99BbuDAn85wsF8hj6bmxwEfbvFO8S_Qfu_foQ8f77DvaXaAJ_Hv38CPMG9RL-_vX9EOsF2AD5hPgF9g34A_gBb_4rRnX7GBwSAd4AHvkT898l4AnVLvb00v0D_yENARYB-wAJ9_A_pzPb_e4HDO8uvyz-7QsR-ywA_v5l_h2OBBLWLccZ-w_UB_QY5RsU8A8E-OYv5BDPNOPfFvb8Or34MfLvIIMC_YIAAAAAAQAAAf8AAf8AAAAB_wAAAAAB_wAAAAAAAAAAAAEA_wEA_wAAAAAAAAH_AAAAAAAAAf8AAwAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAB_wEAAAAAAAEAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAIAAAEAAP8AAf8AAQAAAAAAAAAAAAEAAAAAAAAAAAD_AAEAAAAAAAAAAAADAAAAAQAAAAAAAAAAAAABAAABAAAEArAAAAIAAAAAAAAAAAAAAAAAAAAAAQEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAQABAAAAAAAAAAAAAAEAAAAAAAAAAAABAAABAQAAAAAAAAAAAAAAAS_RAAABAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD_AQAAAAEAAAEAAAAAAAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAD_AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAACPcQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAABAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAQAA9AwBAP8AAAAAAf8AAAAAAQAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAABAAABAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAEBAAAAAAAAAOYaAAAAAAABAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAH_AAAAAAAAAAAA_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAP8B_wAAAf8BAAD_AQABAAAAAAAAAAABAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAIAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC_wEAAAAAAAABAAAAAAEAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAEAAAABAAAAAAABAAAAAQABAQAAAgCyAAAAAAAAAAAAAAAAAAABAQAAAAEAAwAAAP8BAAAAAP8BAP8AAwAAAAAAAAAAAAAAAAAAAAAAAAABAQAAAAAAAAAAAAAAAAAAAAAAAQAAAQEAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAQAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAA", + 3,82,2,34, + "_s8m-xEh0j7DMtpEygAM8CLW2hwrPIX0PhLvC_i1GwY0wff4QuLfPeTtEOkYZQj49gT8DOsK-hWsDkP9_a8JA_oVEP0D_PQGkQEAeRKF8QMI-_gJo8j6CPzrEe4OBC73Cfj61SzyBvoL9QHz8QAK_v7-A_AJ_Zoe5f74_YECAEGZE-0G_gX2_g7y9hLrFArdOAP8_ewPCuAGFv4E1zD1AQQA4gncJeIGB_r3J6luAAH4RTj-LPz8AwX-_omBDPz9GhPz6QH8DfoMC9zvFh7MCRPm8TIEzg0F-C3BHRjQNvz9CNTgz9HvBELU7e8C9wEn6BT8B9kR9wIO1Sf2AwzjABDr9RXg5e8JAAcD7w35BPT7_rED_f5KAfzC7fEG_AamKgBr-Qe-cvj8De8M-AP-_vgBAwsA_P4V-AMB_P38Cfz5XvcG-TH-0STeJfMV4hjzEM0d5yNKn_MSDNoKGOj7BQwN1ggh8-2hcAJdWCT8AwT8AfgI_P1O_kiWAFP9BpX-JvUB_gf6CekxA1YAIAD9kQACsVcDLMcNAO4HDADwDIAAZP1Y-QnoCwj-_BEB5fIJ7hH58Q_fkPET7gIL_Pj7Xf_0CPn-DPQJ9gcF_QlXMf0H8g_wAQr7BPgDyvMC-5bnAgJnaNj39Tf-8eYR9xv98fIX9uvYTHlAASUJ5BEE8vv-ARb7yEjm3QP-ATYAAfr4CATyBFAFEM0SHNvyO97s9TgB4CjK-yXi71jH3RQR7u4d-hMM6eYv4OwhOlP9_gNa_v4CPuRXCD7L-vsC1ew11Dvf9RXSHN_9Bjz-yaJgCRHpKMI33RUVzRPyEDb86xTv-Q4L5wf4BfwI8QoL5AG9-WsDAAABAP8B_wEAAAAAAAAAAP8BAAD_AAEAAAAA_wEAAAD_AAEA_wEAAAAAAAIAAAAAAAAAAAAAAQAAAAABAAAAAQAAAAAAAAEAAAAAAQAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAQAAAAAAAAAAAAAA1ykAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAEAAAEAAAAAAAABAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAABAAAAAAAAAQAAAAAAAgAAAAAAAQEA_wH_AQAAAAD_AQABAAAAAgAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAEAAAAAAAAAAAAAAAABAAABAAAAAAAAAAAAAAABAAABAAAAAAEAAAKyAQD_AQD_AAEA_wEBAAAABAAAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAAAAAAACAAAAAAH_Af8BAAAAAQEAAAAAAAAAAAAAAAEAAAAf4QAAAQACAAAAAAAAAAAAAAAAAAAAAAABAgAAAAAAAAAAAAAAAAAAAAEAAAAAAAEAAAAAAAAEAAD_AAH_AAH_AAABAP8B_wAB_wABAP8AAf8AAQAAAAD_AQD_AQEAAAAAAQD_AQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAEAAQA", + 3,11,"Xf0F-P4IJAEA-_r7BwLz_I7-dqb4-gP-BvYN8nMAAAAAAAEAAAAAAAAAAAABAAABAAAAAAAAAAA",3,128, + "m_EB-f5E7RP8BPwF8_oABNAG_vsF-NrCeAH-AxPy7SHgCRDqDwID_ivjDvzvCSH26w_6_v3wljUD_D_9_gH5AXsCO_v-9gz2_X44A_79_QLSFtPwKOT6AxHqHPTeL84NA-c1xyLh8wcIFdf-LOcp9BDT-iDXOvTAAAf-CR4HD9oNFTLzDAASaZHk-wb2Dvj2DA785f0Q_RH8DfPtCOkr-ewEAfCqBgf2dgEAAAABAAAAAAAAAAAAAAEAAAAAAPIPAAAAAQAAAAAAAAAAAQAAAAEAAAAAAAH_AAAAAAAAAgAAAAAAAAAAAAEAAQAAAAAAAAEAAAAAAAADAAAAAAAAAAAAAAD_Af8BAP8B_wH_AAAAAf8AAf8BAAAA_wH_AQD_AAAAAAEAAAAAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAAA", + 3,11, + "Bg_6_PqYAf5JAvvi9vEa_QIA5RvmAQQS6vYCG2QOQVX5-Q7xAgm4-wT5hAIB_gnmBfr6BwwA7P0F-gj6AhH38wEFAvIAW_z-9wPD-_0AB_MHVgAD9gAB-0_yAPsY3Bgh7fgQ7QXuItIl4f0FF-YH8xb9COkB4Svk7ccv_gIB8_0wMQL5Vy8D-Uf-Tv4IAv73-guKVfEWAgEA_cbwAQMA-foMAfIL9OY4_gf-_lT8Iwz89A_--vf7B4_9AgH3D_j4AQz8_n5POwAL9gMC9sxVrI7vDQTy_AkE6xik_qz0C_X6B_kJUAEBBfL-_AUR8QX90LwE9_0N-v37_Qn6AQSyAP0Ief3-AfxlcOAK7S7uEfoK7QT400r--f7588s5FxflWUv8JSX1AQkAA-39_hFWEDHiHco11R4PCOT11jHgAwEo-ev-BBr59tsh9_73APcO_gFQAgAc_jz-AqYd1yP0EfmVZfjgK91boAgL8f0k7_jpJuEh4QL9FPz8-B3pAAkI9fwH7RrjCRMAwQDK_AAE-AX-FBoF8_0CC2l0rv0DC_UI-Pz9iiqzAgP6_gYA8QP9RQv7BPME9wUACvEAw58D_m4B_PsFJgQD9fcP9A0Q2hX3-Q7sBvIBAvgAQA719BIA8voN-AQH6AMG9gYQ_h43AP02PTr-QkT0Bwr79QT7B_0E70qJAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAEAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAABAAABAAAAAAAAAAABAAAAAAAAAAAB_wEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAQAAAAABAP8AAQAAAQABALIAAAAAAAIAAwAAAAAAAAAAAAEAAQAAAAAAAAADAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAEAAAAAAAAAAAEAAgAAAAAAAAAAAAAAAwAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAwAAAAAAAAAAAAAAAAH_AAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAABAAEAAAAAAAABAAAAAAAAAQABAAAAAAAAAAAAAAEAAAAAAAAAAAABAAAAAAAAAAAAAAABAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAQAAAAAAAAAAAAAAAA", + 3,98, + "Vu4l4QUN9ucFHdwg4Qz1G9ocFdwfBt8R-CvZ9vYQBvYB_jbzB_v-9fgUAeANG-EKAAvmDwf97pQHCfwA-AnwBvkL_PLR7gEPAQDnNs_6ENcVAgYW7wuVAP1k-AL-AngBNgGLCvkHBPAFAAPuDn149wb8Bv38QQIBCnM4AQBc_AD7AZf26RbmCGq9A94H7u5E5uD-vVHcKu3l_TzNIdopD_v06ff-8gr2-hqlEPD6APsI9QfrKjYG_Yj9_FsHPPkC8foHAXRP_fj-C_IG_v3RBfQGOgP-_TtMBAH0AfwGEP796RrnCpzxCP31FPP6Ce0IBWj9ACb-JwAjFyro_vwB-wjKnvgA-P3--gP8AVT9-gJa9wzwCPr-CP5MdQDEtP1T_AfxBir4BP4D9RD5-Qf4A5j-NSP3ugjqI-MV-wX86Av6Bu0k--ztJvPqBgXIUVvC3ErfDvgQ-f73E-oEBfgP9gnxC_GQ-gAnGvjkGQID8wmFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAABAAAAAAAB_wAAAAAAAAAAAAIAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAEAAAAAAAABAAAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAD_Af8BAP8AAQAA_wEAAAAAAAD_AQD_AQIAAAAAAAAAAAEAAQAAAAAAAAABAAABAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAQAAAAAAAAABALIAAAAAAAEEAAAAAAAAAAAAAgAAAAMAAAAAAAAAAAAAAAIBAAEAAgAAAAAAAAAAAwAAAAAAAQAAAAEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQMAAAAAAAAAAAAAAAAAAgAAAAAAAAIAAAEAAAAAAAAAAA", + 3,96, + "D3S-BAD9XETL9QYE_v389kcCCQT4APUS8wQFpvyz_voB-wVjAQBDCeIN_vsS5RbnDgb5_fYECOkAHvndRA4F8BTv8R72BuEi4wr6DfUKOf7-dv05jggH_foB9Cxx_gEm_A4X7QrqF9co9QPYBAwX2P3eNgfvBgsD4yDfBfzz_CH3DshV6wIX6vsM-wbxGvn-Cer3FAXpAQj4BCDTgv0IAQIQ5ApqAf5DACr5_frzBRbsAgLxBfr9FfYGNCAB_v0l_mR13v4F_Pv6-_xE-LlhB_j9BQH7AgDhK7Tx8DTbAxnSBgAODCG8HQ7d_fz8IQUD5fwEAxjNCm34CPkB8fYB-3P--AT7gAb6Af43_hxPAgX--_3hBQD9CP78_QP-Zwr9YPf5AgH-_QQBAP0Guj_-A_pLUQ31_Ar6A_7hG_0Ogw0lzvcAAQb3FPwA-vgI_Lc3XP4DIhcRIAMk_v4xS5D7AGkD-gIC-9bLLABVrABpBg0AAvgF-uoSFQT4-ggB-JdG_gD87PMDI-Tz-wAP7PiwakH7BADzAw758AD6KtX6Evb9-Qn5eEEH9Av89wQGUf5IB_T2AgMCSxYu1fdEDAYA9AYB_pv-srwM7wb-De8IAfkCCivzBQz0CfzxDvb7Yf1DAHxbAP2O_lUR-QL-8AEHCfz6CwL5_OsEG1GT_gaqff77-A_--vkT8O8H9hnqCsAyASfy8_R19wP8-QkA9-D8-w_8BBHnDAHy8xHuD_f1FgH8BzIj_v5mBf39WwX99v4HBgHz_gb7C-p1AAEAAAAAAAEAAAAAAAAAAAEAAf8AAAH_AAEAAAEAAAAAAAAAAAIA_wH_AAH_Af8BAAAA_wAB_wABAAACAAAAGuYAAAAAAAAAAAAAAAEAAAAAAAEBAAAAAAAAAAEAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEBAAAAAAABAAEAAQAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAEAAAAAAAAAAAAAAAAB_wAAAAAAAAAAAAEAAAAB_wEAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAA4h4BAAAAAAAAAAEAAAAAsgAABQAAAAAAAwIBAAEBAAMAAAAAAAAAAAADAf8AAQD_AQABAAAEAAAAAAAAAAAAAAEAAQQAAAAAAAD_Af8B_wABAv8AAf8CAQAAAAAAAAABAAEAAAAAAAAAAAABAAEBAAAAAAAAAAABAgAAAAAAAAAAAAAAAgAAAAAAAAAAAAABAAAAAQEAAAEAAwAAAAAAAAAAAAAAAAAAAAAAAf8AAAEBAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAABAAABAAAAAAAAAAAAAAAAAA", + 3,241,"S9wRAAJp_AEH-grWBSTjAesd5hvzB-7yEAXtI98g8QML7gEsAP3hIwLnHPgERf4ChgH5AvgF9wIxAfwBIY8CAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAQAAxzkAAAEAAAAAAAAAAAAAAAAAAAA",3,85, + "uIj6_dT7_QP2DPj6Af65Gyv7ACMLFAH-e_78-wHzAhriDfQDnvb7-hDvDfz1CvoBCvgBM_1SIf4VDgX-_v4jCN4AYGC89gH4AAIBLQL9NpgBAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAEAAAEAAAAAAAAAAACyAAEAAQMAAAAAAAIAAAE", + 3,554,"w6xOOwsI_PsCAXVZ_gAI-OsEB_ET_PMa4_0QgU9bDA349RRdAQECBAAAAAAAAAAAAQQAAAAAAAAAAAAAAAABAAEEAAAAAA",3,-11, + "Ke0M9w3h_fz6Ap8A_f79KfnxC1JJaAD5LCv9Bfr6BpG2AMoI_PIOsP2L_gL3BvcK9wHz4v44AjBFAHle_Y78AYcF--sHBvH8FAUF3wYD-PQe9QjuAx35CPIAEQL--vUL9gr3X_cA-wn6-wT7Li7-P1n3AfUSAv32CfvwDwTrM_4jawABov0C_cEK-vYEC0aP_v0AAmCL_nD8MOgH8hf1KPLfDM884wkZ9PHuCfERFJVcAAVHAQD7_YwD_nAAAAAAAgAAAAAAAAAAAAIAAAABAQEAAAACAAAAAAAAAQACAAAAAAAAAgAAAAAAAAAAAAEAAAAAAAABAQABAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAD_wH_AAEAAAD_Af8BAAEAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAQAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAABAQAAAAAAAAA", + 3,38, + "XPwD-Wf9_QKJ_vtiAHL6D_cG9gb9Bvv6_fetSP4D_SqyAPT9BQH7DeMCFO_8C-8L-JwJCPkD6A73DQQA8O0IAPr4G-0HBuwJBQfgK_wuOzASAAuYAAAAAAAAAAEAAAAAAQAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAA", + 3,8, + "N3oC_S9hgAAmANAANx3-_v3LCPoADvz5_RD3_ABM-PkH_PwQ9Qb6_gb69w3RAJPU_j3w_hMu3gEA_SQy_QMA-wSIu_0AiVH-Afz9qIwCAv45RHlh_TFcALjcAfwc5PUNBPsG8Bv2AAX7AkwCUj1oCfIK-gEBBUDXAfvU_AD9AgEytf11_fwAVwfnJO4E6Rb6F_Dz5wr2DwYH--cO7hH0_A_pGvTXAf5OAIkBQQBhAQD7YQCN_Qry_gfeAfz6_QvyBAn0mQL7SQH--fzuDQzlR8YG9xD89JX5Cvj0BfcKBPMHDewJ-AcF9QQb6ewPAPEB_kr-Av5J_SwE_f77N6j-Xv4r-QCJ_oMDIQsd5vkG9AdCAAX9APsA1vz-ZJhSZVwD_ST-npf8AAL6Br9tdKw6Efv4A_j8DQby_gj0BgPz_QQD9w4eIvsE_I5-_sw0AJQDmt790fwB6P0Ac4X7-vIT_vMI8Az0E_Cz_v5RBIQhgmT8-Zf94gMI_f3--ASNRwEA_SMX2PH-D_YEAPr8lf4FBAUCBO4G_ff5GOoA8Rvo-x7mGeTHIU4C_i38ARYcFv4tJgz-BaXZAIj7IC7-Bfvo_AADUwMAAAIDAgABAAEAAgQAAAAAAQAABAAAAAAAAAAGAAAAAAAAAAAAAAAAAAACAAABAAECAAAAAQAAAAACAAAAAAAAAQAAAAIAAAAAAAIAAAABAAEBAAEAAAT_Af8BAP8BAAAA_wMAAAAAAAEAAAACAAAAAAAAAAIBAAABAAAAAAABAQAAAAAAAwD_AQAA_wEAAAAA_wH_AQAAAP8B_wH_AAH_AQABAAACAAAAAAABAAAAAAABAAAAAAABAAAAAAAAAAAAAAAAAQAAAQD_AQD_AQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAABAAAAAAAAALIAAQAEAAAFAAIAAQMEBv8B_wEFAAAAAAAAAgAAAQIBAQIAAAMAAAIAAAAAAAEAAQEFAAAAAAAAAAAAAAAAAAIAAAAAAAAAAQAAAAACAAAAAAIAAAEAAQAAAgAAAAMAAAAAAAAAAAAAAAABAAACAAAAAQAAAAEAAQAAAAAAAAAAAQAAAAAAAQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAEAAAAAAAAArwgAAAMCAAIAAQcAAAAGAAAB", + 3,1095, + "UssAidVY_AP9lT-HfrsA5QT8Af6Z_J-9N1aMyAD9-AUD9fv9A_pLTf48ggX9A_75lX_-Bff9BQDIAeQEA_kAA_f9AgD8-KOG_mGIBvIEAPcC-AH-CP1_SBEPGv7wAfYE9PkN-vr8_Qr4pPYL-_AEC_QNCe_-_R7fB9g5RP3-DygpDJpbTv6K2opWH7EBACT7cFQlAPy6kP7HX_4B7GOS_i7WzQX4AvQJAvEB-wRC_f6KjQH8_LzTfsv-WKXyB_kGZQA6VQJwAgAAAQEAAAACAAMAAQACAAAAAAAAAgEAAgEEAAAAAAACAAAAAAEAAAACAAAAAAACAQAAAAAAAAEAAgMAAAAAAAAAAAADAAEAAAEAAQAAAAAAAAAAAAABAAAAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQABAAAAAAAAsgEGAAECAivXAwAAAwAAAQUAAAAFAAIBAAADAQUAAgQEAAAAAAAAAgAAAAEAAAACAAAAAQEBAQACAwAAAAADAAECAA", + 3,196, + "UgX3-QL9CQPyAaz79_MHDOsR6gz3C_3xCQf-9ATUDSEAEhUb_v4MCyH-_QBj-YAev78AJEsB-wLCtwnvYn7-syzx49X0_v0VSACcAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAAAAALcABQEJAQAFBQAAAAICAAMCAAADAgEDBAIAAAADAA", + 3,776,"nSD-BKj8AHtg_AN_HXh2gwkD_vv7AaH7CPsC_voAB_X9Bpt9J44DAAADAAACAQAAAAADAAEBAAAAAAAC_wEAAAAAAAD_AAEAAQA",3,45,"1FmJXwD9AkfDgy0AXy8BiqP9Av1GAFYPAAYAAAAFAgAFAAIDAAACAAAAAwA",3,1124,2,816, + "fP6DmAAL_v7K_gEBAdUo7AgF_p0BAv4C_o9TEz0wAv7-pEcIzHXzHLAD_f7qE_79A57-4hOZw_yRctP-AV79DB-BJwBXlEm4AQC88AEwvhYIJFvZ_QDn_sXqDyFT4_U9vfUOoksAOdnKTug3FeuWVFJZEfAIC_b2DvP0EfAIC_b2DvP3EfAIC_b2DvP0_hwAAf59UwWTZZ1vdYZoOcWTCO8fgV8BlBJgeHMHmnLgLkeVX7lYkMClnaMaUs00JciyUV6XyRUWPSWbP78Gk2XdXYN4k13W0jtRnEXY62e117xIs0OkY-YQTL3mEjz--sNxm0kYBXuUBQEK9n5TDC5fqt9wDt9NjxoVeKE8JAtPLJ0sTLjxXHtqj3UwwRH6nEYQ_Z_oeeD0uXRfIXii9MTKBuxJ0gDFUK7N0qzOOAQKAvitHOZCJAOD_7Ta0ZZMUG6bX1dSTDObZbErAxHs-O8w6DEUAZ7HNZnWjgkUWYxOrqVB524iW0CQeOkX_uN9kG-ClX49GQifAaH_lXYB7v10A7wgCvYJVMgctm6pImde0OxBDvsSwiuiZk22fvtn974DQyTn_ydazX2GHJXr-OUu8Uxyw3kKDCXZzhqW_Gu1SWyoSsrU4RyPI2HpZbeCa1bNkI3ObYdFpwowwMogEnLKTKUR8-Gv9Vjiw9CK5e0hdXRjTaly9ED9zrpFMl20zSCTp2MFm7uxTe_YBy0AXBUcJDAkrkYA_ioTrotrW-oE1mqGj9IQGNecK5fqbCB2AaRbQdzxMoC8FUnPlfX_Hy2_h4fwJ_FZnRIDzSHTcA6o9Pv2IvGbUB5taV3DxgdTwDDrY3FWuGq8zl0FDp4vzzzO9FA8vsO_HTsntHauckwUMCKkZ5IUc446yPZyYRc1yXZhOMFstNesfypkdcFe5Yw3IL9LSba2k_nA6t07O8jHwwOV6tMc9cg71SnQYefx7DE2nO32mQZt4rYC-22yFzOqVKtLB1enWKX3MfHskYwA0vUO5C-SV3uLvrGErKxdTUu1zgnOUnSbCPrtfJaI6RE4LevESpl0RLzvIXEpVnyTT4l_M_4xzkvuQyu0AOexOWEInoiZLGhTC-7hGge1mVW9Fps3cA8k4LpWPtSD55iMZHSQEefgLAuGbazfWhFBxp5o9gjLUtVsCIltklOtuUWtTnkbBVfuUMisT0f9pyPJNUW5j6rFH4dNLNA01RbAJxhS1IAQM74NH98j-zJJgkG6_qwUj7HgyUpRuOwXmlMX8SXvC8pjsPOOfEC-BProFaBeZJvun3AF-Qb47xeEbTIo2UoIAAgk48vhuSazGULBIy2zFOkS7XBqJAj31CrPl6eF1FAz0vsx4BwTrygRESFIlwH99vfIL0SnACbQPsjBdKEjBaDamPYf05p_BpFioWrR_qGMZJo6xKj7He1O0xIHgROE7WKyAk6UnJFCssNDfDpV0P45ww7yJugsthyfQlcpfUGF2jREdWwEi4tI2Mf8HAbkLoFOv3rOQBVNKST9HwbhnJpeCGG2SLOSAxEUjkPC8Ui2KMnUAQcZbqTLN_NfArIB_QXcezIUOjHbv7fkFwvRiCaK9lx8q66ry93ILCrF0ml5AX3VAEXA2gJsgDHJgR2dqMaJAAACAAMAAAYAAAAAAwEBAwAAAgAAAAAAAAABAAAAAAC4GQwMBQEDAwAAAAYCAAAAAgAAAQDRAAwKAgAAAwECAAkBAAABAAEAAAEDAAHDCQcUCAYAAAYAAQPUFAUJCALYJAIC0gAuAQAA2Rr20Agc3ssAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANrZBbVGBfsHpr0x3uWiBfsFtkUFpVYEnO_7dgX7BfsG-gf5B3CJBHSIBfsG-gb6BvoFc4gHgHkH-QePagR0AeMdR59NVAX7BHWHB3KHB_kE_Ab6BfsF-wb6BX4sUQX7BHUATLQAAOsVhwZzAAL-MuZvB4DzAAAAAAAAACoJzTRSB3SFBncZagf5BfsHdACFB41sB4kL7d76oAaT0w8AhQZ1AIUF-waZ3IUGdQAAIGUHYDTgABniCfznngd0hQf5BXaFBHgc5REH54QH-QV4_wDzkQf5Bl-bBfsF-wZ39wgg4QABggT8BGmTBIpyBHoQcgaIAPAAIt5BvAT_AIIHV6IGeYEFjwTn36IEe4EEfIAE_Ad5gAd5AN0jAIAGegP8gQX7BrWiJA_OOGoGfPuDBqfUfwX7BPwF-wd6fwf5B_kFkGsE_AZ7fwZ8ANyiBX3dIxrmfgf5BWCbBVqhBoD0CQr2fQZiCJAGfQZ3BvoF-wV-APIPfAd9F-l8BPwHfewUAAABewX7Bn8AAHsGfgEltqAF-wT8BaW2AyMM9AB6BPwEd_sQ9YUHfwB6BIIA2iYKLMt5BfsEXg6QB4B5BPwHgHkEgzhBBoE0RQaB_uCbBvoH-QT8BrNHBvoGggZyBF0E-SGBB5rFIgAAeAX7BfsGltwKByPddwT8BoPwhwaD-n0H-QSFdwf5BYTYnwX7BIQBBP51BYV2B4N2BoV1BV0q_3UH-QeFC2kGukAE_AeFADCmKtYrCmkG-gaHAABzBIlzBW4a25gEiQD6eQSKcgX7BYlyBfsFiXIGiHIFiQByBvoG-gX7BfsHmGEEvc5xB_kGXS5vB4gAAHEF-wSL3SQGJNZwB_kFi3AEjQFuBov_cAWMANT9ngZdLAJvBmQnANKdB6TNGW8G-gWNbgeL0SwDbgVfL20FgwsAbQePagb6B_kFWh2EB4xtBo0BbAT8BPwHjRbqbAVnlAX7BfsF-wX7BFoGnAW-PQX7BKPpcAX7BfsFkAABAWkF-wT8BqdTB3IbAhZUB49qBpZkB5r17H4Ek8g4aQaQagT8BGlO3ADOMmkFYDJpBZJpBPwF-wT8B_kH-QV0hwX7BfsF-wWTAAAAAAAAANH8NABnBpMA6RcA63wHkiJFBpNnBPwG-gaTZweRAiLe5zveIUUGlABmBYsKAMyaBIwHAwEAZQT8BGyQBJcAAABlBPwGlQFkBfsG-gaI0KIF-wX7BZYB9W8GlmQFYTZkBJhkBpb_AQ_xwz0f1wrVjwb6BfsG-gd8fQT8BJhkBZj_AWMG-gZ9fQa14gAAAGMHYJkFmP8BAAEAAAAAAGIHlwu2oQX7BZkAAABiB6VUBPwF-waZAADtdAaZYQaZYQX7BfsGmQFgB_kGihAAAB7jXwWbAf9gBrH5UAf5BPwGmxDgEF8EnV8HmgD1agVhO18FnA" + ] +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.js b/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.js new file mode 100644 index 0000000..ff9d9cb --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.js @@ -0,0 +1,962 @@ +import { E_STRING } from './_utils.js' +import { asciiPrefix, decodeAscii, decodeLatin1, decodeUCS2, encodeAscii } from './latin1.js' +import { getTable } from './multi-byte.table.js' + +export const E_STRICT = 'Input is not well-formed for this encoding' + +/* Decoders */ + +// If the decoder is not cleared properly, state can be preserved between non-streaming calls! +// See comment about fatal stream + +// All except iso-2022-jp are ASCII supersets +// When adding something that is not an ASCII superset, ajust the ASCII fast path +const mappers = { + // https://encoding.spec.whatwg.org/#euc-kr-decoder + 'euc-kr': (err) => { + const euc = getTable('euc-kr') + let lead = 0 + let oi = 0 + let o16 + + const decodeLead = (b) => { + if (b < 0x41 || b > 0xfe) { + lead = 0 + o16[oi++] = err() + if (b < 128) o16[oi++] = b + } else { + const p = euc[(lead - 0x81) * 190 + b - 0x41] + lead = 0 + if (p) { + o16[oi++] = p + } else { + o16[oi++] = err() + if (b < 128) o16[oi++] = b + } + } + } + + const decode = (arr, start, end, stream) => { + let i = start + o16 = new Uint16Array(end - start + (lead ? 1 : 0)) // there are pairs but they consume more than one byte + oi = 0 + + // Fast path + if (!lead) { + for (const last1 = end - 1; i < last1; ) { + const l = arr[i] + if (l < 128) { + o16[oi++] = l + i++ + } else { + if (l === 0x80 || l === 0xff) break + const b = arr[i + 1] + if (b < 0x41 || b === 0xff) break + const p = euc[(l - 0x81) * 190 + b - 0x41] + if (!p) break + o16[oi++] = p + i += 2 + } + } + } + + if (lead && i < end) decodeLead(arr[i++]) + while (i < end) { + const b = arr[i++] + if (b < 128) { + o16[oi++] = b + } else if (b === 0x80 || b === 0xff) { + o16[oi++] = err() + } else { + lead = b + if (i < end) decodeLead(arr[i++]) + } + } + + if (lead && !stream) { + lead = 0 + o16[oi++] = err() + } + + const res = decodeUCS2(o16, oi) + o16 = null + return res + } + + return { decode, isAscii: () => lead === 0 } + }, + // https://encoding.spec.whatwg.org/#euc-jp-decoder + 'euc-jp': (err) => { + const jis0208 = getTable('jis0208') + const jis0212 = getTable('jis0212') + let j12 = false + let lead = 0 + let oi = 0 + let o16 + + const decodeLead = (b) => { + if (lead === 0x8e && b >= 0xa1 && b <= 0xdf) { + lead = 0 + o16[oi++] = 0xfe_c0 + b + } else if (lead === 0x8f && b >= 0xa1 && b <= 0xfe) { + j12 = true + lead = b + } else { + let cp + if (lead >= 0xa1 && lead <= 0xfe && b >= 0xa1 && b <= 0xfe) { + cp = (j12 ? jis0212 : jis0208)[(lead - 0xa1) * 94 + b - 0xa1] + } + + lead = 0 + j12 = false + if (cp) { + o16[oi++] = cp + } else { + o16[oi++] = err() + if (b < 128) o16[oi++] = b + } + } + } + + const decode = (arr, start, end, stream) => { + let i = start + o16 = new Uint16Array(end - start + (lead ? 1 : 0)) + oi = 0 + + // Fast path, non-j12 + // lead = 0 means j12 = 0 + if (!lead) { + for (const last1 = end - 1; i < last1; ) { + const l = arr[i] + if (l < 128) { + o16[oi++] = l + i++ + } else { + const b = arr[i + 1] + if (l === 0x8e && b >= 0xa1 && b <= 0xdf) { + o16[oi++] = 0xfe_c0 + b + i += 2 + } else { + if (l < 0xa1 || l === 0xff || b < 0xa1 || b === 0xff) break + const cp = jis0208[(l - 0xa1) * 94 + b - 0xa1] + if (!cp) break + o16[oi++] = cp + i += 2 + } + } + } + } + + if (lead && i < end) decodeLead(arr[i++]) + if (lead && i < end) decodeLead(arr[i++]) // could be two leads, but no more + while (i < end) { + const b = arr[i++] + if (b < 128) { + o16[oi++] = b + } else if ((b < 0xa1 && b !== 0x8e && b !== 0x8f) || b === 0xff) { + o16[oi++] = err() + } else { + lead = b + if (i < end) decodeLead(arr[i++]) + if (lead && i < end) decodeLead(arr[i++]) // could be two leads + } + } + + if (lead && !stream) { + lead = 0 + j12 = false // can be true only when lead is non-zero + o16[oi++] = err() + } + + const res = decodeUCS2(o16, oi) + o16 = null + return res + } + + return { decode, isAscii: () => lead === 0 } // j12 can be true only when lead is non-zero + }, + // https://encoding.spec.whatwg.org/#iso-2022-jp-decoder + 'iso-2022-jp': (err) => { + const jis0208 = getTable('jis0208') + let dState = 1 + let oState = 1 + let lead = 0 // 0 or 0x21-0x7e + let out = false + + const bytes = (pushback, b) => { + if (dState < 5 && b === 0x1b) { + dState = 6 // escape start + return + } + + switch (dState) { + case 1: + case 2: + // ASCII, Roman (common) + out = false + if (dState === 2) { + if (b === 0x5c) return 0xa5 + if (b === 0x7e) return 0x20_3e + } + + if (b <= 0x7f && b !== 0x0e && b !== 0x0f) return b + return err() + case 3: + // Katakana + out = false + if (b >= 0x21 && b <= 0x5f) return 0xff_40 + b + return err() + case 4: + // Leading byte + out = false + if (b < 0x21 || b > 0x7e) return err() + lead = b + dState = 5 + return + case 5: + // Trailing byte + out = false + if (b === 0x1b) { + dState = 6 // escape start + return err() + } + + dState = 4 + if (b >= 0x21 && b <= 0x7e) { + const cp = jis0208[(lead - 0x21) * 94 + b - 0x21] + if (cp) return cp + } + + return err() + case 6: + // Escape start + if (b === 0x24 || b === 0x28) { + lead = b + dState = 7 + return + } + + out = false + dState = oState + pushback.push(b) + return err() + case 7: { + // Escape + const l = lead + lead = 0 + let s + if (l === 0x28) { + // eslint-disable-next-line unicorn/prefer-switch + if (b === 0x42) { + s = 1 + } else if (b === 0x4a) { + s = 2 + } else if (b === 0x49) { + s = 3 + } + } else if (l === 0x24 && (b === 0x40 || b === 0x42)) { + s = 4 + } + + if (s) { + dState = oState = s + const output = out + out = true + return output ? err() : undefined + } + + out = false + dState = oState + pushback.push(b, l) + return err() + } + } + } + + const eof = (pushback) => { + if (dState < 5) return null + out = false + switch (dState) { + case 5: + dState = 4 + return err() + case 6: + dState = oState + return err() + case 7: { + dState = oState + pushback.push(lead) + lead = 0 + return err() + } + } + } + + const decode = (arr, start, end, stream) => { + const o16 = new Uint16Array(end - start + 2) // err in eof + lead from state + let oi = 0 + let i = start + const pushback = [] // local and auto-cleared + + // First, dump everything until EOF + // Same as the full loop, but without EOF handling + while (i < end || pushback.length > 0) { + const c = bytes(pushback, pushback.length > 0 ? pushback.pop() : arr[i++]) + if (c !== undefined) o16[oi++] = c // 16-bit + } + + // Then, dump EOF. This needs the same loop as the characters can be pushed back + if (!stream) { + while (i <= end || pushback.length > 0) { + if (i < end || pushback.length > 0) { + const c = bytes(pushback, pushback.length > 0 ? pushback.pop() : arr[i++]) + if (c !== undefined) o16[oi++] = c // 16-bit + } else { + const c = eof(pushback) + if (c === null) break // clean exit + o16[oi++] = c + } + } + } + + // Chrome and WebKit fail on this, we don't: completely destroy the old decoder state when finished streaming + // > If this’s do not flush is false, then set this’s decoder to a new instance of this’s encoding’s decoder, + // > Set this’s do not flush to options["stream"] + if (!stream) { + dState = oState = 1 + lead = 0 + out = false + } + + return decodeUCS2(o16, oi) + } + + return { decode, isAscii: () => false } + }, + // https://encoding.spec.whatwg.org/#shift_jis-decoder + shift_jis: (err) => { + const jis0208 = getTable('jis0208') + let lead = 0 + let oi = 0 + let o16 + + const decodeLead = (b) => { + const l = lead + lead = 0 + if (b >= 0x40 && b <= 0xfc && b !== 0x7f) { + const p = (l - (l < 0xa0 ? 0x81 : 0xc1)) * 188 + b - (b < 0x7f ? 0x40 : 0x41) + if (p >= 8836 && p <= 10_715) { + o16[oi++] = 0xe0_00 - 8836 + p + return + } + + const cp = jis0208[p] + if (cp) { + o16[oi++] = cp + return + } + } + + o16[oi++] = err() + if (b < 128) o16[oi++] = b + } + + const decode = (arr, start, end, stream) => { + o16 = new Uint16Array(end - start + (lead ? 1 : 0)) + oi = 0 + let i = start + + // Fast path + if (!lead) { + for (const last1 = end - 1; i < last1; ) { + const l = arr[i] + if (l <= 0x80) { + o16[oi++] = l + i++ + } else if (l >= 0xa1 && l <= 0xdf) { + o16[oi++] = 0xfe_c0 + l + i++ + } else { + if (l === 0xa0 || l > 0xfc) break + const b = arr[i + 1] + if (b < 0x40 || b > 0xfc || b === 0x7f) break + const p = (l - (l < 0xa0 ? 0x81 : 0xc1)) * 188 + b - (b < 0x7f ? 0x40 : 0x41) + if (p >= 8836 && p <= 10_715) { + o16[oi++] = 0xe0_00 - 8836 + p + i += 2 + } else { + const cp = jis0208[p] + if (!cp) break + o16[oi++] = cp + i += 2 + } + } + } + } + + if (lead && i < end) decodeLead(arr[i++]) + while (i < end) { + const b = arr[i++] + if (b <= 0x80) { + o16[oi++] = b // 0x80 is allowed + } else if (b >= 0xa1 && b <= 0xdf) { + o16[oi++] = 0xfe_c0 + b + } else if (b === 0xa0 || b > 0xfc) { + o16[oi++] = err() + } else { + lead = b + if (i < end) decodeLead(arr[i++]) + } + } + + if (lead && !stream) { + lead = 0 + o16[oi++] = err() + } + + const res = decodeUCS2(o16, oi) + o16 = null + return res + } + + return { decode, isAscii: () => lead === 0 } + }, + // https://encoding.spec.whatwg.org/#gbk-decoder + gbk: (err) => mappers.gb18030(err), // 10.1.1. GBK’s decoder is gb18030’s decoder + // https://encoding.spec.whatwg.org/#gb18030-decoder + gb18030: (err) => { + const gb18030 = getTable('gb18030') + const gb18030r = getTable('gb18030-ranges') + let g1 = 0, g2 = 0, g3 = 0 // prettier-ignore + const index = (p) => { + if ((p > 39_419 && p < 189_000) || p > 1_237_575) return + if (p === 7457) return 0xe7_c7 + let a = 0, b = 0 // prettier-ignore + for (const [c, d] of gb18030r) { + if (c > p) break + a = c + b = d + } + + return b + p - a + } + + // g1 is 0 or 0x81-0xfe + // g2 is 0 or 0x30-0x39 + // g3 is 0 or 0x81-0xfe + + const decode = (arr, start, end, stream) => { + const o16 = new Uint16Array(end - start + (g1 ? 3 : 0)) // even with pushback it's at most 1 char per byte + let oi = 0 + let i = start + const pushback = [] // local and auto-cleared + + // Fast path for 2-byte only + // pushback is always empty ad start, and g1 = 0 means g2 = g3 = 0 + if (g1 === 0) { + for (const last1 = end - 1; i < last1; ) { + const b = arr[i] + if (b < 128) { + o16[oi++] = b + i++ + } else if (b === 0x80) { + o16[oi++] = 0x20_ac + i++ + } else { + if (b === 0xff) break + const n = arr[i + 1] + let cp + if (n < 0x7f) { + if (n < 0x40) break + cp = gb18030[(b - 0x81) * 190 + n - 0x40] + } else { + if (n === 0xff || n === 0x7f) break + cp = gb18030[(b - 0x81) * 190 + n - 0x41] + } + + if (!cp) break + o16[oi++] = cp // 16-bit + i += 2 + } + } + } + + // First, dump everything until EOF + // Same as the full loop, but without EOF handling + while (i < end || pushback.length > 0) { + const b = pushback.length > 0 ? pushback.pop() : arr[i++] + if (g1) { + // g2 can be set only when g1 is set, g3 can be set only when g2 is set + // hence, 3 checks for g3 is faster than 3 checks for g1 + if (g2) { + if (g3) { + if (b <= 0x39 && b >= 0x30) { + const p = index( + (g1 - 0x81) * 12_600 + (g2 - 0x30) * 1260 + (g3 - 0x81) * 10 + b - 0x30 + ) + g1 = g2 = g3 = 0 + if (p === undefined) { + o16[oi++] = err() + } else if (p <= 0xff_ff) { + o16[oi++] = p // Can validly return replacement + } else { + const d = p - 0x1_00_00 + o16[oi++] = 0xd8_00 | (d >> 10) + o16[oi++] = 0xdc_00 | (d & 0x3_ff) + } + } else { + pushback.push(b, g3, g2) + g1 = g2 = g3 = 0 + o16[oi++] = err() + } + } else if (b >= 0x81 && b <= 0xfe) { + g3 = b + } else { + pushback.push(b, g2) + g1 = g2 = 0 + o16[oi++] = err() + } + } else if (b <= 0x39 && b >= 0x30) { + g2 = b + } else { + let cp + if (b >= 0x40 && b <= 0xfe && b !== 0x7f) { + cp = gb18030[(g1 - 0x81) * 190 + b - (b < 0x7f ? 0x40 : 0x41)] + } + + g1 = 0 + if (cp) { + o16[oi++] = cp // 16-bit + } else { + o16[oi++] = err() + if (b < 128) o16[oi++] = b // can be processed immediately + } + } + } else if (b < 128) { + o16[oi++] = b + } else if (b === 0x80) { + o16[oi++] = 0x20_ac + } else if (b === 0xff) { + o16[oi++] = err() + } else { + g1 = b + } + } + + // if g1 = 0 then g2 = g3 = 0 + if (g1 && !stream) { + g1 = g2 = g3 = 0 + o16[oi++] = err() + } + + return decodeUCS2(o16, oi) + } + + return { decode, isAscii: () => g1 === 0 } // if g1 = 0 then g2 = g3 = 0 + }, + // https://encoding.spec.whatwg.org/#big5 + big5: (err) => { + // The only decoder which returns multiple codepoints per byte, also has non-charcode codepoints + // We store that as strings + const big5 = getTable('big5') + let lead = 0 + let oi = 0 + let o16 + + const decodeLead = (b) => { + if (b < 0x40 || (b > 0x7e && b < 0xa1) || b === 0xff) { + lead = 0 + o16[oi++] = err() + if (b < 128) o16[oi++] = b + } else { + const p = big5[(lead - 0x81) * 157 + b - (b < 0x7f ? 0x40 : 0x62)] + lead = 0 + if (p > 0x1_00_00) { + o16[oi++] = p >> 16 + o16[oi++] = p & 0xff_ff + } else if (p) { + o16[oi++] = p + } else { + o16[oi++] = err() + if (b < 128) o16[oi++] = b + } + } + } + + // eslint-disable-next-line sonarjs/no-identical-functions + const decode = (arr, start, end, stream) => { + let i = start + o16 = new Uint16Array(end - start + (lead ? 1 : 0)) // there are pairs but they consume more than one byte + oi = 0 + + // Fast path + if (!lead) { + for (const last1 = end - 1; i < last1; ) { + const l = arr[i] + if (l < 128) { + o16[oi++] = l + i++ + } else { + if (l === 0x80 || l === 0xff) break + const b = arr[i + 1] + if (b < 0x40 || (b > 0x7e && b < 0xa1) || b === 0xff) break + const p = big5[(l - 0x81) * 157 + b - (b < 0x7f ? 0x40 : 0x62)] + if (p > 0x1_00_00) { + o16[oi++] = p >> 16 + o16[oi++] = p & 0xff_ff + } else { + if (!p) break + o16[oi++] = p + } + + i += 2 + } + } + } + + if (lead && i < end) decodeLead(arr[i++]) + while (i < end) { + const b = arr[i++] + if (b < 128) { + o16[oi++] = b + } else if (b === 0x80 || b === 0xff) { + o16[oi++] = err() + } else { + lead = b + if (i < end) decodeLead(arr[i++]) + } + } + + if (lead && !stream) { + lead = 0 + o16[oi++] = err() + } + + const res = decodeUCS2(o16, oi) + o16 = null + return res + } + + return { decode, isAscii: () => lead === 0 } + }, +} + +export const isAsciiSuperset = (enc) => enc !== 'iso-2022-jp' // all others are ASCII supersets and can use fast path + +export function multibyteDecoder(enc, loose = false) { + if (typeof loose !== 'boolean') throw new TypeError('loose option should be boolean') + if (!Object.hasOwn(mappers, enc)) throw new RangeError('Unsupported encoding') + + // Input is assumed to be typechecked already + let mapper + const asciiSuperset = isAsciiSuperset(enc) + let streaming // because onErr is cached in mapper + const onErr = loose + ? () => 0xff_fd + : () => { + // The correct way per spec seems to be not destoying the decoder state in stream mode, even when fatal + // Decoders big5, euc-jp, euc-kr, shift_jis, gb18030 / gbk - all clear state before throwing unless EOF, so not affected + // iso-2022-jp is the only tricky one one where this !stream check matters in non-stream mode + if (!streaming) mapper = null // destroy state, effectively the same as 'do not flush' = false, but early + throw new TypeError(E_STRICT) + } + + return (arr, stream = false) => { + let res = '' + if (asciiSuperset && (!mapper || mapper.isAscii?.())) { + const prefixLen = asciiPrefix(arr) + if (prefixLen === arr.length) return decodeAscii(arr) // ascii + res = decodeLatin1(arr, 0, prefixLen) // TODO: check if decodeAscii with subarray is faster for small prefixes too + } + + streaming = stream // affects onErr + if (!mapper) mapper = mappers[enc](onErr) + return res + mapper.decode(arr, res.length, arr.length, stream) + } +} + +/* Encoders */ + +const maps = new Map() +const e7 = [[148, 236], [149, 237], [150, 243]] // prettier-ignore +const e8 = [[30, 89], [38, 97], [43, 102], [44, 103], [50, 109], [67, 126], [84, 144], [100, 160]] // prettier-ignore +const preencoders = { + __proto__: null, + big5: (p) => ((((p / 157) | 0) + 0x81) << 8) | ((p % 157 < 0x3f ? 0x40 : 0x62) + (p % 157)), + shift_jis: (p) => { + const l = (p / 188) | 0 + const t = p % 188 + return ((l + (l < 0x1f ? 0x81 : 0xc1)) << 8) | ((t < 0x3f ? 0x40 : 0x41) + t) + }, + 'iso-2022-jp': (p) => ((((p / 94) | 0) + 0x21) << 8) | ((p % 94) + 0x21), + 'euc-jp': (p) => ((((p / 94) | 0) + 0xa1) << 8) | ((p % 94) + 0xa1), + 'euc-kr': (p) => ((((p / 190) | 0) + 0x81) << 8) | ((p % 190) + 0x41), + gb18030: (p) => ((((p / 190) | 0) + 0x81) << 8) | ((p % 190 < 0x3f ? 0x40 : 0x41) + (p % 190)), +} + +preencoders.gbk = preencoders.gb18030 + +// We accept that encoders use non-trivial amount of mem, for perf +// most are are 128 KiB mem, big5 is 380 KiB, lazy-loaded at first use +function getMap(id, size, ascii) { + const cached = maps.get(id) + if (cached) return cached + let tname = id + const sjis = id === 'shift_jis' + const iso2022jp = id === 'iso-2022-jp' + if (iso2022jp) tname = 'jis0208' + if (id === 'gbk') tname = 'gb18030' + if (id === 'euc-jp' || sjis) tname = 'jis0208' + const table = getTable(tname) + const map = new Uint16Array(size) + const enc = preencoders[id] || ((p) => p + 1) + for (let i = 0; i < table.length; i++) { + const c = table[i] + if (!c) continue + if (id === 'big5') { + if (i < 5024) continue // this also skips multi-codepoint strings + // In big5, all return first entries except for these + if ( + map[c] && + c !== 0x25_50 && + c !== 0x25_5e && + c !== 0x25_61 && + c !== 0x25_6a && + c !== 0x53_41 && + c !== 0x53_45 + ) { + continue + } + } else { + if (sjis && i >= 8272 && i <= 8835) continue + if (map[c]) continue + } + + if (c > 0xff_ff) { + // always a single codepoint here + const s = String.fromCharCode(c >> 16, c & 0xff_ff) + map[s.codePointAt(0)] = enc(i) + } else { + map[c] = enc(i) + } + } + + if (ascii) for (let i = 0; i < 0x80; i++) map[i] = i + if (sjis || id === 'euc-jp') { + if (sjis) map[0x80] = 0x80 + const d = sjis ? 0xfe_c0 : 0x70_c0 + for (let i = 0xff_61; i <= 0xff_9f; i++) map[i] = i - d + map[0x22_12] = map[0xff_0d] + map[0xa5] = 0x5c + map[0x20_3e] = 0x7e + } else if (tname === 'gb18030') { + if (id === 'gbk') map[0x20_ac] = 0x80 + for (let i = 0xe7_8d; i <= 0xe7_93; i++) map[i] = i - 0x40_b4 + for (const [a, b] of e7) map[0xe7_00 | a] = 0xa6_00 | b + for (const [a, b] of e8) map[0xe8_00 | a] = 0xfe_00 | b + } + + maps.set(id, map) + return map +} + +const NON_LATIN = /[^\x00-\xFF]/ // eslint-disable-line no-control-regex +let gb18030r, katakana + +export function multibyteEncoder(enc, onError) { + if (!Object.hasOwn(mappers, enc)) throw new RangeError('Unsupported encoding') + const size = enc === 'big5' ? 0x2_f8_a7 : 0x1_00_00 // for big5, max codepoint in table + 1 + const iso2022jp = enc === 'iso-2022-jp' + const gb18030 = enc === 'gb18030' + const ascii = isAsciiSuperset(enc) + const width = iso2022jp ? 5 : gb18030 ? 4 : 2 + const tailsize = iso2022jp ? 3 : 0 + const map = getMap(enc, size, ascii) + if (gb18030 && !gb18030r) gb18030r = getTable('gb18030-ranges') + if (iso2022jp && !katakana) katakana = getTable('iso-2022-jp-katakana') + return (str) => { + if (typeof str !== 'string') throw new TypeError(E_STRING) + if (ascii && !NON_LATIN.test(str)) { + try { + return encodeAscii(str, E_STRICT) + } catch {} + } + + const length = str.length + const u8 = new Uint8Array(length * width + tailsize) + let i = 0 + + if (ascii) { + while (i < length) { + const x = str.charCodeAt(i) + if (x >= 128) break + u8[i++] = x + } + } + + // eslint-disable-next-line unicorn/consistent-function-scoping + const err = (code) => { + if (onError) return onError(code, u8, i) + throw new TypeError(E_STRICT) + } + + if (!map || map.length < size) /* c8 ignore next */ throw new Error('Unreachable') // Important for perf + + if (iso2022jp) { + let state = 0 // 0 = ASCII, 1 = Roman, 2 = jis0208 + const restore = () => { + state = 0 + u8[i++] = 0x1b + u8[i++] = 0x28 + u8[i++] = 0x42 + } + + for (let j = 0; j < length; j++) { + let x = str.charCodeAt(j) + if (x >= 0xd8_00 && x < 0xe0_00) { + if (state === 2) restore() + if (x >= 0xdc_00 || j + 1 === length) { + i += err(x) // lone + } else { + const x1 = str.charCodeAt(j + 1) + if (x1 < 0xdc_00 || x1 >= 0xe0_00) { + i += err(x) // lone + } else { + j++ // consume x1 + i += err(0x1_00_00 + ((x1 & 0x3_ff) | ((x & 0x3_ff) << 10))) + } + } + } else if (x < 0x80) { + if (state === 2 || (state === 1 && (x === 0x5c || x === 0x7e))) restore() + if (x === 0xe || x === 0xf || x === 0x1b) { + i += err(0xff_fd) // 12.2.2. step 3: This returns U+FFFD rather than codePoint to prevent attacks + } else { + u8[i++] = x + } + } else if (x === 0xa5 || x === 0x20_3e) { + if (state !== 1) { + state = 1 + u8[i++] = 0x1b + u8[i++] = 0x28 + u8[i++] = 0x4a + } + + u8[i++] = x === 0xa5 ? 0x5c : 0x7e + } else { + if (x === 0x22_12) x = 0xff_0d + if (x >= 0xff_61 && x <= 0xff_9f) x = katakana[x - 0xff_61] + const e = map[x] + if (e) { + if (state !== 2) { + state = 2 + u8[i++] = 0x1b + u8[i++] = 0x24 + u8[i++] = 0x42 + } + + u8[i++] = e >> 8 + u8[i++] = e & 0xff + } else { + if (state === 2) restore() + i += err(x) + } + } + } + + if (state) restore() + } else if (gb18030) { + // Deduping this branch hurts other encoders perf + const encode = (cp) => { + let a = 0, b = 0 // prettier-ignore + for (const [c, d] of gb18030r) { + if (d > cp) break + a = c + b = d + } + + let rp = cp === 0xe7_c7 ? 7457 : a + cp - b + u8[i++] = 0x81 + ((rp / 12_600) | 0) + rp %= 12_600 + u8[i++] = 0x30 + ((rp / 1260) | 0) + rp %= 1260 + u8[i++] = 0x81 + ((rp / 10) | 0) + u8[i++] = 0x30 + (rp % 10) + } + + for (let j = i; j < length; j++) { + const x = str.charCodeAt(j) + if (x >= 0xd8_00 && x < 0xe0_00) { + if (x >= 0xdc_00 || j + 1 === length) { + i += err(x) // lone + } else { + const x1 = str.charCodeAt(j + 1) + if (x1 < 0xdc_00 || x1 >= 0xe0_00) { + i += err(x) // lone + } else { + j++ // consume x1 + encode(0x1_00_00 + ((x1 & 0x3_ff) | ((x & 0x3_ff) << 10))) + } + } + } else { + const e = map[x] + if (e & 0xff_00) { + u8[i++] = e >> 8 + u8[i++] = e & 0xff + } else if (e || x === 0) { + u8[i++] = e + } else if (x === 0xe5_e5) { + i += err(x) + } else { + encode(x) + } + } + } + } else { + const long = + enc === 'big5' + ? (x) => { + const e = map[x] + if (e & 0xff_00) { + u8[i++] = e >> 8 + u8[i++] = e & 0xff + } else if (e || x === 0) { + u8[i++] = e + } else { + i += err(x) + } + } + : (x) => { + i += err(x) + } + + for (let j = i; j < length; j++) { + const x = str.charCodeAt(j) + if (x >= 0xd8_00 && x < 0xe0_00) { + if (x >= 0xdc_00 || j + 1 === length) { + i += err(x) // lone + } else { + const x1 = str.charCodeAt(j + 1) + if (x1 < 0xdc_00 || x1 >= 0xe0_00) { + i += err(x) // lone + } else { + j++ // consume x1 + long(0x1_00_00 + ((x1 & 0x3_ff) | ((x & 0x3_ff) << 10))) + } + } + } else { + const e = map[x] + if (e & 0xff_00) { + u8[i++] = e >> 8 + u8[i++] = e & 0xff + } else if (e || x === 0) { + u8[i++] = e + } else { + i += err(x) + } + } + } + } + + return i === u8.length ? u8 : u8.subarray(0, i) + } +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.table.js b/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.table.js new file mode 100644 index 0000000..c7dfeb2 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/multi-byte.table.js @@ -0,0 +1,118 @@ +import { fromBase64url } from '@exodus/bytes/base64.js' +import { utf16toString } from '@exodus/bytes/utf16.js' +import loadEncodings from './multi-byte.encodings.cjs' + +export const sizes = { + jis0208: 11_104, + jis0212: 7211, + 'euc-kr': 23_750, + gb18030: 23_940, + big5: 19_782, +} + +// This is huge. It's _much_ smaller than https://npmjs.com/text-encoding though +// Exactly as mapped by the index table +// 0,x - hole of x empty elements +// n,c - continious [c, ...] of length n +// $.. - references to common chunks +// -{x} - same as 1,{x} + +// See tests/multi-byte.test.js to verify that this data decodes exactly into the encoding spec tables + +let indices +const tables = new Map() +/* eslint-disable @exodus/mutable/no-param-reassign-prop-only */ + +function loadBase64(str) { + const x = fromBase64url(str) + const len = x.length + const len2 = len >> 1 + const y = new Uint8Array(len) + let a = -1, b = 0 // prettier-ignore + for (let i = 0, j = 0; i < len; i += 2, j++) { + a = (a + x[j] + 1) & 0xff + b = (b + x[len2 + j]) & 0xff + y[i] = a + y[i + 1] = b + } + + return y +} + +function unwrap(res, t, pos) { + let code = 0 + for (let i = 0; i < t.length; i++) { + let x = t[i] + if (typeof x === 'number') { + if (x === 0) { + pos += t[++i] + } else { + if (x < 0) { + code -= x + x = 1 + } else { + code += t[++i] + } + + for (let k = 0; k < x; k++, pos++, code++) { + if (code <= 0xff_ff) { + res[pos] = code + } else { + const c = String.fromCodePoint(code) + res[pos] = (c.charCodeAt(0) << 16) | c.charCodeAt(1) + } + } + } + } else if (x[0] === '$' && Object.hasOwn(indices, x)) { + pos = unwrap(res, indices[x], pos) // self-reference using shared chunks + } else { + let last + // splits by codepoints + for (const c of utf16toString(loadBase64(x), 'uint8-le')) { + last = c + res[pos++] = c.length === 1 ? c.charCodeAt(0) : (c.charCodeAt(0) << 16) | c.charCodeAt(1) + } + + code = last.codePointAt(0) + 1 + } + } + + return pos +} + +export function getTable(id) { + const cached = tables.get(id) + if (cached) return cached + + if (!indices) indices = loadEncodings() // lazy-load + if (!Object.hasOwn(indices, id)) throw new Error('Unknown encoding') + if (!indices[id]) throw new Error('Table already used (likely incorrect bundler dedupe)') + + let res + if (id.endsWith('-ranges')) { + res = [] + let a = 0, b = 0 // prettier-ignore + const idx = indices[id] + while (idx.length > 0) res.push([(a += idx.shift()), (b += idx.shift())]) // destroying, we remove it later anyway + } else if (id.endsWith('-katakana')) { + let a = -1 + res = new Uint16Array(indices[id].map((x) => (a += x + 1))) + } else if (id === 'big5') { + res = new Uint32Array(sizes[id]) // single or double charcodes + unwrap(res, indices[id], 0) + // Pointer code updates are embedded into the table + // These are skipped in encoder as encoder uses only pointers >= (0xA1 - 0x81) * 157 + res[1133] = 0xca_03_04 + res[1135] = 0xca_03_0c + res[1164] = 0xea_03_04 + res[1166] = 0xea_03_0c + } else { + if (!Object.hasOwn(sizes, id)) throw new Error('Unknown encoding') + res = new Uint16Array(sizes[id]) + unwrap(res, indices[id], 0) + } + + indices[id] = null // gc + tables.set(id, res) + return res +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/percent.js b/vanilla/node_modules/@exodus/bytes/fallback/percent.js new file mode 100644 index 0000000..c024d90 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/percent.js @@ -0,0 +1,31 @@ +import { decodeAscii, encodeLatin1 } from './latin1.js' +import { decode2string } from './platform.js' + +const ERR = 'percentEncodeSet must be a string of unique increasing codepoints in range 0x20 - 0x7e' +const percentMap = new Map() +let hex, base + +export function percentEncoder(set, spaceAsPlus = false) { + if (typeof set !== 'string' || /[^\x20-\x7E]/.test(set)) throw new TypeError(ERR) + if (typeof spaceAsPlus !== 'boolean') throw new TypeError('spaceAsPlus must be boolean') + const id = set + +spaceAsPlus + const cached = percentMap.get(id) + if (cached) return cached + + const n = encodeLatin1(set).sort() // string checked above to be ascii + if (decodeAscii(n) !== set || new Set(n).size !== n.length) throw new TypeError(ERR) + + if (!base) { + hex = Array.from({ length: 256 }, (_, i) => `%${i.toString(16).padStart(2, '0').toUpperCase()}`) + base = hex.map((h, i) => (i < 0x20 || i > 0x7e ? h : String.fromCharCode(i))) + } + + const map = base.slice() // copy + for (const c of n) map[c] = hex[c] + if (spaceAsPlus) map[0x20] = '+' // overrides whatever percentEncodeSet thinks about it + + // Input is not typechecked, for internal use only + const percentEncode = (u8, start = 0, end = u8.length) => decode2string(u8, start, end, map) + percentMap.set(id, percentEncode) + return percentEncode +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/platform.browser.js b/vanilla/node_modules/@exodus/bytes/fallback/platform.browser.js new file mode 100644 index 0000000..7131a73 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/platform.browser.js @@ -0,0 +1,31 @@ +import { decodePartAddition as decodePart } from './platform.native.js' + +export { isLE, encodeCharcodesPure as encodeCharcodes } from './platform.native.js' + +export const nativeBuffer = null +export const isHermes = false +export const isDeno = false +export const nativeEncoder = /* @__PURE__ */ (() => new TextEncoder())() +export const nativeDecoder = /* @__PURE__ */ (() => new TextDecoder('utf-8', { ignoreBOM: true }))() +export const nativeDecoderLatin1 = /* @__PURE__ */ (() => + new TextDecoder('latin1', { ignoreBOM: true }))() + +export function decode2string(arr, start, end, m) { + if (end - start > 30_000) { + // Limit concatenation to avoid excessive GC + // Thresholds checked on Hermes for toHex + const concat = [] + for (let i = start; i < end; ) { + const step = i + 500 + const iNext = step > end ? end : step + concat.push(decodePart(arr, i, iNext, m)) + i = iNext + } + + const res = concat.join('') + concat.length = 0 + return res + } + + return decodePart(arr, start, end, m) +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/platform.js b/vanilla/node_modules/@exodus/bytes/fallback/platform.js new file mode 100644 index 0000000..f4dbf75 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/platform.js @@ -0,0 +1,2 @@ +// platform.native actually hosts Node.js / Deno detection too +export * from './platform.native.js' diff --git a/vanilla/node_modules/@exodus/bytes/fallback/platform.native.js b/vanilla/node_modules/@exodus/bytes/fallback/platform.native.js new file mode 100644 index 0000000..4f3ae44 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/platform.native.js @@ -0,0 +1,122 @@ +const { Buffer } = globalThis +const haveNativeBuffer = Buffer && !Buffer.TYPED_ARRAY_SUPPORT +export const nativeBuffer = haveNativeBuffer ? Buffer : null +export const isHermes = /* @__PURE__ */ (() => !!globalThis.HermesInternal)() +export const isDeno = /* @__PURE__ */ (() => !!globalThis.Deno)() +export const isLE = /* @__PURE__ */ (() => new Uint8Array(Uint16Array.of(258).buffer)[0] === 2)() + +// We consider Node.js TextDecoder/TextEncoder native +// Still needed in platform.native.js as this is re-exported to platform.js +let isNative = (x) => x && (haveNativeBuffer || `${x}`.includes('[native code]')) +if (!haveNativeBuffer && isNative(() => {})) isNative = () => false // e.g. XS, we don't want false positives + +export const nativeEncoder = /* @__PURE__ */ (() => + isNative(globalThis.TextEncoder) ? new TextEncoder() : null)() +export const nativeDecoder = /* @__PURE__ */ (() => + isNative(globalThis.TextDecoder) ? new TextDecoder('utf-8', { ignoreBOM: true }) : null)() + +// Actually windows-1252, compatible with ascii and latin1 decoding +// Beware that on non-latin1, i.e. on windows-1252, this is broken in ~all Node.js versions released +// in 2025 due to a regression, so we call it Latin1 as it's usable only for that +export const nativeDecoderLatin1 = /* @__PURE__ */ (() => { + // Not all barebone engines with TextDecoder support something except utf-8, detect + if (nativeDecoder) { + try { + return new TextDecoder('latin1', { ignoreBOM: true }) + } catch {} + } + + return null +})() + +export function decodePartAddition(a, start, end, m) { + let o = '' + let i = start + for (const last3 = end - 3; i < last3; i += 4) { + const x0 = a[i] + const x1 = a[i + 1] + const x2 = a[i + 2] + const x3 = a[i + 3] + o += m[x0] + o += m[x1] + o += m[x2] + o += m[x3] + } + + while (i < end) o += m[a[i++]] + return o +} + +// Decoding with templates is faster on Hermes +export function decodePartTemplates(a, start, end, m) { + let o = '' + let i = start + for (const last15 = end - 15; i < last15; i += 16) { + const x0 = a[i] + const x1 = a[i + 1] + const x2 = a[i + 2] + const x3 = a[i + 3] + const x4 = a[i + 4] + const x5 = a[i + 5] + const x6 = a[i + 6] + const x7 = a[i + 7] + const x8 = a[i + 8] + const x9 = a[i + 9] + const x10 = a[i + 10] + const x11 = a[i + 11] + const x12 = a[i + 12] + const x13 = a[i + 13] + const x14 = a[i + 14] + const x15 = a[i + 15] + o += `${m[x0]}${m[x1]}${m[x2]}${m[x3]}${m[x4]}${m[x5]}${m[x6]}${m[x7]}${m[x8]}${m[x9]}${m[x10]}${m[x11]}${m[x12]}${m[x13]}${m[x14]}${m[x15]}` + } + + while (i < end) o += m[a[i++]] + return o +} + +const decodePart = isHermes ? decodePartTemplates : decodePartAddition +export function decode2string(arr, start, end, m) { + if (end - start > 30_000) { + // Limit concatenation to avoid excessive GC + // Thresholds checked on Hermes for toHex + const concat = [] + for (let i = start; i < end; ) { + const step = i + 500 + const iNext = step > end ? end : step + concat.push(decodePart(arr, i, iNext, m)) + i = iNext + } + + const res = concat.join('') + concat.length = 0 + return res + } + + return decodePart(arr, start, end, m) +} + +/* eslint-disable @exodus/mutable/no-param-reassign-prop-only */ + +function encodeCharcodesHermes(str, arr) { + const length = str.length + if (length > 64) { + const at = str.charCodeAt.bind(str) // faster on strings from ~64 chars on Hermes, but can be 10x slower on e.g. JSC + for (let i = 0; i < length; i++) arr[i] = at(i) + } else { + for (let i = 0; i < length; i++) arr[i] = str.charCodeAt(i) + } + + return arr +} + +export function encodeCharcodesPure(str, arr) { + const length = str.length + // Can be optimized with unrolling, but this is not used on non-Hermes atm + for (let i = 0; i < length; i++) arr[i] = str.charCodeAt(i) + return arr +} + +/* eslint-enable @exodus/mutable/no-param-reassign-prop-only */ + +export const encodeCharcodes = isHermes ? encodeCharcodesHermes : encodeCharcodesPure diff --git a/vanilla/node_modules/@exodus/bytes/fallback/single-byte.encodings.js b/vanilla/node_modules/@exodus/bytes/fallback/single-byte.encodings.js new file mode 100644 index 0000000..edf38c5 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/single-byte.encodings.js @@ -0,0 +1,73 @@ +// See tests/encoding/fixtures/single-byte/dump.js for generator + +const r = 0xff_fd + +/* eslint-disable unicorn/numeric-separators-style, @exodus/export-default/named */ + +// Common ranges + +// prettier-ignore +const i2 = [189,148,0,0,63,0,116,64,0,68,0,78,0,78,0,0,63,64,114,117,0,0,123,0,0,128,149,0,149,0,0,132,0,117,0,0,32,0,85,33,0,37,0,47,0,47,0,0,32,33,83,86,0,0,92,0,0,97,118,0,118,0,0,101,474] +// prettier-ignore +const iB = [[58,3424],[4,r],[29,3424],[4,r]] +const i9 = [[47], 78, [12], 83, 128, [17], 47, [12], 52, 97] +const w1 = [8236, 0, 8088, 0, 8090, 8097, 8090, 8090, 0, 8103] +const w2 = [8236, 0, 8088, 271, 8090, 8097, 8090, 8090, 574, 8103] +// prettier-ignore +const w7 = [64,0,157,[4],39,68,109,62,67,0,0,82,75,68,0,175,75,86,105,92,108,144,114,115,0,120,[3],154,104,128,143,0,158,159,0,37,78,31,36,0,0,51,44,37,0,144,44,55,74,61,77,113,83,84,0,89,[3],123,73,97,112,0,127,128] +const w8 = [8071, 8071, 8073, 8073, 8077, 8061, 8061] +// prettier-ignore +const k8b = [-22,910,879,879,899,880,880,894,876,893,[8,879],894,[4,878],864,859,884,882,861,877,881,876,873,875,846,815,815,835,816,816,830,812,829,[8,815],830,[4,814],800,795,820,818,797,813,817,812,809,811] +// prettier-ignore +const k8a = [9344,9345,9354,9357,9360,9363,9366,9373,9380,9387,9394,9461,9464,9467,9470,[4,9473],8845,9484,8580,8580,8625,8652,8652,6,8838,20,21,25,88,[3,9392],942] + +// prettier-ignore +const maps = { + ibm866: [[48,912],[3,9441],...[29,62,122,122,109,107,120,101,106,111,109,107,31,34,65,56,39,10,69,102,102,96,89,109,105,98,81,108,102,102,97,97,84,82,75,75,98,96,13,0,123,118,125,128,111].map(x=>x+9266),[16,864],785,864,786,865,787,866,792,871,-72,8480,-67,8479,8218,-89,9378,-95], + 'koi8-u': [...k8a,944,9391,944,944,[5,9391],996,944,[4,9391],846,848,9390,848,848,[5,9390],979,848,...k8b], + 'koi8-r': [...k8a,[15,9391],846,[11,9390],...k8b], + macintosh: [68,68,69,70,77,81,86,90,88,89,90,88,89,90,91,89,90,90,91,89,90,90,91,92,90,91,92,90,94,92,93,93,8064,15,0,0,3,8061,16,56,6,0,8312,9,-4,8627,24,41,8558,0,8626,8626,-15,0,8524,8538,8535,775,8561,-17,-2,748,40,57,-1,-32,-22,8535,206,8579,8512,-28,-13,8029,-42,-11,-9,8,132,132,8003,8003,8010,8010,8004,8004,33,9459,39,159,8042,8145,8029,8029,64035,64035,8001,-42,7992,7995,8012,-35,-28,-38,-29,-33,[3,-29],-33,-27,-27,63503,-31,-24,-24,-27,60,464,485,-73,[3,479],-68,480,477,456], + 'x-mac-cyrillic': [[32,912],8064,15,1006,0,3,8061,16,863,6,0,8312,855,934,8627,853,932,8558,0,8626,8626,930,0,987,849,844,923,845,924,845,924,844,923,920,836,-22,8535,206,8579,8512,-28,-13,8029,-42,832,911,831,910,902,8003,8003,8010,8010,8004,8004,33,8007,822,901,821,900,8250,804,883,880,[31,848],8109], + 'windows-874': [8236,[4],8097,[11],...w8,[9],...iB], +} + +// windows-1250 - windows-1258 +// prettier-ignore +;[ + [...w1,214,8110,206,215,239,234,0,...w8,0,8329,199,8095,191,200,224,219,0,550,566,158,0,95,[4],180,[4],204,0,0,553,143,[5],76,165,0,129,544,128,...i2], + [898,898,8088,976,8090,8097,8090,8090,8228,8103,895,8110,894,895,893,896,962,...w8,0,8329,959,8095,958,959,957,960,0,877,956,869,0,1003,0,0,857,0,858,[4],856,0,0,852,931,989,[3],921,8285,922,0,924,840,919,920,[64,848]], + [...w2,214,8110,198,0,239,0,0,...w8,580,8329,199,8095,183,0,224,217], + [8236,0,8088,271,8090,8097,8090,8090,0,8103,0,8110,[5],...w8,0,8329,0,8095,[5],740,740,[7],r,[4],8038,[4],720,[3],[3,720],0,720,0,[20,720],r,[44,720],r], + [...w2,214,8110,198,[4],...w8,580,8329,199,8095,183,0,0,217,0,...i9], + [...w2,0,8110,[5],...w8,580,8329,0,8095,[8],8198,[5],45,[15],61,[5],[20,1264],[5,1308],[7,r],[27,1264],r,r,7953,7953,r], + [8236,1533,8088,271,8090,8097,8090,8090,574,8103,1519,8110,198,1529,1546,1529,1567,...w8,1553,8329,1527,8095,183,8047,8047,1563,0,1387,[8],1556,[15],1377,[4],1376,1537,[22,1376],0,[4,1375],[4,1380],0,1379,0,[4,1378],[5],1373,1373,0,0,[4,1371],0,1370,1370,0,1369,0,1368,0,0,7953,7953,1491], + [...w1,0,8110,0,27,569,41,0,...w8,0,8329,0,8095,0,18,573,0,0,r,[3],r,0,0,48,0,172,[4],23,[8],...w7,474], + [...w2,0,8110,198,[4],...w8,580,8329,0,8095,183,0,0,217,[35],63,[8],564,[3],64,0,567,0,0,203,[7],210,549,[4],32,[8],533,[3],33,0,561,0,0,172,[7],179,8109], +].forEach((m, i) => { + maps[`windows-${i + 1250}`] = m +}); + +// iso-8859-1 - iso-8859-16 +// prettier-ignore +;[ + [], // Actual Latin1 / Unicode subset, non-WHATWG, which maps iso-8859-1 to windows-1252 + [99,566,158,0,152,180,0,0,183,180,185,205,0,207,204,0,84,553,143,0,137,165,528,0,168,165,170,190,544,192,...i2], + [133,566,0,0,r,126,0,0,135,180,115,136,0,r,204,0,118,[4],111,0,0,120,165,100,121,0,r,189,[3],r,0,69,66,[9],r,[4],75,0,0,68,[4],143,126,[4],r,0,38,35,[9],r,[4],44,0,0,37,[4],112,95,474], + [99,150,179,0,131,149,0,0,183,104,119,186,0,207,0,0,84,553,164,0,116,134,528,0,168,89,104,171,141,192,140,64,[6],103,68,0,78,0,74,0,0,91,64,116,122,99,[5],153,[3],139,140,0,33,[6],72,37,0,47,0,43,0,0,60,33,85,91,68,[5],122,[3],108,109,474], + [[12,864],0,[66,864],8230,[12,864],-86,864,864], + [[3,r],0,[7,r],1376,0,[13,r],1376,[3,r],1376,r,[26,1376],[5,r],[19,1376],[13,r]], + [8055,8055,0,8200,8202,[4],720,[3],r,8038,[4],[3,720],0,[3,720],0,720,0,[20,720],r,[44,720],r], + [r,[8],45,[15],61,[4],[32,r],7992,[27,1264],r,r,7953,7953,r], + i9, // non-WHATWG, which maps iso-8859-9 to windows-1254 + [99,112,127,134,131,144,0,147,103,182,187,209,0,188,155,0,84,97,112,119,116,129,0,132,88,167,172,194,8024,173,140,64,[6],103,68,0,78,0,74,[4],116,122,[4],145,0,153,[6],33,[6],72,37,0,47,0,43,[4],85,91,[4],114,0,122,[5],57], + iB, // non-WHATWG, which maps iso-8859-11 to windows-874 + null, // no 12 + [8060,[3],8057,0,0,48,0,172,[4],23,[4],8040,[3],...w7,7962], + [7521,7521,0,102,102,7524,0,7640,0,7640,7520,7750,0,0,201,7534,7534,110,110,7564,7564,0,7583,7625,7582,7625,7589,7735,7623,7623,7586,[16],164,[6],7571,[6],152,[17],133,[6],7540,[6],121], + [[3],8200,0,186,0,185,[11],201,[3],198,[3],150,150,186], + [99,99,158,8200,8057,186,0,185,0,366,0,205,0,204,204,0,0,90,143,201,8040,0,0,198,84,351,0,150,150,186,189,[3],63,0,65,[10],64,114,[3],123,0,131,152,[4],59,316,[4],32,0,34,[10],33,83,[3],92,0,100,121,[4],28,285], +].forEach((m, i) => { + if (m) maps[`iso-8859-${i + 1}`] = [[33], ...m] +}); + +export default maps diff --git a/vanilla/node_modules/@exodus/bytes/fallback/single-byte.js b/vanilla/node_modules/@exodus/bytes/fallback/single-byte.js new file mode 100644 index 0000000..f7f5ec9 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/single-byte.js @@ -0,0 +1,110 @@ +import { asciiPrefix, decodeAscii, decodeLatin1 } from './latin1.js' +import encodings from './single-byte.encodings.js' +import { decode2string, nativeDecoder } from './platform.js' + +export const E_STRICT = 'Input is not well-formed for this encoding' +const xUserDefined = 'x-user-defined' +const iso8i = 'iso-8859-8-i' + +export const assertEncoding = (encoding) => { + if (Object.hasOwn(encodings, encoding) || encoding === xUserDefined || encoding === iso8i) return + throw new RangeError('Unsupported encoding') +} + +const r = 0xff_fd + +export function getEncoding(encoding) { + assertEncoding(encoding) + if (encoding === xUserDefined) return Array.from({ length: 128 }, (_, i) => 0xf7_80 + i) + if (encoding === iso8i) encoding = 'iso-8859-8' + const enc = encodings[encoding] + const deltas = enc.flatMap((x) => (Array.isArray(x) ? new Array(x[0]).fill(x[1] ?? 0) : x)) + return deltas.map((x, i) => (x === r ? x : x + 128 + i)) +} + +const mappers = new Map() +const decoders = new Map() +const encmaps = new Map() + +// Used only on Node.js, no reason to optimize for anything else +// E.g. avoiding .from and filling zero-initialized arr manually is faster on Hermes, but we avoid this codepath on Hermes completely +export function encodingMapper(encoding) { + const cached = mappers.get(encoding) + if (cached) return cached + + const codes = getEncoding(encoding) + const incomplete = codes.includes(r) + let map + const mapper = (arr, start = 0) => { + if (!map) { + map = new Uint16Array(256).map((_, i) => i) // Unicode subset + map.set(Uint16Array.from(codes), 128) + } + + const o = Uint16Array.from(start === 0 ? arr : arr.subarray(start)) // copy to modify in-place, also those are 16-bit now + let i = 0 + for (const end7 = o.length - 7; i < end7; i += 8) { + o[i] = map[o[i]] + o[i + 1] = map[o[i + 1]] + o[i + 2] = map[o[i + 2]] + o[i + 3] = map[o[i + 3]] + o[i + 4] = map[o[i + 4]] + o[i + 5] = map[o[i + 5]] + o[i + 6] = map[o[i + 6]] + o[i + 7] = map[o[i + 7]] + } + + for (const end = o.length; i < end; i++) o[i] = map[o[i]] + return o + } + + mappers.set(encoding, { mapper, incomplete }) + return { mapper, incomplete } +} + +export function encodingDecoder(encoding) { + const cached = decoders.get(encoding) + if (cached) return cached + const isLatin1 = encoding === 'iso-8859-1' + if (isLatin1 && !nativeDecoder) return (arr, loose = false) => decodeLatin1(arr) // native decoder is faster for ascii below + + let strings + const codes = getEncoding(encoding) + const incomplete = codes.includes(r) + const decoder = (arr, loose = false) => { + if (!strings) { + const allCodes = Array.from({ length: 128 }, (_, i) => i).concat(codes) + while (allCodes.length < 256) allCodes.push(allCodes.length) + strings = allCodes.map((c) => String.fromCharCode(c)) + } + + const prefixLen = asciiPrefix(arr) + if (prefixLen === arr.length) return decodeAscii(arr) + if (isLatin1) return decodeLatin1(arr) // TODO: check if decodeAscii with subarray is faster for small prefixes too + const prefix = decodeLatin1(arr, 0, prefixLen) // TODO: check if decodeAscii with subarray is faster for small prefixes too + const suffix = decode2string(arr, prefix.length, arr.length, strings) + if (!loose && incomplete && suffix.includes('\uFFFD')) throw new TypeError(E_STRICT) + return prefix + suffix + } + + decoders.set(encoding, decoder) + return decoder +} + +export function encodeMap(encoding) { + const cached = encmaps.get(encoding) + if (cached) return cached + + const codes = getEncoding(encoding) + let max = 128 + while (codes.length < 128) codes.push(128 + codes.length) + for (const code of codes) if (code > max && code !== r) max = code + const map = new Uint8Array(max + 1) // < 10 KiB for all except macintosh, 63 KiB for macintosh + for (let i = 0; i < 128; i++) { + map[i] = i + if (codes[i] !== r) map[codes[i]] = 128 + i + } + + encmaps.set(encoding, map) + return map +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/utf16.js b/vanilla/node_modules/@exodus/bytes/fallback/utf16.js new file mode 100644 index 0000000..a6f906f --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/utf16.js @@ -0,0 +1,266 @@ +import { decodeUCS2 } from './latin1.js' +import { assertU8, E_STRING, E_STRICT_UNICODE } from './_utils.js' +import { nativeDecoder, isLE, encodeCharcodes } from './platform.js' + +export const E_STRICT = 'Input is not well-formed utf16' +const isWellFormedStr = /* @__PURE__ */ (() => String.prototype.isWellFormed)() +const toWellFormedStr = /* @__PURE__ */ (() => String.prototype.toWellFormed)() + +const replacementCodepoint = 0xff_fd +const replacementCodepointSwapped = 0xfd_ff + +const to16 = (a) => new Uint16Array(a.buffer, a.byteOffset, a.byteLength / 2) // Requires checked length and alignment! + +export function encodeApi(str, loose, format) { + if (typeof str !== 'string') throw new TypeError(E_STRING) + if (format !== 'uint16' && format !== 'uint8-le' && format !== 'uint8-be') { + throw new TypeError('Unknown format') + } + + // On v8 and SpiderMonkey, check via isWellFormed is faster than js + // On JSC, check during loop is faster than isWellFormed + // If isWellFormed is available, we skip check during decoding and recheck after + // If isWellFormed is unavailable, we check in js during decoding + if (!loose && isWellFormedStr && !isWellFormedStr.call(str)) throw new TypeError(E_STRICT_UNICODE) + const shouldSwap = (isLE && format === 'uint8-be') || (!isLE && format === 'uint8-le') + const u16 = encode(str, loose, !loose && isWellFormedStr, shouldSwap) + + // Bytes are already swapped and format is already checked, we need to just cast the view + return format === 'uint16' ? u16 : new Uint8Array(u16.buffer, u16.byteOffset, u16.byteLength) +} + +const fatalLE = nativeDecoder ? new TextDecoder('utf-16le', { ignoreBOM: true, fatal: true }) : null +const looseLE = nativeDecoder ? new TextDecoder('utf-16le', { ignoreBOM: true }) : null +const fatalBE = nativeDecoder ? new TextDecoder('utf-16be', { ignoreBOM: true, fatal: true }) : null +const looseBE = nativeDecoder ? new TextDecoder('utf-16be', { ignoreBOM: true }) : null + +export function decodeApiDecoders(input, loose, format) { + if (format === 'uint16') { + if (!(input instanceof Uint16Array)) throw new TypeError('Expected an Uint16Array') + } else if (format === 'uint8-le' || format === 'uint8-be') { + assertU8(input) + if (input.byteLength % 2 !== 0) throw new TypeError('Expected even number of bytes') + } else { + throw new TypeError('Unknown format') + } + + const le = format === 'uint8-le' || (format === 'uint16' && isLE) + return (le ? (loose ? looseLE : fatalLE) : loose ? looseBE : fatalBE).decode(input) +} + +export function decodeApiJS(input, loose, format) { + let u16 + switch (format) { + case 'uint16': + if (!(input instanceof Uint16Array)) throw new TypeError('Expected an Uint16Array') + u16 = input + break + case 'uint8-le': + assertU8(input) + if (input.byteLength % 2 !== 0) throw new TypeError('Expected even number of bytes') + u16 = to16input(input, true) + break + case 'uint8-be': + assertU8(input) + if (input.byteLength % 2 !== 0) throw new TypeError('Expected even number of bytes') + u16 = to16input(input, false) + break + default: + throw new TypeError('Unknown format') + } + + const str = decode(u16, loose, (!loose && isWellFormedStr) || (loose && toWellFormedStr)) + if (!loose && isWellFormedStr && !isWellFormedStr.call(str)) throw new TypeError(E_STRICT) + if (loose && toWellFormedStr) return toWellFormedStr.call(str) + + return str +} + +export function to16input(u8, le) { + // Assume even number of bytes + if (le === isLE) return to16(u8.byteOffset % 2 === 0 ? u8 : Uint8Array.from(u8)) + return to16(swap16(Uint8Array.from(u8))) +} + +export const decode = (u16, loose = false, checked = false) => { + if (checked || isWellFormed(u16)) return decodeUCS2(u16) + if (!loose) throw new TypeError(E_STRICT) + return decodeUCS2(toWellFormed(Uint16Array.from(u16))) // cloned for replacement +} + +export function encode(str, loose = false, checked = false, swapped = false) { + const arr = new Uint16Array(str.length) + if (checked) return swapped ? encodeCheckedSwapped(str, arr) : encodeChecked(str, arr) + return swapped ? encodeUncheckedSwapped(str, arr, loose) : encodeUnchecked(str, arr, loose) +} + +/* eslint-disable @exodus/mutable/no-param-reassign-prop-only */ + +// Assumes checked length % 2 === 0, otherwise does not swap tail +function swap16(u8) { + let i = 0 + for (const last3 = u8.length - 3; i < last3; i += 4) { + const x0 = u8[i] + const x1 = u8[i + 1] + const x2 = u8[i + 2] + const x3 = u8[i + 3] + u8[i] = x1 + u8[i + 1] = x0 + u8[i + 2] = x3 + u8[i + 3] = x2 + } + + for (const last = u8.length - 1; i < last; i += 2) { + const x0 = u8[i] + const x1 = u8[i + 1] + u8[i] = x1 + u8[i + 1] = x0 + } + + return u8 +} + +// Splitting paths into small functions helps (at least on SpiderMonkey) + +const encodeChecked = (str, arr) => encodeCharcodes(str, arr) // Same as encodeLatin1, but with Uint16Array + +function encodeCheckedSwapped(str, arr) { + // TODO: faster path for Hermes? See encodeCharcodes + const length = str.length + for (let i = 0; i < length; i++) { + const x = str.charCodeAt(i) + arr[i] = ((x & 0xff) << 8) | (x >> 8) + } + + return arr +} + +// lead: d800 - dbff, trail: dc00 - dfff + +function encodeUnchecked(str, arr, loose = false) { + // TODO: faster path for Hermes? See encodeCharcodes + const length = str.length + for (let i = 0; i < length; i++) { + const code = str.charCodeAt(i) + arr[i] = code + if (code >= 0xd8_00 && code < 0xe0_00) { + // An unexpected trail or a lead at the very end of input + if (code > 0xdb_ff || i + 1 >= length) { + if (!loose) throw new TypeError(E_STRICT_UNICODE) + arr[i] = replacementCodepoint + } else { + const next = str.charCodeAt(i + 1) // Process valid pairs immediately + if (next < 0xdc_00 || next >= 0xe0_00) { + if (!loose) throw new TypeError(E_STRICT_UNICODE) + arr[i] = replacementCodepoint + } else { + i++ // consume next + arr[i] = next + } + } + } + } + + return arr +} + +function encodeUncheckedSwapped(str, arr, loose = false) { + // TODO: faster path for Hermes? See encodeCharcodes + const length = str.length + for (let i = 0; i < length; i++) { + const code = str.charCodeAt(i) + arr[i] = ((code & 0xff) << 8) | (code >> 8) + if (code >= 0xd8_00 && code < 0xe0_00) { + // An unexpected trail or a lead at the very end of input + if (code > 0xdb_ff || i + 1 >= length) { + if (!loose) throw new TypeError(E_STRICT_UNICODE) + arr[i] = replacementCodepointSwapped + } else { + const next = str.charCodeAt(i + 1) // Process valid pairs immediately + if (next < 0xdc_00 || next >= 0xe0_00) { + if (!loose) throw new TypeError(E_STRICT_UNICODE) + arr[i] = replacementCodepointSwapped + } else { + i++ // consume next + arr[i] = ((next & 0xff) << 8) | (next >> 8) + } + } + } + } + + return arr +} + +// Only needed on Hermes, everything else has native impl +export function toWellFormed(u16) { + const length = u16.length + for (let i = 0; i < length; i++) { + const code = u16[i] + if (code >= 0xd8_00 && code < 0xe0_00) { + // An unexpected trail or a lead at the very end of input + if (code > 0xdb_ff || i + 1 >= length) { + u16[i] = replacementCodepoint + } else { + const next = u16[i + 1] // Process valid pairs immediately + if (next < 0xdc_00 || next >= 0xe0_00) { + u16[i] = replacementCodepoint + } else { + i++ // consume next + } + } + } + } + + return u16 +} + +// Only needed on Hermes, everything else has native impl +export function isWellFormed(u16) { + const length = u16.length + let i = 0 + + const m = 0x80_00_80_00 + const l = 0xd8_00 + const h = 0xe0_00 + + // Speedup with u32, by skipping to the first surrogate + // Only implemented for aligned input for now, but almost all input is aligned (pooled Buffer or 0 offset) + if (length > 32 && u16.byteOffset % 4 === 0) { + const u32length = (u16.byteLength / 4) | 0 + const u32 = new Uint32Array(u16.buffer, u16.byteOffset, u32length) + for (const last3 = u32length - 3; ; i += 4) { + if (i >= last3) break // loop is fast enough for moving this here to be _very_ useful, likely due to array access checks + const a = u32[i] + const b = u32[i + 1] + const c = u32[i + 2] + const d = u32[i + 3] + if (a & m || b & m || c & m || d & m) break // bitwise OR does not make this faster on Hermes + } + + for (; i < u32length; i++) if (u32[i] & m) break + i *= 2 + } + + // An extra loop gives ~30-40% speedup e.g. on English text without surrogates but with other symbols above 0x80_00 + for (const last3 = length - 3; ; i += 4) { + if (i >= last3) break + const a = u16[i] + const b = u16[i + 1] + const c = u16[i + 2] + const d = u16[i + 3] + if ((a >= l && a < h) || (b >= l && b < h) || (c >= l && c < h) || (d >= l && d < h)) break + } + + for (; i < length; i++) { + const code = u16[i] + if (code >= l && code < h) { + // An unexpected trail or a lead at the very end of input + if (code >= 0xdc_00 || i + 1 >= length) return false + i++ // consume next + const next = u16[i] // Process valid pairs immediately + if (next < 0xdc_00 || next >= h) return false + } + } + + return true +} diff --git a/vanilla/node_modules/@exodus/bytes/fallback/utf8.auto.browser.js b/vanilla/node_modules/@exodus/bytes/fallback/utf8.auto.browser.js new file mode 100644 index 0000000..2ad5138 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/utf8.auto.browser.js @@ -0,0 +1,2 @@ +export const decodeFast = null +export const encode = null diff --git a/vanilla/node_modules/@exodus/bytes/fallback/utf8.auto.js b/vanilla/node_modules/@exodus/bytes/fallback/utf8.auto.js new file mode 100644 index 0000000..bb641ec --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/utf8.auto.js @@ -0,0 +1 @@ +export { decodeFast, encode } from './utf8.js' diff --git a/vanilla/node_modules/@exodus/bytes/fallback/utf8.auto.native.js b/vanilla/node_modules/@exodus/bytes/fallback/utf8.auto.native.js new file mode 100644 index 0000000..bb641ec --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/utf8.auto.native.js @@ -0,0 +1 @@ +export { decodeFast, encode } from './utf8.js' diff --git a/vanilla/node_modules/@exodus/bytes/fallback/utf8.js b/vanilla/node_modules/@exodus/bytes/fallback/utf8.js new file mode 100644 index 0000000..d1467bc --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/fallback/utf8.js @@ -0,0 +1,270 @@ +import { E_STRICT_UNICODE } from './_utils.js' +import { isHermes } from './platform.js' +import { asciiPrefix, decodeLatin1, encodeAsciiPrefix } from './latin1.js' + +export const E_STRICT = 'Input is not well-formed utf8' + +const replacementPoint = 0xff_fd +const shouldUseEscapePath = isHermes // faster only on Hermes, js path beats it on normal engines +const { decodeURIComponent, escape } = globalThis + +export function decodeFast(arr, loose) { + // Fast path for ASCII prefix, this is faster than all alternatives below + const prefix = decodeLatin1(arr, 0, asciiPrefix(arr)) // No native decoder to use, so decodeAscii is useless here + if (prefix.length === arr.length) return prefix + + // This codepath gives a ~3x perf boost on Hermes + if (shouldUseEscapePath && escape && decodeURIComponent) { + const o = escape(decodeLatin1(arr, prefix.length, arr.length)) + try { + return prefix + decodeURIComponent(o) // Latin1 to utf8 + } catch { + if (!loose) throw new TypeError(E_STRICT) + // Ok, we have to use manual implementation for loose decoder + } + } + + return prefix + decode(arr, loose, prefix.length) +} + +// https://encoding.spec.whatwg.org/#utf-8-decoder +// We are most likely in loose mode, for non-loose escape & decodeURIComponent solved everything +export function decode(arr, loose, start = 0) { + start |= 0 + const end = arr.length + let out = '' + const chunkSize = 0x2_00 // far below MAX_ARGUMENTS_LENGTH in npmjs.com/buffer, we use smaller chunks + const tmpSize = Math.min(end - start, chunkSize + 1) // need 1 extra slot for last codepoint, which can be 2 charcodes + const tmp = new Array(tmpSize).fill(0) + let ti = 0 + + for (let i = start; i < end; i++) { + if (ti >= chunkSize) { + tmp.length = ti // can be larger by 1 if last codepoint is two charcodes + out += String.fromCharCode.apply(String, tmp) + if (tmp.length <= chunkSize) tmp.push(0) // restore 1 extra slot for last codepoint + ti = 0 + } + + const byte = arr[i] + if (byte < 0x80) { + tmp[ti++] = byte + // ascii fast path is in decodeFast(), this is called only on non-ascii input + // so we don't unroll this anymore + } else if (byte < 0xc2) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + } else if (byte < 0xe0) { + // need 1 more + if (i + 1 >= end) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + break + } + + const byte1 = arr[i + 1] + if (byte1 < 0x80 || byte1 > 0xbf) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + continue + } + + i++ + tmp[ti++] = ((byte & 0x1f) << 6) | (byte1 & 0x3f) + } else if (byte < 0xf0) { + // need 2 more + if (i + 1 >= end) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + break + } + + const lower = byte === 0xe0 ? 0xa0 : 0x80 + const upper = byte === 0xed ? 0x9f : 0xbf + const byte1 = arr[i + 1] + if (byte1 < lower || byte1 > upper) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + continue + } + + i++ + if (i + 1 >= end) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + break + } + + const byte2 = arr[i + 1] + if (byte2 < 0x80 || byte2 > 0xbf) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + continue + } + + i++ + tmp[ti++] = ((byte & 0xf) << 12) | ((byte1 & 0x3f) << 6) | (byte2 & 0x3f) + } else if (byte <= 0xf4) { + // need 3 more + if (i + 1 >= end) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + break + } + + const lower = byte === 0xf0 ? 0x90 : 0x80 + const upper = byte === 0xf4 ? 0x8f : 0xbf + const byte1 = arr[i + 1] + if (byte1 < lower || byte1 > upper) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + continue + } + + i++ + if (i + 1 >= end) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + break + } + + const byte2 = arr[i + 1] + if (byte2 < 0x80 || byte2 > 0xbf) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + continue + } + + i++ + if (i + 1 >= end) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + break + } + + const byte3 = arr[i + 1] + if (byte3 < 0x80 || byte3 > 0xbf) { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + continue + } + + i++ + const codePoint = + ((byte & 0xf) << 18) | ((byte1 & 0x3f) << 12) | ((byte2 & 0x3f) << 6) | (byte3 & 0x3f) + if (codePoint > 0xff_ff) { + // split into char codes as String.fromCharCode is faster than String.fromCodePoint + const u = codePoint - 0x1_00_00 + tmp[ti++] = 0xd8_00 + ((u >> 10) & 0x3_ff) + tmp[ti++] = 0xdc_00 + (u & 0x3_ff) + } else { + tmp[ti++] = codePoint + } + // eslint-disable-next-line sonarjs/no-duplicated-branches + } else { + if (!loose) throw new TypeError(E_STRICT) + tmp[ti++] = replacementPoint + } + } + + if (ti === 0) return out + tmp.length = ti + return out + String.fromCharCode.apply(String, tmp) +} + +export function encode(string, loose) { + const length = string.length + let small = true + let bytes = new Uint8Array(length) // assume ascii + + let i = encodeAsciiPrefix(bytes, string) + let p = i + for (; i < length; i++) { + let code = string.charCodeAt(i) + if (code < 0x80) { + bytes[p++] = code + // Unroll the loop a bit for faster ops + while (true) { + i++ + if (i >= length) break + code = string.charCodeAt(i) + if (code >= 0x80) break + bytes[p++] = code + i++ + if (i >= length) break + code = string.charCodeAt(i) + if (code >= 0x80) break + bytes[p++] = code + i++ + if (i >= length) break + code = string.charCodeAt(i) + if (code >= 0x80) break + bytes[p++] = code + i++ + if (i >= length) break + code = string.charCodeAt(i) + if (code >= 0x80) break + bytes[p++] = code + } + + if (i >= length) break + // now, code is present and >= 0x80 + } + + if (small) { + // TODO: use resizable array buffers? will have to return a non-resizeable one + if (p !== i) /* c8 ignore next */ throw new Error('Unreachable') // Here, p === i (only when small is still true) + const bytesNew = new Uint8Array(p + (length - i) * 3) // maximium can be 3x of the string length in charcodes + bytesNew.set(bytes) + bytes = bytesNew + small = false + } + + // surrogate, charcodes = [d800 + a & 3ff, dc00 + b & 3ff]; codePoint = 0x1_00_00 | (a << 10) | b + // lead: d800 - dbff + // trail: dc00 - dfff + if (code >= 0xd8_00 && code < 0xe0_00) { + // Can't be a valid trail as we already processed that below + + if (code > 0xdb_ff || i + 1 >= length) { + // An unexpected trail or a lead at the very end of input + if (!loose) throw new TypeError(E_STRICT_UNICODE) + bytes[p++] = 0xef + bytes[p++] = 0xbf + bytes[p++] = 0xbd + continue + } + + const next = string.charCodeAt(i + 1) // Process valid pairs immediately + if (next >= 0xdc_00 && next < 0xe0_00) { + // here, codePoint is always between 0x1_00_00 and 0x11_00_00, we encode as 4 bytes + const codePoint = (((code - 0xd8_00) << 10) | (next - 0xdc_00)) + 0x1_00_00 + bytes[p++] = (codePoint >> 18) | 0xf0 + bytes[p++] = ((codePoint >> 12) & 0x3f) | 0x80 + bytes[p++] = ((codePoint >> 6) & 0x3f) | 0x80 + bytes[p++] = (codePoint & 0x3f) | 0x80 + i++ // consume next + } else { + // Next is not a trail, leave next unconsumed but process unmatched lead error + if (!loose) throw new TypeError(E_STRICT_UNICODE) + bytes[p++] = 0xef + bytes[p++] = 0xbf + bytes[p++] = 0xbd + } + + continue + } + + // We are left with a non-pair char code above ascii, it gets encoded to 2 or 3 bytes + if (code < 0x8_00) { + bytes[p++] = (code >> 6) | 0xc0 + bytes[p++] = (code & 0x3f) | 0x80 + } else { + bytes[p++] = (code >> 12) | 0xe0 + bytes[p++] = ((code >> 6) & 0x3f) | 0x80 + bytes[p++] = (code & 0x3f) | 0x80 + } + } + + return bytes.length === p ? bytes : bytes.slice(0, p) +} diff --git a/vanilla/node_modules/@exodus/bytes/hex.d.ts b/vanilla/node_modules/@exodus/bytes/hex.d.ts new file mode 100644 index 0000000..dbd29e6 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/hex.d.ts @@ -0,0 +1,35 @@ +/** + * Implements Base16 from [RFC4648](https://datatracker.ietf.org/doc/html/rfc4648) + * (no differences from [RFC3548](https://datatracker.ietf.org/doc/html/rfc4648)). + * + * ```js + * import { fromHex, toHex } from '@exodus/bytes/hex.js' + * ``` + * + * @module @exodus/bytes/hex.js + */ + +/// <reference types="node" /> + +import type { OutputFormat, Uint8ArrayBuffer } from './array.js'; + +/** + * Encode a `Uint8Array` to a lowercase hex string + * + * @param arr - The input bytes + * @returns The hex encoded string + */ +export function toHex(arr: Uint8Array): string; + +/** + * Decode a hex string to bytes + * + * Unlike `Buffer.from()`, throws on invalid input + * + * @param string - The hex encoded string (case-insensitive) + * @param format - Output format (default: 'uint8') + * @returns The decoded bytes + */ +export function fromHex(string: string, format?: 'uint8'): Uint8ArrayBuffer; +export function fromHex(string: string, format: 'buffer'): Buffer; +export function fromHex(string: string, format?: OutputFormat): Uint8ArrayBuffer | Buffer; diff --git a/vanilla/node_modules/@exodus/bytes/hex.js b/vanilla/node_modules/@exodus/bytes/hex.js new file mode 100644 index 0000000..a99c935 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/hex.js @@ -0,0 +1,17 @@ +import { typedView } from './array.js' +import { assertU8 } from './fallback/_utils.js' +import * as js from './fallback/hex.js' + +const { toHex: webHex } = Uint8Array.prototype // Modern engines have this + +export function toHex(arr) { + assertU8(arr) + if (arr.length === 0) return '' + if (webHex && arr.toHex === webHex) return arr.toHex() + return js.toHex(arr) +} + +// Unlike Buffer.from(), throws on invalid input +export const fromHex = Uint8Array.fromHex + ? (str, format = 'uint8') => typedView(Uint8Array.fromHex(str), format) + : (str, format = 'uint8') => typedView(js.fromHex(str), format) diff --git a/vanilla/node_modules/@exodus/bytes/hex.node.js b/vanilla/node_modules/@exodus/bytes/hex.node.js new file mode 100644 index 0000000..a4fc000 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/hex.node.js @@ -0,0 +1,28 @@ +import { typedView } from './array.js' +import { assertU8, E_STRING } from './fallback/_utils.js' +import { E_HEX } from './fallback/hex.js' + +if (Buffer.TYPED_ARRAY_SUPPORT) throw new Error('Unexpected Buffer polyfill') + +const { toHex: webHex } = Uint8Array.prototype // Modern engines have this +const denoBug = Buffer.from('ag', 'hex').length > 0 + +export function toHex(arr) { + assertU8(arr) + if (arr.length === 0) return '' + if (webHex && arr.toHex === webHex) return arr.toHex() + if (arr.constructor === Buffer && Buffer.isBuffer(arr)) return arr.hexSlice(0, arr.byteLength) + return Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength).hexSlice(0, arr.byteLength) +} + +// Unlike Buffer.from(), throws on invalid input +export const fromHex = Uint8Array.fromHex + ? (str, format = 'uint8') => typedView(Uint8Array.fromHex(str), format) + : (str, format = 'uint8') => { + if (typeof str !== 'string') throw new TypeError(E_STRING) + if (str.length % 2 !== 0) throw new SyntaxError(E_HEX) + if (denoBug && /[^\dA-Fa-f]/.test(str)) throw new SyntaxError(E_HEX) + const buf = Buffer.from(str, 'hex') // will stop on first non-hex character, so we can just validate length + if (buf.length * 2 !== str.length) throw new SyntaxError(E_HEX) + return typedView(buf, format) + } diff --git a/vanilla/node_modules/@exodus/bytes/index.d.ts b/vanilla/node_modules/@exodus/bytes/index.d.ts new file mode 100644 index 0000000..c679459 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/index.d.ts @@ -0,0 +1,43 @@ +/** + * ### The `@exodus/bytes` package consists of submodules, there is no single export. + * Import specific submodules instead. + * + * See [README](https://github.com/ExodusOSS/bytes/blob/main/README.md). + * + * Example: + * ```js + * import { fromHex, toHex } from '@exodus/bytes/hex.js' + * import { fromBase64, toBase64, fromBase64url, toBase64url, fromBase64any } from '@exodus/bytes/base64.js' + * import { fromBase32, toBase32, fromBase32hex, toBase32hex } from '@exodus/bytes/base32.js' + * import { fromBase58, toBase58, fromBase58xrp, toBase58xrp } from '@exodus/bytes/base58.js' + * import { fromBech32, toBech32, fromBech32m, toBech32m, getPrefix } from '@exodus/bytes/bech32.js' + * import { fromBigInt, toBigInt } from '@exodus/bytes/bigint.js' + * + * import { utf8fromString, utf8toString, utf8fromStringLoose, utf8toStringLoose } from '@exodus/bytes/utf8.js' + * import { utf16fromString, utf16toString, utf16fromStringLoose, utf16toStringLoose } from '@exodus/bytes/utf16.js' + * import { + * createSinglebyteDecoder, createSinglebyteEncoder, + * windows1252toString, windows1252fromString, + * latin1toString, latin1fromString } from '@exodus/bytes/single-byte.js' + * import { createMultibyteDecoder, createMultibyteEncoder } from '@exodus/bytes/multi-byte.js' + * + * import { + * fromBase58check, toBase58check, + * fromBase58checkSync, toBase58checkSync, + * makeBase58check } from '@exodus/bytes/base58check.js' + * import { fromWifString, toWifString, fromWifStringSync, toWifStringSync } from '@exodus/bytes/wif.js' + * + * // All encodings from the WHATWG Encoding spec + * import { TextDecoder, TextEncoder, TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding.js' + * import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding.js' + * + * // Omits legacy multi-byte decoders to save bundle size + * import { TextDecoder, TextEncoder, TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding-lite.js' + * import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding-lite.js' + * + * // In browser bundles, uses built-in TextDecoder / TextEncoder to save bundle size + * import { TextDecoder, TextEncoder, TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding-browser.js' + * import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding-browser.js' + * ``` + */ +declare module '@exodus/bytes' {} diff --git a/vanilla/node_modules/@exodus/bytes/index.js b/vanilla/node_modules/@exodus/bytes/index.js new file mode 100644 index 0000000..4d5292b --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/index.js @@ -0,0 +1,5 @@ +throw new Error( + `This package consists of submodules, there is no single export. Import specific submodules instead. +See README: https://github.com/ExodusOSS/bytes/blob/main/README.md +` +) diff --git a/vanilla/node_modules/@exodus/bytes/multi-byte.d.ts b/vanilla/node_modules/@exodus/bytes/multi-byte.d.ts new file mode 100644 index 0000000..a62313f --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/multi-byte.d.ts @@ -0,0 +1,64 @@ +/** + * Decode / encode the legacy multi-byte encodings according to the + * [Encoding standard](https://encoding.spec.whatwg.org/) + * ([§10](https://encoding.spec.whatwg.org/#legacy-multi-byte-chinese-(simplified)-encodings), + * [§11](https://encoding.spec.whatwg.org/#legacy-multi-byte-chinese-(traditional)-encodings), + * [§12](https://encoding.spec.whatwg.org/#legacy-multi-byte-japanese-encodings), + * [§13](https://encoding.spec.whatwg.org/#legacy-multi-byte-korean-encodings)). + * + * ```js + * import { createMultibyteDecoder, createMultibyteEncoder } from '@exodus/bytes/multi-byte.js' + * ``` + * + * > [!WARNING] + * > This is a lower-level API for legacy multi-byte encodings. + * > + * > For a safe WHATWG Encoding-compatible API, see `@exodus/bytes/encoding.js` import (and variants of it). + * > + * > Be sure to know what you are doing and check documentation when directly using encodings from this file. + * + * Supports all legacy multi-byte encodings listed in the WHATWG Encoding standard: + * `gbk`, `gb18030`, `big5`, `euc-jp`, `iso-2022-jp`, `shift_jis`, `euc-kr`. + * + * @module @exodus/bytes/multi-byte.js + */ + +/// <reference types="node" /> + +import type { Uint8ArrayBuffer } from './array.js'; + +/** + * Create a decoder for a supported legacy multi-byte `encoding`, given its lowercased name `encoding`. + * + * Returns a function `decode(arr, stream = false)` that decodes bytes to a string. + * + * The returned function will maintain internal state while `stream = true` is used, allowing it to + * handle incomplete multi-byte sequences across multiple calls. + * State is reset when `stream = false` or when the function is called without the `stream` parameter. + * + * @param encoding - The encoding name (e.g., 'gbk', 'gb18030', 'big5', 'euc-jp', 'iso-2022-jp', 'shift_jis', 'euc-kr') + * @param loose - If true, replaces unmapped bytes with replacement character instead of throwing (default: false) + * @returns A function that decodes bytes to string, with optional streaming support + */ +export function createMultibyteDecoder( + encoding: string, + loose?: boolean +): (arr: Uint8Array, stream?: boolean) => string; + +/** + * Create an encoder for a supported legacy multi-byte `encoding`, given its lowercased name `encoding`. + * + * Returns a function `encode(string)` that encodes a string to bytes. + * + * In `'fatal'` mode (default), will throw on non well-formed strings or any codepoints which could + * not be encoded in the target encoding. + * + * @param encoding - The encoding name (e.g., 'gbk', 'gb18030', 'big5', 'euc-jp', 'iso-2022-jp', 'shift_jis', 'euc-kr') + * @param options - Encoding options + * @param options.mode - Encoding mode (default: 'fatal'). Currently, only 'fatal' mode is supported. + * @returns A function that encodes string to bytes + */ +export function createMultibyteEncoder( + encoding: string, + options?: { mode?: 'fatal' } +): (string: string) => Uint8ArrayBuffer; diff --git a/vanilla/node_modules/@exodus/bytes/multi-byte.js b/vanilla/node_modules/@exodus/bytes/multi-byte.js new file mode 100644 index 0000000..46dd60f --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/multi-byte.js @@ -0,0 +1,19 @@ +import { assertU8 } from './fallback/_utils.js' +import { multibyteDecoder, multibyteEncoder } from './fallback/multi-byte.js' + +export function createMultibyteDecoder(encoding, loose = false) { + const jsDecoder = multibyteDecoder(encoding, loose) // asserts + let streaming = false + return (arr, stream = false) => { + assertU8(arr) + if (!streaming && arr.byteLength === 0) return '' + streaming = stream + return jsDecoder(arr, stream) + } +} + +export function createMultibyteEncoder(encoding, { mode = 'fatal' } = {}) { + // TODO: replacement, truncate (replacement will need varying length) + if (mode !== 'fatal') throw new Error('Unsupported mode') + return multibyteEncoder(encoding) // asserts +} diff --git a/vanilla/node_modules/@exodus/bytes/multi-byte.node.js b/vanilla/node_modules/@exodus/bytes/multi-byte.node.js new file mode 100644 index 0000000..0c605f2 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/multi-byte.node.js @@ -0,0 +1,29 @@ +import { assertU8, toBuf } from './fallback/_utils.js' +import { isDeno } from './fallback/platform.js' +import { isAsciiSuperset, multibyteDecoder, multibyteEncoder } from './fallback/multi-byte.js' +import { isAscii } from 'node:buffer' + +export function createMultibyteDecoder(encoding, loose = false) { + const jsDecoder = multibyteDecoder(encoding, loose) // asserts + let streaming = false + const asciiSuperset = isAsciiSuperset(encoding) + return (arr, stream = false) => { + assertU8(arr) + if (!streaming) { + if (arr.byteLength === 0) return '' + if (asciiSuperset && isAscii(arr)) { + if (isDeno) return toBuf(arr).toString() + return toBuf(arr).latin1Slice(0, arr.byteLength) // .latin1Slice is faster than .asciiSlice + } + } + + streaming = stream + return jsDecoder(arr, stream) + } +} + +export function createMultibyteEncoder(encoding, { mode = 'fatal' } = {}) { + // TODO: replacement, truncate (replacement will need varying length) + if (mode !== 'fatal') throw new Error('Unsupported mode') + return multibyteEncoder(encoding) // asserts +} diff --git a/vanilla/node_modules/@exodus/bytes/package.json b/vanilla/node_modules/@exodus/bytes/package.json new file mode 100644 index 0000000..407d70a --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/package.json @@ -0,0 +1,298 @@ +{ + "name": "@exodus/bytes", + "version": "1.14.1", + "description": "Various operations on Uint8Array data", + "keywords": [ + "encoding", + "Uint8Array", + "TextDecoder", + "TextEncoder", + "utf8", + "utf16", + "hex", + "base64", + "base32", + "base58", + "base58check", + "bech32", + "bech32m", + "wif" + ], + "scripts": { + "lint": "eslint .", + "typedoc": "typedoc && mkdir -p doc/assets && cp -r theme/styles doc/assets/", + "test:javascriptcore": "npm run test:jsc --", + "test:v8": "exodus-test --engine=v8:bundle", + "test:jsc": "exodus-test --engine=jsc:bundle", + "test:spidermonkey": "exodus-test --engine=spidermonkey:bundle", + "test:hermes": "exodus-test --engine=hermes:bundle", + "test:quickjs": "exodus-test --engine=quickjs:bundle", + "test:xs": "exodus-test --engine=xs:bundle", + "test:engine262": "exodus-test --engine=engine262:bundle", + "test:graaljs": "exodus-test --engine=graaljs:bundle", + "test:escargot": "exodus-test --engine=escargot:bundle", + "test:boa": "exodus-test --engine=boa:bundle", + "test:deno": "exodus-test --engine=deno:pure", + "test:bun": "exodus-test --engine=bun:pure", + "test:workerd": "exodus-test --engine=workerd:bundle", + "test:electron:bundle": "exodus-test --engine=electron:bundle", + "test:electron:as-node": "exodus-test --engine=electron-as-node:test", + "test:chrome:puppeteer": "exodus-test --engine=chrome:puppeteer", + "test:chromium:playwright": "exodus-test --engine=chromium:playwright", + "test:webkit:playwright": "exodus-test --engine=webkit:playwright", + "test:firefox:puppeteer": "exodus-test --engine=firefox:puppeteer --testTimeout=60000", + "test:firefox:playwright": "exodus-test --engine=firefox:playwright --testTimeout=60000", + "test:servo:bundle": "exodus-test --engine=servo:bundle", + "test": "exodus-test", + "size": "esbuild --minify --bundle", + "jsvu": "jsvu", + "playwright": "exodus-test --playwright", + "benchmark": "exodus-test --concurrency=1 benchmarks/*.bench.js", + "coverage": "exodus-test --coverage" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ExodusOSS/bytes.git" + }, + "author": "Exodus Movement, Inc.", + "license": "MIT", + "bugs": { + "url": "https://github.com/ExodusOSS/bytes/issues" + }, + "homepage": "https://github.com/ExodusOSS/bytes", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "type": "module", + "files": [ + "/fallback/_utils.js", + "/fallback/base32.js", + "/fallback/base58check.js", + "/fallback/base64.js", + "/fallback/encoding.js", + "/fallback/encoding.api.js", + "/fallback/encoding.labels.js", + "/fallback/encoding.util.js", + "/fallback/hex.js", + "/fallback/latin1.js", + "/fallback/percent.js", + "/fallback/platform.js", + "/fallback/platform.browser.js", + "/fallback/platform.native.js", + "/fallback/multi-byte.encodings.cjs", + "/fallback/multi-byte.encodings.json", + "/fallback/multi-byte.js", + "/fallback/multi-byte.table.js", + "/fallback/single-byte.encodings.js", + "/fallback/single-byte.js", + "/fallback/utf16.js", + "/fallback/utf8.js", + "/fallback/utf8.auto.js", + "/fallback/utf8.auto.browser.js", + "/fallback/utf8.auto.native.js", + "/array.js", + "/array.d.ts", + "/assert.js", + "/base32.js", + "/base32.d.ts", + "/base58.js", + "/base58.d.ts", + "/base58check.js", + "/base58check.d.ts", + "/base58check.node.js", + "/base64.js", + "/base64.d.ts", + "/bech32.js", + "/bech32.d.ts", + "/bigint.js", + "/bigint.d.ts", + "/encoding-browser.js", + "/encoding-browser.browser.js", + "/encoding-browser.native.js", + "/encoding-browser.d.ts", + "/encoding.js", + "/encoding.d.ts", + "/encoding-lite.js", + "/encoding-lite.d.ts", + "/hex.js", + "/hex.d.ts", + "/hex.node.js", + "/index.js", + "/index.d.ts", + "/multi-byte.js", + "/multi-byte.d.ts", + "/multi-byte.node.js", + "/single-byte.js", + "/single-byte.d.ts", + "/single-byte.node.js", + "/utf16.js", + "/utf16.d.ts", + "/utf16.browser.js", + "/utf16.native.js", + "/utf16.node.js", + "/utf8.js", + "/utf8.d.ts", + "/utf8.node.js", + "/whatwg.js", + "/whatwg.d.ts", + "/wif.js", + "/wif.d.ts" + ], + "main": "index.js", + "module": "index.js", + "types": "index.d.ts", + "exports": { + ".": { + "types": "./index.d.ts", + "default": "./index.js" + }, + "./array.js": { + "types": "./array.d.ts", + "default": "./array.js" + }, + "./base32.js": { + "types": "./base32.d.ts", + "default": "./base32.js" + }, + "./base58.js": { + "types": "./base58.d.ts", + "default": "./base58.js" + }, + "./base58check.js": { + "types": "./base58check.d.ts", + "node": "./base58check.node.js", + "default": "./base58check.js" + }, + "./base64.js": { + "types": "./base64.d.ts", + "default": "./base64.js" + }, + "./bech32.js": { + "types": "./bech32.d.ts", + "default": "./bech32.js" + }, + "./bigint.js": { + "types": "./bigint.d.ts", + "default": "./bigint.js" + }, + "./hex.js": { + "types": "./hex.d.ts", + "node": "./hex.node.js", + "default": "./hex.js" + }, + "./multi-byte.js": { + "types": "./multi-byte.d.ts", + "node": "./multi-byte.node.js", + "default": "./multi-byte.js" + }, + "./single-byte.js": { + "types": "./single-byte.d.ts", + "node": "./single-byte.node.js", + "default": "./single-byte.js" + }, + "./encoding.js": { + "types": "./encoding.d.ts", + "default": "./encoding.js" + }, + "./encoding-lite.js": { + "types": "./encoding-lite.d.ts", + "default": "./encoding-lite.js" + }, + "./encoding-browser.js": { + "types": "./encoding-browser.d.ts", + "node": "./encoding-browser.js", + "react-native": "./encoding-browser.native.js", + "browser": "./encoding-browser.browser.js", + "default": "./encoding-browser.js" + }, + "./utf16.js": { + "types": "./utf16.d.ts", + "node": "./utf16.node.js", + "react-native": "./utf16.native.js", + "browser": "./utf16.browser.js", + "default": "./utf16.js" + }, + "./utf8.js": { + "types": "./utf8.d.ts", + "node": "./utf8.node.js", + "default": "./utf8.js" + }, + "./whatwg.js": { + "types": "./whatwg.d.ts", + "default": "./whatwg.js" + }, + "./wif.js": { + "types": "./wif.d.ts", + "default": "./wif.js" + } + }, + "browser": { + "./utf16.js": "./utf16.browser.js", + "./fallback/platform.js": "./fallback/platform.browser.js", + "./fallback/utf8.auto.js": "./fallback/utf8.auto.browser.js" + }, + "react-native": { + "./encoding-browser.js": "./encoding-browser.native.js", + "./utf16.js": "./utf16.native.js", + "./fallback/platform.js": "./fallback/platform.native.js", + "./fallback/utf8.auto.js": "./fallback/utf8.auto.native.js" + }, + "sideEffects": [ + "./encoding.js" + ], + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + }, + "devDependencies": { + "@ethersproject/strings": "^5.8.0", + "@exodus/crypto": "^1.0.0-rc.30", + "@exodus/eslint-config": "^5.24.0", + "@exodus/prettier": "^1.0.0", + "@exodus/test": "1.0.0-rc.115", + "@hexagon/base64": "^2.0.4", + "@noble/hashes": "^2.0.1", + "@oslojs/encoding": "^1.1.0", + "@petamoriken/float16": "^3.9.3", + "@scure/base": "^1.2.6", + "@stablelib/base64": "^2.0.1", + "@stablelib/hex": "^2.0.1", + "@types/node": "^22.12.0", + "base-x": "^5.0.1", + "base32.js": "^0.1.0", + "base58-js": "^3.0.3", + "base64-js": "^1.5.1", + "bech32": "^2.0.0", + "bs58": "^6.0.0", + "bs58check": "^4.0.0", + "bstring": "^0.3.9", + "buffer": "^6.0.3", + "c8": "^10.1.3", + "decode-utf8": "^1.0.1", + "electron": "36.5.0", + "encode-utf8": "^2.0.0", + "esbuild": "^0.27.3", + "eslint": "^8.44.0", + "fast-base64-decode": "^2.0.0", + "fast-base64-encode": "^1.0.0", + "hextreme": "^1.0.7", + "hi-base32": "^0.5.1", + "iconv-lite": "^0.7.0", + "jsvu": "^3.0.3", + "punycode": "^2.3.1", + "text-encoding": "^0.7.0", + "typedoc": "^0.28.16", + "typescript": "^5.9.3", + "uint8array-tools": "^0.0.9", + "utf8": "^3.0.0", + "web-streams-polyfill": "^4.2.0", + "wif": "^5.0.0", + "workerd": "^1.20260210.0" + }, + "prettier": "@exodus/prettier", + "packageManager": "pnpm@10.12.1+sha256.889bac470ec93ccc3764488a19d6ba8f9c648ad5e50a9a6e4be3768a5de387a3" +} diff --git a/vanilla/node_modules/@exodus/bytes/single-byte.d.ts b/vanilla/node_modules/@exodus/bytes/single-byte.d.ts new file mode 100644 index 0000000..ab6d6a2 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/single-byte.d.ts @@ -0,0 +1,159 @@ +/** + * Decode / encode the legacy single-byte encodings according to the + * [Encoding standard](https://encoding.spec.whatwg.org/) + * ([§9](https://encoding.spec.whatwg.org/#legacy-single-byte-encodings), + * [§14.5](https://encoding.spec.whatwg.org/#x-user-defined)), + * and [unicode.org](https://unicode.org/Public/MAPPINGS/ISO8859) `iso-8859-*` mappings. + * + * ```js + * import { createSinglebyteDecoder, createSinglebyteEncoder } from '@exodus/bytes/single-byte.js' + * import { windows1252toString, windows1252fromString } from '@exodus/bytes/single-byte.js' + * import { latin1toString, latin1fromString } from '@exodus/bytes/single-byte.js' + * ``` + * + * > [!WARNING] + * > This is a lower-level API for single-byte encodings. + * > It might not match what you expect, as it supports both WHATWG and unicode.org encodings under + * > different names, with the main intended usecase for the latter being either non-web or legacy contexts. + * > + * > For a safe WHATWG Encoding-compatible API, see `@exodus/bytes/encoding.js` import (and variants of it). + * > + * > Be sure to know what you are doing and check documentation when directly using encodings from this file. + * + * Supports all single-byte encodings listed in the WHATWG Encoding standard: + * `ibm866`, `iso-8859-2`, `iso-8859-3`, `iso-8859-4`, `iso-8859-5`, `iso-8859-6`, `iso-8859-7`, `iso-8859-8`, + * `iso-8859-8-i`, `iso-8859-10`, `iso-8859-13`, `iso-8859-14`, `iso-8859-15`, `iso-8859-16`, `koi8-r`, `koi8-u`, + * `macintosh`, `windows-874`, `windows-1250`, `windows-1251`, `windows-1252`, `windows-1253`, `windows-1254`, + * `windows-1255`, `windows-1256`, `windows-1257`, `windows-1258`, `x-mac-cyrillic` and `x-user-defined`. + * + * Also supports `iso-8859-1`, `iso-8859-9`, `iso-8859-11` as defined at + * [unicode.org](https://unicode.org/Public/MAPPINGS/ISO8859) + * (and all other `iso-8859-*` encodings there as they match WHATWG). + * + * > [!NOTE] + * > While all `iso-8859-*` encodings supported by the [WHATWG Encoding standard](https://encoding.spec.whatwg.org/) match + * > [unicode.org](https://unicode.org/Public/MAPPINGS/ISO8859), the WHATWG Encoding spec doesn't support + * > `iso-8859-1`, `iso-8859-9`, `iso-8859-11`, and instead maps them as labels to `windows-1252`, `windows-1254`, `windows-874`.\ + * > `createSinglebyteDecoder()` (unlike `TextDecoder` or `legacyHookDecode()`) does not do such mapping, + * > so its results will differ from `TextDecoder` for those encoding names. + * + * ```js + * > new TextDecoder('iso-8859-1').encoding + * 'windows-1252' + * > new TextDecoder('iso-8859-9').encoding + * 'windows-1254' + * > new TextDecoder('iso-8859-11').encoding + * 'windows-874' + * > new TextDecoder('iso-8859-9').decode(Uint8Array.of(0x80, 0x81, 0xd0)) + * '€\x81Ğ' // this is actually decoded according to windows-1254 per TextDecoder spec + * > createSinglebyteDecoder('iso-8859-9')(Uint8Array.of(0x80, 0x81, 0xd0)) + * '\x80\x81Ğ' // this is iso-8859-9 as defined at https://unicode.org/Public/MAPPINGS/ISO8859/8859-9.txt + * ``` + * + * All WHATWG Encoding spec [`windows-*` encodings](https://encoding.spec.whatwg.org/#windows-874) are supersets of + * corresponding [unicode.org encodings](https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/), meaning that + * they encode/decode all the old valid (non-replacement) strings / byte sequences identically, but can also support + * a wider range of inputs. + * + * @module @exodus/bytes/single-byte.js + */ + +/// <reference types="node" /> + +import type { Uint8ArrayBuffer } from './array.js'; + +/** + * Create a decoder for a supported one-byte `encoding`, given its lowercased name `encoding`. + * + * Returns a function `decode(arr)` that decodes bytes to a string. + * + * @param encoding - The encoding name (e.g., 'iso-8859-1', 'windows-1252') + * @param loose - If true, replaces unmapped bytes with replacement character instead of throwing (default: false) + * @returns A function that decodes bytes to string + */ +export function createSinglebyteDecoder( + encoding: string, + loose?: boolean +): (arr: Uint8Array) => string; + +/** + * Create an encoder for a supported one-byte `encoding`, given its lowercased name `encoding`. + * + * Returns a function `encode(string)` that encodes a string to bytes. + * + * In `'fatal'` mode (default), will throw on non well-formed strings or any codepoints which could + * not be encoded in the target encoding. + * + * @param encoding - The encoding name (e.g., 'iso-8859-1', 'windows-1252') + * @param options - Encoding options + * @param options.mode - Encoding mode (default: 'fatal'). Currently, only 'fatal' mode is supported. + * @returns A function that encodes string to bytes + */ +export function createSinglebyteEncoder( + encoding: string, + options?: { mode?: 'fatal' } +): (string: string) => Uint8ArrayBuffer; + +/** + * Decode `iso-8859-1` bytes to a string. + * + * There is no loose variant for this encoding, all bytes can be decoded. + * + * Same as: + * ```js + * const latin1toString = createSinglebyteDecoder('iso-8859-1') + * ``` + * + * > [!NOTE] + * > This is different from `new TextDecoder('iso-8859-1')` and `new TextDecoder('latin1')`, as those + * > alias to `new TextDecoder('windows-1252')`. + * + * @param arr - The bytes to decode + * @returns The decoded string + */ +export function latin1toString(arr: Uint8Array): string; + +/** + * Encode a string to `iso-8859-1` bytes. + * + * Throws on non well-formed strings or any codepoints which could not be encoded in `iso-8859-1`. + * + * Same as: + * ```js + * const latin1fromString = createSinglebyteEncoder('iso-8859-1', { mode: 'fatal' }) + * ``` + * + * @param string - The string to encode + * @returns The encoded bytes + */ +export function latin1fromString(string: string): Uint8ArrayBuffer; + +/** + * Decode `windows-1252` bytes to a string. + * + * There is no loose variant for this encoding, all bytes can be decoded. + * + * Same as: + * ```js + * const windows1252toString = createSinglebyteDecoder('windows-1252') + * ``` + * + * @param arr - The bytes to decode + * @returns The decoded string + */ +export function windows1252toString(arr: Uint8Array): string; + +/** + * Encode a string to `windows-1252` bytes. + * + * Throws on non well-formed strings or any codepoints which could not be encoded in `windows-1252`. + * + * Same as: + * ```js + * const windows1252fromString = createSinglebyteEncoder('windows-1252', { mode: 'fatal' }) + * ``` + * + * @param string - The string to encode + * @returns The encoded bytes + */ +export function windows1252fromString(string: string): Uint8ArrayBuffer; diff --git a/vanilla/node_modules/@exodus/bytes/single-byte.js b/vanilla/node_modules/@exodus/bytes/single-byte.js new file mode 100644 index 0000000..ba17324 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/single-byte.js @@ -0,0 +1,135 @@ +import { assertU8, E_STRING } from './fallback/_utils.js' +import { nativeDecoderLatin1, nativeEncoder } from './fallback/platform.js' +import { encodeAscii, encodeAsciiPrefix, encodeLatin1 } from './fallback/latin1.js' +import { assertEncoding, encodingDecoder, encodeMap, E_STRICT } from './fallback/single-byte.js' + +const { TextDecoder, btoa } = globalThis + +let windows1252works + +// prettier-ignore +const skipNative = new Set([ + 'iso-8859-1', 'iso-8859-9', 'iso-8859-11', // non-WHATWG + 'iso-8859-6', 'iso-8859-8', 'iso-8859-8-i', // slow in all 3 engines + 'iso-8859-16', // iso-8859-16 is somehow broken in WebKit, at least on CI +]) + +function shouldUseNative(enc) { + // https://issues.chromium.org/issues/468458388 + // Also might be incorrectly imlemented on platforms as Latin1 (e.g. in Node.js) or regress + // This is the most significant single-byte encoding, 'ascii' and 'latin1' alias to this + // Even after Chrome bug is fixed, this should serve as a quick correctness check that it's actually windows-1252 + if (enc === 'windows-1252') { + if (windows1252works === undefined) { + windows1252works = false + try { + const u = new Uint8Array(9) // using 9 bytes is significant to catch the bug + u[8] = 128 + windows1252works = new TextDecoder(enc).decode(u).codePointAt(8) === 0x20_ac + } catch {} + } + + return windows1252works + } + + return !skipNative.has(enc) +} + +export function createSinglebyteDecoder(encoding, loose = false) { + if (typeof loose !== 'boolean') throw new TypeError('loose option should be boolean') + assertEncoding(encoding) + + if (nativeDecoderLatin1 && shouldUseNative(encoding)) { + // In try, as not all encodings might be implemented in all engines which have native TextDecoder + try { + const decoder = new TextDecoder(encoding, { fatal: !loose }) + return (arr) => { + assertU8(arr) + if (arr.byteLength === 0) return '' + return decoder.decode(arr) + } + } catch {} + } + + const jsDecoder = encodingDecoder(encoding) + return (arr) => { + assertU8(arr) + if (arr.byteLength === 0) return '' + return jsDecoder(arr, loose) + } +} + +const NON_LATIN = /[^\x00-\xFF]/ // eslint-disable-line no-control-regex + +function encode(s, m) { + const len = s.length + const x = new Uint8Array(len) + let i = nativeEncoder ? 0 : encodeAsciiPrefix(x, s) + + for (const len3 = len - 3; i < len3; i += 4) { + const x0 = s.charCodeAt(i), x1 = s.charCodeAt(i + 1), x2 = s.charCodeAt(i + 2), x3 = s.charCodeAt(i + 3) // prettier-ignore + const c0 = m[x0], c1 = m[x1], c2 = m[x2], c3 = m[x3] // prettier-ignore + if ((!c0 && x0) || (!c1 && x1) || (!c2 && x2) || (!c3 && x3)) return null + + x[i] = c0 + x[i + 1] = c1 + x[i + 2] = c2 + x[i + 3] = c3 + } + + for (; i < len; i++) { + const x0 = s.charCodeAt(i) + const c0 = m[x0] + if (!c0 && x0) return null + x[i] = c0 + } + + return x +} + +// fromBase64+btoa path is faster on everything where fromBase64 is fast +const useLatin1btoa = Uint8Array.fromBase64 && btoa + +export function createSinglebyteEncoder(encoding, { mode = 'fatal' } = {}) { + // TODO: replacement, truncate (replacement will need varying length) + if (mode !== 'fatal') throw new Error('Unsupported mode') + const m = encodeMap(encoding) // asserts + const isLatin1 = encoding === 'iso-8859-1' + + // No single-byte encoder produces surrogate pairs, so any surrogate is invalid + // This needs special treatment only to decide how many replacement chars to output, one or two + // Not much use in running isWellFormed, most likely cause of error is unmapped chars, not surrogate pairs + return (s) => { + if (typeof s !== 'string') throw new TypeError(E_STRING) + if (isLatin1) { + // max limit is to not produce base64 strings that are too long + if (useLatin1btoa && s.length >= 1024 && s.length < 1e8) { + try { + return Uint8Array.fromBase64(btoa(s)) // fails on non-latin1 + } catch { + throw new TypeError(E_STRICT) + } + } + + if (NON_LATIN.test(s)) throw new TypeError(E_STRICT) + return encodeLatin1(s) + } + + // Instead of an ASCII regex check, encode optimistically - this is faster + // Check for 8-bit string with a regex though, this is instant on 8-bit strings so doesn't hurt the ASCII fast path + if (nativeEncoder && !NON_LATIN.test(s)) { + try { + return encodeAscii(s, E_STRICT) + } catch {} + } + + const res = encode(s, m) + if (!res) throw new TypeError(E_STRICT) + return res + } +} + +export const latin1toString = /* @__PURE__ */ createSinglebyteDecoder('iso-8859-1') +export const latin1fromString = /* @__PURE__ */ createSinglebyteEncoder('iso-8859-1') +export const windows1252toString = /* @__PURE__ */ createSinglebyteDecoder('windows-1252') +export const windows1252fromString = /* @__PURE__ */ createSinglebyteEncoder('windows-1252') diff --git a/vanilla/node_modules/@exodus/bytes/single-byte.node.js b/vanilla/node_modules/@exodus/bytes/single-byte.node.js new file mode 100644 index 0000000..e04d942 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/single-byte.node.js @@ -0,0 +1,120 @@ +import { isAscii } from 'node:buffer' +import { assertU8, toBuf, E_STRING } from './fallback/_utils.js' +import { isDeno, isLE } from './fallback/platform.js' +import { asciiPrefix } from './fallback/latin1.js' +import { encodingMapper, encodingDecoder, encodeMap, E_STRICT } from './fallback/single-byte.js' + +function latin1Prefix(arr, start) { + let p = start | 0 + const length = arr.length + for (const len3 = length - 3; p < len3; p += 4) { + if ((arr[p] & 0xe0) === 0x80) return p + if ((arr[p + 1] & 0xe0) === 0x80) return p + 1 + if ((arr[p + 2] & 0xe0) === 0x80) return p + 2 + if ((arr[p + 3] & 0xe0) === 0x80) return p + 3 + } + + for (; p < length; p++) { + if ((arr[p] & 0xe0) === 0x80) return p + } + + return length +} + +export function createSinglebyteDecoder(encoding, loose = false) { + if (typeof loose !== 'boolean') throw new TypeError('loose option should be boolean') + if (isDeno) { + const jsDecoder = encodingDecoder(encoding) // asserts + return (arr) => { + assertU8(arr) + if (arr.byteLength === 0) return '' + if (isAscii(arr)) return toBuf(arr).toString() + return jsDecoder(arr, loose) // somewhy faster on Deno anyway, TODO: optimize? + } + } + + const isLatin1 = encoding === 'iso-8859-1' + const latin1path = encoding === 'windows-1252' + const { incomplete, mapper } = encodingMapper(encoding) // asserts + return (arr) => { + assertU8(arr) + if (arr.byteLength === 0) return '' + if (isLatin1 || isAscii(arr)) return toBuf(arr).latin1Slice() // .latin1Slice is faster than .asciiSlice + + // Node.js TextDecoder is broken, so we can't use it. It's also slow anyway + + let prefixBytes = asciiPrefix(arr) + let prefix = '' + if (latin1path) prefixBytes = latin1Prefix(arr, prefixBytes) + if (prefixBytes > 64 || prefixBytes === arr.length) { + prefix = toBuf(arr).latin1Slice(0, prefixBytes) // .latin1Slice is faster than .asciiSlice + if (prefixBytes === arr.length) return prefix + } + + const b = toBuf(mapper(arr, prefix.length)) // prefix.length can mismatch prefixBytes + if (!isLE) b.swap16() + const suffix = b.ucs2Slice(0, b.byteLength) + if (!loose && incomplete && suffix.includes('\uFFFD')) throw new TypeError(E_STRICT) + return prefix + suffix + } +} + +const NON_LATIN = /[^\x00-\xFF]/ // eslint-disable-line no-control-regex + +function encode(s, m) { + const len = s.length + let i = 0 + const b = Buffer.from(s, 'utf-16le') // aligned + if (!isLE) b.swap16() + const x = new Uint16Array(b.buffer, b.byteOffset, b.byteLength / 2) + for (const len3 = len - 3; i < len3; i += 4) { + const x0 = x[i], x1 = x[i + 1], x2 = x[i + 2], x3 = x[i + 3] // prettier-ignore + const c0 = m[x0], c1 = m[x1], c2 = m[x2], c3 = m[x3] // prettier-ignore + if (!(c0 && c1 && c2 && c3) && ((!c0 && x0) || (!c1 && x1) || (!c2 && x2) || (!c3 && x3))) return null // prettier-ignore + x[i] = c0 + x[i + 1] = c1 + x[i + 2] = c2 + x[i + 3] = c3 + } + + for (; i < len; i++) { + const x0 = x[i] + const c0 = m[x0] + if (!c0 && x0) return null + x[i] = c0 + } + + return new Uint8Array(x) +} + +export function createSinglebyteEncoder(encoding, { mode = 'fatal' } = {}) { + // TODO: replacement, truncate (replacement will need varying length) + if (mode !== 'fatal') throw new Error('Unsupported mode') + const m = encodeMap(encoding) // asserts + const isLatin1 = encoding === 'iso-8859-1' + + return (s) => { + if (typeof s !== 'string') throw new TypeError(E_STRING) + if (isLatin1) { + if (NON_LATIN.test(s)) throw new TypeError(E_STRICT) + const b = Buffer.from(s, 'latin1') + return new Uint8Array(b.buffer, b.byteOffset, b.byteLength) + } + + // Instead of an ASCII regex check, encode optimistically - this is faster + // Check for 8-bit string with a regex though, this is instant on 8-bit strings so doesn't hurt the ASCII fast path + if (!NON_LATIN.test(s)) { + const b = Buffer.from(s, 'utf8') // ascii/latin1 coerces, we need to check + if (b.length === s.length) return new Uint8Array(b.buffer, b.byteOffset, b.byteLength) + } + + const res = encode(s, m) + if (!res) throw new TypeError(E_STRICT) + return res + } +} + +export const latin1toString = /* @__PURE__ */ createSinglebyteDecoder('iso-8859-1') +export const latin1fromString = /* @__PURE__ */ createSinglebyteEncoder('iso-8859-1') +export const windows1252toString = /* @__PURE__ */ createSinglebyteDecoder('windows-1252') +export const windows1252fromString = /* @__PURE__ */ createSinglebyteEncoder('windows-1252') diff --git a/vanilla/node_modules/@exodus/bytes/utf16.browser.js b/vanilla/node_modules/@exodus/bytes/utf16.browser.js new file mode 100644 index 0000000..0c6ecbd --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/utf16.browser.js @@ -0,0 +1,8 @@ +// We trust browsers to always have correct TextDecoder for utf-16le/utf-16be with ignoreBOM without streaming + +import { encodeApi, decodeApiDecoders } from './fallback/utf16.js' + +export const utf16fromString = (str, format = 'uint16') => encodeApi(str, false, format) +export const utf16fromStringLoose = (str, format = 'uint16') => encodeApi(str, true, format) +export const utf16toString = (arr, format = 'uint16') => decodeApiDecoders(arr, false, format) +export const utf16toStringLoose = (arr, format = 'uint16') => decodeApiDecoders(arr, true, format) diff --git a/vanilla/node_modules/@exodus/bytes/utf16.d.ts b/vanilla/node_modules/@exodus/bytes/utf16.d.ts new file mode 100644 index 0000000..96a789a --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/utf16.d.ts @@ -0,0 +1,92 @@ +/** + * UTF-16 encoding/decoding + * + * ```js + * import { utf16fromString, utf16toString } from '@exodus/bytes/utf16.js' + * + * // loose + * import { utf16fromStringLoose, utf16toStringLoose } from '@exodus/bytes/utf16.js' + * ``` + * + * _These methods by design encode/decode BOM (codepoint `U+FEFF` Byte Order Mark) as-is._\ + * _If you need BOM handling or detection, use `@exodus/bytes/encoding.js`_ + * + * @module @exodus/bytes/utf16.js + */ + +/// <reference types="node" /> + +import type { Uint8ArrayBuffer, Uint16ArrayBuffer } from './array.js'; + +/** + * Output format for UTF-16 encoding + */ +export type Utf16Format = 'uint16' | 'uint8-le' | 'uint8-be'; + +/** + * Encode a string to UTF-16 bytes (strict mode) + * + * Throws on invalid Unicode (unpaired surrogates) + * + * @param string - The string to encode + * @param format - Output format (default: 'uint16') + * @returns The encoded bytes + */ +export function utf16fromString(string: string, format?: 'uint16'): Uint16ArrayBuffer; +export function utf16fromString(string: string, format: 'uint8-le'): Uint8ArrayBuffer; +export function utf16fromString(string: string, format: 'uint8-be'): Uint8ArrayBuffer; +export function utf16fromString(string: string, format?: Utf16Format): Uint16ArrayBuffer | Uint8ArrayBuffer; + +/** + * Encode a string to UTF-16 bytes (loose mode) + * + * Replaces invalid Unicode (unpaired surrogates) with replacement codepoints `U+FFFD` + * per [WHATWG Encoding](https://encoding.spec.whatwg.org/) specification. + * + * _Such replacement is a non-injective function, is irreversible and causes collisions.\ + * Prefer using strict throwing methods for cryptography applications._ + * + * @param string - The string to encode + * @param format - Output format (default: 'uint16') + * @returns The encoded bytes + */ +export function utf16fromStringLoose(string: string, format?: 'uint16'): Uint16ArrayBuffer; +export function utf16fromStringLoose(string: string, format: 'uint8-le'): Uint8ArrayBuffer; +export function utf16fromStringLoose(string: string, format: 'uint8-be'): Uint8ArrayBuffer; +export function utf16fromStringLoose(string: string, format?: Utf16Format): Uint16ArrayBuffer | Uint8ArrayBuffer; + +/** + * Decode UTF-16 bytes to a string (strict mode) + * + * Throws on invalid UTF-16 byte sequences + * + * Throws on non-even byte length. + * + * @param arr - The bytes to decode + * @param format - Input format (default: 'uint16') + * @returns The decoded string + */ +export function utf16toString(arr: Uint16Array, format?: 'uint16'): string; +export function utf16toString(arr: Uint8Array, format: 'uint8-le'): string; +export function utf16toString(arr: Uint8Array, format: 'uint8-be'): string; +export function utf16toString(arr: Uint16Array | Uint8Array, format?: Utf16Format): string; + +/** + * Decode UTF-16 bytes to a string (loose mode) + * + * Replaces invalid UTF-16 byte sequences with replacement codepoints `U+FFFD` + * per [WHATWG Encoding](https://encoding.spec.whatwg.org/) specification. + * + * _Such replacement is a non-injective function, is irreversible and causes collisions.\ + * Prefer using strict throwing methods for cryptography applications._ + * + * Throws on non-even byte length. + * + * @param arr - The bytes to decode + * @param format - Input format (default: 'uint16') + * @returns The decoded string + */ +export function utf16toStringLoose(arr: Uint16Array, format?: 'uint16'): string; +export function utf16toStringLoose(arr: Uint8Array, format: 'uint8-le'): string; +export function utf16toStringLoose(arr: Uint8Array, format: 'uint8-be'): string; +export function utf16toStringLoose(arr: Uint16Array | Uint8Array, format?: Utf16Format): string; diff --git a/vanilla/node_modules/@exodus/bytes/utf16.js b/vanilla/node_modules/@exodus/bytes/utf16.js new file mode 100644 index 0000000..3170fc0 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/utf16.js @@ -0,0 +1 @@ +export * from './utf16.native.js' diff --git a/vanilla/node_modules/@exodus/bytes/utf16.native.js b/vanilla/node_modules/@exodus/bytes/utf16.native.js new file mode 100644 index 0000000..2d94357 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/utf16.native.js @@ -0,0 +1,22 @@ +import { encodeApi, decodeApiDecoders, decodeApiJS } from './fallback/utf16.js' +import { nativeDecoder } from './fallback/platform.native.js' + +function checkDecoders() { + // Not all barebone engines with TextDecoder support something except utf-8 + // Also workerd specifically has a broken utf-16le implementation + if (!nativeDecoder) return false + try { + const a = new TextDecoder('utf-16le').decode(Uint8Array.of(1, 2, 3, 0xd8)) + const b = new TextDecoder('utf-16be').decode(Uint8Array.of(2, 1, 0xd8, 3)) + return a === b && a === '\u0201\uFFFD' + } catch {} + + return false +} + +const decode = checkDecoders() ? decodeApiDecoders : decodeApiJS + +export const utf16fromString = (str, format = 'uint16') => encodeApi(str, false, format) +export const utf16fromStringLoose = (str, format = 'uint16') => encodeApi(str, true, format) +export const utf16toString = (arr, format = 'uint16') => decode(arr, false, format) +export const utf16toStringLoose = (arr, format = 'uint16') => decode(arr, true, format) diff --git a/vanilla/node_modules/@exodus/bytes/utf16.node.js b/vanilla/node_modules/@exodus/bytes/utf16.node.js new file mode 100644 index 0000000..53183a3 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/utf16.node.js @@ -0,0 +1,70 @@ +import { assertU8, E_STRING, E_STRICT_UNICODE } from './fallback/_utils.js' +import { isDeno, isLE } from './fallback/platform.js' +import { E_STRICT, decodeApiDecoders } from './fallback/utf16.js' + +if (Buffer.TYPED_ARRAY_SUPPORT) throw new Error('Unexpected Buffer polyfill') + +const { isWellFormed, toWellFormed } = String.prototype +const to8 = (a) => new Uint8Array(a.buffer, a.byteOffset, a.byteLength) + +// Unlike utf8, operates on Uint16Arrays by default + +function encode(str, loose = false, format = 'uint16') { + if (typeof str !== 'string') throw new TypeError(E_STRING) + if (format !== 'uint16' && format !== 'uint8-le' && format !== 'uint8-be') { + throw new TypeError('Unknown format') + } + + if (loose) { + str = toWellFormed.call(str) // Buffer doesn't do this with utf16 encoding + } else if (!isWellFormed.call(str)) { + throw new TypeError(E_STRICT_UNICODE) + } + + const ble = Buffer.from(str, 'utf-16le') + + if (format === 'uint8-le') return to8(ble) + if (format === 'uint8-be') return to8(ble.swap16()) + if (format === 'uint16') { + const b = ble.byteOffset % 2 === 0 ? ble : Buffer.from(ble) // it should be already aligned, but just in case + if (!isLE) b.swap16() + return new Uint16Array(b.buffer, b.byteOffset, b.byteLength / 2) + } + + /* c8 ignore next */ + throw new Error('Unreachable') +} + +// Convert to Buffer view or a swapped Buffer copy +const swapped = (x, swap) => { + const b = Buffer.from(x.buffer, x.byteOffset, x.byteLength) + return swap ? Buffer.from(b).swap16() : b +} + +// We skip TextDecoder on Node.js, as it's is somewhy significantly slower than Buffer for utf16 +// Also, it incorrectly misses replacements with Node.js is built without ICU, we fix that +function decodeNode(input, loose = false, format = 'uint16') { + let ble + if (format === 'uint16') { + if (!(input instanceof Uint16Array)) throw new TypeError('Expected an Uint16Array') + ble = swapped(input, !isLE) + } else if (format === 'uint8-le' || format === 'uint8-be') { + assertU8(input) + if (input.byteLength % 2 !== 0) throw new TypeError('Expected even number of bytes') + ble = swapped(input, format === 'uint8-be') + } else { + throw new TypeError('Unknown format') + } + + const str = ble.ucs2Slice(0, ble.byteLength) + if (loose) return toWellFormed.call(str) + if (isWellFormed.call(str)) return str + throw new TypeError(E_STRICT) +} + +const decode = isDeno ? decodeApiDecoders : decodeNode + +export const utf16fromString = (str, format = 'uint16') => encode(str, false, format) +export const utf16fromStringLoose = (str, format = 'uint16') => encode(str, true, format) +export const utf16toString = (arr, format = 'uint16') => decode(arr, false, format) +export const utf16toStringLoose = (arr, format = 'uint16') => decode(arr, true, format) diff --git a/vanilla/node_modules/@exodus/bytes/utf8.d.ts b/vanilla/node_modules/@exodus/bytes/utf8.d.ts new file mode 100644 index 0000000..9ac1333 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/utf8.d.ts @@ -0,0 +1,96 @@ +/** + * UTF-8 encoding/decoding + * + * ```js + * import { utf8fromString, utf8toString } from '@exodus/bytes/utf8.js' + * + * // loose + * import { utf8fromStringLoose, utf8toStringLoose } from '@exodus/bytes/utf8.js' + * ``` + * + * _These methods by design encode/decode BOM (codepoint `U+FEFF` Byte Order Mark) as-is._\ + * _If you need BOM handling or detection, use `@exodus/bytes/encoding.js`_ + * + * @module @exodus/bytes/utf8.js + */ + +/// <reference types="node" /> + +import type { OutputFormat, Uint8ArrayBuffer } from './array.js'; + +/** + * Encode a string to UTF-8 bytes (strict mode) + * + * Throws on invalid Unicode (unpaired surrogates) + * + * This is similar to the following snippet (but works on all engines): + * ```js + * // Strict encode, requiring Unicode codepoints to be valid + * if (typeof string !== 'string' || !string.isWellFormed()) throw new TypeError() + * return new TextEncoder().encode(string) + * ``` + * + * @param string - The string to encode + * @param format - Output format (default: 'uint8') + * @returns The encoded bytes + */ +export function utf8fromString(string: string, format?: 'uint8'): Uint8ArrayBuffer; +export function utf8fromString(string: string, format: 'buffer'): Buffer; +export function utf8fromString(string: string, format?: OutputFormat): Uint8ArrayBuffer | Buffer; + +/** + * Encode a string to UTF-8 bytes (loose mode) + * + * Replaces invalid Unicode (unpaired surrogates) with replacement codepoints `U+FFFD` + * per [WHATWG Encoding](https://encoding.spec.whatwg.org/) specification. + * + * _Such replacement is a non-injective function, is irreversable and causes collisions.\ + * Prefer using strict throwing methods for cryptography applications._ + * + * This is similar to the following snippet (but works on all engines): + * ```js + * // Loose encode, replacing invalid Unicode codepoints with U+FFFD + * if (typeof string !== 'string') throw new TypeError() + * return new TextEncoder().encode(string) + * ``` + * + * @param string - The string to encode + * @param format - Output format (default: 'uint8') + * @returns The encoded bytes + */ +export function utf8fromStringLoose(string: string, format?: 'uint8'): Uint8ArrayBuffer; +export function utf8fromStringLoose(string: string, format: 'buffer'): Buffer; +export function utf8fromStringLoose( + string: string, + format?: OutputFormat +): Uint8ArrayBuffer | Buffer; + +/** + * Decode UTF-8 bytes to a string (strict mode) + * + * Throws on invalid UTF-8 byte sequences + * + * This is similar to `new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(arr)`, + * but works on all engines. + * + * @param arr - The bytes to decode + * @returns The decoded string + */ +export function utf8toString(arr: Uint8Array): string; + +/** + * Decode UTF-8 bytes to a string (loose mode) + * + * Replaces invalid UTF-8 byte sequences with replacement codepoints `U+FFFD` + * per [WHATWG Encoding](https://encoding.spec.whatwg.org/) specification. + * + * _Such replacement is a non-injective function, is irreversable and causes collisions.\ + * Prefer using strict throwing methods for cryptography applications._ + * + * This is similar to `new TextDecoder('utf-8', { ignoreBOM: true }).decode(arr)`, + * but works on all engines. + * + * @param arr - The bytes to decode + * @returns The decoded string + */ +export function utf8toStringLoose(arr: Uint8Array): string; diff --git a/vanilla/node_modules/@exodus/bytes/utf8.js b/vanilla/node_modules/@exodus/bytes/utf8.js new file mode 100644 index 0000000..86b0022 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/utf8.js @@ -0,0 +1,66 @@ +import { typedView } from './array.js' +import { assertU8, E_STRING, E_STRICT_UNICODE } from './fallback/_utils.js' +import { nativeDecoder, nativeEncoder } from './fallback/platform.js' +import * as js from './fallback/utf8.auto.js' + +// ignoreBOM: true means that BOM will be left as-is, i.e. will be present in the output +// We don't want to strip anything unexpectedly +const decoderLoose = nativeDecoder +const decoderFatal = nativeDecoder + ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) + : null +const { isWellFormed } = String.prototype + +function deLoose(str, loose, res) { + if (loose || str.length === res.length) return res // length is equal only for ascii, which is automatically fine + if (isWellFormed) { + // We have a fast native method + if (isWellFormed.call(str)) return res + throw new TypeError(E_STRICT_UNICODE) + } + + // Recheck if the string was encoded correctly + let start = 0 + const last = res.length - 3 + // Search for EFBFBD (3-byte sequence) + while (start <= last) { + const pos = res.indexOf(0xef, start) + if (pos === -1 || pos > last) break + start = pos + 1 + if (res[pos + 1] === 0xbf && res[pos + 2] === 0xbd) { + // Found a replacement char in output, need to recheck if we encoded the input correctly + if (js.decodeFast && !nativeDecoder && str.length < 1e7) { + // This is ~2x faster than decode in Hermes + try { + if (encodeURI(str) !== null) return res // guard against optimizing out + } catch {} + } else if (str === decode(res)) return res + throw new TypeError(E_STRICT_UNICODE) + } + } + + return res +} + +function encode(str, loose = false) { + if (typeof str !== 'string') throw new TypeError(E_STRING) + if (str.length === 0) return new Uint8Array() // faster than Uint8Array.of + if (nativeEncoder || !js.encode) return deLoose(str, loose, nativeEncoder.encode(str)) + // No reason to use unescape + encodeURIComponent: it's slower than JS on normal engines, and modern Hermes already has TextEncoder + return js.encode(str, loose) +} + +function decode(arr, loose = false) { + assertU8(arr) + if (arr.byteLength === 0) return '' + if (nativeDecoder || !js.decodeFast) { + return loose ? decoderLoose.decode(arr) : decoderFatal.decode(arr) // Node.js and browsers + } + + return js.decodeFast(arr, loose) +} + +export const utf8fromString = (str, format = 'uint8') => typedView(encode(str, false), format) +export const utf8fromStringLoose = (str, format = 'uint8') => typedView(encode(str, true), format) +export const utf8toString = (arr) => decode(arr, false) +export const utf8toStringLoose = (arr) => decode(arr, true) diff --git a/vanilla/node_modules/@exodus/bytes/utf8.node.js b/vanilla/node_modules/@exodus/bytes/utf8.node.js new file mode 100644 index 0000000..5544767 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/utf8.node.js @@ -0,0 +1,67 @@ +import { typedView } from './array.js' +import { assertU8, E_STRING, E_STRICT_UNICODE } from './fallback/_utils.js' +import { E_STRICT } from './fallback/utf8.js' +import { isAscii } from 'node:buffer' + +if (Buffer.TYPED_ARRAY_SUPPORT) throw new Error('Unexpected Buffer polyfill') + +let decoderFatal +const decoderLoose = new TextDecoder('utf-8', { ignoreBOM: true }) +const { isWellFormed } = String.prototype +const isDeno = !!globalThis.Deno + +try { + decoderFatal = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) +} catch { + // Without ICU, Node.js doesn't support fatal option for utf-8 +} + +function encode(str, loose = false) { + if (typeof str !== 'string') throw new TypeError(E_STRING) + const strLength = str.length + if (strLength === 0) return new Uint8Array() // faster than Uint8Array.of + let res + if (strLength > 0x4_00 && !isDeno) { + // Faster for large strings + const byteLength = Buffer.byteLength(str) + res = Buffer.allocUnsafe(byteLength) + const ascii = byteLength === strLength + const written = ascii ? res.latin1Write(str) : res.utf8Write(str) + if (written !== byteLength) throw new Error('Failed to write all bytes') // safeguard just in case + if (ascii || loose) return res // no further checks needed + } else { + res = Buffer.from(str) + if (res.length === strLength || loose) return res + } + + if (!isWellFormed.call(str)) throw new TypeError(E_STRICT_UNICODE) + return res +} + +function decode(arr, loose = false) { + assertU8(arr) + const byteLength = arr.byteLength + if (byteLength === 0) return '' + if (byteLength > 0x6_00 && !(isDeno && loose) && isAscii(arr)) { + // On non-ascii strings, this loses ~10% * [relative position of the first non-ascii byte] (up to 10% total) + // On ascii strings, this wins 1.5x on loose = false and 1.3x on loose = true + // Only makes sense for large enough strings + const buf = Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength) + if (isDeno) return buf.toString() // Deno suffers from .latin1Slice + return buf.latin1Slice(0, arr.byteLength) // .latin1Slice is faster than .asciiSlice + } + + if (loose) return decoderLoose.decode(arr) + if (decoderFatal) return decoderFatal.decode(arr) + + // We are in an env without native fatal decoder support (non-fixed Node.js without ICU) + // Well, just recheck against encode if it contains replacement then, this is still faster than js impl + const str = decoderLoose.decode(arr) + if (str.includes('\uFFFD') && !Buffer.from(str).equals(arr)) throw new TypeError(E_STRICT) + return str +} + +export const utf8fromString = (str, format = 'uint8') => typedView(encode(str, false), format) +export const utf8fromStringLoose = (str, format = 'uint8') => typedView(encode(str, true), format) +export const utf8toString = (arr) => decode(arr, false) +export const utf8toStringLoose = (arr) => decode(arr, true) diff --git a/vanilla/node_modules/@exodus/bytes/whatwg.d.ts b/vanilla/node_modules/@exodus/bytes/whatwg.d.ts new file mode 100644 index 0000000..b0bbed7 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/whatwg.d.ts @@ -0,0 +1,48 @@ +/** + * WHATWG helpers + * + * ```js + * import '@exodus/bytes/encoding.js' // For full legacy multi-byte encodings support + * import { percentEncodeAfterEncoding } from '@exodus/bytes/whatwg.js' + * ``` + * + * @module @exodus/bytes/whatwg.js + */ + +/** + * Implements [percent-encode after encoding](https://url.spec.whatwg.org/#string-percent-encode-after-encoding) + * per WHATWG URL specification. + * + * > [!IMPORTANT] + * > You must import `@exodus/bytes/encoding.js` for this API to accept legacy multi-byte encodings. + * + * Encodings `utf16-le`, `utf16-be`, and `replacement` are not accepted. + * + * [C0 control percent-encode set](https://url.spec.whatwg.org/#c0-control-percent-encode-set) is + * always percent-encoded. + * + * `percentEncodeSet` is an addition to that, and must be a string of unique increasing codepoints + * in range 0x20 - 0x7e, e.g. `' "#<>'`. + * + * This method accepts [DOMStrings](https://webidl.spec.whatwg.org/#idl-DOMString) and converts them + * to [USVStrings](https://webidl.spec.whatwg.org/#idl-USVString). + * This is different from e.g. `encodeURI` and `encodeURIComponent` which throw on surrogates: + * ```js + * > percentEncodeAfterEncoding('utf8', '\ud800', ' "#$%&+,/:;<=>?@[\\]^`{|}') // component + * '%EF%BF%BD' + * > encodeURIComponent('\ud800') + * Uncaught URIError: URI malformed + * ``` + * + * @param encoding - The encoding label per WHATWG Encoding spec + * @param input - Input scalar-value string to encode + * @param percentEncodeSet - A string of ASCII chars to escape in addition to C0 control percent-encode set + * @param spaceAsPlus - Whether to encode space as `'+'` instead of `'%20'` or `' '` (default: false) + * @returns The percent-encoded string + */ +export function percentEncodeAfterEncoding( + encoding: string, + input: string, + percentEncodeSet: string, + spaceAsPlus?: boolean +): string; diff --git a/vanilla/node_modules/@exodus/bytes/whatwg.js b/vanilla/node_modules/@exodus/bytes/whatwg.js new file mode 100644 index 0000000..7f4d05c --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/whatwg.js @@ -0,0 +1,80 @@ +import { utf8fromStringLoose } from '@exodus/bytes/utf8.js' +import { createSinglebyteEncoder } from '@exodus/bytes/single-byte.js' +import { + isMultibyte, + getMultibyteEncoder, + normalizeEncoding, + E_ENCODING, +} from './fallback/encoding.js' +import { percentEncoder } from './fallback/percent.js' +import { encodeMap } from './fallback/single-byte.js' +import { E_STRING } from './fallback/_utils.js' + +// https://url.spec.whatwg.org/#string-percent-encode-after-encoding +// Codepoints below 0x20, 0x7F specifically, and above 0x7F (non-ASCII) are always encoded +// > A C0 control is a code point in the range U+0000 NULL to U+001F INFORMATION SEPARATOR ONE, inclusive. +// > The C0 control percent-encode set are the C0 controls and all code points greater than U+007E (~). +export function percentEncodeAfterEncoding(encoding, input, percentEncodeSet, spaceAsPlus = false) { + const enc = normalizeEncoding(encoding) + // Ref: https://encoding.spec.whatwg.org/#get-an-encoder + if (!enc || enc === 'replacement' || enc === 'utf-16le' || enc === 'utf-16be') { + throw new RangeError(E_ENCODING) + } + + const percent = percentEncoder(percentEncodeSet, spaceAsPlus) + if (enc === 'utf-8') return percent(utf8fromStringLoose(input)) + + const multi = isMultibyte(enc) + const encoder = multi ? getMultibyteEncoder() : createSinglebyteEncoder + const fatal = encoder(enc) + try { + return percent(fatal(input)) + } catch {} + + let res = '' + let last = 0 + if (multi) { + const rep = enc === 'gb18030' ? percent(fatal('\uFFFD')) : `%26%23${0xff_fd}%3B` // only gb18030 can encode it + const escaping = encoder(enc, (cp, u, i) => { + res += percent(u, last, i) + res += cp >= 0xd8_00 && cp < 0xe0_00 ? rep : `%26%23${cp}%3B` // &#cp; + last = i + return 0 // no bytes emitted + }) + + const u = escaping(input) // has side effects on res + res += percent(u, last) + } else { + if (typeof input !== 'string') throw new TypeError(E_STRING) // all other paths have their own validation + const m = encodeMap(enc) + const len = input.length + const u = new Uint8Array(len) + for (let i = 0; i < len; i++) { + const x = input.charCodeAt(i) + const b = m[x] + if (!b && x) { + let cp = x + const i0 = i + if (x >= 0xd8_00 && x < 0xe0_00) { + cp = 0xff_fd + if (x < 0xdc_00 && i + 1 < len) { + const x1 = input.charCodeAt(i + 1) + if (x1 >= 0xdc_00 && x1 < 0xe0_00) { + cp = 0x1_00_00 + ((x1 & 0x3_ff) | ((x & 0x3_ff) << 10)) + i++ + } + } + } + + res += `${percent(u, last, i0)}%26%23${cp}%3B` // &#cp; + last = i + 1 // skip current + } else { + u[i] = b + } + } + + res += percent(u, last) + } + + return res +} diff --git a/vanilla/node_modules/@exodus/bytes/wif.d.ts b/vanilla/node_modules/@exodus/bytes/wif.d.ts new file mode 100644 index 0000000..6e038a1 --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/wif.d.ts @@ -0,0 +1,76 @@ +/** + * Wallet Import Format (WIF) encoding and decoding. + * + * ```js + * import { fromWifString, toWifString } from '@exodus/bytes/wif.js' + * import { fromWifStringSync, toWifStringSync } from '@exodus/bytes/wif.js' + * ``` + * + * On non-Node.js, requires peer dependency [@noble/hashes](https://www.npmjs.com/package/@noble/hashes) to be installed. + * + * @module @exodus/bytes/wif.js + */ + +/// <reference types="node" /> + +import type { Uint8ArrayBuffer } from './array.js'; + +/** + * WIF (Wallet Import Format) data structure + */ +export interface Wif { + /** Network version byte */ + version: number; + /** 32-byte private key */ + privateKey: Uint8ArrayBuffer; + /** Whether the key is compressed */ + compressed: boolean; +} + +/** + * Decode a WIF string to WIF data + * + * Returns a promise that resolves to an object with `{ version, privateKey, compressed }`. + * + * The optional `version` parameter validates the version byte. + * + * Throws if the WIF string is invalid or version doesn't match. + * + * @param string - The WIF encoded string + * @param version - Optional expected version byte to validate against + * @returns The decoded WIF data + * @throws Error if the WIF string is invalid or version doesn't match + */ +export function fromWifString(string: string, version?: number): Promise<Wif>; + +/** + * Decode a WIF string to WIF data (synchronous) + * + * Returns an object with `{ version, privateKey, compressed }`. + * + * The optional `version` parameter validates the version byte. + * + * Throws if the WIF string is invalid or version doesn't match. + * + * @param string - The WIF encoded string + * @param version - Optional expected version byte to validate against + * @returns The decoded WIF data + * @throws Error if the WIF string is invalid or version doesn't match + */ +export function fromWifStringSync(string: string, version?: number): Wif; + +/** + * Encode WIF data to a WIF string + * + * @param wif - The WIF data to encode + * @returns The WIF encoded string + */ +export function toWifString(wif: Wif): Promise<string>; + +/** + * Encode WIF data to a WIF string (synchronous) + * + * @param wif - The WIF data to encode + * @returns The WIF encoded string + */ +export function toWifStringSync(wif: Wif): string; diff --git a/vanilla/node_modules/@exodus/bytes/wif.js b/vanilla/node_modules/@exodus/bytes/wif.js new file mode 100644 index 0000000..690477e --- /dev/null +++ b/vanilla/node_modules/@exodus/bytes/wif.js @@ -0,0 +1,41 @@ +import { toBase58checkSync, fromBase58checkSync } from '@exodus/bytes/base58check.js' +import { assertUint8 } from './assert.js' + +// Mostly matches npmjs.com/wif, but with extra checks + using our base58check +// Also no inconsistent behavior on Buffer/Uint8Array input + +function from(arr, expectedVersion) { + assertUint8(arr) + if (arr.length !== 33 && arr.length !== 34) throw new Error('Invalid WIF length') + const version = arr[0] + if (expectedVersion !== undefined && version !== expectedVersion) { + throw new Error('Invalid network version') + } + + // Makes a copy, regardless of input being a Buffer or a Uint8Array (unlike .slice) + const privateKey = Uint8Array.from(arr.subarray(1, 33)) + if (arr.length === 33) return { version, privateKey, compressed: false } + if (arr[33] !== 1) throw new Error('Invalid compression flag') + return { version, privateKey, compressed: true } +} + +function to({ version: v, privateKey, compressed }) { + if (!Number.isSafeInteger(v) || v < 0 || v > 0xff) throw new Error('Missing or invalid version') + assertUint8(privateKey, { length: 32, name: 'privateKey' }) + const out = new Uint8Array(compressed ? 34 : 33) + out[0] = v + out.set(privateKey, 1) + if (compressed) out[33] = 1 + return out +} + +// Async performance is worse here, so expose the same internal methods as sync for now +// ./base58check is sync internally anyway for now, so doesn't matter until that is changed + +export const fromWifStringSync = (string, version) => from(fromBase58checkSync(string), version) +// export const fromWifString = async (string, version) => from(await fromBase58check(string), version) +export const fromWifString = async (string, version) => from(fromBase58checkSync(string), version) + +export const toWifStringSync = (wif) => toBase58checkSync(to(wif)) +// export const toWifString = async (wif) => toBase58check(to(wif)) +export const toWifString = async (wif) => toBase58checkSync(to(wif)) |
