@tai-kun/surrealdb
Version:
The SurrealDB SDK for JavaScript
693 lines (692 loc) • 87.6 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// src/cbor/decoder.ts
import {
CborMaxDepthReachedError,
CborSyntaxError,
CborTooLittleDataError,
CborUnsafeMapKeyError,
SurrealValueError,
unreachable
} from "../errors/index.mjs";
import { utf8 } from "../utils/index.mjs";
import { getFloat16 } from "./_float.mjs";
import { ianaReviver } from "./_iana.mjs";
import {
AI_EIGHT_BYTES,
AI_FOUR_BYTES,
AI_INDEFINITE_NUM_BYTES,
AI_ONE_BYTE,
AI_SIMPLE_FALSE,
AI_SIMPLE_NULL,
AI_SIMPLE_TRUE,
AI_SIMPLE_UNDEFINED,
AI_TWO_BYTES,
BREAK,
JS_MAX_SAFE_UNSIGNED_BIG_INTEGER,
MT_ARRAY,
MT_BYTE_STRING,
MT_MAP,
MT_NEGATIVE_INTEGER,
MT_SIMPLE_FLOAT,
MT_TAG,
MT_UNSIGNED_INTEGER,
MT_UTF8_STRING,
Simple
} from "./spec.mjs";
import Tagged from "./tagged.mjs";
var PARENT_ROOT = 0;
var PARENT_STR = 1;
var PARENT_ARR = 2;
var PARENT_OBJ = 3;
var PARENT_MAP = 4;
var PARENT_TAG = 5;
var FRAGMENT_STR = 0;
var HUMANIZED_DATA_ITEM = {
[MT_UNSIGNED_INTEGER]: "unsigned integer",
[MT_NEGATIVE_INTEGER]: "negative integer",
[MT_BYTE_STRING]: "byte string",
[MT_UTF8_STRING]: "utf8 string",
[MT_ARRAY]: "array",
[MT_MAP]: "map",
[MT_TAG]: "tagged item",
[MT_SIMPLE_FLOAT]: "simple/float"
};
var NONE = Symbol.for("@tai-kun/surrealdb/cbor/none");
var CONTINUE = Symbol.for("@tai-kun/surrealdb/cbor/continue");
var __Decoder = class __Decoder {
constructor(options = {}) {
const {
mapType = "Object",
reviver,
maxDepth = 64,
isSafeMapKey = /* @__PURE__ */ __name((k) => k !== "__proto__" && k !== "constructor", "isSafeMapKey"),
isSafeObjectKey = /* @__PURE__ */ __name((k) => k !== "__proto__" && k !== "constructor", "isSafeObjectKey")
} = options;
this.mapType = mapType;
this.maxDepth = maxDepth;
this.revivers = toRevivers(reviver);
this.revivers.tagged.push(compatReviver, ianaReviver);
this.isSafeMapKey = isSafeMapKey;
this.isSafeObjectKey = isSafeObjectKey;
this.depth = 0;
this.parents = [
this.parent = {
$: PARENT_ROOT,
put(val) {
if (val === BREAK) {
throw new CborSyntaxError(
`The "break" stop code was encountered outside of a indefinite-length data item.`
);
}
this.val = val;
return false;
},
out() {
return this.val;
},
val: void 0
}
];
this.fragment = null;
}
putValue(value) {
let done = false;
while (done = this.parent.put(value)) {
this.end();
value = this.parents.pop().out();
this.parent = this.parents[this.parents.length - 1];
}
}
begin(parent) {
if (parent.$ !== PARENT_STR && ++this.depth >= this.maxDepth) {
throw new CborMaxDepthReachedError(this.maxDepth);
}
this.parents.push(this.parent = parent);
}
end() {
if (this.parent.$ !== PARENT_STR) {
this.depth -= 1;
}
}
process(input) {
let offset = 0;
const fragment = this.fragment;
if (fragment !== null) {
switch (fragment.$) {
case FRAGMENT_STR: {
const remaining = fragment.size - fragment.offset;
const chunk = input.subarray(offset, offset += remaining);
fragment.data.set(chunk, fragment.offset);
if (chunk.length < remaining) {
fragment.offset += chunk.length;
return;
}
let value = fragment.data;
if (fragment.mt === MT_UTF8_STRING) {
value = utf8.decode(value);
}
this.putValue(value);
this.fragment = null;
break;
}
default:
unreachable(fragment);
}
}
const view = new DataView(input.buffer, input.byteOffset, input.byteLength);
const viewLength = view.byteLength;
while (offset < viewLength) {
const ib = view.getUint8(offset++);
let mt = ib >> 5;
let ai = ib & 31;
let value;
let isSimple = false;
let payloadLength = 0;
switch (ai) {
// # Short Data Item (24 <= ai <= 27)
// +--------------+--------------------------------+---------------------------+-------------------------------------+
// | Byte count | 1 byte (CBOR data item header) | 1, 2, 4 or 8 Bytes | 0 ~ 2^64-1 Bytes |
// +--------------+------------+-------------------+---------------------------+-------------------------------------+
// | Structure | Major type | Additional info | Additional info (Content) | Payload |
// +--------------+------------+-------------------+---------------------------+----------+--------------------------+
// | Bit count | 3 Bits | 5 Bits | 8, 16, 32 or 64 Bits | 8 Bits | ... |
// +--------------+------------+-------------------+---------------------------+----------+--------------------------+
// | Unsigned Int | 0 | 24, 25, 26, 27 | 0 ~ 2^64-1 (Value) | N/A |
// +--------------+------------+-------------------+---------------------------+-------------------------------------+
// | Negative Int | 1 | 24, 25, 26, 27 | 0 ~ 2^64-1 | N/A |
// +--------------+------------+-------------------+---------------------------+----------+---------+----------------+
// | Bytes / Text | 2, 3 | 24, 25, 26, 27 | count := 0 ~ 2^64-1 | bytes[0] | ... | bytes[<count>] |
// +--------------+------------+-------------------+---------------------------+----------+---------+----------------+
// | Array / Map | 4, 5 | 24, 25, 26, 27 | 0 ~ 2^64-1 [items] | N/A (Subsequent data items / pairs) |
// +--------------+------------+-------------------+---------------------------+-------------------------------------+
// | Tag | 6 | 24, 25, 26, 27 | 0 ~ 2^64-1 (Value) | N/A (A subsequent data item) |
// +--------------+------------+-------------------+---------------------------+-------------------------------------+
// | Float | 7 | 25, 26, 27 | (IEEE 754 Float) | N/A |
// +--------------+------------+-------------------+---------------------------+-------------------------------------+
case AI_ONE_BYTE:
payloadLength = 1;
value = view.getUint8(offset);
if (mt === MT_SIMPLE_FLOAT) {
if (value < 32) {
throw new CborSyntaxError(
"2-byte sequence followed by a byte less than 0x20 is being issued after the header 0xf8."
);
}
isSimple = true;
}
break;
case AI_TWO_BYTES:
payloadLength = 2;
value = mt === MT_SIMPLE_FLOAT ? getFloat16(view, offset) : view.getUint16(offset);
break;
case AI_FOUR_BYTES:
payloadLength = 4;
value = mt === MT_SIMPLE_FLOAT ? view.getFloat32(offset) : view.getUint32(offset);
break;
case AI_EIGHT_BYTES:
payloadLength = 8;
if (mt === MT_SIMPLE_FLOAT) {
value = view.getFloat64(offset);
} else {
value = view.getBigUint64(offset);
if (mt === MT_NEGATIVE_INTEGER) {
if (value <= JS_MAX_SAFE_UNSIGNED_BIG_INTEGER - 1n) {
value = Number(value);
}
} else if (value <= JS_MAX_SAFE_UNSIGNED_BIG_INTEGER) {
value = Number(value);
}
}
break;
// # Long Data Item (ai == 31)
// +--------------+--------------------------------+--------------------------------------+
// | Byte count | 1 byte (CBOR data item header) | 0 ~ ? Bytes |
// +--------------+------------+-------------------+--------------------------------------+
// | Structure | Major type | Additional info | Payload |
// +--------------+------------+-------------------+----------+---------------------------+
// | Bit count | 3 Bits | 5 Bits | 8 Bits | ... |
// +--------------+------------+-------------------+----------+-----+---------------------+
// | Bytes / Text | 2, 3 | 31 | bytes[0] | ... | Break (Non-payload) |
// +--------------+------------+-------------------+----------+-----+---------------------+
// | Array / Map | 4, 5 | 31 | N/A (Subsequent data items / pairs) |
// +--------------+------------+-------------------+--------------------------------------+
// | Break | 7 | 31 | N/A |
// +--------------+------------+-------------------+--------------------------------------+
case AI_INDEFINITE_NUM_BYTES:
switch (mt) {
case MT_UNSIGNED_INTEGER:
case MT_NEGATIVE_INTEGER:
case MT_TAG:
throw new CborSyntaxError(
`The data item \`${HUMANIZED_DATA_ITEM[mt]}\` has indefinite-length bytes.`
);
case MT_SIMPLE_FLOAT:
if ((this.parent.$ === PARENT_ARR || this.parent.$ === PARENT_OBJ || this.parent.$ === PARENT_MAP) && this.parent.len !== Infinity) {
throw new CborSyntaxError(
`The definite-length data item \`${HUMANIZED_DATA_ITEM[mt]}\`contains the "break" stop code.`
);
}
value = BREAK;
break;
case MT_BYTE_STRING:
case MT_UTF8_STRING:
if (this.parent.$ === PARENT_STR && mt === this.parent.mt) {
throw new CborSyntaxError(
"The payload of the indefinite-length data item `" + HUMANIZED_DATA_ITEM[mt] + "` contains the same type."
);
}
value = Infinity;
break;
// case MT_ARRAY:
// case MT_MAP:
default:
value = Infinity;
}
break;
// # Invalid Data Item (28 <= ai <= 30)
// +--------------+--------------------------------+
// | Byte count | 1 byte (CBOR data item header) |
// +--------------+------------+-------------------+
// | Structure | Major type | Additional info |
// +--------------+------------+-------------------+
// | Bit count | 3 Bits | 5 Bits |
// +--------------+------------+-------------------+
// | N/A | 0 ~ 7 | 28 ~ 30 |
// +--------------+------------+-------------------+
case 28:
case 29:
case 30:
throw new CborSyntaxError(
`The additional info ${ai} is reserved for future additions to the CBOR format.`
);
// # Tiny Data Item (0 <= ai <= 23)
// +--------------+--------------------------------+-------------------------------------+
// | Byte count | 1 byte (CBOR data item header) | 0 ~ 23 Bytes |
// +--------------+------------+-------------------+-------------------------------------+
// | Structure | Major type | Additional info | Payload |
// +--------------+------------+-------------------+----------+--------------------------+
// | Bit count | 3 Bits | 5 Bits | 8 Bits | ... |
// +--------------+------------+-------------------+----------+--------------------------+
// | Unsigned Int | 0 | 0 ~ 23 (Value) | N/A |
// +--------------+------------+-------------------+-------------------------------------+
// | Negative Int | 1 | 0 ~ 23 | N/A |
// +--------------+------------+-------------------+----------+---------+----------------+
// | Bytes / Text | 2, 3 | count := 0 ~ 23 | bytes[0] | ... | bytes[<count>] |
// +--------------+------------+-------------------+----------+---------+----------------+
// | Array / Map | 4, 5 | 0 ~ 23 [items] | N/A (Subsequent data items / pairs) |
// +--------------+------------+-------------------+-------------------------------------+
// | Tag | 6 | 0 ~ 23 (Value) | N/A (A subsequent data item) |
// +--------------+------------+-------------------+-------------------------------------+
// | Simple | 7 | 0 ~ 19 (Value) | N/A |
// +--------------+------------+-------------------+-------------------------------------+
// | Boolean | 7 | 20, 21 | N/A |
// +--------------+------------+-------------------+-------------------------------------+
// | Nullable | 7 | 22, 23 | N/A |
// +--------------+------------+-------------------+-------------------------------------+
// 0 ~ 23
default:
value = ai;
isSimple = true;
}
offset += payloadLength;
switch (mt) {
case MT_UNSIGNED_INTEGER:
break;
case MT_NEGATIVE_INTEGER:
value = typeof value === "number" ? -1 - value : -1n - value;
break;
case MT_BYTE_STRING:
if (ai === AI_INDEFINITE_NUM_BYTES) {
this.begin({
$: PARENT_STR,
mt,
put(val) {
if (val === BREAK) {
return true;
}
if (val instanceof Uint8Array) {
this.acc.push(val);
this.size += val.length;
return false;
}
unreachable(val);
},
out() {
const data = new Uint8Array(this.size);
for (let offset2 = 0, chunk; chunk = this.acc.shift(); ) {
data.set(chunk, offset2);
offset2 += chunk.length;
}
return data;
},
size: 0,
acc: []
});
continue;
} else {
payloadLength = value;
value = input.subarray(offset, offset += payloadLength);
if (value.length < payloadLength) {
const data = new Uint8Array(payloadLength);
data.set(value);
this.fragment = {
$: FRAGMENT_STR,
mt,
data,
size: data.length,
offset: value.length
};
return;
}
}
break;
case MT_UTF8_STRING:
if (ai === AI_INDEFINITE_NUM_BYTES) {
this.begin({
$: PARENT_STR,
mt,
put(val) {
if (val === BREAK) {
return true;
}
if (typeof val === "string") {
this.acc += val;
return false;
}
unreachable(val);
},
out() {
return this.acc;
},
acc: ""
});
continue;
} else {
payloadLength = value;
value = input.subarray(offset, offset += payloadLength);
if (value.length < payloadLength) {
const data = new Uint8Array(payloadLength);
data.set(value);
this.fragment = {
$: FRAGMENT_STR,
mt,
data,
size: data.length,
offset: value.length
};
return;
}
value = utf8.decode(value);
}
break;
case MT_ARRAY:
if (ai === AI_INDEFINITE_NUM_BYTES) {
this.begin({
$: PARENT_ARR,
put(val) {
if (val === BREAK) {
return true;
}
this.acc.push(val);
return false;
},
out() {
return this.acc;
},
len: Infinity,
idx: NaN,
acc: []
});
continue;
} else if (value !== 0) {
this.begin({
$: PARENT_ARR,
put(val) {
this.acc.push(val);
return ++this.idx === this.len;
},
out() {
return this.acc;
},
len: value,
idx: 0,
acc: []
});
continue;
} else {
value = [];
}
break;
case MT_MAP:
if (this.mapType === "Object") {
if (ai === AI_INDEFINITE_NUM_BYTES) {
this.begin({
$: PARENT_OBJ,
put(val) {
if (val === BREAK) {
return true;
}
if (this.key === NONE) {
if (typeof val !== "string" && typeof val !== "number" || !this.v8n(val, this.acc)) {
throw new CborUnsafeMapKeyError(val);
}
this.key = val;
} else {
this.acc[this.key] = val;
this.key = NONE;
}
return false;
},
out() {
if (this.key === NONE) {
return this.acc;
}
throw new CborTooLittleDataError({
cause: {
key: this.key
}
});
},
v8n: this.isSafeObjectKey,
len: Infinity,
idx: Infinity,
key: NONE,
acc: {}
});
continue;
} else if (value !== 0) {
this.begin({
$: PARENT_OBJ,
put(val) {
if (this.key === NONE) {
if (typeof val !== "string" && typeof val !== "number" || !this.v8n(val, this.acc)) {
throw new CborUnsafeMapKeyError(val);
}
this.key = val;
} else {
this.acc[this.key] = val;
this.key = NONE;
this.idx += 1;
}
return this.idx === this.len;
},
out() {
if (this.key === NONE) {
return this.acc;
}
throw new CborTooLittleDataError({
cause: {
key: this.key
}
});
},
v8n: this.isSafeObjectKey,
len: value,
idx: 0,
key: NONE,
acc: {}
});
continue;
} else {
value = {};
}
} else if (this.mapType === "Map") {
if (ai === AI_INDEFINITE_NUM_BYTES) {
this.begin({
$: PARENT_MAP,
put(val) {
if (val === BREAK) {
return true;
}
if (this.key === NONE) {
if (!this.v8n(val, this.acc)) {
throw new CborUnsafeMapKeyError(val);
}
this.key = val;
} else {
this.acc.set(this.key, val);
this.key = NONE;
}
return false;
},
out() {
if (this.key === NONE) {
return this.acc;
}
throw new CborTooLittleDataError({
cause: {
key: this.key
}
});
},
v8n: this.isSafeMapKey,
len: Infinity,
idx: Infinity,
key: NONE,
acc: /* @__PURE__ */ new Map()
});
continue;
} else if (value !== 0) {
this.begin({
$: PARENT_MAP,
put(val) {
if (this.key === NONE) {
if (!this.v8n(val, this.acc)) {
throw new CborUnsafeMapKeyError(val);
}
this.key = val;
} else {
this.acc.set(this.key, val);
this.key = NONE;
this.idx += 1;
}
return this.idx === this.len;
},
out() {
if (this.key === NONE) {
return this.acc;
}
throw new CborTooLittleDataError({
cause: {
key: this.key
}
});
},
v8n: this.isSafeMapKey,
len: value,
idx: 0,
key: NONE,
acc: /* @__PURE__ */ new Map()
});
continue;
} else {
value = /* @__PURE__ */ new Map();
}
} else {
throw new SurrealValueError(
['"Object"', '"Object"'],
this.mapType
);
}
break;
case MT_TAG:
this.begin({
$: PARENT_TAG,
put(val) {
this.val = val;
return true;
},
out() {
return reviveValue(this.fns, new Tagged(this.tag, this.val));
},
fns: this.revivers.tagged,
tag: value,
val: void 0
});
continue;
case MT_SIMPLE_FLOAT:
if (isSimple) {
switch (value) {
case AI_SIMPLE_FALSE:
value = false;
break;
case AI_SIMPLE_TRUE:
value = true;
break;
case AI_SIMPLE_NULL:
value = null;
break;
case AI_SIMPLE_UNDEFINED:
value = void 0;
break;
default:
value = reviveValue(
this.revivers.simple,
new Simple(value)
);
}
}
break;
default:
unreachable(mt);
}
if (this.parent.$ === PARENT_STR && mt !== this.parent.mt && value !== BREAK) {
throw new CborSyntaxError(
"The payload of the data item `" + HUMANIZED_DATA_ITEM[this.parent.mt] + `\` contains a mismatched data item \`${HUMANIZED_DATA_ITEM[mt]}\`.`
);
}
this.putValue(value);
}
}
output() {
if (this.parent.$ !== PARENT_ROOT || this.fragment) {
throw new CborTooLittleDataError({
cause: {
parents: this.parents,
fragment: this.fragment
}
});
}
return this.parent.out();
}
};
__name(__Decoder, "_Decoder");
var _Decoder = __Decoder;
function reviveValue(revivers, value) {
for (let i = 0, len = revivers.length, ret; i < len; i++) {
if ((ret = revivers[i](value)) !== CONTINUE) {
return ret;
}
}
return value;
}
__name(reviveValue, "reviveValue");
function toRevivers(reviver) {
if (!reviver) {
return {
tagged: [],
simple: []
};
}
if (typeof reviver === "function") {
return {
tagged: [reviver],
simple: [reviver]
};
}
if (Array.isArray(reviver)) {
const tagged = [];
const simple = [];
for (const r of reviver) {
if (typeof r === "function") {
tagged.push(r);
simple.push(r);
} else {
r.tagged && tagged.push(r.tagged);
r.simple && simple.push(r.simple);
}
}
return {
tagged,
simple
};
}
return {
tagged: reviver.tagged ? [reviver.tagged] : [],
simple: reviver.simple ? [reviver.simple] : []
};
}
__name(toRevivers, "toRevivers");
function compatReviver(t) {
if (t.tag === 6 && t.value === null) {
return;
}
return CONTINUE;
}
__name(compatReviver, "compatReviver");
export {
CONTINUE,
_Decoder
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2Nib3IvZGVjb2Rlci50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiaW1wb3J0IHtcbiAgQ2Jvck1heERlcHRoUmVhY2hlZEVycm9yLFxuICBDYm9yU3ludGF4RXJyb3IsXG4gIENib3JUb29MaXR0bGVEYXRhRXJyb3IsXG4gIC8vIENib3JUb29NdWNoRGF0YUVycm9yLFxuICBDYm9yVW5zYWZlTWFwS2V5RXJyb3IsXG4gIFN1cnJlYWxWYWx1ZUVycm9yLFxuICB1bnJlYWNoYWJsZSxcbn0gZnJvbSBcIkB0YWkta3VuL3N1cnJlYWxkYi9lcnJvcnNcIjtcbmltcG9ydCB0eXBlIHsgVWludDhBcnJheUxpa2UgfSBmcm9tIFwiQHRhaS1rdW4vc3VycmVhbGRiL3R5cGVzXCI7XG5pbXBvcnQgeyB1dGY4IH0gZnJvbSBcIkB0YWkta3VuL3N1cnJlYWxkYi91dGlsc1wiO1xuaW1wb3J0IHsgZ2V0RmxvYXQxNiB9IGZyb20gXCIuL19mbG9hdFwiO1xuaW1wb3J0IHsgaWFuYVJldml2ZXIgfSBmcm9tIFwiLi9faWFuYVwiO1xuaW1wb3J0IHtcbiAgdHlwZSBBZGRpdGlvbmFsSW5mbyxcbiAgQUlfRUlHSFRfQllURVMsXG4gIEFJX0ZPVVJfQllURVMsXG4gIEFJX0lOREVGSU5JVEVfTlVNX0JZVEVTLFxuICBBSV9PTkVfQllURSxcbiAgQUlfU0lNUExFX0ZBTFNFLFxuICBBSV9TSU1QTEVfTlVMTCxcbiAgQUlfU0lNUExFX1RSVUUsXG4gIEFJX1NJTVBMRV9VTkRFRklORUQsXG4gIEFJX1RXT19CWVRFUyxcbiAgQlJFQUssXG4gIEpTX01BWF9TQUZFX1VOU0lHTkVEX0JJR19JTlRFR0VSLFxuICB0eXBlIE1ham9yVHlwZSxcbiAgTVRfQVJSQVksXG4gIE1UX0JZVEVfU1RSSU5HLFxuICBNVF9NQVAsXG4gIE1UX05FR0FUSVZFX0lOVEVHRVIsXG4gIE1UX1NJTVBMRV9GTE9BVCxcbiAgTVRfVEFHLFxuICBNVF9VTlNJR05FRF9JTlRFR0VSLFxuICBNVF9VVEY4X1NUUklORyxcbiAgU2ltcGxlLFxufSBmcm9tIFwiLi9zcGVjXCI7XG5pbXBvcnQgVGFnZ2VkIGZyb20gXCIuL3RhZ2dlZFwiO1xuXG50eXBlIElucHV0VmFsdWUgPSB1bmtub3duO1xuXG5jb25zdCBQQVJFTlRfUk9PVCA9IDA7XG5jb25zdCBQQVJFTlRfU1RSID0gMTtcbmNvbnN0IFBBUkVOVF9BUlIgPSAyO1xuY29uc3QgUEFSRU5UX09CSiA9IDM7XG5jb25zdCBQQVJFTlRfTUFQID0gNDtcbmNvbnN0IFBBUkVOVF9UQUcgPSA1O1xuXG5uYW1lc3BhY2UgUGFyZW50IHtcbiAgZXhwb3J0IHR5cGUgUm9vdCA9IHtcbiAgICByZWFkb25seSAkOiB0eXBlb2YgUEFSRU5UX1JPT1Q7XG4gICAgcmVhZG9ubHkgcHV0OiAodmFsOiBJbnB1dFZhbHVlKSA9PiBmYWxzZTtcbiAgICByZWFkb25seSBvdXQ6ICgpID0+IHVua25vd247XG4gICAgdmFsOiB1bmtub3duO1xuICB9O1xuXG4gIGV4cG9ydCBuYW1lc3BhY2UgU3RyIHtcbiAgICBleHBvcnQgdHlwZSBCeXRlID0ge1xuICAgICAgcmVhZG9ubHkgJDogdHlwZW9mIFBBUkVOVF9TVFI7XG4gICAgICByZWFkb25seSBtdDogdHlwZW9mIE1UX0JZVEVfU1RSSU5HO1xuICAgICAgcmVhZG9ubHkgcHV0OiAodmFsOiBJbnB1dFZhbHVlKSA9PiBib29sZWFuO1xuICAgICAgcmVhZG9ubHkgb3V0OiAoKSA9PiBVaW50OEFycmF5O1xuICAgICAgcmVhZG9ubHkgYWNjOiBVaW50OEFycmF5W107XG4gICAgICBzaXplOiBudW1iZXI7XG4gICAgfTtcblxuICAgIGV4cG9ydCB0eXBlIFV0ZjggPSB7XG4gICAgICByZWFkb25seSAkOiB0eXBlb2YgUEFSRU5UX1NUUjtcbiAgICAgIHJlYWRvbmx5IG10OiB0eXBlb2YgTVRfVVRGOF9TVFJJTkc7XG4gICAgICByZWFkb25seSBwdXQ6ICh2YWw6IElucHV0VmFsdWUpID0+IGJvb2xlYW47XG4gICAgICByZWFkb25seSBvdXQ6ICgpID0+IHN0cmluZztcbiAgICAgIGFjYzogc3RyaW5nO1xuICAgIH07XG4gIH1cblxuICBleHBvcnQgdHlwZSBTdHIgPVxuICAgIHwgU3RyLkJ5dGVcbiAgICB8IFN0ci5VdGY4O1xuXG4gIGV4cG9ydCB0eXBlIEFyciA9IHtcbiAgICByZWFkb25seSAkOiB0eXBlb2YgUEFSRU5UX0FSUjtcbiAgICByZWFkb25seSBwdXQ6ICh2YWw6IElucHV0VmFsdWUpID0+IGJvb2xlYW47XG4gICAgcmVhZG9ubHkgb3V0OiAoKSA9PiB1bmtub3duW107XG4gICAgcmVhZG9ubHkgYWNjOiB1bmtub3duW107XG4gICAgcmVhZG9ubHkgbGVuOiBudW1iZXI7XG4gICAgaWR4OiBudW1iZXI7XG4gIH07XG5cbiAgZXhwb3J0IG5hbWVzcGFjZSBPYmoge1xuICAgIGV4cG9ydCB0eXBlIE9iaiA9IHtcbiAgICAgIHJlYWRvbmx5ICQ6IHR5cGVvZiBQQVJFTlRfT0JKO1xuICAgICAgcmVhZG9ubHkgcHV0OiAodmFsOiBJbnB1dFZhbHVlKSA9PiBib29sZWFuO1xuICAgICAgcmVhZG9ubHkgb3V0OiAoKSA9PiB7IFtwOiBzdHJpbmddOiB1bmtub3duIH07XG4gICAgICByZWFkb25seSBhY2M6IHsgW3A6IHN0cmluZ106IHVua25vd24gfTtcbiAgICAgIHJlYWRvbmx5IHY4bjogSXNTYWZlT2JqZWN0S2V5O1xuICAgICAgcmVhZG9ubHkgbGVuOiBudW1iZXI7XG4gICAgICBpZHg6IG51bWJlcjtcbiAgICAgIGtleTogc3RyaW5nIHwgbnVtYmVyIHwgdHlwZW9mIE5PTkU7XG4gICAgfTtcblxuICAgIGV4cG9ydCB0eXBlIE1hcSA9IHtcbiAgICAgIHJlYWRvbmx5ICQ6IHR5cGVvZiBQQVJFTlRfTUFQO1xuICAgICAgcmVhZG9ubHkgcHV0OiAodmFsOiBJbnB1dFZhbHVlKSA9PiBib29sZWFuO1xuICAgICAgcmVhZG9ubHkgb3V0OiAoKSA9PiBNYXA8dW5rbm93biwgdW5rbm93bj47XG4gICAgICByZWFkb25seSBhY2M6IE1hcDx1bmtub3duLCB1bmtub3duPjtcbiAgICAgIHJlYWRvbmx5IHY4bjogSXNTYWZlTWFwS2V5O1xuICAgICAgcmVhZG9ubHkgbGVuOiBudW1iZXI7XG4gICAgICBpZHg6IG51bWJlcjtcbiAgICAgIGtleTogdW5rbm93biB8IHR5cGVvZiBOT05FO1xuICAgIH07XG4gIH1cblxuICBleHBvcnQgdHlwZSBPYmogPVxuICAgIHwgT2JqLk9ialxuICAgIHwgT2JqLk1hcTtcblxuICBleHBvcnQgdHlwZSBUYWcgPSB7XG4gICAgcmVhZG9ubHkgJDogdHlwZW9mIFBBUkVOVF9UQUc7XG4gICAgcmVhZG9ubHkgcHV0OiAodmFsOiBJbnB1dFZhbHVlKSA9PiBib29sZWFuO1xuICAgIHJlYWRvbmx5IG91dDogKCkgPT4gdW5rbm93bjtcbiAgICByZWFkb25seSBmbnM6IHJlYWRvbmx5IFRhZ2dlZEl0ZW1SZXZpdmVyW107XG4gICAgcmVhZG9ubHkgdGFnOiBudW1iZXIgfCBiaWdpbnQ7XG4gICAgdmFsOiB1bmtub3duO1xuICB9O1xufVxuXG50eXBlIFBhcmVudCA9XG4gIHwgUGFyZW50LlJvb3RcbiAgfCBQYXJlbnQuU3RyXG4gIHwgUGFyZW50LkFyclxuICB8IFBhcmVudC5PYmpcbiAgfCBQYXJlbnQuVGFnO1xuXG5jb25zdCBGUkFHTUVOVF9TVFIgPSAwO1xuXG5uYW1lc3BhY2UgRnJhZ21lbnQge1xuICBleHBvcnQgdHlwZSBTdHIgPSB7XG4gICAgcmVhZG9ubHkgJDogdHlwZW9mIEZSQUdNRU5UX1NUUjtcbiAgICByZWFkb25seSBtdDogdHlwZW9mIE1UX0JZVEVfU1RSSU5HIHwgdHlwZW9mIE1UX1VURjhfU1RSSU5HO1xuICAgIHJlYWRvbmx5IGRhdGE6IFVpbnQ4QXJyYXk7XG4gICAgcmVhZG9ubHkgc2l6ZTogbnVtYmVyO1xuICAgIG9mZnNldDogbnVtYmVyO1xuICB9O1xufVxuXG50eXBlIEZyYWdtZW50ID1cbiAgfCBGcmFnbWVudC5TdHJcbiAgfCBuZXZlcjsgLy8gXHUzMDUzXHUzMDUzXHUzMDZCXHU4RkZEXHU1MkEwXG5cbmNvbnN0IEhVTUFOSVpFRF9EQVRBX0lURU0gPSB7XG4gIFtNVF9VTlNJR05FRF9JTlRFR0VSXTogXCJ1bnNpZ25lZCBpbnRlZ2VyXCIsXG4gIFtNVF9ORUdBVElWRV9JTlRFR0VSXTogXCJuZWdhdGl2ZSBpbnRlZ2VyXCIsXG4gIFtNVF9CWVRFX1NUUklOR106IFwiYnl0ZSBzdHJpbmdcIixcbiAgW01UX1VURjhfU1RSSU5HXTogXCJ1dGY4IHN0cmluZ1wiLFxuICBbTVRfQVJSQVldOiBcImFycmF5XCIsXG4gIFtNVF9NQVBdOiBcIm1hcFwiLFxuICBbTVRfVEFHXTogXCJ0YWdnZWQgaXRlbVwiLFxuICBbTVRfU0lNUExFX0ZMT0FUXTogXCJzaW1wbGUvZmxvYXRcIixcbn07XG5cbmNvbnN0IE5PTkUgPSBTeW1ib2wuZm9yKFwiQHRhaS1rdW4vc3VycmVhbGRiL2Nib3Ivbm9uZVwiKTtcblxuZXhwb3J0IGNvbnN0IENPTlRJTlVFID0gU3ltYm9sLmZvcihcIkB0YWkta3VuL3N1cnJlYWxkYi9jYm9yL2NvbnRpbnVlXCIpO1xuXG5leHBvcnQgdHlwZSBUYWdnZWRJdGVtUmV2aXZlciA9ICh0YWdnZWQ6IFRhZ2dlZCkgPT4gdW5rbm93biB8IHR5cGVvZiBDT05USU5VRTtcblxuZXhwb3J0IHR5cGUgU2ltcGxlSXRlbVJldml2ZXIgPSAoc2ltcGxlOiBTaW1wbGUpID0+IHVua25vd24gfCB0eXBlb2YgQ09OVElOVUU7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmV2aXZlck9iamVjdCB7XG4gIHJlYWRvbmx5IHRhZ2dlZD86IFRhZ2dlZEl0ZW1SZXZpdmVyIHwgdW5kZWZpbmVkO1xuICByZWFkb25seSBzaW1wbGU/OiBTaW1wbGVJdGVtUmV2aXZlciB8IHVuZGVmaW5lZDtcbn1cblxuZXhwb3J0IHR5cGUgUmV2aXZlciA9ICh2YWx1ZTogVGFnZ2VkIHwgU2ltcGxlKSA9PiB1bmtub3duIHwgdHlwZW9mIENPTlRJTlVFO1xuXG5leHBvcnQgdHlwZSBJc1NhZmVNYXBLZXkgPSAoXG4gIGtleTogdW5rbm93bixcbiAgbWFwOiBNYXA8dW5rbm93biwgdW5rbm93bj4sXG4pID0+IGJvb2xlYW47XG5cbmV4cG9ydCB0eXBlIElzU2FmZU9iamVjdEtleSA9IChcbiAga2V5OiBzdHJpbmcgfCBudW1iZXIsXG4gIG9iajogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4pID0+IGJvb2xlYW47XG5cbmV4cG9ydCBpbnRlcmZhY2UgRGVjb2Rlck9wdGlvbnMge1xuICByZWFkb25seSBpc1NhZmVNYXBLZXk/OiBJc1NhZmVNYXBLZXkgfCB1bmRlZmluZWQ7XG4gIHJlYWRvbmx5IGlzU2FmZU9iamVjdEtleT86IElzU2FmZU9iamVjdEtleSB8IHVuZGVmaW5lZDtcbiAgcmVhZG9ubHkgbWFwVHlwZT86IFwiT2JqZWN0XCIgfCBcIk1hcFwiIHwgdW5kZWZpbmVkO1xuICByZWFkb25seSBtYXhEZXB0aD86IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgcmVhZG9ubHkgcmV2aXZlcj86XG4gICAgfCBSZXZpdmVyXG4gICAgfCBSZXZpdmVyT2JqZWN0XG4gICAgfCByZWFkb25seSAoUmV2aXZlciB8IFJldml2ZXJPYmplY3QpW11cbiAgICB8IHVuZGVmaW5lZDtcbn1cblxuZXhwb3J0IGNsYXNzIF9EZWNvZGVyIHtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IG1hcFR5cGU6IFwiT2JqZWN0XCIgfCBcIk1hcFwiO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgbWF4RGVwdGg6IG51bWJlcjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHJldml2ZXJzOiB7XG4gICAgdGFnZ2VkOiBUYWdnZWRJdGVtUmV2aXZlcltdO1xuICAgIHNpbXBsZTogU2ltcGxlSXRlbVJldml2ZXJbXTtcbiAgfTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGlzU2FmZU1hcEtleTogKFxuICAgIGtleTogdW5rbm93bixcbiAgICBtYXA6IE1hcDx1bmtub3duLCB1bmtub3duPixcbiAgKSA9PiBib29sZWFuO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgaXNTYWZlT2JqZWN0S2V5OiAoXG4gICAga2V5OiBzdHJpbmcgfCBudW1iZXIsXG4gICAgb2JqOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgKSA9PiBib29sZWFuO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IERlY29kZXJPcHRpb25zIHwgdW5kZWZpbmVkID0ge30pIHtcbiAgICBjb25zdCB7XG4gICAgICBtYXBUeXBlID0gXCJPYmplY3RcIixcbiAgICAgIHJldml2ZXIsXG4gICAgICBtYXhEZXB0aCA9IDY0LFxuICAgICAgaXNTYWZlTWFwS2V5ID0gayA9PiBrICE9PSBcIl9fcHJvdG9fX1wiICYmIGsgIT09IFwiY29uc3RydWN0b3JcIixcbiAgICAgIGlzU2FmZU9iamVjdEtleSA9IGsgPT4gayAhPT0gXCJfX3Byb3RvX19cIiAmJiBrICE9PSBcImNvbnN0cnVjdG9yXCIsXG4gICAgfSA9IG9wdGlvbnM7XG4gICAgdGhpcy5tYXBUeXBlID0gbWFwVHlwZTtcbiAgICB0aGlzLm1heERlcHRoID0gbWF4RGVwdGg7XG4gICAgdGhpcy5yZXZpdmVycyA9IHRvUmV2aXZlcnMocmV2aXZlcik7XG4gICAgdGhpcy5yZXZpdmVycy50YWdnZWQucHVzaChjb21wYXRSZXZpdmVyLCBpYW5hUmV2aXZlcik7XG4gICAgdGhpcy5pc1NhZmVNYXBLZXkgPSBpc1NhZmVNYXBLZXk7XG4gICAgdGhpcy5pc1NhZmVPYmplY3RLZXkgPSBpc1NhZmVPYmplY3RLZXk7XG5cbiAgICB0aGlzLmRlcHRoID0gMDtcbiAgICB0aGlzLnBhcmVudHMgPSBbXG4gICAgICB0aGlzLnBhcmVudCA9IHtcbiAgICAgICAgJDogUEFSRU5UX1JPT1QsXG4gICAgICAgIHB1dCh2YWwpIHtcbiAgICAgICAgICBpZiAodmFsID09PSBCUkVBSykge1xuICAgICAgICAgICAgLy8gaHR0cHM6Ly93d3cucmZjLWVkaXRvci5vcmcvcmZjL3JmYzg5NDkuaHRtbCNzZWN0aW9uLWFwcGVuZGl4LmYtNC40XG4gICAgICAgICAgICB0aHJvdyBuZXcgQ2JvclN5bnRheEVycm9yKFxuICAgICAgICAgICAgICBgVGhlIFwiYnJlYWtcIiBzdG9wIGNvZGUgd2FzIGVuY291bnRlcmVkIG91dHNpZGUgb2YgYFxuICAgICAgICAgICAgICAgICsgXCJhIGluZGVmaW5pdGUtbGVuZ3RoIGRhdGEgaXRlbS5cIixcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy52YWwgPSB2YWw7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9LFxuICAgICAgICBvdXQoKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMudmFsO1xuICAgICAgICB9LFxuICAgICAgICB2YWw6IHVuZGVmaW5lZCxcbiAgICAgIH0sXG4gICAgXTtcbiAgICB0aGlzLmZyYWdtZW50ID0gbnVsbDtcbiAgfVxuXG4gIHByb3RlY3RlZCBkZXB0aDogbnVtYmVyO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgcGFyZW50czogW1BhcmVudC5Sb290LCAuLi5FeGNsdWRlPFBhcmVudCwgUGFyZW50LlJvb3Q+W11dO1xuICBwcm90ZWN0ZWQgcGFyZW50OiBQYXJlbnQ7XG4gIHByb3RlY3RlZCBmcmFnbWVudDogRnJhZ21lbnQgfCBudWxsO1xuXG4gIHByb3RlY3RlZCBwdXRWYWx1ZSh2YWx1ZTogSW5wdXRWYWx1ZSk6IHZvaWQge1xuICAgIC8vIEB0cy1pZ25vcmUgKFRTNjEzMyk6IFx1NEY1NVx1NjU0NVx1MzA0Qlx1MzBBOFx1MzBFOVx1MzBGQ1x1MzA2Qlx1MzA2QVx1MzA4QlxuICAgIGxldCBkb25lID0gZmFsc2U7XG5cbiAgICB3aGlsZSAoKGRvbmUgPSB0aGlzLnBhcmVudC5wdXQodmFsdWUpKSkge1xuICAgICAgdGhpcy5lbmQoKTtcbiAgICAgIHZhbHVlID0gdGhpcy5wYXJlbnRzLnBvcCgpIS5vdXQoKTtcbiAgICAgIHRoaXMucGFyZW50ID0gdGhpcy5wYXJlbnRzW3RoaXMucGFyZW50cy5sZW5ndGggLSAxXSE7XG4gICAgfVxuICB9XG5cbiAgcHJvdGVjdGVkIGJlZ2luKHBhcmVudDogRXhjbHVkZTxQYXJlbnQsIFBhcmVudC5Sb290Pik6IHZvaWQge1xuICAgIGlmIChwYXJlbnQuJCAhPT0gUEFSRU5UX1NUUiAmJiArK3RoaXMuZGVwdGggPj0gdGhpcy5tYXhEZXB0aCkge1xuICAgICAgdGhyb3cgbmV3IENib3JNYXhEZXB0aFJlYWNoZWRFcnJvcih0aGlzLm1heERlcHRoKTtcbiAgICB9XG5cbiAgICB0aGlzLnBhcmVudHMucHVzaCh0aGlzLnBhcmVudCA9IHBhcmVudCk7XG4gIH1cblxuICBwcml2YXRlIGVuZCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5wYXJlbnQuJCAhPT0gUEFSRU5UX1NUUikge1xuICAgICAgdGhpcy5kZXB0aCAtPSAxO1xuICAgIH1cbiAgfVxuXG4gIHByb2Nlc3MoaW5wdXQ6IFVpbnQ4QXJyYXlMaWtlKTogdm9pZCB7XG4gICAgbGV0IG9mZnNldCA9IDA7XG4gICAgY29uc3QgZnJhZ21lbnQgPSB0aGlzLmZyYWdtZW50O1xuXG4gICAgaWYgKGZyYWdtZW50ICE9PSBudWxsKSB7XG4gICAgICBzd2l0Y2ggKGZyYWdtZW50LiQpIHtcbiAgICAgICAgY2FzZSBGUkFHTUVOVF9TVFI6IHtcbiAgICAgICAgICBjb25zdCByZW1haW5pbmcgPSBmcmFnbWVudC5zaXplIC0gZnJhZ21lbnQub2Zmc2V0O1xuICAgICAgICAgIGNvbnN0IGNodW5rID0gaW5wdXQuc3ViYXJyYXkob2Zmc2V0LCBvZmZzZXQgKz0gcmVtYWluaW5nKTtcbiAgICAgICAgICBmcmFnbWVudC5kYXRhLnNldChjaHVuaywgZnJhZ21lbnQub2Zmc2V0KTtcblxuICAgICAgICAgIGlmIChjaHVuay5sZW5ndGggPCByZW1haW5pbmcpIHtcbiAgICAgICAgICAgIGZyYWdtZW50Lm9mZnNldCArPSBjaHVuay5sZW5ndGg7XG4gICAgICAgICAgICByZXR1cm47IC8vIGlucHV0IFx1MzA2RVx1NjcwMFx1NUY4Q1x1MzA2Qlx1NTIzMFx1OTA1NFx1MzA1N1x1MzA2Nlx1MzA0NFx1MzA4Qlx1MzA2RVx1MzA2N1x1NjVFOVx1NjcxRlx1MzBFQVx1MzBCRlx1MzBGQ1x1MzBGM1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxldCB2YWx1ZTogc3RyaW5nIHwgVWludDhBcnJheUxpa2UgPSBmcmFnbWVudC5kYXRhO1xuXG4gICAgICAgICAgaWYgKGZyYWdtZW50Lm10ID09PSBNVF9VVEY4X1NUUklORykge1xuICAgICAgICAgICAgdmFsdWUgPSB1dGY4LmRlY29kZSh2YWx1ZSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5wdXRWYWx1ZSh2YWx1ZSk7XG4gICAgICAgICAgdGhpcy5mcmFnbWVudCA9IG51bGw7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHVucmVhY2hhYmxlKGZyYWdtZW50IGFzIG5ldmVyKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCB2aWV3ID0gbmV3IERhdGFWaWV3KGlucHV0LmJ1ZmZlciwgaW5wdXQuYnl0ZU9mZnNldCwgaW5wdXQuYnl0ZUxlbmd0aCk7XG4gICAgY29uc3Qgdmlld0xlbmd0aCA9IHZpZXcuYnl0ZUxlbmd0aDtcblxuICAgIHdoaWxlIChvZmZzZXQgPCB2aWV3TGVuZ3RoKSB7XG4gICAgICBjb25zdCBpYiA9IHZpZXcuZ2V0VWludDgob2Zmc2V0KyspO1xuICAgICAgbGV0IG10ID0gKGliID4+IDUpIGFzIE1ham9yVHlwZTtcbiAgICAgIGxldCBhaSA9IChpYiAmIDB4MWYpIGFzIEFkZGl0aW9uYWxJbmZvO1xuICAgICAgbGV0IHZhbHVlO1xuICAgICAgbGV0IGlzU2ltcGxlID0gZmFsc2U7IC8vIE5vdCBhIGZsb2F0XG4gICAgICBsZXQgcGF5bG9hZExlbmd0aCA9IDA7XG5cbiAgICAgIHN3aXRjaCAoYWkpIHtcbiAgICAgICAgLy8gIyBTaG9ydCBEYXRhIEl0ZW0gKDI0IDw9IGFpIDw9IDI3KVxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rXG4gICAgICAgIC8vIHwgQnl0ZSBjb3VudCAgIHwgMSBieXRlIChDQk9SIGRhdGEgaXRlbSBoZWFkZXIpIHwgICAgMSwgMiwgNCBvciA4IEJ5dGVzICAgICB8ICAgICAgICAgIDAgfiAyXjY0LTEgQnl0ZXMgICAgICAgICAgIHxcbiAgICAgICAgLy8gKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tK1xuICAgICAgICAvLyB8IFN0cnVjdHVyZSAgICB8IE1ham9yIHR5cGUgfCAgQWRkaXRpb25hbCBpbmZvICB8IEFkZGl0aW9uYWwgaW5mbyAoQ29udGVudCkgfCAgICAgICAgICAgICAgICBQYXlsb2FkICAgICAgICAgICAgICB8XG4gICAgICAgIC8vICstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAgICAgICAgLy8gfCBCaXQgY291bnQgICAgfCAgIDMgQml0cyAgIHwgICAgICA1IEJpdHMgICAgICAgfCAgIDgsIDE2LCAzMiBvciA2NCBCaXRzICAgIHwgIDggQml0cyAgfCAgICAgICAgICAgLi4uICAgICAgICAgICAgfFxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rXG4gICAgICAgIC8vIHwgVW5zaWduZWQgSW50IHwgICAgIDAgICAgICB8ICAyNCwgMjUsIDI2LCAyNyAgIHwgICAgIDAgfiAyXjY0LTEgKFZhbHVlKSAgICB8ICAgICAgICAgICAgICAgICBOL0EgICAgICAgICAgICAgICAgIHxcbiAgICAgICAgLy8gKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tK1xuICAgICAgICAvLyB8IE5lZ2F0aXZlIEludCB8ICAgICAxICAgICAgfCAgMjQsIDI1LCAyNiwgMjcgICB8ICAgICAgICAgMCB+IDJeNjQtMSAgICAgICAgfCAgICAgICAgICAgICAgICAgTi9BICAgICAgICAgICAgICAgICB8XG4gICAgICAgIC8vICstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLSstLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLStcbiAgICAgICAgLy8gfCBCeXRlcyAvIFRleHQgfCAgICAyLCAzICAgIHwgIDI0LCAyNSwgMjYsIDI3ICAgfCAgIGNvdW50IDo9IDAgfiAyXjY0LTEgICAgIHwgYnl0ZXNbMF0gfCAgIC4uLiAgIHwgYnl0ZXNbPGNvdW50Pl0gfFxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0rXG4gICAgICAgIC8vIHwgQXJyYXkgLyBNYXAgIHwgICAgNCwgNSAgICB8ICAyNCwgMjUsIDI2LCAyNyAgIHwgICAgMCB+IDJeNjQtMSBbaXRlbXNdICAgICB8IE4vQSAoU3Vic2VxdWVudCBkYXRhIGl0ZW1zIC8gcGFpcnMpIHxcbiAgICAgICAgLy8gKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tK1xuICAgICAgICAvLyB8IFRhZyAgICAgICAgICB8ICAgICA2ICAgICAgfCAgMjQsIDI1LCAyNiwgMjcgICB8ICAgIDAgfiAyXjY0LTEgKFZhbHVlKSAgICAgfCAgICAgTi9BIChBIHN1YnNlcXVlbnQgZGF0YSBpdGVtKSAgICB8XG4gICAgICAgIC8vICstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAgICAgICAgLy8gfCBGbG9hdCAgICAgICAgfCAgICAgNyAgICAgIHwgICAgMjUsIDI2LCAyNyAgICAgfCAgICAgKElFRUUgNzU0IEZsb2F0KSAgICAgIHwgICAgICAgICAgICAgICAgIE4vQSAgICAgICAgICAgICAgICAgfFxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rXG5cbiAgICAgICAgY2FzZSBBSV9PTkVfQllURTogLy8gMjRcbiAgICAgICAgICBwYXlsb2FkTGVuZ3RoID0gMTtcbiAgICAgICAgICB2YWx1ZSA9IHZpZXcuZ2V0VWludDgob2Zmc2V0KTtcblxuICAgICAgICAgIGlmIChtdCA9PT0gTVRfU0lNUExFX0ZMT0FUKSB7XG4gICAgICAgICAgICBpZiAodmFsdWUgPCAweDIwKSB7XG4gICAgICAgICAgICAgIC8vIFx1MzBBOFx1MzBGM1x1MzBCM1x1MzBGQ1x1MzBDMFx1MzBGQ1x1MzA2Rlx1MzAwMTB4ZjggKE1ham9yIFR5cGU6IDcsIEFkZGl0aW9uYWwgSW5mbzogMjQpIFx1MzA2N1x1NTlDQlx1MzA3RVx1MzA4QVx1MzAwMVxuICAgICAgICAgICAgICAvLyAweDIwIFx1NjcyQVx1NkU4MFx1MzA2RVx1MzBEMFx1MzBBNFx1MzBDOFx1MzA2N1x1N0Q5QVx1MzA0RiAyIFx1MzBEMFx1MzBBNFx1MzBDOFx1MzBCN1x1MzBGQ1x1MzBCMVx1MzBGM1x1MzBCOVx1MzA5Mlx1NzY3QVx1ODg0Q1x1MzA1N1x1MzA2Nlx1MzA2Rlx1MzA2QVx1MzA4OVx1MzA2QVx1MzA0NFx1MzAwMlxuICAgICAgICAgICAgICAvLyBodHRwczovL3d3dy5yZmMtZWRpdG9yLm9yZy9yZmMvcmZjODk0OS5odG1sI3NlY3Rpb24tMy4zLTVcbiAgICAgICAgICAgICAgLy8gaHR0cHM6Ly93d3cucmZjLWVkaXRvci5vcmcvcmZjL3JmYzg5NDkuaHRtbCNzZWN0aW9uLWFwcGVuZGl4LmYtNC4yXG4gICAgICAgICAgICAgIHRocm93IG5ldyBDYm9yU3ludGF4RXJyb3IoXG4gICAgICAgICAgICAgICAgXCIyLWJ5dGUgc2VxdWVuY2UgZm9sbG93ZWQgYnkgYSBieXRlIGxlc3MgdGhhbiAweDIwIGlzIGJlaW5nXCJcbiAgICAgICAgICAgICAgICAgICsgXCIgaXNzdWVkIGFmdGVyIHRoZSBoZWFkZXIgMHhmOC5cIixcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaXNTaW1wbGUgPSB0cnVlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGNhc2UgQUlfVFdPX0JZVEVTOiAvLyAyNVxuICAgICAgICAgIHBheWxvYWRMZW5ndGggPSAyO1xuICAgICAgICAgIHZhbHVlID0gbXQgPT09IE1UX1NJTVBMRV9GTE9BVFxuICAgICAgICAgICAgPyBnZXRGbG9hdDE2KHZpZXcsIG9mZnNldClcbiAgICAgICAgICAgIDogdmlldy5nZXRVaW50MTYob2Zmc2V0KTtcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBjYXNlIEFJX0ZPVVJfQllURVM6IC8vIDI2XG4gICAgICAgICAgcGF5bG9hZExlbmd0aCA9IDQ7XG4gICAgICAgICAgdmFsdWUgPSBtdCA9PT0gTVRfU0lNUExFX0ZMT0FUXG4gICAgICAgICAgICA/IHZpZXcuZ2V0RmxvYXQzMihvZmZzZXQpXG4gICAgICAgICAgICA6IHZpZXcuZ2V0VWludDMyKG9mZnNldCk7XG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgY2FzZSBBSV9FSUdIVF9CWVRFUzogLy8gMjdcbiAgICAgICAgICBwYXlsb2FkTGVuZ3RoID0gODtcblxuICAgICAgICAgIGlmIChtdCA9PT0gTVRfU0lNUExFX0ZMT0FUKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHZpZXcuZ2V0RmxvYXQ2NChvZmZzZXQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHZpZXcuZ2V0QmlnVWludDY0KG9mZnNldCk7XG5cbiAgICAgICAgICAgIGlmIChtdCA9PT0gTVRfTkVHQVRJVkVfSU5URUdFUikge1xuICAgICAgICAgICAgICAvLyBcdThDQTBcdTMwNkVcdTUwMjRcdTMwNkYgLTEgXHUzMDRCXHUzMDg5IHZhbHVlIFx1MzA5Mlx1NUYxNVx1MzA0NFx1MzA1Rlx1NjU3MFx1MzA2QVx1MzA2RVx1MzA2N1x1MzAwMVx1NjcwMFx1NTkyN1x1NTAyNFx1MzA4OFx1MzA4QSAxIFx1NEVFNVx1NEUwQVx1NUMwRlx1MzA1NVx1MzA0Rlx1MzA2QVx1MzA0NFx1MzA2OFxuICAgICAgICAgICAgICAvLyBOdW1iZXIgXHUzMDZCXHUzMDZGXHUzMDZBXHUzMDhDXHUzMDZBXHUzMDQ0XHUzMDAyXG4gICAgICAgICAgICAgIGlmICh2YWx1ZSA8PSBKU19NQVhfU0FGRV9VTlNJR05FRF9CSUdfSU5URUdFUiAtIDFuKSB7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSBOdW1iZXIodmFsdWUpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlIDw9IEpTX01BWF9TQUZFX1VOU0lHTkVEX0JJR19JTlRFR0VSKSB7XG4gICAgICAgICAgICAgIHZhbHVlID0gTnVtYmVyKHZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBicmVhaztcblxuICAgICAgICAvLyAjIExvbmcgRGF0YSBJdGVtIChhaSA9PSAzMSlcbiAgICAgICAgLy8gKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tK1xuICAgICAgICAvLyB8IEJ5dGUgY291bnQgICB8IDEgYnl0ZSAoQ0JPUiBkYXRhIGl0ZW0gaGVhZGVyKSB8ICAgICAgICAgICAgICAwIH4gPyBCeXRlcyAgICAgICAgICAgICB8XG4gICAgICAgIC8vICstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAgICAgICAgLy8gfCBTdHJ1Y3R1cmUgICAgfCBNYWpvciB0eXBlIHwgIEFkZGl0aW9uYWwgaW5mbyAgfCAgICAgICAgICAgICAgICBQYXlsb2FkICAgICAgICAgICAgICAgfFxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rXG4gICAgICAgIC8vIHwgQml0IGNvdW50ICAgIHwgICAzIEJpdHMgICB8ICAgICAgNSBCaXRzICAgICAgIHwgIDggQml0cyAgfCAgICAgICAgICAgIC4uLiAgICAgICAgICAgIHxcbiAgICAgICAgLy8gKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tK1xuICAgICAgICAvLyB8IEJ5dGVzIC8gVGV4dCB8ICAgIDIsIDMgICAgfCAgICAgICAgMzEgICAgICAgICB8IGJ5dGVzWzBdIHwgLi4uIHwgQnJlYWsgKE5vbi1wYXlsb2FkKSB8XG4gICAgICAgIC8vICstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tKy0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAgICAgICAgLy8gfCBBcnJheSAvIE1hcCAgfCAgICA0LCA1ICAgIHwgICAgICAgIDMxICAgICAgICAgfCBOL0EgKFN1YnNlcXVlbnQgZGF0YSBpdGVtcyAvIHBhaXJzKSAgfFxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rXG4gICAgICAgIC8vIHwgQnJlYWsgICAgICAgIHwgICAgIDcgICAgICB8ICAgICAgICAzMSAgICAgICAgIHwgICAgICAgICAgICAgICAgICBOL0EgICAgICAgICAgICAgICAgIHxcbiAgICAgICAgLy8gKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tK1xuXG4gICAgICAgIGNhc2UgQUlfSU5ERUZJTklURV9OVU1fQllURVM6IC8vIDMxXG4gICAgICAgICAgc3dpdGNoIChtdCkge1xuICAgICAgICAgICAgY2FzZSBNVF9VTlNJR05FRF9JTlRFR0VSOlxuICAgICAgICAgICAgY2FzZSBNVF9ORUdBVElWRV9JTlRFR0VSOlxuICAgICAgICAgICAgY2FzZSBNVF9UQUc6XG4gICAgICAgICAgICAgIC8vIGh0dHBzOi8vd3d3LnJmYy1lZGl0b3Iub3JnL3JmYy9yZmM4OTQ5Lmh0bWwjc2VjdGlvbi1hcHBlbmRpeC5mLTQuNVxuICAgICAgICAgICAgICB0aHJvdyBuZXcgQ2JvclN5bnRheEVycm9yKFxuICAgICAgICAgICAgICAgIGBUaGUgZGF0YSBpdGVtIFxcYCR7SFVNQU5JWkVEX0RBVEFfSVRFTVttdF19XFxgIGhhcyBgXG4gICAgICAgICAgICAgICAgICArIFwiaW5kZWZpbml0ZS1sZW5ndGggYnl0ZXMuXCIsXG4gICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIGNhc2UgTVRfU0lNUExFX0ZMT0FUOlxuICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgKHRoaXMucGFyZW50LiQgPT09IFBBUkVOVF9BUlJcbiAgICAgICAgICAgICAgICAgIHx8IHRoaXMucGFyZW50LiQgPT09IFBBUkVOVF9PQkpcbiAgICAgICAgICAgICAgICAgIHx8IHRoaXMucGFyZW50LiQgPT09IFBBUkVOVF9NQVApXG4gICAgICAgICAgICAgICAgJiYgdGhpcy5wYXJlbnQubGVuICE9PSBJbmZpbml0eVxuICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgQ2JvclN5bnRheEVycm9yKFxuICAgICAgICAgICAgICAgICAgYFRoZSBkZWZpbml0ZS1sZW5ndGggZGF0YSBpdGVtIFxcYCR7SFVNQU5JWkVEX0RBVEFfSVRFTVttdF19XFxgYFxuICAgICAgICAgICAgICAgICAgICArIGBjb250YWlucyB0aGUgXCJicmVha1wiIHN0b3AgY29kZS5gLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICB2YWx1ZSA9IEJSRUFLO1xuICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBNVF9CWVRFX1NUUklORzpcbiAgICAgICAgICAgIGNhc2UgTVRfVVRGOF9TVFJJTkc6XG4gICAgICAgICAgICAgIGlmICh0aGlzLnBhcmVudC4kID09PSBQQVJFTlRfU1RSICYmIG10ID09PSB0aGlzLnBhcmVudC5tdCkge1xuICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vd3d3LnJmYy1lZGl0b3Iub3JnL3JmYy9yZmM4OTQ5Lmh0bWwjc2VjdGlvbi1hcHBlbmRpeC5mLTQuM1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBDYm9yU3ludGF4RXJyb3IoXG4gICAgICAgICAgICAgICAgICBcIlRoZSBwYXlsb2FkIG9mIHRoZSBpbmRlZmluaXRlLWxlbmd0aCBkYXRhIGl0ZW0gYFwiXG4gICAgICAgICAgICAgICAgICAgICsgSFVNQU5JWkVEX0RBVEFfSVRFTVttdF0gKyBcImAgY29udGFpbnMgdGhlIHNhbWUgdHlwZS5cIixcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgdmFsdWUgPSBJbmZpbml0eTtcbiAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIC8vIGNhc2UgTVRfQVJSQVk6XG4gICAgICAgICAgICAvLyBjYXNlIE1UX01BUDpcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgIHZhbHVlID0gSW5maW5pdHk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgLy8gIyBJbnZhbGlkIERhdGEgSXRlbSAoMjggPD0gYWkgPD0gMzApXG4gICAgICAgIC8vICstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAgICAgICAgLy8gfCBCeXRlIGNvdW50ICAgfCAxIGJ5dGUgKENCT1IgZGF0YSBpdGVtIGhlYWRlcikgfFxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0rXG4gICAgICAgIC8vIHwgU3RydWN0dXJlICAgIHwgTWFqb3IgdHlwZSB8ICBBZGRpdGlvbmFsIGluZm8gIHxcbiAgICAgICAgLy8gKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tK1xuICAgICAgICAvLyB8IEJpdCBjb3VudCAgICB8ICAgMyBCaXRzICAgfCAgICAgIDUgQml0cyAgICAgICB8XG4gICAgICAgIC8vICstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAgICAgICAgLy8gfCBOL0EgICAgICAgICAgfCAgIDAgfiA3ICAgIHwgICAgICAyOCB+IDMwICAgICAgfFxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0rXG5cbiAgICAgICAgY2FzZSAyODpcbiAgICAgICAgY2FzZSAyOTpcbiAgICAgICAgY2FzZSAzMDpcbiAgICAgICAgICAvLyBodHRwczovL3d3dy5yZmMtZWRpdG9yLm9yZy9yZmMvcmZjODk0OS5odG1sI3NlY3Rpb24tMy0zLjZcbiAgICAgICAgICB0aHJvdyBuZXcgQ2JvclN5bnRheEVycm9yKFxuICAgICAgICAgICAgYFRoZSBhZGRpdGlvbmFsIGluZm8gJHthaX0gaXMgcmVzZXJ2ZWQgZm9yIGZ1dHVyZSBhZGRpdGlvbnMgdG8gdGhlIGBcbiAgICAgICAgICAgICAgKyBcIkNCT1IgZm9ybWF0LlwiLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgLy8gIyBUaW55IERhdGEgSXRlbSAoMCA8PSBhaSA8PSAyMylcbiAgICAgICAgLy8gKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rXG4gICAgICAgIC8vIHwgQnl0ZSBjb3VudCAgIHwgMSBieXRlIChDQk9SIGRhdGEgaXRlbSBoZWFkZXIpIHwgICAgICAgICAgICAgMCB+IDIzIEJ5dGVzICAgICAgICAgICAgfFxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAgICAgICAgLy8gfCBTdHJ1Y3R1cmUgICAgfCBNYWpvciB0eXBlIHwgIEFkZGl0aW9uYWwgaW5mbyAgfCAgICAgICAgICAgICAgIFBheWxvYWQgICAgICAgICAgICAgICB8XG4gICAgICAgIC8vICstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tK1xuICAgICAgICAvLyB8IEJpdCBjb3VudCAgICB8ICAgMyBCaXRzICAgfCAgICAgIDUgQml0cyAgICAgICB8ICA4IEJpdHMgIHwgICAgICAgICAgIC4uLiAgICAgICAgICAgIHxcbiAgICAgICAgLy8gKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rXG4gICAgICAgIC8vIHwgVW5zaWduZWQgSW50IHwgICAgIDAgICAgICB8ICAgMCB+IDIzIChWYWx1ZSkgIHwgICAgICAgICAgICAgICAgIE4vQSAgICAgICAgICAgICAgICAgfFxuICAgICAgICAvLyArLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAgICAgICAgLy8gfCBOZWdhdGl2ZSBJbnQgfCAgICAgMSAgICAgIHwgICAgICAwIH4gMj