/** * @license * Copyright 2018 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 { util } from '@tensorflow/tfjs-core'; /** * Produces GLSL code that derives logical coordinates from a flat * index. The code performs integer division with each stride and decrements * the index until the index equals the final dimension coordinate. */ export function getLogicalCoordinatesFromFlatIndex(coords, shape, index = 'index') { const strides = util.computeStrides(shape); return strides .map((stride, i) => { const line1 = `int ${coords[i]} = ${index} / ${stride}`; const line2 = i === strides.length - 1 ? `int ${coords[i + 1]} = ${index} - ${coords[i]} * ${stride}` : `index -= ${coords[i]} * ${stride}`; return `${line1}; ${line2};`; }) .join(''); } export function getOutputLogicalCoordinatesFromFlatIndexByUniform(coords, shape, index = 'index') { const strides = util.computeStrides(shape); return strides .map((_, i) => { const line1 = `int ${coords[i]} = ${index} / outShapeStrides[${i}]`; const line2 = i === strides.length - 1 ? `int ${coords[i + 1]} = ${index} - ${coords[i]} * outShapeStrides[${i}]` : `index -= ${coords[i]} * outShapeStrides[${i}]`; return `${line1}; ${line2};`; }) .join(''); } // Produces GLSL code that computes strides. function symbolicallyComputeStrides(indicesArr, variableName) { const numCoords = indicesArr.length; const shape = indicesArr.map(d => `${variableName}[${d}]`); const strides = new Array(numCoords - 1); strides[numCoords - 2] = shape[numCoords - 1]; for (let i = numCoords - 3; i >= 0; --i) { strides[i] = `(${strides[i + 1]} * ${shape[i + 1]})`; } return strides; } export function getLogicalCoordinatesFromFlatIndexByUniform(coords, variableName, index = 'index') { const indicesArray = coords.map((_, i) => i); const strides = symbolicallyComputeStrides(indicesArray, variableName); return strides .map((_, i) => { const line1 = `int ${coords[i]} = ${index} / ${strides[i]}`; const line2 = i === strides.length - 1 ? `int ${coords[i + 1]} = ${index} - ${coords[i]} * ${strides[i]}` : `index -= ${coords[i]} * ${strides[i]}`; return `${line1}; ${line2};`; }) .join(''); } function buildVec(x) { if (x.length === 1) { return `${x[0]}`; } return `vec${x.length}(${x.join(',')})`; } /** * Produces GLSL code that computes the dot product of the input x and y * vectors. Handles splitting inputs into increments of vec4s when necessary. */ export function dotify(x, y) { if (x.length !== y.length) { throw new Error(`Vectors to be dotted must be of the same length -` + `got ${x.length} and ${y.length}`); } const slices = []; const nearestVec4 = Math.floor(x.length / 4); const nearestVec4Remainder = x.length % 4; for (let i = 0; i < nearestVec4; i++) { const xSlice = x.slice(i * 4, i * 4 + 4); const ySlice = y.slice(i * 4, i * 4 + 4); slices.push(`${buildVec(xSlice)}, ${buildVec(ySlice)}`); } if (nearestVec4Remainder !== 0) { let xSlice = x.slice(nearestVec4 * 4); let ySlice = y.slice(nearestVec4 * 4); if (xSlice.length === 1) { xSlice = xSlice.map(d => `float(${d})`); ySlice = ySlice.map(d => `float(${d})`); } slices.push(`${buildVec(xSlice)}, ${buildVec(ySlice)}`); } return slices.map((d, i) => `dot(${d})`).join('+'); } /** * Produces GLSL that computes the flat index from 3D coordinates. */ export function getFlatIndexFrom3D(shape) { const strides = util.computeStrides(shape).map(d => d.toString()); return ` int getFlatIndex(ivec3 coords) { return coords.x * ${strides[0]} + coords.y * ${strides[1]} + coords.z; } `; } export function getFlatIndexFrom3DOutput() { return ` int getFlatIndex(ivec3 coords) { return coords.x * outShapeStrides[0] + coords.y * outShapeStrides[1] + coords.z; } `; } export const ENCODE_FLOAT_SNIPPET = ` const float FLOAT_MAX = 1.70141184e38; const float FLOAT_MIN = 1.17549435e-38; lowp vec4 encode_float(highp float v) { if (isnan(v)) { return vec4(255, 255, 255, 255); } highp float av = abs(v); if(av < FLOAT_MIN) { return vec4(0.0, 0.0, 0.0, 0.0); } else if(v > FLOAT_MAX) { return vec4(0.0, 0.0, 128.0, 127.0) / 255.0; } else if(v < -FLOAT_MAX) { return vec4(0.0, 0.0, 128.0, 255.0) / 255.0; } highp vec4 c = vec4(0,0,0,0); highp float e = floor(log2(av)); highp float m = exp2(fract(log2(av))) - 1.0; c[2] = floor(128.0 * m); m -= c[2] / 128.0; c[1] = floor(32768.0 * m); m -= c[1] / 32768.0; c[0] = floor(8388608.0 * m); highp float ebias = e + 127.0; c[3] = floor(ebias / 2.0); ebias -= c[3] * 2.0; c[2] += floor(ebias) * 128.0; c[3] += 128.0 * step(0.0, -v); return c / 255.0; } `; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhZGVyX2NvbXBpbGVyX3V0aWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi90ZmpzLWJhY2tlbmQtd2ViZ2wvc3JjL3NoYWRlcl9jb21waWxlcl91dGlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sRUFBQyxJQUFJLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUUzQzs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLGtDQUFrQyxDQUM5QyxNQUFnQixFQUFFLEtBQWUsRUFBRSxLQUFLLEdBQUcsT0FBTztJQUNwRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzNDLE9BQU8sT0FBTztTQUNULEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUNqQixNQUFNLEtBQUssR0FBRyxPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxLQUFLLE1BQU0sTUFBTSxFQUFFLENBQUM7UUFDeEQsTUFBTSxLQUFLLEdBQUcsQ0FBQyxLQUFLLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDcEMsT0FBTyxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEtBQUssTUFBTSxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sTUFBTSxFQUFFLENBQUMsQ0FBQztZQUM5RCxZQUFZLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxNQUFNLEVBQUUsQ0FBQztRQUN4QyxPQUFPLEdBQUcsS0FBSyxLQUFLLEtBQUssR0FBRyxDQUFDO0lBQy9CLENBQUMsQ0FBQztTQUNELElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUNoQixDQUFDO0FBRUQsTUFBTSxVQUFVLGlEQUFpRCxDQUM3RCxNQUFnQixFQUFFLEtBQWUsRUFBRSxLQUFLLEdBQUcsT0FBTztJQUNwRCxNQUFNLE9BQU8sR0FBRyxJ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TSxvQkFBb0IsR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0NBdUNuQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTggR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG5pbXBvcnQge3V0aWx9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbi8qKlxuICogUHJvZHVjZXMgR0xTTCBjb2RlIHRoYXQgZGVyaXZlcyBsb2dpY2FsIGNvb3JkaW5hdGVzIGZyb20gYSBmbGF0XG4gKiBpbmRleC4gVGhlIGNvZGUgcGVyZm9ybXMgaW50ZWdlciBkaXZpc2lvbiB3aXRoIGVhY2ggc3RyaWRlIGFuZCBkZWNyZW1lbnRzXG4gKiB0aGUgaW5kZXggdW50aWwgdGhlIGluZGV4IGVxdWFscyB0aGUgZmluYWwgZGltZW5zaW9uIGNvb3JkaW5hdGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRMb2dpY2FsQ29vcmRpbmF0ZXNGcm9tRmxhdEluZGV4KFxuICAgIGNvb3Jkczogc3RyaW5nW10sIHNoYXBlOiBudW1iZXJbXSwgaW5kZXggPSAnaW5kZXgnKTogc3RyaW5nIHtcbiAgY29uc3Qgc3RyaWRlcyA9IHV0aWwuY29tcHV0ZVN0cmlkZXMoc2hhcGUpO1xuICByZXR1cm4gc3RyaWRlc1xuICAgICAgLm1hcCgoc3RyaWRlLCBpKSA9PiB7XG4gICAgICAgIGNvbnN0IGxpbmUxID0gYGludCAke2Nvb3Jkc1tpXX0gPSAke2luZGV4fSAvICR7c3RyaWRlfWA7XG4gICAgICAgIGNvbnN0IGxpbmUyID0gaSA9PT0gc3RyaWRlcy5sZW5ndGggLSAxID9cbiAgICAgICAgICAgIGBpbnQgJHtjb29yZHNbaSArIDFdfSA9ICR7aW5kZXh9IC0gJHtjb29yZHNbaV19ICogJHtzdHJpZGV9YCA6XG4gICAgICAgICAgICBgaW5kZXggLT0gJHtjb29yZHNbaV19ICogJHtzdHJpZGV9YDtcbiAgICAgICAgcmV0dXJuIGAke2xpbmUxfTsgJHtsaW5lMn07YDtcbiAgICAgIH0pXG4gICAgICAuam9pbignJyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRPdXRwdXRMb2dpY2FsQ29vcmRpbmF0ZXNGcm9tRmxhdEluZGV4QnlVbmlmb3JtKFxuICAgIGNvb3Jkczogc3RyaW5nW10sIHNoYXBlOiBudW1iZXJbXSwgaW5kZXggPSAnaW5kZXgnKTogc3RyaW5nIHtcbiAgY29uc3Qgc3RyaWRlcyA9IHV0aWwuY29tcHV0ZVN0cmlkZXMoc2hhcGUpO1xuICByZXR1cm4gc3RyaWRlc1xuICAgICAgLm1hcCgoXywgaSkgPT4ge1xuICAgICAgICBjb25zdCBsaW5lMSA9IGBpbnQgJHtjb29yZHNbaV19ID0gJHtpbmRleH0gLyBvdXRTaGFwZVN0cmlkZXNbJHtpfV1gO1xuICAgICAgICBjb25zdCBsaW5lMiA9IGkgPT09IHN0cmlkZXMubGVuZ3RoIC0gMSA/XG4gICAgICAgICAgICBgaW50ICR7Y29vcmRzW2kgKyAxXX0gPSAke2luZGV4fSAtICR7Y29vcmRzW2ldfSAqIG91dFNoYXBlU3RyaWRlc1ske1xuICAgICAgICAgICAgICAgIGl9XWAgOlxuICAgICAgICAgICAgYGluZGV4IC09ICR7Y29vcmRzW2ldfSAqIG91dFNoYXBlU3RyaWRlc1ske2l9XWA7XG4gICAgICAgIHJldHVybiBgJHtsaW5lMX07ICR7bGluZTJ9O2A7XG4gICAgICB9KVxuICAgICAgLmpvaW4oJycpO1xufVxuXG4vLyBQcm9kdWNlcyBHTFNMIGNvZGUgdGhhdCBjb21wdXRlcyBzdHJpZGVzLlxuZnVuY3Rpb24gc3ltYm9saWNhbGx5Q29tcHV0ZVN0cmlkZXMoXG4gICAgaW5kaWNlc0FycjogbnVtYmVyW10sIHZhcmlhYmxlTmFtZTogc3RyaW5nKTogc3RyaW5nW10ge1xuICBjb25zdCBudW1Db29yZHMgPSBpbmRpY2VzQXJyLmxlbmd0aDtcbiAgY29uc3Qgc2hhcGUgPSBpbmRpY2VzQXJyLm1hcChkID0+IGAke3ZhcmlhYmxlTmFtZX1bJHtkfV1gKTtcbiAgY29uc3Qgc3RyaWRlcyA9IG5ldyBBcnJheShudW1Db29yZHMgLSAxKTtcbiAgc3RyaWRlc1tudW1Db29yZHMgLSAyXSA9IHNoYXBlW251bUNvb3JkcyAtIDFdO1xuICBmb3IgKGxldCBpID0gbnVtQ29vcmRzIC0gMzsgaSA+PSAwOyAtLWkpIHtcbiAgICBzdHJpZGVzW2ldID0gYCgke3N0cmlkZXNbaSArIDFdfSAqICR7c2hhcGVbaSArIDFdfSlgO1xuICB9XG5cbiAgcmV0dXJuIHN0cmlkZXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRMb2dpY2FsQ29vcmRpbmF0ZXNGcm9tRmxhdEluZGV4QnlVbmlmb3JtKFxuICAgIGNvb3Jkczogc3RyaW5nW10sIHZhcmlhYmxlTmFtZTogc3RyaW5nLCBpbmRleCA9ICdpbmRleCcpOiBzdHJpbmcge1xuICBjb25zdCBpbmRpY2VzQXJyYXkgPSBjb29yZHMubWFwKChfLCBpKSA9PiBpKTtcbiAgY29uc3Qgc3RyaWRlcyA9IHN5bWJvbGljYWxseUNvbXB1dGVTdHJpZGVzKGluZGljZXNBcnJheSwgdmFyaWFibGVOYW1lKTtcbiAgcmV0dXJuIHN0cmlkZXNcbiAgICAgIC5tYXAoKF8sIGkpID0+IHtcbiAgICAgICAgY29uc3QgbGluZTEgPSBgaW50ICR7Y29vcmRzW2ldfSA9ICR7aW5kZXh9IC8gJHtzdHJpZGVzW2ldfWA7XG4gICAgICAgIGNvbnN0IGxpbmUyID0gaSA9PT0gc3RyaWRlcy5sZW5ndGggLSAxID9cbiAgICAgICAgICAgIGBpbnQgJHtjb29yZHNbaSArIDFdfSA9ICR7aW5kZXh9IC0gJHtjb29yZHNbaV19ICogJHtzdHJpZGVzW2ldfWAgOlxuICAgICAgICAgICAgYGluZGV4IC09ICR7Y29vcmRzW2ldfSAqICR7c3RyaWRlc1tpXX1gO1xuICAgICAgICByZXR1cm4gYCR7bGluZTF9OyAke2xpbmUyfTtgO1xuICAgICAgfSlcbiAgICAgIC5qb2luKCcnKTtcbn1cblxuZnVuY3Rpb24gYnVpbGRWZWMoeDogc3RyaW5nW10pOiBzdHJpbmcge1xuICBpZiAoeC5sZW5ndGggPT09IDEpIHtcbiAgICByZXR1cm4gYCR7eFswXX1gO1xuICB9XG4gIHJldHVybiBgdmVjJHt4Lmxlbmd0aH0oJHt4LmpvaW4oJywnKX0pYDtcbn1cblxuLyoqXG4gKiBQcm9kdWNlcyBHTFNMIGNvZGUgdGhhdCBjb21wdXRlcyB0aGUgZG90IHByb2R1Y3Qgb2YgdGhlIGlucHV0IHggYW5kIHlcbiAqIHZlY3RvcnMuIEhhbmRsZXMgc3BsaXR0aW5nIGlucHV0cyBpbnRvIGluY3JlbWVudHMgb2YgdmVjNHMgd2hlbiBuZWNlc3NhcnkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkb3RpZnkoeDogc3RyaW5nW10sIHk6IHN0cmluZ1tdKTogc3RyaW5nIHtcbiAgaWYgKHgubGVuZ3RoICE9PSB5Lmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYFZlY3RvcnMgdG8gYmUgZG90dGVkIG11c3QgYmUgb2YgdGhlIHNhbWUgbGVuZ3RoIC1gICtcbiAgICAgICAgYGdvdCAke3gubGVuZ3RofSBhbmQgJHt5Lmxlbmd0aH1gKTtcbiAgfVxuXG4gIGNvbnN0IHNsaWNlczogc3RyaW5nW10gPSBbXTtcbiAgY29uc3QgbmVhcmVzdFZlYzQgPSBNYXRoLmZsb29yKHgubGVuZ3RoIC8gNCk7XG4gIGNvbnN0IG5lYXJlc3RWZWM0UmVtYWluZGVyID0geC5sZW5ndGggJSA0O1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbmVhcmVzdFZlYzQ7IGkrKykge1xuICAgIGNvbnN0IHhTbGljZSA9IHguc2xpY2UoaSAqIDQsIGkgKiA0ICsgNCk7XG4gICAgY29uc3QgeVNsaWNlID0geS5zbGljZShpICogNCwgaSAqIDQgKyA0KTtcbiAgICBzbGljZXMucHVzaChgJHtidWlsZFZlYyh4U2xpY2UpfSwgJHtidWlsZFZlYyh5U2xpY2UpfWApO1xuICB9XG5cbiAgaWYgKG5lYXJlc3RWZWM0UmVtYWluZGVyICE9PSAwKSB7XG4gICAgbGV0IHhTbGljZSA9IHguc2xpY2UobmVhcmVzdFZlYzQgKiA0KTtcbiAgICBsZXQgeVNsaWNlID0geS5zbGljZShuZWFyZXN0VmVjNCAqIDQpO1xuICAgIGlmICh4U2xpY2UubGVuZ3RoID09PSAxKSB7XG4gICAgICB4U2xpY2UgPSB4U2xpY2UubWFwKGQgPT4gYGZsb2F0KCR7ZH0pYCk7XG4gICAgICB5U2xpY2UgPSB5U2xpY2UubWFwKGQgPT4gYGZsb2F0KCR7ZH0pYCk7XG4gICAgfVxuICAgIHNsaWNlcy5wdXNoKGAke2J1aWxkVmVjKHhTbGljZSl9LCAke2J1aWxkVmVjKHlTbGljZSl9YCk7XG4gIH1cblxuICByZXR1cm4gc2xpY2VzLm1hcCgoZCwgaSkgPT4gYGRvdCgke2R9KWApLmpvaW4oJysnKTtcbn1cblxuLyoqXG4gKiBQcm9kdWNlcyBHTFNMIHRoYXQgY29tcHV0ZXMgdGhlIGZsYXQgaW5kZXggZnJvbSAzRCBjb29yZGluYXRlcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEZsYXRJbmRleEZyb20zRChzaGFwZTogW251bWJlciwgbnVtYmVyLCBudW1iZXJdKTogc3RyaW5nIHtcbiAgY29uc3Qgc3RyaWRlcyA9IHV0aWwuY29tcHV0ZVN0cmlkZXMoc2hhcGUpLm1hcChkID0+IGQudG9TdHJpbmcoKSk7XG5cbiAgcmV0dXJuIGBcbiAgaW50IGdldEZsYXRJbmRleChpdmVjMyBjb29yZHMpIHtcbiAgICByZXR1cm4gY29vcmRzLnggKiAke3N0cmlkZXNbMF19ICsgY29vcmRzLnkgKiAke3N0cmlkZXNbMV19ICsgY29vcmRzLno7XG4gIH1cbmA7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRGbGF0SW5kZXhGcm9tM0RPdXRwdXQoKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBcbiAgaW50IGdldEZsYXRJbmRleChpdmVjMyBjb29yZHMpIHtcbiAgICByZXR1cm4gY29vcmRzLnggKiBvdXRTaGFwZVN0cmlkZXNbMF0gKyBjb29yZHMueSAqIG91dFNoYXBlU3RyaWRlc1sxXSArIGNvb3Jkcy56O1xuICB9XG5gO1xufVxuXG5leHBvcnQgY29uc3QgRU5DT0RFX0ZMT0FUX1NOSVBQRVQgPSBgXG4gIGNvbnN0IGZsb2F0IEZMT0FUX01BWCA9IDEuNzAxNDExODRlMzg7XG4gIGNvbnN0IGZsb2F0IEZMT0FUX01JTiA9IDEuMTc1NDk0MzVlLTM4O1xuXG4gIGxvd3AgdmVjNCBlbmNvZGVfZmxvYXQoaGlnaHAgZmxvYXQgdikge1xuICAgIGlmIChpc25hbih2KSkge1xuICAgICAgcmV0dXJuIHZlYzQoMjU1LCAyNTUsIDI1NSwgMjU1KTtcbiAgICB9XG5cbiAgICBoaWdocCBmbG9hdCBhdiA9IGFicyh2KTtcblxuICAgIGlmKGF2IDwgRkxPQVRfTUlOKSB7XG4gICAgICByZXR1cm4gdmVjNCgwLjAsIDAuMCwgMC4wLCAwLjApO1xuICAgIH0gZWxzZSBpZih2ID4gRkxPQVRfTUFYKSB7XG4gICAgICByZXR1cm4gdmVjNCgwLjAsIDAuMCwgMTI4LjAsIDEyNy4wKSAvIDI1NS4wO1xuICAgIH0gZWxzZSBpZih2IDwgLUZMT0FUX01BWCkge1xuICAgICAgcmV0dXJuIHZlYzQoMC4wLCAwLjAsICAxMjguMCwgMjU1LjApIC8gMjU1LjA7XG4gICAgfVxuXG4gICAgaGlnaHAgdmVjNCBjID0gdmVjNCgwLDAsMCwwKTtcblxuICAgIGhpZ2hwIGZsb2F0IGUgPSBmbG9vcihsb2cyKGF2KSk7XG4gICAgaGlnaHAgZmxvYXQgbSA9IGV4cDIoZnJhY3QobG9nMihhdikpKSAtIDEuMDtcblxuICAgIGNbMl0gPSBmbG9vcigxMjguMCAqIG0pO1xuICAgIG0gLT0gY1syXSAvIDEyOC4wO1xuICAgIGNbMV0gPSBmbG9vcigzMjc2OC4wICogbSk7XG4gICAgbSAtPSBjWzFdIC8gMzI3NjguMDtcbiAgICBjWzBdID0gZmxvb3IoODM4ODYwOC4wICogbSk7XG5cbiAgICBoaWdocCBmbG9hdCBlYmlhcyA9IGUgKyAxMjcuMDtcbiAgICBjWzNdID0gZmxvb3IoZWJpYXMgLyAyLjApO1xuICAgIGViaWFzIC09IGNbM10gKiAyLjA7XG4gICAgY1syXSArPSBmbG9vcihlYmlhcykgKiAxMjguMDtcblxuICAgIGNbM10gKz0gMTI4LjAgKiBzdGVwKDAuMCwgLXYpO1xuXG4gICAgcmV0dXJuIGMgLyAyNTUuMDtcbiAgfVxuYDtcbiJdfQ==