tink-crypto
Version:
A multi-language, cross-platform library that provides cryptographic APIs that are secure, easy to use correctly, and hard(er) to misuse.
185 lines • 18.7 kB
JavaScript
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { InvalidArgumentsException } from '../exception/invalid_arguments_exception';
/**
* Does near constant time byte array comparison.
* @param ba1 The first bytearray to check.
* @param ba2 The second bytearray to check.
* @return If the array are equal.
*/
export function isEqual(ba1, ba2) {
if (ba1.length !== ba2.length) {
return false;
}
let result = 0;
for (let i = 0; i < ba1.length; i++) {
result |= ba1[i] ^ ba2[i];
}
return result == 0;
}
/**
* Returns a new array that is the result of joining the arguments.
*/
export function concat(...var_args) {
let length = 0;
for (let i = 0; i < arguments.length; i++) {
length += arguments[i].length;
}
const result = new Uint8Array(length);
let curOffset = 0;
for (let i = 0; i < arguments.length; i++) {
result.set(arguments[i], curOffset);
curOffset += arguments[i].length;
}
return result;
}
/**
* Converts a non-negative integer number to a 64-bit big-endian byte array.
* @param value The number to convert.
* @return The number as a big-endian byte array.
* @throws {InvalidArgumentsException}
* @static
*/
export function fromNumber(value) {
if (Number.isNaN(value) || value % 1 !== 0) {
throw new InvalidArgumentsException('cannot convert non-integer value');
}
if (value < 0) {
throw new InvalidArgumentsException('cannot convert negative number');
}
if (value > Number.MAX_SAFE_INTEGER) {
throw new InvalidArgumentsException('cannot convert number larger than ' + Number.MAX_SAFE_INTEGER);
}
const twoPower32 = Math.pow(2, 32);
let low = value % twoPower32;
let high = value / twoPower32;
const result = new Uint8Array(8);
for (let i = 7; i >= 4; i--) {
result[i] = low & 255;
low >>>= 8;
}
for (let i = 3; i >= 0; i--) {
result[i] = high & 255;
high >>>= 8;
}
return result;
}
/**
* Converts the hex string to a byte array.
*
* @param hex the input
* @return the byte array output
* @throws {!InvalidArgumentsException}
* @static
*/
export function fromHex(hex) {
if (hex.length % 2 != 0) {
throw new InvalidArgumentsException('Hex string length must be multiple of 2');
}
const arr = new Uint8Array(hex.length / 2);
for (let i = 0; i < hex.length; i += 2) {
arr[i / 2] = parseInt(hex.substring(i, i + 2), 16);
}
return arr;
}
/**
* Converts a byte array to hex.
*
* @param bytes the byte array input
* @return hex the output
* @static
*/
export function toHex(bytes) {
let result = '';
for (let i = 0; i < bytes.length; i++) {
const hexByte = bytes[i].toString(16);
result += hexByte.length > 1 ? hexByte : '0' + hexByte;
}
return result;
}
/**
* Converts the Base64 string to a byte array.
*
* @param encoded the base64 string
* @param opt_webSafe True indicates we should use the alternative
* alphabet, which does not require escaping for use in URLs.
* @return the byte array output
* @static
*/
export function fromBase64(encoded, opt_webSafe) {
if (opt_webSafe) {
const normalBase64 = encoded.replace(/-/g, '+').replace(/_/g, '/');
return fromByteString(window.atob(normalBase64));
}
return fromByteString(window.atob(encoded));
}
/**
* Base64 encode a byte array.
*
* @param bytes the byte array input
* @param opt_webSafe True indicates we should use the alternative
* alphabet, which does not require escaping for use in URLs.
* @return base64 output
* @static
*/
export function toBase64(bytes, opt_webSafe) {
const encoded = window
.btoa(
/* padding */
toByteString(bytes))
.replace(/=/g, '');
if (opt_webSafe) {
return encoded.replace(/\+/g, '-').replace(/\//g, '_');
}
return encoded;
}
/**
* Converts a byte string to a byte array. Only support ASCII and Latin-1
* strings, does not support multi-byte characters.
*
* @param str the input
* @return the byte array output
* @static
*/
export function fromByteString(str) {
const output = [];
let p = 0;
for (let i = 0; i < str.length; i++) {
const c = str.charCodeAt(i);
output[p++] = c;
}
return new Uint8Array(output);
}
/**
* Turns a byte array into the string given by the concatenation of the
* characters to which the numbers correspond. Each byte is corresponding to a
* character. Does not support multi-byte characters.
*
* @param bytes Array of numbers representing
* characters.
* @return Stringification of the array.
*/
export function toByteString(bytes) {
let str = '';
for (let i = 0; i < bytes.length; i += 1) {
str += String.fromCharCode(bytes[i]);
}
return str;
}
/**
* Returns the element-wise XOR of two byte arrays of the same length
*/
export function xor(x, y) {
if (x.length !== y.length) {
throw new InvalidArgumentsException('Both byte arrays should be of the same length');
}
const arr = new Uint8Array(x.length);
for (let i = 0; i < arr.length; i++) {
arr[i] = x[i] ^ y[i];
}
return arr;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnl0ZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zdWJ0bGUvYnl0ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUVILE9BQU8sRUFBQyx5QkFBeUIsRUFBQyxNQUFNLDBDQUEwQyxDQUFDO0FBRW5GOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLE9BQU8sQ0FBQyxHQUFlLEVBQUUsR0FBZTtJQUN0RCxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssR0FBRyxDQUFDLE1BQU0sRUFBRTtRQUM3QixPQUFPLEtBQUssQ0FBQztLQUNkO0lBQ0QsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ2YsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDbkMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDM0I7SUFDRCxPQUFPLE1BQU0sSUFBSSxDQUFDLENBQUM7QUFDckIsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLE1BQU0sQ0FBQyxHQUFHLFFBQXNCO0lBQzlDLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQztJQUNmLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3pDLE1BQU0sSUFBSSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0tBQy9CO0lBQ0QsTUFBTSxNQUFNLEdBQUcsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDdEMsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0lBQ2xCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3pDLE1BQU0sQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQ3BDLFNBQVMsSUFBSSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0tBQ2xDO0lBQ0QsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILE1BQU0sVUFBVSxVQUFVLENBQUMsS0FBYTtJQUN0QyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUU7UUFDMUMsTUFBTSxJQUFJLHlCQUF5QixDQUFDLGtDQUFrQyxDQUFDLENBQUM7S0FDekU7SUFDRCxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUU7UUFDYixNQUFNLElBQUkseUJBQXlCLENBQUMsZ0NBQWdDLENBQUMsQ0FBQztLQUN2RTtJQUNELElBQUksS0FBSyxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRTtRQUNuQyxNQUFNLElBQUkseUJBQXlCLENBQy9CLG9DQUFvQyxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0tBQ3JFO0lBQ0QsTUFBTSxVQUFVLEdBQUcsU0FBQSxDQUFDLEVBQUksRUFBRSxDQUFBLENBQUM7SUFDM0IsSUFBSSxHQUFHLEdBQUcsS0FBSyxHQUFHLFVBQVUsQ0FBQztJQUM3QixJQUFJLElBQUksR0FBRyxLQUFLLEdBQUcsVUFBVSxDQUFDO0lBQzlCLE1BQU0sTUFBTSxHQUFHLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2pDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDM0IsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7UUFDdEIsR0FBRyxNQUFNLENBQUMsQ0FBQztLQUNaO0lBQ0QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUMzQixNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxHQUFHLEdBQUcsQ0FBQztRQUN2QixJQUFJLE1BQU0sQ0FBQyxDQUFDO0tBQ2I7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxPQUFPLENBQUMsR0FBVztJQUNqQyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRTtRQUN2QixNQUFNLElBQUkseUJBQXlCLENBQy9CLHlDQUF5QyxDQUFDLENBQUM7S0FDaEQ7SUFDRCxNQUFNLEdBQUcsR0FBRyxJQUFJLFVBQVUsQ0FBQyxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzNDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUU7UUFDdEMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0tBQ3BEO0lBQ0QsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLEtBQUssQ0FBQyxLQUFpQjtJQUNyQyxJQUFJLE1BQU0sR0FBRyxFQUFFLENBQUM7SUFDaEIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDckMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN0QyxNQUFNLElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLE9BQU8sQ0FBQztLQUN4RDtJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxVQUFVLENBQUMsT0FBZSxFQUFFLFdBQXFCO0lBQy9ELElBQUksV0FBVyxFQUFFO1FBQ2YsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNuRSxPQUFPLGNBQWMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUM7S0FDbEQ7SUFDRCxPQUFPLGNBQWMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7QUFDOUMsQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxVQUFVLFFBQVEsQ0FBQyxLQUFpQixFQUFFLFdBQXFCO0lBQy9ELE1BQU0sT0FBTyxHQUFHLE1BQU07U0FDRCxJQUFJO0lBQ0QsYUFBYTtJQUNiLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUN2QixPQUFPLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZDLElBQUksV0FBVyxFQUFFO1FBQ2YsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0tBQ3hEO0lBQ0QsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUFDLEdBQVc7SUFDeEMsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDO0lBQ2xCLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNWLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ25DLE1BQU0sQ0FBQyxHQUFHLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDNUIsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0tBQ2pCO0lBQ0QsT0FBTyxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUNoQyxDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLFVBQVUsWUFBWSxDQUFDLEtBQWlCO0lBQzVDLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQztJQUNiLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUU7UUFDeEMsR0FBRyxJQUFJLE1BQU0sQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDdEM7SUFDRCxPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBYSxFQUFFLENBQWE7SUFDOUMsSUFBSSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUU7UUFDekIsTUFBTSxJQUFJLHlCQUF5QixDQUMvQiwrQ0FBK0MsQ0FBQyxDQUFDO0tBQ3REO0lBRUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRXJDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ25DLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQ3RCO0lBRUQsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMjAgR29vZ2xlIExMQ1xuICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcbiAqL1xuXG5pbXBvcnQge0ludmFsaWRBcmd1bWVudHNFeGNlcHRpb259IGZyb20gJy4uL2V4Y2VwdGlvbi9pbnZhbGlkX2FyZ3VtZW50c19leGNlcHRpb24nO1xuXG4vKipcbiAqIERvZXMgbmVhciBjb25zdGFudCB0aW1lIGJ5dGUgYXJyYXkgY29tcGFyaXNvbi5cbiAqIEBwYXJhbSBiYTEgVGhlIGZpcnN0IGJ5dGVhcnJheSB0byBjaGVjay5cbiAqIEBwYXJhbSBiYTIgVGhlIHNlY29uZCBieXRlYXJyYXkgdG8gY2hlY2suXG4gKiBAcmV0dXJuIElmIHRoZSBhcnJheSBhcmUgZXF1YWwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0VxdWFsKGJhMTogVWludDhBcnJheSwgYmEyOiBVaW50OEFycmF5KTogYm9vbGVhbiB7XG4gIGlmIChiYTEubGVuZ3RoICE9PSBiYTIubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGxldCByZXN1bHQgPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGJhMS5sZW5ndGg7IGkrKykge1xuICAgIHJlc3VsdCB8PSBiYTFbaV0gXiBiYTJbaV07XG4gIH1cbiAgcmV0dXJuIHJlc3VsdCA9PSAwO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBuZXcgYXJyYXkgdGhhdCBpcyB0aGUgcmVzdWx0IG9mIGpvaW5pbmcgdGhlIGFyZ3VtZW50cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbmNhdCguLi52YXJfYXJnczogVWludDhBcnJheVtdKTogVWludDhBcnJheSB7XG4gIGxldCBsZW5ndGggPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgIGxlbmd0aCArPSBhcmd1bWVudHNbaV0ubGVuZ3RoO1xuICB9XG4gIGNvbnN0IHJlc3VsdCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aCk7XG4gIGxldCBjdXJPZmZzZXQgPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgIHJlc3VsdC5zZXQoYXJndW1lbnRzW2ldLCBjdXJPZmZzZXQpO1xuICAgIGN1ck9mZnNldCArPSBhcmd1bWVudHNbaV0ubGVuZ3RoO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogQ29udmVydHMgYSBub24tbmVnYXRpdmUgaW50ZWdlciBudW1iZXIgdG8gYSA2NC1iaXQgYmlnLWVuZGlhbiBieXRlIGFycmF5LlxuICogQHBhcmFtIHZhbHVlIFRoZSBudW1iZXIgdG8gY29udmVydC5cbiAqIEByZXR1cm4gVGhlIG51bWJlciBhcyBhIGJpZy1lbmRpYW4gYnl0ZSBhcnJheS5cbiAqIEB0aHJvd3Mge0ludmFsaWRBcmd1bWVudHNFeGNlcHRpb259XG4gKiBAc3RhdGljXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcm9tTnVtYmVyKHZhbHVlOiBudW1iZXIpOiBVaW50OEFycmF5IHtcbiAgaWYgKE51bWJlci5pc05hTih2YWx1ZSkgfHwgdmFsdWUgJSAxICE9PSAwKSB7XG4gICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudHNFeGNlcHRpb24oJ2Nhbm5vdCBjb252ZXJ0IG5vbi1pbnRlZ2VyIHZhbHVlJyk7XG4gIH1cbiAgaWYgKHZhbHVlIDwgMCkge1xuICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRzRXhjZXB0aW9uKCdjYW5ub3QgY29udmVydCBuZWdhdGl2ZSBudW1iZXInKTtcbiAgfVxuICBpZiAodmFsdWUgPiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUikge1xuICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRzRXhjZXB0aW9uKFxuICAgICAgICAnY2Fubm90IGNvbnZlcnQgbnVtYmVyIGxhcmdlciB0aGFuICcgKyBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUik7XG4gIH1cbiAgY29uc3QgdHdvUG93ZXIzMiA9IDIgKiogMzI7XG4gIGxldCBsb3cgPSB2YWx1ZSAlIHR3b1Bvd2VyMzI7XG4gIGxldCBoaWdoID0gdmFsdWUgLyB0d29Qb3dlcjMyO1xuICBjb25zdCByZXN1bHQgPSBuZXcgVWludDhBcnJheSg4KTtcbiAgZm9yIChsZXQgaSA9IDc7IGkgPj0gNDsgaS0tKSB7XG4gICAgcmVzdWx0W2ldID0gbG93ICYgMjU1O1xuICAgIGxvdyA+Pj49IDg7XG4gIH1cbiAgZm9yIChsZXQgaSA9IDM7IGkgPj0gMDsgaS0tKSB7XG4gICAgcmVzdWx0W2ldID0gaGlnaCAmIDI1NTtcbiAgICBoaWdoID4+Pj0gODtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIENvbnZlcnRzIHRoZSBoZXggc3RyaW5nIHRvIGEgYnl0ZSBhcnJheS5cbiAqXG4gKiBAcGFyYW0gaGV4IHRoZSBpbnB1dFxuICogQHJldHVybiB0aGUgYnl0ZSBhcnJheSBvdXRwdXRcbiAqIEB0aHJvd3MgeyFJbnZhbGlkQXJndW1lbnRzRXhjZXB0aW9ufVxuICogQHN0YXRpY1xuICovXG5leHBvcnQgZnVuY3Rpb24gZnJvbUhleChoZXg6IHN0cmluZyk6IFVpbnQ4QXJyYXkge1xuICBpZiAoaGV4Lmxlbmd0aCAlIDIgIT0gMCkge1xuICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRzRXhjZXB0aW9uKFxuICAgICAgICAnSGV4IHN0cmluZyBsZW5ndGggbXVzdCBiZSBtdWx0aXBsZSBvZiAyJyk7XG4gIH1cbiAgY29uc3QgYXJyID0gbmV3IFVpbnQ4QXJyYXkoaGV4Lmxlbmd0aCAvIDIpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGhleC5sZW5ndGg7IGkgKz0gMikge1xuICAgIGFycltpIC8gMl0gPSBwYXJzZUludChoZXguc3Vic3RyaW5nKGksIGkgKyAyKSwgMTYpO1xuICB9XG4gIHJldHVybiBhcnI7XG59XG5cbi8qKlxuICogQ29udmVydHMgYSBieXRlIGFycmF5IHRvIGhleC5cbiAqXG4gKiBAcGFyYW0gYnl0ZXMgdGhlIGJ5dGUgYXJyYXkgaW5wdXRcbiAqIEByZXR1cm4gaGV4IHRoZSBvdXRwdXRcbiAqIEBzdGF0aWNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvSGV4KGJ5dGVzOiBVaW50OEFycmF5KTogc3RyaW5nIHtcbiAgbGV0IHJlc3VsdCA9ICcnO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgaGV4Qnl0ZSA9IGJ5dGVzW2ldLnRvU3RyaW5nKDE2KTtcbiAgICByZXN1bHQgKz0gaGV4Qnl0ZS5sZW5ndGggPiAxID8gaGV4Qnl0ZSA6ICcwJyArIGhleEJ5dGU7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyB0aGUgQmFzZTY0IHN0cmluZyB0byBhIGJ5dGUgYXJyYXkuXG4gKlxuICogQHBhcmFtIGVuY29kZWQgdGhlIGJhc2U2NCBzdHJpbmdcbiAqIEBwYXJhbSBvcHRfd2ViU2FmZSBUcnVlIGluZGljYXRlcyB3ZSBzaG91bGQgdXNlIHRoZSBhbHRlcm5hdGl2ZVxuICogICAgIGFscGhhYmV0LCB3aGljaCBkb2VzIG5vdCByZXF1aXJlIGVzY2FwaW5nIGZvciB1c2UgaW4gVVJMcy5cbiAqIEByZXR1cm4gdGhlIGJ5dGUgYXJyYXkgb3V0cHV0XG4gKiBAc3RhdGljXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcm9tQmFzZTY0KGVuY29kZWQ6IHN0cmluZywgb3B0X3dlYlNhZmU/OiBib29sZWFuKTogVWludDhBcnJheSB7XG4gIGlmIChvcHRfd2ViU2FmZSkge1xuICAgIGNvbnN0IG5vcm1hbEJhc2U2NCA9IGVuY29kZWQucmVwbGFjZSgvLS9nLCAnKycpLnJlcGxhY2UoL18vZywgJy8nKTtcbiAgICByZXR1cm4gZnJvbUJ5dGVTdHJpbmcod2luZG93LmF0b2Iobm9ybWFsQmFzZTY0KSk7XG4gIH1cbiAgcmV0dXJuIGZyb21CeXRlU3RyaW5nKHdpbmRvdy5hdG9iKGVuY29kZWQpKTtcbn1cblxuLyoqXG4gKiBCYXNlNjQgZW5jb2RlIGEgYnl0ZSBhcnJheS5cbiAqXG4gKiBAcGFyYW0gYnl0ZXMgdGhlIGJ5dGUgYXJyYXkgaW5wdXRcbiAqIEBwYXJhbSBvcHRfd2ViU2FmZSBUcnVlIGluZGljYXRlcyB3ZSBzaG91bGQgdXNlIHRoZSBhbHRlcm5hdGl2ZVxuICogICAgIGFscGhhYmV0LCB3aGljaCBkb2VzIG5vdCByZXF1aXJlIGVzY2FwaW5nIGZvciB1c2UgaW4gVVJMcy5cbiAqIEByZXR1cm4gYmFzZTY0IG91dHB1dFxuICogQHN0YXRpY1xuICovXG5leHBvcnQgZnVuY3Rpb24gdG9CYXNlNjQoYnl0ZXM6IFVpbnQ4QXJyYXksIG9wdF93ZWJTYWZlPzogYm9vbGVhbik6IHN0cmluZyB7XG4gIGNvbnN0IGVuY29kZWQgPSB3aW5kb3dcbiAgICAgICAgICAgICAgICAgICAgICAuYnRvYShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLyogcGFkZGluZyAqL1xuICAgICAgICAgICAgICAgICAgICAgICAgICB0b0J5dGVTdHJpbmcoYnl0ZXMpKVxuICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKC89L2csICcnKTtcbiAgaWYgKG9wdF93ZWJTYWZlKSB7XG4gICAgcmV0dXJuIGVuY29kZWQucmVwbGFjZSgvXFwrL2csICctJykucmVwbGFjZSgvXFwvL2csICdfJyk7XG4gIH1cbiAgcmV0dXJuIGVuY29kZWQ7XG59XG5cbi8qKlxuICogQ29udmVydHMgYSBieXRlIHN0cmluZyB0byBhIGJ5dGUgYXJyYXkuIE9ubHkgc3VwcG9ydCBBU0NJSSBhbmQgTGF0aW4tMVxuICogc3RyaW5ncywgZG9lcyBub3Qgc3VwcG9ydCBtdWx0aS1ieXRlIGNoYXJhY3RlcnMuXG4gKlxuICogQHBhcmFtIHN0ciB0aGUgaW5wdXRcbiAqIEByZXR1cm4gdGhlIGJ5dGUgYXJyYXkgb3V0cHV0XG4gKiBAc3RhdGljXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcm9tQnl0ZVN0cmluZyhzdHI6IHN0cmluZyk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBvdXRwdXQgPSBbXTtcbiAgbGV0IHAgPSAwO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IGMgPSBzdHIuY2hhckNvZGVBdChpKTtcbiAgICBvdXRwdXRbcCsrXSA9IGM7XG4gIH1cbiAgcmV0dXJuIG5ldyBVaW50OEFycmF5KG91dHB1dCk7XG59XG5cbi8qKlxuICogVHVybnMgYSBieXRlIGFycmF5IGludG8gdGhlIHN0cmluZyBnaXZlbiBieSB0aGUgY29uY2F0ZW5hdGlvbiBvZiB0aGVcbiAqIGNoYXJhY3RlcnMgdG8gd2hpY2ggdGhlIG51bWJlcnMgY29ycmVzcG9uZC4gRWFjaCBieXRlIGlzIGNvcnJlc3BvbmRpbmcgdG8gYVxuICogY2hhcmFjdGVyLiBEb2VzIG5vdCBzdXBwb3J0IG11bHRpLWJ5dGUgY2hhcmFjdGVycy5cbiAqXG4gKiBAcGFyYW0gYnl0ZXMgQXJyYXkgb2YgbnVtYmVycyByZXByZXNlbnRpbmdcbiAqICAgICBjaGFyYWN0ZXJzLlxuICogQHJldHVybiBTdHJpbmdpZmljYXRpb24gb2YgdGhlIGFycmF5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9CeXRlU3RyaW5nKGJ5dGVzOiBVaW50OEFycmF5KTogc3RyaW5nIHtcbiAgbGV0IHN0ciA9ICcnO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgc3RyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZXNbaV0pO1xuICB9XG4gIHJldHVybiBzdHI7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgZWxlbWVudC13aXNlIFhPUiBvZiB0d28gYnl0ZSBhcnJheXMgb2YgdGhlIHNhbWUgbGVuZ3RoXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB4b3IoeDogVWludDhBcnJheSwgeTogVWludDhBcnJheSk6IFVpbnQ4QXJyYXkge1xuICBpZiAoeC5sZW5ndGggIT09IHkubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudHNFeGNlcHRpb24oXG4gICAgICAgICdCb3RoIGJ5dGUgYXJyYXlzIHNob3VsZCBiZSBvZiB0aGUgc2FtZSBsZW5ndGgnKTtcbiAgfVxuXG4gIGNvbnN0IGFyciA9IG5ldyBVaW50OEFycmF5KHgubGVuZ3RoKTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgIGFycltpXSA9IHhbaV0gXiB5W2ldO1xuICB9XG5cbiAgcmV0dXJuIGFycjtcbn1cbiJdfQ==