/** * @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 * * https://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 { tensor1d } from '../tensor1d'; import { op } from '../operation'; import { cast } from '../cast'; import { split } from '../split'; import { bincount } from '../bincount'; import { lessEqual } from '../less_equal'; import { greater } from '../greater'; import { sum } from '../sum'; import { add } from '../add'; import { mul } from '../mul'; import { div } from '../div'; import { sub } from '../sub'; import { round } from '../round'; import { where } from '../where'; import { fill } from '../fill'; import { slice } from '../slice'; import { range } from '../range'; import { tensor } from '../tensor'; import * as util from '../../util'; import { convertToTensor } from '../../tensor_util_env'; /** * Performs image binarization with corresponding threshold * (depends on the method)value, which creates a binary image from a grayscale. * @param image 3d tensor of shape [imageHeight,imageWidth, depth], * where imageHeight and imageWidth must be positive.The image color * range should be [0, 255]. * @param method Optional string from `'binary' | 'otsu'` * which specifies the method for thresholding. Defaults to 'binary'. * @param inverted Optional boolean whichspecifies * if colours should be inverted. Defaults to false. * @param threshValue Optional number which defines threshold value from 0 to 1. * Defaults to 0.5. * @return A 3d tensor of shape [imageHeight,imageWidth, depth], which * contains binarized image. */ function threshold_(image, method = 'binary', inverted = false, threshValue = 0.5) { const $image = convertToTensor(image, 'image', 'threshold'); /* 0.2989, 0.5870, 0.1140 are represent luma coefficients in CCIR601. Reference for converting between RGB and grayscale: https://en.wikipedia.org/wiki/Luma_%28video%29 */ const RED_INTENCITY_COEF = 0.2989; const GREEN_INTENCITY_COEF = 0.5870; const BLUE_INTENCITY_COEF = 0.1140; const totalPixelsInImage = $image.shape[0] * $image.shape[1]; let $threshold = mul(tensor1d([threshValue]), 255); let r, g, b, grayscale; util.assert($image.rank === 3, () => 'Error in threshold: image must be rank 3,' + `but got rank ${$image.rank}.`); util.assert($image.shape[2] === 3 || $image.shape[2] === 1, () => 'Error in threshold: ' + 'image color channel must be equal to 3 or 1' + `but got ${$image.shape[2]}.`); util.assert($image.dtype === 'int32' || $image.dtype === 'float32', () => 'Error in dtype: image dtype must be int32 or float32,' + `but got dtype ${$image.dtype}.`); util.assert(method === 'otsu' || method === 'binary', () => `Method must be binary or otsu, but was ${method}`); if ($image.shape[2] === 3) { [r, g, b] = split($image, [1, 1, 1], -1); const $r = mul(r, RED_INTENCITY_COEF); const $g = mul(g, GREEN_INTENCITY_COEF); const $b = mul(b, BLUE_INTENCITY_COEF); grayscale = add(add($r, $g), $b); } else { grayscale = image; } if (method === 'otsu') { const $histogram = bincount(cast(round(grayscale), 'int32'), tensor([]), 256); $threshold = otsu($histogram, totalPixelsInImage); } const invCondition = inverted ? lessEqual(grayscale, $threshold) : greater(grayscale, $threshold); const result = cast(mul(invCondition, 255), 'int32'); return result; } function otsu(histogram, total) { let bestThresh = tensor1d([-1]); let bestInBetVar = tensor1d([0]); let cInBetVar = tensor1d([0]); let classFirst, classSecond, meanFirst, meanSec, weightForeground, weightBack; for (let index = 0; index < histogram.size - 1; index++) { classFirst = slice(histogram, 0, index + 1); classSecond = slice(histogram, index + 1); weightForeground = div(sum(classFirst), total); weightBack = div(sum(classSecond), total); const meanFirstDivA = sum(mul(classFirst, range(0, classFirst.size))); meanFirst = div(meanFirstDivA, sum(classFirst)); const meanSecFill = fill(classSecond.shape, classFirst.size); const meanSecAdd = add(range(0, classSecond.size), meanSecFill); const meanSecMul = mul(classSecond, (meanSecAdd)); meanSec = div(sum(meanSecMul), sum(classSecond)); const cInBetVarSubA = sub(meanFirst, meanSec); const cInBetVarSubB = sub(meanFirst, meanSec); const cInBetVarMul = mul(weightForeground, weightBack); cInBetVar = mul(mul(cInBetVarMul, cInBetVarSubA), cInBetVarSubB); const condition = greater(cInBetVar, bestInBetVar); bestInBetVar = where(condition, cInBetVar, bestInBetVar); bestThresh = where(condition, tensor1d([index]), bestThresh); } return bestThresh; } export const threshold = /* @__PURE__ */ op({ threshold_ }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyZXNob2xkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vdGZqcy1jb3JlL3NyYy9vcHMvaW1hZ2UvdGhyZXNob2xkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUdILE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFdkMsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNsQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQy9CLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDakMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN2QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDckMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUM3QixPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzdCLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDN0IsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUM3QixPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzdCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDakMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNqQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQy9CLE9BQU8sRUFBQyxLQUFLLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDL0IsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNqQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sV0FB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O1FBRXpELFVBQVUsR0FBRyxLQUFLLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUM7S0FFaEU7SUFDRCxPQUFPLFVBQVUsQ0FBQztBQUN0QixDQUFDO0FBRUQsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHLGVBQWUsQ0FBQyxFQUFFLENBQUMsRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMjEgR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwczovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKi9cblxuaW1wb3J0IHsgVGVuc29yMUQsIFRlbnNvcjNEIH0gZnJvbSAnLi4vLi4vdGVuc29yJztcbmltcG9ydCB7IHRlbnNvcjFkIH0gZnJvbSAnLi4vdGVuc29yMWQnO1xuaW1wb3J0IHsgVGVuc29yTGlrZSB9IGZyb20gJy4uLy4uL3R5cGVzJztcbmltcG9ydCB7IG9wIH0gZnJvbSAnLi4vb3BlcmF0aW9uJztcbmltcG9ydCB7IGNhc3QgfSBmcm9tICcuLi9jYXN0JztcbmltcG9ydCB7IHNwbGl0IH0gZnJvbSAnLi4vc3BsaXQnO1xuaW1wb3J0IHsgYmluY291bnQgfSBmcm9tICcuLi9iaW5jb3VudCc7XG5pbXBvcnQgeyBsZXNzRXF1YWwgfSBmcm9tICcuLi9sZXNzX2VxdWFsJztcbmltcG9ydCB7IGdyZWF0ZXIgfSBmcm9tICcuLi9ncmVhdGVyJztcbmltcG9ydCB7IHN1bSB9IGZyb20gJy4uL3N1bSc7XG5pbXBvcnQgeyBhZGQgfSBmcm9tICcuLi9hZGQnO1xuaW1wb3J0IHsgbXVsIH0gZnJvbSAnLi4vbXVsJztcbmltcG9ydCB7IGRpdiB9IGZyb20gJy4uL2Rpdic7XG5pbXBvcnQgeyBzdWIgfSBmcm9tICcuLi9zdWInO1xuaW1wb3J0IHsgcm91bmQgfSBmcm9tICcuLi9yb3VuZCc7XG5pbXBvcnQgeyB3aGVyZSB9IGZyb20gJy4uL3doZXJlJztcbmltcG9ydCB7IGZpbGwgfSBmcm9tICcuLi9maWxsJztcbmltcG9ydCB7c2xpY2V9IGZyb20gJy4uL3NsaWNlJztcbmltcG9ydCB7IHJhbmdlIH0gZnJvbSAnLi4vcmFuZ2UnO1xuaW1wb3J0IHsgdGVuc29yIH0gZnJvbSAnLi4vdGVuc29yJztcbmltcG9ydCAqIGFzIHV0aWwgZnJvbSAnLi4vLi4vdXRpbCc7XG5pbXBvcnQgeyBjb252ZXJ0VG9UZW5zb3IgfSBmcm9tICcuLi8uLi90ZW5zb3JfdXRpbF9lbnYnO1xuXG4vKipcbiAqIFBlcmZvcm1zIGltYWdlIGJpbmFyaXphdGlvbiB3aXRoIGNvcnJlc3BvbmRpbmcgdGhyZXNob2xkXG4gKiAoZGVwZW5kcyBvbiB0aGUgbWV0aG9kKXZhbHVlLCB3aGljaCBjcmVhdGVzIGEgYmluYXJ5IGltYWdlIGZyb20gYSBncmF5c2NhbGUuXG4gKiBAcGFyYW0gaW1hZ2UgM2QgdGVuc29yIG9mIHNoYXBlIFtpbWFnZUhlaWdodCxpbWFnZVdpZHRoLCBkZXB0aF0sXG4gKiB3aGVyZSBpbWFnZUhlaWdodCBhbmQgaW1hZ2VXaWR0aCBtdXN0IGJlIHBvc2l0aXZlLlRoZSBpbWFnZSBjb2xvclxuICogcmFuZ2Ugc2hvdWxkIGJlIFswLCAyNTVdLlxuICogQHBhcmFtIG1ldGhvZCBPcHRpb25hbCBzdHJpbmcgZnJvbSBgJ2JpbmFyeScgfCAnb3RzdSdgXG4gKiB3aGljaCBzcGVjaWZpZXMgdGhlIG1ldGhvZCBmb3IgdGhyZXNob2xkaW5nLiBEZWZhdWx0cyB0byAnYmluYXJ5Jy5cbiAqIEBwYXJhbSBpbnZlcnRlZCBPcHRpb25hbCBib29sZWFuIHdoaWNoc3BlY2lmaWVzXG4gKiBpZiBjb2xvdXJzIHNob3VsZCBiZSBpbnZlcnRlZC4gRGVmYXVsdHMgdG8gZmFsc2UuXG4gKiBAcGFyYW0gdGhyZXNoVmFsdWUgT3B0aW9uYWwgbnVtYmVyIHdoaWNoIGRlZmluZXMgdGhyZXNob2xkIHZhbHVlIGZyb20gMCB0byAxLlxuICogRGVmYXVsdHMgdG8gMC41LlxuICogQHJldHVybiBBIDNkIHRlbnNvciBvZiBzaGFwZSBbaW1hZ2VIZWlnaHQsaW1hZ2VXaWR0aCwgZGVwdGhdLCB3aGljaFxuICogY29udGFpbnMgYmluYXJpemVkIGltYWdlLlxuICovXG5cbmZ1bmN0aW9uIHRocmVzaG9sZF8oXG4gICAgaW1hZ2U6IFRlbnNvcjNEIHwgVGVuc29yTGlrZSxcbiAgICBtZXRob2QgPSAnYmluYXJ5JyxcbiAgICBpbnZlcnRlZCA9IGZhbHNlLFxuICAgIHRocmVzaFZhbHVlID0gMC41XG4pOiBUZW5zb3IzRCB7XG4gICAgY29uc3QgJGltYWdlID0gY29udmVydFRvVGVuc29yKGltYWdlLCAnaW1hZ2UnLCAndGhyZXNob2xkJyk7XG5cbiAgICAvKiAwLjI5ODksIDAuNTg3MCwgMC4xMTQwIGFyZSByZXByZXNlbnQgbHVtYSBjb2VmZmljaWVudHMgaW4gQ0NJUjYwMS5cblx0UmVmZXJlbmNlIGZvciBjb252ZXJ0aW5nIGJldHdlZW4gUkdCIGFuZCBncmF5c2NhbGU6IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0x1bWFfJTI4dmlkZW8lMjkgICovXG5cbiAgICBjb25zdCBSRURfSU5URU5DSVRZX0NPRUYgPSAwLjI5ODk7XG4gICAgY29uc3QgR1JFRU5fSU5URU5DSVRZX0NPRUYgPSAwLjU4NzA7XG4gICAgY29uc3QgQkxVRV9JTlRFTkNJVFlfQ09FRiA9IDAuMTE0MDtcbiAgICBjb25zdCB0b3RhbFBpeGVsc0luSW1hZ2UgPSAkaW1hZ2Uuc2hhcGVbMF0gKiAkaW1hZ2Uuc2hhcGVbMV07XG5cbiAgICBsZXQgJHRocmVzaG9sZCA9IG11bCh0ZW5zb3IxZChbdGhyZXNoVmFsdWVdKSwgMjU1KTtcbiAgICBsZXQgciwgZywgYiwgZ3JheXNjYWxlO1xuXG4gICAgdXRpbC5hc3NlcnQoXG4gICAgICAgICRpbWFnZS5yYW5rID09PSAzLFxuICAgICAgICAoKSA9PiAnRXJyb3IgaW4gdGhyZXNob2xkOiBpbWFnZSBtdXN0IGJlIHJhbmsgMywnICtcbiAgICAgICAgICAgIGBidXQgZ290IHJhbmsgJHskaW1hZ2UucmFua30uYCk7XG5cbiAgICB1dGlsLmFzc2VydChcbiAgICAgICAgJGltYWdlLnNoYXBlWzJdID09PSAzIHx8ICRpbWFnZS5zaGFwZVsyXT09PSAxLFxuICAgICAgICAoKSA9PiAnRXJyb3IgaW4gdGhyZXNob2xkOiAnICtcbiAgICAgICAgICAgICdpbWFnZSBjb2xvciBjaGFubmVsIG11c3QgYmUgZXF1YWwgdG8gMyBvciAxJyArXG4gICAgICAgICAgICBgYnV0IGdvdCAkeyRpbWFnZS5zaGFwZVsyXX0uYCk7XG5cbiAgICB1dGlsLmFzc2VydChcbiAgICAgICRpbWFnZS5kdHlwZSA9PT0gJ2ludDMyJyB8fCAkaW1hZ2UuZHR5cGUgPT09ICdmbG9hdDMyJyxcbiAgICAgICgpID0+ICdFcnJvciBpbiBkdHlwZTogaW1hZ2UgZHR5cGUgbXVzdCBiZSBpbnQzMiBvciBmbG9hdDMyLCcgK1xuICAgICAgICAgIGBidXQgZ290IGR0eXBlICR7JGltYWdlLmR0eXBlfS5gKTtcblxuICAgIHV0aWwuYXNzZXJ0KFxuICAgICAgbWV0aG9kID09PSAnb3RzdScgfHwgbWV0aG9kID09PSAnYmluYXJ5JyxcbiAgICAgICgpID0+IGBNZXRob2QgbXVzdCBiZSBiaW5hcnkgb3Igb3RzdSwgYnV0IHdhcyAke21ldGhvZH1gKTtcblxuICAgIGlmICgkaW1hZ2Uuc2hhcGVbMl0gPT09IDMpIHtcbiAgICAgICAgW3IsIGcsIGJdID0gc3BsaXQoJGltYWdlLCBbMSwgMSwgMV0sIC0xKTtcbiAgICAgICAgY29uc3QgJHIgPSBtdWwocixSRURfSU5URU5DSVRZX0NPRUYpO1xuICAgICAgICBjb25zdCAkZyA9IG11bChnLEdSRUVOX0lOVEVOQ0lUWV9DT0VGKTtcbiAgICAgICAgY29uc3QgJGIgPSBtdWwoYixCTFVFX0lOVEVOQ0lUWV9DT0VGKTtcbiAgICAgICAgZ3JheXNjYWxlID0gYWRkKGFkZCgkciwgJGcpLCAkYik7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgZ3JheXNjYWxlID0gaW1hZ2U7XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gJ290c3UnKSB7XG4gICAgICAgIGNvbnN0ICRoaXN0b2dyYW0gPSBiaW5jb3VudChjYXN0KHJvdW5kKGdyYXlzY2FsZSksICdpbnQzMicpIGFzIFRlbnNvcjFELFxuICAgICAgICAgICAgdGVuc29yKFtdKSxcbiAgICAgICAgICAgIDI1Nik7XG4gICAgICAgICR0aHJlc2hvbGQgPSBvdHN1KCRoaXN0b2dyYW0sIHRvdGFsUGl4ZWxzSW5JbWFnZSk7XG4gICAgfVxuXG4gICAgY29uc3QgaW52Q29uZGl0aW9uID0gaW52ZXJ0ZWQgP1xuICAgICAgICBsZXNzRXF1YWwoZ3JheXNjYWxlLCAkdGhyZXNob2xkKSA6IGdyZWF0ZXIoZ3JheXNjYWxlLCAkdGhyZXNob2xkKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGNhc3QobXVsKGludkNvbmRpdGlvbiwyNTUpLCAnaW50MzInKTtcblxuICAgIHJldHVybiByZXN1bHQgYXMgVGVuc29yM0Q7XG59XG5cbmZ1bmN0aW9uIG90c3UoaGlzdG9ncmFtOiBUZW5zb3IxRCwgdG90YWw6IG51bWJlcik6VGVuc29yMUQge1xuXG4gICAgbGV0IGJlc3RUaHJlc2ggPSB0ZW5zb3IxZChbLTFdKTtcbiAgICBsZXQgYmVzdEluQmV0VmFyID0gdGVuc29yMWQoWzBdKTtcbiAgICBsZXQgY0luQmV0VmFyID0gdGVuc29yMWQoWzBdKTtcbiAgICBsZXQgY2xhc3NGaXJzdCwgY2xhc3NTZWNvbmQsIG1lYW5GaXJzdCxcbiAgICAgICAgbWVhblNlYywgd2VpZ2h0Rm9yZWdyb3VuZCwgd2VpZ2h0QmFjaztcblxuICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCBoaXN0b2dyYW0uc2l6ZS0xOyBpbmRleCsrKSB7XG5cbiAgICAgICAgY2xhc3NGaXJzdCA9IHNsaWNlKGhpc3RvZ3JhbSwgMCwgaW5kZXggKyAxKTtcblxuICAgICAgICBjbGFzc1NlY29uZCA9IHNsaWNlKGhpc3RvZ3JhbSxpbmRleCArIDEpO1xuXG4gICAgICAgIHdlaWdodEZvcmVncm91bmQgPSBkaXYoc3VtKGNsYXNzRmlyc3QpLHRvdGFsKTtcblxuICAgICAgICB3ZWlnaHRCYWNrID0gZGl2KHN1bShjbGFzc1NlY29uZCksdG90YWwpO1xuXG4gICAgICAgIGNvbnN0IG1lYW5GaXJzdERpdkEgPSBzdW0obXVsKGNsYXNzRmlyc3QsIHJhbmdlKDAsIGNsYXNzRmlyc3Quc2l6ZSkpKTtcblxuICAgICAgICBtZWFuRmlyc3QgPSBkaXYobWVhbkZpcnN0RGl2QSwgc3VtKGNsYXNzRmlyc3QpICk7XG5cbiAgICAgICAgY29uc3QgbWVhblNlY0ZpbGwgPSBmaWxsKGNsYXNzU2Vjb25kLnNoYXBlLCBjbGFzc0ZpcnN0LnNpemUpO1xuICAgICAgICBjb25zdCBtZWFuU2VjQWRkID0gYWRkKHJhbmdlKDAsY2xhc3NTZWNvbmQuc2l6ZSksbWVhblNlY0ZpbGwpO1xuICAgICAgICBjb25zdCBtZWFuU2VjTXVsID0gbXVsKGNsYXNzU2Vjb25kLCAobWVhblNlY0FkZCkpO1xuICAgICAgICBtZWFuU2VjID0gZGl2KHN1bShtZWFuU2VjTXVsKSwgc3VtKGNsYXNzU2Vjb25kKSk7XG5cbiAgICAgICAgY29uc3QgY0luQmV0VmFyU3ViQSA9IHN1YihtZWFuRmlyc3QsIG1lYW5TZWMpO1xuICAgICAgICBjb25zdCBjSW5CZXRWYXJTdWJCID0gc3ViKG1lYW5GaXJzdCwgbWVhblNlYyk7XG4gICAgICAgIGNvbnN0IGNJbkJldFZhck11bCA9IG11bCh3ZWlnaHRGb3JlZ3JvdW5kLCB3ZWlnaHRCYWNrKTtcbiAgICAgICAgY0luQmV0VmFyID0gbXVsKG11bChjSW5CZXRWYXJNdWwsY0luQmV0VmFyU3ViQSksIGNJbkJldFZhclN1YkIpO1xuXG4gICAgICAgIGNvbnN0IGNvbmRpdGlvbiA9IGdyZWF0ZXIoY0luQmV0VmFyLCBiZXN0SW5CZXRWYXIpO1xuXG4gICAgICAgIGJlc3RJbkJldFZhciA9IHdoZXJlKGNvbmRpdGlvbiwgY0luQmV0VmFyLCBiZXN0SW5CZXRWYXIpO1xuXG4gICAgICAgIGJlc3RUaHJlc2ggPSB3aGVyZShjb25kaXRpb24sIHRlbnNvcjFkKFtpbmRleF0pLCBiZXN0VGhyZXNoKTtcblxuICAgIH1cbiAgICByZXR1cm4gYmVzdFRocmVzaDtcbn1cblxuZXhwb3J0IGNvbnN0IHRocmVzaG9sZCA9IC8qIEBfX1BVUkVfXyAqLyBvcCh7IHRocmVzaG9sZF8gfSk7XG4iXX0=