/**
|
* @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 { ResizeNearestNeighborGrad, util } from '@tensorflow/tfjs-core';
|
import { assertNotComplex } from '../cpu_util';
|
export function resizeNearestNeighborGrad(args) {
|
const { inputs, backend, attrs } = args;
|
const { images, dy } = inputs;
|
const { alignCorners } = attrs;
|
assertNotComplex([dy, images], 'resizeNearestNeighborGrad');
|
const imagesStrides = util.computeStrides(images.shape);
|
const dyStrides = util.computeStrides(dy.shape);
|
const [batch, xHeight, xWidth, depth] = images.shape;
|
const [, yHeight, yWidth] = dy.shape;
|
const output = new Float32Array(batch * xHeight * xWidth * depth);
|
const dyValues = backend.data.get(dy.dataId).values;
|
// In the backwards pass, we want to find the pixels that were generated
|
// for each pixel in the input image the forward pass
|
const effectiveXSize = [
|
(alignCorners && yHeight > 1) ? xHeight - 1 : xHeight,
|
(alignCorners && yWidth > 1) ? xWidth - 1 : xWidth
|
];
|
const effectiveYSize = [
|
(alignCorners && yHeight > 1) ? yHeight - 1 : yHeight,
|
(alignCorners && yWidth > 1) ? yWidth - 1 : yWidth
|
];
|
const heightScale = effectiveXSize[0] / effectiveYSize[0];
|
const widthScale = effectiveXSize[1] / effectiveYSize[1];
|
const invHeightScale = 1 / heightScale;
|
const invWidthScale = 1 / widthScale;
|
// This defines the size of the window of values around a particular
|
// index in dy that we want to search for contributions to dx.
|
const winHeight = (Math.ceil(invHeightScale) * 2) + 2;
|
const winWidth = (Math.ceil(invWidthScale) * 2) + 2;
|
// Loop over the output space.
|
for (let b = 0; b < batch; b++) {
|
const batchOffset = b * imagesStrides[0];
|
for (let r = 0; r < xHeight; r++) {
|
const rowOffset = batchOffset + r * imagesStrides[1];
|
// Compute bounds for where in dy we will look
|
const startRLerp = Math.floor(r * invHeightScale);
|
const startDyR = Math.floor(startRLerp - (winHeight / 2));
|
for (let c = 0; c < xWidth; c++) {
|
const colOffset = rowOffset + c * imagesStrides[2];
|
// Compute bounds for where in dy we will look
|
const startCLerp = Math.floor(c * invWidthScale);
|
const startDyC = Math.floor(startCLerp - (winWidth / 2));
|
for (let d = 0; d < depth; d++) {
|
let accum = 0;
|
// loop over dy
|
for (let dyRIndex = 0; dyRIndex < winHeight; dyRIndex++) {
|
const dyR = dyRIndex + startDyR;
|
// Guard against the window exceeding the bounds of dy
|
if (dyR < 0 || dyR >= yHeight) {
|
continue;
|
}
|
const dyROffset = batchOffset + dyR * dyStrides[1];
|
const sourceFracRow = dyR * heightScale;
|
const sourceNearestRow = Math.min(xHeight - 1, alignCorners ? Math.round(sourceFracRow) :
|
Math.floor(sourceFracRow));
|
if (r !== sourceNearestRow) {
|
continue;
|
}
|
for (let dyCIndex = 0; dyCIndex < winWidth; dyCIndex++) {
|
const dyC = dyCIndex + startDyC;
|
// Guard against the window exceeding the bounds of dy
|
if (dyC < 0 || dyC >= yWidth) {
|
continue;
|
}
|
const dyCOffset = dyROffset + dyC * dyStrides[2];
|
const sourceFracCol = dyC * widthScale;
|
const sourceNearestCol = Math.min(xWidth - 1, alignCorners ? Math.round(sourceFracCol) :
|
Math.floor(sourceFracCol));
|
if (c === sourceNearestCol) {
|
accum += dyValues[dyCOffset + d];
|
}
|
}
|
}
|
output[colOffset + d] = accum;
|
}
|
}
|
}
|
}
|
return backend.makeTensorInfo(images.shape, images.dtype, output);
|
}
|
export const resizeNearestNeighborGradConfig = {
|
kernelName: ResizeNearestNeighborGrad,
|
backendName: 'cpu',
|
kernelFunc: resizeNearestNeighborGrad
|
};
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVzaXplTmVhcmVzdE5laWdoYm9yR3JhZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtYmFja2VuZC1jcHUvc3JjL2tlcm5lbHMvUmVzaXplTmVhcmVzdE5laWdoYm9yR3JhZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFFSCxPQUFPLEVBQTJCLHlCQUF5QixFQUEyRixJQUFJLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUd6TCxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSxhQUFhLENBQUM7QUFFN0MsTUFBTSxVQUFVLHlCQUF5QixDQUFDLElBSXpDO0lBQ0MsTUFBTSxFQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFDLEdBQUcsSUFBSSxDQUFDO0lBQ3RDLE1BQU0sRUFBQyxNQUFNLEVBQUUsRUFBRSxFQUFDLEdBQUcsTUFBTSxDQUFDO0lBQzVCLE1BQU0sRUFBQyxZQUFZLEVBQUMsR0FBRyxLQUFLLENBQUM7SUFFN0IsZ0JBQWdCLENBQUMsQ0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLEVBQUUsMkJBQTJCLENBQUMsQ0FBQztJQUU1RCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN4RCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNoRCxNQUFNLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQztJQUNyRCxNQUFNLENBQUMsRUFBRSxPQUFPLEVBQUUsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQztJQUVyQyxNQUFNLE1BQU0sR0FBRyxJQUFJLFlBQVksQ0FBQyxLQUFLLEdBQUcsT0FBTyxHQUFHLE1BQU0sR0FBRyxL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QUksQ0FBQyxHQUFHLENBQzdCLE1BQU0sR0FBRyxDQUFDLEVBQ1YsWUFBWSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7Z0NBQzNCLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQzs0QkFFOUMsSUFBSSxDQUFDLEtBQUssZ0JBQWdCLEVBQUU7Z0NBQzFCLEtBQUssSUFBSSxRQUFRLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxDQUFDOzZCQUNsQzt5QkFDRjtxQkFDRjtvQkFDRCxNQUFNLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQztpQkFDL0I7YUFDRjtTQUNGO0tBQ0Y7SUFFRCxPQUFPLE9BQU8sQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBQ3BFLENBQUM7QUFFRCxNQUFNLENBQUMsTUFBTSwrQkFBK0IsR0FBaUI7SUFDM0QsVUFBVSxFQUFFLHlCQUF5QjtJQUNyQyxXQUFXLEVBQUUsS0FBSztJQUNsQixVQUFVLEVBQUUseUJBQWtEO0NBQy9ELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAyMCBHb29nbGUgTExDLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbmltcG9ydCB7S2VybmVsQ29uZmlnLCBLZXJuZWxGdW5jLCBSZXNpemVOZWFyZXN0TmVpZ2hib3JHcmFkLCBSZXNpemVOZWFyZXN0TmVpZ2hib3JHcmFkQXR0cnMsIFJlc2l6ZU5lYXJlc3ROZWlnaGJvckdyYWRJbnB1dHMsIFRlbnNvckluZm8sIFR5cGVkQXJyYXksIHV0aWx9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCB7TWF0aEJhY2tlbmRDUFV9IGZyb20gJy4uL2JhY2tlbmRfY3B1JztcbmltcG9ydCB7YXNzZXJ0Tm90Q29tcGxleH0gZnJvbSAnLi4vY3B1X3V0aWwnO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVzaXplTmVhcmVzdE5laWdoYm9yR3JhZChhcmdzOiB7XG4gIGlucHV0czogUmVzaXplTmVhcmVzdE5laWdoYm9yR3JhZElucHV0cyxcbiAgYmFja2VuZDogTWF0aEJhY2tlbmRDUFUsXG4gIGF0dHJzOiBSZXNpemVOZWFyZXN0TmVpZ2hib3JHcmFkQXR0cnNcbn0pOiBUZW5zb3JJbmZvIHtcbiAgY29uc3Qge2lucHV0cywgYmFja2VuZCwgYXR0cnN9ID0gYXJncztcbiAgY29uc3Qge2ltYWdlcywgZHl9ID0gaW5wdXRzO1xuICBjb25zdCB7YWxpZ25Db3JuZXJzfSA9IGF0dHJzO1xuXG4gIGFzc2VydE5vdENvbXBsZXgoW2R5LCBpbWFnZXNdLCAncmVzaXplTmVhcmVzdE5laWdoYm9yR3JhZCcpO1xuXG4gIGNvbnN0IGltYWdlc1N0cmlkZXMgPSB1dGlsLmNvbXB1dGVTdHJpZGVzKGltYWdlcy5zaGFwZSk7XG4gIGNvbnN0IGR5U3RyaWRlcyA9IHV0aWwuY29tcHV0ZVN0cmlkZXMoZHkuc2hhcGUpO1xuICBjb25zdCBbYmF0Y2gsIHhIZWlnaHQsIHhXaWR0aCwgZGVwdGhdID0gaW1hZ2VzLnNoYXBlO1xuICBjb25zdCBbLCB5SGVpZ2h0LCB5V2lkdGhdID0gZHkuc2hhcGU7XG5cbiAgY29uc3Qgb3V0cHV0ID0gbmV3IEZsb2F0MzJBcnJheShiYXRjaCAqIHhIZWlnaHQgKiB4V2lkdGggKiBkZXB0aCk7XG4gIGNvbnN0IGR5VmFsdWVzID0gYmFja2VuZC5kYXRhLmdldChkeS5kYXRhSWQpLnZhbHVlcyBhcyBUeXBlZEFycmF5O1xuXG4gIC8vIEluIHRoZSBiYWNrd2FyZHMgcGFzcywgd2Ugd2FudCB0byBmaW5kIHRoZSBwaXhlbHMgdGhhdCB3ZXJlIGdlbmVyYXRlZFxuICAvLyBmb3IgZWFjaCBwaXhlbCBpbiB0aGUgaW5wdXQgaW1hZ2UgdGhlIGZvcndhcmQgcGFzc1xuXG4gIGNvbnN0IGVmZmVjdGl2ZVhTaXplOiBbbnVtYmVyLCBudW1iZXJdID0gW1xuICAgIChhbGlnbkNvcm5lcnMgJiYgeUhlaWdodCA+IDEpID8geEhlaWdodCAtIDEgOiB4SGVpZ2h0LFxuICAgIChhbGlnbkNvcm5lcnMgJiYgeVdpZHRoID4gMSkgPyB4V2lkdGggLSAxIDogeFdpZHRoXG4gIF07XG5cbiAgY29uc3QgZWZmZWN0aXZlWVNpemU6IFtudW1iZXIsIG51bWJlcl0gPSBbXG4gICAgKGFsaWduQ29ybmVycyAmJiB5SGVpZ2h0ID4gMSkgPyB5SGVpZ2h0IC0gMSA6IHlIZWlnaHQsXG4gICAgKGFsaWduQ29ybmVycyAmJiB5V2lkdGggPiAxKSA/IHlXaWR0aCAtIDEgOiB5V2lkdGhcbiAgXTtcblxuICBjb25zdCBoZWlnaHRTY2FsZSA9IGVmZmVjdGl2ZVhTaXplWzBdIC8gZWZmZWN0aXZlWVNpemVbMF07XG4gIGNvbnN0IHdpZHRoU2NhbGUgPSBlZmZlY3RpdmVYU2l6ZVsxXSAvIGVmZmVjdGl2ZVlTaXplWzFdO1xuXG4gIGNvbnN0IGludkhlaWdodFNjYWxlID0gMSAvIGhlaWdodFNjYWxlO1xuICBjb25zdCBpbnZXaWR0aFNjYWxlID0gMSAvIHdpZHRoU2NhbGU7XG5cbiAgLy8gVGhpcyBkZWZpbmVzIHRoZSBzaXplIG9mIHRoZSB3aW5kb3cgb2YgdmFsdWVzIGFyb3VuZCBhIHBhcnRpY3VsYXJcbiAgLy8gaW5kZXggaW4gZHkgdGhhdCB3ZSB3YW50IHRvIHNlYXJjaCBmb3IgY29udHJpYnV0aW9ucyB0byBkeC5cbiAgY29uc3Qgd2luSGVpZ2h0ID0gKE1hdGguY2VpbChpbnZIZWlnaHRTY2FsZSkgKiAyKSArIDI7XG4gIGNvbnN0IHdpbldpZHRoID0gKE1hdGguY2VpbChpbnZXaWR0aFNjYWxlKSAqIDIpICsgMjtcblxuICAvLyBMb29wIG92ZXIgdGhlIG91dHB1dCBzcGFjZS5cbiAgZm9yIChsZXQgYiA9IDA7IGIgPCBiYXRjaDsgYisrKSB7XG4gICAgY29uc3QgYmF0Y2hPZmZzZXQgPSBiICogaW1hZ2VzU3RyaWRlc1swXTtcbiAgICBmb3IgKGxldCByID0gMDsgciA8IHhIZWlnaHQ7IHIrKykge1xuICAgICAgY29uc3Qgcm93T2Zmc2V0ID0gYmF0Y2hPZmZzZXQgKyByICogaW1hZ2VzU3RyaWRlc1sxXTtcblxuICAgICAgLy8gQ29tcHV0ZSBib3VuZHMgZm9yIHdoZXJlIGluIGR5IHdlIHdpbGwgbG9va1xuICAgICAgY29uc3Qgc3RhcnRSTGVycCA9IE1hdGguZmxvb3IociAqIGludkhlaWdodFNjYWxlKTtcbiAgICAgIGNvbnN0IHN0YXJ0RHlSID0gTWF0aC5mbG9vcihzdGFydFJMZXJwIC0gKHdpbkhlaWdodCAvIDIpKTtcbiAgICAgIGZvciAobGV0IGMgPSAwOyBjIDwgeFdpZHRoOyBjKyspIHtcbiAgICAgICAgY29uc3QgY29sT2Zmc2V0ID0gcm93T2Zmc2V0ICsgYyAqIGltYWdlc1N0cmlkZXNbMl07XG5cbiAgICAgICAgLy8gQ29tcHV0ZSBib3VuZHMgZm9yIHdoZXJlIGluIGR5IHdlIHdpbGwgbG9va1xuICAgICAgICBjb25zdCBzdGFydENMZXJwID0gTWF0aC5mbG9vcihjICogaW52V2lkdGhTY2FsZSk7XG4gICAgICAgIGNvbnN0IHN0YXJ0RHlDID0gTWF0aC5mbG9vcihzdGFydENMZXJwIC0gKHdpbldpZHRoIC8gMikpO1xuXG4gICAgICAgIGZvciAobGV0IGQgPSAwOyBkIDwgZGVwdGg7IGQrKykge1xuICAgICAgICAgIGxldCBhY2N1bSA9IDA7XG4gICAgICAgICAgLy8gbG9vcCBvdmVyIGR5XG5cbiAgICAgICAgICBmb3IgKGxldCBkeVJJbmRleCA9IDA7IGR5UkluZGV4IDwgd2luSGVpZ2h0OyBkeVJJbmRleCsrKSB7XG4gICAgICAgICAgICBjb25zdCBkeVIgPSBkeVJJbmRleCArIHN0YXJ0RHlSO1xuICAgICAgICAgICAgLy8gR3VhcmQgYWdhaW5zdCB0aGUgd2luZG93IGV4Y2VlZGluZyB0aGUgYm91bmRzIG9mIGR5XG4gICAgICAgICAgICBpZiAoZHlSIDwgMCB8fCBkeVIgPj0geUhlaWdodCkge1xuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgZHlST2Zmc2V0ID0gYmF0Y2hPZmZzZXQgKyBkeVIgKiBkeVN0cmlkZXNbMV07XG4gICAgICAgICAgICBjb25zdCBzb3VyY2VGcmFjUm93ID0gZHlSICogaGVpZ2h0U2NhbGU7XG4gICAgICAgICAgICBjb25zdCBzb3VyY2VOZWFyZXN0Um93ID0gTWF0aC5taW4oXG4gICAgICAgICAgICAgICAgeEhlaWdodCAtIDEsXG4gICAgICAgICAgICAgICAgYWxpZ25Db3JuZXJzID8gTWF0aC5yb3VuZChzb3VyY2VGcmFjUm93KSA6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWF0aC5mbG9vcihzb3VyY2VGcmFjUm93KSk7XG4gICAgICAgICAgICBpZiAociAhPT0gc291cmNlTmVhcmVzdFJvdykge1xuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAobGV0IGR5Q0luZGV4ID0gMDsgZHlDSW5kZXggPCB3aW5XaWR0aDsgZHlDSW5kZXgrKykge1xuICAgICAgICAgICAgICBjb25zdCBkeUMgPSBkeUNJbmRleCArIHN0YXJ0RHlDO1xuICAgICAgICAgICAgICAvLyBHdWFyZCBhZ2FpbnN0IHRoZSB3aW5kb3cgZXhjZWVkaW5nIHRoZSBib3VuZHMgb2YgZHlcbiAgICAgICAgICAgICAgaWYgKGR5QyA8IDAgfHwgZHlDID49IHlXaWR0aCkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgY29uc3QgZHlDT2Zmc2V0ID0gZHlST2Zmc2V0ICsgZHlDICogZHlTdHJpZGVzWzJdO1xuICAgICAgICAgICAgICBjb25zdCBzb3VyY2VGcmFjQ29sID0gZHlDICogd2lkdGhTY2FsZTtcbiAgICAgICAgICAgICAgY29uc3Qgc291cmNlTmVhcmVzdENvbCA9IE1hdGgubWluKFxuICAgICAgICAgICAgICAgICAgeFdpZHRoIC0gMSxcbiAgICAgICAgICAgICAgICAgIGFsaWduQ29ybmVycyA/IE1hdGgucm91bmQoc291cmNlRnJhY0NvbCkgOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWF0aC5mbG9vcihzb3VyY2VGcmFjQ29sKSk7XG5cbiAgICAgICAgICAgICAgaWYgKGMgPT09IHNvdXJjZU5lYXJlc3RDb2wpIHtcbiAgICAgICAgICAgICAgICBhY2N1bSArPSBkeVZhbHVlc1tkeUNPZmZzZXQgKyBkXTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBvdXRwdXRbY29sT2Zmc2V0ICsgZF0gPSBhY2N1bTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBiYWNrZW5kLm1ha2VUZW5zb3JJbmZvKGltYWdlcy5zaGFwZSwgaW1hZ2VzLmR0eXBlLCBvdXRwdXQpO1xufVxuXG5leHBvcnQgY29uc3QgcmVzaXplTmVhcmVzdE5laWdoYm9yR3JhZENvbmZpZzogS2VybmVsQ29uZmlnID0ge1xuICBrZXJuZWxOYW1lOiBSZXNpemVOZWFyZXN0TmVpZ2hib3JHcmFkLFxuICBiYWNrZW5kTmFtZTogJ2NwdScsXG4gIGtlcm5lbEZ1bmM6IHJlc2l6ZU5lYXJlc3ROZWlnaGJvckdyYWQgYXMgdW5rbm93biBhcyBLZXJuZWxGdW5jXG59O1xuIl19
|