/** * @license * Copyright 2020 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============================================================================= */ import { backend_util, env, util } from '@tensorflow/tfjs-core'; import { ConcatProgram } from '../concat_gpu'; import { ConcatPackedProgram } from '../concat_packed_gpu'; import { concatImplCPU } from '../kernel_utils/shared'; import { CLONE, UnaryOpProgram } from '../unaryop_gpu'; import { UnaryOpPackedProgram } from '../unaryop_packed_gpu'; import { complex } from './Complex'; import { imag } from './Imag'; import { real } from './Real'; import { reshape } from './Reshape'; export function concatImpl(inputs, axis, backend) { const dtype = inputs[0].dtype; if (dtype === 'complex64') { const reals = inputs.map((t) => real({ inputs: { input: t }, backend })); const imags = inputs.map((t) => imag({ inputs: { input: t }, backend })); const realConcated = concatImpl(reals, axis, backend); const imagConcated = concatImpl(imags, axis, backend); const result = complex({ inputs: { real: realConcated, imag: imagConcated }, backend }); reals.forEach(r => backend.disposeIntermediateTensorInfo(r)); imags.forEach(i => backend.disposeIntermediateTensorInfo(i)); backend.disposeIntermediateTensorInfo(realConcated); backend.disposeIntermediateTensorInfo(imagConcated); return result; } let runOnCpu = backend.shouldExecuteOnCPU(inputs); // Run on cpu if dtype is string. For string, the backend represents it // as Uint8Array[], where each Uint8Array is a character. Given that the // computation is only on the outer array, uploading the whole data onto // gpu is wasteful. Also, currently webgl doesn't have a design to // upload and retrieve Uint8Array[] between cpu and gpu. Therefore, we // just run the kernel on cpu if dtype is string. if (dtype === 'string') { runOnCpu = true; } if (runOnCpu) { // Any concat of n-dimensional tensors across any axis can be reduced to // a concatenation of two-dimensional tensors across the axis 1 by first // partitioning the axes of the original tensors into those less than the // axis to be concatenated and the rest. Then reshape the tensors // into a two-dimensional tensor by collapsing these two sets of axes and // concatenate the resulting matrices across the axis 1, finally reshaping // the result to have the proper shape. const tensors2D = inputs.map(t => { const innerSize = util.sizeFromShape(t.shape.slice(axis)); const shape = [-1, innerSize]; return reshape({ inputs: { x: t }, backend, attrs: { shape } }); }); const inputsValShapes = tensors2D.map(t => { return { vals: backend.readSync(t.dataId), shape: t.shape }; }); // Concats 2d tensors along axis=1. const outShape = backend_util.computeOutShape(tensors2D.map(t => t.shape), 1 /* axis */); const simplyConcat = tensors2D[0].shape[0] === 1; const outVals = concatImplCPU(inputsValShapes, outShape, dtype, simplyConcat); const finalOutShape = backend_util.computeOutShape(inputs.map(t => t.shape), axis); const outInfo = backend.makeTensorInfo(finalOutShape, dtype, outVals); tensors2D.forEach(t => backend.disposeIntermediateTensorInfo(t)); return outInfo; } // Keep only non-empty tensors (ignore tensors with 0 in their shape). const $inputs = inputs.filter(t => util.sizeFromShape(t.shape) > 0); const shouldPack = env().getBool('WEBGL_PACK_ARRAY_OPERATIONS') && $inputs[0].shape.length > 1; if ($inputs.length === 1) { // Clone tensor. const program = shouldPack ? new UnaryOpProgram(inputs[0].shape, CLONE) : new UnaryOpPackedProgram(inputs[0].shape, CLONE); return backend.runWebGLProgram(program, inputs, dtype); } const maxTexturesInShader = env().getNumber('WEBGL_MAX_TEXTURES_IN_SHADER'); if ($inputs.length > maxTexturesInShader) { const reducedInputs = []; for (let i = 0; i < $inputs.length; i += maxTexturesInShader) { const subArray = $inputs.slice(i, i + maxTexturesInShader); reducedInputs.push(concatImpl(subArray, axis, backend)); } const result = concatImpl(reducedInputs, axis, backend); for (const i of reducedInputs) { backend.disposeIntermediateTensorInfo(i); } return result; } if (shouldPack) { const program = new ConcatPackedProgram($inputs.map(t => t.shape), axis); return backend.runWebGLProgram(program, $inputs, dtype); } const { tensors2D, outShape } = computeTensors2D($inputs, axis, backend); const program = new ConcatProgram(tensors2D.map(t => t.shape)); const result = backend.runWebGLProgram(program, tensors2D, dtype); tensors2D.forEach(r => backend.disposeIntermediateTensorInfo(r)); const reshapedResult = reshape({ inputs: { x: result }, attrs: { shape: outShape }, backend }); backend.disposeIntermediateTensorInfo(result); return reshapedResult; } function computeTensors2D(inputs, axis, backend) { // Any concat of n-dimensional tensors across any axis can be reduced to // a concatenation of two-dimensional tensors across the axis 1 by first // partitioning the axes of the original tensors into those less than the // axis to be concatenated and the rest. Then reshape the tensors // into a two-dimensional tensor by collapsing these two sets of axes and // concatenate the resulting matrices across the axis 1, finally reshaping // the result to have the proper shape. const outShape = backend_util.computeOutShape(inputs.map(t => t.shape), axis); const tensors2D = inputs.map(x => reshape({ inputs: { x }, attrs: { shape: [-1, util.sizeFromShape(x.shape.slice(axis))] }, backend })); return { tensors2D, outShape }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29uY2F0X2ltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi90ZmpzLWJhY2tlbmQtd2ViZ2wvc3JjL2tlcm5lbHMvQ29uY2F0X2ltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsT0FBTyxFQUFDLFlBQVksRUFBZ0IsR0FBRyxFQUFjLElBQUksRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBR3hGLE9BQU8sRUFBQyxhQUFhLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDNUMsT0FBTyxFQUFDLG1CQUFtQixFQUFDLE1BQU0sc0JBQXNCLENBQUM7QUFDekQsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLHdCQUF3QixDQUFDO0FBQ3JELE9BQU8sRUFBQyxLQUFLLEVBQUUsY0FBYyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDckQsT0FBTyxFQUFDLG9CQUFvQixFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFFM0QsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUNsQyxPQUFPLEVBQUMsSUFBSSxFQUFDLE1BQU0sUUFBUSxDQUFDO0FBQzVCLE9BQU8sRUFBQyxJQUFJLEVBQUMsTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUVsQyxNQUFNLFVBQVUsVUFBVSxDQUN0QixNQUFvQixFQUFFLElBQVksRUFBRSxPQUF5QjtJQUMvRCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQzlCLElBQUksS0FBSyxLQUFLLFdBQVcsRUFBRTtRQUN6QixNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBQyxNQUFNLEVBQUUsRUFBQyxLQUFLLEVBQUUsQ0FBQyxFQUFDLEVBQUUsT0FBTyxF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S0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBQztRQUM3RCxPQUFPO0tBQ1IsQ0FBQyxDQUFDLENBQUM7SUFFUixPQUFPLEVBQUMsU0FBUyxFQUFFLFFBQVEsRUFBQyxDQUFDO0FBQy9CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAyMCBHb29nbGUgTExDLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbmltcG9ydCB7YmFja2VuZF91dGlsLCBDb25jYXRJbnB1dHMsIGVudiwgVGVuc29ySW5mbywgdXRpbH0gZnJvbSAnQHRlbnNvcmZsb3cvdGZqcy1jb3JlJztcblxuaW1wb3J0IHtNYXRoQmFja2VuZFdlYkdMfSBmcm9tICcuLi9iYWNrZW5kX3dlYmdsJztcbmltcG9ydCB7Q29uY2F0UHJvZ3JhbX0gZnJvbSAnLi4vY29uY2F0X2dwdSc7XG5pbXBvcnQge0NvbmNhdFBhY2tlZFByb2dyYW19IGZyb20gJy4uL2NvbmNhdF9wYWNrZWRfZ3B1JztcbmltcG9ydCB7Y29uY2F0SW1wbENQVX0gZnJvbSAnLi4va2VybmVsX3V0aWxzL3NoYXJlZCc7XG5pbXBvcnQge0NMT05FLCBVbmFyeU9wUHJvZ3JhbX0gZnJvbSAnLi4vdW5hcnlvcF9ncHUnO1xuaW1wb3J0IHtVbmFyeU9wUGFja2VkUHJvZ3JhbX0gZnJvbSAnLi4vdW5hcnlvcF9wYWNrZWRfZ3B1JztcblxuaW1wb3J0IHtjb21wbGV4fSBmcm9tICcuL0NvbXBsZXgnO1xuaW1wb3J0IHtpbWFnfSBmcm9tICcuL0ltYWcnO1xuaW1wb3J0IHtyZWFsfSBmcm9tICcuL1JlYWwnO1xuaW1wb3J0IHtyZXNoYXBlfSBmcm9tICcuL1Jlc2hhcGUnO1xuXG5leHBvcnQgZnVuY3Rpb24gY29uY2F0SW1wbChcbiAgICBpbnB1dHM6IENvbmNhdElucHV0cywgYXhpczogbnVtYmVyLCBiYWNrZW5kOiBNYXRoQmFja2VuZFdlYkdMKTogVGVuc29ySW5mbyB7XG4gIGNvbnN0IGR0eXBlID0gaW5wdXRzWzBdLmR0eXBlO1xuICBpZiAoZHR5cGUgPT09ICdjb21wbGV4NjQnKSB7XG4gICAgY29uc3QgcmVhbHMgPSBpbnB1dHMubWFwKCh0KSA9PiByZWFsKHtpbnB1dHM6IHtpbnB1dDogdH0sIGJhY2tlbmR9KSk7XG4gICAgY29uc3QgaW1hZ3MgPSBpbnB1dHMubWFwKCh0KSA9PiBpbWFnKHtpbnB1dHM6IHtpbnB1dDogdH0sIGJhY2tlbmR9KSk7XG5cbiAgICBjb25zdCByZWFsQ29uY2F0ZWQgPSBjb25jYXRJbXBsKHJlYWxzLCBheGlzLCBiYWNrZW5kKTtcbiAgICBjb25zdCBpbWFnQ29uY2F0ZWQgPSBjb25jYXRJbXBsKGltYWdzLCBheGlzLCBiYWNrZW5kKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9XG4gICAgICAgIGNvbXBsZXgoe2lucHV0czoge3JlYWw6IHJlYWxDb25jYXRlZCwgaW1hZzogaW1hZ0NvbmNhdGVkfSwgYmFja2VuZH0pO1xuXG4gICAgcmVhbHMuZm9yRWFjaChyID0+IGJhY2tlbmQuZGlzcG9zZUludGVybWVkaWF0ZVRlbnNvckluZm8ocikpO1xuICAgIGltYWdzLmZvckVhY2goaSA9PiBiYWNrZW5kLmRpc3Bvc2VJbnRlcm1lZGlhdGVUZW5zb3JJbmZvKGkpKTtcbiAgICBiYWNrZW5kLmRpc3Bvc2VJbnRlcm1lZGlhdGVUZW5zb3JJbmZvKHJlYWxDb25jYXRlZCk7XG4gICAgYmFja2VuZC5kaXNwb3NlSW50ZXJtZWRpYXRlVGVuc29ySW5mbyhpbWFnQ29uY2F0ZWQpO1xuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGxldCBydW5PbkNwdSA9IGJhY2tlbmQuc2hvdWxkRXhlY3V0ZU9uQ1BVKGlucHV0cyk7XG5cbiAgLy8gUnVuIG9uIGNwdSBpZiBkdHlwZSBpcyBzdHJpbmcuIEZvciBzdHJpbmcsIHRoZSBiYWNrZW5kIHJlcHJlc2VudHMgaXRcbiAgLy8gYXMgVWludDhBcnJheVtdLCB3aGVyZSBlYWNoIFVpbnQ4QXJyYXkgaXMgYSBjaGFyYWN0ZXIuIEdpdmVuIHRoYXQgdGhlXG4gIC8vIGNvbXB1dGF0aW9uIGlzIG9ubHkgb24gdGhlIG91dGVyIGFycmF5LCB1cGxvYWRpbmcgdGhlIHdob2xlIGRhdGEgb250b1xuICAvLyBncHUgaXMgd2FzdGVmdWwuIEFsc28sIGN1cnJlbnRseSB3ZWJnbCBkb2Vzbid0IGhhdmUgYSBkZXNpZ24gdG9cbiAgLy8gdXBsb2FkIGFuZCByZXRyaWV2ZSBVaW50OEFycmF5W10gYmV0d2VlbiBjcHUgYW5kIGdwdS4gVGhlcmVmb3JlLCB3ZVxuICAvLyBqdXN0IHJ1biB0aGUga2VybmVsIG9uIGNwdSBpZiBkdHlwZSBpcyBzdHJpbmcuXG4gIGlmIChkdHlwZSA9PT0gJ3N0cmluZycpIHtcbiAgICBydW5PbkNwdSA9IHRydWU7XG4gIH1cblxuICBpZiAocnVuT25DcHUpIHtcbiAgICAvLyBBbnkgY29uY2F0IG9mIG4tZGltZW5zaW9uYWwgdGVuc29ycyBhY3Jvc3MgYW55IGF4aXMgY2FuIGJlIHJlZHVjZWQgdG9cbiAgICAvLyBhIGNvbmNhdGVuYXRpb24gb2YgdHdvLWRpbWVuc2lvbmFsIHRlbnNvcnMgYWNyb3NzIHRoZSBheGlzIDEgYnkgZmlyc3RcbiAgICAvLyBwYXJ0aXRpb25pbmcgdGhlIGF4ZXMgb2YgdGhlIG9yaWdpbmFsIHRlbnNvcnMgaW50byB0aG9zZSBsZXNzIHRoYW4gdGhlXG4gICAgLy8gYXhpcyB0byBiZSBjb25jYXRlbmF0ZWQgYW5kIHRoZSByZXN0LiBUaGVuIHJlc2hhcGUgdGhlIHRlbnNvcnNcbiAgICAvLyBpbnRvIGEgdHdvLWRpbWVuc2lvbmFsIHRlbnNvciBieSBjb2xsYXBzaW5nIHRoZXNlIHR3byBzZXRzIG9mIGF4ZXMgYW5kXG4gICAgLy8gY29uY2F0ZW5hdGUgdGhlIHJlc3VsdGluZyBtYXRyaWNlcyBhY3Jvc3MgdGhlIGF4aXMgMSwgZmluYWxseSByZXNoYXBpbmdcbiAgICAvLyB0aGUgcmVzdWx0IHRvIGhhdmUgdGhlIHByb3BlciBzaGFwZS5cbiAgICBjb25zdCB0ZW5zb3JzMkQgPSBpbnB1dHMubWFwKHQgPT4ge1xuICAgICAgY29uc3QgaW5uZXJTaXplID0gdXRpbC5zaXplRnJvbVNoYXBlKHQuc2hhcGUuc2xpY2UoYXhpcykpO1xuICAgICAgY29uc3Qgc2hhcGUgPSBbLTEsIGlubmVyU2l6ZV07XG4gICAgICByZXR1cm4gcmVzaGFwZSh7aW5wdXRzOiB7eDogdH0sIGJhY2tlbmQsIGF0dHJzOiB7c2hhcGV9fSk7XG4gICAgfSk7XG5cbiAgICBjb25zdCBpbnB1dHNWYWxTaGFwZXMgPSB0ZW5zb3JzMkQubWFwKHQgPT4ge1xuICAgICAgcmV0dXJuIHt2YWxzOiBiYWNrZW5kLnJlYWRTeW5jKHQuZGF0YUlkKSwgc2hhcGU6IHQuc2hhcGV9O1xuICAgIH0pO1xuXG4gICAgLy8gQ29uY2F0cyAyZCB0ZW5zb3JzIGFsb25nIGF4aXM9MS5cbiAgICBjb25zdCBvdXRTaGFwZSA9XG4gICAgICAgIGJhY2tlbmRfdXRpbC5jb21wdXRlT3V0U2hhcGUodGVuc29yczJELm1hcCh0ID0+IHQuc2hhcGUpLCAxIC8qIGF4aXMgKi8pO1xuICAgIGNvbnN0IHNpbXBseUNvbmNhdCA9IHRlbnNvcnMyRFswXS5zaGFwZVswXSA9PT0gMTtcbiAgICBjb25zdCBvdXRWYWxzID1cbiAgICAgICAgY29uY2F0SW1wbENQVShpbnB1dHNWYWxTaGFwZXMsIG91dFNoYXBlLCBkdHlwZSwgc2ltcGx5Q29uY2F0KTtcblxuICAgIGNvbnN0IGZpbmFsT3V0U2hhcGUgPVxuICAgICAgICBiYWNrZW5kX3V0aWwuY29tcHV0ZU91dFNoYXBlKGlucHV0cy5tYXAodCA9PiB0LnNoYXBlKSwgYXhpcyk7XG5cbiAgICBjb25zdCBvdXRJbmZvID0gYmFja2VuZC5tYWtlVGVuc29ySW5mbyhmaW5hbE91dFNoYXBlLCBkdHlwZSwgb3V0VmFscyk7XG5cbiAgICB0ZW5zb3JzMkQuZm9yRWFjaCh0ID0+IGJhY2tlbmQuZGlzcG9zZUludGVybWVkaWF0ZVRlbnNvckluZm8odCkpO1xuXG4gICAgcmV0dXJuIG91dEluZm87XG4gIH1cblxuICAvLyBLZWVwIG9ubHkgbm9uLWVtcHR5IHRlbnNvcnMgKGlnbm9yZSB0ZW5zb3JzIHdpdGggMCBpbiB0aGVpciBzaGFwZSkuXG4gIGNvbnN0ICRpbnB1dHMgPSBpbnB1dHMuZmlsdGVyKHQgPT4gdXRpbC5zaXplRnJvbVNoYXBlKHQuc2hhcGUpID4gMCk7XG5cbiAgY29uc3Qgc2hvdWxkUGFjazogYm9vbGVhbiA9IGVudigpLmdldEJvb2woJ1dFQkdMX1BBQ0tfQVJSQVlfT1BFUkFUSU9OUycpICYmXG4gICAgICAkaW5wdXRzWzBdLnNoYXBlLmxlbmd0aCA+IDE7XG5cbiAgaWYgKCRpbnB1dHMubGVuZ3RoID09PSAxKSB7XG4gICAgLy8gQ2xvbmUgdGVuc29yLlxuICAgIGNvbnN0IHByb2dyYW0gPSBzaG91bGRQYWNrID9cbiAgICAgICAgbmV3IFVuYXJ5T3BQcm9ncmFtKGlucHV0c1swXS5zaGFwZSwgQ0xPTkUpIDpcbiAgICAgICAgbmV3IFVuYXJ5T3BQYWNrZWRQcm9ncmFtKGlucHV0c1swXS5zaGFwZSwgQ0xPTkUpO1xuICAgIHJldHVybiBiYWNrZW5kLnJ1bldlYkdMUHJvZ3JhbShwcm9ncmFtLCBpbnB1dHMsIGR0eXBlKTtcbiAgfVxuXG4gIGNvbnN0IG1heFRleHR1cmVzSW5TaGFkZXIgPSBlbnYoKS5nZXROdW1iZXIoJ1dFQkdMX01BWF9URVhUVVJFU19JTl9TSEFERVInKTtcbiAgaWYgKCRpbnB1dHMubGVuZ3RoID4gbWF4VGV4dHVyZXNJblNoYWRlcikge1xuICAgIGNvbnN0IHJlZHVjZWRJbnB1dHMgPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8ICRpbnB1dHMubGVuZ3RoOyBpICs9IG1heFRleHR1cmVzSW5TaGFkZXIpIHtcbiAgICAgIGNvbnN0IHN1YkFycmF5ID0gJGlucHV0cy5zbGljZShpLCBpICsgbWF4VGV4dHVyZXNJblNoYWRlcik7XG4gICAgICByZWR1Y2VkSW5wdXRzLnB1c2goY29uY2F0SW1wbChzdWJBcnJheSwgYXhpcywgYmFja2VuZCkpO1xuICAgIH1cbiAgICBjb25zdCByZXN1bHQgPSBjb25jYXRJbXBsKHJlZHVjZWRJbnB1dHMsIGF4aXMsIGJhY2tlbmQpO1xuXG4gICAgZm9yIChjb25zdCBpIG9mIHJlZHVjZWRJbnB1dHMpIHtcbiAgICAgIGJhY2tlbmQuZGlzcG9zZUludGVybWVkaWF0ZVRlbnNvckluZm8oaSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGlmIChzaG91bGRQYWNrKSB7XG4gICAgY29uc3QgcHJvZ3JhbSA9IG5ldyBDb25jYXRQYWNrZWRQcm9ncmFtKCRpbnB1dHMubWFwKHQgPT4gdC5zaGFwZSksIGF4aXMpO1xuICAgIHJldHVybiBiYWNrZW5kLnJ1bldlYkdMUHJvZ3JhbShwcm9ncmFtLCAkaW5wdXRzLCBkdHlwZSk7XG4gIH1cblxuICBjb25zdCB7dGVuc29yczJELCBvdXRTaGFwZX0gPSBjb21wdXRlVGVuc29yczJEKCRpbnB1dHMsIGF4aXMsIGJhY2tlbmQpO1xuICBjb25zdCBwcm9ncmFtID1cbiAgICAgIG5ldyBDb25jYXRQcm9ncmFtKHRlbnNvcnMyRC5tYXAodCA9PiB0LnNoYXBlIGFzIFtudW1iZXIsIG51bWJlcl0pKTtcbiAgY29uc3QgcmVzdWx0ID0gYmFja2VuZC5ydW5XZWJHTFByb2dyYW0ocHJvZ3JhbSwgdGVuc29yczJELCBkdHlwZSk7XG5cbiAgdGVuc29yczJELmZvckVhY2gociA9PiBiYWNrZW5kLmRpc3Bvc2VJbnRlcm1lZGlhdGVUZW5zb3JJbmZvKHIpKTtcbiAgY29uc3QgcmVzaGFwZWRSZXN1bHQgPVxuICAgICAgcmVzaGFwZSh7aW5wdXRzOiB7eDogcmVzdWx0fSwgYXR0cnM6IHtzaGFwZTogb3V0U2hhcGV9LCBiYWNrZW5kfSk7XG4gIGJhY2tlbmQuZGlzcG9zZUludGVybWVkaWF0ZVRlbnNvckluZm8ocmVzdWx0KTtcblxuICByZXR1cm4gcmVzaGFwZWRSZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVUZW5zb3JzMkQoXG4gICAgaW5wdXRzOiBDb25jYXRJbnB1dHMsIGF4aXM6IG51bWJlciwgYmFja2VuZDogTWF0aEJhY2tlbmRXZWJHTCkge1xuICAvLyBBbnkgY29uY2F0IG9mIG4tZGltZW5zaW9uYWwgdGVuc29ycyBhY3Jvc3MgYW55IGF4aXMgY2FuIGJlIHJlZHVjZWQgdG9cbiAgLy8gYSBjb25jYXRlbmF0aW9uIG9mIHR3by1kaW1lbnNpb25hbCB0ZW5zb3JzIGFjcm9zcyB0aGUgYXhpcyAxIGJ5IGZpcnN0XG4gIC8vIHBhcnRpdGlvbmluZyB0aGUgYXhlcyBvZiB0aGUgb3JpZ2luYWwgdGVuc29ycyBpbnRvIHRob3NlIGxlc3MgdGhhbiB0aGVcbiAgLy8gYXhpcyB0byBiZSBjb25jYXRlbmF0ZWQgYW5kIHRoZSByZXN0LiBUaGVuIHJlc2hhcGUgdGhlIHRlbnNvcnNcbiAgLy8gaW50byBhIHR3by1kaW1lbnNpb25hbCB0ZW5zb3IgYnkgY29sbGFwc2luZyB0aGVzZSB0d28gc2V0cyBvZiBheGVzIGFuZFxuICAvLyBjb25jYXRlbmF0ZSB0aGUgcmVzdWx0aW5nIG1hdHJpY2VzIGFjcm9zcyB0aGUgYXhpcyAxLCBmaW5hbGx5IHJlc2hhcGluZ1xuICAvLyB0aGUgcmVzdWx0IHRvIGhhdmUgdGhlIHByb3BlciBzaGFwZS5cbiAgY29uc3Qgb3V0U2hhcGUgPSBiYWNrZW5kX3V0aWwuY29tcHV0ZU91dFNoYXBlKGlucHV0cy5tYXAodCA9PiB0LnNoYXBlKSwgYXhpcyk7XG4gIGNvbnN0IHRlbnNvcnMyRCA9IGlucHV0cy5tYXAoXG4gICAgICB4ID0+IHJlc2hhcGUoe1xuICAgICAgICBpbnB1dHM6IHt4fSxcbiAgICAgICAgYXR0cnM6IHtzaGFwZTogWy0xLCB1dGlsLnNpemVGcm9tU2hhcGUoeC5zaGFwZS5zbGljZShheGlzKSldfSxcbiAgICAgICAgYmFja2VuZFxuICAgICAgfSkpO1xuXG4gIHJldHVybiB7dGVuc29yczJELCBvdXRTaGFwZX07XG59XG4iXX0=