UNPKG

61.1 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright 2020 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 */
10var __rest = (this && this.__rest) || function (s, e) {
11 var t = {};
12 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13 t[p] = s[p];
14 if (s != null && typeof Object.getOwnPropertySymbols === "function")
15 for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16 if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17 t[p[i]] = s[p[i]];
18 }
19 return t;
20};
21import * as tfc from '@tensorflow/tfjs-core';
22import { util } from '@tensorflow/tfjs-core';
23import * as K from '../backend/tfjs_backend';
24import { checkDataFormat, checkPaddingMode } from '../common';
25import { InputSpec } from '../engine/topology';
26import { AttributeError, NotImplementedError, ValueError } from '../errors';
27import { Initializer } from '../initializers';
28import { convOutputLength, normalizeArray } from '../utils/conv_utils';
29import { assertPositiveInteger } from '../utils/generic_utils';
30import { getExactlyOneShape } from '../utils/types_utils';
31import { generateDropoutMask, LSTMCell, RNN, RNNCell } from './recurrent';
32class ConvRNN2DCell extends RNNCell {
33}
34/**
35 * Base class for convolutional-recurrent layers.
36 */
37class ConvRNN2D extends RNN {
38 constructor(args) {
39 if (args.unroll) {
40 throw new NotImplementedError('Unrolling is not possible with convolutional RNNs.');
41 }
42 if (Array.isArray(args.cell)) {
43 throw new NotImplementedError('It is not possible at the moment to stack convolutional cells.');
44 }
45 super(args);
46 this.inputSpec = [new InputSpec({ ndim: 5 })];
47 }
48 call(inputs, kwargs) {
49 return tfc.tidy(() => {
50 if (this.cell.dropoutMask != null) {
51 tfc.dispose(this.cell.dropoutMask);
52 this.cell.dropoutMask = null;
53 }
54 if (this.cell.recurrentDropoutMask != null) {
55 tfc.dispose(this.cell.recurrentDropoutMask);
56 this.cell.recurrentDropoutMask = null;
57 }
58 if (kwargs && kwargs['constants']) {
59 throw new ValueError('ConvRNN2D cell does not support constants');
60 }
61 const mask = kwargs == null ? null : kwargs['mask'];
62 const training = kwargs == null ? null : kwargs['training'];
63 const initialState = kwargs == null ? null : kwargs['initialState'];
64 return super.call(inputs, { mask, training, initialState });
65 });
66 }
67 computeOutputShape(inputShape) {
68 let outShape = this.computeSingleOutputShape(inputShape);
69 if (!this.returnSequences) {
70 outShape = [outShape[0], ...outShape.slice(2)];
71 }
72 if (this.returnState) {
73 outShape =
74 [outShape, ...Array(2).fill([inputShape[0], ...outShape.slice(-3)])];
75 }
76 return outShape;
77 }
78 getInitialState(inputs) {
79 return tfc.tidy(() => {
80 const { stateSize } = this.cell;
81 const inputShape = inputs.shape;
82 const outputShape = this.computeSingleOutputShape(inputShape);
83 const stateShape = [outputShape[0], ...outputShape.slice(2)];
84 const initialState = tfc.zeros(stateShape);
85 if (Array.isArray(stateSize)) {
86 return Array(stateSize.length).fill(initialState);
87 }
88 return [initialState];
89 });
90 }
91 resetStates(states, training = false) {
92 tfc.tidy(() => {
93 if (!this.stateful) {
94 throw new AttributeError('Cannot call resetStates() on an RNN Layer that is not stateful.');
95 }
96 const inputShape = this.inputSpec[0].shape;
97 const outputShape = this.computeSingleOutputShape(inputShape);
98 const stateShape = [outputShape[0], ...outputShape.slice(2)];
99 const batchSize = inputShape[0];
100 if (batchSize == null) {
101 throw new ValueError('If an RNN is stateful, it needs to know its batch size. Specify ' +
102 'the batch size of your input tensors: \n' +
103 '- If using a Sequential model, specify the batch size by ' +
104 'passing a `batchInputShape` option to your first layer.\n' +
105 '- If using the functional API, specify the batch size by ' +
106 'passing a `batchShape` option to your Input layer.');
107 }
108 // Initialize state if null.
109 if (this.getStates() == null) {
110 if (Array.isArray(this.cell.stateSize)) {
111 this.states_ = this.cell.stateSize.map(() => tfc.zeros(stateShape));
112 }
113 else {
114 this.states_ = [tfc.zeros(stateShape)];
115 }
116 }
117 else if (states == null) {
118 // Dispose old state tensors.
119 tfc.dispose(this.states_);
120 // For stateful RNNs, fully dispose kept old states.
121 if (this.keptStates != null) {
122 tfc.dispose(this.keptStates);
123 this.keptStates = [];
124 }
125 if (Array.isArray(this.cell.stateSize)) {
126 this.states_ = this.cell.stateSize.map(() => tfc.zeros(stateShape));
127 }
128 else {
129 this.states_[0] = tfc.zeros(stateShape);
130 }
131 }
132 else {
133 if (!Array.isArray(states)) {
134 states = [states];
135 }
136 if (states.length !== this.states_.length) {
137 throw new ValueError(`Layer ${this.name} expects ${this.states_.length} state(s), ` +
138 `but it received ${states.length} state value(s). Input ` +
139 `received: ${states}`);
140 }
141 if (training) {
142 // Store old state tensors for complete disposal later, i.e., during
143 // the next no-arg call to this method. We do not dispose the old
144 // states immediately because that BPTT (among other things) require
145 // them.
146 this.keptStates.push(this.states_.slice());
147 }
148 else {
149 tfc.dispose(this.states_);
150 }
151 for (let index = 0; index < this.states_.length; ++index) {
152 const value = states[index];
153 const expectedShape = stateShape;
154 if (!util.arraysEqual(value.shape, expectedShape)) {
155 throw new ValueError(`State ${index} is incompatible with layer ${this.name}: ` +
156 `expected shape=${expectedShape}, received shape=${value.shape}`);
157 }
158 this.states_[index] = value;
159 }
160 }
161 this.states_ = this.states_.map(state => tfc.keep(state.clone()));
162 });
163 }
164 computeSingleOutputShape(inputShape) {
165 const { dataFormat, filters, kernelSize, padding, strides, dilationRate } = this.cell;
166 const isChannelsFirst = dataFormat === 'channelsFirst';
167 const h = inputShape[isChannelsFirst ? 3 : 2];
168 const w = inputShape[isChannelsFirst ? 4 : 3];
169 const hOut = convOutputLength(h, kernelSize[0], padding, strides[0], dilationRate[0]);
170 const wOut = convOutputLength(w, kernelSize[1], padding, strides[1], dilationRate[1]);
171 const outShape = [
172 ...inputShape.slice(0, 2),
173 ...(isChannelsFirst ? [filters, hOut, wOut] : [hOut, wOut, filters])
174 ];
175 return outShape;
176 }
177}
178/** @nocollapse */
179ConvRNN2D.className = 'ConvRNN2D';
180export class ConvLSTM2DCell extends LSTMCell {
181 constructor(args) {
182 const { filters, kernelSize, strides, padding, dataFormat, dilationRate, } = args;
183 super(Object.assign(Object.assign({}, args), { units: filters }));
184 this.filters = filters;
185 assertPositiveInteger(this.filters, 'filters');
186 this.kernelSize = normalizeArray(kernelSize, 2, 'kernelSize');
187 this.kernelSize.forEach(size => assertPositiveInteger(size, 'kernelSize'));
188 this.strides = normalizeArray(strides || 1, 2, 'strides');
189 this.strides.forEach(stride => assertPositiveInteger(stride, 'strides'));
190 this.padding = padding || 'valid';
191 checkPaddingMode(this.padding);
192 this.dataFormat = dataFormat || 'channelsLast';
193 checkDataFormat(this.dataFormat);
194 this.dilationRate = normalizeArray(dilationRate || 1, 2, 'dilationRate');
195 this.dilationRate.forEach(rate => assertPositiveInteger(rate, 'dilationRate'));
196 }
197 build(inputShape) {
198 var _a;
199 inputShape = getExactlyOneShape(inputShape);
200 const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : inputShape.length - 1;
201 if (inputShape[channelAxis] == null) {
202 throw new ValueError(`The channel dimension of the input should be defined. ` +
203 `Found ${inputShape[channelAxis]}`);
204 }
205 const inputDim = inputShape[channelAxis];
206 const numOfKernels = 4;
207 const kernelShape = this.kernelSize.concat([inputDim, this.filters * numOfKernels]);
208 this.kernel = this.addWeight('kernel', kernelShape, null, this.kernelInitializer, this.kernelRegularizer, true, this.kernelConstraint);
209 const recurrentKernelShape = this.kernelSize.concat([this.filters, this.filters * numOfKernels]);
210 this.recurrentKernel = this.addWeight('recurrent_kernel', recurrentKernelShape, null, this.recurrentInitializer, this.recurrentRegularizer, true, this.recurrentConstraint);
211 if (this.useBias) {
212 let biasInitializer;
213 if (this.unitForgetBias) {
214 const init = this.biasInitializer;
215 const filters = this.filters;
216 biasInitializer = new (_a = class CustomInit extends Initializer {
217 apply(shape, dtype) {
218 const biasI = init.apply([filters]);
219 const biasF = tfc.ones([filters]);
220 const biasCAndO = init.apply([filters * 2]);
221 return K.concatenate([biasI, biasF, biasCAndO]);
222 }
223 },
224 /** @nocollapse */
225 _a.className = 'CustomInit',
226 _a)();
227 }
228 else {
229 biasInitializer = this.biasInitializer;
230 }
231 this.bias = this.addWeight('bias', [this.filters * numOfKernels], null, biasInitializer, this.biasRegularizer, true, this.biasConstraint);
232 }
233 this.built = true;
234 }
235 call(inputs, kwargs) {
236 return tfc.tidy(() => {
237 if (inputs.length !== 3) {
238 throw new ValueError(`ConvLSTM2DCell expects 3 input Tensors (inputs, h, c), got ` +
239 `${inputs.length}.`);
240 }
241 const training = kwargs['training'] || false;
242 const x = inputs[0]; // Current input
243 const hTMinus1 = inputs[1]; // Previous memory state.
244 const cTMinus1 = inputs[2]; // Previous carry state.
245 const numOfKernels = 4;
246 if (0 < this.dropout && this.dropout < 1 && this.dropoutMask == null) {
247 this.dropoutMask = generateDropoutMask({
248 ones: () => tfc.onesLike(x),
249 rate: this.dropout,
250 training,
251 count: numOfKernels,
252 dropoutFunc: this.dropoutFunc
253 });
254 }
255 const dropoutMask = this.dropoutMask;
256 const applyDropout = (x, mask, index) => {
257 if (!mask || !mask[index]) {
258 return x;
259 }
260 return tfc.mul(mask[index], x);
261 };
262 let xI = applyDropout(x, dropoutMask, 0);
263 let xF = applyDropout(x, dropoutMask, 1);
264 let xC = applyDropout(x, dropoutMask, 2);
265 let xO = applyDropout(x, dropoutMask, 3);
266 if (0 < this.recurrentDropout && this.recurrentDropout < 1 &&
267 this.recurrentDropoutMask == null) {
268 this.recurrentDropoutMask = generateDropoutMask({
269 ones: () => tfc.onesLike(hTMinus1),
270 rate: this.recurrentDropout,
271 training,
272 count: numOfKernels,
273 dropoutFunc: this.dropoutFunc
274 });
275 }
276 const recDropoutMask = this.recurrentDropoutMask;
277 let hI = applyDropout(hTMinus1, recDropoutMask, 0);
278 let hF = applyDropout(hTMinus1, recDropoutMask, 1);
279 let hC = applyDropout(hTMinus1, recDropoutMask, 2);
280 let hO = applyDropout(hTMinus1, recDropoutMask, 3);
281 const kernelChannelAxis = 3;
282 const [kernelI, kernelF, kernelC, kernelO] = tfc.split(this.kernel.read(), numOfKernels, kernelChannelAxis);
283 const [biasI, biasF, biasC, biasO] = this.useBias ?
284 tfc.split(this.bias.read(), numOfKernels) :
285 [null, null, null, null];
286 xI = this.inputConv(xI, kernelI, biasI, this.padding);
287 xF = this.inputConv(xF, kernelF, biasF, this.padding);
288 xC = this.inputConv(xC, kernelC, biasC, this.padding);
289 xO = this.inputConv(xO, kernelO, biasO, this.padding);
290 const [recKernelI, recKernelF, recKernelC, recKernelO] = tfc.split(this.recurrentKernel.read(), numOfKernels, kernelChannelAxis);
291 hI = this.recurrentConv(hI, recKernelI);
292 hF = this.recurrentConv(hF, recKernelF);
293 hC = this.recurrentConv(hC, recKernelC);
294 hO = this.recurrentConv(hO, recKernelO);
295 const i = this.recurrentActivation.apply(tfc.add(xI, hI));
296 const f = this.recurrentActivation.apply(tfc.add(xF, hF));
297 const c = tfc.add(tfc.mul(f, cTMinus1), tfc.mul(i, this.activation.apply(tfc.add(xC, hC))));
298 const h = tfc.mul(this.recurrentActivation.apply(tfc.add(xO, hO)), this.activation.apply(c));
299 return [h, h, c];
300 });
301 }
302 getConfig() {
303 const _a = super.getConfig(), { 'units': _ } = _a, baseConfig = __rest(_a, ['units']);
304 const config = {
305 filters: this.filters,
306 kernelSize: this.kernelSize,
307 padding: this.padding,
308 dataFormat: this.dataFormat,
309 dilationRate: this.dilationRate,
310 strides: this.strides,
311 };
312 return Object.assign(Object.assign({}, baseConfig), config);
313 }
314 inputConv(x, w, b, padding) {
315 const out = tfc.conv2d(x, w, this.strides, (padding || 'valid'), this.dataFormat === 'channelsFirst' ? 'NCHW' : 'NHWC', this.dilationRate);
316 if (b) {
317 return K.biasAdd(out, b, this.dataFormat);
318 }
319 return out;
320 }
321 recurrentConv(x, w) {
322 const strides = 1;
323 return tfc.conv2d(x, w, strides, 'same', this.dataFormat === 'channelsFirst' ? 'NCHW' : 'NHWC');
324 }
325}
326/** @nocollapse */
327ConvLSTM2DCell.className = 'ConvLSTM2DCell';
328tfc.serialization.registerClass(ConvLSTM2DCell);
329export class ConvLSTM2D extends ConvRNN2D {
330 constructor(args) {
331 const cell = new ConvLSTM2DCell(args);
332 super(Object.assign(Object.assign({}, args), { cell }));
333 }
334 /** @nocollapse */
335 static fromConfig(cls, config) {
336 return new cls(config);
337 }
338}
339/** @nocollapse */
340ConvLSTM2D.className = 'ConvLSTM2D';
341tfc.serialization.registerClass(ConvLSTM2D);
342//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udm9sdXRpb25hbF9yZWN1cnJlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi90ZmpzLWxheWVycy9zcmMvbGF5ZXJzL2NvbnZvbHV0aW9uYWxfcmVjdXJyZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHOzs7Ozs7Ozs7Ozs7QUFFSCxPQUFPLEtBQUssR0FBRyxNQUFNLHVCQUF1QixDQUFDO0FBQzdDLE9BQU8sRUFBUyxJQUFJLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUduRCxPQUFPLEtBQUssQ0FBQyxNQUFNLHlCQUF5QixDQUFDO0FBQzdDLE9BQU8sRUFBQyxlQUFlLEVBQUUsZ0JBQWdCLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFFNUQsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLG9CQUFvQixDQUFDO0FBQzdDLE9BQU8sRUFBQyxjQUFjLEVBQUUsbUJBQW1CLEVBQUUsVUFBVSxFQUFDLE1BQU0sV0FBVyxDQUFDO0FBQzFFLE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUk1QyxPQUFPLEVBQUMsZ0JBQWdCLEVBQUUsY0FBYyxFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFDckUsT0FBTyxFQUFDLHFCQUFxQixFQUFDLE1BQU0sd0JBQXdCLENBQUM7QUFDN0QsT0FBTyxFQUFDLGtCQUFrQixFQUFDLE1BQU0sc0JBQXNCLENBQUM7QUFFeEQsT0FBTyxFQUFtQixtQkFBbUIsRUFBRSxRQUFRLEVBQW9DLEdBQUcsRUFBRSxPQUFPLEVBQXVDLE1BQU0sYUFBYSxDQUFDO0FBc0RsSyxNQUFlLGFBQWMsU0FBUSxPQUFPO0NBeUIzQztBQUtEOztHQUVHO0FBQ0gsTUFBTSxTQUFVLFNBQVEsR0FBRztJQU16QixZQUFZLElBQXdCO1FBQ2xDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNmLE1BQU0sSUFBSSxtQkFBbUIsQ0FDekIsb0RBQW9ELENBQUMsQ0FB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Q0FDdEIsR0FBaUQsRUFDakQsTUFBb0M7UUFDdEMsT0FBTyxJQUFJLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN6QixDQUFDOztBQWRELGtCQUFrQjtBQUNGLG9CQUFTLEdBQUcsWUFBWSxDQUFDO0FBZ0IzQyxHQUFHLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCAyMDIwIEdvb2dsZSBMTENcbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGVcbiAqIGxpY2Vuc2UgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBvciBhdFxuICogaHR0cHM6Ly9vcGVuc291cmNlLm9yZy9saWNlbnNlcy9NSVQuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbmltcG9ydCAqIGFzIHRmYyBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuaW1wb3J0IHtUZW5zb3IsIHV0aWx9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCB7QWN0aXZhdGlvbn0gZnJvbSAnLi4vYWN0aXZhdGlvbnMnO1xuaW1wb3J0ICogYXMgSyBmcm9tICcuLi9iYWNrZW5kL3RmanNfYmFja2VuZCc7XG5pbXBvcnQge2NoZWNrRGF0YUZvcm1hdCwgY2hlY2tQYWRkaW5nTW9kZX0gZnJvbSAnLi4vY29tbW9uJztcbmltcG9ydCB7Q29uc3RyYWludH0gZnJvbSAnLi4vY29uc3RyYWludHMnO1xuaW1wb3J0IHtJbnB1dFNwZWN9IGZyb20gJy4uL2VuZ2luZS90b3BvbG9neSc7XG5pbXBvcnQge0F0dHJpYnV0ZUVycm9yLCBOb3RJbXBsZW1lbnRlZEVycm9yLCBWYWx1ZUVycm9yfSBmcm9tICcuLi9lcnJvcnMnO1xuaW1wb3J0IHtJbml0aWFsaXplcn0gZnJvbSAnLi4vaW5pdGlhbGl6ZXJzJztcbmltcG9ydCB7RGF0YUZvcm1hdCwgRGF0YVR5cGUsIFBhZGRpbmdNb2RlLCBTaGFwZX0gZnJvbSAnLi4va2VyYXNfZm9ybWF0L2NvbW1vbic7XG5pbXBvcnQge1JlZ3VsYXJpemVyfSBmcm9tICcuLi9yZWd1bGFyaXplcnMnO1xuaW1wb3J0IHtLd2FyZ3N9IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCB7Y29udk91dHB1dExlbmd0aCwgbm9ybWFsaXplQXJyYXl9IGZyb20gJy4uL3V0aWxzL2NvbnZfdXRpbHMnO1xuaW1wb3J0IHthc3NlcnRQb3NpdGl2ZUludGVnZXJ9IGZyb20gJy4uL3V0aWxzL2dlbmVyaWNfdXRpbHMnO1xuaW1wb3J0IHtnZXRFeGFjdGx5T25lU2hhcGV9IGZyb20gJy4uL3V0aWxzL3R5cGVzX3V0aWxzJztcblxuaW1wb3J0IHtCYXNlUk5OTGF5ZXJBcmdzLCBnZW5lcmF0ZURyb3BvdXRNYXNrLCBMU1RNQ2VsbCwgTFNUTUNlbGxMYXllckFyZ3MsIExTVE1MYXllckFyZ3MsIFJOTiwgUk5OQ2VsbCwgUk5OTGF5ZXJBcmdzLCBTaW1wbGVSTk5DZWxsTGF5ZXJBcmdzfSBmcm9tICcuL3JlY3VycmVudCc7XG5cbmRlY2xhcmUgaW50ZXJmYWNlIENvbnZSTk4yRENlbGxBcmdzIGV4dGVuZHNcbiAgICBPbWl0PFNpbXBsZVJOTkNlbGxMYXllckFyZ3MsICd1bml0cyc+IHtcbiAgLyoqXG4gICAqIFRoZSBkaW1lbnNpb25hbGl0eSBvZiB0aGUgb3V0cHV0IHNwYWNlIChpLmUuIHRoZSBudW1iZXIgb2YgZmlsdGVycyBpbiB0aGVcbiAgICogY29udm9sdXRpb24pLlxuICAgKi9cbiAgZmlsdGVyczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgZGltZW5zaW9ucyBvZiB0aGUgY29udm9sdXRpb24gd2luZG93LiBJZiBrZXJuZWxTaXplIGlzIGEgbnVtYmVyLCB0aGVcbiAgICogY29udm9sdXRpb25hbCB3aW5kb3cgd2lsbCBiZSBzcXVhcmUuXG4gICAqL1xuICBrZXJuZWxTaXplOiBudW1iZXJ8bnVtYmVyW107XG5cbiAgLyoqXG4gICAqIFRoZSBzdHJpZGVzIG9mIHRoZSBjb252b2x1dGlvbiBpbiBlYWNoIGRpbWVuc2lvbi4gSWYgc3RyaWRlcyBpcyBhIG51bWJlcixcbiAgICogc3RyaWRlcyBpbiBib3RoIGRpbWVuc2lvbnMgYXJlIGVxdWFsLlxuICAgKlxuICAgKiBTcGVjaWZ5aW5nIGFueSBzdHJpZGUgdmFsdWUgIT0gMSBpcyBpbmNvbXBhdGlibGUgd2l0aCBzcGVjaWZ5aW5nIGFueVxuICAgKiBgZGlsYXRpb25SYXRlYCB2YWx1ZSAhPSAxLlxuICAgKi9cbiAgc3RyaWRlcz86IG51bWJlcnxudW1iZXJbXTtcblxuICAvKipcbiAgICogUGFkZGluZyBtb2RlLlxuICAgKi9cbiAgcGFkZGluZz86IFBhZGRpbmdNb2RlO1xuXG4gIC8qKlxuICAgKiBGb3JtYXQgb2YgdGhlIGRhdGEsIHdoaWNoIGRldGVybWluZXMgdGhlIG9yZGVyaW5nIG9mIHRoZSBkaW1lbnNpb25zIGluXG4gICAqIHRoZSBpbnB1dHMuXG4gICAqXG4gICAqIGBjaGFubmVsc19sYXN0YCBjb3JyZXNwb25kcyB0byBpbnB1dHMgd2l0aCBzaGFwZVxuICAgKiAgIGAoYmF0Y2gsIC4uLiwgY2hhbm5lbHMpYFxuICAgKlxuICAgKiAgYGNoYW5uZWxzX2ZpcnN0YCBjb3JyZXNwb25kcyB0byBpbnB1dHMgd2l0aCBzaGFwZSBgKGJhdGNoLCBjaGFubmVscyxcbiAgICogLi4uKWAuXG4gICAqXG4gICAqIERlZmF1bHRzIHRvIGBjaGFubmVsc19sYXN0YC5cbiAgICovXG4gIGRhdGFGb3JtYXQ/OiBEYXRhRm9ybWF0O1xuXG4gIC8qKlxuICAgKiBUaGUgZGlsYXRpb24gcmF0ZSB0byB1c2UgZm9yIHRoZSBkaWxhdGVkIGNvbnZvbHV0aW9uIGluIGVhY2ggZGltZW5zaW9uLlxuICAgKiBTaG91bGQgYmUgYW4gaW50ZWdlciBvciBhcnJheSBvZiB0d28gb3IgdGhyZWUgaW50ZWdlcnMuXG4gICAqXG4gICAqIEN1cnJlbnRseSwgc3BlY2lmeWluZyBhbnkgYGRpbGF0aW9uUmF0ZWAgdmFsdWUgIT0gMSBpcyBpbmNvbXBhdGlibGUgd2l0aFxuICAgKiBzcGVjaWZ5aW5nIGFueSBgc3RyaWRlc2AgdmFsdWUgIT0gMS5cbiAgICovXG4gIGRpbGF0aW9uUmF0ZT86IG51bWJlcnxbbnVtYmVyXXxbbnVtYmVyLCBudW1iZXJdO1xufVxuXG5hYnN0cmFjdCBjbGFzcyBDb252Uk5OMkRDZWxsIGV4dGVuZHMgUk5OQ2VsbCB7XG4gIHJlYWRvbmx5IGZpbHRlcnM6IG51bWJlcjtcbiAgcmVhZG9ubHkga2VybmVsU2l6ZTogbnVtYmVyW107XG4gIHJlYWRvbmx5IHN0cmlkZXM6IG51bWJlcltdO1xuICByZWFkb25seSBwYWRkaW5nOiBQYWRkaW5nTW9kZTtcbiAgcmVhZG9ubHkgZGF0YUZvcm1hdDogRGF0YUZvcm1hdDtcbiAgcmVhZG9ubHkgZGlsYXRpb25SYXRlOiBudW1iZXJbXTtcblxuICByZWFkb25seSBhY3RpdmF0aW9uOiBBY3RpdmF0aW9uO1xuICByZWFkb25seSB1c2VCaWFzOiBib29sZWFuO1xuXG4gIHJlYWRvbmx5IGtlcm5lbEluaXRpYWxpemVyOiBJbml0aWFsaXplcjtcbiAgcmVhZG9ubHkgcmVjdXJyZW50SW5pdGlhbGl6ZXI6IEluaXRpYWxpemVyO1xuICByZWFkb25seSBiaWFzSW5pdGlhbGl6ZXI6IEluaXRpYWxpemVyO1xuXG4gIHJlYWRvbmx5IGtlcm5lbENvbnN0cmFpbnQ6IENvbnN0cmFpbnQ7XG4gIHJlYWRvbmx5IHJlY3VycmVudENvbnN0cmFpbnQ6IENvbnN0cmFpbnQ7XG4gIHJlYWRvbmx5IGJpYXNDb25zdHJhaW50OiBDb25zdHJhaW50O1xuXG4gIHJlYWRvbmx5IGtlcm5lbFJlZ3VsYXJpemVyOiBSZWd1bGFyaXplcjtcbiAgcmVhZG9ubHkgcmVjdXJyZW50UmVndWxhcml6ZXI6IFJlZ3VsYXJpemVyO1xuICByZWFkb25seSBiaWFzUmVndWxhcml6ZXI6IFJlZ3VsYXJpemVyO1xuXG4gIHJlYWRvbmx5IGRyb3BvdXQ6IG51bWJlcjtcbiAgcmVhZG9ubHkgcmVjdXJyZW50RHJvcG91dDogbnVtYmVyO1xufVxuXG5kZWNsYXJlIGludGVyZmFjZSBDb252Uk5OMkRMYXllckFyZ3MgZXh0ZW5kcyBCYXNlUk5OTGF5ZXJBcmdzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29udlJOTjJEQ2VsbEFyZ3Mge31cblxuLyoqXG4gKiBCYXNlIGNsYXNzIGZvciBjb252b2x1dGlvbmFsLXJlY3VycmVudCBsYXllcnMuXG4gKi9cbmNsYXNzIENvbnZSTk4yRCBleHRlbmRzIFJOTiB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgb3ZlcnJpZGUgY2xhc3NOYW1lID0gJ0NvbnZSTk4yRCc7XG5cbiAgZGVjbGFyZSByZWFkb25seSBjZWxsOiBDb252Uk5OMkRDZWxsO1xuXG4gIGNvbnN0cnVjdG9yKGFyZ3M6IENvbnZSTk4yRExheWVyQXJncykge1xuICAgIGlmIChhcmdzLnVucm9sbCkge1xuICAgICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoXG4gICAgICAgICAgJ1Vucm9sbGluZyBpcyBub3QgcG9zc2libGUgd2l0aCBjb252b2x1dGlvbmFsIFJOTnMuJyk7XG4gICAgfVxuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoYXJncy5jZWxsKSkge1xuICAgICAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoXG4gICAgICAgICAgJ0l0IGlzIG5vdCBwb3NzaWJsZSBhdCB0aGUgbW9tZW50IHRvIHN0YWNrIGNvbnZvbHV0aW9uYWwgY2VsbHMuJyk7XG4gICAgfVxuXG4gICAgc3VwZXIoYXJncyBhcyBSTk5MYXllckFyZ3MpO1xuXG4gICAgdGhpcy5pbnB1dFNwZWMgPSBbbmV3IElucHV0U3BlYyh7bmRpbTogNX0pXTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICByZXR1cm4gdGZjLnRpZHkoKCkgPT4ge1xuICAgICAgaWYgKHRoaXMuY2VsbC5kcm9wb3V0TWFzayAhPSBudWxsKSB7XG4gICAgICAgIHRmYy5kaXNwb3NlKHRoaXMuY2VsbC5kcm9wb3V0TWFzayk7XG5cbiAgICAgICAgdGhpcy5jZWxsLmRyb3BvdXRNYXNrID0gbnVsbDtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuY2VsbC5yZWN1cnJlbnREcm9wb3V0TWFzayAhPSBudWxsKSB7XG4gICAgICAgIHRmYy5kaXNwb3NlKHRoaXMuY2VsbC5yZWN1cnJlbnREcm9wb3V0TWFzayk7XG5cbiAgICAgICAgdGhpcy5jZWxsLnJlY3VycmVudERyb3BvdXRNYXNrID0gbnVsbDtcbiAgICAgIH1cblxuICAgICAgaWYgKGt3YXJncyAmJiBrd2FyZ3NbJ2NvbnN0YW50cyddKSB7XG4gICAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKCdDb252Uk5OMkQgY2VsbCBkb2VzIG5vdCBzdXBwb3J0IGNvbnN0YW50cycpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBtYXNrID0ga3dhcmdzID09IG51bGwgPyBudWxsIDoga3dhcmdzWydtYXNrJ107XG5cbiAgICAgIGNvbnN0IHRyYWluaW5nID0ga3dhcmdzID09IG51bGwgPyBudWxsIDoga3dhcmdzWyd0cmFpbmluZyddO1xuXG4gICAgICBjb25zdCBpbml0aWFsU3RhdGU6IFRlbnNvcltdID1cbiAgICAgICAgICBrd2FyZ3MgPT0gbnVsbCA/IG51bGwgOiBrd2FyZ3NbJ2luaXRpYWxTdGF0ZSddO1xuXG4gICAgICByZXR1cm4gc3VwZXIuY2FsbChpbnB1dHMsIHttYXNrLCB0cmFpbmluZywgaW5pdGlhbFN0YXRlfSk7XG4gICAgfSk7XG4gIH1cblxuICBvdmVycmlkZSBjb21wdXRlT3V0cHV0U2hhcGUoaW5wdXRTaGFwZTogU2hhcGUpOiBTaGFwZXxTaGFwZVtdIHtcbiAgICBsZXQgb3V0U2hhcGU6IFNoYXBlID0gdGhpcy5jb21wdXRlU2luZ2xlT3V0cHV0U2hhcGUoaW5wdXRTaGFwZSk7XG5cbiAgICBpZiAoIXRoaXMucmV0dXJuU2VxdWVuY2VzKSB7XG4gICAgICBvdXRTaGFwZSA9IFtvdXRTaGFwZVswXSwgLi4ub3V0U2hhcGUuc2xpY2UoMildO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnJldHVyblN0YXRlKSB7XG4gICAgICBvdXRTaGFwZSA9XG4gICAgICAgICAgW291dFNoYXBlLCAuLi5BcnJheSgyKS5maWxsKFtpbnB1dFNoYXBlWzBdLCAuLi5vdXRTaGFwZS5zbGljZSgtMyldKV07XG4gICAgfVxuXG4gICAgcmV0dXJuIG91dFNoYXBlO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0SW5pdGlhbFN0YXRlKGlucHV0czogdGZjLlRlbnNvcik6IHRmYy5UZW5zb3JbXSB7XG4gICAgcmV0dXJuIHRmYy50aWR5KCgpID0+IHtcbiAgICAgIGNvbnN0IHtzdGF0ZVNpemV9ID0gdGhpcy5jZWxsO1xuXG4gICAgICBjb25zdCBpbnB1dFNoYXBlID0gaW5wdXRzLnNoYXBlO1xuXG4gICAgICBjb25zdCBvdXRwdXRTaGFwZSA9IHRoaXMuY29tcHV0ZVNpbmdsZU91dHB1dFNoYXBlKGlucHV0U2hhcGUpO1xuXG4gICAgICBjb25zdCBzdGF0ZVNoYXBlID0gW291dHB1dFNoYXBlWzBdLCAuLi5vdXRwdXRTaGFwZS5zbGljZSgyKV07XG5cbiAgICAgIGNvbnN0IGluaXRpYWxTdGF0ZSA9IHRmYy56ZXJvcyhzdGF0ZVNoYXBlKTtcblxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoc3RhdGVTaXplKSkge1xuICAgICAgICByZXR1cm4gQXJyYXkoc3RhdGVTaXplLmxlbmd0aCkuZmlsbChpbml0aWFsU3RhdGUpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gW2luaXRpYWxTdGF0ZV07XG4gICAgfSk7XG4gIH1cblxuICBvdmVycmlkZSByZXNldFN0YXRlcyhzdGF0ZXM/OiBUZW5zb3J8VGVuc29yW10sIHRyYWluaW5nID0gZmFsc2UpOiB2b2lkIHtcbiAgICB0ZmMudGlkeSgoKSA9PiB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGVmdWwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEF0dHJpYnV0ZUVycm9yKFxuICAgICAgICAgICAgJ0Nhbm5vdCBjYWxsIHJlc2V0U3RhdGVzKCkgb24gYW4gUk5OIExheWVyIHRoYXQgaXMgbm90IHN0YXRlZnVsLicpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBpbnB1dFNoYXBlID0gdGhpcy5pbnB1dFNwZWNbMF0uc2hhcGU7XG5cbiAgICAgIGNvbnN0IG91dHB1dFNoYXBlID0gdGhpcy5jb21wdXRlU2luZ2xlT3V0cHV0U2hhcGUoaW5wdXRTaGFwZSk7XG5cbiAgICAgIGNvbnN0IHN0YXRlU2hhcGUgPSBbb3V0cHV0U2hhcGVbMF0sIC4uLm91dHB1dFNoYXBlLnNsaWNlKDIpXTtcblxuICAgICAgY29uc3QgYmF0Y2hTaXplID0gaW5wdXRTaGFwZVswXTtcblxuICAgICAgaWYgKGJhdGNoU2l6ZSA9PSBudWxsKSB7XG4gICAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICAgJ0lmIGFuIFJOTiBpcyBzdGF0ZWZ1bCwgaXQgbmVlZHMgdG8ga25vdyBpdHMgYmF0Y2ggc2l6ZS4gU3BlY2lmeSAnICtcbiAgICAgICAgICAgICd0aGUgYmF0Y2ggc2l6ZSBvZiB5b3VyIGlucHV0IHRlbnNvcnM6IFxcbicgK1xuICAgICAgICAgICAgJy0gSWYgdXNpbmcgYSBTZXF1ZW50aWFsIG1vZGVsLCBzcGVjaWZ5IHRoZSBiYXRjaCBzaXplIGJ5ICcgK1xuICAgICAgICAgICAgJ3Bhc3NpbmcgYSBgYmF0Y2hJbnB1dFNoYXBlYCBvcHRpb24gdG8geW91ciBmaXJzdCBsYXllci5cXG4nICtcbiAgICAgICAgICAgICctIElmIHVzaW5nIHRoZSBmdW5jdGlvbmFsIEFQSSwgc3BlY2lmeSB0aGUgYmF0Y2ggc2l6ZSBieSAnICtcbiAgICAgICAgICAgICdwYXNzaW5nIGEgYGJhdGNoU2hhcGVgIG9wdGlvbiB0byB5b3VyIElucHV0IGxheWVyLicpO1xuICAgICAgfVxuXG4gICAgICAvLyBJbml0aWFsaXplIHN0YXRlIGlmIG51bGwuXG4gICAgICBpZiAodGhpcy5nZXRTdGF0ZXMoKSA9PSBudWxsKSB7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMuY2VsbC5zdGF0ZVNpemUpKSB7XG4gICAgICAgICAgdGhpcy5zdGF0ZXNfID0gdGhpcy5jZWxsLnN0YXRlU2l6ZS5tYXAoKCkgPT4gdGZjLnplcm9zKHN0YXRlU2hhcGUpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnN0YXRlc18gPSBbdGZjLnplcm9zKHN0YXRlU2hhcGUpXTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChzdGF0ZXMgPT0gbnVsbCkge1xuICAgICAgICAvLyBEaXNwb3NlIG9sZCBzdGF0ZSB0ZW5zb3JzLlxuICAgICAgICB0ZmMuZGlzcG9zZSh0aGlzLnN0YXRlc18pO1xuXG4gICAgICAgIC8vIEZvciBzdGF0ZWZ1bCBSTk5zLCBmdWxseSBkaXNwb3NlIGtlcHQgb2xkIHN0YXRlcy5cbiAgICAgICAgaWYgKHRoaXMua2VwdFN0YXRlcyAhPSBudWxsKSB7XG4gICAgICAgICAgdGZjLmRpc3Bvc2UodGhpcy5rZXB0U3RhdGVzKTtcbiAgICAgICAgICB0aGlzLmtlcHRTdGF0ZXMgPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMuY2VsbC5zdGF0ZVNpemUpKSB7XG4gICAgICAgICAgdGhpcy5zdGF0ZXNfID0gdGhpcy5jZWxsLnN0YXRlU2l6ZS5tYXAoKCkgPT4gdGZjLnplcm9zKHN0YXRlU2hhcGUpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnN0YXRlc19bMF0gPSB0ZmMuemVyb3Moc3RhdGVTaGFwZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICghQXJyYXkuaXNBcnJheShzdGF0ZXMpKSB7XG4gICAgICAgICAgc3RhdGVzID0gW3N0YXRlc107XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc3RhdGVzLmxlbmd0aCAhPT0gdGhpcy5zdGF0ZXNfLmxlbmd0aCkge1xuICAgICAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICAgICBgTGF5ZXIgJHt0aGlzLm5hbWV9IGV4cGVjdHMgJHt0aGlzLnN0YXRlc18ubGVuZ3RofSBzdGF0ZShzKSwgYCArXG4gICAgICAgICAgICAgIGBidXQgaXQgcmVjZWl2ZWQgJHtzdGF0ZXMubGVuZ3RofSBzdGF0ZSB2YWx1ZShzKS4gSW5wdXQgYCArXG4gICAgICAgICAgICAgIGByZWNlaXZlZDogJHtzdGF0ZXN9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHJhaW5pbmcpIHtcbiAgICAgICAgICAvLyBTdG9yZSBvbGQgc3RhdGUgdGVuc29ycyBmb3IgY29tcGxldGUgZGlzcG9zYWwgbGF0ZXIsIGkuZS4sIGR1cmluZ1xuICAgICAgICAgIC8vIHRoZSBuZXh0IG5vLWFyZyBjYWxsIHRvIHRoaXMgbWV0aG9kLiBXZSBkbyBub3QgZGlzcG9zZSB0aGUgb2xkXG4gICAgICAgICAgLy8gc3RhdGVzIGltbWVkaWF0ZWx5IGJlY2F1c2UgdGhhdCBCUFRUIChhbW9uZyBvdGhlciB0aGluZ3MpIHJlcXVpcmVcbiAgICAgICAgICAvLyB0aGVtLlxuICAgICAgICAgIHRoaXMua2VwdFN0YXRlcy5wdXNoKHRoaXMuc3RhdGVzXy5zbGljZSgpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0ZmMuZGlzcG9zZSh0aGlzLnN0YXRlc18pO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IHRoaXMuc3RhdGVzXy5sZW5ndGg7ICsraW5kZXgpIHtcbiAgICAgICAgICBjb25zdCB2YWx1ZSA9IHN0YXRlc1tpbmRleF07XG5cbiAgICAgICAgICBjb25zdCBleHBlY3RlZFNoYXBlID0gc3RhdGVTaGFwZTtcblxuICAgICAgICAgIGlmICghdXRpbC5hcnJheXNFcXVhbCh2YWx1ZS5zaGFwZSwgZXhwZWN0ZWRTaGFwZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgICAgICAgIGBTdGF0ZSAke2luZGV4fSBpcyBpbmNvbXBhdGlibGUgd2l0aCBsYXllciAke3RoaXMubmFtZX06IGAgK1xuICAgICAgICAgICAgICAgIGBleHBlY3RlZCBzaGFwZT0ke2V4cGVjdGVkU2hhcGV9LCByZWNlaXZlZCBzaGFwZT0ke1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZS5zaGFwZX1gKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnN0YXRlc19baW5kZXhdID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5zdGF0ZXNfID0gdGhpcy5zdGF0ZXNfLm1hcChzdGF0ZSA9PiB0ZmMua2VlcChzdGF0ZS5jbG9uZSgpKSk7XG4gICAgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgY29tcHV0ZVNpbmdsZU91dHB1dFNoYXBlKGlucHV0U2hhcGU6IFNoYXBlKTogU2hhcGUge1xuICAgIGNvbnN0IHtkYXRhRm9ybWF0LCBmaWx0ZXJzLCBrZXJuZWxTaXplLCBwYWRkaW5nLCBzdHJpZGVzLCBkaWxhdGlvblJhdGV9ID1cbiAgICAgICAgdGhpcy5jZWxsO1xuXG4gICAgY29uc3QgaXNDaGFubmVsc0ZpcnN0ID0gZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnO1xuXG4gICAgY29uc3QgaCA9IGlucHV0U2hhcGVbaXNDaGFubmVsc0ZpcnN0ID8gMyA6IDJdO1xuICAgIGNvbnN0IHcgPSBpbnB1dFNoYXBlW2lzQ2hhbm5lbHNGaXJzdCA/IDQgOiAzXTtcblxuICAgIGNvbnN0IGhPdXQgPSBjb252T3V0cHV0TGVuZ3RoKFxuICAgICAgICBoLCBrZXJuZWxTaXplWzBdLCBwYWRkaW5nLCBzdHJpZGVzWzBdLCBkaWxhdGlvblJhdGVbMF0pO1xuICAgIGNvbnN0IHdPdXQgPSBjb252T3V0cHV0TGVuZ3RoKFxuICAgICAgICB3LCBrZXJuZWxTaXplWzFdLCBwYWRkaW5nLCBzdHJpZGVzWzFdLCBkaWxhdGlvblJhdGVbMV0pO1xuXG4gICAgY29uc3Qgb3V0U2hhcGU6IFNoYXBlID0gW1xuICAgICAgLi4uaW5wdXRTaGFwZS5zbGljZSgwLCAyKSxcbiAgICAgIC4uLihpc0NoYW5uZWxzRmlyc3QgPyBbZmlsdGVycywgaE91dCwgd091dF0gOiBbaE91dCwgd091dCwgZmlsdGVyc10pXG4gICAgXTtcblxuICAgIHJldHVybiBvdXRTaGFwZTtcbiAgfVxufVxuXG5leHBvcnQgZGVjbGFyZSBpbnRlcmZhY2UgQ29udkxTVE0yRENlbGxBcmdzIGV4dGVuZHNcbiAgICBPbWl0PExTVE1DZWxsTGF5ZXJBcmdzLCAndW5pdHMnPiwgQ29udlJOTjJEQ2VsbEFyZ3Mge31cblxuZXhwb3J0IGNsYXNzIENvbnZMU1RNMkRDZWxsIGV4dGVuZHMgTFNUTUNlbGwgaW1wbGVtZW50cyBDb252Uk5OMkRDZWxsIHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyBvdmVycmlkZSBjbGFzc05hbWUgPSAnQ29udkxTVE0yRENlbGwnO1xuXG4gIHJlYWRvbmx5IGZpbHRlcnM6IG51bWJlcjtcbiAgcmVhZG9ubHkga2VybmVsU2l6ZTogbnVtYmVyW107XG4gIHJlYWRvbmx5IHN0cmlkZXM6IG51bWJlcltdO1xuICByZWFkb25seSBwYWRkaW5nOiBQYWRkaW5nTW9kZTtcbiAgcmVhZG9ubHkgZGF0YUZvcm1hdDogRGF0YUZvcm1hdDtcbiAgcmVhZG9ubHkgZGlsYXRpb25SYXRlOiBudW1iZXJbXTtcblxuICBjb25zdHJ1Y3RvcihhcmdzOiBDb252TFNUTTJEQ2VsbEFyZ3MpIHtcbiAgICBjb25zdCB7XG4gICAgICBmaWx0ZXJzLFxuICAgICAga2VybmVsU2l6ZSxcbiAgICAgIHN0cmlkZXMsXG4gICAgICBwYWRkaW5nLFxuICAgICAgZGF0YUZvcm1hdCxcbiAgICAgIGRpbGF0aW9uUmF0ZSxcbiAgICB9ID0gYXJncztcblxuICAgIHN1cGVyKHsuLi5hcmdzLCB1bml0czogZmlsdGVyc30pO1xuXG4gICAgdGhpcy5maWx0ZXJzID0gZmlsdGVycztcbiAgICBhc3NlcnRQb3NpdGl2ZUludGVnZXIodGhpcy5maWx0ZXJzLCAnZmlsdGVycycpO1xuXG4gICAgdGhpcy5rZXJuZWxTaXplID0gbm9ybWFsaXplQXJyYXkoa2VybmVsU2l6ZSwgMiwgJ2tlcm5lbFNpemUnKTtcbiAgICB0aGlzLmtlcm5lbFNpemUuZm9yRWFjaChzaXplID0+IGFzc2VydFBvc2l0aXZlSW50ZWdlcihzaXplLCAna2VybmVsU2l6ZScpKTtcblxuICAgIHRoaXMuc3RyaWRlcyA9IG5vcm1hbGl6ZUFycmF5KHN0cmlkZXMgfHwgMSwgMiwgJ3N0cmlkZXMnKTtcbiAgICB0aGlzLnN0cmlkZXMuZm9yRWFjaChzdHJpZGUgPT4gYXNzZXJ0UG9zaXRpdmVJbnRlZ2VyKHN0cmlkZSwgJ3N0cmlkZXMnKSk7XG5cbiAgICB0aGlzLnBhZGRpbmcgPSBwYWRkaW5nIHx8ICd2YWxpZCc7XG4gICAgY2hlY2tQYWRkaW5nTW9kZSh0aGlzLnBhZGRpbmcpO1xuXG4gICAgdGhpcy5kYXRhRm9ybWF0ID0gZGF0YUZvcm1hdCB8fCAnY2hhbm5lbHNMYXN0JztcbiAgICBjaGVja0RhdGFGb3JtYXQodGhpcy5kYXRhRm9ybWF0KTtcblxuICAgIHRoaXMuZGlsYXRpb25SYXRlID0gbm9ybWFsaXplQXJyYXkoZGlsYXRpb25SYXRlIHx8IDEsIDIsICdkaWxhdGlvblJhdGUnKTtcbiAgICB0aGlzLmRpbGF0aW9uUmF0ZS5mb3JFYWNoKFxuICAgICAgICByYXRlID0+IGFzc2VydFBvc2l0aXZlSW50ZWdlcihyYXRlLCAnZGlsYXRpb25SYXRlJykpO1xuICB9XG5cbiAgcHVibGljIG92ZXJyaWRlIGJ1aWxkKGlucHV0U2hhcGU6IFNoYXBlfFNoYXBlW10pOiB2b2lkIHtcbiAgICBpbnB1dFNoYXBlID0gZ2V0RXhhY3RseU9uZVNoYXBlKGlucHV0U2hhcGUpO1xuXG4gICAgY29uc3QgY2hhbm5lbEF4aXMgPVxuICAgICAgICB0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0JyA/IDEgOiBpbnB1dFNoYXBlLmxlbmd0aCAtIDE7XG5cbiAgICBpZiAoaW5wdXRTaGFwZVtjaGFubmVsQXhpc10gPT0gbnVsbCkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYFRoZSBjaGFubmVsIGRpbWVuc2lvbiBvZiB0aGUgaW5wdXQgc2hvdWxkIGJlIGRlZmluZWQuIGAgK1xuICAgICAgICAgIGBGb3VuZCAke2lucHV0U2hhcGVbY2hhbm5lbEF4aXNdfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGlucHV0RGltID0gaW5wdXRTaGFwZVtjaGFubmVsQXhpc107XG5cbiAgICBjb25zdCBudW1PZktlcm5lbHMgPSA0O1xuXG4gICAgY29uc3Qga2VybmVsU2hhcGUgPVxuICAgICAgICB0aGlzLmtlcm5lbFNpemUuY29uY2F0KFtpbnB1dERpbSwgdGhpcy5maWx0ZXJzICogbnVtT2ZLZXJuZWxzXSk7XG5cbiAgICB0aGlzLmtlcm5lbCA9IHRoaXMuYWRkV2VpZ2h0KFxuICAgICAgICAna2VybmVsJywga2VybmVsU2hhcGUsIG51bGwsIHRoaXMua2VybmVsSW5pdGlhbGl6ZXIsXG4gICAgICAgIHRoaXMua2VybmVsUmVndWxhcml6ZXIsIHRydWUsIHRoaXMua2VybmVsQ29uc3RyYWludCk7XG5cbiAgICBjb25zdCByZWN1cnJlbnRLZXJuZWxTaGFwZSA9XG4gICAgICAgIHRoaXMua2VybmVsU2l6ZS5jb25jYXQoW3RoaXMuZmlsdGVycywgdGhpcy5maWx0ZXJzICogbnVtT2ZLZXJuZWxzXSk7XG5cbiAgICB0aGlzLnJlY3VycmVudEtlcm5lbCA9IHRoaXMuYWRkV2VpZ2h0KFxuICAgICAgICAncmVjdXJyZW50X2tlcm5lbCcsIHJlY3VycmVudEtlcm5lbFNoYXBlLCBudWxsLFxuICAgICAgICB0aGlzLnJlY3VycmVudEluaXRpYWxpemVyLCB0aGlzLnJlY3VycmVudFJlZ3VsYXJpemVyLCB0cnVlLFxuICAgICAgICB0aGlzLnJlY3VycmVudENvbnN0cmFpbnQpO1xuXG4gICAgaWYgKHRoaXMudXNlQmlhcykge1xuICAgICAgbGV0IGJpYXNJbml0aWFsaXplcjogSW5pdGlhbGl6ZXI7XG5cbiAgICAgIGlmICh0aGlzLnVuaXRGb3JnZXRCaWFzKSB7XG4gICAgICAgIGNvbnN0IGluaXQgPSB0aGlzLmJpYXNJbml0aWFsaXplcjtcblxuICAgICAgICBjb25zdCBmaWx0ZXJzID0gdGhpcy5maWx0ZXJzO1xuXG4gICAgICAgIGJpYXNJbml0aWFsaXplciA9IG5ldyAoY2xhc3MgQ3VzdG9tSW5pdCBleHRlbmRzIEluaXRpYWxpemVyIHtcbiAgICAgICAgICAvKiogQG5vY29sbGFwc2UgKi9cbiAgICAgICAgICBzdGF0aWMgY2xhc3NOYW1lID0gJ0N1c3RvbUluaXQnO1xuXG4gICAgICAgICAgYXBwbHkoc2hhcGU6IFNoYXBlLCBkdHlwZT86IERhdGFUeXBlKTogdGZjLlRlbnNvciB7XG4gICAgICAgICAgICBjb25zdCBiaWFzSSA9IGluaXQuYXBwbHkoW2ZpbHRlcnNdKTtcbiAgICAgICAgICAgIGNvbnN0IGJpYXNGID0gdGZjLm9uZXMoW2ZpbHRlcnNdKTtcbiAgICAgICAgICAgIGNvbnN0IGJpYXNDQW5kTyA9IGluaXQuYXBwbHkoW2ZpbHRlcnMgKiAyXSk7XG4gICAgICAgICAgICByZXR1cm4gSy5jb25jYXRlbmF0ZShbYmlhc0ksIGJpYXNGLCBiaWFzQ0FuZE9dKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBiaWFzSW5pdGlhbGl6ZXIgPSB0aGlzLmJpYXNJbml0aWFsaXplcjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5iaWFzID0gdGhpcy5hZGRXZWlnaHQoXG4gICAgICAgICAgJ2JpYXMnLCBbdGhpcy5maWx0ZXJzICogbnVtT2ZLZXJuZWxzXSwgbnVsbCwgYmlhc0luaXRpYWxpemVyLFxuICAgICAgICAgIHRoaXMuYmlhc1JlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmJpYXNDb25zdHJhaW50KTtcbiAgICB9XG5cbiAgICB0aGlzLmJ1aWx0ID0gdHJ1ZTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiB0ZmMuVGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogdGZjLlRlbnNvcltdIHtcbiAgICByZXR1cm4gdGZjLnRpZHkoKCkgPT4ge1xuICAgICAgaWYgKGlucHV0cy5sZW5ndGggIT09IDMpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgICBgQ29udkxTVE0yRENlbGwgZXhwZWN0cyAzIGlucHV0IFRlbnNvcnMgKGlucHV0cywgaCwgYyksIGdvdCBgICtcbiAgICAgICAgICAgIGAke2lucHV0cy5sZW5ndGh9LmApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0cmFpbmluZyA9IGt3YXJnc1sndHJhaW5pbmcnXSB8fCBmYWxzZTtcblxuICAgICAgY29uc3QgeCA9IGlucHV0c1swXTsgICAgICAgICAvLyBDdXJyZW50IGlucHV0XG4gICAgICBjb25zdCBoVE1pbnVzMSA9IGlucHV0c1sxXTsgIC8vIFByZXZpb3VzIG1lbW9yeSBzdGF0ZS5cbiAgICAgIGNvbnN0IGNUTWludXMxID0gaW5wdXRzWzJdOyAgLy8gUHJldmlvdXMgY2Fycnkgc3RhdGUuXG5cbiAgICAgIGNvbnN0IG51bU9mS2VybmVscyA9IDQ7XG5cbiAgICAgIHR5cGUgRHJvcG91dE1hc2tzID0gW3RmYy5UZW5zb3IsIHRmYy5UZW5zb3IsIHRmYy5UZW5zb3IsIHRmYy5UZW5zb3JdO1xuXG4gICAgICBpZiAoMCA8IHRoaXMuZHJvcG91dCAmJiB0aGlzLmRyb3BvdXQgPCAxICYmIHRoaXMuZHJvcG91dE1hc2sgPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmRyb3BvdXRNYXNrID0gZ2VuZXJhdGVEcm9wb3V0TWFzayh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZXM6ICgpID0+IHRmYy5vbmVzTGlrZSh4KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmF0ZTogdGhpcy5kcm9wb3V0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFpbmluZyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnQ6IG51bU9mS2VybmVscyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJvcG91dEZ1bmM6IHRoaXMuZHJvcG91dEZ1bmNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pIGFzIHRmYy5UZW5zb3JbXTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZHJvcG91dE1hc2sgPSB0aGlzLmRyb3BvdXRNYXNrIGFzIERyb3BvdXRNYXNrcztcblxuICAgICAgY29uc3QgYXBwbHlEcm9wb3V0ID1cbiAgICAgICAgICAoeDogdGZjLlRlbnNvciwgbWFzazogdGZjLlRlbnNvcltdLCBpbmRleDogbnVtYmVyKSA9PiB7XG4gICAgICAgICAgICBpZiAoIW1hc2sgfHwgIW1hc2tbaW5kZXhdKSB7XG4gICAgICAgICAgICAgIHJldHVybiB4O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdGZjLm11bChtYXNrW2luZGV4XSwgeCk7XG4gICAgICAgICAgfTtcblxuICAgICAgbGV0IHhJID0gYXBwbHlEcm9wb3V0KHgsIGRyb3BvdXRNYXNrLCAwKTtcbiAgICAgIGxldCB4RiA9IGFwcGx5RHJvcG91dCh4LCBkcm9wb3V0TWFzaywgMSk7XG4gICAgICBsZXQgeEMgPSBhcHBseURyb3BvdXQoeCwgZHJvcG91dE1hc2ssIDIpO1xuICAgICAgbGV0IHhPID0gYXBwbHlEcm9wb3V0KHgsIGRyb3BvdXRNYXNrLCAzKTtcblxuICAgICAgaWYgKDAgPCB0aGlzLnJlY3VycmVudERyb3BvdXQgJiYgdGhpcy5yZWN1cnJlbnREcm9wb3V0IDwgMSAmJlxuICAgICAgICAgIHRoaXMucmVjdXJyZW50RHJvcG91dE1hc2sgPT0gbnVsbCkge1xuICAgICAgICB0aGlzLnJlY3VycmVudERyb3BvdXRNYXNrID0gZ2VuZXJhdGVEcm9wb3V0TWFzayh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZXM6ICgpID0+IHRmYy5vbmVzTGlrZShoVE1pbnVzMSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhdGU6IHRoaXMucmVjdXJyZW50RHJvcG91dCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhaW5pbmcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50OiBudW1PZktlcm5lbHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRyb3BvdXRGdW5jOiB0aGlzLmRyb3BvdXRGdW5jXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSBhcyB0ZmMuVGVuc29yW107XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlY0Ryb3BvdXRNYXNrID0gdGhpcy5yZWN1cnJlbnREcm9wb3V0TWFzayBhcyBEcm9wb3V0TWFza3M7XG5cbiAgICAgIGxldCBoSSA9IGFwcGx5RHJvcG91dChoVE1pbnVzMSwgcmVjRHJvcG91dE1hc2ssIDApO1xuICAgICAgbGV0IGhGID0gYXBwbHlEcm9wb3V0KGhUTWludXMxLCByZWNEcm9wb3V0TWFzaywgMSk7XG4gICAgICBsZXQgaEMgPSBhcHBseURyb3BvdXQoaFRNaW51czEsIHJlY0Ryb3BvdXRNYXNrLCAyKTtcbiAgICAgIGxldCBoTyA9IGFwcGx5RHJvcG91dChoVE1pbnVzMSwgcmVjRHJvcG91dE1hc2ssIDMpO1xuXG4gICAgICBjb25zdCBrZXJuZWxDaGFubmVsQXhpcyA9IDM7XG5cbiAgICAgIGNvbnN0IFtrZXJuZWxJLCBrZXJuZWxGLCBrZXJuZWxDLCBrZXJuZWxPXTogdGZjLlRlbnNvcltdID1cbiAgICAgICAgICB0ZmMuc3BsaXQodGhpcy5rZXJuZWwucmVhZCgpLCBudW1PZktlcm5lbHMsIGtlcm5lbENoYW5uZWxBeGlzKTtcblxuICAgICAgY29uc3QgW2JpYXNJLCBiaWFzRiwgYmlhc0MsIGJpYXNPXTogdGZjLlRlbnNvcltdID0gdGhpcy51c2VCaWFzID9cbiAgICAgICAgICB0ZmMuc3BsaXQodGhpcy5iaWFzLnJlYWQoKSwgbnVtT2ZLZXJuZWxzKSA6XG4gICAgICAgICAgW251bGwsIG51bGwsIG51bGwsIG51bGxdO1xuXG4gICAgICB4SSA9IHRoaXMuaW5wdXRDb252KHhJLCBrZXJuZWxJLCBiaWFzSSwgdGhpcy5wYWRkaW5nKTtcbiAgICAgIHhGID0gdGhpcy5pbnB1dENvbnYoeEYsIGtlcm5lbEYsIGJpYXNGLCB0aGlzLnBhZGRpbmcpO1xuICAgICAgeEMgPSB0aGlzLmlucHV0Q29udih4Qywga2VybmVsQywgYmlhc0MsIHRoaXMucGFkZGluZyk7XG4gICAgICB4TyA9IHRoaXMuaW5wdXRDb252KHhPLCBrZXJuZWxPLCBiaWFzTywgdGhpcy5wYWRkaW5nKTtcblxuICAgICAgY29uc3QgW3JlY0tlcm5lbEksIHJlY0tlcm5lbEYsIHJlY0tlcm5lbEMsIHJlY0tlcm5lbE9dOiB0ZmMuVGVuc29yW10gPVxuICAgICAgICAgIHRmYy5zcGxpdChcbiAgICAgICAgICAgICAgdGhpcy5yZWN1cnJlbnRLZXJuZWwucmVhZCgpLCBudW1PZktlcm5lbHMsIGtlcm5lbENoYW5uZWxBeGlzKTtcblxuICAgICAgaEkgPSB0aGlzLnJlY3VycmVudENvbnYoaEksIHJlY0tlcm5lbEkpO1xuICAgICAgaEYgPSB0aGlzLnJlY3VycmVudENvbnYoaEYsIHJlY0tlcm5lbEYpO1xuICAgICAgaEMgPSB0aGlzLnJlY3VycmVudENvbnYoaEMsIHJlY0tlcm5lbEMpO1xuICAgICAgaE8gPSB0aGlzLnJlY3VycmVudENvbnYoaE8sIHJlY0tlcm5lbE8pO1xuXG4gICAgICBjb25zdCBpID0gdGhpcy5yZWN1cnJlbnRBY3RpdmF0aW9uLmFwcGx5KHRmYy5hZGQoeEksIGhJKSk7XG4gICAgICBjb25zdCBmID0gdGhpcy5yZWN1cnJlbnRBY3RpdmF0aW9uLmFwcGx5KHRmYy5hZGQoeEYsIGhGKSk7XG4gICAgICBjb25zdCBjID0gdGZjLmFkZChcbiAgICAgICAgICB0ZmMubXVsKGYsIGNUTWludXMxKSxcbiAgICAgICAgICB0ZmMubXVsKGksIHRoaXMuYWN0aXZhdGlvbi5hcHBseSh0ZmMuYWRkKHhDLCBoQykpKSk7XG4gICAgICBjb25zdCBoID0gdGZjLm11bChcbiAgICAgICAgICB0aGlzLnJlY3VycmVudEFjdGl2YXRpb24uYXBwbHkodGZjLmFkZCh4TywgaE8pKSxcbiAgICAgICAgICB0aGlzLmFjdGl2YXRpb24uYXBwbHkoYykpO1xuXG4gICAgICByZXR1cm4gW2gsIGgsIGNdO1xuICAgIH0pO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHRmYy5zZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3Qge1xuICAgIGNvbnN0IHsndW5pdHMnOiBfLCAuLi5iYXNlQ29uZmlnfSA9IHN1cGVyLmdldENvbmZpZygpO1xuXG4gICAgY29uc3QgY29uZmlnOiB0ZmMuc2VyaWFsaXphdGlvbi5Db25maWdEaWN0ID0ge1xuICAgICAgZmlsdGVyczogdGhpcy5maWx0ZXJzLFxuICAgICAga2VybmVsU2l6ZTogdGhpcy5rZXJuZWxTaXplLFxuICAgICAgcGFkZGluZzogdGhpcy5wYWRkaW5nLFxuICAgICAgZGF0YUZvcm1hdDogdGhpcy5kYXRhRm9ybWF0LFxuICAgICAgZGlsYXRpb25SYXRlOiB0aGlzLmRpbGF0aW9uUmF0ZSxcbiAgICAgIHN0cmlkZXM6IHRoaXMuc3RyaWRlcyxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHsuLi5iYXNlQ29uZmlnLCAuLi5jb25maWd9O1xuICB9XG5cbiAgaW5wdXRDb252KHg6IFRlbnNvciwgdzogVGVuc29yLCBiPzogVGVuc29yLCBwYWRkaW5nPzogUGFkZGluZ01vZGUpIHtcbiAgICBjb25zdCBvdXQgPSB0ZmMuY29udjJkKFxuICAgICAgICB4IGFzIHRmYy5UZW5zb3IzRCwgdyBhcyB0ZmMuVGVuc29yNEQsIHRoaXMuc3RyaWRlcyBhcyBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICAocGFkZGluZyB8fCAndmFsaWQnKSBhcyAnc2FtZScgfCAndmFsaWQnLFxuICAgICAgICB0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0JyA/ICdOQ0hXJyA6ICdOSFdDJyxcbiAgICAgICAgdGhpcy5kaWxhdGlvblJhdGUgYXMgW251bWJlciwgbnVtYmVyXSk7XG5cbiAgICBpZiAoYikge1xuICAgICAgcmV0dXJuIEsuYmlhc0FkZChvdXQsIGIsIHRoaXMuZGF0YUZvcm1hdCkgYXMgdGZjLlRlbnNvcjNEO1xuICAgIH1cblxuICAgIHJldHVybiBvdXQ7XG4gIH1cblxuICByZWN1cnJlbnRDb252KHg6IFRlbnNvciwgdzogVGVuc29yKSB7XG4gICAgY29uc3Qgc3RyaWRlcyA9IDE7XG5cbiAgICByZXR1cm4gdGZjLmNvbnYyZChcbiAgICAgICAgeCBhcyB0ZmMuVGVuc29yM0QsIHcgYXMgdGZjLlRlbnNvcjRELCBzdHJpZGVzLCAnc2FtZScsXG4gICAgICAgIHRoaXMuZGF0YUZvcm1hdCA9PT0gJ2NoYW5uZWxzRmlyc3QnID8gJ05DSFcnIDogJ05IV0MnKTtcbiAgfVxufVxuXG50ZmMuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnZMU1RNMkRDZWxsKTtcblxuZXhwb3J0IGRlY2xhcmUgaW50ZXJmYWNlIENvbnZMU1RNMkRBcmdzIGV4dGVuZHNcbiAgICBPbWl0PExTVE1MYXllckFyZ3MsICd1bml0cyd8J2NlbGwnPiwgQ29udlJOTjJETGF5ZXJBcmdzIHt9XG5cbmV4cG9ydCBjbGFzcyBDb252TFNUTTJEIGV4dGVuZHMgQ29udlJOTjJEIHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyBvdmVycmlkZSBjbGFzc05hbWUgPSAnQ29udkxTVE0yRCc7XG5cbiAgY29uc3RydWN0b3IoYXJnczogQ29udkxTVE0yREFyZ3MpIHtcbiAgICBjb25zdCBjZWxsID0gbmV3IENvbnZMU1RNMkRDZWxsKGFyZ3MpO1xuXG4gICAgc3VwZXIoey4uLmFyZ3MsIGNlbGx9IGFzIENvbnZSTk4yRExheWVyQXJncyk7XG4gIH1cblxuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIG92ZXJyaWRlIGZyb21Db25maWc8VCBleHRlbmRzIHRmYy5zZXJpYWxpemF0aW9uLlNlcmlhbGl6YWJsZT4oXG4gICAgICBjbHM6IHRmYy5zZXJpYWxpemF0aW9uLlNlcmlhbGl6YWJsZUNvbnN0cnVjdG9yPFQ+LFxuICAgICAgY29uZmlnOiB0ZmMuc2VyaWFsaXphdGlvbi5Db25maWdEaWN0KTogVCB7XG4gICAgcmV0dXJuIG5ldyBjbHMoY29uZmlnKTtcbiAgfVxufVxuXG50ZmMuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKENvbnZMU1RNMkQpO1xuIl19
\No newline at end of file