UNPKG

@tensorflow/tfjs-layers

Version:

TensorFlow layers API in JavaScript

230 lines 32.7 kB
/** * @license * Copyright 2023 Google LLC. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============================================================================= */ /* Original source: keras-nlp/byte_pair_tokenizer.py */ import { Tensor, tensor } from '@tensorflow/tfjs-core'; import { ValueError } from '../../errors'; import { matchAll } from './match_all_polyfill'; import { tensorArrTo2DArr, tensorToArr } from './utils'; export function bytesToUnicode() { const inclusiveRange = (start, end) => Array.from({ length: (end - start + 1) }, (v, k) => k + start); const bs = [ ...inclusiveRange('!'.charCodeAt(0), '~'.charCodeAt(0)), ...inclusiveRange('¡'.charCodeAt(0), '¬'.charCodeAt(0)), ...inclusiveRange('®'.charCodeAt(0), 'ÿ'.charCodeAt(0)) ]; const cs = [...bs]; let n = 0; // Removes mapping an int to a whitespace character for (let b = 0; b < 2 ** 8; b++) { if (!bs.includes(b)) { bs.push(b); cs.push(2 ** 8 + n); n++; } } const chars = cs.map(n => String.fromCharCode(n)); // TODO(orderique): Verify same functionality. const bytes = Uint8Array.from(bs); return [bytes, chars]; } /** * StaticHashTable includes a `lookup` function for multiple keys at once. */ export class StaticHashTable { constructor(keys, values, defaultValue) { this.defaultValue = defaultValue; if (keys.length !== values.length) { throw new ValueError(`keys and values arrays must be same length. Instead got lengths ${keys.length} and ${values.length}.`); } const keyValPairs = []; for (let idx = 0; idx < keys.length; idx++) { const key = keys[idx]; const val = values[idx]; keyValPairs.push([key, val]); } this._map = new Map(keyValPairs); } get(key) { if (this._map.has(key)) { return this._map.get(key); } return this.defaultValue; } lookup(keys) { const values = keys.map(t => { const innerValues = []; for (const key of t.dataSync()) { innerValues.push(this.get(key)); } return tensor(innerValues, t.shape); }); return values; } } export function createStaticHashtable(keys, values, defaultVal) { return new StaticHashTable(keys, values, defaultVal); } /** * Cache that stores the encoded result of seen tokens. * * The cache key is string tensor or python strings, and the value is split * tokens joined by whitespace. For example, "dragonfly" => "dragon fly" * * Examples: * * ```js * const cache = new BytePairTokenizerCache(); * cache.insert(["butterfly", "dragonfly"], ["but ter fly", "dragon fly"]); * cache.lookup(["butterfly"]); * ``` */ export class BytePairTokenizerCache { constructor() { this._cache = new Map(); } get(key) { if (this._cache.has(key)) { return this._cache.get(key); } return ''; } /** * Insert token <=> encoded outputs pairs. */ insert(keys, values) { const arrKeys = keys instanceof Tensor ? keys.dataSync() : keys; for (const [idx, key] of arrKeys.entries()) { this._cache.set(key, values[idx]); } return this; } /** * Look up the encoded outputs of given tokens. */ lookup(keys) { const arrKeys = keys instanceof Tensor ? keys.dataSync() : keys; return arrKeys.map(key => this.get(key)); } } /** * Remove certain strings from input tensor. */ export function removeStringsFromInputs(inputs, stringToRemove) { const stringArrInputs = tensorArrTo2DArr(inputs); const filteredStrArrays = stringArrInputs .map(arr => arr.filter(s => s !== stringToRemove)); const filteredTensors = filteredStrArrays.map(arr => tensor(arr)); return filteredTensors; } /** * Create alternates for all special tokens that will be not split during * tokenization. */ export function createAltsForUnsplittableTokens(unsplittableTokens) { const prefix = 'ĵ'; // Trim out splitters. const replacePattern = /'|\s+|[^\p{L}\p{N}]+/gu; return unsplittableTokens.map(token => prefix + token.replace(replacePattern, '')); } // Typescript and TF handles special spaces differently, we need to // manually handle special spaces during string split. const SPECIAL_WHITESPACES = /\u00A0\u2009\u202f\u3000/; // String splitting regex pattern. const pL = 'a-zA-ZáàâäãåçéèêëíìîïñóòôöõúùûüýÿæœÁÀÂÄÃÅÇÉÈÊËÍÌÎÏÑÓÒÔÖÕÚÙÛÜÝŸÆŒĵ'; const pN = '0-9'; export const SPLIT_PATTERN_1 = new RegExp(`'s|'t|'re|'ve|'m|'ll|'d` + `|[\\s${SPECIAL_WHITESPACES.source}]+` + `[\\n\\r\\t\\f६${SPECIAL_WHITESPACES.source}]| ?${pL}+|` + ` ?${pN}+| ?[^\\s${pL}${pN}${SPECIAL_WHITESPACES.source}]+`, 'gu'); const SPLIT_PATTERN_2 = new RegExp(`[\\s६${SPECIAL_WHITESPACES.source}]\$`); function flatten(inputs) { return inputs.reduce((accumulator, value) => accumulator.concat(value), []); } export function regexSplit(strs, delimRegexPattern, keepDelimRegexPattern = false) { if (strs[0] instanceof Array) { const mapped = strs.map(arr => regexSplit(arr, delimRegexPattern, keepDelimRegexPattern)); return mapped.map(flatten); } strs = strs; if (!(delimRegexPattern instanceof RegExp)) { if (keepDelimRegexPattern) { delimRegexPattern = new RegExp(`(${delimRegexPattern})`); } return strs.map(str => str.split(delimRegexPattern).filter(s => s)); } const regexPattern = delimRegexPattern.flags.includes('g') ? delimRegexPattern : new RegExp(delimRegexPattern.source, delimRegexPattern.flags + 'g'); return strs.map(str => { const matches = matchAll(str, regexPattern); const splitString = []; let currIdx = 0; for (const match of matches) { splitString.push(str.slice(currIdx, match.index)); if (keepDelimRegexPattern) { splitString.push(str.slice(match.index, match.index + match[0].length)); } currIdx = match.index + match[0].length; } if (currIdx !== str.length) { splitString.push(str.slice(currIdx, str.length)); } return splitString.filter(s => s); }); } export function splitStringsForBpe(inputs, unsplittableTokens) { // We need to recreate the exact behavior of token presplitting in the // original gpt2 implementation which uses a lookahead. We are using an // alternative by inserting a special token "६" before leading space of // non-space characters and after the trailing space, e.g., // " tf" will be "६ tf". const pattern1 = new RegExp(`( )([^\s${SPECIAL_WHITESPACES}])`); const pattern2 = new RegExp(`(\s${SPECIAL_WHITESPACES})\$`); const inputsStr = tensorToArr(inputs).map(str => str.replace(pattern1, `६$1$2`).replace(pattern2, `$1६`)); let alts; let rawTokens; function escape(input) { return input.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); } if (unsplittableTokens && unsplittableTokens.length > 0) { alts = createAltsForUnsplittableTokens(unsplittableTokens); for (const [idx, token] of unsplittableTokens.entries()) { const alt = alts[idx]; const escapedToken = escape(token); rawTokens = regexSplit(rawTokens !== undefined ? rawTokens : inputsStr, escapedToken, true); rawTokens = rawTokens.map(arr => arr.map(t => t.replace(new RegExp(escapedToken), alt))); } } rawTokens = regexSplit(rawTokens !== undefined ? rawTokens : inputsStr, SPLIT_PATTERN_1, true); // Second pass splits out the last whilespace char or "६". rawTokens = regexSplit(rawTokens, SPLIT_PATTERN_2, true); if (unsplittableTokens && unsplittableTokens.length > 0) { // Replace special tokens alternate with originals. for (const [idx, token] of unsplittableTokens.entries()) { const alt = alts[idx]; const escapedAlt = escape(alt); rawTokens = rawTokens.map(arr => arr.map(t => t.replace(new RegExp(escapedAlt), token))); } } return removeStringsFromInputs(rawTokens.map(tokens => tensor(tokens)), '६'); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW5pemVyc191dGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3RmanMtbGF5ZXJzL3NyYy9sYXllcnMvbmxwL3Rva2VuaXplcnNfdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsdURBQXVEO0FBRXZELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDdkQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUMxQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFdBQVcsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUV4RCxNQUFNLFVBQVUsY0FBYztJQUM1QixNQUFNLGNBQWMsR0FBRyxDQUFDLEtBQWEsRUFBRSxHQUFXLEVBQUUsRUFBRSxDQUNwRCxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsR0FBRyxHQUFHLEtBQUssR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDO0lBRWpFLE1BQU0sRUFBRSxHQUFHO1FBQ1QsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3ZELEdBQUcsY0FBYyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN2RCxHQUFHLGNBQWMsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7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cmlnaHQgMjAyMyBHb29nbGUgTExDLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbi8qIE9yaWdpbmFsIHNvdXJjZToga2VyYXMtbmxwL2J5dGVfcGFpcl90b2tlbml6ZXIucHkgKi9cblxuaW1wb3J0IHsgVGVuc29yLCB0ZW5zb3IgfSBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuaW1wb3J0IHsgVmFsdWVFcnJvciB9IGZyb20gJy4uLy4uL2Vycm9ycyc7XG5pbXBvcnQgeyBtYXRjaEFsbCB9IGZyb20gJy4vbWF0Y2hfYWxsX3BvbHlmaWxsJztcbmltcG9ydCB7IHRlbnNvckFyclRvMkRBcnIsIHRlbnNvclRvQXJyIH0gZnJvbSAnLi91dGlscyc7XG5cbmV4cG9ydCBmdW5jdGlvbiBieXRlc1RvVW5pY29kZSgpOiBbVWludDhBcnJheSwgc3RyaW5nW11dIHtcbiAgY29uc3QgaW5jbHVzaXZlUmFuZ2UgPSAoc3RhcnQ6IG51bWJlciwgZW5kOiBudW1iZXIpID0+XG4gICAgQXJyYXkuZnJvbSh7IGxlbmd0aDogKGVuZCAtIHN0YXJ0ICsgMSkgfSwgKHYsIGspID0+IGsgKyBzdGFydCk7XG5cbiAgY29uc3QgYnMgPSBbXG4gICAgLi4uaW5jbHVzaXZlUmFuZ2UoJyEnLmNoYXJDb2RlQXQoMCksICd+Jy5jaGFyQ29kZUF0KDApKSxcbiAgICAuLi5pbmNsdXNpdmVSYW5nZSgnwqEnLmNoYXJDb2RlQXQoMCksICfCrCcuY2hhckNvZGVBdCgwKSksXG4gICAgLi4uaW5jbHVzaXZlUmFuZ2UoJ8KuJy5jaGFyQ29kZUF0KDApLCAnw78nLmNoYXJDb2RlQXQoMCkpXG4gIF07XG5cbiAgY29uc3QgY3MgPSBbLi4uYnNdO1xuICBsZXQgbiA9IDA7XG5cbiAgLy8gUmVtb3ZlcyBtYXBwaW5nIGFuIGludCB0byBhIHdoaXRlc3BhY2UgY2hhcmFjdGVyXG4gIGZvciAobGV0IGIgPSAwOyBiIDwgMiAqKiA4OyBiKyspIHtcbiAgICBpZiAoIWJzLmluY2x1ZGVzKGIpKSB7XG4gICAgICBicy5wdXNoKGIpO1xuICAgICAgY3MucHVzaCgyICoqIDggKyBuKTtcbiAgICAgIG4rKztcbiAgICB9XG4gIH1cblxuICBjb25zdCBjaGFycyA9IGNzLm1hcChuID0+IFN0cmluZy5mcm9tQ2hhckNvZGUobikpO1xuXG4gIC8vIFRPRE8ob3JkZXJpcXVlKTogVmVyaWZ5IHNhbWUgZnVuY3Rpb25hbGl0eS5cbiAgY29uc3QgYnl0ZXMgPSBVaW50OEFycmF5LmZyb20oYnMpO1xuXG4gIHJldHVybiBbYnl0ZXMsIGNoYXJzXTtcbn1cblxuLyoqXG4gKiBTdGF0aWNIYXNoVGFibGUgaW5jbHVkZXMgYSBgbG9va3VwYCBmdW5jdGlvbiBmb3IgbXVsdGlwbGUga2V5cyBhdCBvbmNlLlxuICovXG5leHBvcnQgY2xhc3MgU3RhdGljSGFzaFRhYmxlPEssIFYgZXh0ZW5kcyBudW1iZXJ8c3RyaW5nPiB7XG4gIHByaXZhdGUgX21hcDogTWFwPEssIFY+O1xuXG4gIGNvbnN0cnVjdG9yKGtleXM6IEtbXSwgdmFsdWVzOiBWW10sIHByaXZhdGUgcmVhZG9ubHkgZGVmYXVsdFZhbHVlOiBWKSB7XG4gICAgaWYgKGtleXMubGVuZ3RoICE9PSB2YWx1ZXMubGVuZ3RoKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihga2V5cyBhbmQgdmFsdWVzIGFycmF5cyBtdXN0IGJlIHNhbWUgbGVuZ3RoLlxuICAgICAgICBJbnN0ZWFkIGdvdCBsZW5ndGhzICR7a2V5cy5sZW5ndGh9IGFuZCAke3ZhbHVlcy5sZW5ndGh9LmBcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IGtleVZhbFBhaXJzOiBBcnJheTxbSywgVl0+ID0gW107XG4gICAgZm9yIChsZXQgaWR4ID0gMDsgaWR4IDwga2V5cy5sZW5ndGg7IGlkeCsrKSB7XG4gICAgICBjb25zdCBrZXkgPSBrZXlzW2lkeF07XG4gICAgICBjb25zdCB2YWwgPSB2YWx1ZXNbaWR4XTtcbiAgICAgIGtleVZhbFBhaXJzLnB1c2goW2tleSwgdmFsXSk7XG4gICAgfVxuXG4gICAgdGhpcy5fbWFwID0gbmV3IE1hcChrZXlWYWxQYWlycyk7XG4gIH1cblxuICBnZXQoa2V5OiBLKTogViB7XG4gICAgaWYgKHRoaXMuX21hcC5oYXMoa2V5KSkge1xuICAgICAgcmV0dXJuIHRoaXMuX21hcC5nZXQoa2V5KTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdFZhbHVlO1xuICB9XG5cbiAgbG9va3VwKGtleXM6IFRlbnNvcltdKTogVGVuc29yW10ge1xuICAgIGNvbnN0IHZhbHVlcyA9IGtleXMubWFwKHQgPT4ge1xuICAgICAgY29uc3QgaW5uZXJWYWx1ZXM6IFZbXSA9IFtdO1xuICAgICAgZm9yIChjb25zdCBrZXkgb2YgdC5kYXRhU3luYygpIGFzIHVua25vd24gYXMgS1tdKSB7XG4gICAgICAgIGlubmVyVmFsdWVzLnB1c2godGhpcy5nZXQoa2V5KSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0ZW5zb3IoaW5uZXJWYWx1ZXMsIHQuc2hhcGUpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHZhbHVlcztcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU3RhdGljSGFzaHRhYmxlPEssIFYgZXh0ZW5kcyBudW1iZXJ8c3RyaW5nPihcbiAga2V5czogS1tdLCB2YWx1ZXM6IFZbXSwgZGVmYXVsdFZhbDogVik6IFN0YXRpY0hhc2hUYWJsZTxLLCBWPiB7XG5cbiAgcmV0dXJuIG5ldyBTdGF0aWNIYXNoVGFibGUoa2V5cywgdmFsdWVzLCBkZWZhdWx0VmFsKTtcbn1cblxuLyoqXG4gKiBDYWNoZSB0aGF0IHN0b3JlcyB0aGUgZW5jb2RlZCByZXN1bHQgb2Ygc2VlbiB0b2tlbnMuXG4gKlxuICogVGhlIGNhY2hlIGtleSBpcyBzdHJpbmcgdGVuc29yIG9yIHB5dGhvbiBzdHJpbmdzLCBhbmQgdGhlIHZhbHVlIGlzIHNwbGl0XG4gKiB0b2tlbnMgam9pbmVkIGJ5IHdoaXRlc3BhY2UuIEZvciBleGFtcGxlLCBcImRyYWdvbmZseVwiID0+IFwiZHJhZ29uIGZseVwiXG4gKlxuICogRXhhbXBsZXM6XG4gKlxuICogYGBganNcbiAqIGNvbnN0IGNhY2hlID0gbmV3IEJ5dGVQYWlyVG9rZW5pemVyQ2FjaGUoKTtcbiAqIGNhY2hlLmluc2VydChbXCJidXR0ZXJmbHlcIiwgXCJkcmFnb25mbHlcIl0sIFtcImJ1dCB0ZXIgZmx5XCIsIFwiZHJhZ29uIGZseVwiXSk7XG4gKiBjYWNoZS5sb29rdXAoW1wiYnV0dGVyZmx5XCJdKTtcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgQnl0ZVBhaXJUb2tlbml6ZXJDYWNoZSB7XG4gIC8vIFRPRE8ob3JkZXJpcXVlKTogbW9kaWZ5IHRvIHVzZSBpZDJ2YWx1ZSBtYXAuIERlYnVnIGZvciBjb3JyZWN0IGJlaGF2aW9yLlxuICBwcml2YXRlIF9jYWNoZTogTWFwPHN0cmluZywgc3RyaW5nPjtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLl9jYWNoZSA9IG5ldyBNYXAoKTtcbiAgfVxuXG4gIGdldChrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKHRoaXMuX2NhY2hlLmhhcyhrZXkpKSB7XG4gICAgICByZXR1cm4gdGhpcy5fY2FjaGUuZ2V0KGtleSk7XG4gICAgfVxuICAgIHJldHVybiAnJztcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnQgdG9rZW4gPD0+IGVuY29kZWQgb3V0cHV0cyBwYWlycy5cbiAgICovXG4gIGluc2VydChcbiAgICBrZXlzOiBUZW5zb3J8c3RyaW5nW10sIHZhbHVlczogc3RyaW5nW10pOiBCeXRlUGFpclRva2VuaXplckNhY2hlIHtcbiAgICBjb25zdCBhcnJLZXlzID0ga2V5cyBpbnN0YW5jZW9mIFRlbnNvciA/XG4gICAgICBrZXlzLmRhdGFTeW5jKCkgYXMgdW5rbm93biBhcyBzdHJpbmdbXSA6IGtleXM7XG5cbiAgICBmb3IgKGNvbnN0IFtpZHgsIGtleV0gb2YgYXJyS2V5cy5lbnRyaWVzKCkpIHtcbiAgICAgIHRoaXMuX2NhY2hlLnNldChrZXksIHZhbHVlc1tpZHhdKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogTG9vayB1cCB0aGUgZW5jb2RlZCBvdXRwdXRzIG9mIGdpdmVuIHRva2Vucy5cbiAgICovXG4gIGxvb2t1cChrZXlzOiBUZW5zb3J8c3RyaW5nW10pOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgYXJyS2V5cyA9IGtleXMgaW5zdGFuY2VvZiBUZW5zb3IgP1xuICAgICAga2V5cy5kYXRhU3luYygpIGFzIHVua25vd24gYXMgc3RyaW5nW10gOiBrZXlzO1xuICAgIHJldHVybiBhcnJLZXlzLm1hcChrZXkgPT4gdGhpcy5nZXQoa2V5KSk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZW1vdmUgY2VydGFpbiBzdHJpbmdzIGZyb20gaW5wdXQgdGVuc29yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVtb3ZlU3RyaW5nc0Zyb21JbnB1dHMoXG4gIGlucHV0czogVGVuc29yW10sIHN0cmluZ1RvUmVtb3ZlOiBzdHJpbmcpOiBUZW5zb3JbXSB7XG5cbiAgY29uc3Qgc3RyaW5nQXJySW5wdXRzID0gdGVuc29yQXJyVG8yREFycihpbnB1dHMpIGFzIHN0cmluZ1tdW107XG4gIGNvbnN0IGZpbHRlcmVkU3RyQXJyYXlzID0gc3RyaW5nQXJySW5wdXRzXG4gICAgLm1hcChhcnIgPT4gYXJyLmZpbHRlcihzID0+IHMgIT09IHN0cmluZ1RvUmVtb3ZlKSk7XG5cbiAgY29uc3QgZmlsdGVyZWRUZW5zb3JzID0gZmlsdGVyZWRTdHJBcnJheXMubWFwKGFyciA9PiB0ZW5zb3IoYXJyKSk7XG5cbiAgcmV0dXJuIGZpbHRlcmVkVGVuc29ycztcbn1cblxuLyoqXG4gKiBDcmVhdGUgYWx0ZXJuYXRlcyBmb3IgYWxsIHNwZWNpYWwgdG9rZW5zIHRoYXQgd2lsbCBiZSBub3Qgc3BsaXQgZHVyaW5nXG4gKiB0b2tlbml6YXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVBbHRzRm9yVW5zcGxpdHRhYmxlVG9rZW5zKFxuICB1bnNwbGl0dGFibGVUb2tlbnM6IHN0cmluZ1tdKTogc3RyaW5nW10ge1xuXG4gIGNvbnN0IHByZWZpeCA9ICfEtSc7XG5cbiAgLy8gVHJpbSBvdXQgc3BsaXR0ZXJzLlxuICBjb25zdCByZXBsYWNlUGF0dGVybjogUmVnRXhwID0gLyd8XFxzK3xbXlxccHtMfVxccHtOfV0rL2d1O1xuICByZXR1cm4gdW5zcGxpdHRhYmxlVG9rZW5zLm1hcChcbiAgICB0b2tlbiA9PiBwcmVmaXggKyB0b2tlbi5yZXBsYWNlKHJlcGxhY2VQYXR0ZXJuLCAnJykpO1xufVxuXG4vLyBUeXBlc2NyaXB0IGFuZCBURiBoYW5kbGVzIHNwZWNpYWwgc3BhY2VzIGRpZmZlcmVudGx5LCB3ZSBuZWVkIHRvXG4vLyBtYW51YWxseSBoYW5kbGUgc3BlY2lhbCBzcGFjZXMgZHVyaW5nIHN0cmluZyBzcGxpdC5cbmNvbnN0IFNQRUNJQUxfV0hJVEVTUEFDRVMgPSAvXFx1MDBBMFxcdTIwMDlcXHUyMDJmXFx1MzAwMC87XG5cbi8vIFN0cmluZyBzcGxpdHRpbmcgcmVnZXggcGF0dGVybi5cbmNvbnN0IHBMID0gJ2EtekEtWsOhw6DDosOkw6PDpcOnw6nDqMOqw6vDrcOsw67Dr8Oxw7PDssO0w7bDtcO6w7nDu8O8w73Dv8OmxZPDgcOAw4LDhMODw4XDh8OJw4jDisOLw43DjMOOw4/DkcOTw5LDlMOWw5XDmsOZw5vDnMOdxbjDhsWSxLUnO1xuY29uc3QgcE4gPSAnMC05JztcbmV4cG9ydCBjb25zdCBTUExJVF9QQVRURVJOXzEgPSBuZXcgUmVnRXhwKFxuICBgJ3N8J3R8J3JlfCd2ZXwnbXwnbGx8J2RgICtcbiAgYHxbXFxcXHMke1NQRUNJQUxfV0hJVEVTUEFDRVMuc291cmNlfV0rYCArXG4gIGBbXFxcXG5cXFxcclxcXFx0XFxcXGbgpawke1NQRUNJQUxfV0hJVEVTUEFDRVMuc291cmNlfV18ID8ke3BMfSt8YCtcbiAgYCA/JHtwTn0rfCA/W15cXFxccyR7cEx9JHtwTn0ke1NQRUNJQUxfV0hJVEVTUEFDRVMuc291cmNlfV0rYCxcbiAgJ2d1J1xuKTtcblxuY29uc3QgU1BMSVRfUEFUVEVSTl8yID0gbmV3IFJlZ0V4cChgW1xcXFxz4KWsJHtTUEVDSUFMX1dISVRFU1BBQ0VTLnNvdXJjZX1dXFwkYCk7XG5cbmZ1bmN0aW9uIGZsYXR0ZW48VD4oaW5wdXRzOiBUW11bXSk6IFRbXSB7XG4gIHJldHVybiBpbnB1dHMucmVkdWNlKFxuICAgIChhY2N1bXVsYXRvciwgdmFsdWUpID0+IGFjY3VtdWxhdG9yLmNvbmNhdCh2YWx1ZSksIFtdKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlZ2V4U3BsaXQoXG4gIHN0cnM6IHN0cmluZ1tdfHN0cmluZ1tdW10sXG4gIGRlbGltUmVnZXhQYXR0ZXJuOiBSZWdFeHAgfCBzdHJpbmcsXG4gIGtlZXBEZWxpbVJlZ2V4UGF0dGVybiA9IGZhbHNlKTogc3RyaW5nW11bXSB7XG5cbiAgaWYgKHN0cnNbMF0gaW5zdGFuY2VvZiBBcnJheSkge1xuICAgIGNvbnN0IG1hcHBlZCA9IHN0cnMubWFwKGFyciA9PiByZWdleFNwbGl0KFxuICAgICAgYXJyIGFzIHN0cmluZ1tdLCBkZWxpbVJlZ2V4UGF0dGVybiwga2VlcERlbGltUmVnZXhQYXR0ZXJuKSk7XG4gICAgcmV0dXJuIG1hcHBlZC5tYXAoZmxhdHRlbik7XG4gIH1cblxuICBzdHJzID0gc3RycyBhcyBzdHJpbmdbXTtcblxuICBpZiAoIShkZWxpbVJlZ2V4UGF0dGVybiBpbnN0YW5jZW9mIFJlZ0V4cCkpIHtcbiAgICBpZiAoa2VlcERlbGltUmVnZXhQYXR0ZXJuKSB7XG4gICAgICBkZWxpbVJlZ2V4UGF0dGVybiA9IG5ldyBSZWdFeHAoYCgke2RlbGltUmVnZXhQYXR0ZXJufSlgKTtcbiAgICB9XG4gICAgcmV0dXJuIHN0cnMubWFwKHN0ciA9PiBzdHIuc3BsaXQoZGVsaW1SZWdleFBhdHRlcm4pLmZpbHRlcihzID0+IHMpKTtcbiAgfVxuXG4gIGNvbnN0IHJlZ2V4UGF0dGVybiA9IGRlbGltUmVnZXhQYXR0ZXJuLmZsYWdzLmluY2x1ZGVzKCdnJykgP1xuICAgIGRlbGltUmVnZXhQYXR0ZXJuXG4gICAgOiBuZXcgUmVnRXhwKGRlbGltUmVnZXhQYXR0ZXJuLnNvdXJjZSwgZGVsaW1SZWdleFBhdHRlcm4uZmxhZ3MgKyAnZycpO1xuXG4gIHJldHVybiBzdHJzLm1hcChzdHIgPT4ge1xuICAgIGNvbnN0IG1hdGNoZXMgPSBtYXRjaEFsbChzdHIsIHJlZ2V4UGF0dGVybik7XG5cbiAgICBjb25zdCBzcGxpdFN0cmluZyA9IFtdO1xuICAgIGxldCBjdXJySWR4ID0gMDtcbiAgICBmb3IgKGNvbnN0IG1hdGNoIG9mIG1hdGNoZXMpIHtcbiAgICAgIHNwbGl0U3RyaW5nLnB1c2goc3RyLnNsaWNlKGN1cnJJZHgsIG1hdGNoLmluZGV4KSk7XG4gICAgICBpZiAoa2VlcERlbGltUmVnZXhQYXR0ZXJuKSB7XG4gICAgICAgIHNwbGl0U3RyaW5nLnB1c2goXG4gICAgICAgICAgc3RyLnNsaWNlKG1hdGNoLmluZGV4LCBtYXRjaC5pbmRleCEgKyBtYXRjaFswXS5sZW5ndGgpKTtcbiAgICAgIH1cbiAgICAgIGN1cnJJZHggPSBtYXRjaC5pbmRleCEgKyBtYXRjaFswXS5sZW5ndGg7XG4gICAgfVxuICAgIGlmIChjdXJySWR4ICE9PSBzdHIubGVuZ3RoKSB7XG4gICAgICBzcGxpdFN0cmluZy5wdXNoKHN0ci5zbGljZShjdXJySWR4LCBzdHIubGVuZ3RoKSk7XG4gICAgfVxuICAgIHJldHVybiBzcGxpdFN0cmluZy5maWx0ZXIocyA9PiBzKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzcGxpdFN0cmluZ3NGb3JCcGUoXG4gIGlucHV0czogVGVuc29yLCB1bnNwbGl0dGFibGVUb2tlbnM/OiBzdHJpbmdbXSk6IFRlbnNvcltdIHtcblxuICAvLyBXZSBuZWVkIHRvIHJlY3JlYXRlIHRoZSBleGFjdCBiZWhhdmlvciBvZiB0b2tlbiBwcmVzcGxpdHRpbmcgaW4gdGhlXG4gIC8vIG9yaWdpbmFsIGdwdDIgaW1wbGVtZW50YXRpb24gd2hpY2ggdXNlcyBhIGxvb2thaGVhZC4gV2UgYXJlIHVzaW5nIGFuXG4gIC8vIGFsdGVybmF0aXZlIGJ5IGluc2VydGluZyBhIHNwZWNpYWwgdG9rZW4gXCLgpaxcIiBiZWZvcmUgbGVhZGluZyBzcGFjZSBvZlxuICAvLyBub24tc3BhY2UgY2hhcmFjdGVycyBhbmQgYWZ0ZXIgdGhlIHRyYWlsaW5nIHNwYWNlLCBlLmcuLFxuICAvLyBcIiB0ZlwiIHdpbGwgYmUgXCLgpawgdGZcIi5cbiAgY29uc3QgcGF0dGVybjEgPSBuZXcgUmVnRXhwKGAoICkoW15cXHMke1NQRUNJQUxfV0hJVEVTUEFDRVN9XSlgKTtcbiAgY29uc3QgcGF0dGVybjIgPSBuZXcgUmVnRXhwKGAoXFxzJHtTUEVDSUFMX1dISVRFU1BBQ0VTfSlcXCRgKTtcblxuICBjb25zdCBpbnB1dHNTdHIgPSAodGVuc29yVG9BcnIoaW5wdXRzKSBhcyBzdHJpbmdbXSkubWFwKHN0ciA9PlxuICAgIHN0ci5yZXBsYWNlKHBhdHRlcm4xLCBg4KWsJDEkMmApLnJlcGxhY2UocGF0dGVybjIsIGAkMeClrGApXG4gICk7XG5cbiAgbGV0IGFsdHM6IHN0cmluZ1tdO1xuICBsZXQgcmF3VG9rZW5zOiBzdHJpbmdbXVtdO1xuXG4gIGZ1bmN0aW9uIGVzY2FwZShpbnB1dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gaW5wdXQucmVwbGFjZSgvWy1cXC9cXFxcXiQqKz8uKCl8W1xcXXt9XS9nLCAnXFxcXCQmJyk7XG4gIH1cblxuICBpZiAodW5zcGxpdHRhYmxlVG9rZW5zICYmIHVuc3BsaXR0YWJsZVRva2Vucy5sZW5ndGggPiAwKSB7XG4gICAgYWx0cyA9IGNyZWF0ZUFsdHNGb3JVbnNwbGl0dGFibGVUb2tlbnModW5zcGxpdHRhYmxlVG9rZW5zKTtcbiAgICBmb3IgKGNvbnN0IFtpZHgsIHRva2VuXSBvZiB1bnNwbGl0dGFibGVUb2tlbnMuZW50cmllcygpKSB7XG4gICAgICBjb25zdCBhbHQgPSBhbHRzW2lkeF07XG4gICAgICBjb25zdCBlc2NhcGVkVG9rZW4gPSBlc2NhcGUodG9rZW4pO1xuXG4gICAgICByYXdUb2tlbnMgPSByZWdleFNwbGl0KHJhd1Rva2VucyAhPT0gdW5kZWZpbmVkID9cbiAgICAgICAgcmF3VG9rZW5zIDogaW5wdXRzU3RyLCBlc2NhcGVkVG9rZW4sIHRydWUpO1xuICAgICAgcmF3VG9rZW5zID0gcmF3VG9rZW5zLm1hcChcbiAgICAgICAgYXJyID0+IGFyci5tYXAodCA9PiB0LnJlcGxhY2UobmV3IFJlZ0V4cChlc2NhcGVkVG9rZW4pLCBhbHQpKSk7XG4gICAgfVxuICB9XG4gIHJhd1Rva2VucyA9IHJlZ2V4U3BsaXQocmF3VG9rZW5zICE9PSB1bmRlZmluZWQgP1xuICAgIHJhd1Rva2VucyA6IGlucHV0c1N0ciwgU1BMSVRfUEFUVEVSTl8xLCB0cnVlKTtcbiAgLy8gU2Vjb25kIHBhc3Mgc3BsaXRzIG91dCB0aGUgbGFzdCB3aGlsZXNwYWNlIGNoYXIgb3IgXCLgpaxcIi5cbiAgcmF3VG9rZW5zICA9IHJlZ2V4U3BsaXQocmF3VG9rZW5zLCBTUExJVF9QQVRURVJOXzIsIHRydWUpO1xuXG4gIGlmICh1bnNwbGl0dGFibGVUb2tlbnMgJiYgdW5zcGxpdHRhYmxlVG9rZW5zLmxlbmd0aCA+IDApIHtcbiAgICAvLyBSZXBsYWNlIHNwZWNpYWwgdG9rZW5zIGFsdGVybmF0ZSB3aXRoIG9yaWdpbmFscy5cbiAgICBmb3IgKGNvbnN0IFtpZHgsIHRva2VuXSBvZiB1bnNwbGl0dGFibGVUb2tlbnMuZW50cmllcygpKSB7XG4gICAgICBjb25zdCBhbHQgPSBhbHRzW2lkeF07XG4gICAgICBjb25zdCBlc2NhcGVkQWx0ID0gZXNjYXBlKGFsdCk7XG4gICAgICByYXdUb2tlbnMgPSByYXdUb2tlbnMubWFwKFxuICAgICAgICBhcnIgPT4gYXJyLm1hcCh0ID0+IHQucmVwbGFjZShuZXcgUmVnRXhwKGVzY2FwZWRBbHQpLCB0b2tlbikpKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcmVtb3ZlU3RyaW5nc0Zyb21JbnB1dHMocmF3VG9rZW5zLm1hcCh0b2tlbnMgPT4gdGVuc29yKHRva2VucykpLCAn4KWsJyk7XG59XG4iXX0=