UNPKG

@tensorflow/tfjs-backend-wasm

Version:

This package adds a WebAssembly backend to TensorFlow.js. It currently supports the following models from our [models](https://github.com/tensorflow/tfjs-models) repo: - BlazeFace - BodyPix - CocoSSD - Face landmarks detection - HandPose - KNN classifier

114 lines 18.1 kB
/** * @license * Copyright 2021 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, SparseFillEmptyRows } from '@tensorflow/tfjs-core'; import { slice } from './Slice'; import { CppDType } from './types'; let wasmSparseFillEmptyRows; export function setup(backend) { wasmSparseFillEmptyRows = backend.wasm.cwrap('SparseFillEmptyRows', 'number', [ 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', // exceptionValuesId ]); } export function sparseFillEmptyRows(args) { const { backend, inputs } = args; const { indices, values, denseShape, defaultValue } = inputs; const indicesCount = indices.shape[0]; const rank = indices.shape[1]; const denseRows = backend.readSync(denseShape.dataId)[0]; // Set output size to maximum possible and resize later (actual result // might be smaller). const maxOutputIndicesShape = [indicesCount + denseRows, rank]; const indicesId = backend.dataIdMap.get(indices.dataId).id; const valuesId = backend.dataIdMap.get(values.dataId).id; const defaultValueId = backend.dataIdMap.get(defaultValue.dataId).id; const outputIndices = backend.makeOutput(maxOutputIndicesShape, indices.dtype); const outputIndicesId = backend.dataIdMap.get(outputIndices.dataId).id; const outputValues = backend.makeOutput(maxOutputIndicesShape.slice(0, 1), values.dtype); const outputValuesId = backend.dataIdMap.get(outputValues.dataId).id; const emptyRowIndicator = backend.makeOutput([denseRows], 'bool'); const emptyRowIndicatorId = backend.dataIdMap.get(emptyRowIndicator.dataId).id; const reverseIndexMap = backend.makeOutput([indicesCount], indices.dtype); const reverseIndexMapId = backend.dataIdMap.get(reverseIndexMap.dataId).id; const exceptionValues = backend.makeOutput([4], 'int32'); const exceptionValuesId = backend.dataIdMap.get(exceptionValues.dataId).id; const outputRows = wasmSparseFillEmptyRows(indicesId, valuesId, CppDType[values.dtype], indicesCount, denseRows, rank, defaultValueId, outputIndicesId, outputValuesId, emptyRowIndicatorId, reverseIndexMapId, exceptionValuesId); const exceptionValuesArray = backend.readSync(exceptionValues.dataId); let exceptionMessage; switch (exceptionValuesArray[0]) { case 1: { exceptionMessage = backend_util.getSparseFillEmptyRowsIndicesDenseShapeMismatch(exceptionValuesArray[1]); break; } case 2: { exceptionMessage = backend_util.getSparseFillEmptyRowsNegativeIndexErrorMessage(exceptionValuesArray[1], exceptionValuesArray[2]); break; } case 3: exceptionMessage = backend_util.getSparseFillEmptyRowsOutOfRangeIndexErrorMessage(exceptionValuesArray[1], exceptionValuesArray[2], exceptionValuesArray[3]); break; default: exceptionMessage = ''; } backend.disposeData(exceptionValues.dataId); if (exceptionMessage) { backend.disposeData(outputIndices.dataId); backend.disposeData(outputValues.dataId); backend.disposeData(emptyRowIndicator.dataId); backend.disposeData(reverseIndexMap.dataId); throw new Error(exceptionMessage); } let resizedIndices = outputIndices; let resizedValues = outputValues; // Overestimated output size. if (outputRows !== maxOutputIndicesShape[0]) { resizedIndices = slice({ inputs: { x: outputIndices }, attrs: { begin: 0, size: [outputRows, rank] }, backend }); resizedValues = slice({ inputs: { x: outputValues }, attrs: { begin: 0, size: outputRows }, backend }); backend.disposeData(outputIndices.dataId); backend.disposeData(outputValues.dataId); } return [resizedIndices, resizedValues, emptyRowIndicator, reverseIndexMap]; } export const sparseFillEmptyRowsConfig = { kernelName: SparseFillEmptyRows, backendName: 'wasm', setupFunc: setup, kernelFunc: sparseFillEmptyRows }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3BhcnNlRmlsbEVtcHR5Um93cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtYmFja2VuZC13YXNtL3NyYy9rZXJuZWxzL1NwYXJzZUZpbGxFbXB0eVJvd3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsT0FBTyxFQUFDLFlBQVksRUFBNEIsbUJBQW1CLEVBQXdDLE1BQU0sdUJBQXVCLENBQUM7QUFHekksT0FBTyxFQUFDLEtBQUssRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUU5QixPQUFPLEVBQUMsUUFBUSxFQUFDLE1BQU0sU0FBUyxDQUFDO0FBRWpDLElBQUksdUJBS29DLENBQUM7QUFFekMsTUFBTSxVQUFVLEtBQUssQ0FBQyxPQUFvQjtJQUN4Qyx1QkFBdUI7UUFDbkIsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMscUJBQXFCLEVBQUUsUUFBUSxFQUFFO1lBQ2xELFFBQVE7WUFDUixRQUFRO1lBQ1IsUUFBUTtZQUNSLFFBQVE7WUFDUixRQUFRO1lBQ1IsUUFBUTtZQUNSLFFBQVE7WUFDUixRQUFRO1lBQ1IsUUFBUTtZQUNSLFFBQVE7WUFDUixRQUFRO1lBQ1IsUUFBUSxFQUFHLG9CQUFvQjtTQUNoQyxDQUFDLENBQUM7QUFDVCxDQUFDO0FBRUQsTUFBTSxVQUFVLG1CQUFtQixDQUFDLElBR25DO0lBQ0MsTUFBTSxFQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUMsR0FBRyxJQUFJLENBQUM7SUFDL0IsTUFBTSxFQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBQyxHQUFHLE1BQU0sQ0FBQztJQUUzRCxNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RDLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDOUIsTUFBTSxTQUFTLEdB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QUNwQixNQUFNLEVBQUUsRUFBQyxDQUFDLEVBQUUsWUFBWSxFQUFDO1lBQ3pCLEtBQUssRUFBRSxFQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBQztZQUNuQyxPQUFPO1NBQ1IsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDMUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7S0FDMUM7SUFFRCxPQUFPLENBQUMsY0FBYyxFQUFFLGFBQWEsRUFBRSxpQkFBaUIsRUFBRSxlQUFlLENBQUMsQ0FBQztBQUM3RSxDQUFDO0FBRUQsTUFBTSxDQUFDLE1BQU0seUJBQXlCLEdBQWlCO0lBQ3JELFVBQVUsRUFBRSxtQkFBbUI7SUFDL0IsV0FBVyxFQUFFLE1BQU07SUFDbkIsU0FBUyxFQUFFLEtBQUs7SUFDaEIsVUFBVSxFQUFFLG1CQUE0QztDQUN6RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMjEgR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG5pbXBvcnQge2JhY2tlbmRfdXRpbCwgS2VybmVsQ29uZmlnLCBLZXJuZWxGdW5jLCBTcGFyc2VGaWxsRW1wdHlSb3dzLCBTcGFyc2VGaWxsRW1wdHlSb3dzSW5wdXRzLCBUZW5zb3JJbmZvfSBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuXG5pbXBvcnQge0JhY2tlbmRXYXNtfSBmcm9tICcuLi9iYWNrZW5kX3dhc20nO1xuaW1wb3J0IHtzbGljZX0gZnJvbSAnLi9TbGljZSc7XG5cbmltcG9ydCB7Q3BwRFR5cGV9IGZyb20gJy4vdHlwZXMnO1xuXG5sZXQgd2FzbVNwYXJzZUZpbGxFbXB0eVJvd3M6IChcbiAgICBpbmRpY2VzSWQ6IG51bWJlciwgdmFsdWVzSWQ6IG51bWJlciwgdmFsdWVzRFR5cGU6IG51bWJlcixcbiAgICBpbmRpY2VzQ291bnQ6IG51bWJlciwgZGVuc2VSb3dzOiBudW1iZXIsIHJhbms6IG51bWJlcixcbiAgICBkZWZhdWx0VmFsdWVJZDogbnVtYmVyLCBvdXRwdXRJbmRpY2VzSWQ6IG51bWJlciwgb3V0cHV0VmFsdWVzSWQ6IG51bWJlcixcbiAgICBlbXB0eVJvd0luZGljYXRvcklkOiBudW1iZXIsIHJldmVyc2VJbmRleE1hcElkOiBudW1iZXIsXG4gICAgZXhjZXB0aW9uVmFsdWVzSWQ6IG51bWJlcikgPT4gbnVtYmVyO1xuXG5leHBvcnQgZnVuY3Rpb24gc2V0dXAoYmFja2VuZDogQmFja2VuZFdhc20pOiB2b2lkIHtcbiAgd2FzbVNwYXJzZUZpbGxFbXB0eVJvd3MgPVxuICAgICAgYmFja2VuZC53YXNtLmN3cmFwKCdTcGFyc2VGaWxsRW1wdHlSb3dzJywgJ251bWJlcicsIFtcbiAgICAgICAgJ251bWJlcicsICAvLyBpbmRpY2VzSWRcbiAgICAgICAgJ251bWJlcicsICAvLyB2YWx1ZXNJZFxuICAgICAgICAnbnVtYmVyJywgIC8vIHZhbHVlc0RUeXBlXG4gICAgICAgICdudW1iZXInLCAgLy8gaW5kaWNlc0NvdW50XG4gICAgICAgICdudW1iZXInLCAgLy8gZGVuc2VSb3dzXG4gICAgICAgICdudW1iZXInLCAgLy8gcmFua1xuICAgICAgICAnbnVtYmVyJywgIC8vIGRlZmF1bHRWYWx1ZUlkXG4gICAgICAgICdudW1iZXInLCAgLy8gb3V0cHV0SW5kaWNlc0lkXG4gICAgICAgICdudW1iZXInLCAgLy8gb3V0cHV0VmFsdWVzSWRcbiAgICAgICAgJ251bWJlcicsICAvLyBlbXB0eVJvd0luZGljYXRvcklkXG4gICAgICAgICdudW1iZXInLCAgLy8gcmV2ZXJzZUluZGV4TWFwSWRcbiAgICAgICAgJ251bWJlcicsICAvLyBleGNlcHRpb25WYWx1ZXNJZFxuICAgICAgXSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzcGFyc2VGaWxsRW1wdHlSb3dzKGFyZ3M6IHtcbiAgYmFja2VuZDogQmFja2VuZFdhc20sXG4gIGlucHV0czogU3BhcnNlRmlsbEVtcHR5Um93c0lucHV0cyxcbn0pOiBbVGVuc29ySW5mbywgVGVuc29ySW5mbywgVGVuc29ySW5mbywgVGVuc29ySW5mb10ge1xuICBjb25zdCB7YmFja2VuZCwgaW5wdXRzfSA9IGFyZ3M7XG4gIGNvbnN0IHtpbmRpY2VzLCB2YWx1ZXMsIGRlbnNlU2hhcGUsIGRlZmF1bHRWYWx1ZX0gPSBpbnB1dHM7XG5cbiAgY29uc3QgaW5kaWNlc0NvdW50ID0gaW5kaWNlcy5zaGFwZVswXTtcbiAgY29uc3QgcmFuayA9IGluZGljZXMuc2hhcGVbMV07XG4gIGNvbnN0IGRlbnNlUm93cyA9IGJhY2tlbmQucmVhZFN5bmMoZGVuc2VTaGFwZS5kYXRhSWQpWzBdIGFzIG51bWJlcjtcblxuICAvLyBTZXQgb3V0cHV0IHNpemUgdG8gbWF4aW11bSBwb3NzaWJsZSBhbmQgcmVzaXplIGxhdGVyIChhY3R1YWwgcmVzdWx0XG4gIC8vIG1pZ2h0IGJlIHNtYWxsZXIpLlxuICBjb25zdCBtYXhPdXRwdXRJbmRpY2VzU2hhcGUgPSBbaW5kaWNlc0NvdW50ICsgZGVuc2VSb3dzLCByYW5rXTtcblxuICBjb25zdCBpbmRpY2VzSWQgPSBiYWNrZW5kLmRhdGFJZE1hcC5nZXQoaW5kaWNlcy5kYXRhSWQpLmlkO1xuICBjb25zdCB2YWx1ZXNJZCA9IGJhY2tlbmQuZGF0YUlkTWFwLmdldCh2YWx1ZXMuZGF0YUlkKS5pZDtcbiAgY29uc3QgZGVmYXVsdFZhbHVlSWQgPSBiYWNrZW5kLmRhdGFJZE1hcC5nZXQoZGVmYXVsdFZhbHVlLmRhdGFJZCkuaWQ7XG5cbiAgY29uc3Qgb3V0cHV0SW5kaWNlcyA9XG4gICAgICBiYWNrZW5kLm1ha2VPdXRwdXQobWF4T3V0cHV0SW5kaWNlc1NoYXBlLCBpbmRpY2VzLmR0eXBlKTtcbiAgY29uc3Qgb3V0cHV0SW5kaWNlc0lkID0gYmFja2VuZC5kYXRhSWRNYXAuZ2V0KG91dHB1dEluZGljZXMuZGF0YUlkKS5pZDtcblxuICBjb25zdCBvdXRwdXRWYWx1ZXMgPVxuICAgICAgYmFja2VuZC5tYWtlT3V0cHV0KG1heE91dHB1dEluZGljZXNTaGFwZS5zbGljZSgwLCAxKSwgdmFsdWVzLmR0eXBlKTtcbiAgY29uc3Qgb3V0cHV0VmFsdWVzSWQgPSBiYWNrZW5kLmRhdGFJZE1hcC5nZXQob3V0cHV0VmFsdWVzLmRhdGFJZCkuaWQ7XG5cbiAgY29uc3QgZW1wdHlSb3dJbmRpY2F0b3IgPSBiYWNrZW5kLm1ha2VPdXRwdXQoW2RlbnNlUm93c10sICdib29sJyk7XG4gIGNvbnN0IGVtcHR5Um93SW5kaWNhdG9ySWQgPVxuICAgICAgYmFja2VuZC5kYXRhSWRNYXAuZ2V0KGVtcHR5Um93SW5kaWNhdG9yLmRhdGFJZCkuaWQ7XG5cbiAgY29uc3QgcmV2ZXJzZUluZGV4TWFwID0gYmFja2VuZC5tYWtlT3V0cHV0KFtpbmRpY2VzQ291bnRdLCBpbmRpY2VzLmR0eXBlKTtcbiAgY29uc3QgcmV2ZXJzZUluZGV4TWFwSWQgPSBiYWNrZW5kLmRhdGFJZE1hcC5nZXQocmV2ZXJzZUluZGV4TWFwLmRhdGFJZCkuaWQ7XG5cbiAgY29uc3QgZXhjZXB0aW9uVmFsdWVzID0gYmFja2VuZC5tYWtlT3V0cHV0KFs0XSwgJ2ludDMyJyk7XG4gIGNvbnN0IGV4Y2VwdGlvblZhbHVlc0lkID0gYmFja2VuZC5kYXRhSWRNYXAuZ2V0KGV4Y2VwdGlvblZhbHVlcy5kYXRhSWQpLmlkO1xuXG4gIGNvbnN0IG91dHB1dFJvd3MgPSB3YXNtU3BhcnNlRmlsbEVtcHR5Um93cyhcbiAgICAgIGluZGljZXNJZCwgdmFsdWVzSWQsIENwcERUeXBlW3ZhbHVlcy5kdHlwZV0sIGluZGljZXNDb3VudCwgZGVuc2VSb3dzLFxuICAgICAgcmFuaywgZGVmYXVsdFZhbHVlSWQsIG91dHB1dEluZGljZXNJZCwgb3V0cHV0VmFsdWVzSWQsXG4gICAgICBlbXB0eVJvd0luZGljYXRvcklkLCByZXZlcnNlSW5kZXhNYXBJZCwgZXhjZXB0aW9uVmFsdWVzSWQpO1xuXG4gIGNvbnN0IGV4Y2VwdGlvblZhbHVlc0FycmF5ID1cbiAgICAgIGJhY2tlbmQucmVhZFN5bmMoZXhjZXB0aW9uVmFsdWVzLmRhdGFJZCkgYXMgSW50MzJBcnJheTtcblxuICBsZXQgZXhjZXB0aW9uTWVzc2FnZTogc3RyaW5nO1xuICBzd2l0Y2ggKGV4Y2VwdGlvblZhbHVlc0FycmF5WzBdKSB7XG4gICAgY2FzZSAxOiB7XG4gICAgICBleGNlcHRpb25NZXNzYWdlID1cbiAgICAgICAgICBiYWNrZW5kX3V0aWwuZ2V0U3BhcnNlRmlsbEVtcHR5Um93c0luZGljZXNEZW5zZVNoYXBlTWlzbWF0Y2goXG4gICAgICAgICAgICAgIGV4Y2VwdGlvblZhbHVlc0FycmF5WzFdKTtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgICBjYXNlIDI6IHtcbiAgICAgIGV4Y2VwdGlvbk1lc3NhZ2UgPVxuICAgICAgICAgIGJhY2tlbmRfdXRpbC5nZXRTcGFyc2VGaWxsRW1wdHlSb3dzTmVnYXRpdmVJbmRleEVycm9yTWVzc2FnZShcbiAgICAgICAgICAgICAgZXhjZXB0aW9uVmFsdWVzQXJyYXlbMV0sIGV4Y2VwdGlvblZhbHVlc0FycmF5WzJdKTtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgICBjYXNlIDM6XG4gICAgICBleGNlcHRpb25NZXNzYWdlID1cbiAgICAgICAgICBiYWNrZW5kX3V0aWwuZ2V0U3BhcnNlRmlsbEVtcHR5Um93c091dE9mUmFuZ2VJbmRleEVycm9yTWVzc2FnZShcbiAgICAgICAgICAgICAgZXhjZXB0aW9uVmFsdWVzQXJyYXlbMV0sIGV4Y2VwdGlvblZhbHVlc0FycmF5WzJdLFxuICAgICAgICAgICAgICBleGNlcHRpb25WYWx1ZXNBcnJheVszXSk7XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgZXhjZXB0aW9uTWVzc2FnZSA9ICcnO1xuICB9XG5cbiAgYmFja2VuZC5kaXNwb3NlRGF0YShleGNlcHRpb25WYWx1ZXMuZGF0YUlkKTtcbiAgaWYgKGV4Y2VwdGlvbk1lc3NhZ2UpIHtcbiAgICBiYWNrZW5kLmRpc3Bvc2VEYXRhKG91dHB1dEluZGljZXMuZGF0YUlkKTtcbiAgICBiYWNrZW5kLmRpc3Bvc2VEYXRhKG91dHB1dFZhbHVlcy5kYXRhSWQpO1xuICAgIGJhY2tlbmQuZGlzcG9zZURhdGEoZW1wdHlSb3dJbmRpY2F0b3IuZGF0YUlkKTtcbiAgICBiYWNrZW5kLmRpc3Bvc2VEYXRhKHJldmVyc2VJbmRleE1hcC5kYXRhSWQpO1xuICAgIHRocm93IG5ldyBFcnJvcihleGNlcHRpb25NZXNzYWdlKTtcbiAgfVxuXG4gIGxldCByZXNpemVkSW5kaWNlcyA9IG91dHB1dEluZGljZXM7XG4gIGxldCByZXNpemVkVmFsdWVzID0gb3V0cHV0VmFsdWVzO1xuICAvLyBPdmVyZXN0aW1hdGVkIG91dHB1dCBzaXplLlxuICBpZiAob3V0cHV0Um93cyAhPT0gbWF4T3V0cHV0SW5kaWNlc1NoYXBlWzBdKSB7XG4gICAgcmVzaXplZEluZGljZXMgPSBzbGljZSh7XG4gICAgICBpbnB1dHM6IHt4OiBvdXRwdXRJbmRpY2VzfSxcbiAgICAgIGF0dHJzOiB7YmVnaW46IDAsIHNpemU6IFtvdXRwdXRSb3dzLCByYW5rXX0sXG4gICAgICBiYWNrZW5kXG4gICAgfSk7XG4gICAgcmVzaXplZFZhbHVlcyA9IHNsaWNlKHtcbiAgICAgIGlucHV0czoge3g6IG91dHB1dFZhbHVlc30sXG4gICAgICBhdHRyczoge2JlZ2luOiAwLCBzaXplOiBvdXRwdXRSb3dzfSxcbiAgICAgIGJhY2tlbmRcbiAgICB9KTtcbiAgICBiYWNrZW5kLmRpc3Bvc2VEYXRhKG91dHB1dEluZGljZXMuZGF0YUlkKTtcbiAgICBiYWNrZW5kLmRpc3Bvc2VEYXRhKG91dHB1dFZhbHVlcy5kYXRhSWQpO1xuICB9XG5cbiAgcmV0dXJuIFtyZXNpemVkSW5kaWNlcywgcmVzaXplZFZhbHVlcywgZW1wdHlSb3dJbmRpY2F0b3IsIHJldmVyc2VJbmRleE1hcF07XG59XG5cbmV4cG9ydCBjb25zdCBzcGFyc2VGaWxsRW1wdHlSb3dzQ29uZmlnOiBLZXJuZWxDb25maWcgPSB7XG4gIGtlcm5lbE5hbWU6IFNwYXJzZUZpbGxFbXB0eVJvd3MsXG4gIGJhY2tlbmROYW1lOiAnd2FzbScsXG4gIHNldHVwRnVuYzogc2V0dXAsXG4gIGtlcm5lbEZ1bmM6IHNwYXJzZUZpbGxFbXB0eVJvd3MgYXMgdW5rbm93biBhcyBLZXJuZWxGdW5jXG59O1xuIl19