1 | /**
|
2 | * @license
|
3 | * Copyright 2021 Google LLC. All Rights Reserved.
|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | * you may not use this file except in compliance with the License.
|
6 | * You may obtain a copy of the License at
|
7 | *
|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
9 | *
|
10 | * Unless required by applicable law or agreed to in writing, software
|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13 | * See the License for the specific language governing permissions and
|
14 | * limitations under the License.
|
15 | * =============================================================================
|
16 | */
|
17 | import { ENGINE } from '../../engine';
|
18 | import { SparseFillEmptyRows } from '../../kernel_names';
|
19 | import { convertToTensor } from '../../tensor_util_env';
|
20 | import { op } from '../operation';
|
21 | /**
|
22 | * The input SparseTensor is represented via the map of inputs {`indices`,
|
23 | * `values`, `denseShape`}. The output SparseTensor has the same `denseShape`
|
24 | * but with indices `outputIndices` and values `outputValues`. This op inserts a
|
25 | * single entry for every row that doesn't have any values. The index is created
|
26 | * as `[row, 0, ..., 0]` and the inserted value is `defaultValue`.
|
27 | *
|
28 | * For example, suppose `spInput` has shape [5, 6] and non-empty values:
|
29 | * [0, 1]: a
|
30 | * [0, 3]: b
|
31 | * [2, 0]: c
|
32 | * [3, 1]: d
|
33 | *
|
34 | * Rows 1 and 4 are empty, so the output will be of shape [5, 6] with values:
|
35 | * [0, 1]: a
|
36 | * [0, 3]: b
|
37 | * [1, 0]: `defaultValue`
|
38 | * [2, 0]: c
|
39 | * [3, 1]: d
|
40 | * [4, 0]: `defaultValue`
|
41 | *
|
42 | * The output SparseTensor will be in row-major order and will have the same
|
43 | * shape as the input.
|
44 | *
|
45 | * This op also returns an indicator vector shaped [dense_shape[0]] such that
|
46 | * emptyRowIndicator[i] = True iff row i was an empty row.
|
47 | *
|
48 | * And a reverse index map vector shaped [indices.shape[0]] that is used during
|
49 | * backpropagation, reverseIndexMap[i] = outi s.t. indices[i, j] ==
|
50 | * outputIndices[outi, j] for all j
|
51 | *
|
52 | * ```js
|
53 | * const result = tf.sparse.sparseFillEmptyRows(
|
54 | * [[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]],
|
55 | * [0, 10, 13, 14, 32, 33], [5, 6], -1);
|
56 | * console.log(result);
|
57 | * result['outputIndices'].print(); // [[0, 0], [1, 0], [1, 3], [1, 4],
|
58 | * // [2, 0], [3, 2], [3, 3], [4, 0]]
|
59 | * result['outputValues'].print(); // [0, 10, 13, 14,-1, 32, 33, -1]
|
60 | * result['emptyRowIndicator'].print(); // [false, false, true, false, true]
|
61 | * result['reverseIndexMap'].print(); // [0, 1, 2, 3, 5, 6]
|
62 | * ```
|
63 | * @param indices: 2-D. the indices of the sparse tensor.
|
64 | * @param values: 1-D. the values of the sparse tensor.
|
65 | * @param denseShape: 1-D. the shape of the sparse tensor.
|
66 | * @param defaultValue: 0-D. default value to insert into location [row, 0, ...,
|
67 | * 0] for rows missing from the input sparse tensor.
|
68 | * @return A map with the following properties:
|
69 | * - outputIndices
|
70 | * - outputValues: 1-D. the values of the filled sparse tensor.
|
71 | * - emptyRowIndicator: 1-D. whether the dense row was missing in the input
|
72 | * sparse tensor.
|
73 | * - reverseIndexMap: 1-D. a map from the input indices to the output
|
74 | * indices.
|
75 | * @doc {heading: 'Operations', subheading: 'Sparse'}
|
76 | */
|
77 | function sparseFillEmptyRows_(indices, values, denseShape, defaultValue) {
|
78 | const $indices = convertToTensor(indices, 'indices', 'sparseFillEmptyRows', 'int32');
|
79 | const $values = convertToTensor(values, 'values', 'sparseFillEmptyRows');
|
80 | const $denseShape = convertToTensor(denseShape, 'denseShape', 'sparseFillEmptyRows', 'int32');
|
81 | const $defaultValue = convertToTensor(defaultValue, 'defaultValue', 'sparseFillEmptyRows', $values.dtype);
|
82 | if ($indices.rank !== 2) {
|
83 | throw new Error(`Indices should be Tensor2D but received shape
|
84 | ${$indices.shape}`);
|
85 | }
|
86 | if ($values.rank !== 1) {
|
87 | throw new Error(`Values should be Tensor1D but received shape ${$values.shape}`);
|
88 | }
|
89 | if ($denseShape.rank !== 1) {
|
90 | throw new Error(`Dense shape should be Tensor1D but received shape ${$denseShape.shape}`);
|
91 | }
|
92 | if ($defaultValue.rank !== 0) {
|
93 | throw new Error(`Default value should be a scalar but received shape ${$defaultValue.shape}`);
|
94 | }
|
95 | const inputs = {
|
96 | indices: $indices,
|
97 | values: $values,
|
98 | denseShape: $denseShape,
|
99 | defaultValue: $defaultValue
|
100 | };
|
101 | const result = ENGINE.runKernel(SparseFillEmptyRows, inputs);
|
102 | return {
|
103 | outputIndices: result[0],
|
104 | outputValues: result[1],
|
105 | emptyRowIndicator: result[2],
|
106 | reverseIndexMap: result[3]
|
107 | };
|
108 | }
|
109 | export const sparseFillEmptyRows = op({ sparseFillEmptyRows_ });
|
110 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhcnNlX2ZpbGxfZW1wdHlfcm93cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3RmanMtY29yZS9zcmMvb3BzL3NwYXJzZS9zcGFyc2VfZmlsbF9lbXB0eV9yb3dzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sRUFBQyxNQUFNLEVBQUMsTUFBTSxjQUFjLENBQUM7QUFDcEMsT0FBTyxFQUFDLG1CQUFtQixFQUE0QixNQUFNLG9CQUFvQixDQUFDO0FBR2xGLE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUV0RCxPQUFPLEVBQUMsRUFBRSxFQUFDLE1BQU0sY0FBYyxDQUFDO0FBRWhDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdURHO0FBQ0gsU0FBUyxvQkFBb0IsQ0FDekIsT0FBNEIsRUFBRSxNQUEyQixFQUN6RCxVQUErQixFQUMvQixZQUErQjtJQUNqQyxNQUFNLFFBQVEsR0FDVixlQUFlLENBQUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxxQkFBcUIsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUN4RSxNQUFNLE9BQU8sR0FBRyxlQUFlLENBQUMsTUFBTSxFQUFFLFFBQVEsRUFBRSxxQkFBcUIsQ0FBQyxDQUFDO0lBQ3pFLE1BQU0sV0FBVyxHQUNiLGVBQWUsQ0FBQyxVQUFVLEVBQUUsWUFBWSxFQUFFLHFCQUFxQixFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzlFLE1BQU0sYUFBYSxHQUFHLGVBQWUsQ0FDakMsWUFBWSxFQUFFLGNBQWMsRUFBRSxxQkFBcUIsRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFeEUsSUFBSSxRQUFRLENBQUMsSUFBSSxLQUFLLENBQUMsRUFBRTtRQUN2QixNQUFNLElBQUksS0FBSyxDQUFDO1VBQ1YsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7S0FDekI7SUFDRCxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssQ0FBQyxFQUFFO1FBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQ1gsZ0RBQWdELE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0tBQ3RFO0lBQ0QsSUFBSSxXQUFXLENBQUMsSUFBSSxLQUFLLENBQUMsRUFBRTtRQUMxQixNQUFNLElBQUksS0FBSyxDQUFDLHFEQUNaLFdBQVcsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0tBQzFCO0lBQ0QsSUFBSSxhQUFhLENBQUMsSUFBSSxLQUFLLENBQUMsRUFBRTtRQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLHVEQUNaLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0tBQzVCO0lBRUQsTUFBTSxNQUFNLEdBQThCO1FBQ3hDLE9BQU8sRUFBRSxRQUFRO1FBQ2pCLE1BQU0sRUFBRSxPQUFPO1FBQ2YsVUFBVSxFQUFFLFdBQVc7UUFDdkIsWUFBWSxFQUFFLGFBQWE7S0FDNUIsQ0FBQztJQUVGLE1BQU0sTUFBTSxHQUFhLE1BQU0sQ0FBQyxTQUFTLENBQUMsbUJBQW1CLEVBQUUsTUFBWSxDQUFDLENBQUM7SUFDN0UsT0FBTztRQUNMLGFBQWEsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3hCLFlBQVksRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZCLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDNUIsZUFBZSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7S0FDM0IsQ0FBQztBQUNKLENBQUM7QUFFRCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxFQUFFLENBQUMsRUFBQyxvQkFBb0IsRUFBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAyMSBHb29nbGUgTExDLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbmltcG9ydCB7RU5HSU5FfSBmcm9tICcuLi8uLi9lbmdpbmUnO1xuaW1wb3J0IHtTcGFyc2VGaWxsRW1wdHlSb3dzLCBTcGFyc2VGaWxsRW1wdHlSb3dzSW5wdXRzfSBmcm9tICcuLi8uLi9rZXJuZWxfbmFtZXMnO1xuaW1wb3J0IHtTY2FsYXIsIFRlbnNvciwgVGVuc29yMUQsIFRlbnNvcjJEfSBmcm9tICcuLi8uLi90ZW5zb3InO1xuaW1wb3J0IHtOYW1lZFRlbnNvck1hcH0gZnJvbSAnLi4vLi4vdGVuc29yX3R5cGVzJztcbmltcG9ydCB7Y29udmVydFRvVGVuc29yfSBmcm9tICcuLi8uLi90ZW5zb3JfdXRpbF9lbnYnO1xuaW1wb3J0IHtTY2FsYXJMaWtlLCBUZW5zb3JMaWtlfSBmcm9tICcuLi8uLi90eXBlcyc7XG5pbXBvcnQge29wfSBmcm9tICcuLi9vcGVyYXRpb24nO1xuXG4vKipcbiAqIFRoZSBpbnB1dCBTcGFyc2VUZW5zb3IgaXMgcmVwcmVzZW50ZWQgdmlhIHRoZSBtYXAgb2YgaW5wdXRzIHtgaW5kaWNlc2AsXG4gKiBgdmFsdWVzYCwgYGRlbnNlU2hhcGVgfS4gVGhlIG91dHB1dCBTcGFyc2VUZW5zb3IgaGFzIHRoZSBzYW1lIGBkZW5zZVNoYXBlYFxuICogYnV0IHdpdGggaW5kaWNlcyBgb3V0cHV0SW5kaWNlc2AgYW5kIHZhbHVlcyBgb3V0cHV0VmFsdWVzYC4gVGhpcyBvcCBpbnNlcnRzIGFcbiAqIHNpbmdsZSBlbnRyeSBmb3IgZXZlcnkgcm93IHRoYXQgZG9lc24ndCBoYXZlIGFueSB2YWx1ZXMuIFRoZSBpbmRleCBpcyBjcmVhdGVkXG4gKiBhcyBgW3JvdywgMCwgLi4uLCAwXWAgYW5kIHRoZSBpbnNlcnRlZCB2YWx1ZSBpcyBgZGVmYXVsdFZhbHVlYC5cbiAqXG4gKiBGb3IgZXhhbXBsZSwgc3VwcG9zZSBgc3BJbnB1dGAgaGFzIHNoYXBlIFs1LCA2XSBhbmQgbm9uLWVtcHR5IHZhbHVlczpcbiAqIFswLCAxXTogYVxuICogWzAsIDNdOiBiXG4gKiBbMiwgMF06IGNcbiAqIFszLCAxXTogZFxuICpcbiAqIFJvd3MgMSBhbmQgNCBhcmUgZW1wdHksIHNvIHRoZSBvdXRwdXQgd2lsbCBiZSBvZiBzaGFwZSBbNSwgNl0gd2l0aCB2YWx1ZXM6XG4gKiBbMCwgMV06IGFcbiAqIFswLCAzXTogYlxuICogWzEsIDBdOiBgZGVmYXVsdFZhbHVlYFxuICogWzIsIDBdOiBjXG4gKiBbMywgMV06IGRcbiAqIFs0LCAwXTogYGRlZmF1bHRWYWx1ZWBcbiAqXG4gKiBUaGUgb3V0cHV0IFNwYXJzZVRlbnNvciB3aWxsIGJlIGluIHJvdy1tYWpvciBvcmRlciBhbmQgd2lsbCBoYXZlIHRoZSBzYW1lXG4gKiBzaGFwZSBhcyB0aGUgaW5wdXQuXG4gKlxuICogVGhpcyBvcCBhbHNvIHJldHVybnMgYW4gaW5kaWNhdG9yIHZlY3RvciBzaGFwZWQgW2RlbnNlX3NoYXBlWzBdXSBzdWNoIHRoYXRcbiAqIGVtcHR5Um93SW5kaWNhdG9yW2ldID0gVHJ1ZSBpZmYgcm93IGkgd2FzIGFuIGVtcHR5IHJvdy5cbiAqXG4gKiBBbmQgYSByZXZlcnNlIGluZGV4IG1hcCB2ZWN0b3Igc2hhcGVkIFtpbmRpY2VzLnNoYXBlWzBdXSB0aGF0IGlzIHVzZWQgZHVyaW5nXG4gKiBiYWNrcHJvcGFnYXRpb24sIHJldmVyc2VJbmRleE1hcFtpXSA9IG91dGkgcy50LiBpbmRpY2VzW2ksIGpdID09XG4gKiBvdXRwdXRJbmRpY2VzW291dGksIGpdIGZvciBhbGwgalxuICpcbiAqIGBgYGpzXG4gKiBjb25zdCByZXN1bHQgPSB0Zi5zcGFyc2Uuc3BhcnNlRmlsbEVtcHR5Um93cyhcbiAqICAgW1swLCAwXSwgWzEsIDBdLCBbMSwgM10sIFsxLCA0XSwgWzMsIDJdLCBbMywgM11dLFxuICogICBbMCwgMTAsIDEzLCAxNCwgMzIsIDMzXSwgWzUsIDZdLCAtMSk7XG4gKiBjb25zb2xlLmxvZyhyZXN1bHQpO1xuICogcmVzdWx0WydvdXRwdXRJbmRpY2VzJ10ucHJpbnQoKTsgLy8gW1swLCAwXSwgWzEsIDBdLCBbMSwgM10sIFsxLCA0XSxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICBbMiwgMF0sIFszLCAyXSwgWzMsIDNdLCBbNCwgMF1dXG4gKiByZXN1bHRbJ291dHB1dFZhbHVlcyddLnByaW50KCk7IC8vIFswLCAxMCwgMTMsIDE0LC0xLCAzMiwgMzMsIC0xXVxuICogcmVzdWx0WydlbXB0eVJvd0luZGljYXRvciddLnByaW50KCk7IC8vIFtmYWxzZSwgZmFsc2UsIHRydWUsIGZhbHNlLCB0cnVlXVxuICogcmVzdWx0WydyZXZlcnNlSW5kZXhNYXAnXS5wcmludCgpOyAvLyBbMCwgMSwgMiwgMywgNSwgNl1cbiAqIGBgYFxuICogQHBhcmFtIGluZGljZXM6IDItRC4gdGhlIGluZGljZXMgb2YgdGhlIHNwYXJzZSB0ZW5zb3IuXG4gKiBAcGFyYW0gdmFsdWVzOiAxLUQuIHRoZSB2YWx1ZXMgb2YgdGhlIHNwYXJzZSB0ZW5zb3IuXG4gKiBAcGFyYW0gZGVuc2VTaGFwZTogMS1ELiB0aGUgc2hhcGUgb2YgdGhlIHNwYXJzZSB0ZW5zb3IuXG4gKiBAcGFyYW0gZGVmYXVsdFZhbHVlOiAwLUQuIGRlZmF1bHQgdmFsdWUgdG8gaW5zZXJ0IGludG8gbG9jYXRpb24gW3JvdywgMCwgLi4uLFxuICogICAgIDBdIGZvciByb3dzIG1pc3NpbmcgZnJvbSB0aGUgaW5wdXQgc3BhcnNlIHRlbnNvci5cbiAqIEByZXR1cm4gQSBtYXAgd2l0aCB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gKiAgICAgLSBvdXRwdXRJbmRpY2VzXG4gKiAgICAgLSBvdXRwdXRWYWx1ZXM6IDEtRC4gdGhlIHZhbHVlcyBvZiB0aGUgZmlsbGVkIHNwYXJzZSB0ZW5zb3IuXG4gKiAgICAgLSBlbXB0eVJvd0luZGljYXRvcjogMS1ELiB3aGV0aGVyIHRoZSBkZW5zZSByb3cgd2FzIG1pc3NpbmcgaW4gdGhlIGlucHV0XG4gKiBzcGFyc2UgdGVuc29yLlxuICogICAgIC0gcmV2ZXJzZUluZGV4TWFwOiAxLUQuIGEgbWFwIGZyb20gdGhlIGlucHV0IGluZGljZXMgdG8gdGhlIG91dHB1dFxuICogaW5kaWNlcy5cbiAqIEBkb2Mge2hlYWRpbmc6ICdPcGVyYXRpb25zJywgc3ViaGVhZGluZzogJ1NwYXJzZSd9XG4gKi9cbmZ1bmN0aW9uIHNwYXJzZUZpbGxFbXB0eVJvd3NfKFxuICAgIGluZGljZXM6IFRlbnNvcjJEfFRlbnNvckxpa2UsIHZhbHVlczogVGVuc29yMUR8VGVuc29yTGlrZSxcbiAgICBkZW5zZVNoYXBlOiBUZW5zb3IxRHxUZW5zb3JMaWtlLFxuICAgIGRlZmF1bHRWYWx1ZTogU2NhbGFyfFNjYWxhckxpa2UpOiBOYW1lZFRlbnNvck1hcCB7XG4gIGNvbnN0ICRpbmRpY2VzID1cbiAgICAgIGNvbnZlcnRUb1RlbnNvcihpbmRpY2VzLCAnaW5kaWNlcycsICdzcGFyc2VGaWxsRW1wdHlSb3dzJywgJ2ludDMyJyk7XG4gIGNvbnN0ICR2YWx1ZXMgPSBjb252ZXJ0VG9UZW5zb3IodmFsdWVzLCAndmFsdWVzJywgJ3NwYXJzZUZpbGxFbXB0eVJvd3MnKTtcbiAgY29uc3QgJGRlbnNlU2hhcGUgPVxuICAgICAgY29udmVydFRvVGVuc29yKGRlbnNlU2hhcGUsICdkZW5zZVNoYXBlJywgJ3NwYXJzZUZpbGxFbXB0eVJvd3MnLCAnaW50MzInKTtcbiAgY29uc3QgJGRlZmF1bHRWYWx1ZSA9IGNvbnZlcnRUb1RlbnNvcihcbiAgICAgIGRlZmF1bHRWYWx1ZSwgJ2RlZmF1bHRWYWx1ZScsICdzcGFyc2VGaWxsRW1wdHlSb3dzJywgJHZhbHVlcy5kdHlwZSk7XG5cbiAgaWYgKCRpbmRpY2VzLnJhbmsgIT09IDIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEluZGljZXMgc2hvdWxkIGJlIFRlbnNvcjJEIGJ1dCByZWNlaXZlZCBzaGFwZVxuICAgICAgICAkeyRpbmRpY2VzLnNoYXBlfWApO1xuICB9XG4gIGlmICgkdmFsdWVzLnJhbmsgIT09IDEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBWYWx1ZXMgc2hvdWxkIGJlIFRlbnNvcjFEIGJ1dCByZWNlaXZlZCBzaGFwZSAkeyR2YWx1ZXMuc2hhcGV9YCk7XG4gIH1cbiAgaWYgKCRkZW5zZVNoYXBlLnJhbmsgIT09IDEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERlbnNlIHNoYXBlIHNob3VsZCBiZSBUZW5zb3IxRCBidXQgcmVjZWl2ZWQgc2hhcGUgJHtcbiAgICAgICAgJGRlbnNlU2hhcGUuc2hhcGV9YCk7XG4gIH1cbiAgaWYgKCRkZWZhdWx0VmFsdWUucmFuayAhPT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRGVmYXVsdCB2YWx1ZSBzaG91bGQgYmUgYSBzY2FsYXIgYnV0IHJlY2VpdmVkIHNoYXBlICR7XG4gICAgICAgICRkZWZhdWx0VmFsdWUuc2hhcGV9YCk7XG4gIH1cblxuICBjb25zdCBpbnB1dHM6IFNwYXJzZUZpbGxFbXB0eVJvd3NJbnB1dHMgPSB7XG4gICAgaW5kaWNlczogJGluZGljZXMsXG4gICAgdmFsdWVzOiAkdmFsdWVzLFxuICAgIGRlbnNlU2hhcGU6ICRkZW5zZVNoYXBlLFxuICAgIGRlZmF1bHRWYWx1ZTogJGRlZmF1bHRWYWx1ZVxuICB9O1xuXG4gIGNvbnN0IHJlc3VsdDogVGVuc29yW10gPSBFTkdJTkUucnVuS2VybmVsKFNwYXJzZUZpbGxFbXB0eVJvd3MsIGlucHV0cyBhcyB7fSk7XG4gIHJldHVybiB7XG4gICAgb3V0cHV0SW5kaWNlczogcmVzdWx0WzBdLFxuICAgIG91dHB1dFZhbHVlczogcmVzdWx0WzFdLFxuICAgIGVtcHR5Um93SW5kaWNhdG9yOiByZXN1bHRbMl0sXG4gICAgcmV2ZXJzZUluZGV4TWFwOiByZXN1bHRbM11cbiAgfTtcbn1cblxuZXhwb3J0IGNvbnN0IHNwYXJzZUZpbGxFbXB0eVJvd3MgPSBvcCh7c3BhcnNlRmlsbEVtcHR5Um93c199KTtcbiJdfQ== |
\ | No newline at end of file |