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 | import * as tfc from '@tensorflow/tfjs-core';
|
11 | import { Dataset, LazyIterator } from './dataset_stub';
|
12 | function mergeBatchSizeAndShape(batchSize, shape) {
|
13 | if (Array.isArray(shape)) {
|
14 | return [batchSize].concat(shape);
|
15 | }
|
16 | else {
|
17 | const output = {};
|
18 | for (const name in shape) {
|
19 | output[name] = [batchSize].concat(shape[name]);
|
20 | }
|
21 | return output;
|
22 | }
|
23 | }
|
24 | function generateRandomTensorContainer(shape) {
|
25 | let output;
|
26 | if (Array.isArray(shape)) {
|
27 | output = tfc.randomNormal(shape);
|
28 | }
|
29 | else {
|
30 | output = {};
|
31 | for (const name in shape) {
|
32 | output[name] = tfc.randomNormal(shape[name]);
|
33 | }
|
34 | }
|
35 | return output;
|
36 | }
|
37 | class FakeNumericIterator extends LazyIterator {
|
38 | constructor(args) {
|
39 | super();
|
40 | this.tensorIndex = 0;
|
41 | this.xBatchShape = mergeBatchSizeAndShape(args.batchSize, args.xShape);
|
42 | this.yBatchShape = mergeBatchSizeAndShape(args.batchSize, args.yShape);
|
43 | this.numBatches = args.numBatches;
|
44 | this.batchCount = 0;
|
45 | this.xTensorsFunc = args.xTensorsFunc;
|
46 | this.yTensorsFunc = args.yTensorsFunc;
|
47 | // Sanity check on the preset tensors.
|
48 | tfc.util.assert(this.xTensorsFunc == null && this.yTensorsFunc == null ||
|
49 | this.xTensorsFunc != null && this.yTensorsFunc != null, () => 'presetXTensors and presetYTensors must be both null/undefined ' +
|
50 | 'or both set.');
|
51 | }
|
52 | async next() {
|
53 | const done = ++this.batchCount > this.numBatches;
|
54 | if (done) {
|
55 | return { done, value: null };
|
56 | }
|
57 | if (this.xTensorsFunc == null) {
|
58 | // Generate data randomly.
|
59 | return {
|
60 | done,
|
61 | value: done ? null : {
|
62 | xs: generateRandomTensorContainer(this.xBatchShape),
|
63 | ys: generateRandomTensorContainer(this.yBatchShape)
|
64 | }
|
65 | };
|
66 | }
|
67 | else {
|
68 | // Use preset tensors.
|
69 | if ((this.batchCount - 1) % this.numBatches === 0) {
|
70 | this.xTensorValues = this.xTensorsFunc();
|
71 | this.yTensorValues = this.yTensorsFunc();
|
72 | this.tensorIndex = 0;
|
73 | }
|
74 | const index = this.tensorIndex++;
|
75 | let xs;
|
76 | if (Array.isArray(this.xTensorValues)) {
|
77 | xs = this.xTensorValues[index];
|
78 | tfc.util.assert(tfc.util.arraysEqual(xs.shape, this.xBatchShape), () => `Shape mismatch: expected: ${JSON.stringify(this.xBatchShape)}; ` +
|
79 | `actual: ${JSON.stringify(xs.shape)}`);
|
80 | }
|
81 | else {
|
82 | xs = {};
|
83 | for (const key in this.xTensorValues) {
|
84 | xs[key] = this.xTensorValues[key][index];
|
85 | tfc.util.assert(tfc.util.arraysEqual(xs[key].shape, this.xBatchShape), () => `Shape mismatch: expected: ${JSON.stringify(this.xBatchShape)}; ` +
|
86 | `actual: ${JSON.stringify(xs.shape)}`);
|
87 | }
|
88 | }
|
89 | let ys;
|
90 | if (Array.isArray(this.yTensorValues)) {
|
91 | // Get preset ys tensors for single-output models.
|
92 | ys = this.yTensorValues[index];
|
93 | tfc.util.assert(tfc.util.arraysEqual(ys.shape, this.yBatchShape), () => `Shape mismatch: expected: ${JSON.stringify(this.yBatchShape)}; ` +
|
94 | `actual: ${JSON.stringify(ys.shape)}`);
|
95 | }
|
96 | else {
|
97 | // Get preset ys tensors for multi-output models.
|
98 | ys = {};
|
99 | this.yBatchShape = this.yBatchShape;
|
100 | for (const key in this.yTensorValues) {
|
101 | ys[key] = this.yTensorValues[key][index];
|
102 | tfc.util.assert(tfc.util.arraysEqual(ys[key].shape, this.yBatchShape[key]), () => `Shape mismatch: expected: ${JSON.stringify(this.yBatchShape)}; ` +
|
103 | `actual: ${JSON.stringify(ys[key].shape)}`);
|
104 | }
|
105 | }
|
106 | return { done, value: { xs, ys } };
|
107 | }
|
108 | }
|
109 | }
|
110 | /**
|
111 | * A fake dataset with configurable feature and target shapes.
|
112 | *
|
113 | * The batch size and # of batches are also configurable.
|
114 | *
|
115 | * The iterator from the dataset always generate random-normal float32 values.
|
116 | */
|
117 | export class FakeNumericDataset extends Dataset {
|
118 | constructor(args) {
|
119 | super();
|
120 | this.args = args;
|
121 | tfc.util.assert(args.batchSize > 0 && Number.isInteger(args.batchSize), () => `batchSize must be a positive integer, but got ${args.batchSize}`);
|
122 | tfc.util.assert(args.numBatches > 0 && Number.isInteger(args.numBatches), () => `numBatches must be positive integer, but got ${args.numBatches}`);
|
123 | this.size = args.numBatches;
|
124 | }
|
125 | async iterator() {
|
126 | return new FakeNumericIterator(this.args);
|
127 | }
|
128 | }
|
129 | // We can't use Dataset.map(...) because we don't depend on tfjs-data here,
|
130 | // so we manually transform the above {xs, ys} dataset to the [xs, ys] form.
|
131 | export class FakeNumericDatasetLegacyArrayForm extends Dataset {
|
132 | constructor(args) {
|
133 | super();
|
134 | this.args = args;
|
135 | this.ds = new FakeNumericDataset(args);
|
136 | }
|
137 | async iterator() {
|
138 | const it = await this.ds.iterator();
|
139 | return new FakeNumericIteratorLegacyArrayForm(it);
|
140 | }
|
141 | }
|
142 | class FakeNumericIteratorLegacyArrayForm extends LazyIterator {
|
143 | constructor(it) {
|
144 | super();
|
145 | this.it = it;
|
146 | }
|
147 | async next() {
|
148 | const result = await this.it.next();
|
149 | return {
|
150 | done: result.done,
|
151 | value: result.value == null ? null : [result.value.xs, result.value.ys]
|
152 | };
|
153 | }
|
154 | }
|
155 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXNldF9mYWtlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtbGF5ZXJzL3NyYy9lbmdpbmUvZGF0YXNldF9mYWtlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQUVILE9BQU8sS0FBSyxHQUFHLE1BQU0sdUJBQXVCLENBQUM7QUFLN0MsT0FBTyxFQUFDLE9BQU8sRUFBRSxZQUFZLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQTJDckQsU0FBUyxzQkFBc0IsQ0FDM0IsU0FBaUIsRUFBRSxLQUFvQztJQUV6RCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUU7UUFDeEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztLQUNsQztTQUFNO1FBQ0wsTUFBTSxNQUFNLEdBQTRCLEVBQUUsQ0FBQztRQUMzQyxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRTtZQUN4QixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7U0FDaEQ7UUFDRCxPQUFPLE1BQU0sQ0FBQztLQUNmO0FBQ0gsQ0FBQztBQUVELFNBQVMsNkJBQTZCLENBQUMsS0FBb0M7SUFFekUsSUFBSSxNQUErQyxDQUFDO0lBQ3BELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUN4QixNQUFNLEdBQUcsR0FBRyxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQztLQUNsQztTQUFNO1FBQ0wsTUFBTSxHQUFHLEVBQUUsQ0FBQztRQUNaLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFO1lBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMs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RSxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztTQUN4RSxDQUFDO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTggR29vZ2xlIExMQ1xuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZVxuICogbGljZW5zZSB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIG9yIGF0XG4gKiBodHRwczovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL01JVC5cbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKi9cblxuaW1wb3J0ICogYXMgdGZjIGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCB7U2hhcGV9IGZyb20gJy4uL2tlcmFzX2Zvcm1hdC9jb21tb24nO1xuaW1wb3J0IHtUZW5zb3JPckFycmF5T3JNYXB9IGZyb20gJy4uL3R5cGVzJztcblxuaW1wb3J0IHtEYXRhc2V0LCBMYXp5SXRlcmF0b3J9IGZyb20gJy4vZGF0YXNldF9zdHViJztcbmltcG9ydCB7Rml0RGF0YXNldEVsZW1lbnR9IGZyb20gJy4vdHJhaW5pbmdfZGF0YXNldCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRmFrZURhdGFzZXRBcmdzIHtcbiAgLyoqXG4gICAqIFRoZSBzaGFwZShzKSBvZiB0aGUgZmVhdHVyZXMgb2YgYSBzaW5nbGUgZXhhbXBsZS5cbiAgICpcbiAgICogVXNlIGFuIG9iamVjdCBtYXBwaW5nIG5hbWUgdG8gc2hhcGUsIGlmIG1vcmUgdGhhbiBvbmUgZmVhdHVyZSB0ZW5zb3JzXG4gICAqIGFyZSByZXF1aXJlZC5cbiAgICovXG4gIHhTaGFwZTogU2hhcGV8e1tuYW1lOiBzdHJpbmddOiBTaGFwZX07XG5cbiAgLyoqXG4gICAqIFRoZSBzaGFwZSBvZiB0aGUgdGFyZ2V0KHMpIG9mIGEgc2luZ2xlIGV4YXBtbGUuXG4gICAqL1xuICB5U2hhcGU6IFNoYXBlfHtbbmFtZTogc3RyaW5nXTogU2hhcGV9O1xuXG4gIC8qKlxuICAgKiBBIGZ1bmN0aW9uIHRoYXQgZ2VuZXJhdGVzIHByZXNldCBzZXF1ZW5jZSBvZiBYIHRlbnNvcnMuXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gaXMgaW52b2tlZCBlYWNoIHRpbWUgYSBuZXcgaXRlcmF0b3IgaXMgY3JlYXRlZC5cbiAgICovXG4gIHhUZW5zb3JzRnVuYz86ICgpID0+IHRmYy5UZW5zb3JbXSB8IHtbbmFtZTogc3RyaW5nXTogdGZjLlRlbnNvcltdfTtcblxuICAvKipcbiAgICogQSBmdW5jdGlvbiB0aGF0IGdlbmVyYXRlcyBwcmVzZXQgc2VxdWVuY2Ugb2YgWSB0ZW5zb3JzLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGlzIGludm9rZWQgZWFjaCB0aW1lIGEgbmV3IGl0ZXJhdG9yIGlzIGNyZWF0ZWQuXG4gICAqL1xuICB5VGVuc29yc0Z1bmM/OiAoKSA9PiB0ZmMuVGVuc29yW10gfCB7W25hbWU6IHN0cmluZ106IHRmYy5UZW5zb3JbXX07XG5cbiAgLyoqXG4gICAqIFRoZSBzaXplIG9mIGVhY2ggYmF0Y2ggZ2VuZXJhdGVkIGJ5IHRoZSBpdGVyYXRvci5cbiAgICovXG4gIGJhdGNoU2l6ZTogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIGJhdGNoZXMgYW4gaXRlcmF0b3IgZ2VuZXJhdGVzIGJlZm9yZSBkZWNsYXJpbmcgZG9uZSB0byBiZVxuICAgKiB0cnVlLlxuICAgKi9cbiAgbnVtQmF0Y2hlczogbnVtYmVyO1xufVxuXG5mdW5jdGlvbiBtZXJnZUJhdGNoU2l6ZUFuZFNoYXBlKFxuICAgIGJhdGNoU2l6ZTogbnVtYmVyLCBzaGFwZTogU2hhcGV8e1tuYW1lOiBzdHJpbmddOiBTaGFwZX0pOiBTaGFwZXxcbiAgICB7W25hbWU6IHN0cmluZ106IFNoYXBlfSB7XG4gIGlmIChBcnJheS5pc0FycmF5KHNoYXBlKSkge1xuICAgIHJldHVybiBbYmF0Y2hTaXplXS5jb25jYXQoc2hhcGUpO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IG91dHB1dDoge1tuYW1lOiBzdHJpbmddOiBTaGFwZX0gPSB7fTtcbiAgICBmb3IgKGNvbnN0IG5hbWUgaW4gc2hhcGUpIHtcbiAgICAgIG91dHB1dFtuYW1lXSA9IFtiYXRjaFNpemVdLmNvbmNhdChzaGFwZVtuYW1lXSk7XG4gICAgfVxuICAgIHJldHVybiBvdXRwdXQ7XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVSYW5kb21UZW5zb3JDb250YWluZXIoc2hhcGU6IFNoYXBlfHtbbmFtZTogc3RyaW5nXTogU2hhcGV9KTpcbiAgICB0ZmMuVGVuc29yfHtbbmFtZTogc3RyaW5nXTogdGZjLlRlbnNvcn0ge1xuICBsZXQgb3V0cHV0OiB0ZmMuVGVuc29yfHtbbmFtZTogc3RyaW5nXTogdGZjLlRlbnNvcn07XG4gIGlmIChBcnJheS5pc0FycmF5KHNoYXBlKSkge1xuICAgIG91dHB1dCA9IHRmYy5yYW5kb21Ob3JtYWwoc2hhcGUpO1xuICB9IGVsc2Uge1xuICAgIG91dHB1dCA9IHt9O1xuICAgIGZvciAoY29uc3QgbmFtZSBpbiBzaGFwZSkge1xuICAgICAgb3V0cHV0W25hbWVdID0gdGZjLnJhbmRvbU5vcm1hbChzaGFwZVtuYW1lXSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBvdXRwdXQ7XG59XG5cbmNsYXNzIEZha2VOdW1lcmljSXRlcmF0b3IgZXh0ZW5kcyBMYXp5SXRlcmF0b3I8Rml0RGF0YXNldEVsZW1lbnQ+IHtcbiAgcHJpdmF0ZSB4QmF0Y2hTaGFwZTogU2hhcGV8e1tuYW1lOiBzdHJpbmddOiBTaGFwZX07XG4gIHByaXZhdGUgeUJhdGNoU2hhcGU6IFNoYXBlfHtbbmFtZTogc3RyaW5nXTogU2hhcGV9O1xuICBwcml2YXRlIG51bUJhdGNoZXM6IG51bWJlcjtcbiAgcHJpdmF0ZSBiYXRjaENvdW50OiBudW1iZXI7XG4gIHByaXZhdGUgeFRlbnNvcnNGdW5jOiAoKSA9PiB0ZmMuVGVuc29yW10gfCB7W25hbWU6IHN0cmluZ106IHRmYy5UZW5zb3JbXX07XG4gIHByaXZhdGUgeVRlbnNvcnNGdW5jOiAoKSA9PiB0ZmMuVGVuc29yW10gfCB7W25hbWU6IHN0cmluZ106IHRmYy5UZW5zb3JbXX07XG4gIHByaXZhdGUgeFRlbnNvclZhbHVlczogdGZjLlRlbnNvcltdfHtbbmFtZTogc3RyaW5nXTogdGZjLlRlbnNvcltdfTtcbiAgcHJpdmF0ZSB5VGVuc29yVmFsdWVzOiB0ZmMuVGVuc29yW118e1tuYW1lOiBzdHJpbmddOiB0ZmMuVGVuc29yW119O1xuICBwcml2YXRlIHRlbnNvckluZGV4ID0gMDtcblxuICBjb25zdHJ1Y3RvcihhcmdzOiBGYWtlRGF0YXNldEFyZ3MpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMueEJhdGNoU2hhcGUgPSBtZXJnZUJhdGNoU2l6ZUFuZFNoYXBlKGFyZ3MuYmF0Y2hTaXplLCBhcmdzLnhTaGFwZSk7XG4gICAgdGhpcy55QmF0Y2hTaGFwZSA9IG1lcmdlQmF0Y2hTaXplQW5kU2hhcGUoYXJncy5iYXRjaFNpemUsIGFyZ3MueVNoYXBlKTtcbiAgICB0aGlzLm51bUJhdGNoZXMgPSBhcmdzLm51bUJhdGNoZXM7XG4gICAgdGhpcy5iYXRjaENvdW50ID0gMDtcbiAgICB0aGlzLnhUZW5zb3JzRnVuYyA9IGFyZ3MueFRlbnNvcnNGdW5jO1xuICAgIHRoaXMueVRlbnNvcnNGdW5jID0gYXJncy55VGVuc29yc0Z1bmM7XG5cbiAgICAvLyBTYW5pdHkgY2hlY2sgb24gdGhlIHByZXNldCB0ZW5zb3JzLlxuICAgIHRmYy51dGlsLmFzc2VydChcbiAgICAgICAgdGhpcy54VGVuc29yc0Z1bmMgPT0gbnVsbCAmJiB0aGlzLnlUZW5zb3JzRnVuYyA9PSBudWxsIHx8XG4gICAgICAgICAgICB0aGlzLnhUZW5zb3JzRnVuYyAhPSBudWxsICYmIHRoaXMueVRlbnNvcnNGdW5jICE9IG51bGwsXG4gICAgICAgICgpID0+ICdwcmVzZXRYVGVuc29ycyBhbmQgcHJlc2V0WVRlbnNvcnMgbXVzdCBiZSBib3RoIG51bGwvdW5kZWZpbmVkICcgK1xuICAgICAgICAgICAgJ29yIGJvdGggc2V0LicpO1xuICB9XG5cbiAgYXN5bmMgbmV4dCgpOiBQcm9taXNlPEl0ZXJhdG9yUmVzdWx0PEZpdERhdGFzZXRFbGVtZW50Pj4ge1xuICAgIGNvbnN0IGRvbmUgPSArK3RoaXMuYmF0Y2hDb3VudCA+IHRoaXMubnVtQmF0Y2hlcztcbiAgICBpZiAoZG9uZSkge1xuICAgICAgcmV0dXJuIHtkb25lLCB2YWx1ZTogbnVsbH07XG4gICAgfVxuICAgIGlmICh0aGlzLnhUZW5zb3JzRnVuYyA9PSBudWxsKSB7XG4gICAgICAvLyBHZW5lcmF0ZSBkYXRhIHJhbmRvbWx5LlxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZG9uZSxcbiAgICAgICAgdmFsdWU6IGRvbmUgPyBudWxsIDoge1xuICAgICAgICAgIHhzOiBnZW5lcmF0ZVJhbmRvbVRlbnNvckNvbnRhaW5lcih0aGlzLnhCYXRjaFNoYXBlKSxcbiAgICAgICAgICB5czogZ2VuZXJhdGVSYW5kb21UZW5zb3JDb250YWluZXIodGhpcy55QmF0Y2hTaGFwZSlcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gVXNlIHByZXNldCB0ZW5zb3JzLlxuICAgICAgaWYgKCh0aGlzLmJhdGNoQ291bnQgLSAxKSAlIHRoaXMubnVtQmF0Y2hlcyA9PT0gMCkge1xuICAgICAgICB0aGlzLnhUZW5zb3JWYWx1ZXMgPSB0aGlzLnhUZW5zb3JzRnVuYygpO1xuICAgICAgICB0aGlzLnlUZW5zb3JWYWx1ZXMgPSB0aGlzLnlUZW5zb3JzRnVuYygpO1xuICAgICAgICB0aGlzLnRlbnNvckluZGV4ID0gMDtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy50ZW5zb3JJbmRleCsrO1xuXG4gICAgICBsZXQgeHM6IHRmYy5UZW5zb3J8e1tuYW1lOiBzdHJpbmddOiB0ZmMuVGVuc29yfTtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMueFRlbnNvclZhbHVlcykpIHtcbiAgICAgICAgeHMgPSB0aGlzLnhUZW5zb3JWYWx1ZXNbaW5kZXhdO1xuICAgICAgICB0ZmMudXRpbC5hc3NlcnQoXG4gICAgICAgICAgICB0ZmMudXRpbC5hcnJheXNFcXVhbCh4cy5zaGFwZSwgdGhpcy54QmF0Y2hTaGFwZSBhcyBTaGFwZSksXG4gICAgICAgICAgICAoKSA9PiBgU2hhcGUgbWlzbWF0Y2g6IGV4cGVjdGVkOiAke1xuICAgICAgICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHRoaXMueEJhdGNoU2hhcGUpfTsgYCArXG4gICAgICAgICAgICAgICAgYGFjdHVhbDogJHtKU09OLnN0cmluZ2lmeSgoeHMgYXMgdGZjLlRlbnNvcikuc2hhcGUpfWApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgeHMgPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gdGhpcy54VGVuc29yVmFsdWVzKSB7XG4gICAgICAgICAgeHNba2V5XSA9IHRoaXMueFRlbnNvclZhbHVlc1trZXldW2luZGV4XTtcbiAgICAgICAgICB0ZmMudXRpbC5hc3NlcnQoXG4gICAgICAgICAgICAgIHRmYy51dGlsLmFycmF5c0VxdWFsKHhzW2tleV0uc2hhcGUsIHRoaXMueEJhdGNoU2hhcGUgYXMgU2hhcGUpLFxuICAgICAgICAgICAgICAoKSA9PiBgU2hhcGUgbWlzbWF0Y2g6IGV4cGVjdGVkOiAke1xuICAgICAgICAgICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkodGhpcy54QmF0Y2hTaGFwZSl9OyBgICtcbiAgICAgICAgICAgICAgICAgIGBhY3R1YWw6ICR7SlNPTi5zdHJpbmdpZnkoKHhzIGFzIHRmYy5UZW5zb3IpLnNoYXBlKX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBsZXQgeXM6IHRmYy5UZW5zb3J8e1tuYW1lOiBzdHJpbmddOiB0ZmMuVGVuc29yfTtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMueVRlbnNvclZhbHVlcykpIHtcbiAgICAgICAgLy8gR2V0IHByZXNldCB5cyB0ZW5zb3JzIGZvciBzaW5nbGUtb3V0cHV0IG1vZGVscy5cbiAgICAgICAgeXMgPSB0aGlzLnlUZW5zb3JWYWx1ZXNbaW5kZXhdO1xuICAgICAgICB0ZmMudXRpbC5hc3NlcnQoXG4gICAgICAgICAgICB0ZmMudXRpbC5hcnJheXNFcXVhbCh5cy5zaGFwZSwgdGhpcy55QmF0Y2hTaGFwZSBhcyBTaGFwZSksXG4gICAgICAgICAgICAoKSA9PiBgU2hhcGUgbWlzbWF0Y2g6IGV4cGVjdGVkOiAke1xuICAgICAgICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHRoaXMueUJhdGNoU2hhcGUpfTsgYCArXG4gICAgICAgICAgICAgICAgYGFjdHVhbDogJHtKU09OLnN0cmluZ2lmeSgoeXMgYXMgdGZjLlRlbnNvcikuc2hhcGUpfWApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gR2V0IHByZXNldCB5cyB0ZW5zb3JzIGZvciBtdWx0aS1vdXRwdXQgbW9kZWxzLlxuICAgICAgICB5cyA9IHt9O1xuICAgICAgICB0aGlzLnlCYXRjaFNoYXBlID0gdGhpcy55QmF0Y2hTaGFwZSBhcyB7W25hbWU6IHN0cmluZ106IFNoYXBlfTtcbiAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gdGhpcy55VGVuc29yVmFsdWVzKSB7XG4gICAgICAgICAgeXNba2V5XSA9IHRoaXMueVRlbnNvclZhbHVlc1trZXldW2luZGV4XTtcbiAgICAgICAgICB0ZmMudXRpbC5hc3NlcnQoXG4gICAgICAgICAgICAgIHRmYy51dGlsLmFycmF5c0VxdWFsKHlzW2tleV0uc2hhcGUsIHRoaXMueUJhdGNoU2hhcGVba2V5XSksXG4gICAgICAgICAgICAgICgpID0+IGBTaGFwZSBtaXNtYXRjaDogZXhwZWN0ZWQ6ICR7XG4gICAgICAgICAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeSh0aGlzLnlCYXRjaFNoYXBlKX07IGAgK1xuICAgICAgICAgICAgICAgICAgYGFjdHVhbDogJHtcbiAgICAgICAgICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICh5cyBhcyB7W25hbWU6IHN0cmluZ106IHRmYy5UZW5zb3J9KVtrZXldLnNoYXBlKX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4ge2RvbmUsIHZhbHVlOiB7eHMsIHlzfX07XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQSBmYWtlIGRhdGFzZXQgd2l0aCBjb25maWd1cmFibGUgZmVhdHVyZSBhbmQgdGFyZ2V0IHNoYXBlcy5cbiAqXG4gKiBUaGUgYmF0Y2ggc2l6ZSBhbmQgIyBvZiBiYXRjaGVzIGFyZSBhbHNvIGNvbmZpZ3VyYWJsZS5cbiAqXG4gKiBUaGUgaXRlcmF0b3IgZnJvbSB0aGUgZGF0YXNldCBhbHdheXMgZ2VuZXJhdGUgcmFuZG9tLW5vcm1hbCBmbG9hdDMyIHZhbHVlcy5cbiAqL1xuZXhwb3J0IGNsYXNzIEZha2VOdW1lcmljRGF0YXNldCBleHRlbmRzIERhdGFzZXQ8Rml0RGF0YXNldEVsZW1lbnQ+IHtcbiAgY29uc3RydWN0b3IocmVhZG9ubHkgYXJnczogRmFrZURhdGFzZXRBcmdzKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0ZmMudXRpbC5hc3NlcnQoXG4gICAgICAgIGFyZ3MuYmF0Y2hTaXplID4gMCAmJiBOdW1iZXIuaXNJbnRlZ2VyKGFyZ3MuYmF0Y2hTaXplKSxcbiAgICAgICAgKCkgPT5cbiAgICAgICAgICAgIGBiYXRjaFNpemUgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXIsIGJ1dCBnb3QgJHthcmdzLmJhdGNoU2l6ZX1gKTtcbiAgICB0ZmMudXRpbC5hc3NlcnQoXG4gICAgICAgIGFyZ3MubnVtQmF0Y2hlcyA+IDAgJiYgTnVtYmVyLmlzSW50ZWdlcihhcmdzLm51bUJhdGNoZXMpLFxuICAgICAgICAoKSA9PlxuICAgICAgICAgICAgYG51bUJhdGNoZXMgbXVzdCBiZSBwb3NpdGl2ZSBpbnRlZ2VyLCBidXQgZ290ICR7YXJncy5udW1CYXRjaGVzfWApO1xuICAgIHRoaXMuc2l6ZSA9IGFyZ3MubnVtQmF0Y2hlcztcbiAgfVxuXG4gIGFzeW5jIGl0ZXJhdG9yKCk6IFByb21pc2U8TGF6eUl0ZXJhdG9yPEZpdERhdGFzZXRFbGVtZW50Pj4ge1xuICAgIHJldHVybiBuZXcgRmFrZU51bWVyaWNJdGVyYXRvcih0aGlzLmFyZ3MpO1xuICB9XG59XG5cbi8vIFdlIGNhbid0IHVzZSBEYXRhc2V0Lm1hcCguLi4pIGJlY2F1c2Ugd2UgZG9uJ3QgZGVwZW5kIG9uIHRmanMtZGF0YSBoZXJlLFxuLy8gc28gd2UgbWFudWFsbHkgdHJhbnNmb3JtIHRoZSBhYm92ZSB7eHMsIHlzfSBkYXRhc2V0IHRvIHRoZSBbeHMsIHlzXSBmb3JtLlxuZXhwb3J0IGNsYXNzIEZha2VOdW1lcmljRGF0YXNldExlZ2FjeUFycmF5Rm9ybSBleHRlbmRzXG4gICAgRGF0YXNldDxbVGVuc29yT3JBcnJheU9yTWFwLCBUZW5zb3JPckFycmF5T3JNYXBdPiB7XG4gIGRzOiBGYWtlTnVtZXJpY0RhdGFzZXQ7XG4gIGNvbnN0cnVjdG9yKHJlYWRvbmx5IGFyZ3M6IEZha2VEYXRhc2V0QXJncykge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5kcyA9IG5ldyBGYWtlTnVtZXJpY0RhdGFzZXQoYXJncyk7XG4gIH1cblxuICBhc3luYyBpdGVyYXRvcigpOlxuICAgICAgUHJvbWlzZTxMYXp5SXRlcmF0b3I8W1RlbnNvck9yQXJyYXlPck1hcCwgVGVuc29yT3JBcnJheU9yTWFwXT4+IHtcbiAgICBjb25zdCBpdCA9IGF3YWl0IHRoaXMuZHMuaXRlcmF0b3IoKTtcbiAgICByZXR1cm4gbmV3IEZha2VOdW1lcmljSXRlcmF0b3JMZWdhY3lBcnJheUZvcm0oaXQpO1xuICB9XG59XG5cbmNsYXNzIEZha2VOdW1lcmljSXRlcmF0b3JMZWdhY3lBcnJheUZvcm0gZXh0ZW5kc1xuICAgIExhenlJdGVyYXRvcjxbVGVuc29yT3JBcnJheU9yTWFwLCBUZW5zb3JPckFycmF5T3JNYXBdPiB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgaXQ6IExhenlJdGVyYXRvcjxGaXREYXRhc2V0RWxlbWVudD4pIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgYXN5bmMgbmV4dCgpOlxuICAgICAgUHJvbWlzZTxJdGVyYXRvclJlc3VsdDxbVGVuc29yT3JBcnJheU9yTWFwLCBUZW5zb3JPckFycmF5T3JNYXBdPj4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuaXQubmV4dCgpO1xuICAgIHJldHVybiB7XG4gICAgICBkb25lOiByZXN1bHQuZG9uZSxcbiAgICAgIHZhbHVlOiByZXN1bHQudmFsdWUgPT0gbnVsbCA/IG51bGwgOiBbcmVzdWx0LnZhbHVlLnhzLCByZXN1bHQudmFsdWUueXNdXG4gICAgfTtcbiAgfVxufVxuIl19 |
\ | No newline at end of file |