UNPKG

24.1 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: Depthwise Convolutional Layers
12 */
13import * as tfc from '@tensorflow/tfjs-core';
14import { serialization, tidy } from '@tensorflow/tfjs-core';
15import { imageDataFormat } from '../backend/common';
16import * as K from '../backend/tfjs_backend';
17import { checkDataFormat } from '../common';
18import { getConstraint, serializeConstraint } from '../constraints';
19import { ValueError } from '../errors';
20import { getInitializer, serializeInitializer } from '../initializers';
21import { getRegularizer, serializeRegularizer } from '../regularizers';
22import { convOutputLength } from '../utils/conv_utils';
23import { getExactlyOneShape, getExactlyOneTensor } from '../utils/types_utils';
24import { BaseConv, preprocessConv2DInput } from './convolutional';
25/**
26 * 2D convolution with separable filters.
27 * @param x Input tensor.
28 * @param depthwiseKernel Convolution kernel for depthwise convolution.
29 * @param strides Strides (Array of two integers).
30 * @param padding Padding model.
31 * @param dataFormat Data format.
32 * @param dilationRate Array of two integers, dilation rates for the separable
33 * convolution.
34 * @returns Output tensor.
35 * @throws ValueError If depthwiseKernel is not a 4D array.
36 */
37export function depthwiseConv2d(x, depthwiseKernel, strides = [1, 1], padding = 'valid', dataFormat, dilationRate) {
38 return tidy(() => {
39 if (dataFormat == null) {
40 dataFormat = imageDataFormat();
41 }
42 checkDataFormat(dataFormat);
43 let y = preprocessConv2DInput(x, dataFormat);
44 if (x.rank !== 4) {
45 throw new ValueError(`Input for depthwiseConv2d is required to be 4-D, but is instead ` +
46 `${x.rank}-D`);
47 }
48 if (depthwiseKernel.rank !== 4) {
49 throw new ValueError(`depthwiseKernel is required to be 4-D, but is instead ` +
50 `${depthwiseKernel.rank}-D`);
51 }
52 y = tfc.depthwiseConv2d(y, depthwiseKernel, strides, padding === 'same' ? 'same' : 'valid', 'NHWC', dilationRate);
53 if (dataFormat === 'channelsFirst') {
54 y = tfc.transpose(y, [0, 3, 1, 2]);
55 }
56 return y;
57 });
58}
59export class DepthwiseConv2D extends BaseConv {
60 constructor(args) {
61 super(2, args);
62 this.depthwiseKernel = null;
63 this.depthMultiplier =
64 args.depthMultiplier == null ? 1 : args.depthMultiplier;
65 this.depthwiseInitializer = getInitializer(args.depthwiseInitializer || this.DEFAULT_KERNEL_INITIALIZER);
66 this.depthwiseConstraint = getConstraint(args.depthwiseConstraint);
67 this.depthwiseRegularizer = getRegularizer(args.depthwiseRegularizer);
68 }
69 build(inputShape) {
70 inputShape = getExactlyOneShape(inputShape);
71 if (inputShape.length < 4) {
72 throw new ValueError(`Inputs to DepthwiseConv2D should have rank 4. ` +
73 `Received input shape: ${JSON.stringify(inputShape)}.`);
74 }
75 const channelAxis = this.dataFormat === 'channelsFirst' ? 1 : 3;
76 if (inputShape[channelAxis] == null || inputShape[channelAxis] < 0) {
77 throw new ValueError('The channel dimension of the inputs to DepthwiseConv2D should ' +
78 `be defined, but is not (${inputShape[channelAxis]}).`);
79 }
80 const inputDim = inputShape[channelAxis];
81 const depthwiseKernelShape = [
82 this.kernelSize[0], this.kernelSize[1], inputDim, this.depthMultiplier
83 ];
84 this.depthwiseKernel = this.addWeight('depthwise_kernel', depthwiseKernelShape, null, this.depthwiseInitializer, this.depthwiseRegularizer, true, this.depthwiseConstraint);
85 if (this.useBias) {
86 this.bias = this.addWeight('bias', [inputDim * this.depthMultiplier], null, this.biasInitializer, this.biasRegularizer, true, this.biasConstraint);
87 }
88 else {
89 this.bias = null;
90 }
91 this.built = true;
92 }
93 call(inputs, kwargs) {
94 return tidy(() => {
95 inputs = getExactlyOneTensor(inputs);
96 let outputs = depthwiseConv2d(inputs, this.depthwiseKernel.read(), this.strides, this.padding, this.dataFormat, null);
97 // TODO(cais): Add support for dilation.
98 if (this.useBias) {
99 outputs = K.biasAdd(outputs, this.bias.read(), this.dataFormat);
100 }
101 if (this.activation != null) {
102 outputs = this.activation.apply(outputs);
103 }
104 return outputs;
105 });
106 }
107 computeOutputShape(inputShape) {
108 inputShape = getExactlyOneShape(inputShape);
109 const rows = this.dataFormat === 'channelsFirst' ? inputShape[2] : inputShape[1];
110 const cols = this.dataFormat === 'channelsFirst' ? inputShape[3] : inputShape[2];
111 const outFilters = this.dataFormat === 'channelsFirst' ?
112 inputShape[1] * this.depthMultiplier :
113 inputShape[3] * this.depthMultiplier;
114 const outRows = convOutputLength(rows, this.kernelSize[0], this.padding, this.strides[0]);
115 const outCols = convOutputLength(cols, this.kernelSize[1], this.padding, this.strides[1]);
116 if (this.dataFormat === 'channelsFirst') {
117 return [inputShape[0], outFilters, outRows, outCols];
118 }
119 else {
120 // In this case, assume 'channelsLast'.
121 return [inputShape[0], outRows, outCols, outFilters];
122 }
123 }
124 getConfig() {
125 const config = super.getConfig();
126 config['depthMultiplier'] = this.depthMultiplier;
127 config['depthwiseInitializer'] =
128 serializeInitializer(this.depthwiseInitializer);
129 config['depthwiseRegularizer'] =
130 serializeRegularizer(this.depthwiseRegularizer);
131 config['depthwiseConstraint'] =
132 serializeConstraint(this.depthwiseRegularizer);
133 return config;
134 }
135}
136/** @nocollapse */
137DepthwiseConv2D.className = 'DepthwiseConv2D';
138serialization.registerClass(DepthwiseConv2D);
139//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udm9sdXRpb25hbF9kZXB0aHdpc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi90ZmpzLWxheWVycy9zcmMvbGF5ZXJzL2NvbnZvbHV0aW9uYWxfZGVwdGh3aXNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUg7O0dBRUc7QUFFSCxPQUFPLEtBQUssR0FBRyxNQUFNLHVCQUF1QixDQUFDO0FBQzdDLE9BQU8sRUFBQyxhQUFhLEVBQW9CLElBQUksRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBRTVFLE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUNsRCxPQUFPLEtBQUssQ0FBQyxNQUFNLHlCQUF5QixDQUFDO0FBQzdDLE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFDMUMsT0FBTyxFQUFtQyxhQUFhLEVBQUUsbUJBQW1CLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUNwRyxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sV0FBVyxDQUFDO0FBQ3JDLE9BQU8sRUFBQyxjQUFjLEVBQXNDLG9CQUFvQixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFFekcsT0FBTyxFQUFDLGNBQWMsRUFBc0Msb0JBQW9CLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUV6RyxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUMsa0JBQWtCLEVBQUUsbUJBQW1CLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUc3RSxPQUFPLEVBQUMsUUFBUSxFQUFvQyxxQkFBcUIsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBRWxHOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FDM0IsQ0FBUyxFQUFFLGVBQXVCLEVBQUUsVUFBNEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQ3RFLE9BQU8sR0FBRyxPQUFPLEVB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Q0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0QsSUFBSSxJQUFJLENBQUMsVUFBVSxLQUFLLGVBQWUsRUFBRTtZQUN2QyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7U0FDdEQ7YUFBTTtZQUNMLHVDQUF1QztZQUN2QyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUM7U0FDdEQ7SUFDSCxDQUFDO0lBRVEsU0FBUztRQUNoQixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDakMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQztRQUNqRCxNQUFNLENBQUMsc0JBQXNCLENBQUM7WUFDMUIsb0JBQW9CLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDcEQsTUFBTSxDQUFDLHNCQUFzQixDQUFDO1lBQzFCLG9CQUFvQixDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3BELE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQztZQUN6QixtQkFBbUIsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUNuRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDOztBQW5HRCxrQkFBa0I7QUFDWCx5QkFBUyxHQUFHLGlCQUFpQixDQUFDO0FBb0d2QyxhQUFhLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTggR29vZ2xlIExMQ1xuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZVxuICogbGljZW5zZSB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIG9yIGF0XG4gKiBodHRwczovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL01JVC5cbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKi9cblxuLyoqXG4gKiBUZW5zb3JGbG93LmpzIExheWVyczogRGVwdGh3aXNlIENvbnZvbHV0aW9uYWwgTGF5ZXJzXG4gKi9cblxuaW1wb3J0ICogYXMgdGZjIGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5pbXBvcnQge3NlcmlhbGl6YXRpb24sIFRlbnNvciwgVGVuc29yNEQsIHRpZHl9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCB7aW1hZ2VEYXRhRm9ybWF0fSBmcm9tICcuLi9iYWNrZW5kL2NvbW1vbic7XG5pbXBvcnQgKiBhcyBLIGZyb20gJy4uL2JhY2tlbmQvdGZqc19iYWNrZW5kJztcbmltcG9ydCB7Y2hlY2tEYXRhRm9ybWF0fSBmcm9tICcuLi9jb21tb24nO1xuaW1wb3J0IHtDb25zdHJhaW50LCBDb25zdHJhaW50SWRlbnRpZmllciwgZ2V0Q29uc3RyYWludCwgc2VyaWFsaXplQ29uc3RyYWludH0gZnJvbSAnLi4vY29uc3RyYWludHMnO1xuaW1wb3J0IHtWYWx1ZUVycm9yfSBmcm9tICcuLi9lcnJvcnMnO1xuaW1wb3J0IHtnZXRJbml0aWFsaXplciwgSW5pdGlhbGl6ZXIsIEluaXRpYWxpemVySWRlbnRpZmllciwgc2VyaWFsaXplSW5pdGlhbGl6ZXJ9IGZyb20gJy4uL2luaXRpYWxpemVycyc7XG5pbXBvcnQge0RhdGFGb3JtYXQsIFNoYXBlfSBmcm9tICcuLi9rZXJhc19mb3JtYXQvY29tbW9uJztcbmltcG9ydCB7Z2V0UmVndWxhcml6ZXIsIFJlZ3VsYXJpemVyLCBSZWd1bGFyaXplcklkZW50aWZpZXIsIHNlcmlhbGl6ZVJlZ3VsYXJpemVyfSBmcm9tICcuLi9yZWd1bGFyaXplcnMnO1xuaW1wb3J0IHtLd2FyZ3N9IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCB7Y29udk91dHB1dExlbmd0aH0gZnJvbSAnLi4vdXRpbHMvY29udl91dGlscyc7XG5pbXBvcnQge2dldEV4YWN0bHlPbmVTaGFwZSwgZ2V0RXhhY3RseU9uZVRlbnNvcn0gZnJvbSAnLi4vdXRpbHMvdHlwZXNfdXRpbHMnO1xuaW1wb3J0IHtMYXllclZhcmlhYmxlfSBmcm9tICcuLi92YXJpYWJsZXMnO1xuXG5pbXBvcnQge0Jhc2VDb252LCBCYXNlQ29udkxheWVyQXJncywgQ29udkxheWVyQXJncywgcHJlcHJvY2Vzc0NvbnYyRElucHV0fSBmcm9tICcuL2NvbnZvbHV0aW9uYWwnO1xuXG4vKipcbiAqIDJEIGNvbnZvbHV0aW9uIHdpdGggc2VwYXJhYmxlIGZpbHRlcnMuXG4gKiBAcGFyYW0geCBJbnB1dCB0ZW5zb3IuXG4gKiBAcGFyYW0gZGVwdGh3aXNlS2VybmVsIENvbnZvbHV0aW9uIGtlcm5lbCBmb3IgZGVwdGh3aXNlIGNvbnZvbHV0aW9uLlxuICogQHBhcmFtIHN0cmlkZXMgU3RyaWRlcyAoQXJyYXkgb2YgdHdvIGludGVnZXJzKS5cbiAqIEBwYXJhbSBwYWRkaW5nIFBhZGRpbmcgbW9kZWwuXG4gKiBAcGFyYW0gZGF0YUZvcm1hdCBEYXRhIGZvcm1hdC5cbiAqIEBwYXJhbSBkaWxhdGlvblJhdGUgQXJyYXkgb2YgdHdvIGludGVnZXJzLCBkaWxhdGlvbiByYXRlcyBmb3IgdGhlIHNlcGFyYWJsZVxuICogICBjb252b2x1dGlvbi5cbiAqIEByZXR1cm5zIE91dHB1dCB0ZW5zb3IuXG4gKiBAdGhyb3dzIFZhbHVlRXJyb3IgSWYgZGVwdGh3aXNlS2VybmVsIGlzIG5vdCBhIDREIGFycmF5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVwdGh3aXNlQ29udjJkKFxuICAgIHg6IFRlbnNvciwgZGVwdGh3aXNlS2VybmVsOiBUZW5zb3IsIHN0cmlkZXM6IFtudW1iZXIsIG51bWJlcl0gPSBbMSwgMV0sXG4gICAgcGFkZGluZyA9ICd2YWxpZCcsIGRhdGFGb3JtYXQ/OiBEYXRhRm9ybWF0LFxuICAgIGRpbGF0aW9uUmF0ZT86IFtudW1iZXIsIG51bWJlcl0pOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgaWYgKGRhdGFGb3JtYXQgPT0gbnVsbCkge1xuICAgICAgZGF0YUZvcm1hdCA9IGltYWdlRGF0YUZvcm1hdCgpO1xuICAgIH1cbiAgICBjaGVja0RhdGFGb3JtYXQoZGF0YUZvcm1hdCk7XG4gICAgbGV0IHkgPSBwcmVwcm9jZXNzQ29udjJESW5wdXQoeCwgZGF0YUZvcm1hdCk7XG4gICAgaWYgKHgucmFuayAhPT0gNCkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgYElucHV0IGZvciBkZXB0aHdpc2VDb252MmQgaXMgcmVxdWlyZWQgdG8gYmUgNC1ELCBidXQgaXMgaW5zdGVhZCBgICtcbiAgICAgICAgICBgJHt4LnJhbmt9LURgKTtcbiAgICB9XG4gICAgaWYgKGRlcHRod2lzZUtlcm5lbC5yYW5rICE9PSA0KSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgZGVwdGh3aXNlS2VybmVsIGlzIHJlcXVpcmVkIHRvIGJlIDQtRCwgYnV0IGlzIGluc3RlYWQgYCArXG4gICAgICAgICAgYCR7ZGVwdGh3aXNlS2VybmVsLnJhbmt9LURgKTtcbiAgICB9XG4gICAgeSA9IHRmYy5kZXB0aHdpc2VDb252MmQoXG4gICAgICAgIHkgYXMgVGVuc29yNEQsIGRlcHRod2lzZUtlcm5lbCBhcyBUZW5zb3I0RCwgc3RyaWRlcyxcbiAgICAgICAgcGFkZGluZyA9PT0gJ3NhbWUnID8gJ3NhbWUnIDogJ3ZhbGlkJywgJ05IV0MnLCBkaWxhdGlvblJhdGUpO1xuICAgIGlmIChkYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgIHkgPSB0ZmMudHJhbnNwb3NlKHksIFswLCAzLCAxLCAyXSk7XG4gICAgfVxuICAgIHJldHVybiB5O1xuICB9KTtcbn1cblxuZXhwb3J0IGRlY2xhcmUgaW50ZXJmYWNlIERlcHRod2lzZUNvbnYyRExheWVyQXJncyBleHRlbmRzIEJhc2VDb252TGF5ZXJBcmdzIHtcbiAgLyoqXG4gICAqIEFuIGludGVnZXIgb3IgQXJyYXkgb2YgMiBpbnRlZ2Vycywgc3BlY2lmeWluZyB0aGUgd2lkdGggYW5kIGhlaWdodCBvZiB0aGVcbiAgICogMkQgY29udm9sdXRpb24gd2luZG93LiBDYW4gYmUgYSBzaW5nbGUgaW50ZWdlciB0byBzcGVjaWZ5IHRoZSBzYW1lIHZhbHVlXG4gICAqIGZvciBhbGwgc3BhdGlhbCBkaW1lbnNpb25zLlxuICAgKi9cbiAga2VybmVsU2l6ZTogbnVtYmVyfFtudW1iZXIsIG51bWJlcl07XG5cbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgZGVwdGh3aXNlIGNvbnZvbHV0aW9uIG91dHB1dCBjaGFubmVscyBmb3IgZWFjaCBpbnB1dFxuICAgKiBjaGFubmVsLlxuICAgKiBUaGUgdG90YWwgbnVtYmVyIG9mIGRlcHRod2lzZSBjb252b2x1dGlvbiBvdXRwdXQgY2hhbm5lbHMgd2lsbCBiZSBlcXVhbCB0b1xuICAgKiBgZmlsdGVyc0luICogZGVwdGhNdWx0aXBsaWVyYC5cbiAgICogRGVmYXVsdDogMS5cbiAgICovXG4gIGRlcHRoTXVsdGlwbGllcj86IG51bWJlcjtcblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXIgZm9yIHRoZSBkZXB0aHdpc2Uga2VybmVsIG1hdHJpeC5cbiAgICogRGVmYXVsdDogR2xvcm90Tm9ybWFsLlxuICAgKi9cbiAgZGVwdGh3aXNlSW5pdGlhbGl6ZXI/OiBJbml0aWFsaXplcklkZW50aWZpZXJ8SW5pdGlhbGl6ZXI7XG5cbiAgLyoqXG4gICAqIENvbnN0cmFpbnQgZm9yIHRoZSBkZXB0aHdpc2Uga2VybmVsIG1hdHJpeC5cbiAgICovXG4gIGRlcHRod2lzZUNvbnN0cmFpbnQ/OiBDb25zdHJhaW50SWRlbnRpZmllcnxDb25zdHJhaW50O1xuXG4gIC8qKlxuICAgKiBSZWd1bGFyaXplciBmdW5jdGlvbiBmb3IgdGhlIGRlcHRod2lzZSBrZXJuZWwgbWF0cml4LlxuICAgKi9cbiAgZGVwdGh3aXNlUmVndWxhcml6ZXI/OiBSZWd1bGFyaXplcklkZW50aWZpZXJ8UmVndWxhcml6ZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBEZXB0aHdpc2VDb252MkQgZXh0ZW5kcyBCYXNlQ29udiB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgY2xhc3NOYW1lID0gJ0RlcHRod2lzZUNvbnYyRCc7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVwdGhNdWx0aXBsaWVyOiBudW1iZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVwdGh3aXNlSW5pdGlhbGl6ZXI6IEluaXRpYWxpemVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlcHRod2lzZUNvbnN0cmFpbnQ6IENvbnN0cmFpbnQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVwdGh3aXNlUmVndWxhcml6ZXI6IFJlZ3VsYXJpemVyO1xuXG4gIHByaXZhdGUgZGVwdGh3aXNlS2VybmVsOiBMYXllclZhcmlhYmxlID0gbnVsbDtcblxuICBjb25zdHJ1Y3RvcihhcmdzOiBEZXB0aHdpc2VDb252MkRMYXllckFyZ3MpIHtcbiAgICBzdXBlcigyLCBhcmdzIGFzIENvbnZMYXllckFyZ3MpO1xuICAgIHRoaXMuZGVwdGhNdWx0aXBsaWVyID1cbiAgICAgICAgYXJncy5kZXB0aE11bHRpcGxpZXIgPT0gbnVsbCA/IDEgOiBhcmdzLmRlcHRoTXVsdGlwbGllcjtcbiAgICB0aGlzLmRlcHRod2lzZUluaXRpYWxpemVyID0gZ2V0SW5pdGlhbGl6ZXIoXG4gICAgICAgIGFyZ3MuZGVwdGh3aXNlSW5pdGlhbGl6ZXIgfHwgdGhpcy5ERUZBVUxUX0tFUk5FTF9JTklUSUFMSVpFUik7XG4gICAgdGhpcy5kZXB0aHdpc2VDb25zdHJhaW50ID0gZ2V0Q29uc3RyYWludChhcmdzLmRlcHRod2lzZUNvbnN0cmFpbnQpO1xuICAgIHRoaXMuZGVwdGh3aXNlUmVndWxhcml6ZXIgPSBnZXRSZWd1bGFyaXplcihhcmdzLmRlcHRod2lzZVJlZ3VsYXJpemVyKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGJ1aWxkKGlucHV0U2hhcGU6IFNoYXBlfFNoYXBlW10pOiB2b2lkIHtcbiAgICBpbnB1dFNoYXBlID0gZ2V0RXhhY3RseU9uZVNoYXBlKGlucHV0U2hhcGUpO1xuICAgIGlmIChpbnB1dFNoYXBlLmxlbmd0aCA8IDQpIHtcbiAgICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKFxuICAgICAgICAgIGBJbnB1dHMgdG8gRGVwdGh3aXNlQ29udjJEIHNob3VsZCBoYXZlIHJhbmsgNC4gYCArXG4gICAgICAgICAgYFJlY2VpdmVkIGlucHV0IHNoYXBlOiAke0pTT04uc3RyaW5naWZ5KGlucHV0U2hhcGUpfS5gKTtcbiAgICB9XG4gICAgY29uc3QgY2hhbm5lbEF4aXMgPSB0aGlzLmRhdGFGb3JtYXQgPT09ICdjaGFubmVsc0ZpcnN0JyA/IDEgOiAzO1xuICAgIGlmIChpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXSA9PSBudWxsIHx8IGlucHV0U2hhcGVbY2hhbm5lbEF4aXNdIDwgMCkge1xuICAgICAgdGhyb3cgbmV3IFZhbHVlRXJyb3IoXG4gICAgICAgICAgJ1RoZSBjaGFubmVsIGRpbWVuc2lvbiBvZiB0aGUgaW5wdXRzIHRvIERlcHRod2lzZUNvbnYyRCBzaG91bGQgJyArXG4gICAgICAgICAgYGJlIGRlZmluZWQsIGJ1dCBpcyBub3QgKCR7aW5wdXRTaGFwZVtjaGFubmVsQXhpc119KS5gKTtcbiAgICB9XG4gICAgY29uc3QgaW5wdXREaW0gPSBpbnB1dFNoYXBlW2NoYW5uZWxBeGlzXTtcbiAgICBjb25zdCBkZXB0aHdpc2VLZXJuZWxTaGFwZTogU2hhcGUgPSBbXG4gICAgICB0aGlzLmtlcm5lbFNpemVbMF0sIHRoaXMua2VybmVsU2l6ZVsxXSwgaW5wdXREaW0sIHRoaXMuZGVwdGhNdWx0aXBsaWVyXG4gICAgXTtcblxuICAgIHRoaXMuZGVwdGh3aXNlS2VybmVsID0gdGhpcy5hZGRXZWlnaHQoXG4gICAgICAgICdkZXB0aHdpc2Vfa2VybmVsJywgZGVwdGh3aXNlS2VybmVsU2hhcGUsIG51bGwsXG4gICAgICAgIHRoaXMuZGVwdGh3aXNlSW5pdGlhbGl6ZXIsIHRoaXMuZGVwdGh3aXNlUmVndWxhcml6ZXIsIHRydWUsXG4gICAgICAgIHRoaXMuZGVwdGh3aXNlQ29uc3RyYWludCk7XG4gICAgaWYgKHRoaXMudXNlQmlhcykge1xuICAgICAgdGhpcy5iaWFzID0gdGhpcy5hZGRXZWlnaHQoXG4gICAgICAgICAgJ2JpYXMnLCBbaW5wdXREaW0gKiB0aGlzLmRlcHRoTXVsdGlwbGllcl0sIG51bGwsIHRoaXMuYmlhc0luaXRpYWxpemVyLFxuICAgICAgICAgIHRoaXMuYmlhc1JlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmJpYXNDb25zdHJhaW50KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5iaWFzID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5idWlsdCA9IHRydWU7XG4gIH1cblxuICBvdmVycmlkZSBjYWxsKGlucHV0czogVGVuc29yfFRlbnNvcltdLCBrd2FyZ3M6IEt3YXJncyk6IFRlbnNvcnxUZW5zb3JbXSB7XG4gICAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgICAgaW5wdXRzID0gZ2V0RXhhY3RseU9uZVRlbnNvcihpbnB1dHMpO1xuICAgICAgbGV0IG91dHB1dHMgPSBkZXB0aHdpc2VDb252MmQoXG4gICAgICAgICAgaW5wdXRzLCB0aGlzLmRlcHRod2lzZUtlcm5lbC5yZWFkKCksIHRoaXMuc3RyaWRlcyBhcyBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICAgIHRoaXMucGFkZGluZywgdGhpcy5kYXRhRm9ybWF0LCBudWxsKTtcbiAgICAgIC8vIFRPRE8oY2Fpcyk6IEFkZCBzdXBwb3J0IGZvciBkaWxhdGlvbi5cbiAgICAgIGlmICh0aGlzLnVzZUJpYXMpIHtcbiAgICAgICAgb3V0cHV0cyA9IEsuYmlhc0FkZChvdXRwdXRzLCB0aGlzLmJpYXMucmVhZCgpLCB0aGlzLmRhdGFGb3JtYXQpO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuYWN0aXZhdGlvbiAhPSBudWxsKSB7XG4gICAgICAgIG91dHB1dHMgPSB0aGlzLmFjdGl2YXRpb24uYXBwbHkob3V0cHV0cyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gb3V0cHV0cztcbiAgICB9KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXB1dGVPdXRwdXRTaGFwZShpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKTogU2hhcGV8U2hhcGVbXSB7XG4gICAgaW5wdXRTaGFwZSA9IGdldEV4YWN0bHlPbmVTaGFwZShpbnB1dFNoYXBlKTtcbiAgICBjb25zdCByb3dzID1cbiAgICAgICAgdGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcgPyBpbnB1dFNoYXBlWzJdIDogaW5wdXRTaGFwZVsxXTtcbiAgICBjb25zdCBjb2xzID1cbiAgICAgICAgdGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcgPyBpbnB1dFNoYXBlWzNdIDogaW5wdXRTaGFwZVsyXTtcbiAgICBjb25zdCBvdXRGaWx0ZXJzID0gdGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcgP1xuICAgICAgICBpbnB1dFNoYXBlWzFdICogdGhpcy5kZXB0aE11bHRpcGxpZXIgOlxuICAgICAgICBpbnB1dFNoYXBlWzNdICogdGhpcy5kZXB0aE11bHRpcGxpZXI7XG4gICAgY29uc3Qgb3V0Um93cyA9IGNvbnZPdXRwdXRMZW5ndGgoXG4gICAgICAgIHJvd3MsIHRoaXMua2VybmVsU2l6ZVswXSwgdGhpcy5wYWRkaW5nLCB0aGlzLnN0cmlkZXNbMF0pO1xuICAgIGNvbnN0IG91dENvbHMgPSBjb252T3V0cHV0TGVuZ3RoKFxuICAgICAgICBjb2xzLCB0aGlzLmtlcm5lbFNpemVbMV0sIHRoaXMucGFkZGluZywgdGhpcy5zdHJpZGVzWzFdKTtcbiAgICBpZiAodGhpcy5kYXRhRm9ybWF0ID09PSAnY2hhbm5lbHNGaXJzdCcpIHtcbiAgICAgIHJldHVybiBbaW5wdXRTaGFwZVswXSwgb3V0RmlsdGVycywgb3V0Um93cywgb3V0Q29sc107XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEluIHRoaXMgY2FzZSwgYXNzdW1lICdjaGFubmVsc0xhc3QnLlxuICAgICAgcmV0dXJuIFtpbnB1dFNoYXBlWzBdLCBvdXRSb3dzLCBvdXRDb2xzLCBvdXRGaWx0ZXJzXTtcbiAgICB9XG4gIH1cblxuICBvdmVycmlkZSBnZXRDb25maWcoKTogc2VyaWFsaXphdGlvbi5Db25maWdEaWN0IHtcbiAgICBjb25zdCBjb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBjb25maWdbJ2RlcHRoTXVsdGlwbGllciddID0gdGhpcy5kZXB0aE11bHRpcGxpZXI7XG4gICAgY29uZmlnWydkZXB0aHdpc2VJbml0aWFsaXplciddID1cbiAgICAgICAgc2VyaWFsaXplSW5pdGlhbGl6ZXIodGhpcy5kZXB0aHdpc2VJbml0aWFsaXplcik7XG4gICAgY29uZmlnWydkZXB0aHdpc2VSZWd1bGFyaXplciddID1cbiAgICAgICAgc2VyaWFsaXplUmVndWxhcml6ZXIodGhpcy5kZXB0aHdpc2VSZWd1bGFyaXplcik7XG4gICAgY29uZmlnWydkZXB0aHdpc2VDb25zdHJhaW50J10gPVxuICAgICAgICBzZXJpYWxpemVDb25zdHJhaW50KHRoaXMuZGVwdGh3aXNlUmVndWxhcml6ZXIpO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cbn1cbnNlcmlhbGl6YXRpb24ucmVnaXN0ZXJDbGFzcyhEZXB0aHdpc2VDb252MkQpO1xuIl19
\No newline at end of file