@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
84 lines • 15.5 kB
JavaScript
/**
* @license
* Copyright 2019 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 { BatchMatMul, broadcast_util, util } from '@tensorflow/tfjs-core';
import { reshape } from './Reshape';
let wasmBatchMatMul;
function setup(backend) {
wasmBatchMatMul = backend.wasm.cwrap(BatchMatMul, null /* void */, [
'number',
'array',
'number',
'number',
'array',
'number',
'number',
'number',
'number' // out_id
]);
}
function batchMatMul(args) {
const { inputs, backend, attrs } = args;
const { a, b } = inputs;
const { transposeA, transposeB } = attrs;
if (a.dtype !== 'float32' || b.dtype !== 'float32') {
throw new Error(`BatchMatMul for non non-float32 tensors not yet supported.`);
}
const aRank = a.shape.length;
const bRank = b.shape.length;
const innerShapeA = transposeA ? a.shape[aRank - 2] : a.shape[aRank - 1];
const innerShapeB = transposeB ? b.shape[bRank - 1] : b.shape[bRank - 2];
const outerShapeA = transposeA ? a.shape[aRank - 1] : a.shape[aRank - 2];
const outerShapeB = transposeB ? b.shape[bRank - 2] : b.shape[bRank - 1];
const outerDimsA = a.shape.slice(0, -2);
const outerDimsB = b.shape.slice(0, -2);
const batchDimA = util.sizeFromShape(outerDimsA);
const batchDimB = util.sizeFromShape(outerDimsB);
const outShapeOuterDims = broadcast_util.assertAndGetBroadcastShape(a.shape.slice(0, -2), b.shape.slice(0, -2));
const outShape = outShapeOuterDims.concat([outerShapeA, outerShapeB]);
util.assert(innerShapeA === innerShapeB, () => `Error in matMul: inner shapes (${innerShapeA}) and (` +
`${innerShapeB}) of Tensors with shapes ${a.shape} and ` +
`${b.shape} and transposeA=${transposeA}` +
` and transposeB=${transposeB} must match.`);
const a3dShape = transposeA ? [batchDimA, innerShapeA, outerShapeA] :
[batchDimA, outerShapeA, innerShapeA];
const b3dShape = transposeB ? [batchDimB, outerShapeB, innerShapeB] :
[batchDimB, innerShapeB, outerShapeB];
// The rest of the implementation is designed to operate on rank-3 tensors
const a3d = reshape({ inputs: { x: a }, backend, attrs: { shape: a3dShape } });
const b3d = reshape({ inputs: { x: b }, backend, attrs: { shape: b3dShape } });
const a3dId = backend.dataIdMap.get(a3d.dataId).id;
const b3dId = backend.dataIdMap.get(b3d.dataId).id;
const leftDim = transposeA ? a3d.shape[2] : a3d.shape[1];
const rightDim = transposeB ? b3d.shape[1] : b3d.shape[2];
const batchDim = Math.max(batchDimA, batchDimB);
const out = backend.makeOutput([batchDim, leftDim, rightDim], a3d.dtype);
const outId = backend.dataIdMap.get(out.dataId).id;
const aShapeBytes = new Uint8Array(new Int32Array(a3d.shape).buffer);
const bShapeBytes = new Uint8Array(new Int32Array(b3d.shape).buffer);
wasmBatchMatMul(a3dId, aShapeBytes, a3d.shape.length, b3dId, bShapeBytes, b3d.shape.length, transposeA, transposeB, outId);
backend.disposeData(a3d.dataId);
backend.disposeData(b3d.dataId);
out.shape = outShape;
return out;
}
export const batchMatMulConfig = {
kernelName: BatchMatMul,
backendName: 'wasm',
setupFunc: setup,
kernelFunc: batchMatMul
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmF0Y2hNYXRNdWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi90ZmpzLWJhY2tlbmQtd2FzbS9zcmMva2VybmVscy9CYXRjaE1hdE11bC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFFSCxPQUFPLEVBQUMsV0FBVyxFQUF1QyxjQUFjLEVBQTRCLElBQUksRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBSXZJLE9BQU8sRUFBQyxPQUFPLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFFbEMsSUFBSSxlQUcyQyxDQUFDO0FBRWhELFNBQVMsS0FBSyxDQUFDLE9BQW9CO0lBQ2pDLGVBQWUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRTtRQUNqRSxRQUFRO1FBQ1IsT0FBTztRQUNQLFFBQVE7UUFDUixRQUFRO1FBQ1IsT0FBTztRQUNQLFFBQVE7UUFDUixRQUFRO1FBQ1IsUUFBUTtRQUNSLFFBQVEsQ0FBRyxTQUFTO0tBQ3JCLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxTQUFTLFdBQVcsQ0FBQyxJQUlwQjtJQUNDLE1BQU0sRUFBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBQyxHQUFHLElBQUksQ0FBQztJQUN0QyxNQUFNLEVBQUMsQ0FBQyxFQUFFLENBQUMsRUFBQyxHQUFHLE1BQU0sQ0FBQztJQUN0QixNQUFNLEVBQUMsVUFBVSxFQUFFLFVBQVUsRUFBQyxHQUFHLEtBQUssQ0FBQztJQUV2QyxJQUFJLENBQUMsQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLENBQUMsQ0FBQyxLQUFLLEtBQUssU0FBUyxFQUFFO1FBQ2xELE1BQU0sSUFBSSxLQUFLLENBQ1gsNERBQTRELENBQUMsQ0FBQztLQUNuRTtJQUVELE1BQU0sS0FBSyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQzdCLE1BQU0sS0FBSyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBRTdCLE1BQU0sV0FBVyxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3pFLE1BQU0sV0FBVyxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBRXpFLE1BQU0sV0FBVyxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3pFLE1BQU0sV0FBVyxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBRXpFLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hDLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRXhDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDakQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVqRCxNQUFNLGlCQUFpQixH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LEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRXJFLGVBQWUsQ0FDWCxLQUFLLEVBQUUsV0FBVyxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQ3hELEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFFckQsT0FBTyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDaEMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFaEMsR0FBRyxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUM7SUFDckIsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDO0FBRUQsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQWlCO0lBQzdDLFVBQVUsRUFBRSxXQUFXO0lBQ3ZCLFdBQVcsRUFBRSxNQUFNO0lBQ25CLFNBQVMsRUFBRSxLQUFLO0lBQ2hCLFVBQVUsRUFBRSxXQUFvQztDQUNqRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTkgR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG5pbXBvcnQge0JhdGNoTWF0TXVsLCBCYXRjaE1hdE11bEF0dHJzLCBCYXRjaE1hdE11bElucHV0cywgYnJvYWRjYXN0X3V0aWwsIEtlcm5lbENvbmZpZywgS2VybmVsRnVuYywgdXRpbH0gZnJvbSAnQHRlbnNvcmZsb3cvdGZqcy1jb3JlJztcblxuaW1wb3J0IHtCYWNrZW5kV2FzbX0gZnJvbSAnLi4vYmFja2VuZF93YXNtJztcblxuaW1wb3J0IHtyZXNoYXBlfSBmcm9tICcuL1Jlc2hhcGUnO1xuXG5sZXQgd2FzbUJhdGNoTWF0TXVsOiAoXG4gICAgYUlkOiBudW1iZXIsIGFTaGFwZTogVWludDhBcnJheSwgYVNoYXBlU2l6ZTogbnVtYmVyLCBiSWQ6IG51bWJlcixcbiAgICBiU2hhcGU6IFVpbnQ4QXJyYXksIGJTaGFwZVNpemU6IG51bWJlciwgdHJhbnNwb3NlQTogYm9vbGVhbixcbiAgICB0cmFuc3Bvc2VCOiBib29sZWFuLCBvdXRJZDogbnVtYmVyKSA9PiB2b2lkO1xuXG5mdW5jdGlvbiBzZXR1cChiYWNrZW5kOiBCYWNrZW5kV2FzbSkge1xuICB3YXNtQmF0Y2hNYXRNdWwgPSBiYWNrZW5kLndhc20uY3dyYXAoQmF0Y2hNYXRNdWwsIG51bGwgLyogdm9pZCAqLywgW1xuICAgICdudW1iZXInLCAgLy8gYV9pZFxuICAgICdhcnJheScsICAgLy8gYV9zaGFwZVxuICAgICdudW1iZXInLCAgLy8gYV9zaGFwZS5sZW5ndGhcbiAgICAnbnVtYmVyJywgIC8vIGJfaWRcbiAgICAnYXJyYXknLCAgIC8vIGJfc2hhcGVcbiAgICAnbnVtYmVyJywgIC8vIGJfc2hhcGUubGVuZ3RoXG4gICAgJ251bWJlcicsICAvLyB0cmFuc3Bvc2VfYVxuICAgICdudW1iZXInLCAgLy8gdHJhbnNwb3NlX2JcbiAgICAnbnVtYmVyJyAgIC8vIG91dF9pZFxuICBdKTtcbn1cblxuZnVuY3Rpb24gYmF0Y2hNYXRNdWwoYXJnczoge1xuICBpbnB1dHM6IEJhdGNoTWF0TXVsSW5wdXRzLFxuICBiYWNrZW5kOiBCYWNrZW5kV2FzbSxcbiAgYXR0cnM6IEJhdGNoTWF0TXVsQXR0cnNcbn0pIHtcbiAgY29uc3Qge2lucHV0cywgYmFja2VuZCwgYXR0cnN9ID0gYXJncztcbiAgY29uc3Qge2EsIGJ9ID0gaW5wdXRzO1xuICBjb25zdCB7dHJhbnNwb3NlQSwgdHJhbnNwb3NlQn0gPSBhdHRycztcblxuICBpZiAoYS5kdHlwZSAhPT0gJ2Zsb2F0MzInIHx8IGIuZHR5cGUgIT09ICdmbG9hdDMyJykge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEJhdGNoTWF0TXVsIGZvciBub24gbm9uLWZsb2F0MzIgdGVuc29ycyBub3QgeWV0IHN1cHBvcnRlZC5gKTtcbiAgfVxuXG4gIGNvbnN0IGFSYW5rID0gYS5zaGFwZS5sZW5ndGg7XG4gIGNvbnN0IGJSYW5rID0gYi5zaGFwZS5sZW5ndGg7XG5cbiAgY29uc3QgaW5uZXJTaGFwZUEgPSB0cmFuc3Bvc2VBID8gYS5zaGFwZVthUmFuayAtIDJdIDogYS5zaGFwZVthUmFuayAtIDFdO1xuICBjb25zdCBpbm5lclNoYXBlQiA9IHRyYW5zcG9zZUIgPyBiLnNoYXBlW2JSYW5rIC0gMV0gOiBiLnNoYXBlW2JSYW5rIC0gMl07XG5cbiAgY29uc3Qgb3V0ZXJTaGFwZUEgPSB0cmFuc3Bvc2VBID8gYS5zaGFwZVthUmFuayAtIDFdIDogYS5zaGFwZVthUmFuayAtIDJdO1xuICBjb25zdCBvdXRlclNoYXBlQiA9IHRyYW5zcG9zZUIgPyBiLnNoYXBlW2JSYW5rIC0gMl0gOiBiLnNoYXBlW2JSYW5rIC0gMV07XG5cbiAgY29uc3Qgb3V0ZXJEaW1zQSA9IGEuc2hhcGUuc2xpY2UoMCwgLTIpO1xuICBjb25zdCBvdXRlckRpbXNCID0gYi5zaGFwZS5zbGljZSgwLCAtMik7XG5cbiAgY29uc3QgYmF0Y2hEaW1BID0gdXRpbC5zaXplRnJvbVNoYXBlKG91dGVyRGltc0EpO1xuICBjb25zdCBiYXRjaERpbUIgPSB1dGlsLnNpemVGcm9tU2hhcGUob3V0ZXJEaW1zQik7XG5cbiAgY29uc3Qgb3V0U2hhcGVPdXRlckRpbXMgPSBicm9hZGNhc3RfdXRpbC5hc3NlcnRBbmRHZXRCcm9hZGNhc3RTaGFwZShcbiAgICAgIGEuc2hhcGUuc2xpY2UoMCwgLTIpLCBiLnNoYXBlLnNsaWNlKDAsIC0yKSk7XG4gIGNvbnN0IG91dFNoYXBlID0gb3V0U2hhcGVPdXRlckRpbXMuY29uY2F0KFtvdXRlclNoYXBlQSwgb3V0ZXJTaGFwZUJdKTtcblxuICB1dGlsLmFzc2VydChcbiAgICAgIGlubmVyU2hhcGVBID09PSBpbm5lclNoYXBlQixcbiAgICAgICgpID0+IGBFcnJvciBpbiBtYXRNdWw6IGlubmVyIHNoYXBlcyAoJHtpbm5lclNoYXBlQX0pIGFuZCAoYCArXG4gICAgICAgICAgYCR7aW5uZXJTaGFwZUJ9KSBvZiBUZW5zb3JzIHdpdGggc2hhcGVzICR7YS5zaGFwZX0gYW5kIGAgK1xuICAgICAgICAgIGAke2Iuc2hhcGV9IGFuZCB0cmFuc3Bvc2VBPSR7dHJhbnNwb3NlQX1gICtcbiAgICAgICAgICBgIGFuZCB0cmFuc3Bvc2VCPSR7dHJhbnNwb3NlQn0gbXVzdCBtYXRjaC5gKTtcblxuICBjb25zdCBhM2RTaGFwZSA9IHRyYW5zcG9zZUEgPyBbYmF0Y2hEaW1BLCBpbm5lclNoYXBlQSwgb3V0ZXJTaGFwZUFdIDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2JhdGNoRGltQSwgb3V0ZXJTaGFwZUEsIGlubmVyU2hhcGVBXTtcbiAgY29uc3QgYjNkU2hhcGUgPSB0cmFuc3Bvc2VCID8gW2JhdGNoRGltQiwgb3V0ZXJTaGFwZUIsIGlubmVyU2hhcGVCXSA6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtiYXRjaERpbUIsIGlubmVyU2hhcGVCLCBvdXRlclNoYXBlQl07XG5cbiAgLy8gVGhlIHJlc3Qgb2YgdGhlIGltcGxlbWVudGF0aW9uIGlzIGRlc2lnbmVkIHRvIG9wZXJhdGUgb24gcmFuay0zIHRlbnNvcnNcbiAgY29uc3QgYTNkID0gcmVzaGFwZSh7aW5wdXRzOiB7eDogYX0sIGJhY2tlbmQsIGF0dHJzOiB7c2hhcGU6IGEzZFNoYXBlfX0pO1xuICBjb25zdCBiM2QgPSByZXNoYXBlKHtpbnB1dHM6IHt4OiBifSwgYmFja2VuZCwgYXR0cnM6IHtzaGFwZTogYjNkU2hhcGV9fSk7XG5cbiAgY29uc3QgYTNkSWQgPSBiYWNrZW5kLmRhdGFJZE1hcC5nZXQoYTNkLmRhdGFJZCkuaWQ7XG4gIGNvbnN0IGIzZElkID0gYmFja2VuZC5kYXRhSWRNYXAuZ2V0KGIzZC5kYXRhSWQpLmlkO1xuXG4gIGNvbnN0IGxlZnREaW0gPSB0cmFuc3Bvc2VBID8gYTNkLnNoYXBlWzJdIDogYTNkLnNoYXBlWzFdO1xuICBjb25zdCByaWdodERpbSA9IHRyYW5zcG9zZUIgPyBiM2Quc2hhcGVbMV0gOiBiM2Quc2hhcGVbMl07XG4gIGNvbnN0IGJhdGNoRGltID0gTWF0aC5tYXgoYmF0Y2hEaW1BLCBiYXRjaERpbUIpO1xuXG4gIGNvbnN0IG91dCA9IGJhY2tlbmQubWFrZU91dHB1dChbYmF0Y2hEaW0sIGxlZnREaW0sIHJpZ2h0RGltXSwgYTNkLmR0eXBlKTtcbiAgY29uc3Qgb3V0SWQgPSBiYWNrZW5kLmRhdGFJZE1hcC5nZXQob3V0LmRhdGFJZCkuaWQ7XG5cbiAgY29uc3QgYVNoYXBlQnl0ZXMgPSBuZXcgVWludDhBcnJheShuZXcgSW50MzJBcnJheShhM2Quc2hhcGUpLmJ1ZmZlcik7XG4gIGNvbnN0IGJTaGFwZUJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkobmV3IEludDMyQXJyYXkoYjNkLnNoYXBlKS5idWZmZXIpO1xuXG4gIHdhc21CYXRjaE1hdE11bChcbiAgICAgIGEzZElkLCBhU2hhcGVCeXRlcywgYTNkLnNoYXBlLmxlbmd0aCwgYjNkSWQsIGJTaGFwZUJ5dGVzLFxuICAgICAgYjNkLnNoYXBlLmxlbmd0aCwgdHJhbnNwb3NlQSwgdHJhbnNwb3NlQiwgb3V0SWQpO1xuXG4gIGJhY2tlbmQuZGlzcG9zZURhdGEoYTNkLmRhdGFJZCk7XG4gIGJhY2tlbmQuZGlzcG9zZURhdGEoYjNkLmRhdGFJZCk7XG5cbiAgb3V0LnNoYXBlID0gb3V0U2hhcGU7XG4gIHJldHVybiBvdXQ7XG59XG5cbmV4cG9ydCBjb25zdCBiYXRjaE1hdE11bENvbmZpZzogS2VybmVsQ29uZmlnID0ge1xuICBrZXJuZWxOYW1lOiBCYXRjaE1hdE11bCxcbiAgYmFja2VuZE5hbWU6ICd3YXNtJyxcbiAgc2V0dXBGdW5jOiBzZXR1cCxcbiAga2VybmVsRnVuYzogYmF0Y2hNYXRNdWwgYXMgdW5rbm93biBhcyBLZXJuZWxGdW5jXG59O1xuIl19