gx
chenyc
2025-02-12 ea42ff3ebee1eeb3fb29423aa848a249441db81c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/**
 * @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=