UNPKG

23.2 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright 2018 Google LLC
4 *
5 * Use of this source code is governed by an MIT-style
6 * license that can be found in the LICENSE file or at
7 * https://opensource.org/licenses/MIT.
8 * =============================================================================
9 */
10/**
11 * TensorFlow.js Layers: Embedding Layer.
12 *
13 * Original source: keras/constraints.py
14 */
15import { notEqual, reshape, serialization, tidy, zerosLike } from '@tensorflow/tfjs-core';
16import * as K from '../backend/tfjs_backend';
17import { getConstraint, serializeConstraint } from '../constraints';
18import { Layer } from '../engine/topology';
19import { ValueError } from '../errors';
20import { getInitializer, serializeInitializer } from '../initializers';
21import { getRegularizer, serializeRegularizer } from '../regularizers';
22import * as generic_utils from '../utils/generic_utils';
23import { getExactlyOneShape, getExactlyOneTensor } from '../utils/types_utils';
24export class Embedding extends Layer {
25 constructor(args) {
26 super(args);
27 this.embeddings = null;
28 this.DEFAULT_EMBEDDINGS_INITIALIZER = 'randomUniform';
29 if (args.batchInputShape == null && args.inputShape == null) {
30 // Porting Note: This logic is copied from Layer's constructor, since we
31 // can't do exactly what the Python constructor does for Embedding().
32 // Specifically, the super constructor can not be called after the
33 // mutation of the `config` argument.
34 let batchSize = null;
35 if (args.batchSize != null) {
36 batchSize = args.batchSize;
37 }
38 if (args.inputLength == null) {
39 // Fix super-constructor to what it would have done if
40 // 'config.inputShape' were (None, )
41 this.batchInputShape = [batchSize, null];
42 }
43 else {
44 // Fix super-constructor to what it would have done if
45 // 'config.inputShape' were (config.inputLength, )
46 this.batchInputShape =
47 [batchSize].concat(generic_utils.toList(args.inputLength));
48 }
49 }
50 this.inputDim = args.inputDim;
51 generic_utils.assertPositiveInteger(this.inputDim, 'inputDim');
52 this.outputDim = args.outputDim;
53 generic_utils.assertPositiveInteger(this.outputDim, 'outputDim');
54 this.embeddingsInitializer = getInitializer(args.embeddingsInitializer || this.DEFAULT_EMBEDDINGS_INITIALIZER);
55 this.embeddingsRegularizer = getRegularizer(args.embeddingsRegularizer);
56 this.activityRegularizer = getRegularizer(args.activityRegularizer);
57 this.embeddingsConstraint = getConstraint(args.embeddingsConstraint);
58 this.maskZero = args.maskZero;
59 this.supportsMasking = args.maskZero;
60 this.inputLength = args.inputLength;
61 }
62 build(inputShape) {
63 this.embeddings = this.addWeight('embeddings', [this.inputDim, this.outputDim], this.dtype, this.embeddingsInitializer, this.embeddingsRegularizer, true, this.embeddingsConstraint);
64 this.built = true;
65 }
66 // Override warnOnIncompatibleInputShape because an embedding layer allows
67 // the input to have varying ranks.
68 warnOnIncompatibleInputShape(inputShape) { }
69 computeMask(inputs, mask) {
70 return tidy(() => {
71 if (!this.maskZero) {
72 return null;
73 }
74 else {
75 inputs = getExactlyOneTensor(inputs);
76 return notEqual(inputs, zerosLike(inputs));
77 }
78 });
79 }
80 computeOutputShape(inputShape) {
81 inputShape = getExactlyOneShape(inputShape);
82 if (this.inputLength == null) {
83 return [...inputShape, this.outputDim];
84 }
85 // inputLength can be an array if input is 3D or higher.
86 const inLens = generic_utils.toList(this.inputLength);
87 if (inLens.length !== inputShape.length - 1) {
88 throw new ValueError(`"inputLength" is ${this.inputLength}, but received ` +
89 `input shape has shape ${inputShape}`);
90 }
91 else {
92 let i = 0;
93 for (let k = 0; k < inLens.length; ++k) {
94 const s1 = inLens[k];
95 const s2 = inputShape[k + 1];
96 if ((s1 != null) && (s2 != null) && (s1 !== s2)) {
97 throw new ValueError(`"inputLength" is ${this.inputLength}, but received ` +
98 `input shape has shape ${inputShape}`);
99 }
100 else if (s1 == null) {
101 inLens[i] = s2;
102 }
103 i++;
104 }
105 }
106 return [inputShape[0], ...inLens, this.outputDim];
107 }
108 call(inputs, kwargs) {
109 return tidy(() => {
110 this.invokeCallHook(inputs, kwargs);
111 // Embedding layer accepts only a single input.
112 let input = getExactlyOneTensor(inputs);
113 if (input.dtype !== 'int32') {
114 input = K.cast(input, 'int32');
115 }
116 const output = K.gather(this.embeddings.read(), reshape(input, [input.size]));
117 return reshape(output, getExactlyOneShape(this.computeOutputShape(input.shape)));
118 });
119 }
120 getConfig() {
121 const config = {
122 inputDim: this.inputDim,
123 outputDim: this.outputDim,
124 embeddingsInitializer: serializeInitializer(this.embeddingsInitializer),
125 embeddingsRegularizer: serializeRegularizer(this.embeddingsRegularizer),
126 activityRegularizer: serializeRegularizer(this.activityRegularizer),
127 embeddingsConstraint: serializeConstraint(this.embeddingsConstraint),
128 maskZero: this.maskZero,
129 inputLength: this.inputLength
130 };
131 const baseConfig = super.getConfig();
132 Object.assign(config, baseConfig);
133 return config;
134 }
135}
136/** @nocollapse */
137Embedding.className = 'Embedding';
138serialization.registerClass(Embedding);
139//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1iZWRkaW5ncy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtbGF5ZXJzL3NyYy9sYXllcnMvZW1iZWRkaW5ncy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQUVIOzs7O0dBSUc7QUFDSCxPQUFPLEVBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQVUsSUFBSSxFQUFFLFNBQVMsRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBRWhHLE9BQU8sS0FBSyxDQUFDLE1BQU0seUJBQXlCLENBQUM7QUFDN0MsT0FBTyxFQUFtQyxhQUFhLEVBQUUsbUJBQW1CLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUNwRyxPQUFPLEVBQUMsS0FBSyxFQUFZLE1BQU0sb0JBQW9CLENBQUM7QUFDcEQsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLEVBQUMsY0FBYyxFQUFzQyxvQkFBb0IsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBRXpHLE9BQU8sRUFBQyxjQUFjLEVBQXNDLG9CQUFvQixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFFekcsT0FBTyxLQUFLLGFBQWEsTUFBTSx3QkFBd0IsQ0FBQztBQUN4RCxPQUFPLEVBQUMsa0JBQWtCLEVBQUUsbUJBQW1CLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQWlEN0UsTUFBTSxPQUFPLFNBQVUsU0FBUSxLQUFLO0lBZ0JsQyxZQUFZLElBQXdCO1FBQ2xDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztRQVJOLGVBQVUsR0FBa0IsSUFBSSxDQUFDO1FBRWhDLG1DQUE4QixHQUNuQyxlQUFlLENBQUM7UUFNbEIsSUFBSSxJQUFJLENBQUMsZUFBZSxJQUFJLElBQUksSUFBSSxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksRUFBRTtZQUMzRCx3RUFBd0U7WUFDeEUscUVBQXFFO1lBQ3JFLGtFQUFrRTtZQUNsRSxxQ0FBcUM7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QUFDO1FBQ0YsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ3JDLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ2xDLE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7O0FBcklELGtCQUFrQjtBQUNYLG1CQUFTLEdBQUcsV0FBVyxDQUFDO0FBc0lqQyxhQUFhLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTggR29vZ2xlIExMQ1xuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZVxuICogbGljZW5zZSB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIG9yIGF0XG4gKiBodHRwczovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL01JVC5cbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKi9cblxuLyoqXG4gKiBUZW5zb3JGbG93LmpzIExheWVyczogRW1iZWRkaW5nIExheWVyLlxuICpcbiAqIE9yaWdpbmFsIHNvdXJjZToga2VyYXMvY29uc3RyYWludHMucHlcbiAqL1xuaW1wb3J0IHtub3RFcXVhbCwgcmVzaGFwZSwgc2VyaWFsaXphdGlvbiwgVGVuc29yLCB0aWR5LCB6ZXJvc0xpa2V9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCAqIGFzIEsgZnJvbSAnLi4vYmFja2VuZC90ZmpzX2JhY2tlbmQnO1xuaW1wb3J0IHtDb25zdHJhaW50LCBDb25zdHJhaW50SWRlbnRpZmllciwgZ2V0Q29uc3RyYWludCwgc2VyaWFsaXplQ29uc3RyYWludH0gZnJvbSAnLi4vY29uc3RyYWludHMnO1xuaW1wb3J0IHtMYXllciwgTGF5ZXJBcmdzfSBmcm9tICcuLi9lbmdpbmUvdG9wb2xvZ3knO1xuaW1wb3J0IHtWYWx1ZUVycm9yfSBmcm9tICcuLi9lcnJvcnMnO1xuaW1wb3J0IHtnZXRJbml0aWFsaXplciwgSW5pdGlhbGl6ZXIsIEluaXRpYWxpemVySWRlbnRpZmllciwgc2VyaWFsaXplSW5pdGlhbGl6ZXJ9IGZyb20gJy4uL2luaXRpYWxpemVycyc7XG5pbXBvcnQge1NoYXBlfSBmcm9tICcuLi9rZXJhc19mb3JtYXQvY29tbW9uJztcbmltcG9ydCB7Z2V0UmVndWxhcml6ZXIsIFJlZ3VsYXJpemVyLCBSZWd1bGFyaXplcklkZW50aWZpZXIsIHNlcmlhbGl6ZVJlZ3VsYXJpemVyfSBmcm9tICcuLi9yZWd1bGFyaXplcnMnO1xuaW1wb3J0IHtLd2FyZ3N9IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCAqIGFzIGdlbmVyaWNfdXRpbHMgZnJvbSAnLi4vdXRpbHMvZ2VuZXJpY191dGlscyc7XG5pbXBvcnQge2dldEV4YWN0bHlPbmVTaGFwZSwgZ2V0RXhhY3RseU9uZVRlbnNvcn0gZnJvbSAnLi4vdXRpbHMvdHlwZXNfdXRpbHMnO1xuaW1wb3J0IHtMYXllclZhcmlhYmxlfSBmcm9tICcuLi92YXJpYWJsZXMnO1xuXG5leHBvcnQgZGVjbGFyZSBpbnRlcmZhY2UgRW1iZWRkaW5nTGF5ZXJBcmdzIGV4dGVuZHMgTGF5ZXJBcmdzIHtcbiAgLyoqXG4gICAqIEludGVnZXIgPiAwLiBTaXplIG9mIHRoZSB2b2NhYnVsYXJ5LCBpLmUuIG1heGltdW0gaW50ZWdlciBpbmRleCArIDEuXG4gICAqL1xuICBpbnB1dERpbTogbnVtYmVyO1xuICAvKipcbiAgICogSW50ZWdlciA+PSAwLiBEaW1lbnNpb24gb2YgdGhlIGRlbnNlIGVtYmVkZGluZy5cbiAgICovXG4gIG91dHB1dERpbTogbnVtYmVyO1xuICAvKipcbiAgICogSW5pdGlhbGl6ZXIgZm9yIHRoZSBgZW1iZWRkaW5nc2AgbWF0cml4LlxuICAgKi9cbiAgZW1iZWRkaW5nc0luaXRpYWxpemVyPzogSW5pdGlhbGl6ZXJJZGVudGlmaWVyfEluaXRpYWxpemVyO1xuICAvKipcbiAgICogUmVndWxhcml6ZXIgZnVuY3Rpb24gYXBwbGllZCB0byB0aGUgYGVtYmVkZGluZ3NgIG1hdHJpeC5cbiAgICovXG4gIGVtYmVkZGluZ3NSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVySWRlbnRpZmllcnxSZWd1bGFyaXplcjtcbiAgLyoqXG4gICAqIFJlZ3VsYXJpemVyIGZ1bmN0aW9uIGFwcGxpZWQgdG8gdGhlIGFjdGl2YXRpb24uXG4gICAqL1xuICBhY3Rpdml0eVJlZ3VsYXJpemVyPzogUmVndWxhcml6ZXJJZGVudGlmaWVyfFJlZ3VsYXJpemVyO1xuICAvKipcbiAgICogQ29uc3RyYWludCBmdW5jdGlvbiBhcHBsaWVkIHRvIHRoZSBgZW1iZWRkaW5nc2AgbWF0cml4LlxuICAgKi9cbiAgZW1iZWRkaW5nc0NvbnN0cmFpbnQ/OiBDb25zdHJhaW50SWRlbnRpZmllcnxDb25zdHJhaW50O1xuICAvKipcbiAgICogV2hldGhlciB0aGUgaW5wdXQgdmFsdWUgMCBpcyBhIHNwZWNpYWwgXCJwYWRkaW5nXCIgdmFsdWUgdGhhdCBzaG91bGQgYmVcbiAgICogbWFza2VkIG91dC4gVGhpcyBpcyB1c2VmdWwgd2hlbiB1c2luZyByZWN1cnJlbnQgbGF5ZXJzIHdoaWNoIG1heSB0YWtlXG4gICAqIHZhcmlhYmxlIGxlbmd0aCBpbnB1dC5cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgVHJ1ZWAgdGhlbiBhbGwgc3Vic2VxdWVudCBsYXllcnMgaW4gdGhlIG1vZGVsIG5lZWQgdG8gc3VwcG9ydFxuICAgKiBtYXNraW5nIG9yIGFuIGV4Y2VwdGlvbiB3aWxsIGJlIHJhaXNlZC4gSWYgbWFza1plcm8gaXMgc2V0IHRvIGBUcnVlYCwgYXMgYVxuICAgKiBjb25zZXF1ZW5jZSwgaW5kZXggMCBjYW5ub3QgYmUgdXNlZCBpbiB0aGUgdm9jYWJ1bGFyeSAoaW5wdXREaW0gc2hvdWxkXG4gICAqIGVxdWFsIHNpemUgb2Ygdm9jYWJ1bGFyeSArIDEpLlxuICAgKi9cbiAgbWFza1plcm8/OiBib29sZWFuO1xuICAvKipcbiAgICogTGVuZ3RoIG9mIGlucHV0IHNlcXVlbmNlcywgd2hlbiBpdCBpcyBjb25zdGFudC5cbiAgICpcbiAgICogVGhpcyBhcmd1bWVudCBpcyByZXF1aXJlZCBpZiB5b3UgYXJlIGdvaW5nIHRvIGNvbm5lY3QgYGZsYXR0ZW5gIHRoZW5cbiAgICogYGRlbnNlYCBsYXllcnMgdXBzdHJlYW0gKHdpdGhvdXQgaXQsIHRoZSBzaGFwZSBvZiB0aGUgZGVuc2Ugb3V0cHV0cyBjYW5ub3RcbiAgICogYmUgY29tcHV0ZWQpLlxuICAgKi9cbiAgaW5wdXRMZW5ndGg/OiBudW1iZXJ8bnVtYmVyW107XG59XG5cbmV4cG9ydCBjbGFzcyBFbWJlZGRpbmcgZXh0ZW5kcyBMYXllciB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgY2xhc3NOYW1lID0gJ0VtYmVkZGluZyc7XG4gIHByaXZhdGUgaW5wdXREaW06IG51bWJlcjtcbiAgcHJpdmF0ZSBvdXRwdXREaW06IG51bWJlcjtcbiAgcHJpdmF0ZSBlbWJlZGRpbmdzSW5pdGlhbGl6ZXI6IEluaXRpYWxpemVyO1xuICBwcml2YXRlIG1hc2taZXJvOiBib29sZWFuO1xuICBwcml2YXRlIGlucHV0TGVuZ3RoOiBudW1iZXJ8bnVtYmVyW107XG5cbiAgcHJpdmF0ZSBlbWJlZGRpbmdzOiBMYXllclZhcmlhYmxlID0gbnVsbDtcblxuICByZWFkb25seSBERUZBVUxUX0VNQkVERElOR1NfSU5JVElBTElaRVI6IEluaXRpYWxpemVySWRlbnRpZmllciA9XG4gICAgICAncmFuZG9tVW5pZm9ybSc7XG4gIHByaXZhdGUgcmVhZG9ubHkgZW1iZWRkaW5nc1JlZ3VsYXJpemVyPzogUmVndWxhcml6ZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgZW1iZWRkaW5nc0NvbnN0cmFpbnQ/OiBDb25zdHJhaW50O1xuXG4gIGNvbnN0cnVjdG9yKGFyZ3M6IEVtYmVkZGluZ0xheWVyQXJncykge1xuICAgIHN1cGVyKGFyZ3MpO1xuICAgIGlmIChhcmdzLmJhdGNoSW5wdXRTaGFwZSA9PSBudWxsICYmIGFyZ3MuaW5wdXRTaGFwZSA9PSBudWxsKSB7XG4gICAgICAvLyBQb3J0aW5nIE5vdGU6IFRoaXMgbG9naWMgaXMgY29waWVkIGZyb20gTGF5ZXIncyBjb25zdHJ1Y3Rvciwgc2luY2Ugd2VcbiAgICAgIC8vIGNhbid0IGRvIGV4YWN0bHkgd2hhdCB0aGUgUHl0aG9uIGNvbnN0cnVjdG9yIGRvZXMgZm9yIEVtYmVkZGluZygpLlxuICAgICAgLy8gU3BlY2lmaWNhbGx5LCB0aGUgc3VwZXIgY29uc3RydWN0b3IgY2FuIG5vdCBiZSBjYWxsZWQgYWZ0ZXIgdGhlXG4gICAgICAvLyBtdXRhdGlvbiBvZiB0aGUgYGNvbmZpZ2AgYXJndW1lbnQuXG4gICAgICBsZXQgYmF0Y2hTaXplOiBudW1iZXIgPSBudWxsO1xuICAgICAgaWYgKGFyZ3MuYmF0Y2hTaXplICE9IG51bGwpIHtcbiAgICAgICAgYmF0Y2hTaXplID0gYXJncy5iYXRjaFNpemU7XG4gICAgICB9XG4gICAgICBpZiAoYXJncy5pbnB1dExlbmd0aCA9PSBudWxsKSB7XG4gICAgICAgIC8vIEZpeCBzdXBlci1jb25zdHJ1Y3RvciB0byB3aGF0IGl0IHdvdWxkIGhhdmUgZG9uZSBpZlxuICAgICAgICAvLyAnY29uZmlnLmlucHV0U2hhcGUnIHdlcmUgKE5vbmUsIClcbiAgICAgICAgdGhpcy5iYXRjaElucHV0U2hhcGUgPSBbYmF0Y2hTaXplLCBudWxsXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEZpeCBzdXBlci1jb25zdHJ1Y3RvciB0byB3aGF0IGl0IHdvdWxkIGhhdmUgZG9uZSBpZlxuICAgICAgICAvLyAnY29uZmlnLmlucHV0U2hhcGUnIHdlcmUgKGNvbmZpZy5pbnB1dExlbmd0aCwgKVxuICAgICAgICB0aGlzLmJhdGNoSW5wdXRTaGFwZSA9XG4gICAgICAgICAgICBbYmF0Y2hTaXplXS5jb25jYXQoZ2VuZXJpY191dGlscy50b0xpc3QoYXJncy5pbnB1dExlbmd0aCkpO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmlucHV0RGltID0gYXJncy5pbnB1dERpbTtcbiAgICBnZW5lcmljX3V0aWxzLmFzc2VydFBvc2l0aXZlSW50ZWdlcih0aGlzLmlucHV0RGltLCAnaW5wdXREaW0nKTtcbiAgICB0aGlzLm91dHB1dERpbSA9IGFyZ3Mub3V0cHV0RGltO1xuICAgIGdlbmVyaWNfdXRpbHMuYXNzZXJ0UG9zaXRpdmVJbnRlZ2VyKHRoaXMub3V0cHV0RGltLCAnb3V0cHV0RGltJyk7XG4gICAgdGhpcy5lbWJlZGRpbmdzSW5pdGlhbGl6ZXIgPSBnZXRJbml0aWFsaXplcihcbiAgICAgICAgYXJncy5lbWJlZGRpbmdzSW5pdGlhbGl6ZXIgfHwgdGhpcy5ERUZBVUxUX0VNQkVERElOR1NfSU5JVElBTElaRVIpO1xuICAgIHRoaXMuZW1iZWRkaW5nc1JlZ3VsYXJpemVyID0gZ2V0UmVndWxhcml6ZXIoYXJncy5lbWJlZGRpbmdzUmVndWxhcml6ZXIpO1xuICAgIHRoaXMuYWN0aXZpdHlSZWd1bGFyaXplciA9IGdldFJlZ3VsYXJpemVyKGFyZ3MuYWN0aXZpdHlSZWd1bGFyaXplcik7XG4gICAgdGhpcy5lbWJlZGRpbmdzQ29uc3RyYWludCA9IGdldENvbnN0cmFpbnQoYXJncy5lbWJlZGRpbmdzQ29uc3RyYWludCk7XG4gICAgdGhpcy5tYXNrWmVybyA9IGFyZ3MubWFza1plcm87XG4gICAgdGhpcy5zdXBwb3J0c01hc2tpbmcgPSBhcmdzLm1hc2taZXJvO1xuICAgIHRoaXMuaW5wdXRMZW5ndGggPSBhcmdzLmlucHV0TGVuZ3RoO1xuICB9XG5cbiAgcHVibGljIG92ZXJyaWRlIGJ1aWxkKGlucHV0U2hhcGU6IFNoYXBlfFNoYXBlW10pOiB2b2lkIHtcbiAgICB0aGlzLmVtYmVkZGluZ3MgPSB0aGlzLmFkZFdlaWdodChcbiAgICAgICAgJ2VtYmVkZGluZ3MnLCBbdGhpcy5pbnB1dERpbSwgdGhpcy5vdXRwdXREaW1dLCB0aGlzLmR0eXBlLFxuICAgICAgICB0aGlzLmVtYmVkZGluZ3NJbml0aWFsaXplciwgdGhpcy5lbWJlZGRpbmdzUmVndWxhcml6ZXIsIHRydWUsXG4gICAgICAgIHRoaXMuZW1iZWRkaW5nc0NvbnN0cmFpbnQpO1xuICAgIHRoaXMuYnVpbHQgPSB0cnVlO1xuICB9XG5cbiAgLy8gT3ZlcnJpZGUgd2Fybk9uSW5jb21wYXRpYmxlSW5wdXRTaGFwZSBiZWNhdXNlIGFuIGVtYmVkZGluZyBsYXllciBhbGxvd3NcbiAgLy8gdGhlIGlucHV0IHRvIGhhdmUgdmFyeWluZyByYW5rcy5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHdhcm5PbkluY29tcGF0aWJsZUlucHV0U2hhcGUoaW5wdXRTaGFwZTogU2hhcGUpIHt9XG5cbiAgb3ZlcnJpZGUgY29tcHV0ZU1hc2soaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIG1hc2s/OiBUZW5zb3J8VGVuc29yW10pOlxuICAgICAgVGVuc29yIHtcbiAgICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMubWFza1plcm8pIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpbnB1dHMgPSBnZXRFeGFjdGx5T25lVGVuc29yKGlucHV0cyk7XG4gICAgICAgIHJldHVybiBub3RFcXVhbChpbnB1dHMsIHplcm9zTGlrZShpbnB1dHMpKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXB1dGVPdXRwdXRTaGFwZShpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKTogU2hhcGV8U2hhcGVbXSB7XG4gICAgaW5wdXRTaGFwZSA9IGdldEV4YWN0bHlPbmVTaGFwZShpbnB1dFNoYXBlKTtcbiAgICBpZiAodGhpcy5pbnB1dExlbmd0aCA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gWy4uLmlucHV0U2hhcGUsIHRoaXMub3V0cHV0RGltXTtcbiAgICB9XG4gICAgLy8gaW5wdXRMZW5ndGggY2FuIGJlIGFuIGFycmF5IGlmIGlucHV0IGlzIDNEIG9yIGhpZ2hlci5cbiAgICBjb25zdCBpbkxlbnM6IG51bWJlcltdID0gZ2VuZXJpY191dGlscy50b0xpc3QodGhpcy5pbnB1dExlbmd0aCk7XG4gICAgaWYgKGluTGVucy5sZW5ndGggIT09IGlucHV0U2hhcGUubGVuZ3RoIC0gMSkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFwiaW5wdXRMZW5ndGhcIiBpcyAke3RoaXMuaW5wdXRMZW5ndGh9LCBidXQgcmVjZWl2ZWQgYCArXG4gICAgICAgICAgYGlucHV0IHNoYXBlIGhhcyBzaGFwZSAke2lucHV0U2hhcGV9YCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCBpID0gMDtcbiAgICAgIGZvciAobGV0IGsgPSAwOyBrIDwgaW5MZW5zLmxlbmd0aDsgKytrKSB7XG4gICAgICAgIGNvbnN0IHMxID0gaW5MZW5zW2tdO1xuICAgICAgICBjb25zdCBzMiA9IGlucHV0U2hhcGVbayArIDFdO1xuICAgICAgICBpZiAoKHMxICE9IG51bGwpICYmIChzMiAhPSBudWxsKSAmJiAoczEgIT09IHMyKSkge1xuICAgICAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICAgICBgXCJpbnB1dExlbmd0aFwiIGlzICR7dGhpcy5pbnB1dExlbmd0aH0sIGJ1dCByZWNlaXZlZCBgICtcbiAgICAgICAgICAgICAgYGlucHV0IHNoYXBlIGhhcyBzaGFwZSAke2lucHV0U2hhcGV9YCk7XG4gICAgICAgIH0gZWxzZSBpZiAoczEgPT0gbnVsbCkge1xuICAgICAgICAgIGluTGVuc1tpXSA9IHMyO1xuICAgICAgICB9XG4gICAgICAgIGkrKztcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFtpbnB1dFNoYXBlWzBdLCAuLi5pbkxlbnMsIHRoaXMub3V0cHV0RGltXTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgICB0aGlzLmludm9rZUNhbGxIb29rKGlucHV0cywga3dhcmdzKTtcbiAgICAgIC8vIEVtYmVkZGluZyBsYXllciBhY2NlcHRzIG9ubHkgYSBzaW5nbGUgaW5wdXQuXG4gICAgICBsZXQgaW5wdXQgPSBnZXRFeGFjdGx5T25lVGVuc29yKGlucHV0cyk7XG4gICAgICBpZiAoaW5wdXQuZHR5cGUgIT09ICdpbnQzMicpIHtcbiAgICAgICAgaW5wdXQgPSBLLmNhc3QoaW5wdXQsICdpbnQzMicpO1xuICAgICAgfVxuICAgICAgY29uc3Qgb3V0cHV0ID1cbiAgICAgICAgICBLLmdhdGhlcih0aGlzLmVtYmVkZGluZ3MucmVhZCgpLCByZXNoYXBlKGlucHV0LCBbaW5wdXQuc2l6ZV0pKTtcbiAgICAgIHJldHVybiByZXNoYXBlKFxuICAgICAgICAgIG91dHB1dCwgZ2V0RXhhY3RseU9uZVNoYXBlKHRoaXMuY29tcHV0ZU91dHB1dFNoYXBlKGlucHV0LnNoYXBlKSkpO1xuICAgIH0pO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnID0ge1xuICAgICAgaW5wdXREaW06IHRoaXMuaW5wdXREaW0sXG4gICAgICBvdXRwdXREaW06IHRoaXMub3V0cHV0RGltLFxuICAgICAgZW1iZWRkaW5nc0luaXRpYWxpemVyOiBzZXJpYWxpemVJbml0aWFsaXplcih0aGlzLmVtYmVkZGluZ3NJbml0aWFsaXplciksXG4gICAgICBlbWJlZGRpbmdzUmVndWxhcml6ZXI6IHNlcmlhbGl6ZVJlZ3VsYXJpemVyKHRoaXMuZW1iZWRkaW5nc1JlZ3VsYXJpemVyKSxcbiAgICAgIGFjdGl2aXR5UmVndWxhcml6ZXI6IHNlcmlhbGl6ZVJlZ3VsYXJpemVyKHRoaXMuYWN0aXZpdHlSZWd1bGFyaXplciksXG4gICAgICBlbWJlZGRpbmdzQ29uc3RyYWludDogc2VyaWFsaXplQ29uc3RyYWludCh0aGlzLmVtYmVkZGluZ3NDb25zdHJhaW50KSxcbiAgICAgIG1hc2taZXJvOiB0aGlzLm1hc2taZXJvLFxuICAgICAgaW5wdXRMZW5ndGg6IHRoaXMuaW5wdXRMZW5ndGhcbiAgICB9O1xuICAgIGNvbnN0IGJhc2VDb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgYmFzZUNvbmZpZyk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKEVtYmVkZGluZyk7XG4iXX0=
\No newline at end of file