diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 115b4389..5fe8b706 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,97 +2,30 @@ name: Continuous Integration on: push: branches: - - main + - master pull_request: jobs: test: name: Test - runs-on: ${{ matrix.os }} - timeout-minutes: 30 - - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - node-version: [lts/*, lts/-1] + timeout-minutes: 15 + runs-on: ubuntu-latest steps: - name: Checkout project - uses: actions/checkout@v2 + uses: actions/checkout@v6 - - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + - name: Setup Node.js + uses: actions/setup-node@v6 with: - node-version: ${{ matrix.node-version }} - check-latest: true + node-version: "lts/*" cache: "npm" - name: Install dependencies run: npm ci - - name: Run tests - run: npm test - - test-contracts: - name: Test verifier contracts - runs-on: ${{ matrix.os }} - timeout-minutes: 30 - - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - node-version: [lts/*] - - steps: - - name: Checkout project - uses: actions/checkout@v2 + - name: Install Playwright dependencies + run: npx playwright install - - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - check-latest: true - cache: "npm" - - - name: Install dependencies - run: npm ci - - - name: Install hardhat dependencies - working-directory: smart_contract_tests - run: npm ci - - - name: Run hardhat tests - working-directory: smart_contract_tests - run: npm test - - test-browser: - name: Test browser - runs-on: ${{ matrix.os }} - timeout-minutes: 30 - - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - node-version: [lts/*] - - steps: - - name: Checkout project - uses: actions/checkout@v2 - - - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - check-latest: true - cache: "npm" - - - name: Install browser dependencies - working-directory: browser_tests - run: npm ci - - - name: Run browser tests - working-directory: browser_tests + - name: Run tests run: npm test diff --git a/build-config/constants-stub.js b/build-config/constants-stub.js new file mode 100644 index 00000000..3f07deb4 --- /dev/null +++ b/build-config/constants-stub.js @@ -0,0 +1,6 @@ +export const O_TRUNC = 512; +export const O_CREAT = 64; +export const O_RDWR = 2; +export const O_EXCL = 128; +export const O_RDONLY = 0; +export default {}; diff --git a/build-config/empty-stub.js b/build-config/empty-stub.js new file mode 100644 index 00000000..cf873295 --- /dev/null +++ b/build-config/empty-stub.js @@ -0,0 +1,4 @@ +// Empty stub for Node built-ins that are unreachable in the browser prove path +// (fs/os/readline/crypto/...). getRandomBytes/getSHA256 in src/misc.js fall back +// to globalThis.crypto in the browser, so an empty module is safe here. +export default {}; diff --git a/build-config/wasm-toolchain-stub.js b/build-config/wasm-toolchain-stub.js new file mode 100644 index 00000000..60f49116 --- /dev/null +++ b/build-config/wasm-toolchain-stub.js @@ -0,0 +1,11 @@ +// Stub for the runtime wasm codegen toolchain (wasmbuilder + wasmcurves +// generators). Only reachable through ffjavascript's custom-`plugins` +// curve-build path, which snarkjs never takes. Bundling the real toolchain +// into the browser build would add ~180 KB for a code path that never runs. +const err = () => { + throw new Error("wasm codegen toolchain is not included in the snarkjs browser bundle (only needed when building a curve with custom wasm plugins)"); +}; +export class ModuleBuilder { constructor() { err(); } } +export const buildBn128 = err; +export const buildBls12381 = err; +export default {}; diff --git a/build/browser.esm.js b/build/browser.esm.js index 7df476be..9c852ccd 100644 --- a/build/browser.esm.js +++ b/build/browser.esm.js @@ -1,17710 +1,5401 @@ -import { BigBuffer, Scalar, buildBn128, buildBls12381, ChaCha, F1Field, utils, getCurveFromR as getCurveFromR$1 } from 'ffjavascript'; - -var fs = {}; - -async function open$2(fileName, openFlags, cacheSize, pageSize) { - cacheSize = cacheSize || 4096*64; - if (typeof openFlags !== "number" && ["w+", "wx+", "r", "ax+", "a+"].indexOf(openFlags) <0) - throw new Error("Invalid open option"); - const fd =await fs.promises.open(fileName, openFlags); - - const stats = await fd.stat(); - - return new FastFile$2(fd, stats, cacheSize, pageSize, fileName); -} - - -let FastFile$2 = class FastFile { - - constructor(fd, stats, cacheSize, pageSize, fileName) { - this.fileName = fileName; - this.fd = fd; - this.pos = 0; - this.pageSize = pageSize || (1 << 8); - while (this.pageSize < stats.blksize) { - this.pageSize *= 2; - } - this.totalSize = stats.size; - this.totalPages = Math.floor((stats.size -1) / this.pageSize)+1; - this.maxPagesLoaded = Math.floor( cacheSize / this.pageSize)+1; - // Reads/writes at least this large bypass the page cache and move bytes - // straight between disk and the caller's buffer (see readToBuffer / - // write), avoiding the extra buffer<->page copy that dominates large - // sequential transfers (e.g. zkey/ptau sections). - this.directReadThreshold = 1 << 20; - this.directWriteThreshold = 1 << 20; - this.pages = {}; - this.pendingLoads = []; - this.writing = false; - this.reading = false; - this.avBuffs = []; - this.history = {}; - } - - _loadPage(p) { - const self = this; - const P = new Promise((resolve, reject)=> { - self.pendingLoads.push({ - page: p, - resolve: resolve, - reject: reject - }); - }); - self.__statusPage("After Load request: ", p); - return P; - } - - __statusPage(s, p) { - const logEntry = []; - const self=this; - if (!self.logHistory) return; - logEntry.push("==" + s+ " " +p); - let S = ""; - for (let i=0; i " + self.history[p][i][j]); - } - } - } - - - - _triggerLoad() { - const self = this; - - if (self.reading) return; - if (self.pendingLoads.length==0) return; - - const pageIdxs = Object.keys(self.pages); - - const deletablePages = []; - for (let i=0; i0) && - ( (typeof self.pages[self.pendingLoads[0].page] != "undefined" ) - ||( (freePages>0) - ||(deletablePages.length>0)))) { - const load = self.pendingLoads.shift(); - if (typeof self.pages[load.page] != "undefined") { - self.pages[load.page].pendingOps ++; - const idx = deletablePages.indexOf(load.page); - if (idx>=0) deletablePages.splice(idx, 1); - if (self.pages[load.page].loading) { - self.pages[load.page].loading.push(load); - } else { - load.resolve(); - } - self.__statusPage("After Load (cached): ", load.page); - - } else { - if (freePages) { - freePages--; - } else { - const fp = deletablePages.shift(); - self.__statusPage("Before Unload: ", fp); - self.avBuffs.unshift(self.pages[fp]); - delete self.pages[fp]; - self.__statusPage("After Unload: ", fp); - } - - if (load.page>=self.totalPages) { - self.pages[load.page] = getNewPage(); - load.resolve(); - self.__statusPage("After Load (new): ", load.page); - } else { - self.reading = true; - self.pages[load.page] = getNewPage(); - self.pages[load.page].loading = [load]; - ops.push(self.fd.read(self.pages[load.page].buff, 0, self.pageSize, load.page*self.pageSize).then((res)=> { - self.pages[load.page].size = res.bytesRead; - const loading = self.pages[load.page].loading; - delete self.pages[load.page].loading; - for (let i=0; i { - load.reject(err); - })); - self.__statusPage("After Load (loading): ", load.page); - } - } - } - // if (ops.length>1) console.log(ops.length); - - Promise.all(ops).then( () => { - self.reading = false; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - self._tryClose(); - }); - - function getNewPage() { - if (self.avBuffs.length>0) { - const p = self.avBuffs.shift(); - p.dirty = false; - p.pendingOps = 1; - p.size =0; - return p; - } else { - return { - dirty: false, - buff: new Uint8Array(self.pageSize), - pendingOps: 1, - size: 0 - }; - } - } - - } - - - _triggerWrite() { - const self = this; - if (self.writing) return; - - const pageIdxs = Object.keys(self.pages); - - const ops = []; - - for (let i=0; i { - page.writing = false; - return; - }, (err) => { - console.log("ERROR Writing: "+err); - self.error = err; - self._tryClose(); - })); - } - } - - if (self.writing) { - Promise.all(ops).then( () => { - self.writing = false; - setImmediate(self._triggerWrite.bind(self)); - self._tryClose(); - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - }); - } - } - - _getDirtyPage() { - for (let p in this.pages) { - if (this.pages[p].dirty) return p; - } - return -1; - } - - // Iterate the actually-cached pages (usually few) rather than every page - // index in [firstPage, lastPage], so the check stays O(cached pages) even - // for very large ranges / small page sizes. - _rangeHasCachedPages(pos, len) { - const firstPage = Math.floor(pos / this.pageSize); - const lastPage = Math.floor((pos + len - 1) / this.pageSize); - for (const k of Object.keys(this.pages)) { - const p = +k; - if (p >= firstPage && p <= lastPage) return true; - } - return false; - } - - async write(buff, pos) { - if (buff.byteLength == 0) return; - const self = this; - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+buff.byteLength; - if (self.totalSize < pos + buff.byteLength) self.totalSize = pos + buff.byteLength; - if (self.pendingClose) - throw new Error("Writing a closing file"); - - // Direct-write fast path: for large writes to a region with no cached - // pages, write straight to disk, skipping the buff->page copy and the - // deferred page flush. Any cached page in range (even clean) would go - // stale after a direct write, so we fall back to the cached path then. - // ArrayBuffer.isView gate: fd.write needs a real TypedArray/DataView; a - // BigBuffer (paged, not a view) must use the cached path. - if (buff.byteLength >= self.directWriteThreshold && ArrayBuffer.isView(buff) && !self._rangeHasCachedPages(pos, buff.byteLength)) { - let done = 0; - while (done < buff.byteLength) { - const { bytesWritten } = await self.fd.write(buff, done, buff.byteLength - done, pos + done); - if (bytesWritten === 0) break; // should not happen - done += bytesWritten; - } - const lastPage = Math.floor((pos + buff.byteLength - 1) / self.pageSize); - if (lastPage + 1 > self.totalPages) self.totalPages = lastPage + 1; - return; - } - - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + buff.byteLength -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - let r = buff.byteLength; - while (r>0) { - await pagePromises[p-firstPage]; - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = buff.slice( buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.pages[p].buff.buffer, o, l); - dstView.set(srcView); - self.pages[p].dirty = true; - self.pages[p].pendingOps --; - self.pages[p].size = Math.max(o+l, self.pages[p].size); - if (p>=self.totalPages) { - self.totalPages = p+1; - } - r = r-l; - p ++; - o = 0; - if (!self.writing) setImmediate(self._triggerWrite.bind(self)); - } - } - - async read(len, pos) { - const self = this; - let buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - // Iterate the actually-cached pages (usually few) rather than every page - // index in [firstPage, lastPage], so the check stays O(cached pages) even - // for very large ranges / small page sizes. - _rangeHasDirtyPages(pos, len) { - const firstPage = Math.floor(pos / this.pageSize); - const lastPage = Math.floor((pos + len - 1) / this.pageSize); - for (const k of Object.keys(this.pages)) { - const p = +k; - if (p >= firstPage && p <= lastPage) { - const page = this.pages[p]; - if (page.dirty || page.writing) return true; - } - } - return false; - } - - async readToBuffer(buffDst, offset, len, pos) { - if (len == 0) { - return; - } - const self = this; - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+len; - if (self.pendingClose) - throw new Error("Reading a closing file"); - - // Direct-read fast path: for large reads with no overlapping unwritten - // (dirty) pages, copy straight from disk into the destination buffer. - // This skips the page cache and the page->destination copy it incurs, - // which dominates large sequential reads (e.g. zkey/ptau sections). - // ArrayBuffer.isView gate: the direct path hands buffDst to fd.read, which - // needs a real TypedArray/DataView. A BigBuffer (paged, not a view) must - // go through the cached path, which copies into it via its own .set(). - if (len >= self.directReadThreshold && ArrayBuffer.isView(buffDst) && !self._rangeHasDirtyPages(pos, len)) { - let toRead = (pos + len > self.totalSize) ? (self.totalSize - pos) : len; - if (toRead < 0) toRead = 0; - let done = 0; - while (done < toRead) { - const { bytesRead } = await self.fd.read(buffDst, offset + done, toRead - done, pos + done); - if (bytesRead === 0) break; // EOF - done += bytesRead; - } - return; - } - - if (len > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(len * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + len -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - // Remaining bytes to read - let r = pos + len > self.totalSize ? len - (pos + len - self.totalSize): len; - while (r>0) { - await pagePromises[p - firstPage]; - self.__statusPage("After Await (read): ", p); - - // bytes to copy from this page - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = new Uint8Array(self.pages[p].buff.buffer, self.pages[p].buff.byteOffset + o, l); - buffDst.set(srcView, offset+len-r); - self.pages[p].pendingOps --; - - self.__statusPage("After Op done: ", p); - - r = r-l; - p ++; - o = 0; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - } - - this.pos = pos + len; - - } - - - _tryClose() { - const self = this; - if (!self.pendingClose) return; - if (self.error) { - self.pendingCloseReject(self.error); - } - const p = self._getDirtyPage(); - if ((p>=0) || (self.writing) || (self.reading) || (self.pendingLoads.length>0)) return; - self.pendingClose(); - } - - close() { - const self = this; - if (self.pendingClose) - throw new Error("Closing the file twice"); - return new Promise((resolve, reject) => { - self.pendingClose = resolve; - self.pendingCloseReject = reject; - self._tryClose(); - }).then(()=> { - self.fd.close(); - }, (err) => { - self.fd.close(); - throw (err); - }); - } - - async discard() { - const self = this; - await self.close(); - await fs.promises.unlink(this.fileName); - } - - async writeULE32(v, pos) { - const self = this; - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, true); - - await self.write(tmpBuff32, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, false); - - await self.write(tmpBuff32, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - const tmpBuff64 = new Uint8Array(8); - const tmpBuff64v = new DataView(tmpBuff64.buffer); - - tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64, pos); - } - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - if (self.pendingClose) { - throw new Error("Reading a closing file"); - } - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - let currentPage = Math.floor(currentPosition / self.pageSize); - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - //Read page - let pagePromise = self._loadPage(currentPage); - self._triggerLoad(); - await pagePromise; - self.__statusPage("After Await (read): ", currentPage); - - let offsetOnPage = currentPosition % self.pageSize; - - const dataArray = new Uint8Array( - self.pages[currentPage].buff.buffer, - self.pages[currentPage].buff.byteOffset + offsetOnPage, - self.pageSize - offsetOnPage - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * this.pageSize + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * this.pageSize + offsetOnPage + dataArray.length; - } - - self.pages[currentPage].pendingOps--; - self.__statusPage("After Op done: ", currentPage); - - currentPosition = self.pos; - currentPage++; - - if (self.pendingLoads.length > 0) setImmediate(self._triggerLoad.bind(self)); - } - - return str; - } -}; - -function createNew$3(o) { - const initialSize = o.initialSize || 1<<20; - const fd = new MemFile$2(); - fd.o = o; - fd.o.data = new Uint8Array(initialSize); - fd.allocSize = initialSize; - fd.totalSize = 0; - fd.readOnly = false; - fd.pos = 0; - return fd; -} - -function readExisting$8(o) { - const fd = new MemFile$2(); - fd.o = o; - fd.allocSize = o.data.byteLength; - fd.totalSize = o.data.byteLength; - fd.readOnly = true; - fd.pos = 0; - return fd; -} - -const tmpBuff32$5 = new Uint8Array(4); -const tmpBuff32v$5 = new DataView(tmpBuff32$5.buffer); -const tmpBuff64$5 = new Uint8Array(8); -const tmpBuff64v$5 = new DataView(tmpBuff64$5.buffer); - -let MemFile$2 = class MemFile { - - constructor() { - this.pageSize = 1 << 14; // for compatibility - } - - _resizeIfNeeded(newLen) { - if (newLen > this.allocSize) { - const newAllocSize = Math.max( - this.allocSize + (1 << 20), - Math.floor(this.allocSize * 1.1), - newLen - ); - const newData = new Uint8Array(newAllocSize); - newData.set(this.o.data); - this.o.data = newData; - this.allocSize = newAllocSize; - } - } - - async write(buff, pos) { - const self =this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) throw new Error("Writing a read only file"); - - this._resizeIfNeeded(pos + buff.byteLength); - - this.o.data.set(buff.slice(), pos); - - if (pos + buff.byteLength > this.totalSize) this.totalSize = pos + buff.byteLength; - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDest, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const buffSrc = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + pos, len); - - buffDest.set(buffSrc, offset); - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - - const buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - if (this.o.data.byteLength != this.totalSize) { - this.o.data = this.o.data.slice(0, this.totalSize); - } - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$5.setUint32(0, v, true); - - await self.write(tmpBuff32$5, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$5.setUint32(0, v, false); - - await self.write(tmpBuff32$5, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$5.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$5.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$5, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - const dataArray = new Uint8Array( - self.o.data.buffer, - currentPosition, - this.totalSize - currentPosition - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - let endOfStringFound = indexEndOfString !== -1; - - let str = ""; - if (endOfStringFound) { - str = new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPosition + indexEndOfString + 1; - } else { - self.pos = currentPosition; - } - return str; - } +import * as e from "@iden3/binfileutils"; +import { createBinFile as t, endWriteSection as n, readBinFile as r, readSection as i, startWriteSection as a, writeBigInt as o } from "@iden3/binfileutils"; +import { BigBuffer as s, ChaCha as c, F1Field as l, Scalar as u, buildBls12381 as d, buildBn128 as f, utils as p } from "ffjavascript"; +import { readR1cs as m, readR1csFd as h, readR1csHeader as g } from "r1csfile"; +//#region \0rolldown/runtime.js +var _ = Object.defineProperty, v = (e, t) => { + let n = {}; + for (var r in e) _(n, r, { + get: e[r], + enumerable: !0 + }); + return t || _(n, Symbol.toStringTag, { value: "Module" }), n; +}, y = /* @__PURE__ */ v({ + getCurveFromName: () => E, + getCurveFromQ: () => T, + getCurveFromR: () => w +}), b = u.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16), x = u.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"), S = u.e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16), C = u.e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); +async function w(e, t) { + let n, r = t && t.singleThread; + if (u.eq(e, x)) n = await f(r); + else if (u.eq(e, b)) n = await d(r); + else throw Error(`Curve not supported: ${u.toString(e)}`); + return n; +} +async function T(e, t) { + let n, r = t && t.singleThread; + if (u.eq(e, C)) n = await f(r); + else if (u.eq(e, S)) n = await d(r); + else throw Error(`Curve not supported: ${u.toString(e)}`); + return n; +} +async function E(e, t) { + let n, r = t && t.singleThread, i = a(e); + if ([ + "BN128", + "BN254", + "ALTBN128" + ].indexOf(i) >= 0) n = await f(r); + else if (["BLS12381"].indexOf(i) >= 0) n = await d(r); + else throw Error(`Curve not supported: ${e}`); + return n; + function a(e) { + return e.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); + } +} +//#endregion +//#region node_modules/@noble/hashes/utils.js +function D(e) { + return e instanceof Uint8Array || ArrayBuffer.isView(e) && e.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in e && e.BYTES_PER_ELEMENT === 1; +} +function O(e, t = "") { + if (typeof e != "number") { + let n = t && `"${t}" `; + throw TypeError(`${n}expected number, got ${typeof e}`); + } + if (!Number.isSafeInteger(e) || e < 0) { + let n = t && `"${t}" `; + throw RangeError(`${n}expected integer >= 0, got ${e}`); + } +} +function k(e, t, n = "") { + let r = D(e), i = e?.length, a = t !== void 0; + if (!r || a && i !== t) { + let o = n && `"${n}" `, s = a ? ` of length ${t}` : "", c = r ? `length=${i}` : `type=${typeof e}`, l = o + "expected Uint8Array" + s + ", got " + c; + throw r ? RangeError(l) : TypeError(l); + } + return e; +} +function A(e, t = !0) { + if (e.destroyed) throw Error("Hash instance has been destroyed"); + if (t && e.finished) throw Error("Hash#digest() has already been called"); +} +function j(e, t) { + k(e, void 0, "digestInto() output"); + let n = t.outputLen; + if (e.length < n) throw RangeError("\"digestInto() output\" expected to be of length >=" + n); +} +function M(e) { + return new Uint32Array(e.buffer, e.byteOffset, Math.floor(e.byteLength / 4)); +} +function N(...e) { + for (let t = 0; t < e.length; t++) e[t].fill(0); +} +var P = new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68; +function F(e) { + return e << 24 & 4278190080 | e << 8 & 16711680 | e >>> 8 & 65280 | e >>> 24 & 255; +} +var I = P ? (e) => e : (e) => F(e) >>> 0; +function ee(e) { + for (let t = 0; t < e.length; t++) e[t] = F(e[t]); + return e; +} +var L = P ? (e) => e : ee; +function R(e, t = {}) { + let n = (t, n) => e(n).update(t).digest(), r = e(void 0); + return n.outputLen = r.outputLen, n.blockLen = r.blockLen, n.canXOF = r.canXOF, n.create = (t) => e(t), Object.assign(n, t), Object.freeze(n); +} +//#endregion +//#region node_modules/@noble/hashes/_blake.js +var z = /* @__PURE__ */ Uint8Array.from([ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 14, + 10, + 4, + 8, + 9, + 15, + 13, + 6, + 1, + 12, + 0, + 2, + 11, + 7, + 5, + 3, + 11, + 8, + 12, + 0, + 5, + 2, + 15, + 13, + 10, + 14, + 3, + 6, + 7, + 1, + 9, + 4, + 7, + 9, + 3, + 1, + 13, + 12, + 11, + 14, + 2, + 6, + 5, + 10, + 4, + 0, + 15, + 8, + 9, + 0, + 5, + 7, + 2, + 4, + 10, + 15, + 14, + 1, + 11, + 12, + 6, + 8, + 3, + 13, + 2, + 12, + 6, + 10, + 0, + 11, + 8, + 3, + 4, + 13, + 7, + 5, + 15, + 14, + 1, + 9, + 12, + 5, + 1, + 15, + 14, + 13, + 4, + 10, + 0, + 7, + 6, + 3, + 9, + 2, + 8, + 11, + 13, + 11, + 7, + 14, + 12, + 1, + 3, + 9, + 5, + 0, + 15, + 4, + 8, + 6, + 2, + 10, + 6, + 15, + 14, + 9, + 11, + 3, + 0, + 8, + 12, + 2, + 13, + 7, + 1, + 4, + 10, + 5, + 10, + 2, + 8, + 4, + 7, + 6, + 1, + 5, + 15, + 11, + 9, + 14, + 3, + 12, + 13, + 0, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 14, + 10, + 4, + 8, + 9, + 15, + 13, + 6, + 1, + 12, + 0, + 2, + 11, + 7, + 5, + 3, + 11, + 8, + 12, + 0, + 5, + 2, + 15, + 13, + 10, + 14, + 3, + 6, + 7, + 1, + 9, + 4, + 7, + 9, + 3, + 1, + 13, + 12, + 11, + 14, + 2, + 6, + 5, + 10, + 4, + 0, + 15, + 8, + 9, + 0, + 5, + 7, + 2, + 4, + 10, + 15, + 14, + 1, + 11, + 12, + 6, + 8, + 3, + 13, + 2, + 12, + 6, + 10, + 0, + 11, + 8, + 3, + 4, + 13, + 7, + 5, + 15, + 14, + 1, + 9 +]), B = /* @__PURE__ */ BigInt(2 ** 32 - 1), te = /* @__PURE__ */ BigInt(32); +function ne(e, t = !1) { + return t ? { + h: Number(e & B), + l: Number(e >> te & B) + } : { + h: Number(e >> te & B) | 0, + l: Number(e & B) | 0 + }; +} +function V(e, t = !1) { + let n = e.length, r = new Uint32Array(n), i = new Uint32Array(n); + for (let a = 0; a < n; a++) { + let { h: n, l: o } = ne(e[a], t); + [r[a], i[a]] = [n, o]; + } + return [r, i]; +} +var H = (e, t, n) => e >>> n | t << 32 - n, re = (e, t, n) => e << 32 - n | t >>> n, ie = (e, t, n) => e << 64 - n | t >>> n - 32, ae = (e, t, n) => e >>> n - 32 | t << 64 - n, oe = (e, t) => t, se = (e, t) => e, ce = (e, t, n) => e << n | t >>> 32 - n, le = (e, t, n) => t << n | e >>> 32 - n, ue = (e, t, n) => t << n - 32 | e >>> 64 - n, de = (e, t, n) => e << n - 32 | t >>> 64 - n; +function fe(e, t, n, r) { + let i = (t >>> 0) + (r >>> 0); + return { + h: e + n + (i / 2 ** 32 | 0) | 0, + l: i | 0 + }; +} +var pe = (e, t, n) => (e >>> 0) + (t >>> 0) + (n >>> 0), me = (e, t, n, r) => t + n + r + (e / 2 ** 32 | 0) | 0, U = /* @__PURE__ */ Uint32Array.from([ + 4089235720, + 1779033703, + 2227873595, + 3144134277, + 4271175723, + 1013904242, + 1595750129, + 2773480762, + 2917565137, + 1359893119, + 725511199, + 2600822924, + 4215389547, + 528734635, + 327033209, + 1541459225 +]), W = /* @__PURE__ */ new Uint32Array(32); +function he(e, t, n, r, i, a) { + let o = i[a], s = i[a + 1], c = W[2 * e], l = W[2 * e + 1], u = W[2 * t], d = W[2 * t + 1], f = W[2 * n], p = W[2 * n + 1], m = W[2 * r], h = W[2 * r + 1], g = pe(c, u, o); + l = me(g, l, d, s), c = g | 0, {Dh: h, Dl: m} = { + Dh: h ^ l, + Dl: m ^ c + }, {Dh: h, Dl: m} = { + Dh: oe(h, m), + Dl: se(h, m) + }, {h: p, l: f} = fe(p, f, h, m), {Bh: d, Bl: u} = { + Bh: d ^ p, + Bl: u ^ f + }, {Bh: d, Bl: u} = { + Bh: H(d, u, 24), + Bl: re(d, u, 24) + }, W[2 * e] = c, W[2 * e + 1] = l, W[2 * t] = u, W[2 * t + 1] = d, W[2 * n] = f, W[2 * n + 1] = p, W[2 * r] = m, W[2 * r + 1] = h; +} +function ge(e, t, n, r, i, a) { + let o = i[a], s = i[a + 1], c = W[2 * e], l = W[2 * e + 1], u = W[2 * t], d = W[2 * t + 1], f = W[2 * n], p = W[2 * n + 1], m = W[2 * r], h = W[2 * r + 1], g = pe(c, u, o); + l = me(g, l, d, s), c = g | 0, {Dh: h, Dl: m} = { + Dh: h ^ l, + Dl: m ^ c + }, {Dh: h, Dl: m} = { + Dh: H(h, m, 16), + Dl: re(h, m, 16) + }, {h: p, l: f} = fe(p, f, h, m), {Bh: d, Bl: u} = { + Bh: d ^ p, + Bl: u ^ f + }, {Bh: d, Bl: u} = { + Bh: ie(d, u, 63), + Bl: ae(d, u, 63) + }, W[2 * e] = c, W[2 * e + 1] = l, W[2 * t] = u, W[2 * t + 1] = d, W[2 * n] = f, W[2 * n + 1] = p, W[2 * r] = m, W[2 * r + 1] = h; +} +function _e(e, t = {}, n, r, i) { + if (O(n), e <= 0 || e > n) throw Error("outputLen bigger than keyLen"); + let { key: a, salt: o, personalization: s } = t; + if (a !== void 0 && (a.length < 1 || a.length > n)) throw Error("\"key\" expected to be undefined or of length=1.." + n); + o !== void 0 && k(o, r, "salt"), s !== void 0 && k(s, i, "personalization"); +} +var ve = class { + buffer; + buffer32; + finished = !1; + destroyed = !1; + length = 0; + pos = 0; + blockLen; + outputLen; + canXOF = !1; + constructor(e, t) { + O(e), O(t), this.blockLen = e, this.outputLen = t, this.buffer = new Uint8Array(e), this.buffer32 = M(this.buffer); + } + update(e) { + A(this), k(e); + let { blockLen: t, buffer: n, buffer32: r } = this, i = e.length, a = e.byteOffset, o = e.buffer; + for (let s = 0; s < i;) { + this.pos === t && (L(r), this.compress(r, 0, !1), L(r), this.pos = 0); + let c = Math.min(t - this.pos, i - s), l = a + s; + if (c === t && !(l % 4) && s + c < i) { + let e = new Uint32Array(o, l, Math.floor((i - s) / 4)); + L(e); + for (let n = 0; s + t < i; n += r.length, s += t) this.length += t, this.compress(e, n, !1); + L(e); + continue; + } + n.set(e.subarray(s, s + c), this.pos), this.pos += c, this.length += c, s += c; + } + return this; + } + digestInto(e) { + A(this), j(e, this); + let { pos: t, buffer32: n } = this; + if (this.finished = !0, N(this.buffer.subarray(t)), L(n), this.compress(n, 0, !0), L(n), e.byteOffset & 3) throw RangeError("\"digestInto() output\" expected 4-byte aligned byteOffset, got " + e.byteOffset); + let r = this.get(), i = M(e), a = Math.floor(this.outputLen / 4); + for (let e = 0; e < a; e++) i[e] = I(r[e]); + let o = this.outputLen % 4; + if (!o) return; + let s = a * 4, c = r[a]; + for (let t = 0; t < o; t++) e[s + t] = c >>> 8 * t; + } + digest() { + let { buffer: e, outputLen: t } = this; + this.digestInto(e); + let n = e.slice(0, t); + return this.destroy(), n; + } + _cloneInto(e) { + let { buffer: t, length: n, finished: r, destroyed: i, outputLen: a, pos: o } = this; + return e ||= new this.constructor({ dkLen: a }), e.set(...this.get()), e.buffer.set(t), e.destroyed = i, e.finished = r, e.length = n, e.pos = o, e.outputLen = a, e; + } + clone() { + return this._cloneInto(); + } +}, ye = class extends ve { + v0l = U[0] | 0; + v0h = U[1] | 0; + v1l = U[2] | 0; + v1h = U[3] | 0; + v2l = U[4] | 0; + v2h = U[5] | 0; + v3l = U[6] | 0; + v3h = U[7] | 0; + v4l = U[8] | 0; + v4h = U[9] | 0; + v5l = U[10] | 0; + v5h = U[11] | 0; + v6l = U[12] | 0; + v6h = U[13] | 0; + v7l = U[14] | 0; + v7h = U[15] | 0; + constructor(e = {}) { + let t = e.dkLen === void 0 ? 64 : e.dkLen; + super(128, t), _e(t, e, 64, 16, 16); + let { key: n, personalization: r, salt: i } = e, a = 0; + if (n !== void 0 && (k(n, void 0, "key"), a = n.length), this.v0l ^= this.outputLen | a << 8 | 16842752, i !== void 0) { + k(i, void 0, "salt"); + let e = M(i); + this.v4l ^= I(e[0]), this.v4h ^= I(e[1]), this.v5l ^= I(e[2]), this.v5h ^= I(e[3]); + } + if (r !== void 0) { + k(r, void 0, "personalization"); + let e = M(r); + this.v6l ^= I(e[0]), this.v6h ^= I(e[1]), this.v7l ^= I(e[2]), this.v7h ^= I(e[3]); + } + if (n !== void 0) { + let e = new Uint8Array(this.blockLen); + e.set(n), this.update(e); + } + } + get() { + let { v0l: e, v0h: t, v1l: n, v1h: r, v2l: i, v2h: a, v3l: o, v3h: s, v4l: c, v4h: l, v5l: u, v5h: d, v6l: f, v6h: p, v7l: m, v7h: h } = this; + return [ + e, + t, + n, + r, + i, + a, + o, + s, + c, + l, + u, + d, + f, + p, + m, + h + ]; + } + set(e, t, n, r, i, a, o, s, c, l, u, d, f, p, m, h) { + this.v0l = e | 0, this.v0h = t | 0, this.v1l = n | 0, this.v1h = r | 0, this.v2l = i | 0, this.v2h = a | 0, this.v3l = o | 0, this.v3h = s | 0, this.v4l = c | 0, this.v4h = l | 0, this.v5l = u | 0, this.v5h = d | 0, this.v6l = f | 0, this.v6h = p | 0, this.v7l = m | 0, this.v7h = h | 0; + } + compress(e, t, n) { + this.get().forEach((e, t) => W[t] = e), W.set(U, 16); + let { h: r, l: i } = ne(BigInt(this.length)); + W[24] = U[8] ^ i, W[25] = U[9] ^ r, n && (W[28] = ~W[28], W[29] = ~W[29]); + let a = 0, o = z; + for (let n = 0; n < 12; n++) he(0, 4, 8, 12, e, t + 2 * o[a++]), ge(0, 4, 8, 12, e, t + 2 * o[a++]), he(1, 5, 9, 13, e, t + 2 * o[a++]), ge(1, 5, 9, 13, e, t + 2 * o[a++]), he(2, 6, 10, 14, e, t + 2 * o[a++]), ge(2, 6, 10, 14, e, t + 2 * o[a++]), he(3, 7, 11, 15, e, t + 2 * o[a++]), ge(3, 7, 11, 15, e, t + 2 * o[a++]), he(0, 5, 10, 15, e, t + 2 * o[a++]), ge(0, 5, 10, 15, e, t + 2 * o[a++]), he(1, 6, 11, 12, e, t + 2 * o[a++]), ge(1, 6, 11, 12, e, t + 2 * o[a++]), he(2, 7, 8, 13, e, t + 2 * o[a++]), ge(2, 7, 8, 13, e, t + 2 * o[a++]), he(3, 4, 9, 14, e, t + 2 * o[a++]), ge(3, 4, 9, 14, e, t + 2 * o[a++]); + this.v0l ^= W[0] ^ W[16], this.v0h ^= W[1] ^ W[17], this.v1l ^= W[2] ^ W[18], this.v1h ^= W[3] ^ W[19], this.v2l ^= W[4] ^ W[20], this.v2h ^= W[5] ^ W[21], this.v3l ^= W[6] ^ W[22], this.v3h ^= W[7] ^ W[23], this.v4l ^= W[8] ^ W[24], this.v4h ^= W[9] ^ W[25], this.v5l ^= W[10] ^ W[26], this.v5h ^= W[11] ^ W[27], this.v6l ^= W[12] ^ W[28], this.v6h ^= W[13] ^ W[29], this.v7l ^= W[14] ^ W[30], this.v7h ^= W[15] ^ W[31], N(W); + } + destroy() { + this.destroyed = !0, N(this.buffer32), this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } +}, G = /* @__PURE__ */ R((e) => new ye(e)), be = {}, xe = []; +for (let e = 0; e < 256; e++) xe[e] = Se(e, 8); +function Se(e, t) { + let n = 0, r = e; + for (let e = 0; e < t; e++) n <<= 1, n |= r & 1, r >>= 1; + return n; +} +function Ce(e) { + return (e & 4294901760 ? (e &= 4294901760, 16) : 0) | (e & 4278255360 ? (e &= 4278255360, 8) : 0) | (e & 4042322160 ? (e &= 4042322160, 4) : 0) | (e & 3435973836 ? (e &= 3435973836, 2) : 0) | (e & 2863311530) != 0; +} +function K(e, t) { + let n = new DataView(e.buffer, e.byteOffset, e.byteLength), r = ""; + for (let e = 0; e < 4; e++) { + e > 0 && (r += "\n"), r += " "; + for (let t = 0; t < 4; t++) t > 0 && (r += " "), r += n.getUint32(e * 16 + t * 4).toString(16).padStart(8, "0"); + } + return t && (r = t + "\n" + r), r; +} +function we(e, t) { + if (e.byteLength != t.byteLength) return !1; + for (var n = new Int8Array(e), r = new Int8Array(t), i = 0; i != e.byteLength; i++) if (n[i] != r[i]) return !1; + return !0; +} +function Te(e) { + return e.clone(); +} +function Ee(e) { + let t = e.subarray(0, 128), n = M(e.subarray(128)), r = G.create({ dkLen: 64 }); + r.buffer.set(t), r.v0l = n[0] | 0, r.v0h = n[1] | 0, r.v1l = n[2] | 0, r.v1h = n[3] | 0, r.v2l = n[4] | 0, r.v2h = n[5] | 0, r.v3l = n[6] | 0, r.v3h = n[7] | 0, r.v4l = n[8] | 0, r.v4h = n[9] | 0, r.v5l = n[10] | 0, r.v5h = n[11] | 0, r.v6l = n[12] | 0, r.v6h = n[13] | 0, r.v7l = n[14] | 0, r.v7h = n[15] | 0; + let i = 2 ** 32, a = n[16] + n[17] * i, o = n[18] + n[19] * i; + return r.length = a + o, r.pos = o, r; +} +function De(e) { + let t = /* @__PURE__ */ new Uint8Array(216), n = M(t.subarray(128)); + return t.set(e.buffer), n[0] = e.v0l, n[1] = e.v0h, n[2] = e.v1l, n[3] = e.v1h, n[4] = e.v2l, n[5] = e.v2h, n[6] = e.v3l, n[7] = e.v3h, n[8] = e.v4l, n[9] = e.v4h, n[10] = e.v5l, n[11] = e.v5h, n[12] = e.v6l, n[13] = e.v6h, n[14] = e.v7l, n[15] = e.v7h, n[18] = e.pos, n[16] = e.length - e.pos, t; +} +async function Oe(e, t, n, r, i) { + return e.G1.isZero(t) || e.G1.isZero(n) || e.G2.isZero(r) || e.G2.isZero(i) ? !1 : await e.pairingEq(t, i, e.G1.neg(n), r); +} +function ke() { + if (typeof window < "u" && typeof window.prompt == "function") return window.prompt("Enter a random text. (Entropy): ", ""); + { + let e = be.createInterface({ + input: process.stdin, + output: process.stdout + }); + return new Promise((t) => { + e.question("Enter a random text. (Entropy): ", (e) => t(e)); + }); + } +} +function Ae(e) { + let t = new Uint8Array(e); + if (be && be.randomFillSync) be.randomFillSync(t); + else if (globalThis.crypto !== void 0 && globalThis.crypto.getRandomValues) for (let n = 0; n < e; n += 65536) globalThis.crypto.getRandomValues(t.subarray(n, Math.min(n + 65536, e))); + else throw Error("No secure random source available"); + return t; +} +async function je(e) { + if (be && be.createHash) return be.createHash("sha256").update(e).digest(); + { + let t = await globalThis.crypto.subtle.digest("SHA-256", e); + return new Uint8Array(t); + } +} +function Me(e, t) { + return new DataView(e.buffer).getUint32(t, !1); +} +async function Ne(e) { + for (; !e;) e = await ke(); + let t = G.create(64); + t.update(Ae(64)); + let n = new TextEncoder(); + t.update(n.encode(e)); + let r = t.digest(), i = []; + for (let e = 0; e < 8; e++) i[e] = Me(r, e * 4); + return new c(i); +} +async function Pe(e, t) { + let n, r; + t < 32 ? (n = 1 << t >>> 0, r = 1) : (n = 4294967296, r = 1 << t - 32 >>> 0); + let i = e; + for (let e = 0; e < r; e++) for (let e = 0; e < n; e++) i = await je(i); + let a = new DataView(i.buffer, i.byteOffset, i.byteLength), o = []; + for (let e = 0; e < 8; e++) o[e] = a.getUint32(e * 4, !1); + return new c(o); +} +function Fe(e) { + return e instanceof Uint8Array ? e : (e.slice(0, 2) == "0x" && (e = e.slice(2)), new Uint8Array(e.match(/[\da-f]{2}/gi).map(function(e) { + return parseInt(e, 16); + }))); +} +function Ie(e) { + return Array.prototype.map.call(e, function(e) { + return ("0" + (e & 255).toString(16)).slice(-2); + }).join(""); +} +function Le(e, t) { + if (t instanceof Uint8Array) return e.toString(t); + if (Array.isArray(t)) return t.map(Le.bind(null, e)); + if (typeof t == "object") { + let n = {}; + return Object.keys(t).forEach((r) => { + n[r] = Le(e, t[r]); + }), n; + } else if (typeof t == "bigint" || t.eq !== void 0) return t.toString(10); + else return t; +} +//#endregion +//#region src/zkey_utils.js +async function Re(t, n) { + await e.startWriteSection(t, 1), await t.writeULE32(1), await e.endWriteSection(t); + let r = await T(n.q); + await e.startWriteSection(t, 2); + let i = r.q, a = (Math.floor((u.bitLength(i) - 1) / 64) + 1) * 8, o = r.r, s = (Math.floor((u.bitLength(o) - 1) / 64) + 1) * 8; + await t.writeULE32(a), await e.writeBigInt(t, i, a), await t.writeULE32(s), await e.writeBigInt(t, o, s), await t.writeULE32(n.nVars), await t.writeULE32(n.nPublic), await t.writeULE32(n.domainSize), await ze(t, r, n.vk_alpha_1), await ze(t, r, n.vk_beta_1), await Be(t, r, n.vk_beta_2), await Be(t, r, n.vk_gamma_2), await ze(t, r, n.vk_delta_1), await Be(t, r, n.vk_delta_2), await e.endWriteSection(t); +} +async function ze(e, t, n) { + let r = new Uint8Array(t.G1.F.n8 * 2); + t.G1.toRprLEM(r, 0, n), await e.write(r); +} +async function Be(e, t, n) { + let r = new Uint8Array(t.G2.F.n8 * 2); + t.G2.toRprLEM(r, 0, n), await e.write(r); +} +async function q(e, t, n) { + let r = await e.read(t.G1.F.n8 * 2), i = t.G1.fromRprLEM(r, 0); + return n ? t.G1.toObject(i) : i; +} +async function Ve(e, t, n) { + let r = await e.read(t.G2.F.n8 * 2), i = t.G2.fromRprLEM(r, 0); + return n ? t.G2.toObject(i) : i; +} +async function He(t, n, r, i) { + await e.startReadUniqueSection(t, n, 1); + let a = await t.readULE32(); + if (await e.endReadSection(t), a === 1) return await Ue(t, n, r, i); + if (a === 2) return await We(t, n, r, i); + if (a === 10) return await Ge(t, n, r, i); + throw Error("Protocol not supported: "); +} +async function Ue(t, n, r, i) { + let a = {}; + a.protocol = "groth16", await e.startReadUniqueSection(t, n, 2); + let o = await t.readULE32(); + a.n8q = o, a.q = await e.readBigInt(t, o); + let s = await t.readULE32(); + return a.n8r = s, a.r = await e.readBigInt(t, s), a.curve = await T(a.q, i), a.nVars = await t.readULE32(), a.nPublic = await t.readULE32(), a.domainSize = await t.readULE32(), a.power = Ce(a.domainSize), a.vk_alpha_1 = await q(t, a.curve, r), a.vk_beta_1 = await q(t, a.curve, r), a.vk_beta_2 = await Ve(t, a.curve, r), a.vk_gamma_2 = await Ve(t, a.curve, r), a.vk_delta_1 = await q(t, a.curve, r), a.vk_delta_2 = await Ve(t, a.curve, r), await e.endReadSection(t), a; +} +async function We(t, n, r, i) { + let a = {}; + a.protocol = "plonk", await e.startReadUniqueSection(t, n, 2); + let o = await t.readULE32(); + a.n8q = o, a.q = await e.readBigInt(t, o); + let s = await t.readULE32(); + return a.n8r = s, a.r = await e.readBigInt(t, s), a.curve = await T(a.q, i), a.nVars = await t.readULE32(), a.nPublic = await t.readULE32(), a.domainSize = await t.readULE32(), a.power = Ce(a.domainSize), a.nAdditions = await t.readULE32(), a.nConstraints = await t.readULE32(), a.k1 = await t.read(s), a.k2 = await t.read(s), a.Qm = await q(t, a.curve, r), a.Ql = await q(t, a.curve, r), a.Qr = await q(t, a.curve, r), a.Qo = await q(t, a.curve, r), a.Qc = await q(t, a.curve, r), a.S1 = await q(t, a.curve, r), a.S2 = await q(t, a.curve, r), a.S3 = await q(t, a.curve, r), a.X_2 = await Ve(t, a.curve, r), await e.endReadSection(t), a; +} +async function Ge(t, n, r, i) { + let a = {}; + a.protocol = "fflonk", a.protocolId = 10, await e.startReadUniqueSection(t, n, 2); + let o = await t.readULE32(); + a.n8q = o, a.q = await e.readBigInt(t, o), a.curve = await T(a.q, i); + let s = await t.readULE32(); + return a.n8r = s, a.r = await e.readBigInt(t, s), a.nVars = await t.readULE32(), a.nPublic = await t.readULE32(), a.domainSize = await t.readULE32(), a.power = Ce(a.domainSize), a.nAdditions = await t.readULE32(), a.nConstraints = await t.readULE32(), a.k1 = await t.read(s), a.k2 = await t.read(s), a.w3 = await t.read(s), a.w4 = await t.read(s), a.w8 = await t.read(s), a.wr = await t.read(s), a.X_2 = await Ve(t, a.curve, r), a.C0 = await q(t, a.curve, r), await e.endReadSection(t), a; +} +async function Ke(t, n) { + let { fd: r, sections: i } = await e.readBinFile(t, "zkey", 1), a = await He(r, i, n), o = new l(a.r), s = u.mod(u.shl(1, a.n8r * 8), a.r), c = o.inv(s), d = o.mul(c, c), f = await T(a.q); + await e.startReadUniqueSection(r, i, 3), a.IC = []; + for (let e = 0; e <= a.nPublic; e++) { + let e = await q(r, f, n); + a.IC.push(e); + } + await e.endReadSection(r), await e.startReadUniqueSection(r, i, 4); + let p = await r.readULE32(); + a.ccoefs = []; + for (let e = 0; e < p; e++) { + let e = await r.readULE32(), t = await r.readULE32(), i = await r.readULE32(), o = await m(n); + a.ccoefs.push({ + matrix: e, + constraint: t, + signal: i, + value: o + }); + } + await e.endReadSection(r), await e.startReadUniqueSection(r, i, 5), a.A = []; + for (let e = 0; e < a.nVars; e++) { + let t = await q(r, f, n); + a.A[e] = t; + } + await e.endReadSection(r), await e.startReadUniqueSection(r, i, 6), a.B1 = []; + for (let e = 0; e < a.nVars; e++) { + let t = await q(r, f, n); + a.B1[e] = t; + } + await e.endReadSection(r), await e.startReadUniqueSection(r, i, 7), a.B2 = []; + for (let e = 0; e < a.nVars; e++) { + let t = await Ve(r, f, n); + a.B2[e] = t; + } + await e.endReadSection(r), await e.startReadUniqueSection(r, i, 8), a.C = []; + for (let e = a.nPublic + 1; e < a.nVars; e++) { + let t = await q(r, f, n); + a.C[e] = t; + } + await e.endReadSection(r), await e.startReadUniqueSection(r, i, 9), a.hExps = []; + for (let e = 0; e < a.domainSize; e++) { + let e = await q(r, f, n); + a.hExps.push(e); + } + return await e.endReadSection(r), await r.close(), a; + async function m() { + let t = await e.readBigInt(r, a.n8r); + return o.mul(t, d); + } +} +async function qe(e, t, n) { + let r = { delta: {} }; + r.deltaAfter = await q(e, t, n), r.delta.g1_s = await q(e, t, n), r.delta.g1_sx = await q(e, t, n), r.delta.g2_spx = await Ve(e, t, n), r.transcript = await e.read(64), r.type = await e.readULE32(); + let i = await e.readULE32(), a = e.pos, o = 0; + for (; e.pos - a < i;) { + let t = await e.read(1); + if (t[0] <= o) throw Error("Parameters in the contribution must be sorted"); + if (o = t[0], t[0] == 1) { + let t = await e.read(1), n = await e.read(t[0]); + r.name = new TextDecoder().decode(n); + } else if (t[0] == 2) r.numIterationsExp = (await e.read(1))[0]; + else if (t[0] == 3) { + let t = await e.read(1); + r.beaconHash = await e.read(t[0]); + } else throw Error("Parameter not recognized"); + } + if (e.pos != a + i) throw Error("Parameters do not match"); + return r; +} +async function Je(t, n, r) { + await e.startReadUniqueSection(t, r, 10); + let i = { contributions: [] }; + i.csHash = await t.read(64); + let a = await t.readULE32(); + for (let e = 0; e < a; e++) { + let e = await qe(t, n); + i.contributions.push(e); + } + return await e.endReadSection(t), i; +} +async function Ye(e, t, n) { + await ze(e, t, n.deltaAfter), await ze(e, t, n.delta.g1_s), await ze(e, t, n.delta.g1_sx), await Be(e, t, n.delta.g2_spx), await e.write(n.transcript), await e.writeULE32(n.type || 0); + let r = []; + if (n.name) { + r.push(1); + let e = new TextEncoder("utf-8").encode(n.name.substring(0, 64)); + r.push(e.byteLength); + for (let t = 0; t < e.byteLength; t++) r.push(e[t]); + } + if (n.type == 1) { + r.push(2), r.push(n.numIterationsExp), r.push(3), r.push(n.beaconHash.byteLength); + for (let e = 0; e < n.beaconHash.byteLength; e++) r.push(n.beaconHash[e]); + } + if (r.length > 0) { + let t = new Uint8Array(r); + await e.writeULE32(t.byteLength), await e.write(t); + } else await e.writeULE32(0); +} +async function Xe(t, n, r) { + await e.startWriteSection(t, 10), await t.write(r.csHash), await t.writeULE32(r.contributions.length); + for (let e = 0; e < r.contributions.length; e++) await Ye(t, n, r.contributions[e]); + await e.endWriteSection(t); +} +function Ze(e, t, n) { + let r = new Uint8Array(t.G1.F.n8 * 2); + t.G1.toRprUncompressed(r, 0, n), e.update(r); +} +function Qe(e, t, n) { + let r = new Uint8Array(t.G2.F.n8 * 2); + t.G2.toRprUncompressed(r, 0, n), e.update(r); +} +function $e(e, t, n) { + Ze(e, t, n.deltaAfter), Ze(e, t, n.delta.g1_s), Ze(e, t, n.delta.g1_sx), Qe(e, t, n.delta.g2_spx), e.update(n.transcript); +} +//#endregion +//#region src/wtns_utils.js +async function et(t, n, r) { + await e.startWriteSection(t, 1); + let i = (Math.floor((u.bitLength(r) - 1) / 64) + 1) * 8; + await t.writeULE32(i), await e.writeBigInt(t, r, i), await t.writeULE32(n.length), await e.endWriteSection(t), await e.startWriteSection(t, 2); + for (let r = 0; r < n.length; r++) await e.writeBigInt(t, n[r], i); + await e.endWriteSection(t, 2); +} +async function tt(t, n, r) { + await e.startWriteSection(t, 1); + let i = (Math.floor((u.bitLength(r) - 1) / 64) + 1) * 8; + if (await t.writeULE32(i), await e.writeBigInt(t, r, i), n.byteLength % i != 0) throw Error("Invalid witness length"); + await t.writeULE32(n.byteLength / i), await e.endWriteSection(t), await e.startWriteSection(t, 2), await t.write(n), await e.endWriteSection(t); +} +async function nt(t, n) { + await e.startReadUniqueSection(t, n, 1); + let r = await t.readULE32(), i = await e.readBigInt(t, r), a = await t.readULE32(); + return await e.endReadSection(t), { + n8: r, + q: i, + nWitness: a + }; +} +async function rt(t) { + let { fd: n, sections: r } = await e.readBinFile(t, "wtns", 2), { n8: i, nWitness: a } = await nt(n, r); + await e.startReadUniqueSection(n, r, 2); + let o = []; + for (let t = 0; t < a; t++) { + let t = await e.readBigInt(n, i); + o.push(t); + } + return await e.endReadSection(n), await n.close(), o; +} +//#endregion +//#region src/groth16_prove.js +var { stringifyBigInts: it } = p; +async function at(e, t, n, r) { + let i = null; + n && r && r.memoryLogging && typeof process < "u" && typeof process.memoryUsage == "function" && (i = ft(n, Number(r.memoryLogging) > 1 ? Number(r.memoryLogging) : 1e3)); + try { + return await ot(e, t, n, r); + } finally { + i && (clearInterval(i), dt(n)); + } +} +async function ot(t, n, r, i) { + let { fd: a, sections: o } = await e.readBinFile(n, "wtns", 2, 1 << 25, 1 << 23), s = await nt(a, o), { fd: c, sections: l } = await e.readBinFile(t, "zkey", 2, 1 << 25, 1 << 23), d = await He(c, l, void 0, i); + if (d.protocol != "groth16") throw Error("zkey file is not groth16"); + if (!u.eq(d.r, s.q)) throw Error("Curve of the witness does not match the curve of the proving key"); + if (s.nWitness != d.nVars) throw Error(`Invalid witness length. Circuit: ${d.nVars}, witness: ${s.nWitness}`); + let f = d.curve, p = f.Fr, m = f.G1, h = f.G2; + i ||= {}; + let g = i.msmBatching || "auto"; + if (g !== "auto" && g !== "enabled" && g !== "disabled") throw Error(`groth16Prove: invalid msmBatching "${g}" (expected "auto", "enabled" or "disabled")`); + let _ = i.msmGlv || "auto", v = i.msmGls || "auto"; + for (let [e, t] of [["msmGlv", _], ["msmGls", v]]) if (t !== "auto" && t !== "disabled") throw Error(`groth16Prove: invalid ${e} "${t}" (expected "auto" or "disabled")`); + let y = { + batch: g, + glv: _, + gls: v + }, b = Ce(d.domainSize); + r && r.debug("Reading Wtns"); + let x = await e.readSection(a, o, 2), S = (e) => { + let t = l[e][0].p, n = l[e][0].size; + return async (r, i) => { + if (r + i > n) throw Error(`groth16Prove: read out of range of section ${e}`); + let a = new Uint8Array(i); + return await c.readToBuffer(a, 0, i, t + r), a; + }; + }, C, w, T, E = (async function() { + let t, n, a; + await (async function() { + r && r.debug("Reading Coeffs"); + let o = await e.readSection(c, l, 4); + if (r && r.debug("Building ABC"), i.buildABC === "js") [t, n, a] = await st(f, d, x, o, r); + else if (i.buildABC === "stream") { + let e = ct(f, d, o, i); + [t, n, a] = await lt(f, d, x, o, r, e.nChunks, e.maxInFlight); + } else { + let e = ct(f, d, o, i); + r && r.debug(`buildABC: stream nChunks=${e.nChunks} maxInFlight=${e.maxInFlight}`), [t, n, a] = await lt(f, d, x, o, r, e.nChunks, e.maxInFlight); + } + })(); + let o = b === p.s ? f.Fr.shift : f.Fr.w[b + 1], s, u, m; + await Promise.all([ + (async function() { + let e = await p.ifft(t, "", "", r, "IFFT_A", !0); + t = null; + let n = await p.batchApplyKey(e, p.e(1), o); + s = await p.fft(n, "", "", r, "FFT_A", !0); + })(), + (async function() { + let e = await p.ifft(n, "", "", r, "IFFT_B", !0); + n = null; + let t = await p.batchApplyKey(e, p.e(1), o); + u = await p.fft(t, "", "", r, "FFT_B", !0); + })(), + (async function() { + let e = await p.ifft(a, "", "", r, "IFFT_C", !0); + a = null; + let t = await p.batchApplyKey(e, p.e(1), o); + m = await p.fft(t, "", "", r, "FFT_C", !0); + })() + ]), r && r.debug("Join ABC"), T = await ut(f, d, s, u, m, r), r && r.debug("Join ABC finished"), s = null, u = null, m = null, globalThis.gc && globalThis.gc(); + })(), D = {}; + async function O() { + r && r.debug("Reading A Points"), D.pi_a = await f.G1.multiExpAffineChunked(S(5), l[5][0].size, x, r, "multiexp A", y); + } + let k = O(), A; + async function j() { + r && r.debug("Reading B1 Points"), A = await f.G1.multiExpAffineChunked(S(6), l[6][0].size, x, r, "multiexp B1", y); + } + let M = j(); + async function N() { + r && r.debug("Reading B2 Points"), D.pi_b = await f.G2.multiExpAffineChunked(S(7), l[7][0].size, x, r, "multiexp B2", y); + } + let P = N(), F = (async function() { + r && r.debug("Reading C Points"), D.pi_c = await f.G1.multiExpAffineChunked(S(8), l[8][0].size, x.slice((d.nPublic + 1) * f.Fr.n8), r, "multiexp C", y); + })(); + w = (async function() { + r && r.debug("Reading H Points"), await E, C = await f.G1.multiExpAffineChunked(S(9), l[9][0].size, T, r, "multiexp H", y); + })(); + let I = f.Fr.random(), ee = f.Fr.random(); + await k, D.pi_a = m.add(D.pi_a, d.vk_alpha_1), D.pi_a = m.add(D.pi_a, m.timesFr(d.vk_delta_1, I)), await P, D.pi_b = h.add(D.pi_b, d.vk_beta_2), D.pi_b = h.add(D.pi_b, h.timesFr(d.vk_delta_2, ee)), await M, A = m.add(A, d.vk_beta_1), A = m.add(A, m.timesFr(d.vk_delta_1, ee)), await Promise.all([F, w]), D.pi_c = m.add(D.pi_c, C), D.pi_c = m.add(D.pi_c, m.timesFr(D.pi_a, ee)), D.pi_c = m.add(D.pi_c, m.timesFr(A, I)), D.pi_c = m.add(D.pi_c, m.timesFr(d.vk_delta_1, p.neg(p.mul(I, ee)))); + let L = []; + for (let e = 1; e <= d.nPublic; e++) { + let t = x.slice(e * p.n8, e * p.n8 + p.n8); + L.push(u.fromRprLE(t)); + } + return D.pi_a = m.toObject(m.toAffine(D.pi_a)), D.pi_b = h.toObject(h.toAffine(D.pi_b)), D.pi_c = m.toObject(m.toAffine(D.pi_c)), D.protocol = "groth16", D.curve = f.name, await c.close(), await a.close(), D = it(D), L = it(L), { + proof: D, + publicSignals: L + }; +} +async function st(e, t, n, r, i) { + let a = e.Fr.n8, o = 12 + t.n8r, c = (r.byteLength - 4) / o, l = new s(t.domainSize * a), u = new s(t.domainSize * a), d = new s(t.domainSize * a), f = [l, u]; + for (let t = 0; t < c; t++) { + i && t % 1e6 == 0 && i.debug(`QAP AB: ${t}/${c}`); + let s, l; + if (r.buffer) { + let e = 4 + t * o; + s = new DataView(r.buffer, r.byteOffset + e, o), l = new Uint8Array(r.buffer, r.byteOffset + e + 12, a); + } else { + let e = r.slice(4 + t * o, 4 + t * o + o); + s = new DataView(e.buffer), l = e.slice(12, 12 + a); + } + let u = s.getUint32(0, !0), d = s.getUint32(4, !0), p = s.getUint32(8, !0); + f[u].set(e.Fr.add(f[u].slice(d * a, d * a + a), e.Fr.mul(l, n.slice(p * a, p * a + a))), d * a), t % 1e6 == 0 && i && dt(i); + } + for (let n = 0; n < t.domainSize; n++) i && n % 1e6 == 0 && i.debug(`QAP C: ${n}/${t.domainSize}`), d.set(e.Fr.mul(l.slice(n * a, n * a + a), u.slice(n * a, n * a + a)), n * a); + return [ + l, + u, + d + ]; +} +function ct(e, t, n, r) { + r ||= {}; + let i = e.Fr.n8, a = e.tm.concurrency || 1, o = (n.byteLength - 4) / (12 + i), s = n.byteLength + o * i + 3 * t.domainSize * i, c = r.buildABCFloorBudget || 256 * 1024 * 1024, l = Math.max(1, Math.ceil(s / (32 * 1024 * 1024))), u = Math.ceil(s / l), d = Math.max(1, Math.min(a, Math.floor(c / u))); + return l = Math.min(256, Math.max(l, d * 3)), d = Math.min(d, l), r.buildABCnChunks && (l = r.buildABCnChunks), r.buildABCmaxInFlight && (d = r.buildABCmaxInFlight), { + nChunks: l, + maxInFlight: d + }; +} +async function lt(e, t, n, r, i, a, o) { + let c = e.Fr.n8, l = 12 + t.n8r, u = t.domainSize, d; + if (r instanceof s) { + let e = [], t = r.buffers[0].length; + for (let t = 0; t < r.buffers.length; t++) e.push(new DataView(r.buffers[t].buffer)); + d = (n) => e[Math.floor(n / t)].getUint32(n % t, !0); + } else { + let e = new DataView(r.buffer, r.byteOffset, r.byteLength); + d = (t) => e.getUint32(t, !0); + } + function f(e) { + let t = 0, n = d(0); + for (; t < n;) { + let r = Math.floor((n + t) / 2), i = d(4 + r * l + 4); + i > e ? n = r - 1 : i < e ? t = r + 1 : n = r; + } + return 4 + t * l; + } + let p = Math.floor((u - 1) / a) + 1, m = []; + for (let e = 0; e < a; e++) m.push(f(e * p)); + m.push(r.byteLength); + let h = u * c, g = () => h < 1 << 30 ? new Uint8Array(h) : new s(h), _ = g(), v = g(), y = g(), b = /* @__PURE__ */ new Set(), x = []; + for (let t = 0; t < a; t++) { + let s = t * p, d = Math.min(p, u - s); + if (d <= 0) break; + let f = m[t], h = m[t + 1]; + for (; b.size >= o;) await Promise.race(b); + i && i.debug(`buildABCStream: ${t}/${a}`); + let g = (async () => { + let t = r.slice(f, h), i = (h - f) / l, a = new Uint8Array(i * c), o = new Uint32Array(t.buffer, t.byteOffset, t.byteLength >> 2), u = l >> 2; + if (n.buffer && !(n.byteOffset & 3) && c === 32) { + let e = new Uint32Array(n.buffer, n.byteOffset, n.byteLength >> 2), t = new Uint32Array(a.buffer); + for (let n = 0; n < i; n++) { + let r = o[n * u + 2] << 3, i = n << 3; + t[i] = e[r], t[i + 1] = e[r + 1], t[i + 2] = e[r + 2], t[i + 3] = e[r + 3], t[i + 4] = e[r + 4], t[i + 5] = e[r + 5], t[i + 6] = e[r + 6], t[i + 7] = e[r + 7], o[n * u + 2] = n; + } + } else { + let e = !!n.buffer; + for (let t = 0; t < i; t++) { + let r = o[t * u + 2]; + e ? a.set(n.subarray(r * c, (r + 1) * c), t * c) : a.set(n.slice(r * c, (r + 1) * c), t * c), o[t * u + 2] = t; + } + } + let p = [ + { + cmd: "ALLOCSET", + var: 0, + buff: t + }, + { + cmd: "ALLOCSET", + var: 1, + buff: a + }, + { + cmd: "ALLOC", + var: 2, + len: d * c + }, + { + cmd: "ALLOC", + var: 3, + len: d * c + }, + { + cmd: "ALLOC", + var: 4, + len: d * c + }, + { + cmd: "CALL", + fnName: "qap_buildABC", + params: [ + { var: 0 }, + { val: i }, + { var: 1 }, + { var: 2 }, + { var: 3 }, + { var: 4 }, + { val: s }, + { val: d }, + { val: 0 }, + { val: i } + ] + }, + { + cmd: "GET", + out: 0, + var: 2, + len: d * c + }, + { + cmd: "GET", + out: 1, + var: 3, + len: d * c + }, + { + cmd: "GET", + out: 2, + var: 4, + len: d * c + } + ], m = await e.tm.queueAction(p, [t.buffer, a.buffer]); + _.set(m[0], s * c), v.set(m[1], s * c), y.set(m[2], s * c); + })().finally(() => b.delete(g)); + b.add(g), x.push(g); + } + return await Promise.all(x), [ + _, + v, + y + ]; +} +async function ut(e, t, n, r, i, a) { + let o = 65536, c = e.Fr.n8, l = Math.floor(n.byteLength / e.Fr.n8), u = []; + for (let t = 0; t < l; t += o) { + a && a.debug(`JoinABC: ${t}/${l}`); + let s = Math.min(l - t, o), d = [], f = n.slice(t * c, (t + s) * c), p = r.slice(t * c, (t + s) * c), m = i.slice(t * c, (t + s) * c); + d.push({ + cmd: "ALLOCSET", + var: 0, + buff: f + }), d.push({ + cmd: "ALLOCSET", + var: 1, + buff: p + }), d.push({ + cmd: "ALLOCSET", + var: 2, + buff: m + }), d.push({ + cmd: "ALLOC", + var: 3, + len: s * c + }), d.push({ + cmd: "CALL", + fnName: "qap_joinABC", + params: [ + { var: 0 }, + { var: 1 }, + { var: 2 }, + { val: s }, + { var: 3 } + ] + }), d.push({ + cmd: "CALL", + fnName: "frm_batchFromMontgomery", + params: [ + { var: 3 }, + { val: s }, + { var: 3 } + ] + }), d.push({ + cmd: "GET", + out: 0, + var: 3, + len: s * c + }), u.push(e.tm.queueAction(d, [ + f.buffer, + p.buffer, + m.buffer + ])); + } + let d = await Promise.all(u), f; + f = n instanceof s ? new s(n.byteLength) : new Uint8Array(n.byteLength); + let p = 0; + for (let e = 0; e < d.length; e++) f.set(d[e][0], p), p += d[e][0].byteLength; + return f; +} +function dt(e) { + if (!e) return; + let t = process.memoryUsage(); + e.info(" ", "\x1B[0m Heap:\x1B[32m", `${Math.round(t.heapUsed / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m / \x1B[32m", `${Math.round(t.heapTotal / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m RSS:\x1B[32m", `${Math.round(t.rss / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m External:\x1B[32m", `${Math.round(t.external / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m ArrBuffers:\x1B[32m", `${Math.round(t.arrayBuffers / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m"); +} +function ft(e, t = 5e3) { + return setInterval(() => { + dt(e); + }, t); +} +//#endregion +//#region ../fastfile/build/browser/browser.esm.js +function pt(e) { + let t = e.initialSize || 1 << 20, n = new yt(); + return n.o = e, n.o.data = new Uint8Array(t), n.allocSize = t, n.totalSize = 0, n.readOnly = !1, n.pos = 0, n; +} +function mt(e) { + let t = new yt(); + return t.o = e, t.allocSize = e.data.byteLength, t.totalSize = e.data.byteLength, t.readOnly = !0, t.pos = 0, t; +} +var ht = /* @__PURE__ */ new Uint8Array(4), gt = new DataView(ht.buffer), _t = /* @__PURE__ */ new Uint8Array(8), vt = new DataView(_t.buffer), yt = class { + constructor() { + this.pageSize = 16384; + } + _resizeIfNeeded(e) { + if (e > this.allocSize) { + let t = Math.max(this.allocSize + (1 << 20), Math.floor(this.allocSize * 1.1), e), n = new Uint8Array(t); + n.set(this.o.data), this.o.data = n, this.allocSize = t; + } + } + async write(e, t) { + let n = this; + if (t === void 0 && (t = n.pos), this.readOnly) throw Error("Writing a read only file"); + this._resizeIfNeeded(t + e.byteLength), this.o.data.set(e.slice(), t), t + e.byteLength > this.totalSize && (this.totalSize = t + e.byteLength), this.pos = t + e.byteLength; + } + async readToBuffer(e, t, n, r) { + let i = this; + if (r === void 0 && (r = i.pos), this.readOnly && r + n > this.totalSize) throw Error("Reading out of bounds"); + this._resizeIfNeeded(r + n); + let a = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + r, n); + e.set(a, t), this.pos = r + n; + } + async read(e, t) { + let n = this, r = new Uint8Array(e); + return await n.readToBuffer(r, 0, e, t), r; + } + close() { + this.o.data.byteLength != this.totalSize && (this.o.data = this.o.data.slice(0, this.totalSize)); + } + async discard() {} + async writeULE32(e, t) { + let n = this; + gt.setUint32(0, e, !0), await n.write(ht, t); + } + async writeUBE32(e, t) { + let n = this; + gt.setUint32(0, e, !1), await n.write(ht, t); + } + async writeULE64(e, t) { + let n = this; + vt.setUint32(0, e & 4294967295, !0), vt.setUint32(4, Math.floor(e / 4294967296), !0), await n.write(_t, t); + } + async readULE32(e) { + let t = await this.read(4, e); + return new Uint32Array(t.buffer)[0]; + } + async readUBE32(e) { + let t = await this.read(4, e); + return new DataView(t.buffer).getUint32(0, !1); + } + async readULE64(e) { + let t = await this.read(8, e), n = new Uint32Array(t.buffer); + return n[1] * 4294967296 + n[0]; + } + async readString(e) { + let t = this, n = e === void 0 ? t.pos : e; + if (n > this.totalSize) { + if (this.readOnly) throw Error("Reading out of bounds"); + this._resizeIfNeeded(e); + } + let r = new Uint8Array(t.o.data.buffer, n, this.totalSize - n), i = r.findIndex((e) => e === 0), a = i !== -1, o = ""; + return a ? (o = new TextDecoder().decode(r.slice(0, i)), t.pos = n + i + 1) : t.pos = n, o; + } +}, J = 1 << 22; +function bt(e) { + let t = e.initialSize || 0, n = new Et(); + n.o = e; + let r = t ? Math.floor((t - 1) / J) + 1 : 0; + n.o.data = []; + for (let e = 0; e < r - 1; e++) n.o.data.push(new Uint8Array(J)); + return r && n.o.data.push(new Uint8Array(t - J * (r - 1))), n.totalSize = 0, n.readOnly = !1, n.pos = 0, n; +} +function xt(e) { + let t = new Et(); + return t.o = e, t.totalSize = (e.data.length - 1) * J + e.data[e.data.length - 1].byteLength, t.readOnly = !0, t.pos = 0, t; +} +var St = /* @__PURE__ */ new Uint8Array(4), Ct = new DataView(St.buffer), wt = /* @__PURE__ */ new Uint8Array(8), Tt = new DataView(wt.buffer), Et = class { + constructor() { + this.pageSize = 16384; + } + _resizeIfNeeded(e) { + if (e <= this.totalSize) return; + if (this.readOnly) throw Error("Reading out of file bounds"); + let t = Math.floor((e - 1) / J) + 1; + for (let n = Math.max(this.o.data.length - 1, 0); n < t; n++) { + let r = n < t - 1 ? J : e - (t - 1) * J, i = new Uint8Array(r); + n == this.o.data.length - 1 && i.set(this.o.data[n]), this.o.data[n] = i; + } + this.totalSize = e; + } + async write(e, t) { + let n = this; + if (t === void 0 && (t = n.pos), this.readOnly) throw Error("Writing a read only file"); + this._resizeIfNeeded(t + e.byteLength); + let r = Math.floor(t / J), i = t % J, a = e.byteLength; + for (; a > 0;) { + let t = i + a > J ? J - i : a, o = e.slice(e.byteLength - a, e.byteLength - a + t); + new Uint8Array(n.o.data[r].buffer, i, t).set(o), a -= t, r++, i = 0; + } + this.pos = t + e.byteLength; + } + async readToBuffer(e, t, n, r) { + let i = this; + if (r === void 0 && (r = i.pos), this.readOnly && r + n > this.totalSize) throw Error("Reading out of bounds"); + this._resizeIfNeeded(r + n); + let a = Math.floor(r / J), o = r % J, s = n; + for (; s > 0;) { + let r = o + s > J ? J - o : s, c = new Uint8Array(i.o.data[a].buffer, o, r); + e.set(c, t + n - s), s -= r, a++, o = 0; + } + this.pos = r + n; + } + async read(e, t) { + let n = this, r = new Uint8Array(e); + return await n.readToBuffer(r, 0, e, t), r; + } + close() {} + async discard() {} + async writeULE32(e, t) { + let n = this; + Ct.setUint32(0, e, !0), await n.write(St, t); + } + async writeUBE32(e, t) { + let n = this; + Ct.setUint32(0, e, !1), await n.write(St, t); + } + async writeULE64(e, t) { + let n = this; + Tt.setUint32(0, e & 4294967295, !0), Tt.setUint32(4, Math.floor(e / 4294967296), !0), await n.write(wt, t); + } + async readULE32(e) { + let t = await this.read(4, e); + return new Uint32Array(t.buffer)[0]; + } + async readUBE32(e) { + let t = await this.read(4, e); + return new DataView(t.buffer).getUint32(0, !1); + } + async readULE64(e) { + let t = await this.read(8, e), n = new Uint32Array(t.buffer); + return n[1] * 4294967296 + n[0]; + } + async readString(e) { + let t = this, n = e === void 0 ? t.pos : e; + if (n > this.totalSize) { + if (this.readOnly) throw Error("Reading out of bounds"); + this._resizeIfNeeded(e); + } + let r = !1, i = ""; + for (; !r;) { + let e = Math.floor(n / J), a = n % J; + if (t.o.data[e] === void 0) throw Error("ERROR"); + let o = Math.min(2048, t.o.data[e].length - a), s = new Uint8Array(t.o.data[e].buffer, a, o), c = s.findIndex((e) => e === 0); + r = c !== -1, r ? (i += new TextDecoder().decode(s.slice(0, c)), t.pos = e * J + a + c + 1) : (i += new TextDecoder().decode(s), t.pos = e * J + a + s.length), n = t.pos; + } + return i; + } }; - -const PAGE_SIZE$2 = 1<<22; - -function createNew$2(o) { - const initialSize = o.initialSize || 0; - const fd = new BigMemFile$2(); - fd.o = o; - const nPages = initialSize ? Math.floor((initialSize - 1) / PAGE_SIZE$2)+1 : 0; - fd.o.data = []; - for (let i=0; i0) { - const l = (o+r > PAGE_SIZE$2) ? (PAGE_SIZE$2 -o) : r; - const srcView = buff.slice(buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.o.data[p].buffer, o, l); - dstView.set(srcView); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDst, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const firstPage = Math.floor(pos / PAGE_SIZE$2); - - let p = firstPage; - let o = pos % PAGE_SIZE$2; - // Remaining bytes to read - let r = len; - while (r>0) { - // bytes to copy from this page - const l = (o+r > PAGE_SIZE$2) ? (PAGE_SIZE$2 -o) : r; - const srcView = new Uint8Array(self.o.data[p].buffer, o, l); - buffDst.set(srcView, offset+len-r); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - const buff = new Uint8Array(len); - - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$4.setUint32(0, v, true); - - await self.write(tmpBuff32$4, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$4.setUint32(0, v, false); - - await self.write(tmpBuff32$4, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$4.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$4.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$4, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - const fixedSize = 2048; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - let currentPage = Math.floor(currentPosition / PAGE_SIZE$2); - let offsetOnPage = currentPosition % PAGE_SIZE$2; - - if (self.o.data[currentPage] === undefined) { - throw new Error("ERROR"); - } - - let readLength = Math.min(fixedSize, self.o.data[currentPage].length - offsetOnPage); - const dataArray = new Uint8Array(self.o.data[currentPage].buffer, offsetOnPage, readLength); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * PAGE_SIZE$2 + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * PAGE_SIZE$2 + offsetOnPage + dataArray.length; - } - - currentPosition = self.pos; - } - return str; - } -}; - -const O_TRUNC = 512; -const O_CREAT = 64; -const O_RDWR = 2; -const O_RDONLY = 0; - -const DEFAULT_CACHE_SIZE$1 = (1 << 16); -const DEFAULT_PAGE_SIZE$1 = (1 << 13); - -// Robust Node detection that never throws (unlike `true`, which is a -// webpack-ism and is undefined under Vite/esbuild/SES). -const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null; - - -async function createOverride$1(o, b, c) { - if (typeof o === "string") { - o = { - type: "file", - fileName: o, - cacheSize: b || DEFAULT_CACHE_SIZE$1, - pageSize: c || DEFAULT_PAGE_SIZE$1 - }; - } - if (o.type == "file") { - return await open$2(o.fileName, O_TRUNC | O_CREAT | O_RDWR, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return createNew$3(o); - } else if (o.type == "bigMem") { - return createNew$2(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } -} - -async function readExisting$6(o, b, c) { - if (o instanceof Uint8Array) { - o = { - type: "mem", - data: o - }; - } - if (!isNode) { - if (typeof o === "string") { - const buff = await fetch(o).then( function(res) { - return res.arrayBuffer(); - }).then(function (ab) { - return new Uint8Array(ab); - }); - o = { - type: "mem", - data: buff - }; - } - } else { - if (typeof o === "string") { - o = { - type: "file", - fileName: o, - cacheSize: b || DEFAULT_CACHE_SIZE$1, - pageSize: c || DEFAULT_PAGE_SIZE$1 - }; - } - } - if (o.type == "file") { - return await open$2(o.fileName, O_RDONLY, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return await readExisting$8(o); - } else if (o.type == "bigMem") { - return await readExisting$7(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } -} - -// 1 GiB threshold (matched to BigBuffer's page size): sections at/above this are -// read into a paged BigBuffer instead of one flat Uint8Array. -const MAX_BUFFER_SIZE = 1 << 30; - -async function readBinFile$1(fileName, type, maxVersion, cacheSize, pageSize) { - - const fd = await readExisting$6(fileName, cacheSize, pageSize); - - const b = await fd.read(4); - let readedType = ""; - for (let i=0; i<4; i++) readedType += String.fromCharCode(b[i]); - - if (readedType != type) throw new Error(fileName + ": Invalid File format"); - - let v = await fd.readULE32(); - - if (v>maxVersion) throw new Error("Version not supported"); - - const nSections = await fd.readULE32(); - - // Scan sections - let sections = []; - for (let i=0; i1) throw new Error(fd.fileName +": Section Duplicated " +idSection); - - fd.pos = sections[idSection][0].p; - - fd.readingSection = sections[idSection][0]; -} - -async function endReadSection$1(fd, noCheck) { - if (typeof fd.readingSection === "undefined") throw new Error("Not reading a section"); - if (!noCheck) { - if (fd.pos-fd.readingSection.p != fd.readingSection.size) throw new Error("Invalid section size reading"); - } - delete fd.readingSection; -} - -async function writeBigInt(fd, n, n8, pos) { - const buff = new Uint8Array(n8); - Scalar.toRprLE(buff, 0, n, n8); - await fd.write(buff, pos); -} - -async function readBigInt$1(fd, n8, pos) { - const buff = await fd.read(n8, pos); - return Scalar.fromRprLE(buff, 0, n8); -} - -async function copySection(fdFrom, sections, fdTo, sectionId, size) { - if (typeof size === "undefined") { - size = sections[sectionId][0].size; - } - const chunkSize = fdFrom.pageSize; - await startReadUniqueSection$1(fdFrom, sections, sectionId); - await startWriteSection(fdTo, sectionId); - for (let p=0; p sections[idSection][0].size) { - throw new Error("Reading out of the range of the section"); - } - - let buff; - if (length < MAX_BUFFER_SIZE) { - buff = new Uint8Array(length); - } else { - buff = new BigBuffer(length); - } - - await fd.readToBuffer(buff, 0, length, sections[idSection][0].p + offset); - - - return buff; -} - - -async function sectionIsEqual(fd1, sections1, fd2, sections2, idSection) { - const MAX_BUFF_SIZE = fd1.pageSize * 16; - await startReadUniqueSection$1(fd1, sections1, idSection); - await startReadUniqueSection$1(fd2, sections2, idSection); - if (sections1[idSection][0].size != sections2[idSection][0].size) return false; - const totalBytes=sections1[idSection][0].size; - for (let i=0; i= 0) { - curve = await buildBn128(singleThread); - } else if (["BLS12381"].indexOf(normName) >= 0) { - curve = await buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${name}`); - } - return curve; - - function normalizeName(n) { - return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); - } - -} - -var curves = /*#__PURE__*/Object.freeze({ - __proto__: null, - getCurveFromName: getCurveFromName, - getCurveFromQ: getCurveFromQ, - getCurveFromR: getCurveFromR +function Dt() { + throw Error("File I/O is not supported in the browser"); +} +function Ot(e) { + return e instanceof Uint8Array ? { + type: "mem", + data: e + } : (typeof e == "string" && Dt(), e); +} +async function kt(e) { + let t = await fetch(e).then((e) => e.arrayBuffer()); + return { + type: "mem", + data: new Uint8Array(t) + }; +} +function At(e, t, n) { + if (e.type === "file" && Dt(), e.type === "mem") return t(e); + if (e.type === "bigMem") return n(e); + throw Error("Invalid FastFile type: " + e.type); +} +function jt(e) { + return At(Ot(e), pt, bt); +} +async function Mt(e) { + return e = typeof e == "string" ? await kt(e) : Ot(e), At(e, mt, xt); +} +//#endregion +//#region node_modules/circom_runtime/js/utils.js +function Nt(e) { + let t = []; + return n(t, e), t; + function n(e, t) { + if (Array.isArray(t)) for (let r = 0; r < t.length; r++) n(e, t[r]); + else e.push(t); + } +} +function Pt(e, t) { + let n = BigInt(e) % t; + return n < 0 && (n += t), n; +} +function Ft(e) { + let t = BigInt(2) ** BigInt(64), n = BigInt("0xCBF29CE484222325"); + for (let r = 0; r < e.length; r++) n ^= BigInt(e[r].charCodeAt(0)), n *= BigInt(1099511628211), n %= t; + let r = n.toString(16), i = 16 - r.length; + return r = "0".repeat(i).concat(r), r; +} +function It(e, t) { + let n = [], r = BigInt(e), i = BigInt(4294967296); + for (; r;) n.unshift(Number(r % i)), r /= i; + if (t) { + let e = t - n.length; + for (; e > 0;) n.unshift(0), e--; + } + return n; +} +//#endregion +//#region node_modules/circom_runtime/js/witness_calculator.js +async function Lt(e, t) { + let n, r, i; + t ||= {}; + let a = 1, o = 0, s = 0, c = !1; + if (e instanceof WebAssembly.Instance) n = e, c = !0; + else { + let c = 32767; + if (t.memorySize && (c = parseInt(t.memorySize), c < 0)) throw Error("Invalid memory size"); + let l = !1; + for (; !l;) try { + i = new WebAssembly.Memory({ initial: c }), l = !0; + } catch (e) { + if (c <= 1) throw e; + console.warn("Could not allocate " + c * 1024 * 64 + " bytes. This may cause severe instability. Trying with " + c * 1024 * 64 / 2 + " bytes"), c = Math.floor(c / 2); + } + let p = await WebAssembly.compile(e), m = "", h = ""; + n = await WebAssembly.instantiate(p, { + env: { memory: i }, + runtime: { + printDebug: function(e) { + console.log("printDebug:", e); + }, + exceptionHandler: function(e) { + let t; + throw t = e === 1 ? "Signal not found. " : e === 2 ? "Too many signals set. " : e === 3 ? "Signal already set. " : e === 4 ? "Assert Failed. " : e === 5 ? "Not enough memory. " : e === 6 ? "Input signal array access exceeds the size. " : "Unknown error. ", console.error("ERROR: ", e, m), Error(t + m); + }, + printErrorMessage: function() { + m += d() + "\n"; + }, + writeBufferMessage: function() { + let e = d(); + e === "\n" ? (console.log(h), h = "") : (h !== "" && (h += " "), h += e); + }, + showSharedRWMemory: function() { + let e = n.exports.getFieldNumLen32(), t = new Uint32Array(e); + for (let r = 0; r < e; r++) t[e - 1 - r] = n.exports.readSharedRWMemory(r); + if (a >= 2 && (o >= 1 || s >= 7)) { + h !== "" && (h += " "); + let e = u.fromArray(t, 4294967296).toString(); + h += e; + } else console.log(u.fromArray(t, 4294967296)); + }, + error: function(e, n, i, a, o, s) { + let c; + throw c = e === 7 ? f(n) + " " + r.getFr(a).toString() + " != " + r.getFr(o).toString() + " " + f(s) : e === 9 ? f(n) + " " + r.getFr(a).toString() + " " + f(o) : e === 5 && t.sym ? f(n) + " " + t.sym.labelIdx2Name[o] : f(n) + " " + i + " " + a + " " + o + " " + s, console.log("ERROR: ", e, c), Error(c); + }, + log: function(e) { + console.log(r.getFr(e).toString()); + }, + logGetSignal: function(e, n) { + t.logGetSignal && t.logGetSignal(e, r.getFr(n)); + }, + logSetSignal: function(e, n) { + t.logSetSignal && t.logSetSignal(e, r.getFr(n)); + }, + logStartComponent: function(e) { + t.logStartComponent && t.logStartComponent(e); + }, + logFinishComponent: function(e) { + t.logFinishComponent && t.logFinishComponent(e); + } + } + }); + } + typeof n.exports.getVersion == "function" && (a = n.exports.getVersion()), typeof n.exports.getMinorVersion == "function" && (o = n.exports.getMinorVersion()), typeof n.exports.getPatchVersion == "function" && (s = n.exports.getPatchVersion()); + let l = t && (t.sanityCheck || t.logGetSignal || t.logSetSignal || t.logStartComponent || t.logFinishComponent); + if (a === 2) r = new zt(n, l); + else if (a === 1) { + if (c) throw Error("Loading code from WebAssembly instance is not supported for circom version 1"); + r = new Rt(i, n, l); + } else throw Error(`Unsupported circom version: ${a}`); + return r; + function d() { + let e = "", t = n.exports.getMessageChar(); + for (; t !== 0;) e += String.fromCharCode(t), t = n.exports.getMessageChar(); + return e; + } + function f(e) { + let t = new Uint8Array(i.buffer), n = []; + for (let r = 0; t[e + r] > 0; r++) n.push(t[e + r]); + return String.fromCharCode.apply(null, n); + } +} +var Rt = class { + constructor(e, t, n) { + this.memory = e, this.i32 = new Uint32Array(e.buffer), this.instance = t, this.n32 = (this.instance.exports.getFrLen() >> 2) - 2; + let r = this.instance.exports.getPRawPrime(), i = Array(this.n32); + for (let e = 0; e < this.n32; e++) i[this.n32 - 1 - e] = this.i32[(r >> 2) + e]; + this.prime = u.fromArray(i, 4294967296), this.Fr = new l(this.prime), this.mask32 = u.fromString("FFFFFFFF", 16), this.NVars = this.instance.exports.getNVars(), this.n64 = Math.floor((this.Fr.bitLength - 1) / 64) + 1, this.R = this.Fr.e(u.shiftLeft(1, this.n64 * 64)), this.RInv = this.Fr.inv(this.R), this.sanityCheck = n; + } + circom_version() { + return 1; + } + async _doCalculateWitness(e, t) { + this.instance.exports.init(this.sanityCheck || t ? 1 : 0); + let n = this.allocInt(), r = this.allocFr(); + Object.keys(e).forEach((t) => { + let i = Ft(t), a = parseInt(i.slice(0, 8), 16), o = parseInt(i.slice(8, 16), 16); + try { + this.instance.exports.getSignalOffset32(n, 0, a, o); + } catch { + throw Error(`Signal ${t} is not an input of the circuit.`); + } + let s = this.getInt(n), c = Nt(e[t]); + for (let e = 0; e < c.length; e++) this.setFr(r, c[e]), this.instance.exports.setSignal(0, 0, s + e, r); + }); + } + async calculateWitness(e, t) { + let n = this, r = n.i32[0], i = []; + await n._doCalculateWitness(e, t); + for (let e = 0; e < n.NVars; e++) { + let t = n.instance.exports.getPWitness(e); + i.push(n.getFr(t)); + } + return n.i32[0] = r, i; + } + async calculateBinWitness(e, t) { + let n = this, r = n.i32[0]; + await n._doCalculateWitness(e, t); + let i = n.instance.exports.getWitnessBuffer(); + n.i32[0] = r; + let a = n.memory.buffer.slice(i, i + n.NVars * n.n64 * 8); + return new Uint8Array(a); + } + allocInt() { + let e = this.i32[0]; + return this.i32[0] = e + 8, e; + } + allocFr() { + let e = this.i32[0]; + return this.i32[0] = e + this.n32 * 4 + 8, e; + } + getInt(e) { + return this.i32[e >> 2]; + } + setInt(e, t) { + this.i32[e >> 2] = t; + } + getFr(e) { + let t = this, n = e >> 2; + if (t.i32[n + 1] & 2147483648) { + let e = Array(t.n32); + for (let r = 0; r < t.n32; r++) e[t.n32 - 1 - r] = t.i32[n + 2 + r]; + let i = t.Fr.e(u.fromArray(e, 4294967296)); + return t.i32[n + 1] & 1073741824 ? r(i) : i; + } else if (t.i32[n] & 2147483648) return t.Fr.e(t.i32[n] - 4294967296); + else return t.Fr.e(t.i32[n]); + function r(e) { + return t.Fr.mul(t.RInv, e); + } + } + setFr(e, t) { + let n = this; + t = n.Fr.e(t); + let r = n.Fr.neg(n.Fr.e("80000000", 16)), i = n.Fr.e("7FFFFFFF", 16); + if (n.Fr.geq(t, r) && n.Fr.leq(t, i)) { + let i; + n.Fr.geq(t, n.Fr.zero) ? i = u.toNumber(t) : (i = u.toNumber(n.Fr.sub(t, r)), i -= 2147483648, i = 4294967296 + i), n.i32[e >> 2] = i, n.i32[(e >> 2) + 1] = 0; + return; + } + n.i32[e >> 2] = 0, n.i32[(e >> 2) + 1] = 2147483648; + let a = u.toArray(t, 4294967296); + for (let t = 0; t < n.n32; t++) { + let r = a.length - 1 - t; + r >= 0 ? n.i32[(e >> 2) + 2 + t] = a[r] : n.i32[(e >> 2) + 2 + t] = 0; + } + } +}, zt = class { + constructor(e, t) { + this.instance = e, this.version = this.instance.exports.getVersion(), this.n32 = this.instance.exports.getFieldNumLen32(), this.instance.exports.getRawPrime(); + let n = new Uint32Array(this.n32); + for (let e = 0; e < this.n32; e++) n[this.n32 - 1 - e] = this.instance.exports.readSharedRWMemory(e); + this.prime = u.fromArray(n, 4294967296), this.witnessSize = this.instance.exports.getWitnessSize(), this.sanityCheck = t; + } + circom_version() { + return this.instance.exports.getVersion(); + } + async _doCalculateWitness(e, t) { + this.instance.exports.init(this.sanityCheck || t ? 1 : 0); + let n = Object.keys(e), r = 0; + if (n.forEach((t) => { + let n = Ft(t), i = parseInt(n.slice(0, 8), 16), a = parseInt(n.slice(8, 16), 16), o = Nt(e[t]); + if (typeof this.instance.exports.getInputSignalSize == "function") { + let e = this.instance.exports.getInputSignalSize(i, a); + if (e < 0) throw Error(`Signal ${t} not found\n`); + if (o.length < e) throw Error(`Not enough values for input signal ${t}\n`); + if (o.length > e) throw Error(`Too many values for input signal ${t}\n`); + } + for (let e = 0; e < o.length; e++) { + let t = It(Pt(o[e], this.prime), this.n32); + for (let e = 0; e < this.n32; e++) this.instance.exports.writeSharedRWMemory(e, t[this.n32 - 1 - e]); + try { + this.instance.exports.setInputSignal(i, a, e), r++; + } catch (e) { + throw Error(e); + } + } + }), r < this.instance.exports.getInputSize()) throw Error(`Not all inputs have been set. Only ${r} out of ${this.instance.exports.getInputSize()}`); + } + async calculateWitness(e, t) { + let n = []; + await this._doCalculateWitness(e, t); + for (let e = 0; e < this.witnessSize; e++) { + this.instance.exports.getWitness(e); + let t = new Uint32Array(this.n32); + for (let e = 0; e < this.n32; e++) t[this.n32 - 1 - e] = this.instance.exports.readSharedRWMemory(e); + n.push(u.fromArray(t, 4294967296)); + } + return n; + } + async calculateWTNSBin(e, t) { + let n = new Uint32Array(this.witnessSize * this.n32 + this.n32 + 11), r = new Uint8Array(n.buffer); + await this._doCalculateWitness(e, t), r[0] = 119, r[1] = 116, r[2] = 110, r[3] = 115, n[1] = 2, n[2] = 2, n[3] = 1; + let i = this.n32 * 4, a = (8 + i).toString(16); + n[4] = parseInt(a.slice(0, 8), 16), n[5] = parseInt(a.slice(8, 16), 16), n[6] = i, this.instance.exports.getRawPrime(); + let o = 7; + for (let e = 0; e < this.n32; e++) n[o + e] = this.instance.exports.readSharedRWMemory(e); + o += this.n32, n[o] = this.witnessSize, o++, n[o] = 2, o++; + let s = (i * this.witnessSize).toString(16); + n[o] = parseInt(s.slice(0, 8), 16), n[o + 1] = parseInt(s.slice(8, 16), 16), o += 2; + for (let e = 0; e < this.witnessSize; e++) { + this.instance.exports.getWitness(e); + for (let e = 0; e < this.n32; e++) n[o + e] = this.instance.exports.readSharedRWMemory(e); + o += this.n32; + } + return r; + } +}, { unstringifyBigInts: Bt } = p; +async function Vt(t, n, r, i) { + let a = Bt(t), o = await Mt(n), s = await o.read(o.totalSize); + await o.close(); + let c = await Lt(s, i); + if (c.circom_version() === 1) { + let t = await c.calculateBinWitness(a), n = await e.createBinFile(r, "wtns", 2, 2); + await tt(n, t, c.prime), await n.close(); + } else { + let e = await jt(r), t = await c.calculateWTNSBin(a); + await e.write(t), await e.close(); + } +} +//#endregion +//#region src/groth16_fullprove.js +var { unstringifyBigInts: Ht } = p; +async function Ut(e, t, n, r, i, a) { + let o = Ht(e), s = { type: "mem" }; + return await Vt(o, t, s, i), await at(n, s, r, a); +} +//#endregion +//#region src/groth16_verify.js +var { unstringifyBigInts: Wt } = p; +async function Gt(e, t, n, r) { + let i = Wt(e), a = Wt(n), o = Wt(t), s = await E(i.curve), c = s.G1.fromObject(i.IC[0]), l = new Uint8Array(s.G1.F.n8 * 2 * o.length), d = new Uint8Array(s.Fr.n8 * o.length); + if (!Jt(s, o)) return r && r.error("Public inputs are not valid."), !1; + for (let e = 0; e < o.length; e++) { + let t = s.G1.fromObject(i.IC[e + 1]); + l.set(t, e * s.G1.F.n8 * 2), u.toRprLE(d, s.Fr.n8 * e, o[e], s.Fr.n8); + } + let f = await s.G1.multiExpAffine(l, d); + f = s.G1.add(f, c); + let p = s.G1.fromObject(a.pi_a), m = s.G2.fromObject(a.pi_b), h = s.G1.fromObject(a.pi_c); + if (!Kt(s, { + pi_a: p, + pi_b: m, + pi_c: h + })) return r && r.error("Proof commitments are not valid."), !1; + let g = s.G2.fromObject(i.vk_gamma_2), _ = s.G2.fromObject(i.vk_delta_2), v = s.G1.fromObject(i.vk_alpha_1), y = s.G2.fromObject(i.vk_beta_2); + return await s.pairingEq(s.G1.neg(p), m, f, g, h, _, v, y) ? (r && r.info("OK!"), !0) : (r && r.error("Invalid proof"), !1); +} +function Kt(e, t) { + let n = e.G1, r = e.G2; + return n.isValid(t.pi_a) && r.isValid(t.pi_b) && n.isValid(t.pi_c); +} +function qt(e, t) { + return u.geq(t, 0) && u.lt(t, e.r); +} +function Jt(e, t) { + for (let n = 0; n < t.length; n++) if (!qt(e, t[n])) return !1; + return !0; +} +//#endregion +//#region src/groth16_exportsoliditycalldata.js +var { unstringifyBigInts: Yt } = p; +function Xt(e) { + let t = e.toString(16); + for (; t.length < 64;) t = "0" + t; + return t = `"0x${t}"`, t; +} +async function Zt(e, t) { + let n = Yt(e), r = Yt(t), i = ""; + for (let e = 0; e < r.length; e++) i != "" && (i += ","), i += Xt(r[e]); + let a; + return a = `[${Xt(n.pi_a[0])}, ${Xt(n.pi_a[1])}],[[${Xt(n.pi_b[0][1])}, ${Xt(n.pi_b[0][0])}],[${Xt(n.pi_b[1][1])}, ${Xt(n.pi_b[1][0])}]],[${Xt(n.pi_c[0])}, ${Xt(n.pi_c[1])}],[${i}]`, a; +} +//#endregion +//#region src/groth16.js +var Qt = /* @__PURE__ */ v({ + exportSolidityCallData: () => Zt, + fullProve: () => Ut, + prove: () => at, + verify: () => Gt }); - -/** - * Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. - * @param a - value to test - * @returns `true` when the value is a Uint8Array-compatible view. - * @example - * Check whether a value is a Uint8Array-compatible view. - * ```ts - * isBytes(new Uint8Array([1, 2, 3])); - * ``` - */ -function isBytes(a) { - // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases. - // The fallback still requires a real ArrayBuffer view, so plain - // JSON-deserialized `{ constructor: ... }` spoofing is rejected, and - // `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views. - return (a instanceof Uint8Array || - (ArrayBuffer.isView(a) && - a.constructor.name === 'Uint8Array' && - 'BYTES_PER_ELEMENT' in a && - a.BYTES_PER_ELEMENT === 1)); -} -/** - * Asserts something is a non-negative integer. - * @param n - number to validate - * @param title - label included in thrown errors - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validate a non-negative integer option. - * ```ts - * anumber(32, 'length'); - * ``` - */ -function anumber(n, title = '') { - if (typeof n !== 'number') { - const prefix = title && `"${title}" `; - throw new TypeError(`${prefix}expected number, got ${typeof n}`); - } - if (!Number.isSafeInteger(n) || n < 0) { - const prefix = title && `"${title}" `; - throw new RangeError(`${prefix}expected integer >= 0, got ${n}`); - } -} -/** - * Asserts something is Uint8Array. - * @param value - value to validate - * @param length - optional exact length constraint - * @param title - label included in thrown errors - * @returns The validated byte array. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validate that a value is a byte array. - * ```ts - * abytes(new Uint8Array([1, 2, 3])); - * ``` - */ -function abytes(value, length, title = '') { - const bytes = isBytes(value); - const len = value?.length; - const needsLen = length !== undefined; - if (!bytes || (needsLen && len !== length)) { - const prefix = title && `"${title}" `; - const ofLen = needsLen ? ` of length ${length}` : ''; - const got = bytes ? `length=${len}` : `type=${typeof value}`; - const message = prefix + 'expected Uint8Array' + ofLen + ', got ' + got; - if (!bytes) - throw new TypeError(message); - throw new RangeError(message); - } - return value; -} -/** - * Asserts a hash instance has not been destroyed or finished. - * @param instance - hash instance to validate - * @param checkFinished - whether to reject finalized instances - * @throws If the hash instance has already been destroyed or finalized. {@link Error} - * @example - * Validate that a hash instance is still usable. - * ```ts - * import { aexists } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * const hash = sha256.create(); - * aexists(hash); - * ``` - */ -function aexists(instance, checkFinished = true) { - if (instance.destroyed) - throw new Error('Hash instance has been destroyed'); - if (checkFinished && instance.finished) - throw new Error('Hash#digest() has already been called'); -} -/** - * Asserts output is a sufficiently-sized byte array. - * @param out - destination buffer - * @param instance - hash instance providing output length - * Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validate a caller-provided digest buffer. - * ```ts - * import { aoutput } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * const hash = sha256.create(); - * aoutput(new Uint8Array(hash.outputLen), hash); - * ``` - */ -function aoutput(out, instance) { - abytes(out, undefined, 'digestInto() output'); - const min = instance.outputLen; - if (out.length < min) { - throw new RangeError('"digestInto() output" expected to be of length >=' + min); - } -} -/** - * Casts a typed array view to Uint32Array. - * `arr.byteOffset` must already be 4-byte aligned or the platform - * Uint32Array constructor will throw. - * @param arr - source typed array - * @returns Uint32Array view over the same buffer. - * @example - * Reinterpret a byte array as 32-bit words. - * ```ts - * u32(new Uint8Array(8)); - * ``` - */ -function u32(arr) { - return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); -} -/** - * Zeroizes typed arrays in place. Warning: JS provides no guarantees. - * @param arrays - arrays to overwrite with zeros - * @example - * Zeroize sensitive buffers in place. - * ```ts - * clean(new Uint8Array([1, 2, 3])); - * ``` - */ -function clean(...arrays) { - for (let i = 0; i < arrays.length; i++) { - arrays[i].fill(0); - } -} -/** Whether the current platform is little-endian. */ -const isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)(); -/** - * Byte-swap operation for uint32 values. - * @param word - source word - * @returns Word with reversed byte order. - * @example - * Reverse the byte order of a 32-bit word. - * ```ts - * byteSwap(0x11223344); - * ``` - */ -function byteSwap(word) { - return (((word << 24) & 0xff000000) | - ((word << 8) & 0xff0000) | - ((word >>> 8) & 0xff00) | - ((word >>> 24) & 0xff)); -} -/** - * Conditionally byte-swaps one 32-bit word on big-endian platforms. - * @param n - source word - * @returns Original or byte-swapped word depending on platform endianness. - * @example - * Normalize a 32-bit word for host endianness. - * ```ts - * swap8IfBE(0x11223344); - * ``` - */ -const swap8IfBE = isLE - ? (n) => n - : (n) => byteSwap(n) >>> 0; -/** - * Byte-swaps every word of a Uint32Array in place. - * @param arr - array to mutate - * @returns The same array after mutation; callers pass live state arrays here. - * @example - * Reverse the byte order of every word in place. - * ```ts - * byteSwap32(new Uint32Array([0x11223344])); - * ``` - */ -function byteSwap32(arr) { - for (let i = 0; i < arr.length; i++) { - arr[i] = byteSwap(arr[i]); - } - return arr; -} -/** - * Conditionally byte-swaps a Uint32Array on big-endian platforms. - * @param u - array to normalize for host endianness - * @returns Original or byte-swapped array depending on platform endianness. - * On big-endian runtimes this mutates `u` in place via `byteSwap32(...)`. - * @example - * Normalize a word array for host endianness. - * ```ts - * swap32IfBE(new Uint32Array([0x11223344])); - * ``` - */ -const swap32IfBE = isLE - ? (u) => u - : byteSwap32; -/** - * Creates a callable hash function from a stateful class constructor. - * @param hashCons - hash constructor or factory - * @param info - optional metadata such as DER OID - * @returns Frozen callable hash wrapper with `.create()`. - * Wrapper construction eagerly calls `hashCons(undefined)` once to read - * `outputLen` / `blockLen`, so constructor side effects happen at module - * init time. - * @example - * Wrap a stateful hash constructor into a callable helper. - * ```ts - * import { createHasher } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * const wrapped = createHasher(sha256.create, { oid: sha256.oid }); - * wrapped(new Uint8Array([1])); - * ``` - */ -function createHasher(hashCons, info = {}) { - const hashC = (msg, opts) => hashCons(opts) - .update(msg) - .digest(); - const tmp = hashCons(undefined); - hashC.outputLen = tmp.outputLen; - hashC.blockLen = tmp.blockLen; - hashC.canXOF = tmp.canXOF; - hashC.create = (opts) => hashCons(opts); - Object.assign(hashC, info); - return Object.freeze(hashC); -} - -/** - * Internal helpers for blake hash. - * @module - */ -/** - * Internal blake permutation table. - * Rows `0..9` serve BLAKE2s, rows `0..11` serve BLAKE2b with `10..11 = 0..1`, and Blake1 also - * reuses the later rows shown below. Blake1 expands rounds `10..15` as `SIGMA[i % 10]`, so rows - * `10..15` intentionally repeat rows `0..5` for the 14-round (256) and 16-round (512) variants. - */ -// prettier-ignore -const BSIGMA = /* @__PURE__ */ Uint8Array.from([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, - 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, - 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, - 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, - 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, - 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, - 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, - 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, - 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, - // Blake1, unused in others - 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, - 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, - 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, - 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, -]); - -const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1); -const _32n = /* @__PURE__ */ BigInt(32); -// Split bigint into two 32-bit halves. With `le=true`, returned fields become `{ h: low, l: high -// }` to match little-endian word order rather than the property names. -function fromBig(n, le = false) { - if (le) - return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) }; - return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 }; -} -// Split bigint list into `[highWords, lowWords]` when `le=false`; with `le=true`, the first array -// holds the low halves because `fromBig(...)` swaps the semantic meaning of `h` and `l`. -function split(lst, le = false) { - const len = lst.length; - let Ah = new Uint32Array(len); - let Al = new Uint32Array(len); - for (let i = 0; i < len; i++) { - const { h, l } = fromBig(lst[i], le); - [Ah[i], Al[i]] = [h, l]; - } - return [Ah, Al]; -} -// High 32-bit half of a 64-bit right rotate, valid for `s` in `1..31`. -const rotrSH = (h, l, s) => (h >>> s) | (l << (32 - s)); -// Low 32-bit half of a 64-bit right rotate, valid for `s` in `1..31`. -const rotrSL = (h, l, s) => (h << (32 - s)) | (l >>> s); -// High 32-bit half of a 64-bit right rotate, valid for `s` in `33..63`; `32` uses `rotr32*`. -const rotrBH = (h, l, s) => (h << (64 - s)) | (l >>> (s - 32)); -// Low 32-bit half of a 64-bit right rotate, valid for `s` in `33..63`; `32` uses `rotr32*`. -const rotrBL = (h, l, s) => (h >>> (s - 32)) | (l << (64 - s)); -// High 32-bit half of a 64-bit right rotate for `s === 32`; this is just the swapped low half. -const rotr32H = (_h, l) => l; -// Low 32-bit half of a 64-bit right rotate for `s === 32`; this is just the swapped high half. -const rotr32L = (h, _l) => h; -// High 32-bit half of a 64-bit left rotate, valid for `s` in `1..31`. -const rotlSH = (h, l, s) => (h << s) | (l >>> (32 - s)); -// Low 32-bit half of a 64-bit left rotate, valid for `s` in `1..31`. -const rotlSL = (h, l, s) => (l << s) | (h >>> (32 - s)); -// High 32-bit half of a 64-bit left rotate, valid for `s` in `33..63`; `32` uses `rotr32*`. -const rotlBH = (h, l, s) => (l << (s - 32)) | (h >>> (64 - s)); -// Low 32-bit half of a 64-bit left rotate, valid for `s` in `33..63`; `32` uses `rotr32*`. -const rotlBL = (h, l, s) => (h << (s - 32)) | (l >>> (64 - s)); -// Add two split 64-bit words and return the split `{ h, l }` sum. -// JS uses 32-bit signed integers for bitwise operations, so we cannot simply shift the carry out -// of the low sum and instead use division. -function add(Ah, Al, Bh, Bl) { - const l = (Al >>> 0) + (Bl >>> 0); - return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 }; -} -// Addition with more than 2 elements -// Unmasked low-word accumulator for 3-way addition; pass the raw result into `add3H(...)`. -const add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0); -// High-word finalize step for 3-way addition; `low` must be the untruncated output of `add3L(...)`. -const add3H = (low, Ah, Bh, Ch) => (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0; - -/** - * blake2b (64-bit) & blake2s (8 to 32-bit) hash functions. - * b could have been faster, but there is no fast u64 in js, so s is 1.5x faster. - * @module - */ -// Same IV words as `SHA512_IV`, but endian-swapped into LE u32 low/high halves -// for the BLAKE2b u64 helpers below. -const B2B_IV = /* @__PURE__ */ Uint32Array.from([ - 0xf3bcc908, 0x6a09e667, 0x84caa73b, 0xbb67ae85, 0xfe94f82b, 0x3c6ef372, 0x5f1d36f1, 0xa54ff53a, - 0xade682d1, 0x510e527f, 0x2b3e6c1f, 0x9b05688c, 0xfb41bd6b, 0x1f83d9ab, 0x137e2179, 0x5be0cd19, -]); -// Shared synchronous BLAKE2b work vector as LE u32 low/high halves. -const BBUF = /* @__PURE__ */ new Uint32Array(32); -// BLAKE2b G mix split into two half-rounds over LE u32 low/high limbs. -function G1b(a, b, c, d, msg, x) { - // NOTE: V is LE here - const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore - let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore - let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore - let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore - let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore - // v[a] = (v[a] + v[b] + x) | 0; - let ll = add3L(Al, Bl, Xl); - Ah = add3H(ll, Ah, Bh, Xh); - Al = ll | 0; - // v[d] = rotr(v[d] ^ v[a], 32) - ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al }); - ({ Dh, Dl } = { Dh: rotr32H(Dh, Dl), Dl: rotr32L(Dh) }); - // v[c] = (v[c] + v[d]) | 0; - ({ h: Ch, l: Cl } = add(Ch, Cl, Dh, Dl)); - // v[b] = rotr(v[b] ^ v[c], 24) - ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl }); - ({ Bh, Bl } = { Bh: rotrSH(Bh, Bl, 24), Bl: rotrSL(Bh, Bl, 24) }); - ((BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah)); - ((BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh)); - ((BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch)); - ((BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh)); -} -// Second half-round of the same LE-limb BLAKE2b G mix; `x` is the message word offset. -function G2b(a, b, c, d, msg, x) { - // NOTE: V is LE here - const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore - let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore - let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore - let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore - let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore - // v[a] = (v[a] + v[b] + x) | 0; - let ll = add3L(Al, Bl, Xl); - Ah = add3H(ll, Ah, Bh, Xh); - Al = ll | 0; - // v[d] = rotr(v[d] ^ v[a], 16) - ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al }); - ({ Dh, Dl } = { Dh: rotrSH(Dh, Dl, 16), Dl: rotrSL(Dh, Dl, 16) }); - // v[c] = (v[c] + v[d]) | 0; - ({ h: Ch, l: Cl } = add(Ch, Cl, Dh, Dl)); - // v[b] = rotr(v[b] ^ v[c], 63) - ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl }); - ({ Bh, Bl } = { Bh: rotrBH(Bh, Bl, 63), Bl: rotrBL(Bh, Bl, 63) }); - ((BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah)); - ((BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh)); - ((BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch)); - ((BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh)); -} -function checkBlake2Opts(outputLen, opts = {}, keyLen, saltLen, persLen) { - anumber(keyLen); - // RFC 7693 §2.1 requires digest length nn in 1..keyLen. - if (outputLen <= 0 || outputLen > keyLen) - throw new Error('outputLen bigger than keyLen'); - const { key, salt, personalization } = opts; - // This API uses `undefined` for the RFC 7693 `kk = 0` case, so a provided key must be non-empty. - if (key !== undefined && (key.length < 1 || key.length > keyLen)) - throw new Error('"key" expected to be undefined or of length=1..' + keyLen); - if (salt !== undefined) - abytes(salt, saltLen, 'salt'); - if (personalization !== undefined) - abytes(personalization, persLen, 'personalization'); -} -/** Internal base class for BLAKE2. */ -class _BLAKE2 { - buffer; - buffer32; - finished = false; - destroyed = false; - length = 0; - pos = 0; - blockLen; - outputLen; - canXOF = false; - constructor(blockLen, outputLen) { - anumber(blockLen); - anumber(outputLen); - this.blockLen = blockLen; - this.outputLen = outputLen; - this.buffer = new Uint8Array(blockLen); - this.buffer32 = u32(this.buffer); - } - update(data) { - aexists(this); - abytes(data); - // Main difference with other hashes: there is flag for last block, - // so we cannot process current block before we know that there - // is the next one. This significantly complicates logic and reduces ability - // to do zero-copy processing - const { blockLen, buffer, buffer32 } = this; - const len = data.length; - const offset = data.byteOffset; - const buf = data.buffer; - for (let pos = 0; pos < len;) { - // If buffer is full and we still have input (don't process last block, same as blake2s) - if (this.pos === blockLen) { - swap32IfBE(buffer32); - this.compress(buffer32, 0, false); - swap32IfBE(buffer32); - this.pos = 0; - } - const take = Math.min(blockLen - this.pos, len - pos); - const dataOffset = offset + pos; - // Zero-copy only for full, 4-byte-aligned, non-final blocks. - if (take === blockLen && !(dataOffset % 4) && pos + take < len) { - const data32 = new Uint32Array(buf, dataOffset, Math.floor((len - pos) / 4)); - swap32IfBE(data32); - for (let pos32 = 0; pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) { - this.length += blockLen; - this.compress(data32, pos32, false); - } - swap32IfBE(data32); - continue; - } - buffer.set(data.subarray(pos, pos + take), this.pos); - this.pos += take; - this.length += take; - pos += take; - } - return this; - } - digestInto(out) { - aexists(this); - aoutput(out, this); - const { pos, buffer32 } = this; - this.finished = true; - // Padding - clean(this.buffer.subarray(pos)); - swap32IfBE(buffer32); - this.compress(buffer32, 0, true); - swap32IfBE(buffer32); - // Reject unaligned views explicitly instead of hiding them behind a full scratch copy. - if (out.byteOffset & 3) - throw new RangeError('"digestInto() output" expected 4-byte aligned byteOffset, got ' + out.byteOffset); - const state = this.get(); - const out32 = u32(out); - const full = Math.floor(this.outputLen / 4); - for (let i = 0; i < full; i++) - out32[i] = swap8IfBE(state[i]); - const tail = this.outputLen % 4; - if (!tail) - return; - const off = full * 4; - const word = state[full]; - for (let i = 0; i < tail; i++) - out[off + i] = word >>> (8 * i); - } - digest() { - const { buffer, outputLen } = this; - this.digestInto(buffer); - // Return a copy so callers do not alias the instance scratch buffer used during finalization. - const res = buffer.slice(0, outputLen); - this.destroy(); - return res; - } - _cloneInto(to) { - const { buffer, length, finished, destroyed, outputLen, pos } = this; - // Recreate only `dkLen`; key/salt/personalization are already absorbed into the copied state. - to ||= new this.constructor({ dkLen: outputLen }); - to.set(...this.get()); - to.buffer.set(buffer); - to.destroyed = destroyed; - to.finished = finished; - to.length = length; - to.pos = pos; - // @ts-ignore - to.outputLen = outputLen; - return to; - } - clone() { - return this._cloneInto(); - } -} -/** Internal blake2b hash class with state stored as LE u32 low/high halves. */ -class _BLAKE2b extends _BLAKE2 { - // Same IV words as SHA-512 / BLAKE2b, encoded as LE u32 low/high halves. - v0l = B2B_IV[0] | 0; - v0h = B2B_IV[1] | 0; - v1l = B2B_IV[2] | 0; - v1h = B2B_IV[3] | 0; - v2l = B2B_IV[4] | 0; - v2h = B2B_IV[5] | 0; - v3l = B2B_IV[6] | 0; - v3h = B2B_IV[7] | 0; - v4l = B2B_IV[8] | 0; - v4h = B2B_IV[9] | 0; - v5l = B2B_IV[10] | 0; - v5h = B2B_IV[11] | 0; - v6l = B2B_IV[12] | 0; - v6h = B2B_IV[13] | 0; - v7l = B2B_IV[14] | 0; - v7h = B2B_IV[15] | 0; - constructor(opts = {}) { - const olen = opts.dkLen === undefined ? 64 : opts.dkLen; - super(128, olen); - checkBlake2Opts(olen, opts, 64, 16, 16); - let { key, personalization, salt } = opts; - let keyLength = 0; - if (key !== undefined) { - abytes(key, undefined, 'key'); - keyLength = key.length; - } - // RFC 7693 §2.5: xor `p[0] = 0x0101kknn` into the low 32 bits of `h[0]`; - // the high 32 bits stay at `IV[0]`. - this.v0l ^= this.outputLen | (keyLength << 8) | (0x01 << 16) | (0x01 << 24); - if (salt !== undefined) { - abytes(salt, undefined, 'salt'); - const slt = u32(salt); - this.v4l ^= swap8IfBE(slt[0]); - this.v4h ^= swap8IfBE(slt[1]); - this.v5l ^= swap8IfBE(slt[2]); - this.v5h ^= swap8IfBE(slt[3]); - } - if (personalization !== undefined) { - abytes(personalization, undefined, 'personalization'); - const pers = u32(personalization); - this.v6l ^= swap8IfBE(pers[0]); - this.v6h ^= swap8IfBE(pers[1]); - this.v7l ^= swap8IfBE(pers[2]); - this.v7h ^= swap8IfBE(pers[3]); - } - if (key !== undefined) { - // Pad to blockLen and update - const tmp = new Uint8Array(this.blockLen); - tmp.set(key); - this.update(tmp); - } - } - // prettier-ignore - get() { - let { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this; - return [v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h]; - } - // prettier-ignore - set(v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h) { - this.v0l = v0l | 0; - this.v0h = v0h | 0; - this.v1l = v1l | 0; - this.v1h = v1h | 0; - this.v2l = v2l | 0; - this.v2h = v2h | 0; - this.v3l = v3l | 0; - this.v3h = v3h | 0; - this.v4l = v4l | 0; - this.v4h = v4h | 0; - this.v5l = v5l | 0; - this.v5h = v5h | 0; - this.v6l = v6l | 0; - this.v6h = v6h | 0; - this.v7l = v7l | 0; - this.v7h = v7h | 0; - } - compress(msg, offset, isLast) { - this.get().forEach((v, i) => (BBUF[i] = v)); // First half from state. - BBUF.set(B2B_IV, 16); // Second half from IV. - let { h, l } = fromBig(BigInt(this.length)); - BBUF[24] = B2B_IV[8] ^ l; // Low word of the offset. - BBUF[25] = B2B_IV[9] ^ h; // High word. - // Invert all bits for last block - if (isLast) { - BBUF[28] = ~BBUF[28]; - BBUF[29] = ~BBUF[29]; - } - let j = 0; - const s = BSIGMA; - // SIGMA selects 64-bit message words; multiply by 2 because `msg` stores - // each word as [low32, high32]. - for (let i = 0; i < 12; i++) { - G1b(0, 4, 8, 12, msg, offset + 2 * s[j++]); - G2b(0, 4, 8, 12, msg, offset + 2 * s[j++]); - G1b(1, 5, 9, 13, msg, offset + 2 * s[j++]); - G2b(1, 5, 9, 13, msg, offset + 2 * s[j++]); - G1b(2, 6, 10, 14, msg, offset + 2 * s[j++]); - G2b(2, 6, 10, 14, msg, offset + 2 * s[j++]); - G1b(3, 7, 11, 15, msg, offset + 2 * s[j++]); - G2b(3, 7, 11, 15, msg, offset + 2 * s[j++]); - G1b(0, 5, 10, 15, msg, offset + 2 * s[j++]); - G2b(0, 5, 10, 15, msg, offset + 2 * s[j++]); - G1b(1, 6, 11, 12, msg, offset + 2 * s[j++]); - G2b(1, 6, 11, 12, msg, offset + 2 * s[j++]); - G1b(2, 7, 8, 13, msg, offset + 2 * s[j++]); - G2b(2, 7, 8, 13, msg, offset + 2 * s[j++]); - G1b(3, 4, 9, 14, msg, offset + 2 * s[j++]); - G2b(3, 4, 9, 14, msg, offset + 2 * s[j++]); - } - this.v0l ^= BBUF[0] ^ BBUF[16]; - this.v0h ^= BBUF[1] ^ BBUF[17]; - this.v1l ^= BBUF[2] ^ BBUF[18]; - this.v1h ^= BBUF[3] ^ BBUF[19]; - this.v2l ^= BBUF[4] ^ BBUF[20]; - this.v2h ^= BBUF[5] ^ BBUF[21]; - this.v3l ^= BBUF[6] ^ BBUF[22]; - this.v3h ^= BBUF[7] ^ BBUF[23]; - this.v4l ^= BBUF[8] ^ BBUF[24]; - this.v4h ^= BBUF[9] ^ BBUF[25]; - this.v5l ^= BBUF[10] ^ BBUF[26]; - this.v5h ^= BBUF[11] ^ BBUF[27]; - this.v6l ^= BBUF[12] ^ BBUF[28]; - this.v6h ^= BBUF[13] ^ BBUF[29]; - this.v7l ^= BBUF[14] ^ BBUF[30]; - this.v7h ^= BBUF[15] ^ BBUF[31]; - clean(BBUF); - } - destroy() { - this.destroyed = true; - clean(this.buffer32); - this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } -} -/** - * Blake2b hash function. 64-bit. 1.5x slower than blake2s in JS. - * @param msg - message that would be hashed - * @param opts - Optional output, MAC, salt, and personalization settings. - * `dkLen` must be 1..64 bytes; `salt` and `personalization`, if present, - * must be 16 bytes each. See {@link Blake2Opts}. - * @returns Digest bytes. - * @example - * Hash a message with Blake2b. - * ```ts - * blake2b(new Uint8Array([97, 98, 99])); - * ``` - */ -const blake2b = /* @__PURE__ */ createHasher((opts) => new _BLAKE2b(opts)); - -var readline = {}; - -var crypto = {}; - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - - -function log2( V ) -{ - return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) ); -} - - -function formatHash(b, title) { - const a = new DataView(b.buffer, b.byteOffset, b.byteLength); - let S = ""; - for (let i=0; i<4; i++) { - if (i>0) S += "\n"; - S += "\t\t"; - for (let j=0; j<4; j++) { - if (j>0) S += " "; - S += a.getUint32(i*16+j*4).toString(16).padStart(8, "0"); - } - } - if (title) S = title + "\n" + S; - return S; -} - -function hashIsEqual(h1, h2) { - if (h1.byteLength != h2.byteLength) return false; - var dv1 = new Int8Array(h1); - var dv2 = new Int8Array(h2); - for (var i = 0 ; i != h1.byteLength ; i++) - { - if (dv1[i] != dv2[i]) return false; - } - return true; -} - -function cloneHasher(h) { - return h.clone(); -} - -function fromPartialHash(partial) { - // NOTE: this is unsafe and uses internal API - const buf = partial.subarray(0, 128); - const rest = u32(partial.subarray(128)); - const res = blake2b.create({ dkLen: 64 }); - res.buffer.set(buf); - (res.v0l = rest[0] | 0), (res.v0h = rest[1] | 0); - (res.v1l = rest[2] | 0), (res.v1h = rest[3] | 0); - (res.v2l = rest[4] | 0), (res.v2h = rest[5] | 0); - (res.v3l = rest[6] | 0), (res.v3h = rest[7] | 0); - (res.v4l = rest[8] | 0), (res.v4h = rest[9] | 0); - (res.v5l = rest[10] | 0), (res.v5h = rest[11] | 0); - (res.v6l = rest[12] | 0), (res.v6h = rest[13] | 0); - (res.v7l = rest[14] | 0), (res.v7h = rest[15] | 0); - const shift = 2 ** 32; - const len = rest[16] + rest[17] * shift; - const pos = rest[18] + rest[19] * shift; - res.length = len + pos; - res.pos = pos; - return res; -} - -function toPartialHash(hash){ - // NOTE: this is unsafe and uses internal API - const res = new Uint8Array(216); - const res32 = u32(res.subarray(128)); - res.set(hash.buffer); - (res32[0] = hash.v0l), (res32[1] = hash.v0h); - (res32[2] = hash.v1l), (res32[3] = hash.v1h); - (res32[4] = hash.v2l), (res32[5] = hash.v2h); - (res32[6] = hash.v3l), (res32[7] = hash.v3h); - (res32[8] = hash.v4l), (res32[9] = hash.v4h); - (res32[10] = hash.v5l), (res32[11] = hash.v5h); - (res32[12] = hash.v6l), (res32[13] = hash.v6h); - (res32[14] = hash.v7l), (res32[15] = hash.v7h); - res32[18] = hash.pos; - res32[16] = hash.length-hash.pos; - return res; -} - -async function sameRatio$2(curve, g1s, g1sx, g2s, g2sx) { - if (curve.G1.isZero(g1s)) return false; - if (curve.G1.isZero(g1sx)) return false; - if (curve.G2.isZero(g2s)) return false; - if (curve.G2.isZero(g2sx)) return false; - // return curve.F12.eq(curve.pairing(g1s, g2sx), curve.pairing(g1sx, g2s)); - const res = await curve.pairingEq(g1s, g2sx, curve.G1.neg(g1sx), g2s); - return res; -} - - -function askEntropy() { - // Use the browser prompt only when a real DOM window exists. "not Node" is - // NOT the same as "browser" (Bun/Deno/edge/SES have neither window nor are - // classic Node), so detect the actual API. - if (typeof window !== "undefined" && typeof window.prompt === "function") { - return window.prompt("Enter a random text. (Entropy): ", ""); - } else { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); - - return new Promise((resolve) => { - rl.question("Enter a random text. (Entropy): ", (input) => resolve(input) ); - }); - } -} - -function getRandomBytes(n) { - let array = new Uint8Array(n); - if (crypto && crypto.randomFillSync) { // Node: no per-call size limit - crypto.randomFillSync(array); - } else if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) { - // Web Crypto caps each call at 65536 bytes; fill in windows. - for (let i = 0; i < n; i += 65536) { - globalThis.crypto.getRandomValues(array.subarray(i, Math.min(i + 65536, n))); - } - } else { - throw new Error("No secure random source available"); - } - return array; -} - -async function sha256digest(data) { - if (crypto && crypto.createHash) { // Node - return crypto.createHash("sha256").update(data).digest(); - } else { - // Web Crypto: pass the view (data), not data.buffer, so byteOffset and - // byteLength of subarray views are respected. - const buffer = await globalThis.crypto.subtle.digest("SHA-256", data); - return new Uint8Array(buffer); - } -} - -/** - * @param {Uint8Array} data - * @param {number} offset - */ -function readUInt32BE(data, offset) { - return new DataView(data.buffer).getUint32(offset, false); -} - -async function getRandomRng(entropy) { - // Generate a random Rng - while (!entropy) { - entropy = await askEntropy(); - } - const hasher = blake2b.create(64); - hasher.update(getRandomBytes(64)); - const enc = new TextEncoder(); // always utf-8 - hasher.update(enc.encode(entropy)); - const hash = hasher.digest(); - - const seed = []; - for (let i=0;i<8;i++) { - seed[i] = readUInt32BE(hash, i*4); - } - const rng = new ChaCha(seed); - return rng; -} - -async function rngFromBeaconParams(beaconHash, numIterationsExp) { - let nIterationsInner; - let nIterationsOuter; - if (numIterationsExp<32) { - nIterationsInner = (1 << numIterationsExp) >>> 0; - nIterationsOuter = 1; - } else { - nIterationsInner = 0x100000000; - nIterationsOuter = (1 << (numIterationsExp-32)) >>> 0; - } - - let curHash = beaconHash; - for (let i=0; i { - res[k] = stringifyBigIntsWithField(Fr, o[k]); - }); - return res; - } else if ((typeof(o) == "bigint") || o.eq !== undefined) { - return o.toString(10); - } else { - return o; - } -} - -const HEADER_ZKEY_SECTION = 1; - -const GROTH16_PROTOCOL_ID = 1; -const PLONK_PROTOCOL_ID = 2; -const FFLONK_PROTOCOL_ID = 10; - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -// FFlonk constants -const FF_T_POL_DEG_MIN = 3; - -// ZKEY constants -const ZKEY_FF_NSECTIONS = 17; - -const ZKEY_FF_HEADER_SECTION = 2; -const ZKEY_FF_ADDITIONS_SECTION = 3; -const ZKEY_FF_A_MAP_SECTION = 4; -const ZKEY_FF_B_MAP_SECTION = 5; -const ZKEY_FF_C_MAP_SECTION = 6; -const ZKEY_FF_QL_SECTION = 7; -const ZKEY_FF_QR_SECTION = 8; -const ZKEY_FF_QM_SECTION = 9; -const ZKEY_FF_QO_SECTION = 10; -const ZKEY_FF_QC_SECTION = 11; -const ZKEY_FF_SIGMA1_SECTION = 12; -const ZKEY_FF_SIGMA2_SECTION = 13; -const ZKEY_FF_SIGMA3_SECTION = 14; -const ZKEY_FF_LAGRANGE_SECTION = 15; -const ZKEY_FF_PTAU_SECTION = 16; -const ZKEY_FF_C0_SECTION = 17; - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function writeHeader(fd, zkey) { - - // Write the header - /////////// - await startWriteSection(fd, 1); - await fd.writeULE32(1); // Groth - await endWriteSection(fd); - - // Write the Groth header section - /////////// - - const curve = await getCurveFromQ(zkey.q); - - await startWriteSection(fd, 2); - const primeQ = curve.q; - const n8q = (Math.floor( (Scalar.bitLength(primeQ) - 1) / 64) +1)*8; - - const primeR = curve.r; - const n8r = (Math.floor( (Scalar.bitLength(primeR) - 1) / 64) +1)*8; - - await fd.writeULE32(n8q); - await writeBigInt(fd, primeQ, n8q); - await fd.writeULE32(n8r); - await writeBigInt(fd, primeR, n8r); - await fd.writeULE32(zkey.nVars); // Total number of bars - await fd.writeULE32(zkey.nPublic); // Total number of public vars (not including ONE) - await fd.writeULE32(zkey.domainSize); // domainSize - await writeG1(fd, curve, zkey.vk_alpha_1); - await writeG1(fd, curve, zkey.vk_beta_1); - await writeG2(fd, curve, zkey.vk_beta_2); - await writeG2(fd, curve, zkey.vk_gamma_2); - await writeG1(fd, curve, zkey.vk_delta_1); - await writeG2(fd, curve, zkey.vk_delta_2); - - await endWriteSection(fd); - - -} - -async function writeG1(fd, curve, p) { - const buff = new Uint8Array(curve.G1.F.n8*2); - curve.G1.toRprLEM(buff, 0, p); - await fd.write(buff); -} - -async function writeG2(fd, curve, p) { - const buff = new Uint8Array(curve.G2.F.n8*2); - curve.G2.toRprLEM(buff, 0, p); - await fd.write(buff); -} - -async function readG1(fd, curve, toObject) { - const buff = await fd.read(curve.G1.F.n8*2); - const res = curve.G1.fromRprLEM(buff, 0); - return toObject ? curve.G1.toObject(res) : res; -} - -async function readG2(fd, curve, toObject) { - const buff = await fd.read(curve.G2.F.n8*2); - const res = curve.G2.fromRprLEM(buff, 0); - return toObject ? curve.G2.toObject(res) : res; -} - - -async function readHeader$1(fd, sections, toObject, options) { - // Read Header - ///////////////////// - await startReadUniqueSection$1(fd, sections, 1); - const protocolId = await fd.readULE32(); - await endReadSection$1(fd); - - if (protocolId === GROTH16_PROTOCOL_ID) { - return await readHeaderGroth16(fd, sections, toObject, options); - } else if (protocolId === PLONK_PROTOCOL_ID) { - return await readHeaderPlonk(fd, sections, toObject, options); - } else if (protocolId === FFLONK_PROTOCOL_ID) { - return await readHeaderFFlonk(fd, sections, toObject, options); - } else { - throw new Error("Protocol not supported: "); - } -} - - - - -async function readHeaderGroth16(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "groth16"; - - // Read Groth Header - ///////////////////// - await startReadUniqueSection$1(fd, sections, 2); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await readBigInt$1(fd, n8q); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await readBigInt$1(fd, n8r); - zkey.curve = await getCurveFromQ(zkey.q, options); - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.vk_alpha_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_beta_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_beta_2 = await readG2(fd, zkey.curve, toObject); - zkey.vk_gamma_2 = await readG2(fd, zkey.curve, toObject); - zkey.vk_delta_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_delta_2 = await readG2(fd, zkey.curve, toObject); - await endReadSection$1(fd); - - return zkey; - -} - -async function readHeaderPlonk(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "plonk"; - - // Read Plonk Header - ///////////////////// - await startReadUniqueSection$1(fd, sections, 2); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await readBigInt$1(fd, n8q); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await readBigInt$1(fd, n8r); - zkey.curve = await getCurveFromQ(zkey.q, options); - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.nAdditions = await fd.readULE32(); - zkey.nConstraints = await fd.readULE32(); - zkey.k1 = await fd.read(n8r); - zkey.k2 = await fd.read(n8r); - - zkey.Qm = await readG1(fd, zkey.curve, toObject); - zkey.Ql = await readG1(fd, zkey.curve, toObject); - zkey.Qr = await readG1(fd, zkey.curve, toObject); - zkey.Qo = await readG1(fd, zkey.curve, toObject); - zkey.Qc = await readG1(fd, zkey.curve, toObject); - zkey.S1 = await readG1(fd, zkey.curve, toObject); - zkey.S2 = await readG1(fd, zkey.curve, toObject); - zkey.S3 = await readG1(fd, zkey.curve, toObject); - zkey.X_2 = await readG2(fd, zkey.curve, toObject); - - await endReadSection$1(fd); - - return zkey; -} - -async function readHeaderFFlonk(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "fflonk"; - zkey.protocolId = FFLONK_PROTOCOL_ID; - - await startReadUniqueSection$1(fd, sections, ZKEY_FF_HEADER_SECTION); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await readBigInt$1(fd, n8q); - zkey.curve = await getCurveFromQ(zkey.q, options); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await readBigInt$1(fd, n8r); - - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.nAdditions = await fd.readULE32(); - zkey.nConstraints = await fd.readULE32(); - - zkey.k1 = await fd.read(n8r); - zkey.k2 = await fd.read(n8r); - - zkey.w3 = await fd.read(n8r); - zkey.w4 = await fd.read(n8r); - zkey.w8 = await fd.read(n8r); - zkey.wr = await fd.read(n8r); - - zkey.X_2 = await readG2(fd, zkey.curve, toObject); - - zkey.C0 = await readG1(fd, zkey.curve, toObject); - - await endReadSection$1(fd); - - return zkey; -} - -async function readZKey(fileName, toObject) { - const {fd, sections} = await readBinFile$1(fileName, "zkey", 1); - - const zkey = await readHeader$1(fd, sections, toObject); - - const Fr = new F1Field(zkey.r); - const Rr = Scalar.mod(Scalar.shl(1, zkey.n8r*8), zkey.r); - const Rri = Fr.inv(Rr); - const Rri2 = Fr.mul(Rri, Rri); - - let curve = await getCurveFromQ(zkey.q); - - // Read IC Section - /////////// - await startReadUniqueSection$1(fd, sections, 3); - zkey.IC = []; - for (let i=0; i<= zkey.nPublic; i++) { - const P = await readG1(fd, curve, toObject); - zkey.IC.push(P); - } - await endReadSection$1(fd); - - - // Read Coefs - /////////// - await startReadUniqueSection$1(fd, sections, 4); - const nCCoefs = await fd.readULE32(); - zkey.ccoefs = []; - for (let i=0; i0) { - const paramsBuff = new Uint8Array(params); - await fd.writeULE32(paramsBuff.byteLength); - await fd.write(paramsBuff); - } else { - await fd.writeULE32(0); - } - -} - -async function writeMPCParams(fd, curve, mpcParams) { - await startWriteSection(fd, 10); - await fd.write(mpcParams.csHash); - await fd.writeULE32(mpcParams.contributions.length); - for (let i=0; i. -*/ - - - -async function write(fd, witness, prime) { - - await startWriteSection(fd, 1); - const n8 = (Math.floor( (Scalar.bitLength(prime) - 1) / 64) +1)*8; - await fd.writeULE32(n8); - await writeBigInt(fd, prime, n8); - await fd.writeULE32(witness.length); - await endWriteSection(fd); - - await startWriteSection(fd, 2); - for (let i=0; i. -*/ - -const {stringifyBigInts: stringifyBigInts$4} = utils; - -async function groth16Prove(zkeyFileName, witnessFileName, logger, options) { - // Opt-in periodic memory-usage logging (heap/RSS/external/ArrayBuffers). - // options.memoryLogging: true (1s interval) or an interval in ms. - // Node-only: process.memoryUsage does not exist in browsers. - let memTimer = null; - if (logger && options && options.memoryLogging - && typeof process !== "undefined" && typeof process.memoryUsage === "function") { - const interval = Number(options.memoryLogging) > 1 ? Number(options.memoryLogging) : 1000; - memTimer = monitorMemoryUsage(logger, interval); - } - try { - return await _groth16Prove(zkeyFileName, witnessFileName, logger, options); - } finally { - if (memTimer) { - clearInterval(memTimer); - memUsage(logger); - } - } -} - -async function _groth16Prove(zkeyFileName, witnessFileName, logger, options) { - - const {fd: fdWtns, sections: sectionsWtns} = await readBinFile$1(witnessFileName, "wtns", 2, 1<<25, 1<<23); - - const wtns = await readHeader(fdWtns, sectionsWtns); - - const {fd: fdZKey, sections: sectionsZKey} = await readBinFile$1(zkeyFileName, "zkey", 2, 1<<25, 1<<23); - - const zkey = await readHeader$1(fdZKey, sectionsZKey, undefined, options); - - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - if (!Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness != zkey.nVars) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}`); - } - - const curve = zkey.curve; - const Fr = curve.Fr; - const G1 = curve.G1; - const G2 = curve.G2; - - options = options || {}; - - // MSM batching mode, threaded to every multiexp below: - // "auto" (default) use the batch-affine MSM module only for - // cache-friendly chunk sizes (where it is measurably faster); - // "enabled" always use it (best for small/medium circuits); - // "disabled" never use it (plain in-module multiexp; lowest memory). - const msmBatching = options.msmBatching || "auto"; - if (msmBatching !== "auto" && msmBatching !== "enabled" && msmBatching !== "disabled") { - throw new Error(`groth16Prove: invalid msmBatching "${msmBatching}" (expected "auto", "enabled" or "disabled")`); - } - // msmGlv / msmGls: "auto" (default -- use the G1/G2 endomorphism MSM paths - // where the curve supports them; the wasm still gates internally on chunk - // sizes) or "disabled" (generic batch accumulation). A/B and debugging - // aids, like msmBatching. - const msmGlv = options.msmGlv || "auto"; - const msmGls = options.msmGls || "auto"; - for (const [name, v] of [["msmGlv", msmGlv], ["msmGls", msmGls]]) { - if (v !== "auto" && v !== "disabled") { - throw new Error(`groth16Prove: invalid ${name} "${v}" (expected "auto" or "disabled")`); - } - } - const msmOpts = { batch: msmBatching, glv: msmGlv, gls: msmGls }; - - const power = log2(zkey.domainSize); - - if (logger) logger.debug("Reading Wtns"); - const buffWitness = await readSection$1(fdWtns, sectionsWtns, 2); - - // Reader for a zkey section that returns an arbitrary sub-range directly from - // disk, used to feed multiExp bases to the workers in chunks instead of - // reading the whole (potentially hundreds of MB) section into one buffer and - // slicing it. Bounds the bases resident in RAM to a few in-flight chunks. - const mkSectionReader = (idSection) => { - const start = sectionsZKey[idSection][0].p; - const size = sectionsZKey[idSection][0].size; - return async (off, len) => { - if (off + len > size) throw new Error(`groth16Prove: read out of range of section ${idSection}`); - const buff = new Uint8Array(len); - await fdZKey.readToBuffer(buff, 0, len, start + off); - return buff; - }; - }; - - let resH; - let resHPromise; - let buffPodd_T; - - let abcPromise = (async function (){ - let buffA_T, buffB_T, buffC_T; - - await (async function (){ - if (logger) logger.debug("Reading Coeffs"); - const buffCoeffs = await readSection$1(fdZKey, sectionsZKey, 4); - - if (logger) logger.debug("Building ABC"); - - if (options.buildABC === "js") { - [buffA_T, buffB_T, buffC_T] = await buildABC1(curve, zkey, buffWitness, buffCoeffs, logger); - } else if (options.buildABC === "stream") { - const p = pickStreamParams(curve, zkey, buffCoeffs, options); - [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); - } else { - // Default: streaming build (bounded worker memory, tunable - // parallelism). The per-chunk witness gather keeps the witness - // out of WASM entirely, so there is no witness size limit. - const p = pickStreamParams(curve, zkey, buffCoeffs, options); - if (logger) logger.debug(`buildABC: stream nChunks=${p.nChunks} maxInFlight=${p.maxInFlight}`); - [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); - } - })(); - - - // Do not call gc() here. gc() is a stop-the-world pause that blocks the - // Node.js event loop. If the pause exceeds the worker idle-termination - // timeout (1s), a worker closes its port while the main thread is blocked, - // and the next task dispatched to it is silently dropped → hang. The - // coefficients buffer goes out of scope at the end of the inner IIFE above - // and is reclaimed by V8's incremental GC automatically. - - const inc = power === Fr.s ? curve.Fr.shift : curve.Fr.w[power+1]; - - let buffAodd_T, buffBodd_T, buffCodd_T; - // The IFFT input (buffX_T) is dropped immediately, and the FFT input - // (buffXodd) goes out of scope right after -- so both can be consumed - // (consume=true), skipping ffjavascript's defensive full-input copy. - await Promise.all([ - (async function () { - let buffA = await Fr.ifft(buffA_T, "", "", logger, "IFFT_A", true); - buffA_T = null; - const buffAodd = await Fr.batchApplyKey(buffA, Fr.e(1), inc); - buffAodd_T = await Fr.fft(buffAodd, "", "", logger, "FFT_A", true); - })(), - (async function () { - let buffB = await Fr.ifft(buffB_T, "", "", logger, "IFFT_B", true); - buffB_T = null; - const buffBodd = await Fr.batchApplyKey(buffB, Fr.e(1), inc); - buffBodd_T = await Fr.fft(buffBodd, "", "", logger, "FFT_B", true); - })(), - (async function () { - let buffC = await Fr.ifft(buffC_T, "", "", logger, "IFFT_C", true); - buffC_T = null; - const buffCodd = await Fr.batchApplyKey(buffC, Fr.e(1), inc); - buffCodd_T = await Fr.fft(buffCodd, "", "", logger, "FFT_C", true); - })(), - ]); - - if (logger) logger.debug("Join ABC"); - buffPodd_T = await joinABC(curve, zkey, buffAodd_T, buffBodd_T, buffCodd_T, logger); - if (logger) logger.debug("Join ABC finished"); - buffAodd_T = null; - buffBodd_T = null; - buffCodd_T = null; - - if (globalThis.gc) {globalThis.gc();} - })(); - //await abcPromise; - - let proof = {}; - - async function calcPiA(){ - if (logger) logger.debug("Reading A Points"); - proof.pi_a = await curve.G1.multiExpAffineChunked(mkSectionReader(5), sectionsZKey[5][0].size, buffWitness, logger, "multiexp A", msmOpts); - } - - let piaPromise = calcPiA(); - //await piaPromise; - - let pib1; - - async function calcPiB1() { - if (logger) logger.debug("Reading B1 Points"); - pib1 = await curve.G1.multiExpAffineChunked(mkSectionReader(6), sectionsZKey[6][0].size, buffWitness, logger, "multiexp B1", msmOpts); - } - - let pib1Promise = calcPiB1(); - //await pib1Promise; - - async function calcPiB() { - if (logger) logger.debug("Reading B2 Points"); - proof.pi_b = await curve.G2.multiExpAffineChunked(mkSectionReader(7), sectionsZKey[7][0].size, buffWitness, logger, "multiexp B2", msmOpts); - } - - let pibPromise = calcPiB(); - //await pibPromise; - - let picPromise = (async function (){ - if (logger) logger.debug("Reading C Points"); - proof.pi_c = await curve.G1.multiExpAffineChunked(mkSectionReader(8), sectionsZKey[8][0].size, buffWitness.slice((zkey.nPublic+1)*curve.Fr.n8), logger, "multiexp C", msmOpts); - })(); - //await picPromise; - - resHPromise = (async function (){ - if (logger) logger.debug("Reading H Points"); - await abcPromise; - resH = await curve.G1.multiExpAffineChunked(mkSectionReader(9), sectionsZKey[9][0].size, buffPodd_T, logger, "multiexp H", msmOpts); - })(); - //await resHPromise; - - - const r = curve.Fr.random(); - const s = curve.Fr.random(); - - await piaPromise; - proof.pi_a = G1.add( proof.pi_a, zkey.vk_alpha_1 ); - proof.pi_a = G1.add( proof.pi_a, G1.timesFr( zkey.vk_delta_1, r )); - - await pibPromise; - proof.pi_b = G2.add( proof.pi_b, zkey.vk_beta_2 ); - proof.pi_b = G2.add( proof.pi_b, G2.timesFr( zkey.vk_delta_2, s )); - - await pib1Promise; - pib1 = G1.add( pib1, zkey.vk_beta_1 ); - pib1 = G1.add( pib1, G1.timesFr( zkey.vk_delta_1, s )); - - await Promise.all([picPromise, resHPromise]); - proof.pi_c = G1.add(proof.pi_c, resH); - - - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( proof.pi_a, s )); - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( pib1, r )); - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( zkey.vk_delta_1, Fr.neg(Fr.mul(r,s) ))); - - - let publicSignals = []; - - for (let i=1; i<= zkey.nPublic; i++) { - const b = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8); - publicSignals.push(Scalar.fromRprLE(b)); - } - - proof.pi_a = G1.toObject(G1.toAffine(proof.pi_a)); - proof.pi_b = G2.toObject(G2.toAffine(proof.pi_b)); - proof.pi_c = G1.toObject(G1.toAffine(proof.pi_c)); - - proof.protocol = "groth16"; - proof.curve = curve.name; - - await fdZKey.close(); - await fdWtns.close(); - - proof = stringifyBigInts$4(proof); - publicSignals = stringifyBigInts$4(publicSignals); - - return {proof, publicSignals}; -} - - -async function buildABC1(curve, zkey, witness, coeffs, logger) { - const n8 = curve.Fr.n8; - const sCoef = 4*3 + zkey.n8r; - const nCoef = (coeffs.byteLength-4) / sCoef; - - const outBuffA = new BigBuffer(zkey.domainSize * n8); - const outBuffB = new BigBuffer(zkey.domainSize * n8); - const outBuffC = new BigBuffer(zkey.domainSize * n8); - - const outBuf = [ outBuffA, outBuffB ]; - for (let i=0; i coeffsDV[Math.floor(pos / PAGE_LEN)].getUint32(pos % PAGE_LEN, true); - } else { - const coeffsDV = new DataView(coeffs.buffer, coeffs.byteOffset, coeffs.byteLength); - getUint32 = (pos) => coeffsDV.getUint32(pos, true); - } - function getCutPoint(v) { - let m = 0, n = getUint32(0); - while (m < n) { - const k = Math.floor((n + m) / 2); - const va = getUint32(4 + k * sCoef + 4); - if (va > v) n = k - 1; else if (va < v) m = k + 1; else n = k; - } - return 4 + m * sCoef; - } - - const elementsPerChunk = Math.floor((domainSize - 1) / nChunks) + 1; - const cutPoints = []; - for (let i = 0; i < nChunks; i++) cutPoints.push(getCutPoint(i * elementsPerChunk)); - cutPoints.push(coeffs.byteLength); - - // Return a flat Uint8Array when the domain fits under BigBuffer's 1 GiB page, - // so the downstream IFFT can consume it in place (skip its defensive copy). - // Larger domains stay paged BigBuffers (the IFFT flattens those as before). - const outBytes = domainSize * n8; - const mkOut = () => (outBytes < (1 << 30)) ? new Uint8Array(outBytes) : new BigBuffer(outBytes); - const outBuffA = mkOut(); - const outBuffB = mkOut(); - const outBuffC = mkOut(); - - const inFlight = new Set(); - const tasks = []; - for (let i = 0; i < nChunks; i++) { - const outOffset = i * elementsPerChunk; - const n = Math.min(elementsPerChunk, domainSize - outOffset); - if (n <= 0) break; - const cpA = cutPoints[i], cpB = cutPoints[i + 1]; - while (inFlight.size >= maxInFlight) await Promise.race(inFlight); - if (logger) logger.debug(`buildABCStream: ${i}/${nChunks}`); - const op = (async () => { - // Gather the witness values this chunk references into a compact - // buffer (one entry per coefficient, in coefficient order) and - // rewrite each coefficient's s-index to its sequential position. - // The witness itself never enters WASM, so its size is unbounded - // (it can stay a BigBuffer) and each task ships only what it uses - // -- typically much less than a full witness copy per task. - const coeffChunk = coeffs.slice(cpA, cpB); - const nCoefChunk = (cpB - cpA) / sCoef; - const gathered = new Uint8Array(nCoefChunk * n8); - // Hot loop (one iteration per coefficient): use typed-array lane - // copies instead of set(subarray) -- per-element memcpy dispatch - // dominated the profile otherwise. Uint32 lanes on purpose: the - // data is integer bit patterns, and Float64Array stores may - // legally canonicalize NaN-patterned lanes (SetValueInBuffer is - // implementation-defined for NaN encodings). The s-field offsets - // are 4-byte aligned (sCoef and the +8 offset are multiples of 4). - const chunkU32 = new Uint32Array(coeffChunk.buffer, coeffChunk.byteOffset, coeffChunk.byteLength >> 2); - const sStep = sCoef >> 2; - const laneFast = !!witness.buffer && ((witness.byteOffset & 3) === 0) && (n8 === 32); - if (laneFast) { - const wU32 = new Uint32Array(witness.buffer, witness.byteOffset, witness.byteLength >> 2); - const gU32 = new Uint32Array(gathered.buffer); - for (let j = 0; j < nCoefChunk; j++) { - const si = chunkU32[j * sStep + 2]; - const so = si << 3, go = j << 3; - gU32[go] = wU32[so]; gU32[go + 1] = wU32[so + 1]; - gU32[go + 2] = wU32[so + 2]; gU32[go + 3] = wU32[so + 3]; - gU32[go + 4] = wU32[so + 4]; gU32[go + 5] = wU32[so + 5]; - gU32[go + 6] = wU32[so + 6]; gU32[go + 7] = wU32[so + 7]; - chunkU32[j * sStep + 2] = j; - } - } else { - const witnessIsView = !!witness.buffer; - for (let j = 0; j < nCoefChunk; j++) { - const s = chunkU32[j * sStep + 2]; - if (witnessIsView) gathered.set(witness.subarray(s * n8, (s + 1) * n8), j * n8); - else gathered.set(witness.slice(s * n8, (s + 1) * n8), j * n8); - chunkU32[j * sStep + 2] = j; - } - } - const task = [ - {cmd: "ALLOCSET", var: 0, buff: coeffChunk}, - {cmd: "ALLOCSET", var: 1, buff: gathered}, - {cmd: "ALLOC", var: 2, len: n * n8}, - {cmd: "ALLOC", var: 3, len: n * n8}, - {cmd: "ALLOC", var: 4, len: n * n8}, - {cmd: "CALL", fnName: "qap_buildABC", params: [ - {var: 0}, {val: nCoefChunk}, {var: 1}, - {var: 2}, {var: 3}, {var: 4}, - {val: outOffset}, {val: n}, {val: 0}, {val: nCoefChunk}, - ]}, - {cmd: "GET", out: 0, var: 2, len: n * n8}, - {cmd: "GET", out: 1, var: 3, len: n * n8}, - {cmd: "GET", out: 2, var: 4, len: n * n8}, - ]; - const r = await curve.tm.queueAction(task, [coeffChunk.buffer, gathered.buffer]); - outBuffA.set(r[0], outOffset * n8); - outBuffB.set(r[1], outOffset * n8); - outBuffC.set(r[2], outOffset * n8); - })(); - const slot = op.finally(() => inFlight.delete(slot)); - inFlight.add(slot); - tasks.push(slot); - } - await Promise.all(tasks); - return [outBuffA, outBuffB, outBuffC]; -} - -async function joinABC(curve, zkey, a, b, c, logger) { - const MAX_CHUNK_SIZE = 1 << 16; - - const n8 = curve.Fr.n8; - const nElements = Math.floor(a.byteLength / curve.Fr.n8); - - const promises = []; - - for (let i=0; i { - memUsage(logger); - }, interval); -} - -async function open$1(fileName, openFlags, cacheSize, pageSize) { - cacheSize = cacheSize || 4096*64; - if (typeof openFlags !== "number" && ["w+", "wx+", "r", "ax+", "a+"].indexOf(openFlags) <0) - throw new Error("Invalid open option"); - const fd =await fs.promises.open(fileName, openFlags); - - const stats = await fd.stat(); - - return new FastFile$1(fd, stats, cacheSize, pageSize, fileName); -} - - -let FastFile$1 = class FastFile { - - constructor(fd, stats, cacheSize, pageSize, fileName) { - this.fileName = fileName; - this.fd = fd; - this.pos = 0; - this.pageSize = pageSize || (1 << 8); - while (this.pageSize < stats.blksize) { - this.pageSize *= 2; - } - this.totalSize = stats.size; - this.totalPages = Math.floor((stats.size -1) / this.pageSize)+1; - this.maxPagesLoaded = Math.floor( cacheSize / this.pageSize)+1; - this.pages = {}; - this.pendingLoads = []; - this.writing = false; - this.reading = false; - this.avBuffs = []; - this.history = {}; - } - - _loadPage(p) { - const self = this; - const P = new Promise((resolve, reject)=> { - self.pendingLoads.push({ - page: p, - resolve: resolve, - reject: reject - }); - }); - self.__statusPage("After Load request: ", p); - return P; - } - - __statusPage(s, p) { - const logEntry = []; - const self=this; - if (!self.logHistory) return; - logEntry.push("==" + s+ " " +p); - let S = ""; - for (let i=0; i " + self.history[p][i][j]); - } - } - } - - - - _triggerLoad() { - const self = this; - - if (self.reading) return; - if (self.pendingLoads.length==0) return; - - const pageIdxs = Object.keys(self.pages); - - const deletablePages = []; - for (let i=0; i0) && - ( (typeof self.pages[self.pendingLoads[0].page] != "undefined" ) - ||( (freePages>0) - ||(deletablePages.length>0)))) { - const load = self.pendingLoads.shift(); - if (typeof self.pages[load.page] != "undefined") { - self.pages[load.page].pendingOps ++; - const idx = deletablePages.indexOf(load.page); - if (idx>=0) deletablePages.splice(idx, 1); - if (self.pages[load.page].loading) { - self.pages[load.page].loading.push(load); - } else { - load.resolve(); - } - self.__statusPage("After Load (cached): ", load.page); - - } else { - if (freePages) { - freePages--; - } else { - const fp = deletablePages.shift(); - self.__statusPage("Before Unload: ", fp); - self.avBuffs.unshift(self.pages[fp]); - delete self.pages[fp]; - self.__statusPage("After Unload: ", fp); - } - - if (load.page>=self.totalPages) { - self.pages[load.page] = getNewPage(); - load.resolve(); - self.__statusPage("After Load (new): ", load.page); - } else { - self.reading = true; - self.pages[load.page] = getNewPage(); - self.pages[load.page].loading = [load]; - ops.push(self.fd.read(self.pages[load.page].buff, 0, self.pageSize, load.page*self.pageSize).then((res)=> { - self.pages[load.page].size = res.bytesRead; - const loading = self.pages[load.page].loading; - delete self.pages[load.page].loading; - for (let i=0; i { - load.reject(err); - })); - self.__statusPage("After Load (loading): ", load.page); - } - } - } - // if (ops.length>1) console.log(ops.length); - - Promise.all(ops).then( () => { - self.reading = false; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - self._tryClose(); - }); - - function getNewPage() { - if (self.avBuffs.length>0) { - const p = self.avBuffs.shift(); - p.dirty = false; - p.pendingOps = 1; - p.size =0; - return p; - } else { - return { - dirty: false, - buff: new Uint8Array(self.pageSize), - pendingOps: 1, - size: 0 - }; - } - } - - } - - - _triggerWrite() { - const self = this; - if (self.writing) return; - - const pageIdxs = Object.keys(self.pages); - - const ops = []; - - for (let i=0; i { - page.writing = false; - return; - }, (err) => { - console.log("ERROR Writing: "+err); - self.error = err; - self._tryClose(); - })); - } - } - - if (self.writing) { - Promise.all(ops).then( () => { - self.writing = false; - setImmediate(self._triggerWrite.bind(self)); - self._tryClose(); - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - }); - } - } - - _getDirtyPage() { - for (let p in this.pages) { - if (this.pages[p].dirty) return p; - } - return -1; - } - - async write(buff, pos) { - if (buff.byteLength == 0) return; - const self = this; -/* - if (buff.byteLength > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(buff.byteLength * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } -*/ - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+buff.byteLength; - if (self.totalSize < pos + buff.byteLength) self.totalSize = pos + buff.byteLength; - if (self.pendingClose) - throw new Error("Writing a closing file"); - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + buff.byteLength -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - let r = buff.byteLength; - while (r>0) { - await pagePromises[p-firstPage]; - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = buff.slice( buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.pages[p].buff.buffer, o, l); - dstView.set(srcView); - self.pages[p].dirty = true; - self.pages[p].pendingOps --; - self.pages[p].size = Math.max(o+l, self.pages[p].size); - if (p>=self.totalPages) { - self.totalPages = p+1; - } - r = r-l; - p ++; - o = 0; - if (!self.writing) setImmediate(self._triggerWrite.bind(self)); - } - } - - async read(len, pos) { - const self = this; - let buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - async readToBuffer(buffDst, offset, len, pos) { - if (len == 0) { - return; - } - const self = this; - if (len > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(len * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+len; - if (self.pendingClose) - throw new Error("Reading a closing file"); - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + len -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - // Remaining bytes to read - let r = pos + len > self.totalSize ? len - (pos + len - self.totalSize): len; - while (r>0) { - await pagePromises[p - firstPage]; - self.__statusPage("After Await (read): ", p); - - // bytes to copy from this page - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = new Uint8Array(self.pages[p].buff.buffer, self.pages[p].buff.byteOffset + o, l); - buffDst.set(srcView, offset+len-r); - self.pages[p].pendingOps --; - - self.__statusPage("After Op done: ", p); - - r = r-l; - p ++; - o = 0; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - } - - this.pos = pos + len; - - } - - - _tryClose() { - const self = this; - if (!self.pendingClose) return; - if (self.error) { - self.pendingCloseReject(self.error); - } - const p = self._getDirtyPage(); - if ((p>=0) || (self.writing) || (self.reading) || (self.pendingLoads.length>0)) return; - self.pendingClose(); - } - - close() { - const self = this; - if (self.pendingClose) - throw new Error("Closing the file twice"); - return new Promise((resolve, reject) => { - self.pendingClose = resolve; - self.pendingCloseReject = reject; - self._tryClose(); - }).then(()=> { - self.fd.close(); - }, (err) => { - self.fd.close(); - throw (err); - }); - } - - async discard() { - const self = this; - await self.close(); - await fs.promises.unlink(this.fileName); - } - - async writeULE32(v, pos) { - const self = this; - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, true); - - await self.write(tmpBuff32, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, false); - - await self.write(tmpBuff32, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - const tmpBuff64 = new Uint8Array(8); - const tmpBuff64v = new DataView(tmpBuff64.buffer); - - tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64, pos); - } - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - if (self.pendingClose) { - throw new Error("Reading a closing file"); - } - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - let currentPage = Math.floor(currentPosition / self.pageSize); - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - //Read page - let pagePromise = self._loadPage(currentPage); - self._triggerLoad(); - await pagePromise; - self.__statusPage("After Await (read): ", currentPage); - - let offsetOnPage = currentPosition % self.pageSize; - - const dataArray = new Uint8Array( - self.pages[currentPage].buff.buffer, - self.pages[currentPage].buff.byteOffset + offsetOnPage, - self.pageSize - offsetOnPage - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * this.pageSize + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * this.pageSize + offsetOnPage + dataArray.length; - } - - self.pages[currentPage].pendingOps--; - self.__statusPage("After Op done: ", currentPage); - - currentPosition = self.pos; - currentPage++; - - if (self.pendingLoads.length > 0) setImmediate(self._triggerLoad.bind(self)); - } - - return str; - } -}; - -function createNew$1(o) { - const initialSize = o.initialSize || 1<<20; - const fd = new MemFile$1(); - fd.o = o; - fd.o.data = new Uint8Array(initialSize); - fd.allocSize = initialSize; - fd.totalSize = 0; - fd.readOnly = false; - fd.pos = 0; - return fd; -} - -function readExisting$5(o) { - const fd = new MemFile$1(); - fd.o = o; - fd.allocSize = o.data.byteLength; - fd.totalSize = o.data.byteLength; - fd.readOnly = true; - fd.pos = 0; - return fd; -} - -const tmpBuff32$3 = new Uint8Array(4); -const tmpBuff32v$3 = new DataView(tmpBuff32$3.buffer); -const tmpBuff64$3 = new Uint8Array(8); -const tmpBuff64v$3 = new DataView(tmpBuff64$3.buffer); - -let MemFile$1 = class MemFile { - - constructor() { - this.pageSize = 1 << 14; // for compatibility - } - - _resizeIfNeeded(newLen) { - if (newLen > this.allocSize) { - const newAllocSize = Math.max( - this.allocSize + (1 << 20), - Math.floor(this.allocSize * 1.1), - newLen - ); - const newData = new Uint8Array(newAllocSize); - newData.set(this.o.data); - this.o.data = newData; - this.allocSize = newAllocSize; - } - } - - async write(buff, pos) { - const self =this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) throw new Error("Writing a read only file"); - - this._resizeIfNeeded(pos + buff.byteLength); - - this.o.data.set(buff.slice(), pos); - - if (pos + buff.byteLength > this.totalSize) this.totalSize = pos + buff.byteLength; - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDest, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const buffSrc = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + pos, len); - - buffDest.set(buffSrc, offset); - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - - const buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - if (this.o.data.byteLength != this.totalSize) { - this.o.data = this.o.data.slice(0, this.totalSize); - } - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$3.setUint32(0, v, true); - - await self.write(tmpBuff32$3, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$3.setUint32(0, v, false); - - await self.write(tmpBuff32$3, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$3.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$3.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$3, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - const dataArray = new Uint8Array( - self.o.data.buffer, - currentPosition, - this.totalSize - currentPosition - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - let endOfStringFound = indexEndOfString !== -1; - - let str = ""; - if (endOfStringFound) { - str = new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPosition + indexEndOfString + 1; - } else { - self.pos = currentPosition; - } - return str; - } -}; - -const PAGE_SIZE$1 = 1<<22; - -function createNew(o) { - const initialSize = o.initialSize || 0; - const fd = new BigMemFile$1(); - fd.o = o; - const nPages = initialSize ? Math.floor((initialSize - 1) / PAGE_SIZE$1)+1 : 0; - fd.o.data = []; - for (let i=0; i0) { - const l = (o+r > PAGE_SIZE$1) ? (PAGE_SIZE$1 -o) : r; - const srcView = buff.slice(buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.o.data[p].buffer, o, l); - dstView.set(srcView); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDst, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const firstPage = Math.floor(pos / PAGE_SIZE$1); - - let p = firstPage; - let o = pos % PAGE_SIZE$1; - // Remaining bytes to read - let r = len; - while (r>0) { - // bytes to copy from this page - const l = (o+r > PAGE_SIZE$1) ? (PAGE_SIZE$1 -o) : r; - const srcView = new Uint8Array(self.o.data[p].buffer, o, l); - buffDst.set(srcView, offset+len-r); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - const buff = new Uint8Array(len); - - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$2.setUint32(0, v, true); - - await self.write(tmpBuff32$2, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$2.setUint32(0, v, false); - - await self.write(tmpBuff32$2, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$2.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$2.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$2, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - const fixedSize = 2048; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - let currentPage = Math.floor(currentPosition / PAGE_SIZE$1); - let offsetOnPage = currentPosition % PAGE_SIZE$1; - - if (self.o.data[currentPage] === undefined) { - throw new Error("ERROR"); - } - - let readLength = Math.min(fixedSize, self.o.data[currentPage].length - offsetOnPage); - const dataArray = new Uint8Array(self.o.data[currentPage].buffer, offsetOnPage, readLength); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * PAGE_SIZE$1 + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * PAGE_SIZE$1 + offsetOnPage + dataArray.length; - } - - currentPosition = self.pos; - } - return str; - } -}; - -/* global fetch */ - -const DEFAULT_CACHE_SIZE = (1 << 16); -const DEFAULT_PAGE_SIZE = (1 << 13); - - -async function createOverride(o, b, c) { - if (typeof o === "string") { - o = { - type: "file", - fileName: o, - cacheSize: DEFAULT_CACHE_SIZE, - pageSize: DEFAULT_PAGE_SIZE - }; - } - if (o.type == "file") { - return await open$1(o.fileName, O_TRUNC | O_CREAT | O_RDWR, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return createNew$1(o); - } else if (o.type == "bigMem") { - return createNew(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } -} - -async function readExisting$3(o, b, c) { - if (o instanceof Uint8Array) { - o = { - type: "mem", - data: o - }; - } - { - if (typeof o === "string") { - const buff = await fetch(o).then( function(res) { - return res.arrayBuffer(); - }).then(function (ab) { - return new Uint8Array(ab); - }); - o = { - type: "mem", - data: buff - }; - } - } - if (o.type == "file") { - return await open$1(o.fileName, O_RDONLY, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return await readExisting$5(o); - } else if (o.type == "bigMem") { - return await readExisting$4(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } -} - -/* - -Copyright 2020 0KIMS association. - -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. - -*/ - -function flatArray(a) { - let res = []; - fillArray(res, a); - return res; - - function fillArray(res, a) { - if (Array.isArray(a)) { - for (let i = 0; i < a.length; i++) { - fillArray(res, a[i]); - } - } else { - res.push(a); - } - } -} - -// Ref https://github.com/iden3/circom/commit/ec6388cf6eb62463539cb4c40cc3ceae9826de19 -function normalize(n, prime) { - let res = BigInt(n) % prime; - if (res < 0) res += prime; - return res; -} - -function fnvHash(str) { - const uint64_max = BigInt(2) ** BigInt(64); - let hash = BigInt("0xCBF29CE484222325"); - for (let i = 0; i < str.length; i++) { - hash ^= BigInt(str[i].charCodeAt(0)); - hash *= BigInt(0x100000001B3); - hash %= uint64_max; - } - let shash = hash.toString(16); - let n = 16 - shash.length; - shash = "0".repeat(n).concat(shash); - return shash; -} - -// Note that this pads zeros -function toArray32(s, size) { - const res = []; //new Uint32Array(size); //has no unshift - let rem = BigInt(s); - const radix = BigInt(0x100000000); - while (rem) { - res.unshift(Number(rem % radix)); - rem = rem / radix; - } - if (size) { - let i = size - res.length; - while (i > 0) { - res.unshift(0); - i--; - } - } - return res; -} - -/* globals WebAssembly */ -/* - -Copyright 2020 0KIMS association. - -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. - -*/ - - -async function builder(code, options) { - let instance; - let wc; - let memory; - options = options || {}; - - // Only circom 2 implements version lookup through exports in the WASM - // We default to `1` and update if we see the `getVersion` export (major version) - // These are updated after the instance is instantiated, assuming the functions are available - let majorVersion = 1; - // After Circom 2.0.7, Blaine added exported functions for getting minor and patch versions - let minorVersion = 0; - // If we can't look up the patch version, assume the lowest - let patchVersion = 0; - - let codeIsWebAssemblyInstance = false; - - // If code is already prepared WebAssembly.Instance, we use it directly - if (code instanceof WebAssembly.Instance) { - instance = code; - codeIsWebAssemblyInstance = true; - } else { - let memorySize = 32767; - - if (options.memorySize) { - // make sure we have int - memorySize = parseInt(options.memorySize); - if (memorySize < 0) { - throw new Error("Invalid memory size"); - } - } - - let memoryAllocated = false; - while (!memoryAllocated) { - try { - memory = new WebAssembly.Memory({initial: memorySize}); - memoryAllocated = true; - } catch (err) { - if (memorySize <= 1) { - throw err; - } - console.warn("Could not allocate " + memorySize * 1024 * 64 + " bytes. This may cause severe instability. Trying with " + memorySize * 1024 * 64 / 2 + " bytes"); - memorySize = Math.floor(memorySize / 2); - } - } - - const wasmModule = await WebAssembly.compile(code); - - let errStr = ""; - let msgStr = ""; - - instance = await WebAssembly.instantiate(wasmModule, { - env: { - "memory": memory - }, - runtime: { - printDebug : function(value) { - console.log("printDebug:", value); - }, - exceptionHandler: function (code) { - let err; - if (code === 1) { - err = "Signal not found. "; - } else if (code === 2) { - err = "Too many signals set. "; - } else if (code === 3) { - err = "Signal already set. "; - } else if (code === 4) { - err = "Assert Failed. "; - } else if (code === 5) { - err = "Not enough memory. "; - } else if (code === 6) { - err = "Input signal array access exceeds the size. "; - } else { - err = "Unknown error. "; - } - console.error("ERROR: ", code, errStr); - throw new Error(err + errStr); - }, - // A new way of logging messages was added in Circom 2.0.7 that requires 2 new imports - // `printErrorMessage` and `writeBufferMessage`. - printErrorMessage: function () { - errStr += getMessage() + "\n"; - }, - writeBufferMessage: function () { - const msg = getMessage(); - // Any calls to `log()` will always end with a `\n`, so that's when we print and reset - if (msg === "\n") { - console.log(msgStr); - msgStr = ""; - } else { - // If we've buffered other content, put a space in between the items - if (msgStr !== "") { - msgStr += " "; - } - // Then append the message to the message we are creating - msgStr += msg; - } - }, - showSharedRWMemory: function () { - const shared_rw_memory_size = instance.exports.getFieldNumLen32(); - const arr = new Uint32Array(shared_rw_memory_size); - for (let j = 0; j < shared_rw_memory_size; j++) { - arr[shared_rw_memory_size - 1 - j] = instance.exports.readSharedRWMemory(j); - } - - // In circom 2.0.7, they changed the log() function to allow strings and changed the - // output API. This smoothes over the breaking change. - if (majorVersion >= 2 && (minorVersion >= 1 || patchVersion >= 7)) { - // If we've buffered other content, put a space in between the items - if (msgStr !== "") { - msgStr += " "; - } - // Then append the value to the message we are creating - const msg = (Scalar.fromArray(arr, 0x100000000).toString()); - msgStr += msg; - } else { - console.log(Scalar.fromArray(arr, 0x100000000)); - } - }, - error: function (code, pstr, a, b, c, d) { - let errStr; - if (code === 7) { - errStr = p2str(pstr) + " " + wc.getFr(b).toString() + " != " + wc.getFr(c).toString() + " " + p2str(d); - } else if (code === 9) { - errStr = p2str(pstr) + " " + wc.getFr(b).toString() + " " + p2str(c); - } else if ((code === 5) && (options.sym)) { - errStr = p2str(pstr) + " " + options.sym.labelIdx2Name[c]; - } else { - errStr = p2str(pstr) + " " + a + " " + b + " " + c + " " + d; - } - console.log("ERROR: ", code, errStr); - throw new Error(errStr); - }, - log: function (a) { - console.log(wc.getFr(a).toString()); - }, - logGetSignal: function (signal, pVal) { - if (options.logGetSignal) { - options.logGetSignal(signal, wc.getFr(pVal)); - } - }, - logSetSignal: function (signal, pVal) { - if (options.logSetSignal) { - options.logSetSignal(signal, wc.getFr(pVal)); - } - }, - logStartComponent: function (cIdx) { - if (options.logStartComponent) { - options.logStartComponent(cIdx); - } - }, - logFinishComponent: function (cIdx) { - if (options.logFinishComponent) { - options.logFinishComponent(cIdx); - } - } - } - }); - } - - if (typeof instance.exports.getVersion == "function") { - majorVersion = instance.exports.getVersion(); - } - if (typeof instance.exports.getMinorVersion == "function") { - minorVersion = instance.exports.getMinorVersion(); - } - if (typeof instance.exports.getPatchVersion == "function") { - patchVersion = instance.exports.getPatchVersion(); - } - - const sanityCheck = - options && - ( - options.sanityCheck || - options.logGetSignal || - options.logSetSignal || - options.logStartComponent || - options.logFinishComponent - ); - - // We explicitly check for major version 2 in case there's a circom v3 in the future - if (majorVersion === 2) { - wc = new WitnessCalculatorCircom2(instance, sanityCheck); - } else if (majorVersion === 1) { - if (codeIsWebAssemblyInstance) { - throw new Error('Loading code from WebAssembly instance is not supported for circom version 1'); - } - wc = new WitnessCalculatorCircom1(memory, instance, sanityCheck); - } else { - throw new Error(`Unsupported circom version: ${majorVersion}`); - } - return wc; - - function getMessage() { - let message = ""; - let c = instance.exports.getMessageChar(); - while (c !== 0) { - message += String.fromCharCode(c); - c = instance.exports.getMessageChar(); - } - return message; - } - - function p2str(p) { - const i8 = new Uint8Array(memory.buffer); - - const bytes = []; - - for (let i = 0; i8[p + i] > 0; i++) bytes.push(i8[p + i]); - - return String.fromCharCode.apply(null, bytes); - } -} - -class WitnessCalculatorCircom1 { - constructor(memory, instance, sanityCheck) { - this.memory = memory; - this.i32 = new Uint32Array(memory.buffer); - this.instance = instance; - - this.n32 = (this.instance.exports.getFrLen() >> 2) - 2; - const pRawPrime = this.instance.exports.getPRawPrime(); - - const arr = new Array(this.n32); - for (let i = 0; i < this.n32; i++) { - arr[this.n32 - 1 - i] = this.i32[(pRawPrime >> 2) + i]; - } - - this.prime = Scalar.fromArray(arr, 0x100000000); - - this.Fr = new F1Field(this.prime); - - this.mask32 = Scalar.fromString("FFFFFFFF", 16); - this.NVars = this.instance.exports.getNVars(); - this.n64 = Math.floor((this.Fr.bitLength - 1) / 64) + 1; - this.R = this.Fr.e(Scalar.shiftLeft(1, this.n64 * 64)); - this.RInv = this.Fr.inv(this.R); - this.sanityCheck = sanityCheck; - } - - circom_version() { - return 1; - } - - async _doCalculateWitness(input, sanityCheck) { - this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0); - const pSigOffset = this.allocInt(); - const pFr = this.allocFr(); - const keys = Object.keys(input); - keys.forEach((k) => { - const h = fnvHash(k); - const hMSB = parseInt(h.slice(0, 8), 16); - const hLSB = parseInt(h.slice(8, 16), 16); - try { - this.instance.exports.getSignalOffset32(pSigOffset, 0, hMSB, hLSB); - } catch (err) { - throw new Error(`Signal ${k} is not an input of the circuit.`); - } - const sigOffset = this.getInt(pSigOffset); - const fArr = flatArray(input[k]); - for (let i = 0; i < fArr.length; i++) { - this.setFr(pFr, fArr[i]); - this.instance.exports.setSignal(0, 0, sigOffset + i, pFr); - } - }); - } - - async calculateWitness(input, sanityCheck) { - const self = this; - - const old0 = self.i32[0]; - const w = []; - - await self._doCalculateWitness(input, sanityCheck); - - for (let i = 0; i < self.NVars; i++) { - const pWitness = self.instance.exports.getPWitness(i); - w.push(self.getFr(pWitness)); - } - - self.i32[0] = old0; - return w; - } - - async calculateBinWitness(input, sanityCheck) { - const self = this; - - const old0 = self.i32[0]; - - await self._doCalculateWitness(input, sanityCheck); - - const pWitnessBuffer = self.instance.exports.getWitnessBuffer(); - - self.i32[0] = old0; - - const buff = self.memory.buffer.slice(pWitnessBuffer, pWitnessBuffer + (self.NVars * self.n64 * 8)); - return new Uint8Array(buff); - } - - allocInt() { - const p = this.i32[0]; - this.i32[0] = p + 8; - return p; - } - - allocFr() { - const p = this.i32[0]; - this.i32[0] = p + this.n32 * 4 + 8; - return p; - } - - getInt(p) { - return this.i32[p >> 2]; - } - - setInt(p, v) { - this.i32[p >> 2] = v; - } - - getFr(p) { - const self = this; - const idx = (p >> 2); - - if (self.i32[idx + 1] & 0x80000000) { - const arr = new Array(self.n32); - for (let i = 0; i < self.n32; i++) { - arr[self.n32 - 1 - i] = self.i32[idx + 2 + i]; - } - const res = self.Fr.e(Scalar.fromArray(arr, 0x100000000)); - if (self.i32[idx + 1] & 0x40000000) { - return fromMontgomery(res); - } else { - return res; - } - - } else { - if (self.i32[idx] & 0x80000000) { - return self.Fr.e(self.i32[idx] - 0x100000000); - } else { - return self.Fr.e(self.i32[idx]); - } - } - - function fromMontgomery(n) { - return self.Fr.mul(self.RInv, n); - } - - } - - - setFr(p, v) { - const self = this; - - v = self.Fr.e(v); - - const minShort = self.Fr.neg(self.Fr.e("80000000", 16)); - const maxShort = self.Fr.e("7FFFFFFF", 16); - - if ((self.Fr.geq(v, minShort)) - && (self.Fr.leq(v, maxShort))) { - let a; - if (self.Fr.geq(v, self.Fr.zero)) { - a = Scalar.toNumber(v); - } else { - a = Scalar.toNumber(self.Fr.sub(v, minShort)); - a = a - 0x80000000; - a = 0x100000000 + a; - } - self.i32[(p >> 2)] = a; - self.i32[(p >> 2) + 1] = 0; - return; - } - - self.i32[(p >> 2)] = 0; - self.i32[(p >> 2) + 1] = 0x80000000; - const arr = Scalar.toArray(v, 0x100000000); - for (let i = 0; i < self.n32; i++) { - const idx = arr.length - 1 - i; - - if (idx >= 0) { - self.i32[(p >> 2) + 2 + i] = arr[idx]; - } else { - self.i32[(p >> 2) + 2 + i] = 0; - } - } - } -} - -class WitnessCalculatorCircom2 { - constructor(instance, sanityCheck) { - this.instance = instance; - - this.version = this.instance.exports.getVersion(); - this.n32 = this.instance.exports.getFieldNumLen32(); - - this.instance.exports.getRawPrime(); - const arr = new Uint32Array(this.n32); - for (let i = 0; i < this.n32; i++) { - arr[this.n32 - 1 - i] = this.instance.exports.readSharedRWMemory(i); - } - this.prime = Scalar.fromArray(arr, 0x100000000); - - this.witnessSize = this.instance.exports.getWitnessSize(); - - this.sanityCheck = sanityCheck; - } - - circom_version() { - return this.instance.exports.getVersion(); - } - - async _doCalculateWitness(input, sanityCheck) { - //input is assumed to be a map from signals to arrays of bigints - this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0); - const keys = Object.keys(input); - let input_counter = 0; - keys.forEach((k) => { - const h = fnvHash(k); - const hMSB = parseInt(h.slice(0, 8), 16); - const hLSB = parseInt(h.slice(8, 16), 16); - const fArr = flatArray(input[k]); - // Slight deviation from https://github.com/iden3/circom/blob/v2.1.6/code_producers/src/wasm_elements/common/witness_calculator.js - // because I don't know when this exported function was added - if (typeof this.instance.exports.getInputSignalSize === "function") { - let signalSize = this.instance.exports.getInputSignalSize(hMSB, hLSB); - if (signalSize < 0) { - throw new Error(`Signal ${k} not found\n`); - } - if (fArr.length < signalSize) { - throw new Error(`Not enough values for input signal ${k}\n`); - } - if (fArr.length > signalSize) { - throw new Error(`Too many values for input signal ${k}\n`); - } - } - for (let i = 0; i < fArr.length; i++) { - const arrFr = toArray32(normalize(fArr[i], this.prime), this.n32); - for (let j = 0; j < this.n32; j++) { - this.instance.exports.writeSharedRWMemory(j, arrFr[this.n32 - 1 - j]); - } - try { - this.instance.exports.setInputSignal(hMSB, hLSB, i); - input_counter++; - } catch (err) { - // console.log(`After adding signal ${i} of ${k}`) - throw new Error(err); - } - } - - }); - if (input_counter < this.instance.exports.getInputSize()) { - throw new Error(`Not all inputs have been set. Only ${input_counter} out of ${this.instance.exports.getInputSize()}`); - } - } - - async calculateWitness(input, sanityCheck) { - const w = []; - - await this._doCalculateWitness(input, sanityCheck); - - for (let i = 0; i < this.witnessSize; i++) { - this.instance.exports.getWitness(i); - const arr = new Uint32Array(this.n32); - for (let j = 0; j < this.n32; j++) { - arr[this.n32 - 1 - j] = this.instance.exports.readSharedRWMemory(j); - } - w.push(Scalar.fromArray(arr, 0x100000000)); - } - - return w; - } - - async calculateWTNSBin(input, sanityCheck) { - const buff32 = new Uint32Array(this.witnessSize * this.n32 + this.n32 + 11); - const buff = new Uint8Array(buff32.buffer); - await this._doCalculateWitness(input, sanityCheck); - - //"wtns" - buff[0] = "w".charCodeAt(0); - buff[1] = "t".charCodeAt(0); - buff[2] = "n".charCodeAt(0); - buff[3] = "s".charCodeAt(0); - - //version 2 - buff32[1] = 2; - - //number of sections: 2 - buff32[2] = 2; - - //id section 1 - buff32[3] = 1; - - const n8 = this.n32 * 4; - //id section 1 length in 64bytes - const idSection1length = 8 + n8; - const idSection1lengthHex = idSection1length.toString(16); - buff32[4] = parseInt(idSection1lengthHex.slice(0, 8), 16); - buff32[5] = parseInt(idSection1lengthHex.slice(8, 16), 16); - - //this.n32 - buff32[6] = n8; - - //prime number - this.instance.exports.getRawPrime(); - - let pos = 7; - for (let j = 0; j < this.n32; j++) { - buff32[pos + j] = this.instance.exports.readSharedRWMemory(j); - } - pos += this.n32; - - // witness size - buff32[pos] = this.witnessSize; - pos++; - - //id section 2 - buff32[pos] = 2; - pos++; - - // section 2 length - const idSection2length = n8 * this.witnessSize; - const idSection2lengthHex = idSection2length.toString(16); - buff32[pos] = parseInt(idSection2lengthHex.slice(0, 8), 16); - buff32[pos + 1] = parseInt(idSection2lengthHex.slice(8, 16), 16); - - pos += 2; - for (let i = 0; i < this.witnessSize; i++) { - this.instance.exports.getWitness(i); - for (let j = 0; j < this.n32; j++) { - buff32[pos + j] = this.instance.exports.readSharedRWMemory(j); - } - pos += this.n32; - } - - return buff; - } - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const { unstringifyBigInts: unstringifyBigInts$b} = utils; - -async function wtnsCalculate(_input, wasmFileName, wtnsFileName, options) { - const input = unstringifyBigInts$b(_input); - - const fdWasm = await readExisting$3(wasmFileName); - const wasm = await fdWasm.read(fdWasm.totalSize); - await fdWasm.close(); - - const wc = await builder(wasm, options); - if (wc.circom_version() === 1) { - const w = await wc.calculateBinWitness(input); - - const fdWtns = await createBinFile(wtnsFileName, "wtns", 2, 2); - - await writeBin(fdWtns, w, wc.prime); - await fdWtns.close(); - } else { - const fdWtns = await createOverride(wtnsFileName); - - const w = await wc.calculateWTNSBin(input); - - await fdWtns.write(w); - await fdWtns.close(); - } -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const {unstringifyBigInts: unstringifyBigInts$a} = utils; - -async function groth16FullProve(_input, wasmFile, zkeyFileName, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$a(_input); - - const wtns= { - type: "mem" - }; - await wtnsCalculate(input, wasmFile, wtns, wtnsCalcOptions); - return await groth16Prove(zkeyFileName, wtns, logger, proverOptions); -} - -/* - Copyright 2018 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const {unstringifyBigInts: unstringifyBigInts$9} = utils; - -async function groth16Verify(_vk_verifier, _publicSignals, _proof, logger) { -/* - let cpub = vk_verifier.IC[0]; - for (let s= 0; s< vk_verifier.nPublic; s++) { - cpub = G1.add( cpub, G1.timesScalar( vk_verifier.IC[s+1], publicSignals[s])); - } -*/ - - const vk_verifier = unstringifyBigInts$9(_vk_verifier); - const proof = unstringifyBigInts$9(_proof); - const publicSignals = unstringifyBigInts$9(_publicSignals); - - const curve = await getCurveFromName(vk_verifier.curve); - - const IC0 = curve.G1.fromObject(vk_verifier.IC[0]); - const IC = new Uint8Array(curve.G1.F.n8*2 * publicSignals.length); - const w = new Uint8Array(curve.Fr.n8 * publicSignals.length); - - if (!publicInputsAreValid$2(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - for (let i=0; i. -*/ -const { unstringifyBigInts: unstringifyBigInts$8} = utils; - -function p256$2(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0"+nstr; - nstr = `"0x${nstr}"`; - return nstr; -} - -async function groth16ExportSolidityCallData(_proof, _pub) { - const proof = unstringifyBigInts$8(_proof); - const pub = unstringifyBigInts$8(_pub); - - let inputs = ""; - for (let i=0; i. -*/ - -var groth16 = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportSolidityCallData: groth16ExportSolidityCallData, - fullProve: groth16FullProve, - prove: groth16Prove, - verify: groth16Verify +//#endregion +//#region src/keypair.js +function $t(e, t) { + let n = new DataView(t.buffer, t.byteOffset, t.byteLength), r = []; + for (let e = 0; e < 8; e++) r[e] = n.getUint32(e * 4); + let i = new c(r); + return e.G2.fromRng(i); +} +function en(e, t, n, r, i) { + let a = G.create({ dkLen: 64 }), o = new Uint8Array([t]); + a.update(o), a.update(n); + let s = e.G1.toUncompressed(r); + a.update(s); + let c = e.G1.toUncompressed(i); + return a.update(c), $t(e, a.digest()); +} +function tn(e, t, n, r, i) { + return e.g1_s = t.G1.toAffine(t.G1.fromRng(i)), e.g1_sx = t.G1.toAffine(t.G1.timesFr(e.g1_s, e.prvKey)), e.g2_sp = t.G2.toAffine(en(t, n, r, e.g1_s, e.g1_sx)), e.g2_spx = t.G2.toAffine(t.G2.timesFr(e.g2_sp, e.prvKey)), e; +} +function nn(e, t, n) { + let r = { + tau: {}, + alpha: {}, + beta: {} + }; + return r.tau.prvKey = e.Fr.fromRng(n), r.alpha.prvKey = e.Fr.fromRng(n), r.beta.prvKey = e.Fr.fromRng(n), tn(r.tau, e, 0, t, n), tn(r.alpha, e, 1, t, n), tn(r.beta, e, 2, t, n), r; +} +//#endregion +//#region src/powersoftau_utils.js +async function rn(e, t, n, r) { + r ||= n, await e.writeULE32(1); + let i = e.pos; + await e.writeULE64(0), await e.writeULE32(t.F1.n64 * 8); + let a = new Uint8Array(t.F1.n8); + u.toRprLE(a, 0, t.q, t.F1.n8), await e.write(a), await e.writeULE32(n), await e.writeULE32(r); + let o = e.pos - i - 8, s = e.pos; + await e.writeULE64(o, i), e.pos = s; +} +async function an(e, t) { + if (!t[1]) throw Error(e.fileName + ": File has no header"); + if (t[1].length > 1) throw Error(e.fileName + ": File has more than one header"); + e.pos = t[1][0].p; + let n = await e.readULE32(), r = await e.read(n), i = await T(u.fromRprLE(r)); + if (i.F1.n64 * 8 != n) throw Error(e.fileName + ": Invalid size"); + let a = await e.readULE32(), o = await e.readULE32(); + if (e.pos - t[1][0].p != t[1][0].size) throw Error("Invalid PTau header size"); + return { + curve: i, + power: a, + ceremonyPower: o + }; +} +async function on(e, t, n) { + return sn(await e.read(t.F1.n8 * 2 * 6 + t.F2.n8 * 2 * 3), 0, t, n); +} +function sn(e, t, n, r) { + let i = { + tau: {}, + alpha: {}, + beta: {} + }; + return i.tau.g1_s = a(), i.tau.g1_sx = a(), i.alpha.g1_s = a(), i.alpha.g1_sx = a(), i.beta.g1_s = a(), i.beta.g1_sx = a(), i.tau.g2_spx = o(), i.alpha.g2_spx = o(), i.beta.g2_spx = o(), i; + function a() { + let i; + return i = r ? n.G1.fromRprLEM(e, t) : n.G1.fromRprUncompressed(e, t), t += n.G1.F.n8 * 2, i; + } + function o() { + let i; + return i = r ? n.G2.fromRprLEM(e, t) : n.G2.fromRprUncompressed(e, t), t += n.G2.F.n8 * 2, i; + } +} +function cn(e, t, n, r, i) { + a(r.tau.g1_s), a(r.tau.g1_sx), a(r.alpha.g1_s), a(r.alpha.g1_sx), a(r.beta.g1_s), a(r.beta.g1_sx), o(r.tau.g2_spx), o(r.alpha.g2_spx), o(r.beta.g2_spx); + async function a(r) { + i ? n.G1.toRprLEM(e, t, r) : n.G1.toRprUncompressed(e, t, r), t += n.F1.n8 * 2; + } + async function o(r) { + i ? n.G2.toRprLEM(e, t, r) : n.G2.toRprUncompressed(e, t, r), t += n.F2.n8 * 2; + } + return e; +} +async function ln(e, t, n, r) { + let i = new Uint8Array(t.F1.n8 * 2 * 6 + t.F2.n8 * 2 * 3); + cn(i, 0, t, n, r), await e.write(i); +} +async function un(e, t) { + let n = {}; + n.tauG1 = await c(), n.tauG2 = await l(), n.alphaG1 = await c(), n.betaG1 = await c(), n.betaG2 = await l(), n.key = await on(e, t, !0), n.partialHash = await e.read(216), n.nextChallenge = await e.read(64), n.type = await e.readULE32(); + let r = new Uint8Array(t.G1.F.n8 * 2 * 6 + t.G2.F.n8 * 2 * 3); + cn(r, 0, t, n.key, !1); + let i = Ee(n.partialHash); + i.update(r), n.responseHash = i.digest(); + let a = await e.readULE32(), o = e.pos, s = 0; + for (; e.pos - o < a;) { + let e = await u(1); + if (e[0] <= s) throw Error("Parameters in the contribution must be sorted"); + if (s = e[0], e[0] == 1) { + let e = await u((await u(1))[0]); + n.name = new TextDecoder().decode(e); + } else if (e[0] == 2) n.numIterationsExp = (await u(1))[0]; + else if (e[0] == 3) n.beaconHash = await u((await u(1))[0]); + else throw Error("Parameter not recognized"); + } + if (e.pos != o + a) throw Error("Parameters do not match"); + return n; + async function c() { + let n = await e.read(t.G1.F.n8 * 2); + return t.G1.fromRprLEM(n); + } + async function l() { + let n = await e.read(t.G2.F.n8 * 2); + return t.G2.fromRprLEM(n); + } + async function u(t) { + let n = await e.read(t); + return new Uint8Array(n); + } +} +async function dn(e, t, n) { + if (!n[7]) throw Error(e.fileName + ": File has no contributions"); + if (n[7][0].length > 1) throw Error(e.fileName + ": File has more than one contributions section"); + e.pos = n[7][0].p; + let r = await e.readULE32(), i = []; + for (let n = 0; n < r; n++) { + let r = await un(e, t); + r.id = n + 1, i.push(r); + } + if (e.pos - n[7][0].p != n[7][0].size) throw Error("Invalid contribution section size"); + return i; +} +async function fn(e, t, n) { + let r = new Uint8Array(t.F1.n8 * 2), i = new Uint8Array(t.F2.n8 * 2); + await o(n.tauG1), await s(n.tauG2), await o(n.alphaG1), await o(n.betaG1), await s(n.betaG2), await ln(e, t, n.key, !0), await e.write(n.partialHash), await e.write(n.nextChallenge), await e.writeULE32(n.type || 0); + let a = []; + if (n.name) { + a.push(1); + let e = new TextEncoder("utf-8").encode(n.name.substring(0, 64)); + a.push(e.byteLength); + for (let t = 0; t < e.byteLength; t++) a.push(e[t]); + } + if (n.type == 1) { + a.push(2), a.push(n.numIterationsExp), a.push(3), a.push(n.beaconHash.byteLength); + for (let e = 0; e < n.beaconHash.byteLength; e++) a.push(n.beaconHash[e]); + } + if (a.length > 0) { + let t = new Uint8Array(a); + await e.writeULE32(t.byteLength), await e.write(t); + } else await e.writeULE32(0); + async function o(n) { + t.G1.toRprLEM(r, 0, n), await e.write(r); + } + async function s(n) { + t.G2.toRprLEM(i, 0, n), await e.write(i); + } +} +async function pn(e, t, n) { + await e.writeULE32(7); + let r = e.pos; + await e.writeULE64(0), await e.writeULE32(n.length); + for (let r = 0; r < n.length; r++) await fn(e, t, n[r]); + let i = e.pos - r - 8, a = e.pos; + await e.writeULE64(i, r), e.pos = a; +} +function mn(e, t, n) { + n && n.debug("Calculating First Challenge Hash"); + let r = G.create({ dkLen: 64 }), i = new Uint8Array(e.G1.F.n8 * 2), a = new Uint8Array(e.G2.F.n8 * 2); + e.G1.toRprUncompressed(i, 0, e.G1.g), e.G2.toRprUncompressed(a, 0, e.G2.g), r.update(G.create({ dkLen: 64 }).digest()); + let o; + return o = 2 ** t * 2 - 1, n && n.debug("Calculate Initial Hash: tauG1"), s(i, o), o = 2 ** t, n && n.debug("Calculate Initial Hash: tauG2"), s(a, o), n && n.debug("Calculate Initial Hash: alphaTauG1"), s(i, o), n && n.debug("Calculate Initial Hash: betaTauG1"), s(i, o), r.update(a), r.digest(); + function s(e, t) { + let i = 341e3, a = Math.floor(t / i), o = t % i, s = new Uint8Array(i * e.byteLength); + for (let t = 0; t < i; t++) s.set(e, t * e.byteLength); + for (let e = 0; e < a; e++) r.update(s), n && n.debug("Initial hash: " + e * i); + for (let t = 0; t < o; t++) r.update(e); + } +} +async function hn(e, t, n, r) { + return nn(e, t, await Pe(n, r)); +} +//#endregion +//#region src/powersoftau_new.js +async function gn(t, n, r, i) { + let a = await e.createBinFile(r, "ptau", 1, 7); + await rn(a, t, n, 0); + let o = t.G1.oneAffine, s = t.G2.oneAffine; + await e.startWriteSection(a, 2); + let c = 2 ** n * 2 - 1; + for (let e = 0; e < c; e++) await a.write(o), i && e % 1e5 == 0 && e && i.log("tauG1: " + e); + await e.endWriteSection(a), await e.startWriteSection(a, 3); + let l = 2 ** n; + for (let e = 0; e < l; e++) await a.write(s), i && e % 1e5 == 0 && e && i.log("tauG2: " + e); + await e.endWriteSection(a), await e.startWriteSection(a, 4); + let u = 2 ** n; + for (let e = 0; e < u; e++) await a.write(o), i && e % 1e5 == 0 && e && i.log("alphaTauG1: " + e); + await e.endWriteSection(a), await e.startWriteSection(a, 5); + let d = 2 ** n; + for (let e = 0; e < d; e++) await a.write(o), i && e % 1e5 == 0 && e && i.log("betaTauG1: " + e); + await e.endWriteSection(a), await e.startWriteSection(a, 6), await a.write(s), await e.endWriteSection(a), await e.startWriteSection(a, 7), await a.writeULE32(0), await e.endWriteSection(a), await a.close(); + let f = mn(t, n, i); + return i && i.debug(K(G.create({ dkLen: 64 }).digest(), "Blank Contribution Hash:")), i && i.info(K(f, "First Contribution Hash:")), f; +} +//#endregion +//#region src/powersoftau_export_challenge.js +async function _n(t, n, r) { + let { fd: i, sections: a } = await e.readBinFile(t, "ptau", 1), { curve: o, power: s } = await an(i, a), c = await dn(i, o, a), l, u; + c.length == 0 ? (l = G.create({ dkLen: 64 }).digest(), u = mn(o, s)) : (l = c[c.length - 1].responseHash, u = c[c.length - 1].nextChallenge), r && r.info(K(l, "Last Response Hash: ")), r && r.info(K(u, "New Challenge Hash: ")); + let d = await jt(n), f = G.create({ dkLen: 64 }); + await d.write(l), f.update(l), await m(2, "G1", 2 ** s * 2 - 1, "tauG1"), await m(3, "G2", 2 ** s, "tauG2"), await m(4, "G1", 2 ** s, "alphaTauG1"), await m(5, "G1", 2 ** s, "betaTauG1"), await m(6, "G2", 1, "betaG2"), await i.close(), await d.close(); + let p = f.digest(); + if (!we(u, p)) throw r && r.info(K(p, "Calc Curret Challenge Hash: ")), r && r.error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"), Error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); + return u; + async function m(t, n, s, c) { + let l = o[n], u = l.F.n8 * 2, p = Math.floor((1 << 24) / u); + await e.startReadUniqueSection(i, a, t); + for (let e = 0; e < s; e += p) { + r && r.debug(`Exporting ${c}: ${e}/${s}`); + let t = Math.min(s - e, p), n; + n = await i.read(t * u), n = await l.batchLEMtoU(n), await d.write(n), f.update(n); + } + await e.endReadSection(i); + } +} +//#endregion +//#region src/powersoftau_import.js +async function vn(t, n, r, i, a, o) { + let s = /* @__PURE__ */ new Uint8Array(64); + for (let e = 0; e < 64; e++) s[e] = 255; + let { fd: c, sections: l } = await e.readBinFile(t, "ptau", 1), { curve: u, power: d } = await an(c, l), f = await dn(c, u, l), p = {}; + i && (p.name = i); + let m = u.F1.n8 * 2, h = u.F1.n8, g = u.F2.n8 * 2, _ = u.F2.n8, v = await Mt(n); + if (v.totalSize != 64 + (2 ** d * 2 - 1) * h + 2 ** d * _ + 2 ** d * h + 2 ** d * h + _ + m * 6 + g * 3) throw Error("Size of the contribution is invalid"); + let y; + y = f.length > 0 ? f[f.length - 1].nextChallenge : mn(u, d, o); + let b = await e.createBinFile(r, "ptau", 1, a ? 7 : 2); + await rn(b, u, d); + let x = await v.read(64); + if (we(s, y) && (y = x, f[f.length - 1].nextChallenge = y), !we(x, y)) throw Error("Wrong contribution. This contribution is not based on the previous hash"); + let S = G.create({ dkLen: 64 }); + S.update(x); + let C = [], w; + w = await D(v, b, "G1", 2, 2 ** d * 2 - 1, [1], "tauG1"), p.tauG1 = w[0], w = await D(v, b, "G2", 3, 2 ** d, [1], "tauG2"), p.tauG2 = w[0], w = await D(v, b, "G1", 4, 2 ** d, [0], "alphaG1"), p.alphaG1 = w[0], w = await D(v, b, "G1", 5, 2 ** d, [0], "betaG1"), p.betaG1 = w[0], w = await D(v, b, "G2", 6, 1, [0], "betaG2"), p.betaG2 = w[0], p.partialHash = De(S); + let T = await v.read(u.F1.n8 * 2 * 6 + u.F2.n8 * 2 * 3); + p.key = sn(T, 0, u, !1), S.update(new Uint8Array(T)); + let E = S.digest(); + if (o && o.info(K(E, "Contribution Response Hash imported: ")), a) { + let e = G.create({ dkLen: 64 }); + e.update(E), await A(e, b, "G1", 2, 2 ** d * 2 - 1, "tauG1", o), await A(e, b, "G2", 3, 2 ** d, "tauG2", o), await A(e, b, "G1", 4, 2 ** d, "alphaTauG1", o), await A(e, b, "G1", 5, 2 ** d, "betaTauG1", o), await A(e, b, "G2", 6, 1, "betaG2", o), p.nextChallenge = e.digest(), o && o.info(K(p.nextChallenge, "Next Challenge Hash: ")); + } else p.nextChallenge = s; + return f.push(p), await pn(b, u, f), await v.close(), await b.close(), await c.close(), p.nextChallenge; + async function D(e, t, n, r, i, o, s) { + return a ? await O(e, t, n, r, i, o, s) : await k(e, t, n, r, i, o, s); + } + async function O(t, n, r, i, a, s, c) { + let l = u[r], d = l.F.n8, f = l.F.n8 * 2, p = []; + await e.startWriteSection(n, i); + let m = Math.floor((1 << 24) / f); + C[i] = n.pos; + for (let e = 0; e < a; e += m) { + o && o.debug(`Importing ${c}: ${e}/${a}`); + let r = Math.min(a - e, m), i = await t.read(r * d); + S.update(i); + let u = await l.batchCtoLEM(i); + await n.write(u); + for (let t = 0; t < s.length; t++) { + let n = s[t]; + if (n >= e && n < e + r) { + let t = l.fromRprLEM(u, (n - e) * f); + p.push(t); + } + } + } + return await e.endWriteSection(n), p; + } + async function k(e, t, n, r, i, a, s) { + let c = u[n], l = c.F.n8, d = [], f = Math.floor((1 << 24) / l); + for (let t = 0; t < i; t += f) { + o && o.debug(`Importing ${s}: ${t}/${i}`); + let n = Math.min(i - t, f), r = await e.read(n * l); + S.update(r); + for (let e = 0; e < a.length; e++) { + let i = a[e]; + if (i >= t && i < t + n) { + let e = c.fromRprCompressed(r, (i - t) * l); + d.push(e); + } + } + } + return d; + } + async function A(e, t, n, r, i, a, o) { + let s = u[n], c = s.F.n8 * 2, l = Math.floor((1 << 24) / c), d = t.pos; + t.pos = C[r]; + for (let n = 0; n < i; n += l) { + o && o.debug(`Hashing ${a}: ${n}/${i}`); + let r = Math.min(i - n, l), u = await t.read(r * c), d = await s.batchLEMtoU(u); + e.update(d); + } + t.pos = d; + } +} +//#endregion +//#region src/powersoftau_verify.js +var yn = Oe; +async function bn(e, t, n, r) { + let i; + if (t.type == 1) { + let i = await hn(e, n.nextChallenge, t.beaconHash, t.numIterationsExp); + if (!e.G1.eq(t.key.tau.g1_s, i.tau.g1_s)) return r && r.error(`BEACON key (tauG1_s) is not generated correctly in challenge #${t.id} ${t.name || ""}`), !1; + if (!e.G1.eq(t.key.tau.g1_sx, i.tau.g1_sx)) return r && r.error(`BEACON key (tauG1_sx) is not generated correctly in challenge #${t.id} ${t.name || ""}`), !1; + if (!e.G2.eq(t.key.tau.g2_spx, i.tau.g2_spx)) return r && r.error(`BEACON key (tauG2_spx) is not generated correctly in challenge #${t.id} ${t.name || ""}`), !1; + if (!e.G1.eq(t.key.alpha.g1_s, i.alpha.g1_s)) return r && r.error(`BEACON key (alphaG1_s) is not generated correctly in challenge #${t.id} ${t.name || ""}`), !1; + if (!e.G1.eq(t.key.alpha.g1_sx, i.alpha.g1_sx)) return r && r.error(`BEACON key (alphaG1_sx) is not generated correctly in challenge #${t.id} ${t.name || ""}`), !1; + if (!e.G2.eq(t.key.alpha.g2_spx, i.alpha.g2_spx)) return r && r.error(`BEACON key (alphaG2_spx) is not generated correctly in challenge #${t.id} ${t.name || ""}`), !1; + if (!e.G1.eq(t.key.beta.g1_s, i.beta.g1_s)) return r && r.error(`BEACON key (betaG1_s) is not generated correctly in challenge #${t.id} ${t.name || ""}`), !1; + if (!e.G1.eq(t.key.beta.g1_sx, i.beta.g1_sx)) return r && r.error(`BEACON key (betaG1_sx) is not generated correctly in challenge #${t.id} ${t.name || ""}`), !1; + if (!e.G2.eq(t.key.beta.g2_spx, i.beta.g2_spx)) return r && r.error(`BEACON key (betaG2_spx) is not generated correctly in challenge #${t.id} ${t.name || ""}`), !1; + } + return t.key.tau.g2_sp = e.G2.toAffine(en(e, 0, n.nextChallenge, t.key.tau.g1_s, t.key.tau.g1_sx)), t.key.alpha.g2_sp = e.G2.toAffine(en(e, 1, n.nextChallenge, t.key.alpha.g1_s, t.key.alpha.g1_sx)), t.key.beta.g2_sp = e.G2.toAffine(en(e, 2, n.nextChallenge, t.key.beta.g1_s, t.key.beta.g1_sx)), i = await yn(e, t.key.tau.g1_s, t.key.tau.g1_sx, t.key.tau.g2_sp, t.key.tau.g2_spx), i === !0 ? (i = await yn(e, t.key.alpha.g1_s, t.key.alpha.g1_sx, t.key.alpha.g2_sp, t.key.alpha.g2_spx), i === !0 ? (i = await yn(e, t.key.beta.g1_s, t.key.beta.g1_sx, t.key.beta.g2_sp, t.key.beta.g2_spx), i === !0 ? (i = await yn(e, n.tauG1, t.tauG1, t.key.tau.g2_sp, t.key.tau.g2_spx), i === !0 ? (i = await yn(e, t.key.tau.g1_s, t.key.tau.g1_sx, n.tauG2, t.tauG2), i === !0 ? (i = await yn(e, n.alphaG1, t.alphaG1, t.key.alpha.g2_sp, t.key.alpha.g2_spx), i === !0 ? (i = await yn(e, n.betaG1, t.betaG1, t.key.beta.g2_sp, t.key.beta.g2_spx), i === !0 ? (i = await yn(e, t.key.beta.g1_s, t.key.beta.g1_sx, n.betaG2, t.betaG2), i === !0 ? (r && r.info("Powers Of tau file OK!"), !0) : (r && r.error("INVALID beta*G2. challenge #" + t.id + "It does not follow the previous contribution"), !1)) : (r && r.error("INVALID beta*G1. challenge #" + t.id + " It does not follow the previous contribution"), !1)) : (r && r.error("INVALID alpha*G1. challenge #" + t.id + " It does not follow the previous contribution"), !1)) : (r && r.error("INVALID tau*G2. challenge #" + t.id + " It does not follow the previous contribution"), !1)) : (r && r.error("INVALID tau*G1. challenge #" + t.id + " It does not follow the previous contribution"), !1)) : (r && r.error("INVALID key (beta) in challenge #" + t.id), !1)) : (r && r.error("INVALID key (alpha) in challenge #" + t.id), !1)) : (r && r.error("INVALID key (tau) in challenge #" + t.id), !1); +} +async function xn(t, n) { + let r, { fd: i, sections: a } = await e.readBinFile(t, "ptau", 1), { curve: o, power: l, ceremonyPower: u } = await an(i, a), d = await dn(i, o, a); + n && n.debug("power: 2**" + l), n && n.debug("Computing initial contribution hash"); + let f = { + tauG1: o.G1.g, + tauG2: o.G2.g, + alphaG1: o.G1.g, + betaG1: o.G1.g, + betaG2: o.G2.g, + nextChallenge: mn(o, u, n), + responseHash: G.create({ dkLen: 64 }).digest() + }; + if (d.length == 0) return n && n.error("This file has no contribution! It cannot be used in production"), !1; + let p; + p = d.length > 1 ? d[d.length - 2] : f; + let m = d[d.length - 1]; + if (n && n.debug("Validating contribution #" + d[d.length - 1].id), !await bn(o, m, p, n)) return !1; + let h = G.create({ dkLen: 64 }); + h.update(m.responseHash), n && n.debug("Verifying powers in tau*G1 section"); + let g = await w(2, "G1", "tauG1", 2 ** l * 2 - 1, [0, 1], n); + if (r = await yn(o, g.R1, g.R2, o.G2.g, m.tauG2), r !== !0) return n && n.error("tauG1 section. Powers do not match"), !1; + if (!o.G1.eq(o.G1.g, g.singularPoints[0])) return n && n.error("First element of tau*G1 section must be the generator"), !1; + if (!o.G1.eq(m.tauG1, g.singularPoints[1])) return n && n.error("Second element of tau*G1 section does not match the one in the contribution section"), !1; + n && n.debug("Verifying powers in tau*G2 section"); + let _ = await w(3, "G2", "tauG2", 2 ** l, [0, 1], n); + if (r = await yn(o, o.G1.g, m.tauG1, _.R1, _.R2), r !== !0) return n && n.error("tauG2 section. Powers do not match"), !1; + if (!o.G2.eq(o.G2.g, _.singularPoints[0])) return n && n.error("First element of tau*G2 section must be the generator"), !1; + if (!o.G2.eq(m.tauG2, _.singularPoints[1])) return n && n.error("Second element of tau*G2 section does not match the one in the contribution section"), !1; + n && n.debug("Verifying powers in alpha*tau*G1 section"); + let v = await w(4, "G1", "alphatauG1", 2 ** l, [0], n); + if (r = await yn(o, v.R1, v.R2, o.G2.g, m.tauG2), r !== !0) return n && n.error("alphaTauG1 section. Powers do not match"), !1; + if (!o.G1.eq(m.alphaG1, v.singularPoints[0])) return n && n.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"), !1; + n && n.debug("Verifying powers in beta*tau*G1 section"); + let y = await w(5, "G1", "betatauG1", 2 ** l, [0], n); + if (r = await yn(o, y.R1, y.R2, o.G2.g, m.tauG2), r !== !0) return n && n.error("betaTauG1 section. Powers do not match"), !1; + if (!o.G1.eq(m.betaG1, y.singularPoints[0])) return n && n.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"), !1; + let b = await C(n); + if (!o.G2.eq(m.betaG2, b)) return n && n.error("betaG2 element in betaG2 section does not match the one in the contribution section"), !1; + let x = h.digest(); + if (l == u && !we(x, m.nextChallenge)) return n && n.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"), !1; + n && n.info(K(x, "Next challenge hash: ")), S(m, p); + for (let e = d.length - 2; e >= 0; e--) { + let t = d[e], r = e > 0 ? d[e - 1] : f; + if (!await bn(o, t, r, n)) return !1; + S(t, r, n); + } + if (n && n.info("-----------------------------------------------------"), !a[12] || !a[13] || !a[14] || !a[15]) n && n.warn("this file does not contain phase2 precalculated values. Please run: \n snarkjs \"powersoftau preparephase2\" to prepare this file to be used in the phase2 ceremony."); + else { + let e; + if (e = await T("G1", 2, 12, "tauG1", n), !e || (e = await T("G2", 3, 13, "tauG2", n), !e) || (e = await T("G1", 4, 14, "alphaTauG1", n), !e) || (e = await T("G1", 5, 15, "betaTauG1", n), !e)) return !1; + } + return await i.close(), n && n.info("Powers of Tau Ok!"), !0; + function S(e, t) { + if (!n) return; + n.info("-----------------------------------------------------"), n.info(`Contribution #${e.id}: ${e.name || ""}`), n.info(K(e.nextChallenge, "Next Challenge: ")); + let r = new Uint8Array(o.G1.F.n8 * 2 * 6 + o.G2.F.n8 * 2 * 3); + cn(r, 0, o, e.key, !1); + let i = Ee(e.partialHash); + i.update(r); + let a = i.digest(); + n.info(K(a, "Response Hash:")), n.info(K(t.nextChallenge, "Response Hash:")), e.type == 1 && (n.info(`Beacon generator: ${Ie(e.beaconHash)}`), n.info(`Beacon iterations Exp: ${e.numIterationsExp}`)); + } + async function C(e) { + let t = o.G2, n = t.F.n8 * 2, r = new Uint8Array(n); + if (!a[6]) throw e.error("File has no BetaG2 section"), Error("File has no BetaG2 section"); + if (a[6].length > 1) throw e.error("File has no BetaG2 section"), Error("File has more than one GetaG2 section"); + i.pos = a[6][0].p; + let s = await i.read(n), c = t.fromRprLEM(s); + return t.toRprUncompressed(r, 0, c), h.update(r), c; + } + async function w(t, n, r, s, c, l) { + let u = 65536, d = o[n], f = d.F.n8 * 2; + await e.startReadUniqueSection(i, a, t); + let p = [], m = d.zero, g = d.zero, _ = d.zero; + for (let e = 0; e < s; e += u) { + l && l.debug(`points relations: ${r}: ${e}/${s} `); + let t = Math.min(s - e, u), n = await i.read(t * f), a = await d.batchLEMtoU(n); + h.update(a); + let o = Ae(4 * (t - 1)); + if (e > 0) { + let e = d.fromRprLEM(n, 0), t = Me(Ae(4), 0); + m = d.add(m, d.timesScalar(_, t)), g = d.add(g, d.timesScalar(e, t)); + } + let v = await d.multiExpAffine(n.slice(0, (t - 1) * f), o), y = await d.multiExpAffine(n.slice(f), o); + m = d.add(m, v), g = d.add(g, y), _ = d.fromRprLEM(n, (t - 1) * f); + for (let r = 0; r < c.length; r++) { + let i = c[r]; + if (i >= e && i < e + t) { + let t = d.fromRprLEM(n, (i - e) * f); + p.push(t); + } + } + } + return await e.endReadSection(i), { + R1: m, + R2: g, + singularPoints: p + }; + } + async function T(t, n, r, u, d) { + d && d.debug(`Verifying phase2 calculated values ${u}...`); + let f = o[t], p = f.F.n8 * 2, m = Array(8); + for (let e = 0; e < 8; e++) m[e] = Me(Ae(4), 0); + for (let e = 0; e <= l; e++) if (!await h(e)) return !1; + if (n == 2 && !await h(l + 1)) return !1; + return !0; + async function h(t) { + d && d.debug(`Power ${t}...`); + let h = o.Fr.n8, g = 2 ** t, _ = new Uint32Array(g), v, y = new c(m); + d && d.debug(`Creating random numbers Powers${t}...`); + for (let e = 0; e < g; e++) t == l + 1 && e == g - 1 ? _[e] = 0 : _[e] = y.nextU32(); + _ = new Uint8Array(_.buffer, _.byteOffset, _.byteLength), d && d.debug(`reading points Powers${t}...`), await e.startReadUniqueSection(i, a, n), v = new s(g * p), t == l + 1 ? (await i.readToBuffer(v, 0, (g - 1) * p), v.set(o.G1.zeroAffine, (g - 1) * p)) : await i.readToBuffer(v, 0, g * p), await e.endReadSection(i, !0); + let b = await f.multiExpAffine(v, _, d, u + "_" + t); + _ = new s(g * h), y = new c(m); + let x = /* @__PURE__ */ new Uint8Array(4), S = new DataView(x.buffer); + d && d.debug(`Creating random numbers Powers${t}...`); + for (let e = 0; e < g; e++) (e != g - 1 || t != l + 1) && (S.setUint32(0, y.nextU32(), !0), _.set(x, e * h)); + d && d.debug(`batchToMontgomery ${t}...`), _ = await o.Fr.batchToMontgomery(_), d && d.debug(`fft ${t}...`), _ = await o.Fr.fft(_), d && d.debug(`batchFromMontgomery ${t}...`), _ = await o.Fr.batchFromMontgomery(_), d && d.debug(`reading points Lagrange${t}...`), await e.startReadUniqueSection(i, a, r), i.pos += p * (2 ** t - 1), await i.readToBuffer(v, 0, g * p), await e.endReadSection(i, !0); + let C = await f.multiExpAffine(v, _, d, u + "_" + t + "_transformed"); + return f.eq(b, C) ? !0 : (d && d.error("Phase2 caclutation does not match with powers of tau"), !1); + } + } +} +//#endregion +//#region src/mpc_applykey.js +async function Sn(t, n, r, i, a, o, s, c, l, u) { + let d = 65536, f = a[o], p = f.F.n8 * 2, m = n[i][0].size / p; + await e.startReadUniqueSection(t, n, i), await e.startWriteSection(r, i); + let h = s; + for (let e = 0; e < m; e += d) { + u && u.debug(`Applying key: ${l}: ${e}/${m}`); + let n = Math.min(m - e, d), i; + i = await t.read(n * p), i = await f.batchApplyKey(i, h, c), await r.write(i), h = a.Fr.mul(h, a.Fr.exp(c, n)); + } + await e.endWriteSection(r), await e.endReadSection(t); +} +async function Cn(e, t, n, r, i, a, o, s, c, l, u) { + let d = r[i], f = d.F.n8 * 2, p = Math.floor((1 << 20) / f), m = o; + for (let i = 0; i < a; i += p) { + u && u.debug(`Applying key ${l}: ${i}/${a}`); + let o = Math.min(a - i, p), h = await e.read(o * f), g = await d.batchUtoLEM(h), _ = await d.batchApplyKey(g, m, s), v; + v = c == "COMPRESSED" ? await d.batchLEMtoC(_) : await d.batchLEMtoU(_), n && n.update(v), await t.write(v), m = r.Fr.mul(m, r.Fr.exp(s, o)); + } +} +//#endregion +//#region src/powersoftau_challenge_contribute.js +async function wn(e, t, n, r, i) { + let a = await Mt(t), o = e.F1.n64 * 8 * 2, s = e.F2.n64 * 8 * 2, c = (a.totalSize + o - 64 - s) / (4 * o + s), l = c, u = 0; + for (; l > 1;) l /= 2, u += 1; + if (2 ** u != c) throw Error("Invalid file size"); + i && i.debug("Power to tau size: " + u); + let d = await Ne(r), f = await jt(n), p = G.create({ dkLen: 64 }); + for (let e = 0; e < a.totalSize; e += a.pageSize) { + i && i.debug(`Hashing challenge ${e}/${a.totalSize}`); + let t = Math.min(a.totalSize - e, a.pageSize), n = await a.read(t); + p.update(n); + } + let m = await a.read(64, 0); + i && i.info(K(m, "Claimed Previous Response Hash: ")); + let h = p.digest(); + i && i.info(K(h, "Current Challenge Hash: ")); + let g = nn(e, h, d); + i && [ + "tau", + "alpha", + "beta" + ].forEach((t) => { + i.debug(t + ".g1_s: " + e.G1.toString(g[t].g1_s, 16)), i.debug(t + ".g1_sx: " + e.G1.toString(g[t].g1_sx, 16)), i.debug(t + ".g2_sp: " + e.G2.toString(g[t].g2_sp, 16)), i.debug(t + ".g2_spx: " + e.G2.toString(g[t].g2_spx, 16)), i.debug(""); + }); + let _ = G.create({ dkLen: 64 }); + await f.write(h), _.update(h), await Cn(a, f, _, e, "G1", 2 ** u * 2 - 1, e.Fr.one, g.tau.prvKey, "COMPRESSED", "tauG1", i), await Cn(a, f, _, e, "G2", 2 ** u, e.Fr.one, g.tau.prvKey, "COMPRESSED", "tauG2", i), await Cn(a, f, _, e, "G1", 2 ** u, g.alpha.prvKey, g.tau.prvKey, "COMPRESSED", "alphaTauG1", i), await Cn(a, f, _, e, "G1", 2 ** u, g.beta.prvKey, g.tau.prvKey, "COMPRESSED", "betaTauG1", i), await Cn(a, f, _, e, "G2", 1, g.beta.prvKey, g.tau.prvKey, "COMPRESSED", "betaTauG2", i); + let v = new Uint8Array(e.F1.n8 * 2 * 6 + e.F2.n8 * 2 * 3); + cn(v, 0, e, g, !1), await f.write(v), _.update(v); + let y = _.digest(); + i && i.info(K(y, "Contribution Response Hash: ")), await f.close(), await a.close(); +} +//#endregion +//#region src/powersoftau_beacon.js +async function Tn(t, n, r, i, a, o) { + let s = Fe(i); + if (s.byteLength == 0 || s.byteLength * 2 != i.length) return o && o.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"), !1; + if (s.length >= 256) return o && o.error("Maximum length of beacon hash is 255 bytes"), !1; + if (a = parseInt(a), a < 10 || a > 63) return o && o.error("Invalid numIterationsExp. (Must be between 10 and 63)"), !1; + let { fd: c, sections: l } = await e.readBinFile(t, "ptau", 1), { curve: u, power: d, ceremonyPower: f } = await an(c, l); + if (d != f) return o && o.error("This file has been reduced. You cannot contribute into a reduced file."), !1; + l[12] && o && o.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); + let p = await dn(c, u, l), m = { + name: r, + type: 1, + numIterationsExp: a, + beaconHash: s + }, h; + h = p.length > 0 ? p[p.length - 1].nextChallenge : mn(u, d, o), m.key = await hn(u, h, s, a); + let g = G.create({ dkLen: 64 }); + g.update(h); + let _ = await e.createBinFile(n, "ptau", 1, 7); + await rn(_, u, d); + let v = [], y; + y = await C(2, "G1", 2 ** d * 2 - 1, u.Fr.e(1), m.key.tau.prvKey, "tauG1", o), m.tauG1 = y[1], y = await C(3, "G2", 2 ** d, u.Fr.e(1), m.key.tau.prvKey, "tauG2", o), m.tauG2 = y[1], y = await C(4, "G1", 2 ** d, m.key.alpha.prvKey, m.key.tau.prvKey, "alphaTauG1", o), m.alphaG1 = y[0], y = await C(5, "G1", 2 ** d, m.key.beta.prvKey, m.key.tau.prvKey, "betaTauG1", o), m.betaG1 = y[0], y = await C(6, "G2", 1, m.key.beta.prvKey, m.key.tau.prvKey, "betaTauG2", o), m.betaG2 = y[0], m.partialHash = De(g); + let b = new Uint8Array(u.F1.n8 * 2 * 6 + u.F2.n8 * 2 * 3); + cn(b, 0, u, m.key, !1), g.update(new Uint8Array(b)); + let x = g.digest(); + o && o.info(K(x, "Contribution Response Hash imported: ")); + let S = G.create({ dkLen: 64 }); + return S.update(x), await w(_, "G1", 2, 2 ** d * 2 - 1, "tauG1", o), await w(_, "G2", 3, 2 ** d, "tauG2", o), await w(_, "G1", 4, 2 ** d, "alphaTauG1", o), await w(_, "G1", 5, 2 ** d, "betaTauG1", o), await w(_, "G2", 6, 1, "betaG2", o), m.nextChallenge = S.digest(), o && o.info(K(m.nextChallenge, "Next Challenge Hash: ")), p.push(m), await pn(_, u, p), await c.close(), await _.close(), x; + async function C(t, n, r, i, a, o, s) { + let d = []; + c.pos = l[t][0].p, await e.startWriteSection(_, t), v[t] = _.pos; + let f = u[n], p = f.F.n8 * 2, m = Math.floor((1 << 20) / p), h = i; + for (let e = 0; e < r; e += m) { + s && s.debug(`applying key${o}: ${e}/${r}`); + let t = Math.min(r - e, m), n = await c.read(t * p), i = await f.batchApplyKey(n, h, a), l = _.write(i), v = await f.batchLEMtoC(i); + if (g.update(v), await l, e == 0) for (let e = 0; e < Math.min(2, r); e++) d.push(f.fromRprLEM(i, e * p)); + h = u.Fr.mul(h, u.Fr.exp(a, t)); + } + return await e.endWriteSection(_), d; + } + async function w(e, t, n, r, i, a) { + let o = u[t], s = o.F.n8 * 2, c = Math.floor((1 << 24) / s), l = e.pos; + e.pos = v[n]; + for (let t = 0; t < r; t += c) { + a && a.debug(`Hashing ${i}: ${t}/${r}`); + let n = Math.min(r - t, c), l = await e.read(n * s), u = await o.batchLEMtoU(l); + S.update(u); + } + e.pos = l; + } +} +//#endregion +//#region src/powersoftau_contribute.js +async function En(t, n, r, i, a) { + let { fd: o, sections: s } = await e.readBinFile(t, "ptau", 1), { curve: c, power: l, ceremonyPower: u } = await an(o, s); + if (l != u) throw a && a.error("This file has been reduced. You cannot contribute into a reduced file."), Error("This file has been reduced. You cannot contribute into a reduced file."); + s[12] && a && a.warn("WARNING: Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); + let d = await dn(o, c, s), f = { + name: r, + type: 0 + }, p, m = await Ne(i); + p = d.length > 0 ? d[d.length - 1].nextChallenge : mn(c, l, a), f.key = nn(c, p, m); + let h = G.create({ dkLen: 64 }); + h.update(p); + let g = await e.createBinFile(n, "ptau", 1, 7); + await rn(g, c, l); + let _ = [], v; + v = await S(2, "G1", 2 ** l * 2 - 1, c.Fr.e(1), f.key.tau.prvKey, "tauG1"), f.tauG1 = v[1], v = await S(3, "G2", 2 ** l, c.Fr.e(1), f.key.tau.prvKey, "tauG2"), f.tauG2 = v[1], v = await S(4, "G1", 2 ** l, f.key.alpha.prvKey, f.key.tau.prvKey, "alphaTauG1"), f.alphaG1 = v[0], v = await S(5, "G1", 2 ** l, f.key.beta.prvKey, f.key.tau.prvKey, "betaTauG1"), f.betaG1 = v[0], v = await S(6, "G2", 1, f.key.beta.prvKey, f.key.tau.prvKey, "betaTauG2"), f.betaG2 = v[0], f.partialHash = De(h); + let y = new Uint8Array(c.F1.n8 * 2 * 6 + c.F2.n8 * 2 * 3); + cn(y, 0, c, f.key, !1), h.update(new Uint8Array(y)); + let b = h.digest(); + a && a.info(K(b, "Contribution Response Hash imported: ")); + let x = G.create({ dkLen: 64 }); + return x.update(b), await C(g, "G1", 2, 2 ** l * 2 - 1, "tauG1"), await C(g, "G2", 3, 2 ** l, "tauG2"), await C(g, "G1", 4, 2 ** l, "alphaTauG1"), await C(g, "G1", 5, 2 ** l, "betaTauG1"), await C(g, "G2", 6, 1, "betaG2"), f.nextChallenge = x.digest(), a && a.info(K(f.nextChallenge, "Next Challenge Hash: ")), d.push(f), await pn(g, c, d), await o.close(), await g.close(), b; + async function S(t, n, r, i, l, u) { + let d = []; + o.pos = s[t][0].p, await e.startWriteSection(g, t), _[t] = g.pos; + let f = c[n], p = f.F.n8 * 2, m = Math.floor((1 << 20) / p), v = i; + for (let e = 0; e < r; e += m) { + a && a.debug(`processing: ${u}: ${e}/${r}`); + let t = Math.min(r - e, m), n = await o.read(t * p), i = await f.batchApplyKey(n, v, l), s = g.write(i), _ = await f.batchLEMtoC(i); + if (h.update(_), await s, e == 0) for (let e = 0; e < Math.min(2, r); e++) d.push(f.fromRprLEM(i, e * p)); + v = c.Fr.mul(v, c.Fr.exp(l, t)); + } + return await e.endWriteSection(g), d; + } + async function C(e, t, n, r, i) { + let o = c[t], s = o.F.n8 * 2, l = Math.floor((1 << 24) / s), u = e.pos; + e.pos = _[n]; + for (let t = 0; t < r; t += l) { + a && t && a.debug(`Hashing ${i}: ` + t); + let n = Math.min(r - t, l), c = await e.read(n * s), u = await o.batchLEMtoU(c); + x.update(u); + } + e.pos = u; + } +} +//#endregion +//#region src/powersoftau_preparephase2.js +async function Dn(t, n, r) { + let { fd: i, sections: a } = await e.readBinFile(t, "ptau", 1), { curve: o, power: c } = await an(i, a), l = await e.createBinFile(n, "ptau", 1, 11); + await rn(l, o, c), await e.copySection(i, a, l, 2), await e.copySection(i, a, l, 3), await e.copySection(i, a, l, 4), await e.copySection(i, a, l, 5), await e.copySection(i, a, l, 6), await e.copySection(i, a, l, 7), await u(2, 12, "G1", "tauG1"), await u(3, 13, "G2", "tauG2"), await u(4, 14, "G1", "alphaTauG1"), await u(5, 15, "G1", "betaTauG1"), await i.close(), await l.close(); + return; + async function u(t, n, u, d) { + r && r.debug("Starting section: " + d), await e.startWriteSection(l, n); + for (let e = 0; e <= c; e++) await f(e); + t == 2 && await f(c + 1), await e.endWriteSection(l); + async function f(n) { + let f = 2 ** n, p = o[u], m = p.F.n8 * 2, h; + h = new s(f * m), await e.startReadUniqueSection(i, a, t), t == 2 && n == c + 1 ? (await i.readToBuffer(h, 0, (f - 1) * m), h.set(o.G1.zeroAffine, (f - 1) * m)) : await i.readToBuffer(h, 0, f * m), await e.endReadSection(i, !0), h = await p.lagrangeEvaluations(h, "affine", "affine", r, d), await l.write(h); + } + } +} +//#endregion +//#region src/powersoftau_truncate.js +async function On(t, n, r) { + let { fd: i, sections: a } = await e.readBinFile(t, "ptau", 1), { curve: o, power: s, ceremonyPower: c } = await an(i, a), l = o.G1.F.n8 * 2, u = o.G2.F.n8 * 2; + for (let e = 1; e < s; e++) await d(e); + return await i.close(), !0; + async function d(t) { + let s = t.toString(); + for (; s.length < 2;) s = "0" + s; + r && r.debug("Writing Power: " + s); + let d = await e.createBinFile(n + s + ".ptau", "ptau", 1, 11); + await rn(d, o, t, c), await e.copySection(i, a, d, 2, (2 ** t * 2 - 1) * l), await e.copySection(i, a, d, 3, 2 ** t * u), await e.copySection(i, a, d, 4, 2 ** t * l), await e.copySection(i, a, d, 5, 2 ** t * l), await e.copySection(i, a, d, 6, u), await e.copySection(i, a, d, 7), await e.copySection(i, a, d, 12, (2 ** (t + 1) * 2 - 1) * l), await e.copySection(i, a, d, 13, (2 ** t * 2 - 1) * u), await e.copySection(i, a, d, 14, (2 ** t * 2 - 1) * l), await e.copySection(i, a, d, 15, (2 ** t * 2 - 1) * l), await d.close(); + } +} +//#endregion +//#region src/powersoftau_convert.js +async function kn(t, n, r) { + let { fd: i, sections: a } = await e.readBinFile(t, "ptau", 1), { curve: o, power: c } = await an(i, a), l = await e.createBinFile(n, "ptau", 1, 11); + await rn(l, o, c), await e.copySection(i, a, l, 2), await e.copySection(i, a, l, 3), await e.copySection(i, a, l, 4), await e.copySection(i, a, l, 5), await e.copySection(i, a, l, 6), await e.copySection(i, a, l, 7), await u(2, 12, "G1", "tauG1"), await e.copySection(i, a, l, 13), await e.copySection(i, a, l, 14), await e.copySection(i, a, l, 15), await i.close(), await l.close(); + return; + async function u(t, n, u, d) { + r && r.debug("Starting section: " + d), await e.startWriteSection(l, n); + let f = a[n][0].size, p = i.pageSize; + await e.startReadUniqueSection(i, a, n); + for (let e = 0; e < f; e += p) { + let t = Math.min(f - e, p), n = await i.read(t); + await l.write(n); + } + await e.endReadSection(i), t == 2 && await m(c + 1), await e.endWriteSection(l); + async function m(n) { + let f = 2 ** n, p = o[u], m = p.F.n8 * 2, h; + h = new s(f * m), await e.startReadUniqueSection(i, a, t), t == 2 && n == c + 1 ? (await i.readToBuffer(h, 0, (f - 1) * m), h.set(o.G1.zeroAffine, (f - 1) * m)) : await i.readToBuffer(h, 0, f * m), await e.endReadSection(i, !0), h = await p.lagrangeEvaluations(h, "affine", "affine", r, d), await l.write(h); + } + } +} +//#endregion +//#region src/powersoftau_export_json.js +async function An(t, n) { + let { fd: r, sections: i } = await e.readBinFile(t, "ptau", 1), { curve: a, power: o } = await an(r, i), s = {}; + return s.q = a.q, s.power = o, s.contributions = await dn(r, a, i), s.tauG1 = await c(2, "G1", 2 ** o * 2 - 1, "tauG1"), s.tauG2 = await c(3, "G2", 2 ** o, "tauG2"), s.alphaTauG1 = await c(4, "G1", 2 ** o, "alphaTauG1"), s.betaTauG1 = await c(5, "G1", 2 ** o, "betaTauG1"), s.betaG2 = await c(6, "G2", 1, "betaG2"), s.lTauG1 = await l(12, "G1", "lTauG1"), s.lTauG2 = await l(13, "G2", "lTauG2"), s.lAlphaTauG1 = await l(14, "G1", "lAlphaTauG2"), s.lBetaTauG1 = await l(15, "G1", "lBetaTauG2"), await r.close(), Le(a.Fr, s); + async function c(t, o, s, c) { + let l = a[o], u = l.F.n8 * 2, d = []; + await e.startReadUniqueSection(r, i, t); + for (let e = 0; e < s; e++) { + n && e && e % 1e4 == 0 && console.log(`${c}: ` + e); + let t = await r.read(u); + d.push(l.fromRprLEM(t, 0)); + } + return await e.endReadSection(r), d; + } + async function l(t, s, c) { + let l = a[s], u = l.F.n8 * 2, d = []; + await e.startReadUniqueSection(r, i, t); + for (let e = 0; e <= o; e++) { + n && console.log(`${c}: Power: ${e}`), d[e] = []; + let t = 2 ** e; + for (let i = 0; i < t; i++) { + n && i && i % 1e4 == 0 && console.log(`${c}: ${i}/${t}`); + let a = await r.read(u); + d[e].push(l.fromRprLEM(a, 0)); + } + } + return await e.endReadSection(r, !0), d; + } +} +//#endregion +//#region src/powersoftau.js +var jn = /* @__PURE__ */ v({ + beacon: () => Tn, + challengeContribute: () => wn, + contribute: () => En, + convert: () => kn, + exportChallenge: () => _n, + exportJson: () => An, + importResponse: () => vn, + newAccumulator: () => gn, + preparePhase2: () => Dn, + truncate: () => On, + verify: () => xn }); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -function hashToG2(curve, hash) { - const hashV = new DataView(hash.buffer, hash.byteOffset, hash.byteLength); - const seed = []; - for (let i=0; i<8; i++) { - seed[i] = hashV.getUint32(i*4); - } - - const rng = new ChaCha(seed); - - const g2_sp = curve.G2.fromRng(rng); - - return g2_sp; -} - -function getG2sp(curve, persinalization, challenge, g1s, g1sx) { - - const h = blake2b.create({ dkLen: 64 }); - const b1 = new Uint8Array([persinalization]); - h.update(b1); - h.update(challenge); - const b3 = curve.G1.toUncompressed(g1s); - h.update( b3); - const b4 = curve.G1.toUncompressed(g1sx); - h.update( b4); - const hash =h.digest(); - - return hashToG2(curve, hash); -} - -function calculatePubKey(k, curve, personalization, challengeHash, rng ) { - k.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); - k.g1_sx = curve.G1.toAffine(curve.G1.timesFr(k.g1_s, k.prvKey)); - k.g2_sp = curve.G2.toAffine(getG2sp(curve, personalization, challengeHash, k.g1_s, k.g1_sx)); - k.g2_spx = curve.G2.toAffine(curve.G2.timesFr(k.g2_sp, k.prvKey)); - return k; -} - -function createPTauKey(curve, challengeHash, rng) { - const key = { - tau: {}, - alpha: {}, - beta: {} - }; - key.tau.prvKey = curve.Fr.fromRng(rng); - key.alpha.prvKey = curve.Fr.fromRng(rng); - key.beta.prvKey = curve.Fr.fromRng(rng); - calculatePubKey(key.tau, curve, 0, challengeHash, rng); - calculatePubKey(key.alpha, curve, 1, challengeHash, rng); - calculatePubKey(key.beta, curve, 2, challengeHash, rng); - return key; -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function writePTauHeader(fd, curve, power, ceremonyPower) { - // Write the header - /////////// - - if (! ceremonyPower) ceremonyPower = power; - await fd.writeULE32(1); // Header type - const pHeaderSize = fd.pos; - await fd.writeULE64(0); // Temporally set to 0 length - - await fd.writeULE32(curve.F1.n64*8); - - const buff = new Uint8Array(curve.F1.n8); - Scalar.toRprLE(buff, 0, curve.q, curve.F1.n8); - await fd.write(buff); - await fd.writeULE32(power); // power - await fd.writeULE32(ceremonyPower); // power - - const headerSize = fd.pos - pHeaderSize - 8; - - const oldPos = fd.pos; - - await fd.writeULE64(headerSize, pHeaderSize); - - fd.pos = oldPos; -} - -async function readPTauHeader(fd, sections) { - if (!sections[1]) throw new Error(fd.fileName + ": File has no header"); - if (sections[1].length>1) throw new Error(fd.fileName +": File has more than one header"); - - fd.pos = sections[1][0].p; - const n8 = await fd.readULE32(); - const buff = await fd.read(n8); - const q = Scalar.fromRprLE(buff); - - const curve = await getCurveFromQ(q); - - if (curve.F1.n64*8 != n8) throw new Error(fd.fileName +": Invalid size"); - - const power = await fd.readULE32(); - const ceremonyPower = await fd.readULE32(); - - if (fd.pos-sections[1][0].p != sections[1][0].size) throw new Error("Invalid PTau header size"); - - return {curve, power, ceremonyPower}; -} - - -async function readPtauPubKey(fd, curve, montgomery) { - - const buff = await fd.read(curve.F1.n8*2*6 + curve.F2.n8*2*3); - - return fromPtauPubKeyRpr(buff, 0, curve, montgomery); -} - -function fromPtauPubKeyRpr(buff, pos, curve, montgomery) { - - const key = { - tau: {}, - alpha: {}, - beta: {} - }; - - key.tau.g1_s = readG1(); - key.tau.g1_sx = readG1(); - key.alpha.g1_s = readG1(); - key.alpha.g1_sx = readG1(); - key.beta.g1_s = readG1(); - key.beta.g1_sx = readG1(); - key.tau.g2_spx = readG2(); - key.alpha.g2_spx = readG2(); - key.beta.g2_spx = readG2(); - - return key; - - function readG1() { - let p; - if (montgomery) { - p = curve.G1.fromRprLEM( buff, pos ); - } else { - p = curve.G1.fromRprUncompressed( buff, pos ); - } - pos += curve.G1.F.n8*2; - return p; - } - - function readG2() { - let p; - if (montgomery) { - p = curve.G2.fromRprLEM( buff, pos ); - } else { - p = curve.G2.fromRprUncompressed( buff, pos ); - } - pos += curve.G2.F.n8*2; - return p; - } -} - -function toPtauPubKeyRpr(buff, pos, curve, key, montgomery) { - - writeG1(key.tau.g1_s); - writeG1(key.tau.g1_sx); - writeG1(key.alpha.g1_s); - writeG1(key.alpha.g1_sx); - writeG1(key.beta.g1_s); - writeG1(key.beta.g1_sx); - writeG2(key.tau.g2_spx); - writeG2(key.alpha.g2_spx); - writeG2(key.beta.g2_spx); - - async function writeG1(p) { - if (montgomery) { - curve.G1.toRprLEM(buff, pos, p); - } else { - curve.G1.toRprUncompressed(buff, pos, p); - } - pos += curve.F1.n8*2; - } - - async function writeG2(p) { - if (montgomery) { - curve.G2.toRprLEM(buff, pos, p); - } else { - curve.G2.toRprUncompressed(buff, pos, p); - } - pos += curve.F2.n8*2; - } - - return buff; -} - -async function writePtauPubKey(fd, curve, key, montgomery) { - const buff = new Uint8Array(curve.F1.n8*2*6 + curve.F2.n8*2*3); - toPtauPubKeyRpr(buff, 0, curve, key, montgomery); - await fd.write(buff); -} - -async function readContribution(fd, curve) { - const c = {}; - - c.tauG1 = await readG1(); - c.tauG2 = await readG2(); - c.alphaG1 = await readG1(); - c.betaG1 = await readG1(); - c.betaG2 = await readG2(); - c.key = await readPtauPubKey(fd, curve, true); - c.partialHash = await fd.read(216); - c.nextChallenge = await fd.read(64); - c.type = await fd.readULE32(); - - const buffV = new Uint8Array(curve.G1.F.n8*2*6+curve.G2.F.n8*2*3); - toPtauPubKeyRpr(buffV, 0, curve, c.key, false); - - const responseHasher = fromPartialHash(c.partialHash); - responseHasher.update(buffV); - c.responseHash = responseHasher.digest(); - - const paramLength = await fd.readULE32(); - const curPos = fd.pos; - let lastType =0; - while (fd.pos-curPos < paramLength) { - const buffType = await readDV(1); - if (buffType[0]<= lastType) throw new Error("Parameters in the contribution must be sorted"); - lastType = buffType[0]; - if (buffType[0]==1) { // Name - const buffLen = await readDV(1); - const buffStr = await readDV(buffLen[0]); - c.name = new TextDecoder().decode(buffStr); - } else if (buffType[0]==2) { - const buffExp = await readDV(1); - c.numIterationsExp = buffExp[0]; - } else if (buffType[0]==3) { - const buffLen = await readDV(1); - c.beaconHash = await readDV(buffLen[0]); - } else { - throw new Error("Parameter not recognized"); - } - } - if (fd.pos != curPos + paramLength) { - throw new Error("Parameters do not match"); - } - - return c; - - async function readG1() { - const pBuff = await fd.read(curve.G1.F.n8*2); - return curve.G1.fromRprLEM( pBuff ); - } - - async function readG2() { - const pBuff = await fd.read(curve.G2.F.n8*2); - return curve.G2.fromRprLEM( pBuff ); - } - - async function readDV(n) { - const b = await fd.read(n); - return new Uint8Array(b); - } -} - -async function readContributions(fd, curve, sections) { - if (!sections[7]) throw new Error(fd.fileName + ": File has no contributions"); - if (sections[7][0].length>1) throw new Error(fd.fileName +": File has more than one contributions section"); - - fd.pos = sections[7][0].p; - const nContributions = await fd.readULE32(); - const contributions = []; - for (let i=0; i0) { - const paramsBuff = new Uint8Array(params); - await fd.writeULE32(paramsBuff.byteLength); - await fd.write(paramsBuff); - } else { - await fd.writeULE32(0); - } - - - async function writeG1(p) { - curve.G1.toRprLEM(buffG1, 0, p); - await fd.write(buffG1); - } - - async function writeG2(p) { - curve.G2.toRprLEM(buffG2, 0, p); - await fd.write(buffG2); - } - -} - -async function writeContributions(fd, curve, contributions) { - - await fd.writeULE32(7); // Header type - const pContributionsSize = fd.pos; - await fd.writeULE64(0); // Temporally set to 0 length - - await fd.writeULE32(contributions.length); - for (let i=0; i< contributions.length; i++) { - await writeContribution(fd, curve, contributions[i]); - } - const contributionsSize = fd.pos - pContributionsSize - 8; - - const oldPos = fd.pos; - - await fd.writeULE64(contributionsSize, pContributionsSize); - fd.pos = oldPos; -} - -function calculateFirstChallengeHash(curve, power, logger) { - if (logger) logger.debug("Calculating First Challenge Hash"); - - const hasher = blake2b.create({ dkLen: 64 }); - - const vG1 = new Uint8Array(curve.G1.F.n8*2); - const vG2 = new Uint8Array(curve.G2.F.n8*2); - curve.G1.toRprUncompressed(vG1, 0, curve.G1.g); - curve.G2.toRprUncompressed(vG2, 0, curve.G2.g); - - hasher.update(blake2b.create({ dkLen: 64 }).digest()); - - let n; - - n=(2 ** power)*2 -1; - if (logger) logger.debug("Calculate Initial Hash: tauG1"); - hashBlock(vG1, n); - n= 2 ** power; - if (logger) logger.debug("Calculate Initial Hash: tauG2"); - hashBlock(vG2, n); - if (logger) logger.debug("Calculate Initial Hash: alphaTauG1"); - hashBlock(vG1, n); - if (logger) logger.debug("Calculate Initial Hash: betaTauG1"); - hashBlock(vG1, n); - hasher.update(vG2); - - return hasher.digest(); - - function hashBlock(buff, n) { - // this block size is a good compromise between speed and the maximum - // input size of the Blake2b update method (65,535,720 bytes). - const blockSize = 341000; - const nBlocks = Math.floor(n / blockSize); - const rem = n % blockSize; - const bigBuff = new Uint8Array(blockSize * buff.byteLength); - for (let i=0; i. -*/ - - -async function newAccumulator(curve, power, fileName, logger) { - - const fd = await createBinFile(fileName, "ptau", 1, 7); - - await writePTauHeader(fd, curve, power, 0); - - const buffG1 = curve.G1.oneAffine; - const buffG2 = curve.G2.oneAffine; - - // Write tauG1 - /////////// - await startWriteSection(fd, 2); - const nTauG1 = (2 ** power) * 2 -1; - for (let i=0; i< nTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("tauG1: " + i); - } - await endWriteSection(fd); - - // Write tauG2 - /////////// - await startWriteSection(fd, 3); - const nTauG2 = (2 ** power); - for (let i=0; i< nTauG2; i++) { - await fd.write(buffG2); - if ((logger)&&((i%100000) == 0)&&i) logger.log("tauG2: " + i); - } - await endWriteSection(fd); - - // Write alphaTauG1 - /////////// - await startWriteSection(fd, 4); - const nAlfaTauG1 = (2 ** power); - for (let i=0; i< nAlfaTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("alphaTauG1: " + i); - } - await endWriteSection(fd); - - // Write betaTauG1 - /////////// - await startWriteSection(fd, 5); - const nBetaTauG1 = (2 ** power); - for (let i=0; i< nBetaTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("betaTauG1: " + i); - } - await endWriteSection(fd); - - // Write betaG2 - /////////// - await startWriteSection(fd, 6); - await fd.write(buffG2); - await endWriteSection(fd); - - // Contributions - /////////// - await startWriteSection(fd, 7); - await fd.writeULE32(0); // 0 Contributions - await endWriteSection(fd); - - await fd.close(); - - const firstChallengeHash = calculateFirstChallengeHash(curve, power, logger); - - if (logger) logger.debug(formatHash(blake2b.create({ dkLen: 64 }).digest(), "Blank Contribution Hash:")); - - if (logger) logger.info(formatHash(firstChallengeHash, "First Contribution Hash:")); - - return firstChallengeHash; - -} - -// Format of the outpu -// Hash of the last contribution 64Bytes -// 2^N * 2 -1 TauG1 points (uncompressed) -// 2^N TauG2 Points (uncompressed) -// 2^N AlphaTauG1 Points (uncompressed) -// 2^N BetaTauG1 Points (uncompressed) -// BetaG2 (uncompressed) - - -async function exportChallenge(pTauFilename, challengeFilename, logger) { - const {fd: fdFrom, sections} = await readBinFile$1(pTauFilename, "ptau", 1); - - const {curve, power} = await readPTauHeader(fdFrom, sections); - - const contributions = await readContributions(fdFrom, curve, sections); - let lastResponseHash, curChallengeHash; - if (contributions.length == 0) { - lastResponseHash = blake2b.create({ dkLen: 64 }).digest(); - curChallengeHash = calculateFirstChallengeHash(curve, power); - } else { - lastResponseHash = contributions[contributions.length-1].responseHash; - curChallengeHash = contributions[contributions.length-1].nextChallenge; - } - - if (logger) logger.info(formatHash(lastResponseHash, "Last Response Hash: ")); - - if (logger) logger.info(formatHash(curChallengeHash, "New Challenge Hash: ")); - - - const fdTo = await createOverride(challengeFilename); - - const toHash = blake2b.create({ dkLen: 64 }); - await fdTo.write(lastResponseHash); - toHash.update(lastResponseHash); - - await exportSection(2, "G1", (2 ** power) * 2 -1, "tauG1"); - await exportSection(3, "G2", (2 ** power) , "tauG2"); - await exportSection(4, "G1", (2 ** power) , "alphaTauG1"); - await exportSection(5, "G1", (2 ** power) , "betaTauG1"); - await exportSection(6, "G2", 1 , "betaG2"); - - await fdFrom.close(); - await fdTo.close(); - - const calcCurChallengeHash = toHash.digest(); - - if (!hashIsEqual (curChallengeHash, calcCurChallengeHash)) { - if (logger) logger.info(formatHash(calcCurChallengeHash, "Calc Curret Challenge Hash: ")); - - if (logger) logger.error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); - throw new Error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); - } - - return curChallengeHash; - - async function exportSection(sectionId, groupName, nPoints, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPointsChunk = Math.floor((1<<24)/sG); - - await startReadUniqueSection$1(fdFrom, sections, sectionId); - for (let i=0; i< nPoints; i+= nPointsChunk) { - if (logger) logger.debug(`Exporting ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - let buff; - buff = await fdFrom.read(n*sG); - buff = await G.batchLEMtoU(buff); - await fdTo.write(buff); - toHash.update(buff); - } - await endReadSection$1(fdFrom); - } - - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function importResponse(oldPtauFilename, contributionFilename, newPTauFilename, name, importPoints, logger) { - - const noHash = new Uint8Array(64); - for (let i=0; i<64; i++) noHash[i] = 0xFF; - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - const contributions = await readContributions(fdOld, curve, sections); - const currentContribution = {}; - - if (name) currentContribution.name = name; - - const sG1 = curve.F1.n8*2; - const scG1 = curve.F1.n8; // Compressed size - const sG2 = curve.F2.n8*2; - const scG2 = curve.F2.n8; // Compressed size - - const fdResponse = await readExisting$3(contributionFilename); - - if (fdResponse.totalSize != - 64 + // Old Hash - ((2 ** power)*2-1)*scG1 + - (2 ** power)*scG2 + - (2 ** power)*scG1 + - (2 ** power)*scG1 + - scG2 + - sG1*6 + sG2*3) - throw new Error("Size of the contribution is invalid"); - - let lastChallengeHash; - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, importPoints ? 7: 2); - await writePTauHeader(fdNew, curve, power); - - const contributionPreviousHash = await fdResponse.read(64); - - if (hashIsEqual(noHash,lastChallengeHash)) { - lastChallengeHash = contributionPreviousHash; - contributions[contributions.length-1].nextChallenge = lastChallengeHash; - } - - if(!hashIsEqual(contributionPreviousHash,lastChallengeHash)) - throw new Error("Wrong contribution. This contribution is not based on the previous hash"); - - const hasherResponse = blake2b.create({ dkLen: 64 }); - hasherResponse.update(contributionPreviousHash); - - const startSections = []; - let res; - res = await processSection(fdResponse, fdNew, "G1", 2, (2 ** power) * 2 -1, [1], "tauG1"); - currentContribution.tauG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G2", 3, (2 ** power) , [1], "tauG2"); - currentContribution.tauG2 = res[0]; - res = await processSection(fdResponse, fdNew, "G1", 4, (2 ** power) , [0], "alphaG1"); - currentContribution.alphaG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G1", 5, (2 ** power) , [0], "betaG1"); - currentContribution.betaG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G2", 6, 1 , [0], "betaG2"); - currentContribution.betaG2 = res[0]; - - currentContribution.partialHash = toPartialHash(hasherResponse); - - - const buffKey = await fdResponse.read(curve.F1.n8*2*6+curve.F2.n8*2*3); - - currentContribution.key = fromPtauPubKeyRpr(buffKey, 0, curve, false); - - hasherResponse.update(new Uint8Array(buffKey)); - const hashResponse = hasherResponse.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - if (importPoints) { - const nextChallengeHasher = blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(nextChallengeHasher, fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G2", 3, (2 ** power) , "tauG2", logger); - await hashSection(nextChallengeHasher, fdNew, "G1", 4, (2 ** power) , "alphaTauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G1", 5, (2 ** power) , "betaTauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G2", 6, 1 , "betaG2", logger); - - currentContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(currentContribution.nextChallenge, "Next Challenge Hash: ")); - } else { - currentContribution.nextChallenge = noHash; - } - - contributions.push(currentContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdResponse.close(); - await fdNew.close(); - await fdOld.close(); - - return currentContribution.nextChallenge; - - async function processSection(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - if (importPoints) { - return await processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); - } else { - return await processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); - } - } - - async function processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - - const G = curve[groupName]; - const scG = G.F.n8; - const sG = G.F.n8*2; - - const singularPoints = []; - - await startWriteSection(fdTo, sectionId); - const nPointsChunk = Math.floor((1<<24)/sG); - - startSections[sectionId] = fdTo.pos; - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffC = await fdFrom.read(n * scG); - hasherResponse.update(buffC); - - const buffLEM = await G.batchCtoLEM(buffC); - - await fdTo.write(buffLEM); - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprLEM(buffLEM, (sp-i)*sG); - singularPoints.push(P); - } - } - } - - await endWriteSection(fdTo); - - return singularPoints; - } - - - async function processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - - const G = curve[groupName]; - const scG = G.F.n8; - - const singularPoints = []; - - const nPointsChunk = Math.floor((1<<24)/scG); - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffC = await fdFrom.read(n * scG); - hasherResponse.update(buffC); - - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprCompressed(buffC, (sp-i)*scG); - singularPoints.push(P); - } - } - } - - return singularPoints; - } - - - async function hashSection(nextChallengeHasher, fdTo, groupName, sectionId, nPoints, sectionName, logger) { - - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPointsChunk = Math.floor((1<<24)/sG); - - const oldPos = fdTo.pos; - fdTo.pos = startSections[sectionId]; - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Hashing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffLEM = await fdTo.read(n * sG); - - const buffU = await G.batchLEMtoU(buffLEM); - - nextChallengeHasher.update(buffU); - } - - fdTo.pos = oldPos; - } - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const sameRatio$1 = sameRatio$2; - -async function verifyContribution(curve, cur, prev, logger) { - let sr; - if (cur.type == 1) { // Verify the beacon. - const beaconKey = await keyFromBeacon(curve, prev.nextChallenge, cur.beaconHash, cur.numIterationsExp); - - if (!curve.G1.eq(cur.key.tau.g1_s, beaconKey.tau.g1_s)) { - if (logger) logger.error(`BEACON key (tauG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.tau.g1_sx, beaconKey.tau.g1_sx)) { - if (logger) logger.error(`BEACON key (tauG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.tau.g2_spx, beaconKey.tau.g2_spx)) { - if (logger) logger.error(`BEACON key (tauG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - - if (!curve.G1.eq(cur.key.alpha.g1_s, beaconKey.alpha.g1_s)) { - if (logger) logger.error(`BEACON key (alphaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.alpha.g1_sx, beaconKey.alpha.g1_sx)) { - if (logger) logger.error(`BEACON key (alphaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.alpha.g2_spx, beaconKey.alpha.g2_spx)) { - if (logger) logger.error(`BEACON key (alphaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - - if (!curve.G1.eq(cur.key.beta.g1_s, beaconKey.beta.g1_s)) { - if (logger) logger.error(`BEACON key (betaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.beta.g1_sx, beaconKey.beta.g1_sx)) { - if (logger) logger.error(`BEACON key (betaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.beta.g2_spx, beaconKey.beta.g2_spx)) { - if (logger) logger.error(`BEACON key (betaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - } - - cur.key.tau.g2_sp = curve.G2.toAffine(getG2sp(curve, 0, prev.nextChallenge, cur.key.tau.g1_s, cur.key.tau.g1_sx)); - cur.key.alpha.g2_sp = curve.G2.toAffine(getG2sp(curve, 1, prev.nextChallenge, cur.key.alpha.g1_s, cur.key.alpha.g1_sx)); - cur.key.beta.g2_sp = curve.G2.toAffine(getG2sp(curve, 2, prev.nextChallenge, cur.key.beta.g1_s, cur.key.beta.g1_sx)); - - sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, cur.key.tau.g2_sp, cur.key.tau.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (tau) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, cur.key.alpha.g1_s, cur.key.alpha.g1_sx, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (alpha) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, cur.key.beta.g2_sp, cur.key.beta.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (beta) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, prev.tauG1, cur.tauG1, cur.key.tau.g2_sp, cur.key.tau.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID tau*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, prev.tauG2, cur.tauG2); - if (sr !== true) { - if (logger) logger.error("INVALID tau*G2. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, prev.alphaG1, cur.alphaG1, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID alpha*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, prev.betaG1, cur.betaG1, cur.key.beta.g2_sp, cur.key.beta.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID beta*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, prev.betaG2, cur.betaG2); - if (sr !== true) { - if (logger) logger.error("INVALID beta*G2. challenge #"+cur.id+"It does not follow the previous contribution"); - return false; - } - - if (logger) logger.info("Powers Of tau file OK!"); - return true; -} - -async function verify(tauFilename, logger) { - let sr; - - const {fd, sections} = await readBinFile$1(tauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fd, sections); - const contrs = await readContributions(fd, curve, sections); - - if (logger) logger.debug("power: 2**" + power); - // Verify Last contribution - - if (logger) logger.debug("Computing initial contribution hash"); - const initialContribution = { - tauG1: curve.G1.g, - tauG2: curve.G2.g, - alphaG1: curve.G1.g, - betaG1: curve.G1.g, - betaG2: curve.G2.g, - nextChallenge: calculateFirstChallengeHash(curve, ceremonyPower, logger), - responseHash: blake2b.create({ dkLen: 64 }).digest() - }; - - if (contrs.length == 0) { - if (logger) logger.error("This file has no contribution! It cannot be used in production"); - return false; - } - - let prevContr; - if (contrs.length>1) { - prevContr = contrs[contrs.length-2]; - } else { - prevContr = initialContribution; - } - const curContr = contrs[contrs.length-1]; - if (logger) logger.debug("Validating contribution #"+contrs[contrs.length-1].id); - const res = await verifyContribution(curve, curContr, prevContr, logger); - if (!res) return false; - - - const nextContributionHasher = blake2b.create({ dkLen: 64 }); - nextContributionHasher.update(curContr.responseHash); - - // Verify powers and compute nextChallengeHash - - // await test(); - - // Verify Section tau*G1 - if (logger) logger.debug("Verifying powers in tau*G1 section"); - const rTau1 = await processSection(2, "G1", "tauG1", (2 ** power)*2-1, [0, 1], logger); - sr = await sameRatio$1(curve, rTau1.R1, rTau1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("tauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curve.G1.g, rTau1.singularPoints[0])) { - if (logger) logger.error("First element of tau*G1 section must be the generator"); - return false; - } - if (!curve.G1.eq(curContr.tauG1, rTau1.singularPoints[1])) { - if (logger) logger.error("Second element of tau*G1 section does not match the one in the contribution section"); - return false; - } - - // await test(); - - // Verify Section tau*G2 - if (logger) logger.debug("Verifying powers in tau*G2 section"); - const rTau2 = await processSection(3, "G2", "tauG2", 2 ** power, [0, 1], logger); - sr = await sameRatio$1(curve, curve.G1.g, curContr.tauG1, rTau2.R1, rTau2.R2); - if (sr !== true) { - if (logger) logger.error("tauG2 section. Powers do not match"); - return false; - } - if (!curve.G2.eq(curve.G2.g, rTau2.singularPoints[0])) { - if (logger) logger.error("First element of tau*G2 section must be the generator"); - return false; - } - if (!curve.G2.eq(curContr.tauG2, rTau2.singularPoints[1])) { - if (logger) logger.error("Second element of tau*G2 section does not match the one in the contribution section"); - return false; - } - - // Verify Section alpha*tau*G1 - if (logger) logger.debug("Verifying powers in alpha*tau*G1 section"); - const rAlphaTauG1 = await processSection(4, "G1", "alphatauG1", 2 ** power, [0], logger); - sr = await sameRatio$1(curve, rAlphaTauG1.R1, rAlphaTauG1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("alphaTauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curContr.alphaG1, rAlphaTauG1.singularPoints[0])) { - if (logger) logger.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"); - return false; - } - - // Verify Section beta*tau*G1 - if (logger) logger.debug("Verifying powers in beta*tau*G1 section"); - const rBetaTauG1 = await processSection(5, "G1", "betatauG1", 2 ** power, [0], logger); - sr = await sameRatio$1(curve, rBetaTauG1.R1, rBetaTauG1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("betaTauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curContr.betaG1, rBetaTauG1.singularPoints[0])) { - if (logger) logger.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"); - return false; - } - - //Verify Beta G2 - const betaG2 = await processSectionBetaG2(logger); - if (!curve.G2.eq(curContr.betaG2, betaG2)) { - if (logger) logger.error("betaG2 element in betaG2 section does not match the one in the contribution section"); - return false; - } - - - const nextContributionHash = nextContributionHasher.digest(); - - // Check the nextChallengeHash - if (power == ceremonyPower) { - if (!hashIsEqual(nextContributionHash,curContr.nextChallenge)) { - if (logger) logger.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"); - return false; - } - } - - if (logger) logger.info(formatHash(nextContributionHash, "Next challenge hash: ")); - - // Verify Previous contributions - - printContribution(curContr, prevContr); - for (let i = contrs.length-2; i>=0; i--) { - const curContr = contrs[i]; - const prevContr = (i>0) ? contrs[i-1] : initialContribution; - const res = await verifyContribution(curve, curContr, prevContr, logger); - if (!res) return false; - printContribution(curContr, prevContr); - } - if (logger) logger.info("-----------------------------------------------------"); - - if ((!sections[12]) || (!sections[13]) || (!sections[14]) || (!sections[15])) { - if (logger) logger.warn( - "this file does not contain phase2 precalculated values. Please run: \n" + - " snarkjs \"powersoftau preparephase2\" to prepare this file to be used in the phase2 ceremony." - ); - } else { - let res; - res = await verifyLagrangeEvaluations("G1", 2, 12, "tauG1", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G2", 3, 13, "tauG2", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G1", 4, 14, "alphaTauG1", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G1", 5, 15, "betaTauG1", logger); - if (!res) return false; - } - - await fd.close(); - - if (logger) logger.info("Powers of Tau Ok!"); - - return true; - - function printContribution(curContr, prevContr) { - if (!logger) return; - logger.info("-----------------------------------------------------"); - logger.info(`Contribution #${curContr.id}: ${curContr.name ||""}`); - - logger.info(formatHash(curContr.nextChallenge, "Next Challenge: ")); - - const buffV = new Uint8Array(curve.G1.F.n8*2*6+curve.G2.F.n8*2*3); - toPtauPubKeyRpr(buffV, 0, curve, curContr.key, false); - - const responseHasher = fromPartialHash(curContr.partialHash); - responseHasher.update(buffV); - const responseHash = responseHasher.digest(); - - logger.info(formatHash(responseHash, "Response Hash:")); - - logger.info(formatHash(prevContr.nextChallenge, "Response Hash:")); - - if (curContr.type == 1) { - logger.info(`Beacon generator: ${byteArray2hex(curContr.beaconHash)}`); - logger.info(`Beacon iterations Exp: ${curContr.numIterationsExp}`); - } - - } - - async function processSectionBetaG2(logger) { - const G = curve.G2; - const sG = G.F.n8*2; - const buffUv = new Uint8Array(sG); - - if (!sections[6]) { - logger.error("File has no BetaG2 section"); - throw new Error("File has no BetaG2 section"); - } - if (sections[6].length>1) { - logger.error("File has no BetaG2 section"); - throw new Error("File has more than one GetaG2 section"); - } - fd.pos = sections[6][0].p; - - const buff = await fd.read(sG); - const P = G.fromRprLEM(buff); - - G.toRprUncompressed(buffUv, 0, P); - nextContributionHasher.update(buffUv); - - return P; - } - - async function processSection(idSection, groupName, sectionName, nPoints, singularPointIndexes, logger) { - const MAX_CHUNK_SIZE = 1<<16; - const G = curve[groupName]; - const sG = G.F.n8*2; - await startReadUniqueSection$1(fd, sections, idSection); - - const singularPoints = []; - - let R1 = G.zero; - let R2 = G.zero; - - let lastBase = G.zero; - - for (let i=0; i0) { - const firstBase = G.fromRprLEM(bases, 0); - const r = readUInt32BE(getRandomBytes(4), 0); - - R1 = G.add(R1, G.timesScalar(lastBase, r)); - R2 = G.add(R2, G.timesScalar(firstBase, r)); - } - - const r1 = await G.multiExpAffine(bases.slice(0, (n-1)*sG), scalars); - const r2 = await G.multiExpAffine(bases.slice(sG), scalars); - - R1 = G.add(R1, r1); - R2 = G.add(R2, r2); - - lastBase = G.fromRprLEM( bases, (n-1)*sG); - - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprLEM(bases, (sp-i)*sG); - singularPoints.push(P); - } - } - - } - await endReadSection$1(fd); - - return { - R1: R1, - R2: R2, - singularPoints: singularPoints - }; - - } - - async function verifyLagrangeEvaluations(gName, tauSection, lagrangeSection, sectionName, logger) { - - if (logger) logger.debug(`Verifying phase2 calculated values ${sectionName}...`); - const G = curve[gName]; - const sG = G.F.n8*2; - - const seed= new Array(8); - for (let i=0; i<8; i++) { - seed[i] = readUInt32BE(getRandomBytes(4), 0); - } - - for (let p=0; p<= power; p ++) { - const res = await verifyPower(p); - if (!res) return false; - } - - if (tauSection == 2) { - const res = await verifyPower(power+1); - if (!res) return false; - } - - return true; - - async function verifyPower(p) { - if (logger) logger.debug(`Power ${p}...`); - const n8r = curve.Fr.n8; - const nPoints = 2 ** p; - let buff_r = new Uint32Array(nPoints); - let buffG; - - let rng = new ChaCha(seed); - - if (logger) logger.debug(`Creating random numbers Powers${p}...`); - for (let i=0; i. -*/ - - -/* - This function creates a new section in the fdTo file with id idSection. - It multiplies the points in fdFrom by first, first*inc, first*inc^2, .... - nPoint Times. - It also updates the newChallengeHasher with the new points -*/ - -async function applyKeyToSection(fdOld, sections, fdNew, idSection, curve, groupName, first, inc, sectionName, logger) { - const MAX_CHUNK_SIZE = 1 << 16; - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPoints = sections[idSection][0].size / sG; - - await startReadUniqueSection$1(fdOld, sections,idSection ); - await startWriteSection(fdNew, idSection); - - let t = first; - for (let i=0; i. -*/ - - -async function challengeContribute(curve, challengeFilename, responseFileName, entropy, logger) { - const fdFrom = await readExisting$3(challengeFilename); - - - const sG1 = curve.F1.n64*8*2; - const sG2 = curve.F2.n64*8*2; - const domainSize = (fdFrom.totalSize + sG1 - 64 - sG2) / (4*sG1 + sG2); - let e = domainSize; - let power = 0; - while (e>1) { - e = e /2; - power += 1; - } - - if (2 ** power != domainSize) throw new Error("Invalid file size"); - if (logger) logger.debug("Power to tau size: "+power); - - const rng = await getRandomRng(entropy); - - const fdTo = await createOverride(responseFileName); - - // Calculate the hash - const challengeHasher = blake2b.create({ dkLen: 64 }); - for (let i=0; i { - logger.debug(k + ".g1_s: " + curve.G1.toString(key[k].g1_s, 16)); - logger.debug(k + ".g1_sx: " + curve.G1.toString(key[k].g1_sx, 16)); - logger.debug(k + ".g2_sp: " + curve.G2.toString(key[k].g2_sp, 16)); - logger.debug(k + ".g2_spx: " + curve.G2.toString(key[k].g2_spx, 16)); - logger.debug(""); - }); - } - - const responseHasher = blake2b.create({ dkLen: 64 }); - - await fdTo.write(challengeHash); - responseHasher.update(challengeHash); - - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power)*2-1, curve.Fr.one , key.tau.prvKey, "COMPRESSED", "tauG1" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", (2 ** power) , curve.Fr.one , key.tau.prvKey, "COMPRESSED", "tauG2" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power) , key.alpha.prvKey, key.tau.prvKey, "COMPRESSED", "alphaTauG1", logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power) , key.beta.prvKey , key.tau.prvKey, "COMPRESSED", "betaTauG1" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", 1 , key.beta.prvKey , key.tau.prvKey, "COMPRESSED", "betaTauG2" , logger ); - - // Write and hash key - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - toPtauPubKeyRpr(buffKey, 0, curve, key, false); - await fdTo.write(buffKey); - responseHasher.update(buffKey); - const responseHash = responseHasher.digest(); - if (logger) logger.info(formatHash(responseHash, "Contribution Response Hash: ")); - - await fdTo.close(); - await fdFrom.close(); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function beacon$1(oldPtauFilename, newPTauFilename, name, beaconHashStr,numIterationsExp, logger) { - const beaconHash = hex2ByteArray(beaconHashStr); - if ( (beaconHash.byteLength == 0) - || (beaconHash.byteLength*2 !=beaconHashStr.length)) - { - if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); - return false; - } - if (beaconHash.length>=256) { - if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); - return false; - } - - numIterationsExp = parseInt(numIterationsExp); - if ((numIterationsExp<10)||(numIterationsExp>63)) { - if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); - return false; - } - - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - if (power != ceremonyPower) { - if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); - return false; - } - if (sections[12]) { - if (logger) logger.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); - } - const contributions = await readContributions(fdOld, curve, sections); - const curContribution = { - name: name, - type: 1, // Beacon - numIterationsExp: numIterationsExp, - beaconHash: beaconHash - }; - - let lastChallengeHash; - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - curContribution.key = await keyFromBeacon(curve, lastChallengeHash, beaconHash, numIterationsExp); - - const responseHasher = blake2b.create({ dkLen: 64 }); - responseHasher.update(lastChallengeHash); - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, 7); - await writePTauHeader(fdNew, curve, power); - - const startSections = []; - - let firstPoints; - firstPoints = await processSection(2, "G1", (2 ** power) * 2 -1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1", logger ); - curContribution.tauG1 = firstPoints[1]; - firstPoints = await processSection(3, "G2", (2 ** power) , curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2", logger ); - curContribution.tauG2 = firstPoints[1]; - firstPoints = await processSection(4, "G1", (2 ** power) , curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1", logger ); - curContribution.alphaG1 = firstPoints[0]; - firstPoints = await processSection(5, "G1", (2 ** power) , curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1", logger ); - curContribution.betaG1 = firstPoints[0]; - firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2", logger ); - curContribution.betaG2 = firstPoints[0]; - - curContribution.partialHash = toPartialHash(responseHasher); - - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - - toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); - - responseHasher.update(new Uint8Array(buffKey)); - const hashResponse = responseHasher.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - const nextChallengeHasher = blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1", logger); - await hashSection(fdNew, "G2", 3, (2 ** power) , "tauG2", logger); - await hashSection(fdNew, "G1", 4, (2 ** power) , "alphaTauG1", logger); - await hashSection(fdNew, "G1", 5, (2 ** power) , "betaTauG1", logger); - await hashSection(fdNew, "G2", 6, 1 , "betaG2", logger); - - curContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); - - contributions.push(curContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdOld.close(); - await fdNew.close(); - - return hashResponse; - - async function processSection(sectionId, groupName, NPoints, first, inc, sectionName, logger) { - const res = []; - fdOld.pos = sections[sectionId][0].p; - - await startWriteSection(fdNew, sectionId); - - startSections[sectionId] = fdNew.pos; - - const G = curve[groupName]; - const sG = G.F.n8*2; - const chunkSize = Math.floor((1<<20) / sG); // 128Mb chunks - let t = first; - for (let i=0 ; i. -*/ - - -async function contribute(oldPtauFilename, newPTauFilename, name, entropy, logger) { - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - if (power != ceremonyPower) { - if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); - throw new Error("This file has been reduced. You cannot contribute into a reduced file."); - } - if (sections[12]) { - if (logger) logger.warn("WARNING: Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); - } - const contributions = await readContributions(fdOld, curve, sections); - const curContribution = { - name: name, - type: 0, // Beacon - }; - - let lastChallengeHash; - - const rng = await getRandomRng(entropy); - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - // Generate a random key - - - curContribution.key = createPTauKey(curve, lastChallengeHash, rng); - - - const responseHasher = blake2b.create({ dkLen: 64 }); - responseHasher.update(lastChallengeHash); - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, 7); - await writePTauHeader(fdNew, curve, power); - - const startSections = []; - - let firstPoints; - firstPoints = await processSection(2, "G1", (2 ** power) * 2 -1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1" ); - curContribution.tauG1 = firstPoints[1]; - firstPoints = await processSection(3, "G2", (2 ** power) , curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2" ); - curContribution.tauG2 = firstPoints[1]; - firstPoints = await processSection(4, "G1", (2 ** power) , curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1" ); - curContribution.alphaG1 = firstPoints[0]; - firstPoints = await processSection(5, "G1", (2 ** power) , curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1" ); - curContribution.betaG1 = firstPoints[0]; - firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2" ); - curContribution.betaG2 = firstPoints[0]; - - curContribution.partialHash = toPartialHash(responseHasher); - - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - - toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); - - responseHasher.update(new Uint8Array(buffKey)); - const hashResponse = responseHasher.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - const nextChallengeHasher = blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1"); - await hashSection(fdNew, "G2", 3, (2 ** power) , "tauG2"); - await hashSection(fdNew, "G1", 4, (2 ** power) , "alphaTauG1"); - await hashSection(fdNew, "G1", 5, (2 ** power) , "betaTauG1"); - await hashSection(fdNew, "G2", 6, 1 , "betaG2"); - - curContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); - - contributions.push(curContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdOld.close(); - await fdNew.close(); - - return hashResponse; - - async function processSection(sectionId, groupName, NPoints, first, inc, sectionName) { - const res = []; - fdOld.pos = sections[sectionId][0].p; - - await startWriteSection(fdNew, sectionId); - - startSections[sectionId] = fdNew.pos; - - const G = curve[groupName]; - const sG = G.F.n8*2; - const chunkSize = Math.floor((1<<20) / sG); // 128Mb chunks - let t = first; - for (let i=0 ; i. -*/ - - -async function preparePhase2(oldPtauFilename, newPTauFilename, logger) { - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, 11); - await writePTauHeader(fdNew, curve, power); - - await copySection(fdOld, sections, fdNew, 2); - await copySection(fdOld, sections, fdNew, 3); - await copySection(fdOld, sections, fdNew, 4); - await copySection(fdOld, sections, fdNew, 5); - await copySection(fdOld, sections, fdNew, 6); - await copySection(fdOld, sections, fdNew, 7); - - await processSection(2, 12, "G1", "tauG1" ); - await processSection(3, 13, "G2", "tauG2" ); - await processSection(4, 14, "G1", "alphaTauG1" ); - await processSection(5, 15, "G1", "betaTauG1" ); - - await fdOld.close(); - await fdNew.close(); - - // await fs.promises.unlink(newPTauFilename+ ".tmp"); - - return; - - async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { - if (logger) logger.debug("Starting section: "+sectionName); - - await startWriteSection(fdNew, newSectionId); - - for (let p=0; p<=power; p++) { - await processSectionPower(p); - } - - if (oldSectionId == 2) { - await processSectionPower(power+1); - } - - await endWriteSection(fdNew); - - - async function processSectionPower(p) { - const nPoints = 2 ** p; - const G = curve[Gstr]; - const sGin = G.F.n8*2; - - let buff; - buff = new BigBuffer(nPoints*sGin); - - await startReadUniqueSection$1(fdOld, sections, oldSectionId); - if ((oldSectionId == 2)&&(p==power+1)) { - await fdOld.readToBuffer(buff, 0,(nPoints-1)*sGin ); - buff.set(curve.G1.zeroAffine, (nPoints-1)*sGin ); - } else { - await fdOld.readToBuffer(buff, 0,nPoints*sGin ); - } - await endReadSection$1(fdOld, true); - - - buff = await G.lagrangeEvaluations(buff, "affine", "affine", logger, sectionName); - await fdNew.write(buff); - - /* - if (p <= curve.Fr.s) { - buff = await G.ifft(buff, "affine", "affine", logger, sectionName); - await fdNew.write(buff); - } else if (p == curve.Fr.s+1) { - const smallM = 1<. -*/ - - -async function truncate(ptauFilename, template, logger) { - - const {fd: fdOld, sections} = await readBinFile$1(ptauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - for (let p=1; p. -*/ - - -async function convert(oldPtauFilename, newPTauFilename, logger) { - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, 11); - await writePTauHeader(fdNew, curve, power); - - // const fdTmp = await fastFile.createOverride(newPTauFilename+ ".tmp"); - - await copySection(fdOld, sections, fdNew, 2); - await copySection(fdOld, sections, fdNew, 3); - await copySection(fdOld, sections, fdNew, 4); - await copySection(fdOld, sections, fdNew, 5); - await copySection(fdOld, sections, fdNew, 6); - await copySection(fdOld, sections, fdNew, 7); - - await processSection(2, 12, "G1", "tauG1" ); - await copySection(fdOld, sections, fdNew, 13); - await copySection(fdOld, sections, fdNew, 14); - await copySection(fdOld, sections, fdNew, 15); - - await fdOld.close(); - await fdNew.close(); - - // await fs.promises.unlink(newPTauFilename+ ".tmp"); - - return; - - async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { - if (logger) logger.debug("Starting section: "+sectionName); - - await startWriteSection(fdNew, newSectionId); - - const size = sections[newSectionId][0].size; - const chunkSize = fdOld.pageSize; - await startReadUniqueSection$1(fdOld, sections, newSectionId); - for (let p=0; p. -*/ - - -async function exportJson(pTauFilename, verbose) { - const {fd, sections} = await readBinFile$1(pTauFilename, "ptau", 1); - - const {curve, power} = await readPTauHeader(fd, sections); - - const pTau = {}; - pTau.q = curve.q; - pTau.power = power; - pTau.contributions = await readContributions(fd, curve, sections); - - pTau.tauG1 = await exportSection(2, "G1", (2 ** power)*2 -1, "tauG1"); - pTau.tauG2 = await exportSection(3, "G2", (2 ** power), "tauG2"); - pTau.alphaTauG1 = await exportSection(4, "G1", (2 ** power), "alphaTauG1"); - pTau.betaTauG1 = await exportSection(5, "G1", (2 ** power), "betaTauG1"); - pTau.betaG2 = await exportSection(6, "G2", 1, "betaG2"); - - pTau.lTauG1 = await exportLagrange(12, "G1", "lTauG1"); - pTau.lTauG2 = await exportLagrange(13, "G2", "lTauG2"); - pTau.lAlphaTauG1 = await exportLagrange(14, "G1", "lAlphaTauG2"); - pTau.lBetaTauG1 = await exportLagrange(15, "G1", "lBetaTauG2"); - - await fd.close(); - - return stringifyBigIntsWithField(curve.Fr, pTau); - - - - async function exportSection(sectionId, groupName, nPoints, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - - const res = []; - await startReadUniqueSection$1(fd, sections, sectionId); - for (let i=0; i< nPoints; i++) { - if ((verbose)&&i&&(i%10000 == 0)) console.log(`${sectionName}: ` + i); - const buff = await fd.read(sG); - res.push(G.fromRprLEM(buff, 0)); - } - await endReadSection$1(fd); - - return res; - } - - async function exportLagrange(sectionId, groupName, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - - const res = []; - await startReadUniqueSection$1(fd, sections, sectionId); - for (let p=0; p<=power; p++) { - if (verbose) console.log(`${sectionName}: Power: ${p}`); - res[p] = []; - const nPoints = (2 ** p); - for (let i=0; i. -*/ - -var powersoftau = /*#__PURE__*/Object.freeze({ - __proto__: null, - beacon: beacon$1, - challengeContribute: challengeContribute, - contribute: contribute, - convert: convert, - exportChallenge: exportChallenge, - exportJson: exportJson, - importResponse: importResponse, - newAccumulator: newAccumulator, - preparePhase2: preparePhase2, - truncate: truncate, - verify: verify +//#endregion +//#region src/r1cs_print.js +function Mn(e, t, n) { + for (let t = 0; t < e.constraints.length; t++) r(e.constraints[t]); + function r(r) { + let i = (n) => { + let r = ""; + return Object.keys(n).forEach((i) => { + let a = t.varIdx2Name[i]; + a == "one" && (a = "1"); + let o = e.curve.Fr.toString(n[i]); + o == "1" && (o = ""), o == "-1" && (o = "-"), r != "" && o[0] != "-" && (o = "+" + o), r != "" && (o = " " + o), r = r + o + a; + }), r; + }, a = `[ ${i(r[0])} ] * [ ${i(r[1])} ] - [ ${i(r[2])} ] = 0`; + n && n.info(a); + } +} +//#endregion +//#region src/r1cs_info.js +var Nn = u.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16), Pn = u.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); +async function Fn(e, t) { + let n = await m(e, { + loadConstraints: !1, + loadMap: !1 + }); + return u.eq(n.prime, Pn) ? t && t.info("Curve: bn-128") : u.eq(n.prime, Nn) ? t && t.info("Curve: bls12-381") : t && t.info(`Unknown Curve. Prime: ${u.toString(n.prime)}`), t && t.info(`# of Wires: ${n.nVars}`), t && t.info(`# of Constraints: ${n.nConstraints}`), t && t.info(`# of Private Inputs: ${n.nPrvInputs}`), t && t.info(`# of Public Inputs: ${n.nPubInputs}`), t && t.info(`# of Labels: ${n.nLabels}`), t && t.info(`# of Outputs: ${n.nOutputs}`), n; +} +//#endregion +//#region src/r1cs_export_json.js +async function In(e, t) { + let n = await m(e, !0, !0, !0, t), r = n.curve.Fr; + return delete n.curve, delete n.F, Le(r, n); +} +//#endregion +//#region src/r1cs.js +var Ln = /* @__PURE__ */ v({ + exportJson: () => In, + info: () => Fn, + print: () => Mn }); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -function r1csPrint(r1cs, syms, logger) { - for (let i=0; i { - let S = ""; - const keys = Object.keys(lc); - keys.forEach( (k) => { - let name = syms.varIdx2Name[k]; - if (name == "one") name = "1"; - - let vs = r1cs.curve.Fr.toString(lc[k]); - if (vs == "1") vs = ""; // Do not show ones - if (vs == "-1") vs = "-"; // Do not show ones - if ((S!="")&&(vs[0]!="-")) vs = "+"+vs; - if (S!="") vs = " "+vs; - S= S + vs + name; - }); - return S; - }; - const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`; - if (logger) logger.info(S); - } - -} - -const SUBARRAY_SIZE$1 = 0x40000; - -const BigArrayHandler$1 = { - get: function(obj, prop) { - if (!isNaN(prop)) { - return obj.getElement(prop); - } else return obj[prop]; - }, - set: function(obj, prop, value) { - if (!isNaN(prop)) { - return obj.setElement(prop, value); - } else { - obj[prop] = value; - return true; - } - } -}; - -let _BigArray$1 = class _BigArray { - constructor (initSize) { - this.length = initSize || 0; - this.arr = new Array(SUBARRAY_SIZE$1); - - for (let i=0; i= this.length) this.length = idx+1; - return true; - } - getKeys() { - const newA = new BigArray$1(); - for (let i=0; i " + t.toString()); + }), a.trigger && (d ||= await Rn(i), u.logStartComponent = function(e) { + o && o.info("START: " + d.componentIdx2Name[e]); + }, u.logFinishComponent = function(e) { + o && o.info("FINISH: " + d.componentIdx2Name[e]); + }), u.sym = d; + let f = await Lt(l, u), p = await f.calculateWitness(s, !0), m = await e.createBinFile(r, "wtns", 2, 2); + await et(m, p, f.prime), await m.close(); +} +//#endregion +//#region src/wtns_export_json.js +async function Vn(e) { + return await rt(e); +} +//#endregion +//#region src/wtns_check.js +async function Hn(t, n, r) { + r && r.info("WITNESS CHECKING STARTED"), r && r.info("> Reading r1cs file"); + let { fd: i, sections: a } = await e.readBinFile(t, "r1cs", 1, 1 << 22, 1 << 24), o = await h(i, a, { + loadConstraints: !1, + loadCustomGates: !1 + }); + r && r.info("> Reading witness file"); + let { fd: s, sections: c } = await e.readBinFile(n, "wtns", 2, 1 << 22, 1 << 24), l = await nt(s, c); + if (!u.eq(o.prime, l.q)) throw Error("Curve of the witness does not match the curve of the proving key"); + let d = await e.readSection(s, c, 2); + await s.close(); + let f = (await w(o.prime)).Fr, p = f.n8, m = await e.readSection(i, a, 2); + r && (r.info("----------------------------"), r.info(" WITNESS CHECK"), r.info(` Curve: ${o.curve.name}`), r.info(` Vars (wires): ${o.nVars}`), r.info(` Outputs: ${o.nOutputs}`), r.info(` Public Inputs: ${o.nPubInputs}`), r.info(` Private Inputs: ${o.nPrvInputs}`), r.info(` Labels: ${o.nLabels}`), r.info(` Constraints: ${o.nConstraints}`), r.info(` Custom Gates: ${o.useCustomGates}`), r.info("----------------------------")), r && r.info("> Checking witness correctness"); + let g = 0, _ = !0; + for (let e = 0; e < o.nConstraints; e++) { + r && e !== 0 && e % 5e5 == 0 && r.info(`··· processing r1cs constraints ${e}/${o.nConstraints}`); + let t = y(), n = y(), i = y(), a = v(t), s = v(n), c = v(i); + if (!f.eq(f.sub(f.mul(a, s), c), f.zero)) { + r.warn("··· aborting checking process at constraint " + e), _ = !1; + break; + } + } + return i.close(), r && (_ ? (r.info("WITNESS IS CORRECT"), r.info("WITNESS CHECKING FINISHED SUCCESSFULLY")) : (r.warn("WITNESS IS NOT CORRECT"), r.warn("WITNESS CHECKING FINISHED UNSUCCESSFULLY"))), _; + function v(e) { + let t = f.zero; + return Object.keys(e).forEach((n) => { + let r = b(n), i = e[n]; + t = f.add(t, f.mul(r, i)); + }), t; + } + function y() { + let e = {}, t = m.slice(g, g + 4); + g += 4; + let n = new DataView(t.buffer).getUint32(0, !0), r = m.slice(g, g + (4 + o.n8) * n); + g += (4 + o.n8) * n; + let i = new DataView(r.buffer); + for (let t = 0; t < n; t++) { + let n = i.getUint32(t * (4 + o.n8), !0); + e[n] = o.F.fromRprLE(r, t * (4 + o.n8) + 4); + } + return e; + } + function b(e) { + return f.fromRprLE(d.slice(e * p, e * p + p)); + } +} +//#endregion +//#region src/wtns.js +var Un = /* @__PURE__ */ v({ + calculate: () => Vt, + check: () => Hn, + debug: () => Bn, + exportJson: () => Vn +}), Wn = 262144, Gn = { + get: function(e, t) { + return isNaN(t) ? e[t] : e.getElement(t); + }, + set: function(e, t, n) { + return isNaN(t) ? (e[t] = n, !0) : e.setElement(t, n); + } +}, Kn = class { + constructor(e) { + this.length = e || 0, this.arr = Array(Wn); + for (let t = 0; t < e; t += Wn) this.arr[t / Wn] = Array(Math.min(Wn, e - t)); + return this; + } + push() { + for (let e = 0; e < arguments.length; e++) this.setElement(this.length, arguments[e]); + } + slice(e, t) { + let n = Array(t - e); + for (let r = e; r < t; r++) n[r - e] = this.getElement(r); + return n; + } + getElement(e) { + e = parseInt(e); + let t = Math.floor(e / Wn), n = e % Wn; + return this.arr[t] ? this.arr[t][n] : void 0; + } + setElement(e, t) { + e = parseInt(e); + let n = Math.floor(e / Wn); + this.arr[n] || (this.arr[n] = Array(Wn)); + let r = e % Wn; + return this.arr[n][r] = t, e >= this.length && (this.length = e + 1), !0; + } + getKeys() { + let e = new qn(); + for (let t = 0; t < this.arr.length; t++) if (this.arr[t]) for (let n = 0; n < this.arr[t].length; n++) this.arr[t][n] !== void 0 && e.push(t * Wn + n); + return e; + } +}, qn = class { + constructor(e) { + let t = new Kn(e); + return new Proxy(t, Gn); + } }; - -async function open(fileName, openFlags, cacheSize, pageSize) { - cacheSize = cacheSize || 4096*64; - const fd =await fs.promises.open(fileName, openFlags); - - const stats = await fd.stat(); - - return new FastFile(fd, stats, cacheSize, pageSize, fileName); -} - - -class FastFile { - - constructor(fd, stats, cacheSize, pageSize, fileName) { - this.fileName = fileName; - this.fd = fd; - this.pos = 0; - this.pageSize = pageSize || (1 << 8); - while (this.pageSize < stats.blksize) { - this.pageSize *= 2; - } - this.totalSize = stats.size; - this.totalPages = Math.floor((stats.size -1) / this.pageSize)+1; - this.maxPagesLoaded = Math.floor( cacheSize / this.pageSize)+1; - this.pages = {}; - this.pendingLoads = []; - this.writing = false; - this.reading = false; - this.avBuffs = []; - this.history = {}; - } - - _loadPage(p) { - const self = this; - const P = new Promise((resolve, reject)=> { - self.pendingLoads.push({ - page: p, - resolve: resolve, - reject: reject - }); - }); - self.__statusPage("After Load request: ", p); - return P; - } - - __statusPage(s, p) { - const logEntry = []; - const self=this; - if (!self.logHistory) return; - logEntry.push("==" + s+ " " +p); - let S = ""; - for (let i=0; i " + self.history[p][i][j]); - } - } - } - - - - _triggerLoad() { - const self = this; - - if (self.reading) return; - if (self.pendingLoads.length==0) return; - - const pageIdxs = Object.keys(self.pages); - - const deletablePages = []; - for (let i=0; i0) && - ( (typeof self.pages[self.pendingLoads[0].page] != "undefined" ) - ||( (freePages>0) - ||(deletablePages.length>0)))) { - const load = self.pendingLoads.shift(); - if (typeof self.pages[load.page] != "undefined") { - self.pages[load.page].pendingOps ++; - const idx = deletablePages.indexOf(load.page); - if (idx>=0) deletablePages.splice(idx, 1); - if (self.pages[load.page].loading) { - self.pages[load.page].loading.push(load); - } else { - load.resolve(); - } - self.__statusPage("After Load (cached): ", load.page); - - } else { - if (freePages) { - freePages--; - } else { - const fp = deletablePages.shift(); - self.__statusPage("Before Unload: ", fp); - self.avBuffs.unshift(self.pages[fp]); - delete self.pages[fp]; - self.__statusPage("After Unload: ", fp); - } - - if (load.page>=self.totalPages) { - self.pages[load.page] = getNewPage(); - load.resolve(); - self.__statusPage("After Load (new): ", load.page); - } else { - self.reading = true; - self.pages[load.page] = getNewPage(); - self.pages[load.page].loading = [load]; - ops.push(self.fd.read(self.pages[load.page].buff, 0, self.pageSize, load.page*self.pageSize).then((res)=> { - self.pages[load.page].size = res.bytesRead; - const loading = self.pages[load.page].loading; - delete self.pages[load.page].loading; - for (let i=0; i { - load.reject(err); - })); - self.__statusPage("After Load (loading): ", load.page); - } - } - } - // if (ops.length>1) console.log(ops.length); - - Promise.all(ops).then( () => { - self.reading = false; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - self._tryClose(); - }); - - function getNewPage() { - if (self.avBuffs.length>0) { - const p = self.avBuffs.shift(); - p.dirty = false; - p.pendingOps = 1; - p.size =0; - return p; - } else { - return { - dirty: false, - buff: new Uint8Array(self.pageSize), - pendingOps: 1, - size: 0 - }; - } - } - - } - - - _triggerWrite() { - const self = this; - if (self.writing) return; - - const pageIdxs = Object.keys(self.pages); - - const ops = []; - - for (let i=0; i { - page.writing = false; - return; - }, (err) => { - console.log("ERROR Writing: "+err); - self.error = err; - self._tryClose(); - })); - } - } - - if (self.writing) { - Promise.all(ops).then( () => { - self.writing = false; - setImmediate(self._triggerWrite.bind(self)); - self._tryClose(); - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - }); - } - } - - _getDirtyPage() { - for (let p in this.pages) { - if (this.pages[p].dirty) return p; - } - return -1; - } - - async write(buff, pos) { - if (buff.byteLength == 0) return; - const self = this; -/* - if (buff.byteLength > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(buff.byteLength * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } -*/ - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+buff.byteLength; - if (self.totalSize < pos + buff.byteLength) self.totalSize = pos + buff.byteLength; - if (self.pendingClose) - throw new Error("Writing a closing file"); - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + buff.byteLength -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - let r = buff.byteLength; - while (r>0) { - await pagePromises[p-firstPage]; - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = buff.slice( buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.pages[p].buff.buffer, o, l); - dstView.set(srcView); - self.pages[p].dirty = true; - self.pages[p].pendingOps --; - self.pages[p].size = Math.max(o+l, self.pages[p].size); - if (p>=self.totalPages) { - self.totalPages = p+1; - } - r = r-l; - p ++; - o = 0; - if (!self.writing) setImmediate(self._triggerWrite.bind(self)); - } - } - - async read(len, pos) { - const self = this; - let buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - async readToBuffer(buffDst, offset, len, pos) { - if (len == 0) { - return; - } - const self = this; - if (len > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(len * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+len; - if (self.pendingClose) - throw new Error("Reading a closing file"); - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + len -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - // Remaining bytes to read - let r = pos + len > self.totalSize ? len - (pos + len - self.totalSize): len; - while (r>0) { - await pagePromises[p - firstPage]; - self.__statusPage("After Await (read): ", p); - - // bytes to copy from this page - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = new Uint8Array(self.pages[p].buff.buffer, self.pages[p].buff.byteOffset + o, l); - buffDst.set(srcView, offset+len-r); - self.pages[p].pendingOps --; - - self.__statusPage("After Op done: ", p); - - r = r-l; - p ++; - o = 0; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - } - - this.pos = pos + len; - - } - - - _tryClose() { - const self = this; - if (!self.pendingClose) return; - if (self.error) { - self.pendingCloseReject(self.error); - } - const p = self._getDirtyPage(); - if ((p>=0) || (self.writing) || (self.reading) || (self.pendingLoads.length>0)) return; - self.pendingClose(); - } - - close() { - const self = this; - if (self.pendingClose) - throw new Error("Closing the file twice"); - return new Promise((resolve, reject) => { - self.pendingClose = resolve; - self.pendingCloseReject = reject; - self._tryClose(); - }).then(()=> { - self.fd.close(); - }, (err) => { - self.fd.close(); - throw (err); - }); - } - - async discard() { - const self = this; - await self.close(); - await fs.promises.unlink(this.fileName); - } - - async writeULE32(v, pos) { - const self = this; - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, true); - - await self.write(tmpBuff32, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, false); - - await self.write(tmpBuff32, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - const tmpBuff64 = new Uint8Array(8); - const tmpBuff64v = new DataView(tmpBuff64.buffer); - - tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64, pos); - } - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - if (self.pendingClose) { - throw new Error("Reading a closing file"); - } - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - let currentPage = Math.floor(currentPosition / self.pageSize); - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - //Read page - let pagePromise = self._loadPage(currentPage); - self._triggerLoad(); - await pagePromise; - self.__statusPage("After Await (read): ", currentPage); - - let offsetOnPage = currentPosition % self.pageSize; - - const dataArray = new Uint8Array( - self.pages[currentPage].buff.buffer, - self.pages[currentPage].buff.byteOffset + offsetOnPage, - self.pageSize - offsetOnPage - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * this.pageSize + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * this.pageSize + offsetOnPage + dataArray.length; - } - - self.pages[currentPage].pendingOps--; - self.__statusPage("After Op done: ", currentPage); - - currentPosition = self.pos; - currentPage++; - - if (self.pendingLoads.length > 0) setImmediate(self._triggerLoad.bind(self)); - } - - return str; - } -} - -function readExisting$2(o) { - const fd = new MemFile(); - fd.o = o; - fd.allocSize = o.data.byteLength; - fd.totalSize = o.data.byteLength; - fd.readOnly = true; - fd.pos = 0; - return fd; -} - -const tmpBuff32$1 = new Uint8Array(4); -const tmpBuff32v$1 = new DataView(tmpBuff32$1.buffer); -const tmpBuff64$1 = new Uint8Array(8); -const tmpBuff64v$1 = new DataView(tmpBuff64$1.buffer); - -class MemFile { - - constructor() { - this.pageSize = 1 << 14; // for compatibility - } - - _resizeIfNeeded(newLen) { - if (newLen > this.allocSize) { - const newAllocSize = Math.max( - this.allocSize + (1 << 20), - Math.floor(this.allocSize * 1.1), - newLen - ); - const newData = new Uint8Array(newAllocSize); - newData.set(this.o.data); - this.o.data = newData; - this.allocSize = newAllocSize; - } - } - - async write(buff, pos) { - const self =this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) throw new Error("Writing a read only file"); - - this._resizeIfNeeded(pos + buff.byteLength); - - this.o.data.set(buff.slice(), pos); - - if (pos + buff.byteLength > this.totalSize) this.totalSize = pos + buff.byteLength; - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDest, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const buffSrc = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + pos, len); - - buffDest.set(buffSrc, offset); - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - - const buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - if (this.o.data.byteLength != this.totalSize) { - this.o.data = this.o.data.slice(0, this.totalSize); - } - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$1.setUint32(0, v, true); - - await self.write(tmpBuff32$1, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$1.setUint32(0, v, false); - - await self.write(tmpBuff32$1, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$1.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$1.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$1, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - const dataArray = new Uint8Array( - self.o.data.buffer, - currentPosition, - this.totalSize - currentPosition - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - let endOfStringFound = indexEndOfString !== -1; - - let str = ""; - if (endOfStringFound) { - str = new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPosition + indexEndOfString + 1; - } else { - self.pos = currentPosition; - } - return str; - } -} - -const PAGE_SIZE = 1<<22; - -function readExisting$1(o) { - const fd = new BigMemFile(); - fd.o = o; - fd.totalSize = (o.data.length-1)* PAGE_SIZE + o.data[o.data.length-1].byteLength; - fd.readOnly = true; - fd.pos = 0; - return fd; -} - -const tmpBuff32 = new Uint8Array(4); -const tmpBuff32v = new DataView(tmpBuff32.buffer); -const tmpBuff64 = new Uint8Array(8); -const tmpBuff64v = new DataView(tmpBuff64.buffer); - -class BigMemFile { - - constructor() { - this.pageSize = 1 << 14; // for compatibility - } - - _resizeIfNeeded(newLen) { - - if (newLen <= this.totalSize) return; - - if (this.readOnly) throw new Error("Reading out of file bounds"); - - const nPages = Math.floor((newLen - 1) / PAGE_SIZE)+1; - for (let i= Math.max(this.o.data.length-1, 0); i0) { - const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; - const srcView = buff.slice(buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.o.data[p].buffer, o, l); - dstView.set(srcView); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDst, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const firstPage = Math.floor(pos / PAGE_SIZE); - - let p = firstPage; - let o = pos % PAGE_SIZE; - // Remaining bytes to read - let r = len; - while (r>0) { - // bytes to copy from this page - const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; - const srcView = new Uint8Array(self.o.data[p].buffer, o, l); - buffDst.set(srcView, offset+len-r); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - const buff = new Uint8Array(len); - - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v.setUint32(0, v, true); - - await self.write(tmpBuff32, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v.setUint32(0, v, false); - - await self.write(tmpBuff32, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - const fixedSize = 2048; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - let currentPage = Math.floor(currentPosition / PAGE_SIZE); - let offsetOnPage = currentPosition % PAGE_SIZE; - - if (self.o.data[currentPage] === undefined) { - throw new Error("ERROR"); - } - - let readLength = Math.min(fixedSize, self.o.data[currentPage].length - offsetOnPage); - const dataArray = new Uint8Array(self.o.data[currentPage].buffer, offsetOnPage, readLength); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * PAGE_SIZE + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * PAGE_SIZE + offsetOnPage + dataArray.length; - } - - currentPosition = self.pos; - } - return str; - } -} - -/* global fetch */ - -async function readExisting(o, b, c) { - if (o instanceof Uint8Array) { - o = { - type: "mem", - data: o - }; - } - { - if (typeof o === "string") { - const buff = await fetch(o).then( function(res) { - return res.arrayBuffer(); - }).then(function (ab) { - return new Uint8Array(ab); - }); - o = { - type: "mem", - data: buff - }; - } - } - if (o.type == "file") { - return await open(o.fileName, O_RDONLY, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return await readExisting$2(o); - } else if (o.type == "bigMem") { - return await readExisting$1(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } -} - -async function readBinFile(fileName, type, maxVersion, cacheSize, pageSize) { - - const fd = await readExisting(fileName); - - const b = await fd.read(4); - let readedType = ""; - for (let i=0; i<4; i++) readedType += String.fromCharCode(b[i]); - - if (readedType != type) throw new Error(fileName + ": Invalid File format"); - - let v = await fd.readULE32(); - - if (v>maxVersion) throw new Error("Version not supported"); - - const nSections = await fd.readULE32(); - - // Scan sections - let sections = []; - for (let i=0; i1) throw new Error(fd.fileName +": Section Duplicated " +idSection); - - fd.pos = sections[idSection][0].p; - - fd.readingSection = sections[idSection][0]; -} - -async function endReadSection(fd, noCheck) { - if (typeof fd.readingSection === "undefined") throw new Error("Not reading a section"); - { - if (fd.pos-fd.readingSection.p != fd.readingSection.size) throw new Error("Invalid section size reading"); - } - delete fd.readingSection; -} - -async function readBigInt(fd, n8, pos) { - const buff = await fd.read(n8, pos); - return Scalar.fromRprLE(buff, 0, n8); -} - -async function readSection(fd, sections, idSection, offset, length) { - - offset = (typeof offset === "undefined") ? 0 : offset; - length = (typeof length === "undefined") ? sections[idSection][0].size - offset : length; - - if (offset + length > sections[idSection][0].size) { - throw new Error("Reading out of the range of the section"); - } - - let buff; - if (length < (1 << 30) ) { - buff = new Uint8Array(length); - } else { - buff = new BigBuffer(length); - } - - await fd.readToBuffer(buff, 0, length, sections[idSection][0].p + offset); - return buff; -} - -const R1CS_FILE_CUSTOM_GATES_LIST_SECTION = 4; -const R1CS_FILE_CUSTOM_GATES_USES_SECTION = 5; - -async function readR1csHeader(fd,sections,singleThread) { - let options; - if (typeof singleThread === "object") { - options = singleThread; - } else if (typeof singleThread === "undefined") { - options= { - singleThread: false, - }; - } else { - options = { - singleThread: singleThread, - }; - } - - const res = {}; - await startReadUniqueSection(fd, sections, 1); - // Read Header - res.n8 = await fd.readULE32(); - res.prime = await readBigInt(fd, res.n8); - - if (options.F) { - if (options.F.p != res.prime) throw new Error("Different Prime"); - res.F = options.F; - } else if (options.getFieldFromPrime) { - res.F = await options.getFieldFromPrime(res.prime, options.singleThread); - } else if (options.getCurveFromPrime) { - res.curve = await options.getCurveFromPrime(res.prime, options.singleThread); - res.F = res.curve.Fr; - } else { - try { - res.curve = await getCurveFromR$1(res.prime, options.singleThread); - res.F = res.curve.Fr; - } catch { - res.F = new F1Field(res.prime); - } - } - - res.nVars = await fd.readULE32(); - res.nOutputs = await fd.readULE32(); - res.nPubInputs = await fd.readULE32(); - res.nPrvInputs = await fd.readULE32(); - res.nLabels = await fd.readULE64(); - res.nConstraints = await fd.readULE32(); - res.useCustomGates = typeof sections[R1CS_FILE_CUSTOM_GATES_LIST_SECTION] !== "undefined" && sections[R1CS_FILE_CUSTOM_GATES_LIST_SECTION] !== null - && typeof sections[R1CS_FILE_CUSTOM_GATES_USES_SECTION] !== "undefined" && sections[R1CS_FILE_CUSTOM_GATES_USES_SECTION] !== null; - - await endReadSection(fd); - - return res; -} - -async function readConstraints(fd,sections, r1cs, logger, loggerCtx) { - let options; - if (typeof logger === "object") { - options = logger; - } else if (typeof logger === "undefined") { - options= {}; - } else { - options = { - logger: logger, - loggerCtx: loggerCtx, - }; - } - - const bR1cs = await readSection(fd, sections, 2); - let bR1csPos = 0; - let constraints; - if (r1cs.nConstraints>1<<20) { - constraints = new BigArray$1(); - } else { - constraints = []; - } - for (let i=0; i1<<20) { - map = new BigArray$1(); - } else { - map = []; - } - for (let i=0; i true by default - * loadMap: false by default - * loadCustomGates: true by default - */ - - if(typeof options !== "object") { - throw new Error("readR1csFd: options must be an object"); - } - - options.loadConstraints = "loadConstraints" in options ? options.loadConstraints : true; - options.loadMap = "loadMap" in options ? options.loadMap : false; - options.loadCustomGates = "loadCustomGates" in options ? options.loadCustomGates : true; - - const res = await readR1csHeader(fd, sections, options); - - if (options.loadConstraints) { - res.constraints = await readConstraints(fd, sections, res, options); - } - - // Read Labels - - if (options.loadMap) { - res.map = await readMap(fd, sections, res, options); - } - - if (options.loadCustomGates) { - if (res.useCustomGates) { - res.customGates = await readCustomGatesListSection(fd, sections, res); - res.customGatesUses = await readCustomGatesUsesSection(fd, sections, options); - } else { - res.customGates = []; - res.customGatesUses = []; - } - } - return res; -} - -async function readR1cs(fileName, loadConstraints, loadMap, singleThread, logger, loggerCtx) { - let options; - if (typeof loadConstraints === "object") { - options = loadConstraints; - } else if (typeof loadConstraints === "undefined") { - options= { - loadConstraints: true, - loadMap: false, - loadCustomGates: true - }; - } else { - options = { - loadConstraints: loadConstraints, - loadMap: loadMap, - singleThread: singleThread, - logger: logger, - loggerCtx: loggerCtx - }; - } - - const {fd, sections} = await readBinFile(fileName, "r1cs", 1); - - const res = await readR1csFd(fd, sections, options); - - await fd.close(); - - return res; -} - -async function readCustomGatesListSection(fd, sections, res) { - await startReadUniqueSection(fd, sections, R1CS_FILE_CUSTOM_GATES_LIST_SECTION); - - let num = await fd.readULE32(); - - let customGates = []; - for (let i = 0; i < num; i++) { - let customGate = {}; - customGate.templateName = await fd.readString(); - let numParameters = await fd.readULE32(); - - customGate.parameters = Array(numParameters); - let buff = await fd.read(res.n8 * numParameters); - - for (let j = 0; j < numParameters; j++) { - customGate.parameters[j] = res.F.fromRprLE(buff, j * res.n8, res.n8); } - customGates.push(customGate); - } - await endReadSection(fd); - - return customGates; -} - -async function readCustomGatesUsesSection(fd,sections, options) { - const bR1cs = await readSection(fd, sections, R1CS_FILE_CUSTOM_GATES_USES_SECTION); - const bR1cs32 = new Uint32Array(bR1cs.buffer, bR1cs.byteOffset, bR1cs.byteLength/4); - const nCustomGateUses = bR1cs32[0]; - let bR1csPos = 1; - let customGatesUses; - if (nCustomGateUses>1<<20) { - customGatesUses = new BigArray$1(); - } else { - customGatesUses = []; - } - for (let i=0; i. -*/ - - -const bls12381r = Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); -const bn128r = Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - -async function r1csInfo(r1csName, logger) { - - // Only the header (section 1) is needed for these counts; loading the - // constraints + wire-to-label map would read the whole (potentially many-GB) - // file for nothing. - const cir = await readR1cs(r1csName, {loadConstraints: false, loadMap: false}); - - if (Scalar.eq(cir.prime, bn128r)) { - if (logger) logger.info("Curve: bn-128"); - } else if (Scalar.eq(cir.prime, bls12381r)) { - if (logger) logger.info("Curve: bls12-381"); - } else { - if (logger) logger.info(`Unknown Curve. Prime: ${Scalar.toString(cir.prime)}`); - } - if (logger) logger.info(`# of Wires: ${cir.nVars}`); - if (logger) logger.info(`# of Constraints: ${cir.nConstraints}`); - if (logger) logger.info(`# of Private Inputs: ${cir.nPrvInputs}`); - if (logger) logger.info(`# of Public Inputs: ${cir.nPubInputs}`); - if (logger) logger.info(`# of Labels: ${cir.nLabels}`); - if (logger) logger.info(`# of Outputs: ${cir.nOutputs}`); - - return cir; -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - - -async function r1csExportJson(r1csFileName, logger) { - - const cir = await readR1cs(r1csFileName, true, true, true, logger); - const Fr=cir.curve.Fr; - delete cir.curve; - delete cir.F; - - return stringifyBigIntsWithField(Fr, cir); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -var r1cs = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportJson: r1csExportJson, - info: r1csInfo, - print: r1csPrint +//#endregion +//#region src/zkey_new.js +async function Jn(e, c, l, d) { + let f = G.create({ dkLen: 64 }), { fd: p, sections: m } = await r(c, "ptau", 1, 1 << 22, 1 << 24), { curve: h, power: _ } = await an(p, m), { fd: v, sections: y } = await r(e, "r1cs", 1, 1 << 22, 1 << 24), b = await g(v, y, !1), x = await t(l, "zkey", 1, 10, 1 << 22, 1 << 24), S = h.G1.F.n8 * 2, C = h.G2.F.n8 * 2; + if (b.prime != h.r) return d && d.error("r1cs curve does not match powers of tau ceremony curve"), -1; + let w = Ce(b.nConstraints + b.nPubInputs + b.nOutputs + 1 - 1) + 1; + if (w > _) return d && d.error(`circuit too big for this power of tau ceremony. ${b.nConstraints}*2 > 2**${_}`), -1; + if (!m[12]) return d && d.error("Powers of tau is not prepared."), -1; + let T = b.nOutputs + b.nPubInputs, E = 2 ** w; + await a(x, 1), await x.writeULE32(1), await n(x), await a(x, 2); + let D = h.q, O = (Math.floor((u.bitLength(D) - 1) / 64) + 1) * 8, k = h.r, A = (Math.floor((u.bitLength(k) - 1) / 64) + 1) * 8, j = u.mod(u.shl(1, A * 8), k), M = h.Fr.e(u.mod(u.mul(j, j), k)); + await x.writeULE32(O), await o(x, D, O), await x.writeULE32(A), await o(x, k, A), await x.writeULE32(b.nVars), await x.writeULE32(T), await x.writeULE32(E); + let N; + N = await p.read(S, m[4][0].p), await x.write(N), N = await h.G1.batchLEMtoU(N), f.update(N); + let P; + P = await p.read(S, m[5][0].p), await x.write(P), P = await h.G1.batchLEMtoU(P), f.update(P); + let F; + F = await p.read(C, m[6][0].p), await x.write(F), F = await h.G2.batchLEMtoU(F), f.update(F); + let I = new Uint8Array(S); + h.G1.toRprLEM(I, 0, h.G1.g); + let ee = new Uint8Array(C); + h.G2.toRprLEM(ee, 0, h.G2.g); + let L = new Uint8Array(S); + h.G1.toRprUncompressed(L, 0, h.G1.g); + let R = new Uint8Array(C); + h.G2.toRprUncompressed(R, 0, h.G2.g), await x.write(ee), await x.write(I), await x.write(ee), f.update(R), f.update(L), f.update(R), await n(x), d && d.info(W()), d && d.info("Reading r1cs"); + let z = await i(v, y, 2); + await v.close(); + let B = new qn(b.nVars), te = new qn(b.nVars), ne = new qn(b.nVars), V = new qn(b.nVars - T - 1), H = Array(T + 1); + d && d.info(W()), d && d.info("Reading tauG1"); + let re = await i(p, m, 12, (E - 1) * S, E * S); + d && d.info("Reading tauG2"); + let ie = await i(p, m, 13, (E - 1) * C, E * C); + d && d.info("Reading alphatauG1"); + let ae = await i(p, m, 14, (E - 1) * S, E * S); + d && d.info("Reading betatauG1"); + let oe = await i(p, m, 15, (E - 1) * S, E * S); + d && d.info(W()), d && d.info("processConstraints"), await le(), d && d.info(W()), d && d.info("composeAndWritePoints"), await ue(3, "G1", H, "IC"), H = null, d && d.info(W()), d && d.info("writeHs"), await ce(), d && d.info(W()), d && d.info("hashHPoints"), await fe(), d && d.info(W()), d && d.info("composeAndWritePoints 8 G1 C"), await ue(8, "G1", V, "C"), V = null, d && d.info(W()), d && d.info("composeAndWritePoints 5 G1 A"), await ue(5, "G1", B, "A"), B = null, d && d.info(W()), d && d.info("composeAndWritePoints 6 G1 B1"), await ue(6, "G1", te, "B1"), te = null, d && d.info(W()), d && d.info("composeAndWritePoints 7 G2 B2"), await ue(7, "G2", ne, "B2"), ne = null, d && d.info(W()), d && d.info("Contributions section"); + let se = f.digest(); + return await a(x, 10), await x.write(se), await x.writeULE32(0), await n(x), d && d.info(K(se, "Circuit hash: ")), await x.close(), await p.close(), se; + async function ce() { + await a(x, 9); + let e = new s(E * S); + if (w < h.Fr.s) { + let t = await i(p, m, 12, (E * 2 - 1) * S, E * 2 * S); + for (let n = 0; n < E; n++) { + d && n % 1e4 == 0 && d.debug(`splitting buffer: ${n}/${E}`); + let r = t.slice((n * 2 + 1) * S, (n * 2 + 1) * S + S); + e.set(r, n * S); + } + } else if (w == h.Fr.s) { + let t = m[12][0].p + (2 ** (w + 1) - 1) * S; + await p.readToBuffer(e, 0, E * S, t + E * S); + } else throw d && d.error("Circuit too big"), Error("Circuit too big for this curve"); + await x.write(e), await n(x); + } + async function le() { + let e = new Uint8Array(12 + h.Fr.n8), t = new DataView(e.buffer), r = new Uint8Array(h.Fr.n8); + h.Fr.toRprLE(r, 0, h.Fr.e(1)); + let i = 0; + function o() { + let e = z.slice(i, i + 4); + return i += 4, new DataView(e.buffer).getUint32(0, !0); + } + let c = new qn(); + for (let e = 0; e < b.nConstraints; e++) { + d && e % 1e4 == 0 && d.debug(`processing constraints: ${e}/${b.nConstraints}`); + let t = o(); + for (let n = 0; n < t; n++) { + let t = o(), n = i; + i += h.Fr.n8; + let r = S * e, a = S * e; + B[t] === void 0 && (B[t] = []), B[t].push([ + 0, + r, + n + ]), t <= T ? (H[t] === void 0 && (H[t] = []), H[t].push([ + 3, + a, + n + ])) : (V[t - T - 1] === void 0 && (V[t - T - 1] = []), V[t - T - 1].push([ + 3, + a, + n + ])), c.push([ + 0, + e, + t, + n + ]); + } + let n = o(); + for (let t = 0; t < n; t++) { + let t = o(), n = i; + i += h.Fr.n8; + let r = S * e, a = C * e, s = S * e; + te[t] === void 0 && (te[t] = []), te[t].push([ + 0, + r, + n + ]), ne[t] === void 0 && (ne[t] = []), ne[t].push([ + 1, + a, + n + ]), t <= T ? (H[t] === void 0 && (H[t] = []), H[t].push([ + 2, + s, + n + ])) : (V[t - T - 1] === void 0 && (V[t - T - 1] = []), V[t - T - 1].push([ + 2, + s, + n + ])), c.push([ + 1, + e, + t, + n + ]); + } + let r = o(); + for (let t = 0; t < r; t++) { + let t = o(), n = i; + i += h.Fr.n8; + let r = S * e; + t <= T ? (H[t] === void 0 && (H[t] = []), H[t].push([ + 0, + r, + n + ])) : (V[t - T - 1] === void 0 && (V[t - T - 1] = []), V[t - T - 1].push([ + 0, + r, + n + ])); + } + } + for (let e = 0; e <= T; e++) { + let t = S * (b.nConstraints + e), n = S * (b.nConstraints + e); + B[e] === void 0 && (B[e] = []), B[e].push([ + 0, + t, + -1 + ]), H[e] === void 0 && (H[e] = []), H[e].push([ + 3, + n, + -1 + ]), c.push([ + 0, + b.nConstraints + e, + e, + -1 + ]); + } + await a(x, 4); + let l = new s(c.length * (12 + h.Fr.n8) + 4), u = /* @__PURE__ */ new Uint8Array(4); + new DataView(u.buffer).setUint32(0, c.length, !0), l.set(u); + let f = 4; + for (let e = 0; e < c.length; e++) d && e % 1e5 == 0 && d.debug(`writing coeffs: ${e}/${c.length}`), p(c[e]); + await x.write(l), await n(x); + function p(n) { + t.setUint32(0, n[0], !0), t.setUint32(4, n[1], !0), t.setUint32(8, n[2], !0); + let i; + i = n[3] >= 0 ? h.Fr.fromRprLE(z.slice(n[3], n[3] + h.Fr.n8), 0) : h.Fr.fromRprLE(r, 0); + let a = h.Fr.mul(i, M); + h.Fr.toRprLE(e, 12, a), l.set(e, f), f += e.length; + } + } + async function ue(e, t, r, i) { + let o = 32768, s = h[t]; + U(r.length), await a(x, e); + let c = [], l = 0; + for (; l < r.length;) { + let e = 0; + for (; l < r.length && e < h.tm.concurrency;) { + d && d.debug(`Writing points start ${i}: ${l}/${r.length}`); + let n = 1, a = r[l] ? r[l].length : 0; + for (; l + n < r.length && a + (r[l + n] ? r[l + n].length : 0) < o && n < o;) a += r[l + n] ? r[l + n].length : 0, n++; + d && d.info("before slice:"), d && d.info(W()); + let s = r.slice(l, l + n); + d && d.info("after slice:"), d && d.info(W()); + let u = l; + c.push(de(t, s, d, i).then((e) => (d && d.debug(`Writing points end ${i}: ${u}/${r.length}`), e))), l += n, e++; + } + let n = await Promise.all(c); + for (let e = 0; e < n.length; e++) { + await x.write(n[e][0]); + let t = await s.batchLEMtoU(n[e][0]); + f.update(t); + } + c = []; + } + await n(x); + } + async function de(e, t, n, r) { + let i = h[e], a = i.F.n8 * 2, o = i.F.n8 * 3, c = i.F.n8 * 2, l, u, d, f; + if (e == "G1") l = "g1m_timesScalarAffine", u = "g1m_multiexpAffine", d = "g1m_batchToAffine", f = "g1m_zero"; + else if (e == "G2") l = "g2m_timesScalarAffine", u = "g2m_multiexpAffine", d = "g2m_batchToAffine", f = "g2m_zero"; + else throw Error("Invalid group"); + let p = 0; + for (let e = 0; e < t.length; e++) p += t[e] ? t[e].length : 0; + let m, g; + p > 32768 ? (m = new s(p * a), g = new s(p * h.Fr.n8)) : (m = new Uint8Array(p * a), g = new Uint8Array(p * h.Fr.n8)); + let _ = 0, v = 0, y = [ + re, + ie, + ae, + oe + ], b = new Uint8Array(h.Fr.n8); + h.Fr.toRprLE(b, 0, h.Fr.e(1)); + let x = 0; + for (let e = 0; e < t.length; e++) if (t[e]) for (let i = 0; i < t[e].length; i++) n && i && i % 1e4 == 0 && n.debug(`Configuring big array ${r}: ${i}/${t[e].length}`), m.set(y[t[e][i][0]].slice(t[e][i][1], t[e][i][1] + a), x * a), t[e][i][2] >= 0 ? g.set(z.slice(t[e][i][2], t[e][i][2] + h.Fr.n8), x * h.Fr.n8) : g.set(b, x * h.Fr.n8), x++; + if (t.length > 1) { + let e = []; + e.push({ + cmd: "ALLOCSET", + var: 0, + buff: m + }), e.push({ + cmd: "ALLOCSET", + var: 1, + buff: g + }), e.push({ + cmd: "ALLOC", + var: 2, + len: t.length * o + }), _ = 0, v = 0; + let n = 0; + for (let r = 0; r < t.length; r++) { + if (!t[r]) { + e.push({ + cmd: "CALL", + fnName: f, + params: [{ + var: 2, + offset: n + }] + }), n += o; + continue; + } + t[r].length == 1 ? e.push({ + cmd: "CALL", + fnName: l, + params: [ + { + var: 0, + offset: _ + }, + { + var: 1, + offset: v + }, + { val: h.Fr.n8 }, + { + var: 2, + offset: n + } + ] + }) : e.push({ + cmd: "CALL", + fnName: u, + params: [ + { + var: 0, + offset: _ + }, + { + var: 1, + offset: v + }, + { val: h.Fr.n8 }, + { val: t[r].length }, + { + var: 2, + offset: n + } + ] + }), _ += a * t[r].length, v += h.Fr.n8 * t[r].length, n += o; + } + return e.push({ + cmd: "CALL", + fnName: d, + params: [ + { var: 2 }, + { val: t.length }, + { var: 2 } + ] + }), e.push({ + cmd: "GET", + out: 0, + var: 2, + len: t.length * c + }), await h.tm.queueAction(e); + } else { + let e = await i.multiExpAffine(m, g, n, r); + return e = [i.toAffine(e)], e; + } + } + async function fe() { + let e = 16384; + U(E - 1); + for (let t = 0; t < E - 1; t += e) { + d && d.debug(`HashingHPoints: ${t}/${E}`); + let n = Math.min(E - 1, e); + await pe(t, n); + } + } + async function pe(e, t) { + let n = await p.read(t * S, m[2][0].p + (e + E) * S), r = await p.read(t * S, m[2][0].p + e * S), i = h.tm.concurrency, a = Math.floor(t / i), o = []; + for (let e = 0; e < i; e++) { + let s; + if (s = e < i - 1 ? a : t - e * a, s == 0) continue; + let c = n.slice(e * a * S, (e * a + s) * S), l = r.slice(e * a * S, (e * a + s) * S); + o.push(me(c, l)); + } + let s = await Promise.all(o); + for (let e = 0; e < s.length; e++) f.update(s[e][0]); + } + async function me(e, t) { + let n = e.byteLength / S, r = h.G1.F.n8 * 3, i = []; + i.push({ + cmd: "ALLOCSET", + var: 0, + buff: e + }), i.push({ + cmd: "ALLOCSET", + var: 1, + buff: t + }), i.push({ + cmd: "ALLOC", + var: 2, + len: n * r + }); + for (let e = 0; e < n; e++) i.push({ + cmd: "CALL", + fnName: "g1m_subAffine", + params: [ + { + var: 0, + offset: e * S + }, + { + var: 1, + offset: e * S + }, + { + var: 2, + offset: e * r + } + ] + }); + return i.push({ + cmd: "CALL", + fnName: "g1m_batchToAffine", + params: [ + { var: 2 }, + { val: n }, + { var: 2 } + ] + }), i.push({ + cmd: "CALL", + fnName: "g1m_batchLEMtoU", + params: [ + { var: 2 }, + { val: n }, + { var: 2 } + ] + }), i.push({ + cmd: "GET", + out: 0, + var: 2, + len: n * S + }), await h.tm.queueAction(i); + } + function U(e) { + let t = /* @__PURE__ */ new Uint8Array(4); + new DataView(t.buffer, t.byteOffset, t.byteLength).setUint32(0, e, !1), f.update(t); + } + function W() { + let e = process.memoryUsage(); + for (let t in e) e[t] = Math.round(e[t] / (1024 * 1024)); + return e; + } +} +//#endregion +//#region src/zkey_export_bellman.js +async function Yn(t, n, r) { + let { fd: i, sections: a } = await e.readBinFile(t, "zkey", 2), o = await He(i, a); + if (o.protocol != "groth16") throw Error("zkey file is not groth16"); + let s = await T(o.q), c = s.G1.F.n8 * 2, l = s.G2.F.n8 * 2, u = await Je(i, s, a), d = await jt(n); + await y(o.vk_alpha_1), await y(o.vk_beta_1), await b(o.vk_beta_2), await b(o.vk_gamma_2), await y(o.vk_delta_1), await b(o.vk_delta_2); + let f; + f = await e.readSection(i, a, 3), f = await s.G1.batchLEMtoU(f), await x("G1", f); + let p = await e.readSection(i, a, 9), m; + m = await s.G1.fft(p, "affine", "jacobian", r), m = await s.G1.batchApplyKey(m, s.Fr.neg(s.Fr.e(2)), s.Fr.w[o.power + 1], "jacobian", "affine", r), m = m.slice(0, m.byteLength - c), m = await s.G1.batchLEMtoU(m), await x("G1", m); + let h; + h = await e.readSection(i, a, 8), h = await s.G1.batchLEMtoU(h), await x("G1", h); + let g; + g = await e.readSection(i, a, 5), g = await s.G1.batchLEMtoU(g), await x("G1", g); + let _; + _ = await e.readSection(i, a, 6), _ = await s.G1.batchLEMtoU(_), await x("G1", _); + let v; + v = await e.readSection(i, a, 7), v = await s.G2.batchLEMtoU(v), await x("G2", v), await d.write(u.csHash), await S(u.contributions.length); + for (let e = 0; e < u.contributions.length; e++) { + let t = u.contributions[e]; + await y(t.deltaAfter), await y(t.delta.g1_s), await y(t.delta.g1_sx), await b(t.delta.g2_spx), await d.write(t.transcript); + } + await i.close(), await d.close(); + async function y(e) { + let t = new Uint8Array(c); + s.G1.toRprUncompressed(t, 0, e), await d.write(t); + } + async function b(e) { + let t = new Uint8Array(l); + s.G2.toRprUncompressed(t, 0, e), await d.write(t); + } + async function x(e, t) { + let n; + n = e == "G1" ? c : l; + let r = /* @__PURE__ */ new Uint8Array(4); + new DataView(r.buffer, r.byteOffset, r.byteLength).setUint32(0, t.byteLength / n, !1), await d.write(r), await d.write(t); + } + async function S(e) { + let t = /* @__PURE__ */ new Uint8Array(4); + new DataView(t.buffer, t.byteOffset, t.byteLength).setUint32(0, e, !1), await d.write(t); + } +} +//#endregion +//#region src/zkey_import_bellman.js +async function Xn(t, n, r, i, a) { + let { fd: o, sections: s } = await e.readBinFile(t, "zkey", 2), c = await He(o, s, !1); + if (c.protocol != "groth16") throw Error("zkey file is not groth16"); + let l = await T(c.q), u = l.G1.F.n8 * 2, d = l.G2.F.n8 * 2, f = await Je(o, l, s), p = {}, m = await Mt(n); + m.pos = u * 3 + d * 3 + 8 + u * c.nVars + 4 + u * (c.domainSize - 1) + 4 + u * c.nVars + 4 + u * c.nVars + 4 + d * c.nVars, p.csHash = await m.read(64); + let h = await m.readUBE32(); + p.contributions = []; + for (let e = 0; e < h; e++) { + let t = { delta: {} }; + t.deltaAfter = await C(m), t.delta.g1_s = await C(m), t.delta.g1_sx = await C(m), t.delta.g2_spx = await w(m), t.transcript = await m.read(64), e < f.contributions.length && (t.type = f.contributions[e].type, t.type == 1 && (t.beaconHash = f.contributions[e].beaconHash, t.numIterationsExp = f.contributions[e].numIterationsExp), f.contributions[e].name && (t.name = f.contributions[e].name)), p.contributions.push(t); + } + if (!we(p.csHash, f.csHash)) return a && a.error("Hash of the original circuit does not match with the MPC one"), !1; + if (f.contributions.length > p.contributions.length) return a && a.error("The impoerted file does not include new contributions"), !1; + for (let e = 0; e < f.contributions.length; e++) if (!E(f.contributions[e], p.contributions[e])) return a && a.error(`Previous contribution ${e} does not match`), !1; + if (i) for (let e = f.contributions.length; e < p.contributions.length; e++) p.contributions[e].name = i; + let g = await e.createBinFile(r, "zkey", 1, 10); + if (m.pos = 0, m.pos += u, m.pos += u, m.pos += d, m.pos += d, c.vk_delta_1 = await C(m), c.vk_delta_2 = await w(m), await Re(g, c), await m.readUBE32() != c.nPublic + 1) return a && a.error("Invalid number of points in IC"), await g.discard(), !1; + if (m.pos += u * (c.nPublic + 1), await e.copySection(o, s, g, 3), await e.copySection(o, s, g, 4), await m.readUBE32() != c.domainSize - 1) return a && a.error("Invalid number of points in H"), await g.discard(), !1; + let _, v = await m.read(u * (c.domainSize - 1)), y = await l.G1.batchUtoLEM(v); + _ = new Uint8Array(c.domainSize * u), _.set(y), l.G1.toRprLEM(_, u * (c.domainSize - 1), l.G1.zeroAffine); + let b = l.Fr.neg(l.Fr.inv(l.Fr.e(2))), x = l.Fr.inv(l.Fr.w[c.power + 1]); + if (_ = await l.G1.batchApplyKey(_, b, x, "affine", "jacobian", a), _ = await l.G1.ifft(_, "jacobian", "affine", a), await e.startWriteSection(g, 9), await g.write(_), await e.endWriteSection(g), await m.readUBE32() != c.nVars - c.nPublic - 1) return a && a.error("Invalid number of points in L"), await g.discard(), !1; + let S; + if (S = await m.read(u * (c.nVars - c.nPublic - 1)), S = await l.G1.batchUtoLEM(S), await e.startWriteSection(g, 8), await g.write(S), await e.endWriteSection(g), await m.readUBE32() != c.nVars) return a && a.error("Invalid number of points in A"), await g.discard(), !1; + if (m.pos += u * c.nVars, await e.copySection(o, s, g, 5), await m.readUBE32() != c.nVars) return a && a.error("Invalid number of points in B1"), await g.discard(), !1; + if (m.pos += u * c.nVars, await e.copySection(o, s, g, 6), await m.readUBE32() != c.nVars) return a && a.error("Invalid number of points in B2"), await g.discard(), !1; + return m.pos += d * c.nVars, await e.copySection(o, s, g, 7), await Xe(g, l, p), await m.close(), await g.close(), await o.close(), !0; + async function C(e) { + let t = await e.read(l.G1.F.n8 * 2); + return l.G1.fromRprUncompressed(t, 0); + } + async function w(e) { + let t = await e.read(l.G2.F.n8 * 2); + return l.G2.fromRprUncompressed(t, 0); + } + function E(e, t) { + return !(!l.G1.eq(e.deltaAfter, t.deltaAfter) || !l.G1.eq(e.delta.g1_s, t.delta.g1_s) || !l.G1.eq(e.delta.g1_sx, t.delta.g1_sx) || !l.G2.eq(e.delta.g2_spx, t.delta.g2_spx) || !we(e.transcript, t.transcript)); + } +} +//#endregion +//#region src/zkey_verify_frominit.js +var Zn = Oe; +async function Qn(t, n, r, i) { + let a, { fd: o, sections: l } = await e.readBinFile(r, "zkey", 2), d = await He(o, l, !1); + if (d.protocol != "groth16") throw Error("zkey file is not groth16"); + let f = await T(d.q), p = f.G1.F.n8 * 2, m = await Je(o, f, l), h = G.create({ dkLen: 64 }); + h.update(m.csHash); + let g = f.G1.g; + for (let e = 0; e < m.contributions.length; e++) { + let t = m.contributions[e], n = Te(h); + if (Ze(n, f, t.delta.g1_s), Ze(n, f, t.delta.g1_sx), !we(n.digest(), t.transcript)) return console.log(`INVALID(${e}): Inconsistent transcript `), !1; + let r = $t(f, t.transcript); + if (a = await Zn(f, t.delta.g1_s, t.delta.g1_sx, r, t.delta.g2_spx), a !== !0) return console.log(`INVALID(${e}): public key G1 and G2 do not have the same ration `), !1; + if (a = await Zn(f, g, t.deltaAfter, r, t.delta.g2_spx), a !== !0) return console.log(`INVALID(${e}): deltaAfter does not fillow the public key `), !1; + if (t.type == 1) { + let n = await Pe(t.beaconHash, t.numIterationsExp), r = f.Fr.fromRng(n), i = f.G1.toAffine(f.G1.fromRng(n)), a = f.G1.toAffine(f.G1.timesFr(i, r)); + if (f.G1.eq(i, t.delta.g1_s) !== !0) return console.log(`INVALID(${e}): Key of the beacon does not match. g1_s `), !1; + if (f.G1.eq(a, t.delta.g1_sx) !== !0) return console.log(`INVALID(${e}): Key of the beacon does not match. g1_sx `), !1; + } + $e(h, f, t); + let i = G.create({ dkLen: 64 }); + $e(i, f, t), t.contributionHash = i.digest(), g = t.deltaAfter; + } + let { fd: _, sections: v } = await e.readBinFile(t, "zkey", 2), y = await He(_, v, !1); + if (y.protocol != "groth16") throw Error("zkeyinit file is not groth16"); + if (!u.eq(y.q, d.q) || !u.eq(y.r, d.r) || y.n8q != d.n8q || y.n8r != d.n8r) return i && i.error("INVALID: Different curves"), !1; + if (y.nVars != d.nVars || y.nPublic != d.nPublic || y.domainSize != d.domainSize) return i && i.error("INVALID: Different circuit parameters"), !1; + if (!f.G1.eq(d.vk_alpha_1, y.vk_alpha_1)) return i && i.error("INVALID: Invalid alpha1"), !1; + if (!f.G1.eq(d.vk_beta_1, y.vk_beta_1)) return i && i.error("INVALID: Invalid beta1"), !1; + if (!f.G2.eq(d.vk_beta_2, y.vk_beta_2)) return i && i.error("INVALID: Invalid beta2"), !1; + if (!f.G2.eq(d.vk_gamma_2, y.vk_gamma_2)) return i && i.error("INVALID: Invalid gamma2"), !1; + if (!f.G1.eq(d.vk_delta_1, g)) return i && i.error("INVALID: Invalid delta1"), !1; + if (a = await Zn(f, f.G1.g, g, f.G2.g, d.vk_delta_2), a !== !0) return i && i.error("INVALID: Invalid delta2"), !1; + let b = await Je(_, f, v); + if (!we(m.csHash, b.csHash)) return i && i.error("INVALID: Circuit does not match"), !1; + if (l[8][0].size != p * (d.nVars - d.nPublic - 1)) return i && i.error("INVALID: Invalid L section size"), !1; + if (l[9][0].size != p * d.domainSize) return i && i.error("INVALID: Invalid H section size"), !1; + let x; + if (x = await e.sectionIsEqual(o, l, _, v, 3), !x) return i && i.error("INVALID: IC section is not identical"), !1; + if (x = await e.sectionIsEqual(o, l, _, v, 4), !x) return i && i.error("Coeffs section is not identical"), !1; + if (x = await e.sectionIsEqual(o, l, _, v, 5), !x) return i && i.error("A section is not identical"), !1; + if (x = await e.sectionIsEqual(o, l, _, v, 6), !x) return i && i.error("B1 section is not identical"), !1; + if (x = await e.sectionIsEqual(o, l, _, v, 7), !x) return i && i.error("B2 section is not identical"), !1; + if (a = await S("G1", _, v, o, l, 8, d.vk_delta_2, y.vk_delta_2, "L section"), a !== !0) return i && i.error("L section does not match"), !1; + if (a = await C(), a !== !0) return i && i.error("H section does not match"), !1; + i && i.info(K(m.csHash, "Circuit Hash: ")), await o.close(), await _.close(); + for (let e = m.contributions.length - 1; e >= 0; e--) { + let t = m.contributions[e]; + i && i.info("-------------------------"), i && i.info(K(t.contributionHash, `contribution #${e + 1} ${t.name ? t.name : ""}:`)), t.type == 1 && (i && i.info(`Beacon generator: ${Ie(t.beaconHash)}`), i && i.info(`Beacon iterations Exp: ${t.numIterationsExp}`)); + } + return i && i.info("-------------------------"), i && i.info("ZKey Ok!"), !0; + async function S(t, n, r, o, s, c, l, u, d) { + let p = 1 << 20, m = f[t], h = m.F.n8 * 2; + await e.startReadUniqueSection(n, r, c), await e.startReadUniqueSection(o, s, c); + let g = m.zero, _ = m.zero, v = r[c][0].size / h; + for (let e = 0; e < v; e += p) { + i && i.debug(`Same ratio check ${d}: ${e}/${v}`); + let t = Math.min(v - e, p), r = await n.read(t * h), a = await o.read(t * h), s = Ae(4 * t), c = await m.multiExpAffine(r, s), l = await m.multiExpAffine(a, s); + g = m.add(g, c), _ = m.add(_, l); + } + return await e.endReadSection(n), await e.endReadSection(o), v == 0 ? !0 : (a = await Zn(f, g, _, l, u), a === !0); + } + async function C() { + let t = 1 << 20, r = f.G1, u = f.Fr, p = r.F.n8 * 2, { fd: m, sections: h } = await e.readBinFile(n, "ptau", 1), g = new s(d.domainSize * d.n8r), _ = Array(8); + for (let e = 0; e < 8; e++) _[e] = Me(Ae(4), 0); + let v = new c(_); + for (let e = 0; e < d.domainSize - 1; e++) { + let t = u.fromRng(v); + u.toRprLE(g, e * d.n8r, t); + } + u.toRprLE(g, (d.domainSize - 1) * d.n8r, u.zero); + let b = r.zero; + for (let e = 0; e < d.domainSize; e += t) { + i && i.debug(`H Verification(tau): ${e}/${d.domainSize}`); + let n = Math.min(d.domainSize - e, t), a = await w(await m.read(p * n, h[2][0].p + d.domainSize * p + e * p), await m.read(p * n, h[2][0].p + e * p)), o = g.slice(e * d.n8r, (e + n) * d.n8r), s = await r.multiExpAffine(a, o); + b = r.add(b, s); + } + g = await u.batchToMontgomery(g); + let x; + if (d.power < u.s) x = u.neg(u.e(2)); + else { + let e = 2 ** u.s, t = u.exp(u.shift, e); + x = u.sub(t, u.one); + } + let S = d.power < u.s ? u.w[d.power + 1] : u.shift; + g = await u.batchApplyKey(g, x, S), g = await u.fft(g), g = await u.batchFromMontgomery(g), await e.startReadUniqueSection(o, l, 9); + let C = r.zero; + for (let e = 0; e < d.domainSize; e += t) { + i && i.debug(`H Verification(lagrange): ${e}/${d.domainSize}`); + let n = Math.min(d.domainSize - e, t), a = await o.read(p * n), s = g.slice(e * d.n8r, (e + n) * d.n8r), c = await r.multiExpAffine(a, s); + C = r.add(C, c); + } + return await e.endReadSection(o), a = await Zn(f, b, C, d.vk_delta_2, y.vk_delta_2), a === !0; + } + async function w(e, t) { + let n = f.G1.F.n8 * 2, r = e.byteLength / n, i = f.tm.concurrency, a = Math.floor(r / i), o = []; + for (let n = 0; n < i; n++) { + let s; + if (s = n < i - 1 ? a : r - n * a, s == 0) continue; + let c = e.slice(n * a * p, (n * a + s) * p), l = t.slice(n * a * p, (n * a + s) * p); + o.push(E(c, l)); + } + let s = await Promise.all(o), c = new Uint8Array(r * n), l = 0; + for (let e = 0; e < s.length; e++) c.set(s[e][0], l), l += s[e][0].byteLength; + return c; + } + async function E(e, t) { + let n = f.G1.F.n8 * 2, r = f.G1.F.n8 * 3, i = e.byteLength / n, a = []; + a.push({ + cmd: "ALLOCSET", + var: 0, + buff: e + }), a.push({ + cmd: "ALLOCSET", + var: 1, + buff: t + }), a.push({ + cmd: "ALLOC", + var: 2, + len: i * r + }); + for (let e = 0; e < i; e++) a.push({ + cmd: "CALL", + fnName: "g1m_subAffine", + params: [ + { + var: 0, + offset: e * n + }, + { + var: 1, + offset: e * n + }, + { + var: 2, + offset: e * r + } + ] + }); + return a.push({ + cmd: "CALL", + fnName: "g1m_batchToAffine", + params: [ + { var: 2 }, + { val: i }, + { var: 2 } + ] + }), a.push({ + cmd: "GET", + out: 0, + var: 2, + len: i * n + }), await f.tm.queueAction(a); + } +} +//#endregion +//#region src/zkey_verify_fromr1cs.js +async function $n(e, t, n, r) { + let i = { type: "bigMem" }; + return await Jn(e, t, i, r), await Qn(i, t, n, r); +} +//#endregion +//#region src/zkey_contribute.js +async function er(t, n, r, i, a) { + let { fd: o, sections: s } = await e.readBinFile(t, "zkey", 2), c = await He(o, s); + if (c.protocol != "groth16") throw Error("zkey file is not groth16"); + let l = await T(c.q), u = await Je(o, l, s), d = await e.createBinFile(n, "zkey", 1, 10), f = await Ne(i), p = G.create({ dkLen: 64 }); + p.update(u.csHash); + for (let e = 0; e < u.contributions.length; e++) $e(p, l, u.contributions[e]); + let m = {}; + m.delta = {}, m.delta.prvKey = l.Fr.fromRng(f), m.delta.g1_s = l.G1.toAffine(l.G1.fromRng(f)), m.delta.g1_sx = l.G1.toAffine(l.G1.timesFr(m.delta.g1_s, m.delta.prvKey)), Ze(p, l, m.delta.g1_s), Ze(p, l, m.delta.g1_sx), m.transcript = p.digest(), m.delta.g2_sp = $t(l, m.transcript), m.delta.g2_spx = l.G2.toAffine(l.G2.timesFr(m.delta.g2_sp, m.delta.prvKey)), c.vk_delta_1 = l.G1.timesFr(c.vk_delta_1, m.delta.prvKey), c.vk_delta_2 = l.G2.timesFr(c.vk_delta_2, m.delta.prvKey), m.deltaAfter = c.vk_delta_1, m.type = 0, r && (m.name = r), u.contributions.push(m), await Re(d, c), await e.copySection(o, s, d, 3), await e.copySection(o, s, d, 4), await e.copySection(o, s, d, 5), await e.copySection(o, s, d, 6), await e.copySection(o, s, d, 7); + let h = l.Fr.inv(m.delta.prvKey); + await Sn(o, s, d, 8, l, "G1", h, l.Fr.e(1), "L Section", a), await Sn(o, s, d, 9, l, "G1", h, l.Fr.e(1), "H Section", a), await Xe(d, l, u), await o.close(), await d.close(); + let g = G.create({ dkLen: 64 }); + $e(g, l, m); + let _ = g.digest(); + return a && a.info(K(u.csHash, "Circuit Hash: ")), a && a.info(K(_, "Contribution Hash: ")), _; +} +//#endregion +//#region src/zkey_beacon.js +async function tr(t, n, r, i, a, o) { + let s = Fe(i); + if (s.byteLength == 0 || s.byteLength * 2 != i.length) return o && o.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"), !1; + if (s.length >= 256) return o && o.error("Maximum length of beacon hash is 255 bytes"), !1; + if (a = parseInt(a), a < 10 || a > 63) return o && o.error("Invalid numIterationsExp. (Must be between 10 and 63)"), !1; + let { fd: c, sections: l } = await e.readBinFile(t, "zkey", 2), u = await He(c, l); + if (u.protocol != "groth16") throw Error("zkey file is not groth16"); + let d = await T(u.q), f = await Je(c, d, l), p = await e.createBinFile(n, "zkey", 1, 10), m = await Pe(s, a), h = G.create({ dkLen: 64 }); + h.update(f.csHash); + for (let e = 0; e < f.contributions.length; e++) $e(h, d, f.contributions[e]); + let g = {}; + g.delta = {}, g.delta.prvKey = d.Fr.fromRng(m), g.delta.g1_s = d.G1.toAffine(d.G1.fromRng(m)), g.delta.g1_sx = d.G1.toAffine(d.G1.timesFr(g.delta.g1_s, g.delta.prvKey)), Ze(h, d, g.delta.g1_s), Ze(h, d, g.delta.g1_sx), g.transcript = h.digest(), g.delta.g2_sp = $t(d, g.transcript), g.delta.g2_spx = d.G2.toAffine(d.G2.timesFr(g.delta.g2_sp, g.delta.prvKey)), u.vk_delta_1 = d.G1.timesFr(u.vk_delta_1, g.delta.prvKey), u.vk_delta_2 = d.G2.timesFr(u.vk_delta_2, g.delta.prvKey), g.deltaAfter = u.vk_delta_1, g.type = 1, g.numIterationsExp = a, g.beaconHash = s, r && (g.name = r), f.contributions.push(g), await Re(p, u), await e.copySection(c, l, p, 3), await e.copySection(c, l, p, 4), await e.copySection(c, l, p, 5), await e.copySection(c, l, p, 6), await e.copySection(c, l, p, 7); + let _ = d.Fr.inv(g.delta.prvKey); + await Sn(c, l, p, 8, d, "G1", _, d.Fr.e(1), "L Section", o), await Sn(c, l, p, 9, d, "G1", _, d.Fr.e(1), "H Section", o), await Xe(p, d, f), await c.close(), await p.close(); + let v = G.create({ dkLen: 64 }); + $e(v, d, g); + let y = v.digest(); + return o && o.info(K(y, "Contribution Hash: ")), y; +} +//#endregion +//#region src/zkey_export_json.js +async function nr(e) { + let t = await Ke(e, !0); + return delete t.curve, delete t.F, p.stringifyBigInts(t); +} +//#endregion +//#region src/zkey_bellman_contribute.js +async function rr(e, t, n, r, i) { + let a = await Ne(r), o = e.Fr.fromRng(a), s = e.Fr.inv(o), c = e.G1.F.n8 * 2, l = e.G2.F.n8 * 2, u = await Mt(t), d = await jt(n); + await D(c), await D(c), await D(l), await D(l); + let f = await O(), p = e.G1.timesFr(f, o); + await A(p); + let m = await k(); + await j(e.G2.timesFr(m, o)); + let h = await u.readUBE32(); + await d.writeUBE32(h), await D(h * c); + let g = await u.readUBE32(); + await d.writeUBE32(g), await Cn(u, d, null, e, "G1", g, s, e.Fr.e(1), "UNCOMPRESSED", "H", i); + let _ = await u.readUBE32(); + await d.writeUBE32(_), await Cn(u, d, null, e, "G1", _, s, e.Fr.e(1), "UNCOMPRESSED", "L", i); + let v = await u.readUBE32(); + await d.writeUBE32(v), await D(v * c); + let y = await u.readUBE32(); + await d.writeUBE32(y), await D(y * c); + let b = await u.readUBE32(); + await d.writeUBE32(b), await D(b * l); + let x = G.create({ dkLen: 64 }), S = {}; + S.csHash = await u.read(64), x.update(S.csHash); + let C = await u.readUBE32(); + S.contributions = []; + for (let t = 0; t < C; t++) { + let t = { delta: {} }; + t.deltaAfter = await O(), t.delta.g1_s = await O(), t.delta.g1_sx = await O(), t.delta.g2_spx = await k(), t.transcript = await u.read(64), S.contributions.push(t), $e(x, e, t); + } + let w = {}; + w.delta = {}, w.delta.prvKey = o, w.delta.g1_s = e.G1.toAffine(e.G1.fromRng(a)), w.delta.g1_sx = e.G1.toAffine(e.G1.timesFr(w.delta.g1_s, o)), Ze(x, e, w.delta.g1_s), Ze(x, e, w.delta.g1_sx), w.transcript = x.digest(), w.delta.g2_sp = $t(e, w.transcript), w.delta.g2_spx = e.G2.toAffine(e.G2.timesFr(w.delta.g2_sp, o)), w.deltaAfter = p, w.type = 0, S.contributions.push(w), await d.write(S.csHash), await d.writeUBE32(S.contributions.length); + for (let e = 0; e < S.contributions.length; e++) { + let t = S.contributions[e]; + await A(t.deltaAfter), await A(t.delta.g1_s), await A(t.delta.g1_sx), await j(t.delta.g2_spx), await d.write(t.transcript); + } + let T = G.create({ dkLen: 64 }); + $e(T, e, w); + let E = T.digest(); + return i && i.info(K(E, "Contribution Hash: ")), await d.close(), await u.close(), E; + async function D(e) { + let t = u.pageSize * 2; + for (let n = 0; n < e; n += t) { + let r = Math.min(e - n, t), i = await u.read(r); + await d.write(i); + } + } + async function O() { + let t = await u.read(e.G1.F.n8 * 2); + return e.G1.fromRprUncompressed(t, 0); + } + async function k() { + let t = await u.read(e.G2.F.n8 * 2); + return e.G2.fromRprUncompressed(t, 0); + } + async function A(t) { + let n = new Uint8Array(c); + e.G1.toRprUncompressed(n, 0, t), await d.write(n); + } + async function j(t) { + let n = new Uint8Array(l); + e.G2.toRprUncompressed(n, 0, t), await d.write(n); + } +} +//#endregion +//#region src/zkey_export_verificationkey.js +var { stringifyBigInts: ir } = p; +async function ar(t, n) { + n && n.info("EXPORT VERIFICATION KEY STARTED"); + let { fd: r, sections: i } = await e.readBinFile(t, "zkey", 2), a = await He(r, i); + n && n.info("> Detected protocol: " + a.protocol); + let o; + if (a.protocol === "groth16") o = await or(a, r, i); + else if (a.protocol === "plonk") o = await sr(a); + else if (a.protocolId && a.protocolId === 10) o = await cr(a, n); + else throw Error("zkey file protocol unrecognized"); + return await r.close(), n && n.info("EXPORT VERIFICATION KEY FINISHED"), o; +} +async function or(t, n, r) { + let i = await T(t.q), a = i.G1.F.n8 * 2, o = await i.pairing(t.vk_alpha_1, t.vk_beta_2), s = { + protocol: t.protocol, + curve: i.name, + nPublic: t.nPublic, + vk_alpha_1: i.G1.toObject(t.vk_alpha_1), + vk_beta_2: i.G2.toObject(t.vk_beta_2), + vk_gamma_2: i.G2.toObject(t.vk_gamma_2), + vk_delta_2: i.G2.toObject(t.vk_delta_2), + vk_alphabeta_12: i.Gt.toObject(o) + }; + await e.startReadUniqueSection(n, r, 3), s.IC = []; + for (let e = 0; e <= t.nPublic; e++) { + let e = await n.read(a), t = i.G1.toObject(e); + s.IC.push(t); + } + return await e.endReadSection(n), s = ir(s), s; +} +async function sr(e) { + let t = await T(e.q), n = { + protocol: e.protocol, + curve: t.name, + nPublic: e.nPublic, + power: e.power, + k1: t.Fr.toObject(e.k1), + k2: t.Fr.toObject(e.k2), + Qm: t.G1.toObject(e.Qm), + Ql: t.G1.toObject(e.Ql), + Qr: t.G1.toObject(e.Qr), + Qo: t.G1.toObject(e.Qo), + Qc: t.G1.toObject(e.Qc), + S1: t.G1.toObject(e.S1), + S2: t.G1.toObject(e.S2), + S3: t.G1.toObject(e.S3), + X_2: t.G2.toObject(e.X_2), + w: t.Fr.toObject(t.Fr.w[e.power]) + }; + return n = ir(n), n; +} +async function cr(e, t) { + let n = await T(e.q); + return ir({ + protocol: e.protocol, + curve: n.name, + nPublic: e.nPublic, + power: e.power, + k1: n.Fr.toObject(e.k1), + k2: n.Fr.toObject(e.k2), + w: n.Fr.toObject(n.Fr.w[e.power]), + w3: n.Fr.toObject(e.w3), + w4: n.Fr.toObject(e.w4), + w8: n.Fr.toObject(e.w8), + wr: n.Fr.toObject(e.wr), + X_2: n.G2.toObject(e.X_2), + C0: n.G1.toObject(e.C0) + }); +} +//#endregion +//#region src/zkey.js +var lr = /* @__PURE__ */ v({ + beacon: () => tr, + bellmanContribute: () => rr, + contribute: () => er, + exportBellman: () => Yn, + exportJson: () => nr, + exportSolidityVerifier: () => null, + exportVerificationKey: () => ar, + importBellman: () => Xn, + newZKey: () => Jn, + verifyFromInit: () => Qn, + verifyFromR1cs: () => $n }); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function loadSymbols(symFileName) { - const sym = { - labelIdx2Name: [ "one" ], - varIdx2Name: [ "one" ], - componentIdx2Name: [] - }; - const fd = await readExisting$3(symFileName); - const buff = await fd.read(fd.totalSize); - const symsStr = new TextDecoder("utf-8").decode(buff); - const lines = symsStr.split("\n"); - for (let i=0; i. -*/ - -const {unstringifyBigInts: unstringifyBigInts$7} = utils; - - -async function wtnsDebug(_input, wasmFileName, wtnsFileName, symName, options, logger) { - - const input = unstringifyBigInts$7(_input); - - const fdWasm = await readExisting$3(wasmFileName); - const wasm = await fdWasm.read(fdWasm.totalSize); - await fdWasm.close(); - - const wcOps = {...options, sanityCheck: true}; - let sym = await loadSymbols(symName); - if (options.set) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logSetSignal= function(labelIdx, value) { - // The line below splits the arrow log into 2 strings to avoid some Secure ECMAScript issues - if (logger) logger.info("SET " + sym.labelIdx2Name[labelIdx] + " <" + "-- " + value.toString()); - }; - } - if (options.get) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logGetSignal= function(varIdx, value) { - // The line below splits the arrow log into 2 strings to avoid some Secure ECMAScript issues - if (logger) logger.info("GET " + sym.labelIdx2Name[varIdx] + " --" + "> " + value.toString()); - }; - } - if (options.trigger) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logStartComponent= function(cIdx) { - if (logger) logger.info("START: " + sym.componentIdx2Name[cIdx]); - }; - wcOps.logFinishComponent= function(cIdx) { - if (logger) logger.info("FINISH: " + sym.componentIdx2Name[cIdx]); - }; - } - wcOps.sym = sym; - - const wc = await builder(wasm, wcOps); - const w = await wc.calculateWitness(input, true); - - const fdWtns = await createBinFile(wtnsFileName, "wtns", 2, 2); - - await write(fdWtns, w, wc.prime); - - await fdWtns.close(); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function wtnsExportJson(wtnsFileName) { - - const w = await read(wtnsFileName); - - return w; -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function wtnsCheck(r1csFilename, wtnsFilename, logger) { - - if (logger) logger.info("WITNESS CHECKING STARTED"); - - // Read r1cs file - if (logger) logger.info("> Reading r1cs file"); - const { - fd: fdR1cs, - sections: sectionsR1cs - } = await readBinFile$1(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); - const r1cs = await readR1csFd(fdR1cs, sectionsR1cs, { loadConstraints: false, loadCustomGates: false }); - - // Read witness file - if (logger) logger.info("> Reading witness file"); - const { - fd: fdWtns, - sections: wtnsSections - } = await readBinFile$1(wtnsFilename, "wtns", 2, 1 << 22, 1 << 24); - const wtnsHeader = await readHeader(fdWtns, wtnsSections); - - if (!Scalar.eq(r1cs.prime, wtnsHeader.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - const buffWitness = await readSection$1(fdWtns, wtnsSections, 2); - await fdWtns.close(); - - const curve = await getCurveFromR(r1cs.prime); - const Fr = curve.Fr; - const sFr = Fr.n8; - - const bR1cs = await readSection$1(fdR1cs, sectionsR1cs, 2); - - if (logger) { - logger.info("----------------------------"); - logger.info(" WITNESS CHECK"); - logger.info(` Curve: ${r1cs.curve.name}`); - logger.info(` Vars (wires): ${r1cs.nVars}`); - logger.info(` Outputs: ${r1cs.nOutputs}`); - logger.info(` Public Inputs: ${r1cs.nPubInputs}`); - logger.info(` Private Inputs: ${r1cs.nPrvInputs}`); - logger.info(` Labels: ${r1cs.nLabels}`); - logger.info(` Constraints: ${r1cs.nConstraints}`); - logger.info(` Custom Gates: ${r1cs.useCustomGates}`); - logger.info("----------------------------"); - } - - if (logger) logger.info("> Checking witness correctness"); - - let bR1csPos = 0; - let res = true; - for (let i = 0; i < r1cs.nConstraints; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(`··· processing r1cs constraints ${i}/${r1cs.nConstraints}`); - } - - //Read the three linear combinations of the constraint where A * B - C = 0 - const lcA = readLC(); - const lcB = readLC(); - const lcC = readLC(); - - // Evaluate the linear combinations - const evalA = EvaluateLinearCombination(lcA); - const evalB = EvaluateLinearCombination(lcB); - const evalC = EvaluateLinearCombination(lcC); - - // Check that A * B - C == 0 - if (!Fr.eq(Fr.sub(Fr.mul(evalA, evalB), evalC), Fr.zero)) { - logger.warn("··· aborting checking process at constraint " + i); - res = false; - break; - } - } - - fdR1cs.close(); - - if (logger) { - if (res) { - logger.info("WITNESS IS CORRECT"); - logger.info("WITNESS CHECKING FINISHED SUCCESSFULLY"); - } else { - logger.warn("WITNESS IS NOT CORRECT"); - logger.warn("WITNESS CHECKING FINISHED UNSUCCESSFULLY"); - } - } - - return res; - - function EvaluateLinearCombination(lc) { - let res = Fr.zero; - - const keys = Object.keys(lc); - keys.forEach((signalId) => { - const signalValue = getWitnessValue(signalId); - const signalFactor = lc[signalId]; - - res = Fr.add(res, Fr.mul(signalValue, signalFactor)); - }); - - return res; - } - - function readLC() { - const lc = {}; - - const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); - bR1csPos += 4; - const buffUL32V = new DataView(buffUL32.buffer); - const nIdx = buffUL32V.getUint32(0, true); - - const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); - bR1csPos += (4 + r1cs.n8) * nIdx; - const buffV = new DataView(buff.buffer); - for (let i = 0; i < nIdx; i++) { - const idx = buffV.getUint32(i * (4 + r1cs.n8), true); - const val = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); - lc[idx] = val; - } - return lc; - } - - function getWitnessValue(signalId) { - return Fr.fromRprLE(buffWitness.slice(signalId * sFr, signalId * sFr + sFr)); - } -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -var wtns = /*#__PURE__*/Object.freeze({ - __proto__: null, - calculate: wtnsCalculate, - check: wtnsCheck, - debug: wtnsDebug, - exportJson: wtnsExportJson +//#endregion +//#region src/plonk_setup.js +async function ur(e, i, c, l) { + globalThis.gc && globalThis.gc(); + let { fd: d, sections: f } = await r(i, "ptau", 1, 1 << 22, 1 << 24), { curve: p, power: m } = await an(d, f), { fd: g, sections: _ } = await r(e, "r1cs", 1, 1 << 22, 1 << 24), v = await h(g, _, { + loadConstraints: !0, + loadCustomGates: !0 + }), y = p.G1.F.n8 * 2, b = p.G1, x = p.G2.F.n8 * 2, S = p.Fr, C = p.Fr.n8; + l && l.info("Reading r1cs"); + let w = new qn(), T = new qn(), E = v.nVars, D = v.nOutputs + v.nPubInputs; + await ee(p.Fr, v, l), globalThis.gc && globalThis.gc(); + let O = await t(c, "zkey", 1, 14, 1 << 22, 1 << 24); + if (v.prime != p.r) return l && l.error("r1cs curve does not match powers of tau ceremony curve"), -1; + let k = Ce(w.length - 1) + 1; + k < 3 && (k = 3); + let A = 2 ** k; + if (l && l.info("Plonk constraints: " + w.length), k > m) return l && l.error(`circuit too big for this power of tau ceremony. ${w.length} > 2**${m}`), -1; + if (!f[12]) return l && l.error("Powers of tau is not prepared."), -1; + let j = new s(A * y), M = f[12][0].p + (2 ** k - 1) * y; + await d.readToBuffer(j, 0, A * y, M); + let [N, P] = H(), F = {}; + await B(3, "Additions"), globalThis.gc && globalThis.gc(), await L(4, 0, "Amap"), globalThis.gc && globalThis.gc(), await L(5, 1, "Bmap"), globalThis.gc && globalThis.gc(), await L(6, 2, "Cmap"), globalThis.gc && globalThis.gc(), await R(7, 3, "Qm"), globalThis.gc && globalThis.gc(), await R(8, 4, "Ql"), globalThis.gc && globalThis.gc(), await R(9, 5, "Qr"), globalThis.gc && globalThis.gc(), await R(10, 6, "Qo"), globalThis.gc && globalThis.gc(), await R(11, 7, "Qc"), globalThis.gc && globalThis.gc(), await te(12, "sigma"), globalThis.gc && globalThis.gc(), await ne(13, "lagrange polynomials"), globalThis.gc && globalThis.gc(), await a(O, 14); + let I = new s((A + 6) * y); + await d.readToBuffer(I, 0, (A + 6) * y, f[2][0].p), await O.write(I), await n(O), globalThis.gc && globalThis.gc(), await V(), await O.close(), await g.close(), await d.close(), l && l.info("Setup Finished"); + return; + async function ee(e, t, n) { + function r(e) { + let t = Object.keys(e); + for (let n = 0; n < t.length; n++) e[t[n]] == 0n && delete e[t[n]]; + } + function i(t, n, i) { + let a = {}; + for (let r in t) a[r] === void 0 ? a[r] = e.mul(n, t[r]) : a[r] = e.add(a[r], e.mul(n, t[r])); + for (let t in i) a[t] === void 0 ? a[t] = i[t] : a[t] = e.add(a[t], i[t]); + return r(a), a; + } + function a(t, n) { + let r = { + k: e.zero, + s: [], + coefs: [] + }, i = []; + for (let n in t) n == 0 ? r.k = e.add(r.k, t[n]) : t[n] != 0n && i.push([Number(n), t[n]]); + for (; i.length > n;) { + let t = i.shift(), n = i.shift(), r = t[0], a = n[0], o = E++, s = e.zero, c = e.neg(t[1]), l = e.neg(n[1]), u = e.one, d = e.zero; + w.push([ + r, + a, + o, + s, + c, + l, + u, + d + ]), T.push([ + r, + a, + t[1], + n[1] + ]), i.push([o, e.one]); + } + for (let e = 0; e < i.length; e++) r.s[e] = i[e][0], r.coefs[e] = i[e][1]; + for (; r.coefs.length < n;) r.s.push(0), r.coefs.push(e.zero); + return r; + } + function o(t) { + let n = a(t, 3), r = n.s[0], i = n.s[1], o = n.s[2], s = e.zero, c = n.coefs[0], l = n.coefs[1], u = n.coefs[2], d = n.k; + w.push([ + r, + i, + o, + s, + c, + l, + u, + d + ]); + } + function s(t, n, r) { + let i = a(t, 1), o = a(n, 1), s = a(r, 1), c = i.s[0], l = o.s[0], u = s.s[0], d = e.mul(i.coefs[0], o.coefs[0]), f = e.mul(i.coefs[0], o.k), p = e.mul(i.k, o.coefs[0]), m = e.neg(s.coefs[0]), h = e.sub(e.mul(i.k, o.k), s.k); + w.push([ + c, + l, + u, + d, + f, + p, + m, + h + ]); + } + function c(t) { + let n = e.zero, r = 0, i = Object.keys(t); + for (let a = 0; a < i.length; a++) t[i[a]] == 0n ? delete t[i[a]] : i[a] == 0 ? n = e.add(n, t[i[a]]) : r++; + return r > 0 ? r.toString() : n == e.zero ? "0" : "k"; + } + function l(e, t, n) { + let a = c(e), l = c(t); + a === "0" || l === "0" ? (r(n), o(n)) : a === "k" ? o(i(t, e[0], n)) : l === "k" ? o(i(e, t[0], n)) : s(e, t, n); + } + for (let t = 1; t <= D; t++) { + let n = t, r = e.zero, i = e.one, a = e.zero, o = e.zero, s = e.zero; + w.push([ + n, + 0, + 0, + r, + i, + a, + o, + s + ]); + } + for (let e = 0; e < t.constraints.length; e++) n && e % 1e4 == 0 && n.debug(`processing constraints: ${e}/${t.nConstraints}`), l(...t.constraints[e]); + } + async function L(e, t, r) { + await a(O, e); + for (let e = 0; e < w.length; e++) await O.writeULE32(w[e][t]), l && e % 1e6 == 0 && l.debug(`writing ${r}: ${e}/${w.length}`); + await n(O); + } + async function R(e, t, r) { + let i = new s(A * C); + for (let e = 0; e < w.length; e++) i.set(w[e][t], e * C), l && e % 1e6 == 0 && l.debug(`writing ${r}: ${e}/${w.length}`); + await a(O, e), await z(i), await n(O), i = await S.batchFromMontgomery(i), F[r] = await p.G1.multiExpAffine(j, i, l, "multiexp " + r); + } + async function z(e) { + let t = await S.ifft(e), n = new s(A * C * 4); + n.set(t, 0); + let r = await S.fft(n); + await O.write(t), await O.write(r); + } + async function B(e, t) { + await a(O, e); + let r = new Uint8Array(8 + 2 * C), i = new DataView(r.buffer); + for (let e = 0; e < T.length; e++) { + let n = T[e], a = 0; + i.setUint32(a, n[0], !0), a += 4, i.setUint32(a, n[1], !0), a += 4, r.set(n[2], a), a += C, r.set(n[3], a), a += C, await O.write(r), l && e % 1e6 == 0 && l.debug(`writing ${t}: ${e}/${T.length}`); + } + await n(O); + } + async function te(e, t) { + let r = new s(C * A * 3), i = new qn(E), o = new qn(E), c = S.one; + for (let e = 0; e < A; e++) e < w.length ? (m(w[e][0], e), m(w[e][1], A + e), m(w[e][2], A * 2 + e)) : (m(0, e), m(0, A + e), m(0, A * 2 + e)), c = S.mul(c, S.w[k]), l && e % 1e6 == 0 && l.debug(`writing ${t} phase1: ${e}/${w.length}`); + for (let e = 0; e < E; e++) o[e] === void 0 ? console.log("Variable not used") : r.set(i[e], o[e] * C), l && e % 1e6 == 0 && l.debug(`writing ${t} phase2: ${e}/${E}`); + globalThis.gc && globalThis.gc(), await a(O, e); + let u = r.slice(0, A * C); + await z(u), globalThis.gc && globalThis.gc(); + let d = r.slice(A * C, A * C * 2); + await z(d), globalThis.gc && globalThis.gc(); + let f = r.slice(A * C * 2, A * C * 3); + await z(f), globalThis.gc && globalThis.gc(), await n(O), u = await S.batchFromMontgomery(u), d = await S.batchFromMontgomery(d), f = await S.batchFromMontgomery(f), F.S1 = await p.G1.multiExpAffine(j, u, l, "multiexp S1"), globalThis.gc && globalThis.gc(), F.S2 = await p.G1.multiExpAffine(j, d, l, "multiexp S2"), globalThis.gc && globalThis.gc(), F.S3 = await p.G1.multiExpAffine(j, f, l, "multiexp S3"), globalThis.gc && globalThis.gc(); + function m(e, t) { + i[e] === void 0 ? o[e] = t : r.set(i[e], t * C); + let n; + n = t < A ? c : t < 2 * A ? S.mul(c, N) : S.mul(c, P), i[e] = n; + } + } + async function ne(e, t) { + await a(O, e); + let r = Math.max(D, 1); + for (let e = 0; e < r; e++) { + let n = new s(A * C); + n.set(S.one, e * C), await z(n), l && l.debug(`writing ${t} ${e}/${r}`); + } + await n(O); + } + async function V() { + await a(O, 1), await O.writeULE32(2), await n(O), await a(O, 2); + let e = p.q, t = (Math.floor((u.bitLength(e) - 1) / 64) + 1) * 8, r = p.r, i = (Math.floor((u.bitLength(r) - 1) / 64) + 1) * 8; + await O.writeULE32(t), await o(O, e, t), await O.writeULE32(i), await o(O, r, i), await O.writeULE32(E), await O.writeULE32(D), await O.writeULE32(A), await O.writeULE32(T.length), await O.writeULE32(w.length), await O.write(N), await O.write(P), await O.write(b.toAffine(F.Qm)), await O.write(b.toAffine(F.Ql)), await O.write(b.toAffine(F.Qr)), await O.write(b.toAffine(F.Qo)), await O.write(b.toAffine(F.Qc)), await O.write(b.toAffine(F.S1)), await O.write(b.toAffine(F.S2)), await O.write(b.toAffine(F.S3)); + let s; + s = await d.read(x, f[3][0].p + x), await O.write(s), await n(O); + } + function H() { + let e = S.two; + for (; n(e, [], k);) S.add(e, S.one); + let t = S.add(e, S.one); + for (; n(t, [e], k);) S.add(t, S.one); + return [e, t]; + function n(e, t, n) { + let r = 2 ** n, i = S.one; + for (let a = 0; a < r; a++) { + if (S.eq(e, i)) return !0; + for (let n = 0; n < t.length; n++) if (S.eq(e, S.mul(t[n], i))) return !0; + i = S.mul(i, S.w[n]); + } + return !1; + } + } +} +//#endregion +//#region src/proof.js +var dr = class { + constructor(e, t) { + this.curve = e, this.logger = t, this.resetProof(); + } + resetProof() { + this.polynomials = {}, this.evaluations = {}; + } + addPolynomial(e, t) { + e in this.polynomials && this.logger.warn(`proof: polynomial.${e} already exist in proof`), this.polynomials[e] = t; + } + getPolynomial(e) { + return e in this.polynomials || this.logger.warn(`proof: polynomial ${e} does not exist in proof`), this.polynomials[e]; + } + addEvaluation(e, t) { + e in this.evaluations && this.logger.warn(`proof: evaluations.${e} already exist in proof`), this.evaluations[e] = t; + } + getEvaluation(e) { + return e in this.evaluations || this.logger.warn(`proof: evaluation ${e} does not exist in proof`), this.evaluations[e]; + } + toObjectProof(e = !0) { + let t = e ? { + polynomials: {}, + evaluations: {} + } : {}; + return Object.keys(this.polynomials).forEach((n) => { + let r = this.curve.G1.toObject(this.polynomials[n]); + e ? t.polynomials[n] = r : t[n] = r; + }), Object.keys(this.evaluations).forEach((n) => { + let r = this.curve.Fr.toObject(this.evaluations[n]); + e ? t.evaluations[n] = r : t[n] = r; + }), t; + } + fromObjectProof(e) { + this.resetProof(), Object.keys(e.polynomials).forEach((t) => { + this.polynomials[t] = this.curve.G1.fromObject(e.polynomials[t]); + }), Object.keys(e.evaluations).forEach((t) => { + this.evaluations[t] = this.curve.Fr.fromObject(e.evaluations[t]); + }); + } +}, fr = BigInt(0), pr = BigInt(1), mr = BigInt(2), hr = BigInt(7), gr = BigInt(256), _r = BigInt(113), vr = [], yr = [], br = []; +for (let e = 0, t = pr, n = 1, r = 0; e < 24; e++) { + [n, r] = [r, (2 * n + 3 * r) % 5], vr.push(2 * (5 * r + n)), yr.push((e + 1) * (e + 2) / 2 % 64); + let i = fr; + for (let e = 0; e < 7; e++) t = (t << pr ^ (t >> hr) * _r) % gr, t & mr && (i ^= pr << (pr << BigInt(e)) - pr); + br.push(i); +} +var xr = V(br, !0), Sr = xr[0], Cr = xr[1], wr = (e, t, n) => n > 32 ? ue(e, t, n) : ce(e, t, n), Tr = (e, t, n) => n > 32 ? de(e, t, n) : le(e, t, n); +function Er(e, t = 24) { + if (O(t, "rounds"), t < 1 || t > 24) throw Error("\"rounds\" expected integer 1..24"); + let n = /* @__PURE__ */ new Uint32Array(10); + for (let r = 24 - t; r < 24; r++) { + for (let t = 0; t < 10; t++) n[t] = e[t] ^ e[t + 10] ^ e[t + 20] ^ e[t + 30] ^ e[t + 40]; + for (let t = 0; t < 10; t += 2) { + let r = (t + 8) % 10, i = (t + 2) % 10, a = n[i], o = n[i + 1], s = wr(a, o, 1) ^ n[r], c = Tr(a, o, 1) ^ n[r + 1]; + for (let n = 0; n < 50; n += 10) e[t + n] ^= s, e[t + n + 1] ^= c; + } + let t = e[2], i = e[3]; + for (let n = 0; n < 24; n++) { + let r = yr[n], a = wr(t, i, r), o = Tr(t, i, r), s = vr[n]; + t = e[s], i = e[s + 1], e[s] = a, e[s + 1] = o; + } + for (let t = 0; t < 50; t += 10) { + let n = e[t], r = e[t + 1], i = e[t + 2], a = e[t + 3]; + e[t] ^= ~e[t + 2] & e[t + 4], e[t + 1] ^= ~e[t + 3] & e[t + 5], e[t + 2] ^= ~e[t + 4] & e[t + 6], e[t + 3] ^= ~e[t + 5] & e[t + 7], e[t + 4] ^= ~e[t + 6] & e[t + 8], e[t + 5] ^= ~e[t + 7] & e[t + 9], e[t + 6] ^= ~e[t + 8] & n, e[t + 7] ^= ~e[t + 9] & r, e[t + 8] ^= ~n & i, e[t + 9] ^= ~r & a; + } + e[0] ^= Sr[r], e[1] ^= Cr[r]; + } + N(n); +} +var Dr = class e { + state; + pos = 0; + posOut = 0; + finished = !1; + state32; + destroyed = !1; + blockLen; + suffix; + outputLen; + canXOF; + enableXOF = !1; + rounds; + constructor(e, t, n, r = !1, i = 24) { + if (this.blockLen = e, this.suffix = t, this.outputLen = n, this.enableXOF = r, this.canXOF = r, this.rounds = i, O(n, "outputLen"), !(0 < e && e < 200)) throw Error("only keccak-f1600 function is supported"); + this.state = /* @__PURE__ */ new Uint8Array(200), this.state32 = M(this.state); + } + clone() { + return this._cloneInto(); + } + keccak() { + L(this.state32), Er(this.state32, this.rounds), L(this.state32), this.posOut = 0, this.pos = 0; + } + update(e) { + A(this), k(e); + let { blockLen: t, state: n } = this, r = e.length; + for (let i = 0; i < r;) { + let a = Math.min(t - this.pos, r - i); + for (let t = 0; t < a; t++) n[this.pos++] ^= e[i++]; + this.pos === t && this.keccak(); + } + return this; + } + finish() { + if (this.finished) return; + this.finished = !0; + let { state: e, suffix: t, pos: n, blockLen: r } = this; + e[n] ^= t, t & 128 && n === r - 1 && this.keccak(), e[r - 1] ^= 128, this.keccak(); + } + writeInto(e) { + A(this, !1), k(e), this.finish(); + let t = this.state, { blockLen: n } = this; + for (let r = 0, i = e.length; r < i;) { + this.posOut >= n && this.keccak(); + let a = Math.min(n - this.posOut, i - r); + e.set(t.subarray(this.posOut, this.posOut + a), r), this.posOut += a, r += a; + } + return e; + } + xofInto(e) { + if (!this.enableXOF) throw Error("XOF is not possible for this instance"); + return this.writeInto(e); + } + xof(e) { + return O(e), this.xofInto(new Uint8Array(e)); + } + digestInto(e) { + if (j(e, this), this.finished) throw Error("digest() was already called"); + this.writeInto(e.subarray(0, this.outputLen)), this.destroy(); + } + digest() { + let e = new Uint8Array(this.outputLen); + return this.digestInto(e), e; + } + destroy() { + this.destroyed = !0, N(this.state); + } + _cloneInto(t) { + let { blockLen: n, suffix: r, outputLen: i, rounds: a, enableXOF: o } = this; + return t ||= new e(n, r, i, o, a), t.blockLen = n, t.state32.set(this.state32), t.pos = this.pos, t.posOut = this.posOut, t.finished = this.finished, t.rounds = a, t.suffix = r, t.outputLen = i, t.enableXOF = o, t.canXOF = this.canXOF, t.destroyed = this.destroyed, t; + } +}, Or = /* @__PURE__ */ ((e, t, n, r = {}) => R(() => new Dr(t, e, n), r))(1, 136, 32), kr = 0, Ar = 1, jr = class { + constructor(e) { + this.G1 = e.G1, this.Fr = e.Fr, this.reset(); + } + reset() { + this.data = []; + } + addPolCommitment(e) { + this.data.push({ + type: kr, + data: e + }); + } + addScalar(e) { + this.data.push({ + type: Ar, + data: e + }); + } + getChallenge() { + if (this.data.length === 0) throw Error("Keccak256Transcript: No data to generate a transcript"); + let e = 0, t = 0; + this.data.forEach((n) => kr === n.type ? e++ : t++); + let n = new Uint8Array(t * this.Fr.n8 + e * this.G1.F.n8 * 2), r = 0; + for (let e = 0; e < this.data.length; e++) kr === this.data[e].type ? (this.G1.toRprUncompressed(n, r, this.data[e].data), r += this.G1.F.n8 * 2) : (this.Fr.toRprBE(n, r, this.data[e].data), r += this.Fr.n8); + let i = u.fromRprBE(Or(n)); + return this.Fr.e(i); + } +}, Mr = class { + static getZ1(e) { + return [ + e.zero, + e.add(e.e(-1), e.w[2]), + e.e(-2), + e.sub(e.e(-1), e.w[2]) + ]; + } + static getZ2(e) { + return [ + e.zero, + e.add(e.zero, e.mul(e.e(-2), e.w[2])), + e.e(4), + e.sub(e.zero, e.mul(e.e(-2), e.w[2])) + ]; + } + static getZ3(e) { + return [ + e.zero, + e.add(e.e(2), e.mul(e.e(2), e.w[2])), + e.e(-8), + e.sub(e.e(2), e.mul(e.e(2), e.w[2])) + ]; + } + static mul2(e, t, n, r, i, a) { + let o = this.getZ1(a), s, c, l = a.mul(e, t), u = a.mul(e, r), d = a.mul(n, t), f = a.mul(n, r); + s = l; + let p = a.add(u, d), m = f; + return c = p, i && (c = a.add(c, a.mul(o[i], m))), [s, c]; + } + static mul3(e, t, n, r, i, a, o, s) { + let c = this.getZ1(s), l = this.getZ2(s), u, d, f = s.mul(e, t), p = s.mul(e, i), m = s.mul(r, t), h = s.mul(r, i); + u = s.mul(f, n); + let g = s.mul(m, n); + g = s.add(g, s.mul(p, n)), g = s.add(g, s.mul(f, a)); + let _ = s.mul(h, n); + if (_ = s.add(_, s.mul(p, a)), _ = s.add(_, s.mul(m, a)), d = g, o) { + let e = s.mul(h, a); + d = s.add(d, s.mul(c[o], _)), d = s.add(d, s.mul(l[o], e)); + } + return [u, d]; + } + static mul4(e, t, n, r, i, a, o, s, c, l) { + let u = this.getZ1(l), d = this.getZ2(l), f = this.getZ3(l), p, m, h = l.mul(e, t), g = l.mul(e, a), _ = l.mul(i, t), v = l.mul(i, a), y = l.mul(n, r), b = l.mul(n, s), x = l.mul(o, r), S = l.mul(o, s); + p = l.mul(h, y); + let C = l.mul(_, y); + C = l.add(C, l.mul(g, y)), C = l.add(C, l.mul(h, x)), C = l.add(C, l.mul(h, b)); + let w = l.mul(v, y); + w = l.add(w, l.mul(_, x)), w = l.add(w, l.mul(_, b)), w = l.add(w, l.mul(g, x)), w = l.add(w, l.mul(g, b)), w = l.add(w, l.mul(h, S)); + let T = l.mul(g, S); + T = l.add(T, l.mul(_, S)), T = l.add(T, l.mul(v, b)), T = l.add(T, l.mul(v, x)); + let E = l.mul(v, S); + return m = C, c && (m = l.add(m, l.mul(u[c], w)), m = l.add(m, l.mul(d[c], T)), m = l.add(m, l.mul(f[c], E))), [p, m]; + } +}, Y = class e { + constructor(e, t, n) { + this.coef = e, this.curve = t, this.Fr = t.Fr, this.G1 = t.G1, this.logger = n; + } + static async fromEvaluations(t, n, r) { + return new e(await n.Fr.ifft(t), n, r); + } + static fromCoefficientsArray(t, n, r) { + let i = n.Fr, a = t.length > 32768 ? new s(t.length * i.n8) : new Uint8Array(t.length * i.n8); + for (let e = 0; e < t.length; e++) a.set(t[e], e * i.n8); + return new e(a, n, r); + } + static fromPolynomial(t, n, r) { + let i = t.length(), a = n.Fr, o = i > 32768 ? new s(i * a.n8) : new Uint8Array(i * a.n8); + return o.set(t.coef.slice(), 0), new e(o, n, r); + } + isEqual(e) { + let t = this.degree(); + if (t !== e.degree()) return !1; + for (let n = 0; n < t + 1; n++) if (!this.Fr.eq(this.getCoef(n), e.getCoef(n))) return !1; + return !0; + } + blindCoefficients(e) { + e ||= []; + let t = this.length() + e.length > 32768 ? new s((this.length() + e.length) * this.Fr.n8) : new Uint8Array((this.length() + e.length) * this.Fr.n8); + t.set(this.coef, 0); + for (let n = 0; n < e.length; n++) t.set(this.Fr.add(t.slice((this.length() + n) * this.Fr.n8, (this.length() + n + 1) * this.Fr.n8), e[n]), (this.length() + n) * this.Fr.n8), t.set(this.Fr.sub(t.slice(n * this.Fr.n8, (n + 1) * this.Fr.n8), e[n]), n * this.Fr.n8); + this.coef = t; + } + getCoef(e) { + let t = e * this.Fr.n8; + return t + this.Fr.n8 > this.coef.byteLength ? this.Fr.zero : this.coef.slice(t, t + this.Fr.n8); + } + setCoef(e, t) { + if (e > this.length() - 1) throw Error("Coef index is not available"); + this.coef.set(t, e * this.Fr.n8); + } + static async to4T(e, t, n, r) { + n ||= []; + let i = await r.ifft(e), a = t * 4 > 32768 ? new s(t * 4 * r.n8) : new Uint8Array(t * 4 * r.n8); + a.set(i, 0); + let o = await r.fft(a); + if (n.length === 0) return [i, o]; + let c = t + n.length > 32768 ? new s((t + n.length) * r.n8) : new Uint8Array((t + n.length) * r.n8); + c.set(i, 0); + for (let e = 0; e < n.length; e++) c.set(r.add(c.slice((t + e) * r.n8, (t + e + 1) * r.n8), n[e]), (t + e) * r.n8), c.set(r.sub(c.slice(e * r.n8, (e + 1) * r.n8), n[e]), e * r.n8); + return [c, o]; + } + length() { + let e = this.coef.byteLength / this.Fr.n8; + if (e !== Math.floor(this.coef.byteLength / this.Fr.n8)) throw Error("Polynomial coefficients buffer has incorrect size"); + return e === 0 && this.logger && this.logger.warn("Polynomial has length zero"), e; + } + degree() { + for (let e = this.length() - 1; e > 0; e--) { + let t = e * this.Fr.n8; + if (!this.Fr.eq(this.Fr.zero, this.coef.slice(t, t + this.Fr.n8))) return e; + } + return 0; + } + evaluate(e) { + let t = this.Fr.zero; + for (let n = this.degree() + 1; n > 0; n--) { + let r = n * this.Fr.n8, i = this.coef.slice(r - this.Fr.n8, r); + t = this.Fr.add(i, this.Fr.mul(t, e)); + } + return t; + } + fastEvaluate(e) { + let t = this.Fr, n = this.degree() + 1, r = parseInt(n / 3), i = n - r * 3, a = [], o = []; + o[0] = t.one; + for (let n = 0; n < 3; n++) { + a[n] = t.zero; + let s = n === 2 ? r + i : r; + for (let i = s; i > 0; i--) a[n] = t.add(this.getCoef(n * r + i - 1), t.mul(a[n], e)), n === 0 && (o[0] = t.mul(o[0], e)); + } + for (let e = 1; e < 3; e++) a[0] = t.add(a[0], t.mul(o[e - 1], a[e])), o[e] = t.mul(o[e - 1], o[0]); + return a[0]; + } + add(e, t) { + let n = !1; + e.length() > this.length() && (n = !0); + let r = this.length(), i = e.length(); + for (let a = 0; a < Math.max(r, i); a++) { + let o = a * this.Fr.n8, s = a < r ? this.coef.slice(o, o + this.Fr.n8) : this.Fr.zero, c = a < i ? e.coef.slice(o, o + this.Fr.n8) : this.Fr.zero; + t !== void 0 && (c = this.Fr.mul(c, t)), n ? e.coef.set(this.Fr.add(s, c), o) : this.coef.set(this.Fr.add(s, c), o); + } + n && (delete this.coef, this.coef = e.coef); + } + sub(e, t) { + let n = !1; + e.length() > this.length() && (n = !0); + let r = this.length(), i = e.length(); + for (let a = 0; a < Math.max(r, i); a++) { + let o = a * this.Fr.n8, s = a < r ? this.coef.slice(o, o + this.Fr.n8) : this.Fr.zero, c = a < i ? e.coef.slice(o, o + this.Fr.n8) : this.Fr.zero; + t !== void 0 && (c = this.Fr.mul(c, t)), n ? e.coef.set(this.Fr.sub(s, c), o) : this.coef.set(this.Fr.sub(s, c), o); + } + n && (delete this.coef, this.coef = e.coef); + } + mulScalar(e) { + for (let t = 0; t < this.length(); t++) { + let n = t * this.Fr.n8; + this.coef.set(this.Fr.mul(this.coef.slice(n, n + this.Fr.n8), e), n); + } + } + addScalar(e) { + let t = this.length() === 0 ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); + this.coef.set(this.Fr.add(t, e), 0); + } + subScalar(e) { + let t = this.length() === 0 ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); + this.coef.set(this.Fr.sub(t, e), 0); + } + byXSubValue(t) { + let n = this.Fr, r = n.eq(n.zero, this.getCoef(this.length() - 1)) ? this.length() : this.length() + 1, i = new e(r > 32768 ? new s(r * n.n8) : new Uint8Array(r * n.n8), this.curve, this.logger); + i.coef.set(this.coef.slice(0, (r - 1) * n.n8), 32), this.mulScalar(n.neg(t)), i.add(this), this.coef = i.coef; + } + byXNSubValue(t, n) { + let r = this.Fr, i = this.length() - t - 1 >= this.degree() ? this.length() : this.length() + t, a = new e(i > 32768 ? new s(i * r.n8) : new Uint8Array(i * r.n8), this.curve, this.logger); + a.coef.set(this.coef.slice(0, (this.degree() + 1) * 32), t * 32), this.mulScalar(n), a.add(this), this.coef = a.coef; + } + divBy(t) { + let n = this.Fr, r = this.degree(), i = t.degree(), a = new e(this.coef, this.curve, this.logger); + this.coef = this.length() > 32768 ? new s(this.length() * n.n8) : new Uint8Array(this.length() * n.n8); + for (let e = r - i; e >= 0; e--) { + this.setCoef(e, n.div(a.getCoef(e + i), t.getCoef(i))); + for (let r = 0; r <= i; r++) a.setCoef(e + r, n.sub(a.getCoef(e + r), n.mul(this.getCoef(e), t.getCoef(r)))); + } + return a; + } + divByMonic(t, n) { + let r = this.Fr, i = this.degree(), a = new e(this.length() > 32768 ? new s(this.length() * r.n8) : new Uint8Array(this.length() * r.n8), this.curve, this.logger), o = []; + for (let e = 0; e < t; e++) a.setCoef(i - e - t, this.getCoef(i - e)), o[e] = this.getCoef(i - e); + let c = t, l = 0; + for (let e = 0; e < c; e++) for (let s = i - 2 * t - e; s >= 0 && !(s < 0); s -= c) { + let i = e; + o[i] = r.add(this.getCoef(s + t), r.mul(o[i], n)), a.setCoef(s, o[i]), l = (l + 1) % t; + } + this.coef = a.coef; + } + divByVanishing(t, n) { + if (this.degree() < t) throw Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); + let r = this.Fr, i = new e(this.coef, this.curve, this.logger); + this.coef = this.length() > 32768 ? new s(this.length() * r.n8) : new Uint8Array(this.length() * r.n8); + for (let e = this.length() - 1; e >= t; e--) { + let a = i.getCoef(e); + r.eq(r.zero, a) || (i.setCoef(e, r.zero), i.setCoef(e - t, r.add(i.getCoef(e - t), r.mul(n, a))), this.setCoef(e - t, r.add(this.getCoef(e - t), a))); + } + return i; + } + divByVanishing2(t, n) { + if (this.degree() < t) throw Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); + let r = this.Fr, i = new e(this.coef, this.curve, this.logger); + this.coef = this.length() > 32768 ? new s(this.length() * r.n8) : new Uint8Array(this.length() * r.n8); + let a = this.length() - t, o = Math.floor(a / 3), c = a - 2 * o; + console.log(a), console.log(o + " " + c); + for (let e = 0; e < 3; e++) { + console.log("> Thread " + e); + for (let a = e === 0 ? c : o; a > 0; a--) { + let s = a - 1; + e !== 0 && (s += (e - 1) * o + c); + let l = s + t, u = i.getCoef(l); + r.eq(r.zero, u) || (i.setCoef(l, r.zero), i.setCoef(s, r.add(i.getCoef(s), r.mul(n, u))), this.setCoef(s, r.add(this.getCoef(s), u)), console.log(s + " <-- " + l)); + } + } + return this.print(), i; + } + fastDivByVanishing(t) { + let n = this.Fr; + for (let r = 0; r < t.length; r++) { + let i = t[r][0], a = t[r][1]; + if (this.degree() < i) throw Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); + let o = this.length() - i, c = Math.floor(o / 5 / i), l = c * i, u = o - 5 * l, d = new e(this.length() > 32768 ? new s(this.length() * n.n8) : new Uint8Array(this.length() * n.n8), this.curve, this.logger), f = this.coef; + this.coef = d.coef, d.coef = f; + for (let e = 0; e < 5; e++) { + let t = (e + 1) * l + u; + for (let e = 0; e < i; e++) this.setCoef(t + e - i, d.getCoef(t + e)); + for (let e = 0; e < l - i; e++) { + let r = t - e - 1, o = n.add(d.getCoef(r), n.mul(a, this.getCoef(r))); + this.setCoef(r - i, o); + } + } + let p = u, m = u; + for (let e = 0; e < i && m; e++) this.setCoef(p - e - 1, d.getCoef(p + i - e - 1)), m--; + for (let e = 0; e < m; e++) { + let t = p - e - 1, r = n.add(d.getCoef(t), n.mul(a, this.getCoef(t))); + this.setCoef(t - i, r); + } + let h = [], g = n.one; + for (let e = 0; e < c; e++) g = n.mul(g, a); + let _ = n.one; + for (let e = 5; e > 0; e--) { + let t = e - 1, r = t * l + u; + h[t] = []; + for (let a = 0; a < i; a++) h[t][a] = this.getCoef(r + a), e !== 5 && (h[t][a] = n.add(h[t][a], n.mul(g, h[t + 1][a]))); + _ = n.mul(_, g); + } + for (let e = 0; e < 5; e++) { + let t = e * l + u, r = a, o = i - 1, s = e === 0 ? u : l; + for (let c = 0; c < s; c++) { + let s = t - c - 1, l = n.add(this.getCoef(s), n.mul(r, h[e][o])); + this.setCoef(s, l), o === 0 ? (o = i - 1, r = n.mul(r, a)) : o--; + } + } + } + } + divByXSubValue(e) { + let t = this.length() > 32768 ? new s(this.length() * this.Fr.n8) : new Uint8Array(this.length() * this.Fr.n8); + t.set(this.Fr.zero, (this.length() - 1) * this.Fr.n8), t.set(this.coef.slice((this.length() - 1) * this.Fr.n8, this.length() * this.Fr.n8), (this.length() - 2) * this.Fr.n8); + for (let n = this.length() - 3; n >= 0; n--) { + let r = n * this.Fr.n8; + t.set(this.Fr.add(this.coef.slice(r + this.Fr.n8, r + 2 * this.Fr.n8), this.Fr.mul(e, t.slice(r + this.Fr.n8, r + 2 * this.Fr.n8))), n * this.Fr.n8); + } + if (!this.Fr.eq(this.coef.slice(0, this.Fr.n8), this.Fr.mul(this.Fr.neg(e), t.slice(0, this.Fr.n8)))) throw Error("Polynomial does not divide"); + this.coef = t; + } + divZh(e, t = 4) { + for (let t = 0; t < e; t++) { + let e = t * this.Fr.n8; + this.coef.set(this.Fr.neg(this.coef.slice(e, e + this.Fr.n8)), e); + } + let n = this.coef.byteLength / this.Fr.n8; + for (let r = e; r < n; r++) { + let n = r * this.Fr.n8, i = this.Fr.sub(this.coef.slice((r - e) * this.Fr.n8, (r - e) * this.Fr.n8 + this.Fr.n8), this.coef.slice(n, n + this.Fr.n8)); + if (this.coef.set(i, n), r > e * (t - 1) - t && !this.Fr.isZero(i)) throw Error("Polynomial is not divisible"); + } + return this; + } + divByZerofier(e, t) { + let n = this.Fr, r = n.inv(t), i = n.neg(r), a = n.eq(n.one, i), o = n.eq(n.negone, i); + if (!a) for (let t = 0; t < e; t++) { + let e = t * this.Fr.n8, r; + r = o ? n.neg(this.coef.slice(e, e + this.Fr.n8)) : n.mul(i, this.coef.slice(e, e + this.Fr.n8)), this.coef.set(r, e); + } + a = n.eq(n.one, r), o = n.eq(n.negone, r); + for (let t = e; t < this.length(); t++) { + let i = t * this.Fr.n8, s = (t - e) * this.Fr.n8, c = this.Fr.sub(this.coef.slice(s, s + this.Fr.n8), this.coef.slice(i, i + this.Fr.n8)); + if (a || (c = o ? n.neg(c) : n.mul(r, c)), this.coef.set(c, i), t > this.length() - e - 1 && !this.Fr.isZero(c)) throw Error("Polynomial is not divisible"); + } + return this; + } + byX() { + let e = this.length() + 1 > 32768 ? new s(this.coef.byteLength + this.Fr.n8) : new Uint8Array(this.coef.byteLength + this.Fr.n8); + e.set(this.Fr.zero, 0), e.set(this.coef, this.Fr.n8), this.coef = e; + } + static async expX(t, n, r = !1) { + let i = t.Fr; + if (n < 1) throw Error("Compute a new polynomial to a zero or negative number is not allowed"); + if (n === 1) return await e.fromEvaluations(t.coef, t.curve, t.logger); + let a = r ? t.degree() : t.length() - 1, o = a * n + 1 > 32768 ? new s((a * n + 1) * i.n8) : new Uint8Array((a * n + 1) * i.n8); + o.set(t.getCoef(0), 0); + for (let e = 1; e <= a; e++) { + let r = e * i.n8, a = t.getCoef(e); + o.set(a, r * n); + } + return new e(o, t.curve, t.logger); + } + split(t, n, r) { + if (t < 1) throw Error(`Polynomials can't be split in ${t} parts`); + if (t === 1) return [this]; + if (r.length !== 0 && r.length < t - 1) throw Error(`Blinding factors length must be ${t - 1}`); + let i = (n + 1) * this.Fr.n8, a = [], o = Math.ceil((this.degree() + 1) * this.Fr.n8 / i); + if (o < t) for (let n = o; n < t; n++) a[n] = new e(new Uint8Array(this.Fr.n8), this.curve, this.logger); + t = Math.min(t, o); + for (let n = 0; n < t; n++) { + let o = t - 1 === n, c = o ? this.coef.byteLength - (t - 1) * i : i + this.Fr.n8; + a[n] = new e(c / this.Fr.n8 > 32768 ? new s(c) : new Uint8Array(c), this.curve, this.logger); + let l = n * i, u = o ? this.coef.byteLength : (n + 1) * i; + if (a[n].coef.set(this.coef.slice(l, u), 0), o || a[n].coef.set(r[n], i), n !== 0) { + let e = this.Fr.sub(a[n].coef.slice(0, this.Fr.n8), r[n - 1]); + a[n].coef.set(e, 0); + } + o && a[n].truncate(); + } + return a; + } + truncate() { + let e = this.degree(); + if (e + 1 < this.coef.byteLength / this.Fr.n8) { + let t = e + 1 > 32768 ? new s((e + 1) * this.Fr.n8) : new Uint8Array((e + 1) * this.Fr.n8); + t.set(this.coef.slice(0, (e + 1) * this.Fr.n8), 0), this.coef = t; + } + } + static lagrangePolynomialInterpolation(t, n, r) { + let i = r.Fr, a = o(0); + for (let e = 1; e < t.length; e++) a.add(o(e)); + return a; + function o(a) { + let o; + for (let n = 0; n < t.length; n++) n !== a && (o === void 0 ? (o = new e(t.length > 32768 ? new s(t.length * i.n8) : new Uint8Array(t.length * i.n8), r), o.setCoef(0, i.neg(t[n])), o.setCoef(1, i.one)) : o.byXSubValue(t[n])); + let c = o.evaluate(t[a]); + c = i.inv(c); + let l = i.mul(n[a], c); + return o.mulScalar(l), o; + } + } + static zerofierPolynomial(t, n) { + let r = n.Fr, i = new e(t.length + 1 > 32768 ? new s((t.length + 1) * r.n8) : new Uint8Array((t.length + 1) * r.n8), n); + i.setCoef(0, r.neg(t[0])), i.setCoef(1, r.one); + for (let e = 1; e < t.length; e++) i.byXSubValue(t[e]); + return i; + } + print() { + let e = this.Fr, t = ""; + for (let n = this.degree(); n >= 0; n--) { + let r = this.getCoef(n); + e.eq(e.zero, r) || (e.isNegative(r) ? t += " - " : n !== this.degree() && (t += " + "), t += e.toString(r), n > 0 && (t += n > 1 ? "x^" + n : "x")); + } + console.log(t); + } + async multiExponentiation(e, t) { + let n = this.coef.byteLength / this.Fr.n8, r = e.slice(0, n * this.G1.F.n8 * 2), i = await this.Fr.batchFromMontgomery(this.coef), a = await this.G1.multiExpAffine(r, i, this.logger, t); + return a = this.G1.toAffine(a), a; + } +}, X = class e { + constructor(e, t, n) { + this.eval = e, this.curve = t, this.Fr = t.Fr, this.logger = n; + } + static async fromPolynomial(t, n, r, i) { + let a = new s(t.length() * n * r.Fr.n8); + return a.set(t.coef, 0), new e(await r.Fr.fft(a), r, i); + } + getEvaluation(e) { + let t = e * this.Fr.n8; + if (t + this.Fr.n8 > this.eval.byteLength) throw Error("Evaluations.getEvaluation() out of bounds"); + return this.eval.slice(t, t + this.Fr.n8); + } + length() { + let e = this.eval.byteLength / this.Fr.n8; + if (e !== Math.floor(this.eval.byteLength / this.Fr.n8)) throw Error("Polynomial evaluations buffer has incorrect size"); + return e === 0 && this.logger.warn("Polynomial has length zero"), e; + } +}, { stringifyBigInts: Nr } = p; +async function Pr(t, n, r, i) { + let { fd: a, sections: o } = await e.readBinFile(n, "wtns", 2, 1 << 25, 1 << 23); + r && r.debug("> Reading witness file"); + let c = await nt(a, o); + r && r.debug("> Reading zkey file"); + let { fd: l, sections: d } = await e.readBinFile(t, "zkey", 2, 1 << 25, 1 << 23), f = await He(l, d, void 0, i); + if (f.protocol != "plonk") throw Error("zkey file is not plonk"); + if (!u.eq(f.r, c.q)) throw Error("Curve of the witness does not match the curve of the proving key"); + if (c.nWitness != f.nVars - f.nAdditions) throw Error(`Invalid witness length. Circuit: ${f.nVars}, witness: ${c.nWitness}, ${f.nAdditions}`); + let p = f.curve, m = p.Fr, h = p.Fr.n8, g = f.domainSize * h; + r && (r.debug("----------------------------"), r.debug(" PLONK PROVE SETTINGS"), r.debug(` Curve: ${p.name}`), r.debug(` Circuit power: ${f.power}`), r.debug(` Domain size: ${f.domainSize}`), r.debug(` Vars: ${f.nVars}`), r.debug(` Public vars: ${f.nPublic}`), r.debug(` Constraints: ${f.nConstraints}`), r.debug(` Additions: ${f.nAdditions}`), r.debug("----------------------------")), r && r.debug("> Reading witness file data"); + let _ = await e.readSection(a, o, 2); + _.set(m.zero, 0); + let v = new s(h * f.nAdditions), y = {}, b = {}, x = {}, S = {}, C = new dr(p, r), w = new jr(p); + r && r.debug("> Reading Section 3. Additions"), await O(), r && r.debug("> Reading Section 12. Sigma1, Sigma2 & Sigma 3"), r && r.debug("··· Reading Sigma polynomials "), b.Sigma1 = new Y(new s(g), p, r), b.Sigma2 = new Y(new s(g), p, r), b.Sigma3 = new Y(new s(g), p, r), await l.readToBuffer(b.Sigma1.coef, 0, g, d[12][0].p), await l.readToBuffer(b.Sigma2.coef, 0, g, d[12][0].p + 5 * g), await l.readToBuffer(b.Sigma3.coef, 0, g, d[12][0].p + 10 * g), r && r.debug("··· Reading Sigma evaluations"), x.Sigma1 = new X(new s(g * 4), p, r), x.Sigma2 = new X(new s(g * 4), p, r), x.Sigma3 = new X(new s(g * 4), p, r), await l.readToBuffer(x.Sigma1.eval, 0, g * 4, d[12][0].p + g), await l.readToBuffer(x.Sigma2.eval, 0, g * 4, d[12][0].p + 6 * g), await l.readToBuffer(x.Sigma3.eval, 0, g * 4, d[12][0].p + 11 * g), r && r.debug("> Reading Section 14. Powers of Tau"); + let T = await e.readSection(l, d, 14), E = []; + for (let e = 1; e <= f.nPublic; e++) { + let t = _.slice(e * m.n8, e * m.n8 + m.n8); + E.push(u.fromRprLE(t)); + } + r && r.debug(""), r && r.debug("> ROUND 1"), await j(), r && r.debug("> ROUND 2"), await N(), r && r.debug("> ROUND 3"), await F(), r && r.debug("> ROUND 4"), await ee(), r && r.debug("> ROUND 5"), await L(), await l.close(), await a.close(); + let D = C.toObjectProof(!1); + return D.protocol = "plonk", D.curve = p.name, r && r.debug("PLONK PROVER FINISHED"), { + proof: Nr(D), + publicSignals: Nr(E) + }; + async function O() { + r && r.debug("··· Computing additions"); + let t = await e.readSection(l, d, 3), n = 8 + h * 2; + for (let e = 0; e < f.nAdditions; e++) { + r && e !== 0 && e % 1e5 == 0 && r.debug(` addition ${e}/${f.nAdditions}`); + let i = e * n, a = k(t, i); + i += 4; + let o = k(t, i); + i += 4; + let s = t.slice(i, i + h); + i += h; + let c = t.slice(i, i + h), l = A(a), u = A(o), d = m.add(m.mul(s, l), m.mul(c, u)); + v.set(d, h * e); + } + } + function k(e, t) { + let n = e.slice(t, t + 4); + return new DataView(n.buffer, n.byteOffset, n.byteLength).getUint32(0, !0); + } + function A(e) { + return e < f.nVars - f.nAdditions ? _.slice(e * h, e * h + h) : e < f.nVars ? v.slice((e - (f.nVars - f.nAdditions)) * h, (e - (f.nVars - f.nAdditions)) * h + h) : p.Fr.zero; + } + async function j() { + S.b = []; + for (let e = 1; e <= 11; e++) S.b[e] = p.Fr.random(); + r && r.debug("> Computing A, B, C wire polynomials"), await M(), r && r.debug("> Computing A, B, C MSM"); + let e = await b.A.multiExponentiation(T, "A"), t = await b.B.multiExponentiation(T, "B"), n = await b.C.multiExponentiation(T, "C"); + return C.addPolynomial("A", e), C.addPolynomial("B", t), C.addPolynomial("C", n), 0; + } + async function M() { + r && r.debug("··· Reading data from zkey file"), y.A = new s(g), y.B = new s(g), y.C = new s(g); + let t = await e.readSection(l, d, 4), n = await e.readSection(l, d, 5), i = await e.readSection(l, d, 6); + for (let e = 0; e < f.nConstraints; e++) { + let r = e * h, a = e * 4, o = k(t, a); + y.A.set(A(o), r); + let s = k(n, a); + y.B.set(A(s), r); + let c = k(i, a); + y.C.set(A(c), r); + } + if (y.A = await m.batchToMontgomery(y.A), y.B = await m.batchToMontgomery(y.B), y.C = await m.batchToMontgomery(y.C), r && r.debug("··· Computing A ifft"), b.A = await Y.fromEvaluations(y.A, p, r), r && r.debug("··· Computing B ifft"), b.B = await Y.fromEvaluations(y.B, p, r), r && r.debug("··· Computing C ifft"), b.C = await Y.fromEvaluations(y.C, p, r), r && r.debug("··· Computing A fft"), x.A = await X.fromPolynomial(b.A, 4, p, r), r && r.debug("··· Computing B fft"), x.B = await X.fromPolynomial(b.B, 4, p, r), r && r.debug("··· Computing C fft"), x.C = await X.fromPolynomial(b.C, 4, p, r), b.A.blindCoefficients([S.b[2], S.b[1]]), b.B.blindCoefficients([S.b[4], S.b[3]]), b.C.blindCoefficients([S.b[6], S.b[5]]), b.A.degree() >= f.domainSize + 2) throw Error("A Polynomial is not well calculated"); + if (b.B.degree() >= f.domainSize + 2) throw Error("B Polynomial is not well calculated"); + if (b.C.degree() >= f.domainSize + 2) throw Error("C Polynomial is not well calculated"); + } + async function N() { + r && r.debug("> Computing challenges beta and gamma"), w.reset(), w.addPolCommitment(f.Qm), w.addPolCommitment(f.Ql), w.addPolCommitment(f.Qr), w.addPolCommitment(f.Qo), w.addPolCommitment(f.Qc), w.addPolCommitment(f.S1), w.addPolCommitment(f.S2), w.addPolCommitment(f.S3); + for (let e = 0; e < f.nPublic; e++) w.addScalar(y.A.slice(e * h, e * h + h)); + w.addPolCommitment(C.getPolynomial("A")), w.addPolCommitment(C.getPolynomial("B")), w.addPolCommitment(C.getPolynomial("C")), S.beta = w.getChallenge(), r && r.debug("··· challenges.beta: " + m.toString(S.beta, 16)), w.reset(), w.addScalar(S.beta), S.gamma = w.getChallenge(), r && r.debug("··· challenges.gamma: " + m.toString(S.gamma, 16)), r && r.debug("> Computing Z polynomial"), await P(), r && r.debug("> Computing Z MSM"); + let e = await b.Z.multiExponentiation(T, "Z"); + C.addPolynomial("Z", e); + } + async function P() { + r && r.debug("··· Computing Z evaluations"); + let e = new s(g), t = new s(g); + e.set(m.one, 0), t.set(m.one, 0); + let n = m.one; + for (let r = 0; r < f.domainSize; r++) { + let i = r * h, a = y.A.slice(i, i + h), o = y.B.slice(i, i + h), s = y.C.slice(i, i + h), c = m.mul(S.beta, n), l = m.add(a, c); + l = m.add(l, S.gamma); + let u = m.add(o, m.mul(f.k1, c)); + u = m.add(u, S.gamma); + let d = m.add(s, m.mul(f.k2, c)); + d = m.add(d, S.gamma); + let p = m.mul(l, m.mul(u, d)), g = m.add(a, m.mul(x.Sigma1.getEvaluation(r * 4), S.beta)); + g = m.add(g, S.gamma); + let _ = m.add(o, m.mul(x.Sigma2.getEvaluation(r * 4), S.beta)); + _ = m.add(_, S.gamma); + let v = m.add(s, m.mul(x.Sigma3.getEvaluation(r * 4), S.beta)); + v = m.add(v, S.gamma); + let b = m.mul(g, m.mul(_, v)); + p = m.mul(e.slice(i, i + h), p), e.set(p, (r + 1) % f.domainSize * h), b = m.mul(t.slice(i, i + h), b), t.set(b, (r + 1) % f.domainSize * h), n = m.mul(n, m.w[f.power]); + } + t = await m.batchInverse(t); + for (let n = 0; n < f.domainSize; n++) { + let r = n * h, i = m.mul(e.slice(r, r + h), t.slice(r, r + h)); + e.set(i, r); + } + if (y.Z = e, !m.eq(e.slice(0, h), m.one)) throw Error("Copy constraints does not match"); + if (r && r.debug("··· Computing Z ifft"), b.Z = await Y.fromEvaluations(y.Z, p, r), r && r.debug("··· Computing Z fft"), x.Z = await X.fromPolynomial(b.Z, 4, p, r), b.Z.blindCoefficients([ + S.b[9], + S.b[8], + S.b[7] + ]), b.Z.degree() >= f.domainSize + 3) throw Error("Z Polynomial is not well calculated"); + delete y.Z; + } + async function F() { + r && r.debug("> Computing challenge alpha"), w.reset(), w.addScalar(S.beta), w.addScalar(S.gamma), w.addPolCommitment(C.getPolynomial("Z")), S.alpha = w.getChallenge(), S.alpha2 = m.square(S.alpha), r && r.debug("··· challenges.alpha: " + m.toString(S.alpha, 16)), r && r.debug("> Computing T polynomial"), await I(), r && r.debug("> Computing T MSM"); + let e = await b.T1.multiExponentiation(T, "T1"), t = await b.T2.multiExponentiation(T, "T2"), n = await b.T3.multiExponentiation(T, "T3"); + C.addPolynomial("T1", e), C.addPolynomial("T2", t), C.addPolynomial("T3", n); + } + async function I() { + r && r.debug("··· Reading sections 8, 9, 7, 10, 11. Q selectors"), x.QL = new X(new s(g * 4), p, r), x.QR = new X(new s(g * 4), p, r), x.QM = new X(new s(g * 4), p, r), x.QO = new X(new s(g * 4), p, r), x.QC = new X(new s(g * 4), p, r), await l.readToBuffer(x.QL.eval, 0, g * 4, d[8][0].p + g), await l.readToBuffer(x.QR.eval, 0, g * 4, d[9][0].p + g), await l.readToBuffer(x.QM.eval, 0, g * 4, d[7][0].p + g), await l.readToBuffer(x.QO.eval, 0, g * 4, d[10][0].p + g), await l.readToBuffer(x.QC.eval, 0, g * 4, d[11][0].p + g), x.Lagrange = new X(new s(g * 4 * f.nPublic), p, r); + for (let e = 0; e < f.nPublic; e++) await l.readToBuffer(x.Lagrange.eval, e * g * 4, g * 4, d[13][0].p + e * 5 * g + g); + y.T = new s(g * 4), y.Tz = new s(g * 4), r && r.debug("··· Computing T evaluations"); + let e = m.one; + for (let t = 0; t < f.domainSize * 4; t++) { + r && t !== 0 && t % 1e5 == 0 && r.debug(` T evaluation ${t}/${f.domainSize * 4}`); + let n = x.A.getEvaluation(t), i = x.B.getEvaluation(t), a = x.C.getEvaluation(t), o = x.Z.getEvaluation(t), s = x.Z.getEvaluation((f.domainSize * 4 + 4 + t) % (f.domainSize * 4)), c = x.QM.getEvaluation(t), l = x.QL.getEvaluation(t), u = x.QR.getEvaluation(t), d = x.QO.getEvaluation(t), p = x.QC.getEvaluation(t), g = x.Sigma1.getEvaluation(t), _ = x.Sigma2.getEvaluation(t), v = x.Sigma3.getEvaluation(t), b = m.add(S.b[2], m.mul(S.b[1], e)), C = m.add(S.b[4], m.mul(S.b[3], e)), w = m.add(S.b[6], m.mul(S.b[5], e)), T = m.square(e), E = m.add(m.add(m.mul(S.b[7], T), m.mul(S.b[8], e)), S.b[9]), D = m.mul(e, m.w[f.power]), O = m.square(D), k = m.add(m.add(m.mul(S.b[7], O), m.mul(S.b[8], D)), S.b[9]), A = m.zero; + for (let e = 0; e < f.nPublic; e++) { + let n = e * 4 * f.domainSize + t, r = x.Lagrange.getEvaluation(n), i = y.A.slice(e * h, (e + 1) * h); + A = m.sub(A, m.mul(r, i)); + } + let [j, M] = Mr.mul2(n, i, b, C, t % 4, m); + j = m.mul(j, c), M = m.mul(M, c), j = m.add(j, m.mul(n, l)), M = m.add(M, m.mul(b, l)), j = m.add(j, m.mul(i, u)), M = m.add(M, m.mul(C, u)), j = m.add(j, m.mul(a, d)), M = m.add(M, m.mul(w, d)), j = m.add(j, A), j = m.add(j, p); + let N = m.mul(S.beta, e), P = n; + P = m.add(P, N), P = m.add(P, S.gamma); + let F = i; + F = m.add(F, m.mul(N, f.k1)), F = m.add(F, S.gamma); + let I = a; + I = m.add(I, m.mul(N, f.k2)), I = m.add(I, S.gamma); + let ee = o, [L, R] = Mr.mul4(P, F, I, ee, b, C, w, E, t % 4, m); + L = m.mul(L, S.alpha), R = m.mul(R, S.alpha); + let z = n; + z = m.add(z, m.mul(S.beta, g)), z = m.add(z, S.gamma); + let B = i; + B = m.add(B, m.mul(S.beta, _)), B = m.add(B, S.gamma); + let te = a; + te = m.add(te, m.mul(S.beta, v)), te = m.add(te, S.gamma); + let ne = s, [V, H] = Mr.mul4(z, B, te, ne, b, C, w, k, t % 4, m); + V = m.mul(V, S.alpha), H = m.mul(H, S.alpha); + let re = m.sub(o, m.one); + re = m.mul(re, x.Lagrange.getEvaluation(t)), re = m.mul(re, S.alpha2); + let ie = m.mul(E, x.Lagrange.getEvaluation(t)); + ie = m.mul(ie, S.alpha2); + let ae = m.add(m.sub(m.add(j, L), V), re), oe = m.add(m.sub(m.add(M, R), H), ie); + y.T.set(ae, t * h), y.Tz.set(oe, t * h), e = m.mul(e, m.w[f.power + 2]); + } + if (r && r.debug("··· Computing T ifft"), b.T = await Y.fromEvaluations(y.T, p, r), r && r.debug("··· Computing T / ZH"), b.T.divZh(f.domainSize, 4), r && r.debug("··· Computing Tz ifft"), b.Tz = await Y.fromEvaluations(y.Tz, p, r), b.T.add(b.Tz), b.T.degree() >= f.domainSize * 3 + 6) throw Error("T Polynomial is not well calculated"); + r && r.debug("··· Computing T1, T2, T3 polynomials"), b.T1 = new Y(new s((f.domainSize + 1) * h), p, r), b.T2 = new Y(new s((f.domainSize + 1) * h), p, r), b.T3 = new Y(new s((f.domainSize + 6) * h), p, r), b.T1.coef.set(b.T.coef.slice(0, g), 0), b.T2.coef.set(b.T.coef.slice(g, g * 2), 0), b.T3.coef.set(b.T.coef.slice(g * 2, g * 3 + 6 * h), 0), b.T1.setCoef(f.domainSize, S.b[10]); + let t = m.sub(b.T2.getCoef(0), S.b[10]); + b.T2.setCoef(0, t), b.T2.setCoef(f.domainSize, S.b[11]); + let n = m.sub(b.T3.getCoef(0), S.b[11]); + b.T3.setCoef(0, n); + } + async function ee() { + r && r.debug("> Computing challenge xi"), w.reset(), w.addScalar(S.alpha), w.addPolCommitment(C.getPolynomial("T1")), w.addPolCommitment(C.getPolynomial("T2")), w.addPolCommitment(C.getPolynomial("T3")), S.xi = w.getChallenge(), S.xiw = m.mul(S.xi, m.w[f.power]), r && r.debug("··· challenges.xi: " + m.toString(S.xi, 16)), C.addEvaluation("eval_a", b.A.evaluate(S.xi)), C.addEvaluation("eval_b", b.B.evaluate(S.xi)), C.addEvaluation("eval_c", b.C.evaluate(S.xi)), C.addEvaluation("eval_s1", b.Sigma1.evaluate(S.xi)), C.addEvaluation("eval_s2", b.Sigma2.evaluate(S.xi)), C.addEvaluation("eval_zw", b.Z.evaluate(S.xiw)); + } + async function L() { + r && r.debug("> Computing challenge v"), w.reset(), w.addScalar(S.xi), w.addScalar(C.getEvaluation("eval_a")), w.addScalar(C.getEvaluation("eval_b")), w.addScalar(C.getEvaluation("eval_c")), w.addScalar(C.getEvaluation("eval_s1")), w.addScalar(C.getEvaluation("eval_s2")), w.addScalar(C.getEvaluation("eval_zw")), S.v = [], S.v[1] = w.getChallenge(), r && r.debug("··· challenges.v: " + m.toString(S.v[1], 16)); + for (let e = 2; e < 6; e++) S.v[e] = m.mul(S.v[e - 1], S.v[1]); + r && r.debug("> Computing linearisation polynomial R(X)"), await R(), r && r.debug("> Computing opening proof polynomial Wxi(X) polynomial"), z(), r && r.debug("> Computing opening proof polynomial Wxiw(X) polynomial"), B(), r && r.debug("> Computing Wxi, Wxiw MSM"); + let e = await b.Wxi.multiExponentiation(T, "Wxi"), t = await b.Wxiw.multiExponentiation(T, "Wxiw"); + C.addPolynomial("Wxi", e), C.addPolynomial("Wxiw", t); + } + async function R() { + let e = p.Fr; + b.QL = new Y(new s(g), p, r), b.QR = new Y(new s(g), p, r), b.QM = new Y(new s(g), p, r), b.QO = new Y(new s(g), p, r), b.QC = new Y(new s(g), p, r), await l.readToBuffer(b.QL.coef, 0, g, d[8][0].p), await l.readToBuffer(b.QR.coef, 0, g, d[9][0].p), await l.readToBuffer(b.QM.coef, 0, g, d[7][0].p), await l.readToBuffer(b.QO.coef, 0, g, d[10][0].p), await l.readToBuffer(b.QC.coef, 0, g, d[11][0].p), S.xin = S.xi; + for (let t = 0; t < f.power; t++) S.xin = e.square(S.xin); + S.zh = e.sub(S.xin, e.one); + let t = [], n = e.e(f.domainSize), i = e.one; + for (let r = 1; r <= Math.max(1, f.nPublic); r++) t[r] = e.div(e.mul(i, S.zh), e.mul(n, e.sub(S.xi, i))), i = e.mul(i, e.w[f.power]); + let a = e.div(e.sub(S.xin, e.one), e.mul(n, e.sub(S.xi, e.one))); + if (r) { + r.debug("Lagrange Evaluations: "); + for (let n = 1; n < t.length; n++) r.debug(`L${n}(xi)=` + e.toString(t[n], 16)); + } + let o = e.zero; + for (let n = 0; n < E.length; n++) { + let r = e.e(E[n]); + o = e.sub(o, e.mul(r, t[n + 1])); + } + r && r.debug("PI: " + e.toString(o, 16)); + let c = e.mul(C.evaluations.eval_a, C.evaluations.eval_b), u = C.evaluations.eval_a, m = e.mul(S.beta, S.xi); + u = e.add(u, m), u = e.add(u, S.gamma); + let _ = C.evaluations.eval_b; + _ = e.add(_, e.mul(m, f.k1)), _ = e.add(_, S.gamma); + let v = C.evaluations.eval_c; + v = e.add(v, e.mul(m, f.k2)), v = e.add(v, S.gamma); + let y = e.mul(e.mul(e.mul(u, _), v), S.alpha), x = C.evaluations.eval_a; + x = e.add(x, e.mul(S.beta, C.evaluations.eval_s1)), x = e.add(x, S.gamma); + let w = C.evaluations.eval_b; + w = e.add(w, e.mul(S.beta, C.evaluations.eval_s2)), w = e.add(w, S.gamma); + let T = e.mul(x, w); + T = e.mul(T, C.evaluations.eval_zw), T = e.mul(T, S.alpha); + let D = e.mul(a, S.alpha2); + b.R = new Y(new s((f.domainSize + 6) * h), p, r), b.R.add(b.QM, c), b.R.add(b.QL, C.evaluations.eval_a), b.R.add(b.QR, C.evaluations.eval_b), b.R.add(b.QO, C.evaluations.eval_c), b.R.add(b.QC), b.R.add(b.Z, y), b.R.sub(b.Sigma3, e.mul(T, S.beta)), b.R.add(b.Z, D); + let O = Y.fromPolynomial(b.T3, p, r); + O.mulScalar(e.square(S.xin)), O.add(b.T2, S.xin), O.add(b.T1), O.mulScalar(S.zh), b.R.sub(O); + let k = e.sub(o, e.mul(T, e.add(C.evaluations.eval_c, S.gamma))); + k = e.sub(k, D), r && r.debug("r0: " + e.toString(k, 16)), b.R.addScalar(k); + } + function z() { + b.Wxi = new Y(new s(g + 6 * h), p, r), b.Wxi.add(b.R), b.Wxi.add(b.A, S.v[1]), b.Wxi.add(b.B, S.v[2]), b.Wxi.add(b.C, S.v[3]), b.Wxi.add(b.Sigma1, S.v[4]), b.Wxi.add(b.Sigma2, S.v[5]), b.Wxi.subScalar(m.mul(S.v[1], C.evaluations.eval_a)), b.Wxi.subScalar(m.mul(S.v[2], C.evaluations.eval_b)), b.Wxi.subScalar(m.mul(S.v[3], C.evaluations.eval_c)), b.Wxi.subScalar(m.mul(S.v[4], C.evaluations.eval_s1)), b.Wxi.subScalar(m.mul(S.v[5], C.evaluations.eval_s2)), b.Wxi.divByZerofier(1, S.xi); + } + async function B() { + b.Wxiw = Y.fromPolynomial(b.Z, p, r), b.Wxiw.subScalar(C.evaluations.eval_zw), b.Wxiw.divByZerofier(1, S.xiw); + } +} +//#endregion +//#region src/plonk_fullprove.js +var { unstringifyBigInts: Fr } = p; +async function Ir(e, t, n, r, i, a) { + let o = Fr(e), s = { type: "mem" }; + return await Vt(o, t, s, i), await Pr(n, s, r, a); +} +//#endregion +//#region src/plonk_verify.js +var { unstringifyBigInts: Lr } = p; +async function Rr(e, t, n, r) { + let i = Lr(e); + n = Lr(n); + let a = Lr(t), o = await E(i.curve), s = o.Fr, c = o.G1; + r && r.info("PLONK VERIFIER STARTED"); + let l = zr(o, n); + if (i = Br(o, i), !Vr(o, l)) return r.error("Proof commitments are not valid."), !1; + if (a.length != i.nPublic) return r && r.error("Invalid number of public inputs"), !1; + if (!Wr(o, l)) return r && r.error("Proof evaluations are not valid"), !1; + if (!Gr(o, a)) return r && r.error("Public inputs are not valid."), !1; + let u = Kr(o, l, a, i); + if (r) { + r.debug("beta: " + s.toString(u.beta, 16)), r.debug("gamma: " + s.toString(u.gamma, 16)), r.debug("alpha: " + s.toString(u.alpha, 16)), r.debug("xi: " + s.toString(u.xi, 16)); + for (let e = 1; e < 6; e++) r && r.debug("v: " + s.toString(u.v[e], 16)); + r.debug("u: " + s.toString(u.u, 16)); + } + let d = qr(o, u, i); + if (r) for (let e = 1; e < d.length; e++) r.debug(`L${e}(xi)=` + s.toString(d[e], 16)); + if (a.length != i.nPublic) return r.error("Number of public signals does not match with vk"), !1; + let f = Jr(o, a, d); + r && r.debug("PI(xi): " + s.toString(f, 16)); + let p = Yr(o, l, u, f, d[1]); + r && r.debug("r0: " + s.toString(p, 16)); + let m = Xr(o, l, u, i, d[1]); + r && r.debug("D: " + c.toString(c.toAffine(m), 16)); + let h = Zr(o, l, u, i, m); + r && r.debug("F: " + c.toString(c.toAffine(h), 16)); + let g = Qr(o, l, u, p); + r && r.debug("E: " + c.toString(c.toAffine(g), 16)); + let _ = await $r(o, l, u, i, g, h); + return r && (_ ? r.info("OK!") : r.warn("Invalid Proof")), _; +} +function zr(e, t) { + let n = e.G1, r = e.Fr, i = {}; + return i.A = n.fromObject(t.A), i.B = n.fromObject(t.B), i.C = n.fromObject(t.C), i.Z = n.fromObject(t.Z), i.T1 = n.fromObject(t.T1), i.T2 = n.fromObject(t.T2), i.T3 = n.fromObject(t.T3), i.eval_a = r.fromObject(t.eval_a), i.eval_b = r.fromObject(t.eval_b), i.eval_c = r.fromObject(t.eval_c), i.eval_zw = r.fromObject(t.eval_zw), i.eval_s1 = r.fromObject(t.eval_s1), i.eval_s2 = r.fromObject(t.eval_s2), i.Wxi = n.fromObject(t.Wxi), i.Wxiw = n.fromObject(t.Wxiw), i; +} +function Br(e, t) { + let n = e.G1, r = e.G2, i = e.Fr, a = t; + return a.Qm = n.fromObject(t.Qm), a.Ql = n.fromObject(t.Ql), a.Qr = n.fromObject(t.Qr), a.Qo = n.fromObject(t.Qo), a.Qc = n.fromObject(t.Qc), a.S1 = n.fromObject(t.S1), a.S2 = n.fromObject(t.S2), a.S3 = n.fromObject(t.S3), a.k1 = i.fromObject(t.k1), a.k2 = i.fromObject(t.k2), a.X_2 = r.fromObject(t.X_2), a; +} +function Vr(e, t) { + let n = e.G1; + return !(!n.isValid(t.A) || !n.isValid(t.B) || !n.isValid(t.C) || !n.isValid(t.Z) || !n.isValid(t.T1) || !n.isValid(t.T2) || !n.isValid(t.T3) || !n.isValid(t.Wxi) || !n.isValid(t.Wxiw)); +} +function Hr(e, t) { + return u.geq(t, 0) && u.lt(t, e.r); +} +function Ur(e, t) { + return Hr(e, u.fromRprLE(t)); +} +function Wr(e, t) { + return Ur(e, t.eval_a) && Ur(e, t.eval_b) && Ur(e, t.eval_c) && Ur(e, t.eval_s1) && Ur(e, t.eval_s2) && Ur(e, t.eval_zw); +} +function Gr(e, t) { + for (let n = 0; n < t.length; n++) if (!Hr(e, t[n])) return !1; + return !0; +} +function Kr(e, t, n, r) { + let i = e.Fr, a = {}, o = new jr(e); + o.addPolCommitment(r.Qm), o.addPolCommitment(r.Ql), o.addPolCommitment(r.Qr), o.addPolCommitment(r.Qo), o.addPolCommitment(r.Qc), o.addPolCommitment(r.S1), o.addPolCommitment(r.S2), o.addPolCommitment(r.S3); + for (let e = 0; e < n.length; e++) o.addScalar(i.e(n[e])); + o.addPolCommitment(t.A), o.addPolCommitment(t.B), o.addPolCommitment(t.C), a.beta = o.getChallenge(), o.reset(), o.addScalar(a.beta), a.gamma = o.getChallenge(), o.reset(), o.addScalar(a.beta), o.addScalar(a.gamma), o.addPolCommitment(t.Z), a.alpha = o.getChallenge(), o.reset(), o.addScalar(a.alpha), o.addPolCommitment(t.T1), o.addPolCommitment(t.T2), o.addPolCommitment(t.T3), a.xi = o.getChallenge(), o.reset(), o.addScalar(a.xi), o.addScalar(t.eval_a), o.addScalar(t.eval_b), o.addScalar(t.eval_c), o.addScalar(t.eval_s1), o.addScalar(t.eval_s2), o.addScalar(t.eval_zw), a.v = [], a.v[1] = o.getChallenge(); + for (let e = 2; e < 6; e++) a.v[e] = i.mul(a.v[e - 1], a.v[1]); + return o.reset(), o.addPolCommitment(t.Wxi), o.addPolCommitment(t.Wxiw), a.u = o.getChallenge(), a; +} +function qr(e, t, n) { + let r = e.Fr, i = t.xi, a = 1; + for (let e = 0; e < n.power; e++) i = r.square(i), a *= 2; + t.xin = i, t.zh = r.sub(i, r.one); + let o = [], s = r.e(a), c = r.one; + for (let e = 1; e <= Math.max(1, n.nPublic); e++) o[e] = r.div(r.mul(c, t.zh), r.mul(s, r.sub(t.xi, c))), c = r.mul(c, r.w[n.power]); + return o; +} +function Jr(e, t, n) { + let r = e.Fr, i = r.zero; + for (let e = 0; e < t.length; e++) { + let a = r.e(t[e]); + i = r.sub(i, r.mul(a, n[e + 1])); + } + return i; +} +function Yr(e, t, n, r, i) { + let a = e.Fr, o = r, s = a.mul(i, a.square(n.alpha)), c = a.add(t.eval_a, a.mul(n.beta, t.eval_s1)); + c = a.add(c, n.gamma); + let l = a.add(t.eval_b, a.mul(n.beta, t.eval_s2)); + l = a.add(l, n.gamma); + let u = a.add(t.eval_c, n.gamma), d = a.mul(a.mul(c, l), u); + return d = a.mul(d, t.eval_zw), d = a.mul(d, n.alpha), a.sub(a.sub(o, s), d); +} +function Xr(e, t, n, r, i) { + let a = e.G1, o = e.Fr, s = a.timesFr(r.Qm, o.mul(t.eval_a, t.eval_b)); + s = a.add(s, a.timesFr(r.Ql, t.eval_a)), s = a.add(s, a.timesFr(r.Qr, t.eval_b)), s = a.add(s, a.timesFr(r.Qo, t.eval_c)), s = a.add(s, r.Qc); + let c = o.mul(n.beta, n.xi), l = o.add(o.add(t.eval_a, c), n.gamma), u = o.add(o.add(t.eval_b, o.mul(c, r.k1)), n.gamma), d = o.add(o.add(t.eval_c, o.mul(c, r.k2)), n.gamma), f = o.mul(o.mul(o.mul(l, u), d), n.alpha), p = o.mul(i, o.square(n.alpha)), m = a.timesFr(t.Z, o.add(o.add(f, p), n.u)), h = o.add(o.add(t.eval_a, o.mul(n.beta, t.eval_s1)), n.gamma), g = o.add(o.add(t.eval_b, o.mul(n.beta, t.eval_s2)), n.gamma), _ = o.mul(o.mul(n.alpha, n.beta), t.eval_zw), v = a.timesFr(r.S3, o.mul(o.mul(h, g), _)), y = t.T1, b = a.timesFr(t.T2, n.xin), x = a.timesFr(t.T3, o.square(n.xin)), S = a.add(y, a.add(b, x)); + return S = a.timesFr(S, n.zh), a.sub(a.sub(a.add(s, m), v), S); +} +function Zr(e, t, n, r, i) { + let a = e.G1, o = a.add(i, a.timesFr(t.A, n.v[1])); + return o = a.add(o, a.timesFr(t.B, n.v[2])), o = a.add(o, a.timesFr(t.C, n.v[3])), o = a.add(o, a.timesFr(r.S1, n.v[4])), o = a.add(o, a.timesFr(r.S2, n.v[5])), o; +} +function Qr(e, t, n, r) { + let i = e.G1, a = e.Fr, o = a.add(a.neg(r), a.mul(n.v[1], t.eval_a)); + return o = a.add(o, a.mul(n.v[2], t.eval_b)), o = a.add(o, a.mul(n.v[3], t.eval_c)), o = a.add(o, a.mul(n.v[4], t.eval_s1)), o = a.add(o, a.mul(n.v[5], t.eval_s2)), o = a.add(o, a.mul(n.u, t.eval_zw)), i.timesFr(i.one, o); +} +async function $r(e, t, n, r, i, a) { + let o = e.G1, s = e.Fr, c = t.Wxi; + c = o.add(c, o.timesFr(t.Wxiw, n.u)); + let l = o.timesFr(t.Wxi, n.xi), u = s.mul(s.mul(n.u, n.xi), s.w[r.power]); + return l = o.add(l, o.timesFr(t.Wxiw, u)), l = o.add(l, a), l = o.sub(l, i), await e.pairingEq(o.neg(c), r.X_2, l, e.G2.one); +} +//#endregion +//#region src/plonk_exportsoliditycalldata.js +var { unstringifyBigInts: ei } = p; +function Z(e) { + let t = e.toString(16); + for (; t.length < 64;) t = "0" + t; + return t = `"0x${t}"`, t; +} +async function ti(e, t) { + let n = ei(e), r = ei(t); + await E(n.curve); + let i = ""; + for (let e = 0; e < r.length; e++) i != "" && (i += ","), i += Z(r[e]); + return `[${Z(n.A[0])}, ${Z(n.A[1])},${Z(n.B[0])},${Z(n.B[1])},${Z(n.C[0])},${Z(n.C[1])},${Z(n.Z[0])},${Z(n.Z[1])},${Z(n.T1[0])},${Z(n.T1[1])},${Z(n.T2[0])},${Z(n.T2[1])},${Z(n.T3[0])},${Z(n.T3[1])},${Z(n.Wxi[0])},${Z(n.Wxi[1])},${Z(n.Wxiw[0])},${Z(n.Wxiw[1])},${Z(n.eval_a)},${Z(n.eval_b)},${Z(n.eval_c)},${Z(n.eval_s1)},${Z(n.eval_s2)},${Z(n.eval_zw)}][${i}]`; +} +//#endregion +//#region src/plonk.js +var ni = /* @__PURE__ */ v({ + exportSolidityCallData: () => ti, + fullProve: () => Ir, + prove: () => Pr, + setup: () => ur, + verify: () => Rr }); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const SUBARRAY_SIZE = 0x40000; - -const BigArrayHandler = { - get: function(obj, prop) { - if (!isNaN(prop)) { - return obj.getElement(prop); - } else return obj[prop]; - }, - set: function(obj, prop, value) { - if (!isNaN(prop)) { - return obj.setElement(prop, value); - } else { - obj[prop] = value; - return true; - } - } +//#endregion +//#region src/plonk_equation.js +function ri(e, t) { + return [ + e, + 0, + 0, + t.one, + t.zero, + t.zero, + t.zero, + t.zero + ]; +} +function ii(e, t, n, r, i, a, o, s) { + return [ + e, + t, + n, + r, + i, + a, + o, + s + ]; +} +function ai(e, t, n, r, i, a, o, s, c) { + return [ + e, + t, + n, + r, + i, + a, + o, + s + ]; +} +//#endregion +//#region src/r1cs_constraint_processor.js +var oi = 0, si = 1, ci = 2, li = class { + constructor(e, t, n, r, i) { + this.Fr = e, this.logger = i, this.fnGetAdditionConstraint = n, this.fnGetMultiplicationConstraint = r; + } + processR1csConstraint(e, t, n, r) { + this.normalizeLinearCombination(t), this.normalizeLinearCombination(n), this.normalizeLinearCombination(r); + let i = this.getLinearCombinationType(t), a = this.getLinearCombinationType(n); + if (i === oi || a === oi) return this.processR1csAdditionConstraint(e, r); + if (i === si) { + let i = this.joinLinearCombinations(n, r, t[0]); + return this.processR1csAdditionConstraint(e, i); + } else if (a === si) { + let i = this.joinLinearCombinations(t, r, n[0]); + return this.processR1csAdditionConstraint(e, i); + } else return this.processR1csMultiplicationConstraint(e, t, n, r); + } + getLinearCombinationType(e) { + let t = this.Fr.zero, n = 0, r = Object.keys(e); + for (let i = 0; i < r.length; i++) e[r[i]] == 0n ? delete e[r[i]] : r[i] == 0 ? t = this.Fr.add(t, e[r[i]]) : n++; + return n > 0 ? ci : this.Fr.isZero(t) ? oi : si; + } + normalizeLinearCombination(e) { + let t = Object.keys(e); + for (let n = 0; n < t.length; n++) this.Fr.isZero(e[t[n]]) && delete e[t[n]]; + return e; + } + joinLinearCombinations(e, t, n) { + let r = {}; + for (let t in e) r[t] === void 0 ? r[t] = this.Fr.mul(n, e[t]) : r[t] = this.Fr.add(r[t], this.Fr.mul(n, e[t])); + for (let e in t) r[e] === void 0 ? r[e] = t[e] : r[e] = this.Fr.add(r[e], t[e]); + return this.normalizeLinearCombination(r); + } + reduceCoefs(e, t, n, r, i) { + let a = { + k: this.Fr.zero, + signals: [], + coefs: [] + }, o = []; + for (let e in r) e == 0 ? a.k = this.Fr.add(a.k, r[e]) : r[e] != 0n && o.push([Number(e), r[e]]); + for (; o.length > i;) { + let r = o.shift(), i = o.shift(), a = e.nVars++, s = this.fnGetAdditionConstraint(r[0], i[0], a, this.Fr.neg(r[1]), this.Fr.neg(i[1]), this.Fr.zero, this.Fr.one, this.Fr.zero); + t.push(s), n.push([ + r[0], + i[0], + r[1], + i[1] + ]), o.push([a, this.Fr.one]); + } + for (let e = 0; e < o.length; e++) a.signals[e] = o[e][0], a.coefs[e] = o[e][1]; + for (; a.coefs.length < i;) a.signals.push(0), a.coefs.push(this.Fr.zero); + return a; + } + processR1csAdditionConstraint(e, t) { + let n = [], r = [], i = this.reduceCoefs(e, n, r, t, 3), a = this.fnGetAdditionConstraint(i.signals[0], i.signals[1], i.signals[2], i.coefs[0], i.coefs[1], this.Fr.zero, i.coefs[2], i.k); + return n.push(a), [n, r]; + } + processR1csMultiplicationConstraint(e, t, n, r) { + let i = [], a = [], o = this.reduceCoefs(e, i, a, t, 1), s = this.reduceCoefs(e, i, a, n, 1), c = this.reduceCoefs(e, i, a, r, 1), l = this.fnGetMultiplicationConstraint(o.signals[0], s.signals[0], c.signals[0], this.Fr.mul(o.coefs[0], s.k), this.Fr.mul(o.k, s.coefs[0]), this.Fr.mul(o.coefs[0], s.coefs[0]), this.Fr.neg(c.coefs[0]), this.Fr.sub(this.Fr.mul(o.k, s.k), c.k)); + return i.push(l), [i, a]; + } +}, ui = class { + constructor(e, t, n) { + this.n = e, this.polynomials = Array(e).fill(void 0), this.curve = t, this.Fr = t.Fr, this.G1 = t.G1, this.logger = n; + } + addPolynomial(e, t) { + if (e > this.n - 1) throw Error("CPolynomial:addPolynomial, cannot add a polynomial to a position greater than n-1"); + this.polynomials[e] = t; + } + degree() { + let e = this.polynomials.map((e, t) => e === void 0 ? 0 : e.degree() * this.n + t); + return Math.max(...e); + } + getPolynomial() { + let e = this.polynomials.map((e) => e === void 0 ? 0 : e.degree()), t = this.degree(), n = 2 ** (Ce(t - 1) + 1), r = this.Fr.n8, i = new Y(new s(n * r), this.curve, this.logger); + for (let n = 0; n < t; n++) { + let t = n * r, a = t * this.n; + for (let o = 0; o < this.n; o++) this.polynomials[o] !== void 0 && n <= e[o] && i.coef.set(this.polynomials[o].coef.slice(t, t + r), a + o * r); + } + return i; + } + async multiExponentiation(e, t) { + let n = this.getPolynomial(), r = n.coef.byteLength / this.Fr.n8, i = e.slice(0, r * this.G1.F.n8 * 2), a = await this.Fr.batchFromMontgomery(n.coef), o = await this.G1.multiExpAffine(i, a, this.logger, t); + return o = this.G1.toAffine(o), o; + } }; - -class _BigArray { - constructor (initSize) { - this.length = initSize || 0; - this.arr = new Array(SUBARRAY_SIZE); - - for (let i=0; i= this.length) this.length = idx+1; - return true; - } - getKeys() { - const newA = new BigArray(); - for (let i=0; i. -*/ - - -async function newZKey(r1csName, ptauName, zkeyName, logger) { - - const TAU_G1 = 0; - const TAU_G2 = 1; - const ALPHATAU_G1 = 2; - const BETATAU_G1 = 3; - const csHasher = blake2b.create({ dkLen: 64 }); - - const {fd: fdPTau, sections: sectionsPTau} = await readBinFile$1(ptauName, "ptau", 1, 1<<22, 1<<24); - const {curve, power} = await readPTauHeader(fdPTau, sectionsPTau); - const {fd: fdR1cs, sections: sectionsR1cs} = await readBinFile$1(r1csName, "r1cs", 1, 1<<22, 1<<24); - const r1cs = await readR1csHeader(fdR1cs, sectionsR1cs, false); - - const fdZKey = await createBinFile(zkeyName, "zkey", 1, 10, 1<<22, 1<<24); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - if (r1cs.prime != curve.r) { - if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); - return -1; - } - - const cirPower = log2(r1cs.nConstraints + r1cs.nPubInputs + r1cs.nOutputs +1 -1) +1; - - if (cirPower > power) { - if (logger) logger.error(`circuit too big for this power of tau ceremony. ${r1cs.nConstraints}*2 > 2**${power}`); - return -1; - } - - if (!sectionsPTau[12]) { - if (logger) logger.error("Powers of tau is not prepared."); - return -1; - } - - const nPublic = r1cs.nOutputs + r1cs.nPubInputs; - const domainSize = 2 ** cirPower; - - // Write the header - /////////// - await startWriteSection(fdZKey, 1); - await fdZKey.writeULE32(1); // Groth - await endWriteSection(fdZKey); - - // Write the Groth header section - /////////// - - await startWriteSection(fdZKey, 2); - const primeQ = curve.q; - const n8q = (Math.floor( (Scalar.bitLength(primeQ) - 1) / 64) +1)*8; - - const primeR = curve.r; - const n8r = (Math.floor( (Scalar.bitLength(primeR) - 1) / 64) +1)*8; - const Rr = Scalar.mod(Scalar.shl(1, n8r*8), primeR); - const R2r = curve.Fr.e(Scalar.mod(Scalar.mul(Rr,Rr), primeR)); - - await fdZKey.writeULE32(n8q); - await writeBigInt(fdZKey, primeQ, n8q); - await fdZKey.writeULE32(n8r); - await writeBigInt(fdZKey, primeR, n8r); - await fdZKey.writeULE32(r1cs.nVars); // Total number of bars - await fdZKey.writeULE32(nPublic); // Total number of public vars (not including ONE) - await fdZKey.writeULE32(domainSize); // domainSize - - let bAlpha1; - bAlpha1 = await fdPTau.read(sG1, sectionsPTau[4][0].p); - await fdZKey.write(bAlpha1); - bAlpha1 = await curve.G1.batchLEMtoU(bAlpha1); - csHasher.update(bAlpha1); - - let bBeta1; - bBeta1 = await fdPTau.read(sG1, sectionsPTau[5][0].p); - await fdZKey.write(bBeta1); - bBeta1 = await curve.G1.batchLEMtoU(bBeta1); - csHasher.update(bBeta1); - - let bBeta2; - bBeta2 = await fdPTau.read(sG2, sectionsPTau[6][0].p); - await fdZKey.write(bBeta2); - bBeta2 = await curve.G2.batchLEMtoU(bBeta2); - csHasher.update(bBeta2); - - const bg1 = new Uint8Array(sG1); - curve.G1.toRprLEM(bg1, 0, curve.G1.g); - const bg2 = new Uint8Array(sG2); - curve.G2.toRprLEM(bg2, 0, curve.G2.g); - const bg1U = new Uint8Array(sG1); - curve.G1.toRprUncompressed(bg1U, 0, curve.G1.g); - const bg2U = new Uint8Array(sG2); - curve.G2.toRprUncompressed(bg2U, 0, curve.G2.g); - - await fdZKey.write(bg2); // gamma2 - await fdZKey.write(bg1); // delta1 - await fdZKey.write(bg2); // delta2 - csHasher.update(bg2U); // gamma2 - csHasher.update(bg1U); // delta1 - csHasher.update(bg2U); // delta2 - await endWriteSection(fdZKey); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Reading r1cs"); - let sR1cs = await readSection$1(fdR1cs, sectionsR1cs, 2); - await fdR1cs.close(); - - let A = new BigArray(r1cs.nVars); - let B1 = new BigArray(r1cs.nVars); - let B2 = new BigArray(r1cs.nVars); - let C = new BigArray(r1cs.nVars- nPublic -1); - let IC = new Array(nPublic+1); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Reading tauG1"); - let sTauG1 = await readSection$1(fdPTau, sectionsPTau, 12, (domainSize -1)*sG1, domainSize*sG1); - if (logger) logger.info("Reading tauG2"); - let sTauG2 = await readSection$1(fdPTau, sectionsPTau, 13, (domainSize -1)*sG2, domainSize*sG2); - if (logger) logger.info("Reading alphatauG1"); - let sAlphaTauG1 = await readSection$1(fdPTau, sectionsPTau, 14, (domainSize -1)*sG1, domainSize*sG1); - if (logger) logger.info("Reading betatauG1"); - let sBetaTauG1 = await readSection$1(fdPTau, sectionsPTau, 15, (domainSize -1)*sG1, domainSize*sG1); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("processConstraints"); - await processConstraints(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints"); - await composeAndWritePoints(3, "G1", IC, "IC"); - - IC = null; - // const gc = runInNewContext("gc"); // nocommit - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("writeHs"); - await writeHs(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("hashHPoints"); - await hashHPoints(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 8 G1 C"); - await composeAndWritePoints(8, "G1", C, "C"); - - C = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 5 G1 A"); - await composeAndWritePoints(5, "G1", A, "A"); - - A = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 6 G1 B1"); - await composeAndWritePoints(6, "G1", B1, "B1"); - - B1 = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 7 G2 B2"); - await composeAndWritePoints(7, "G2", B2, "B2"); - - B2 = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Contributions section"); - const csHash = csHasher.digest(); - // Contributions section - await startWriteSection(fdZKey, 10); - await fdZKey.write(csHash); - await fdZKey.writeULE32(0); - await endWriteSection(fdZKey); - - if (logger) logger.info(formatHash(csHash, "Circuit hash: ")); - - - await fdZKey.close(); - await fdPTau.close(); - - return csHash; - - async function writeHs() { - await startWriteSection(fdZKey, 9); - const buffOut = new BigBuffer(domainSize*sG1); - if (cirPower < curve.Fr.s) { - let sTauG1 = await readSection$1(fdPTau, sectionsPTau, 12, (domainSize*2-1)*sG1, domainSize*2*sG1); - for (let i=0; i< domainSize; i++) { - if ((logger)&&(i%10000 == 0)) logger.debug(`splitting buffer: ${i}/${domainSize}`); - const buff = sTauG1.slice( (i*2+1)*sG1, (i*2+1)*sG1 + sG1 ); - buffOut.set(buff, i*sG1); - } - } else if (cirPower == curve.Fr.s) { - const o = sectionsPTau[12][0].p + ((2 ** (cirPower+1)) -1)*sG1; - await fdPTau.readToBuffer(buffOut, 0, domainSize*sG1, o + domainSize*sG1); - } else { - if (logger) logger.error("Circuit too big"); - throw new Error("Circuit too big for this curve"); - } - await fdZKey.write(buffOut); - await endWriteSection(fdZKey); - } - - async function processConstraints() { - const buffCoeff = new Uint8Array(12 + curve.Fr.n8); - const buffCoeffV = new DataView(buffCoeff.buffer); - const bOne = new Uint8Array(curve.Fr.n8); - curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); - - let r1csPos = 0; - - function r1cs_readULE32() { - const buff = sR1cs.slice(r1csPos, r1csPos+4); - r1csPos += 4; - const buffV = new DataView(buff.buffer); - return buffV.getUint32(0, true); - } - - const coefs = new BigArray(); - for (let c=0; c=0) { - n = curve.Fr.fromRprLE(sR1cs.slice(c[3], c[3] + curve.Fr.n8), 0); - } else { - n = curve.Fr.fromRprLE(bOne, 0); - } - const nR2 = curve.Fr.mul(n, R2r); - curve.Fr.toRprLE(buffCoeff, 12, nR2); - buffSection.set(buffCoeff, coefsPos); - coefsPos += buffCoeff.length; - } - - } - - async function composeAndWritePoints(idSection, groupName, arr, sectionName) { - const CHUNK_SIZE= 1<<15; - const G = curve[groupName]; - - hashU32(arr.length); - await startWriteSection(fdZKey, idSection); - - let opPromises = []; - - let i=0; - while (i { - if (logger) logger.debug(`Writing points end ${sectionName}: ${_i}/${arr.length}`); - return r; - })); - i += n; - t++; - } - - const result = await Promise.all(opPromises); - - for (let k=0; k 2<<14) { - bBases = new BigBuffer(acc*sGin); - bScalars = new BigBuffer(acc*curve.Fr.n8); - } else { - bBases = new Uint8Array(acc*sGin); - bScalars = new Uint8Array(acc*curve.Fr.n8); - } - let pB =0; - let pS =0; - - const sBuffs = [ - sTauG1, - sTauG2, - sAlphaTauG1, - sBetaTauG1 - ]; - - const bOne = new Uint8Array(curve.Fr.n8); - curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); - - let offset = 0; - for (let i=0; i=0) { - bScalars.set( - sR1cs.slice( - arr[i][j][2], - arr[i][j][2] + curve.Fr.n8 - ), - offset*curve.Fr.n8 - ); - } else { - bScalars.set(bOne, offset*curve.Fr.n8); - } - offset ++; - } - } - - if (arr.length>1) { - const task = []; - task.push({cmd: "ALLOCSET", var: 0, buff: bBases}); - task.push({cmd: "ALLOCSET", var: 1, buff: bScalars}); - task.push({cmd: "ALLOC", var: 2, len: arr.length*sGmid}); - pB = 0; - pS = 0; - let pD =0; - for (let i=0; i. -*/ - - -async function phase2importMPCParams(zkeyNameOld, mpcparamsName, zkeyNameNew, name, logger) { - - const {fd: fdZKeyOld, sections: sectionsZKeyOld} = await readBinFile$1(zkeyNameOld, "zkey", 2); - const zkeyHeader = await readHeader$1(fdZKeyOld, sectionsZKeyOld, false); - if (zkeyHeader.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkeyHeader.q); - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - const oldMPCParams = await readMPCParams(fdZKeyOld, curve, sectionsZKeyOld); - const newMPCParams = {}; - - const fdMPCParams = await readExisting$3(mpcparamsName); - - fdMPCParams.pos = - sG1*3 + sG2*3 + // vKey - 8 + sG1*zkeyHeader.nVars + // IC + C - 4 + sG1*(zkeyHeader.domainSize-1) + // H - 4 + sG1*zkeyHeader.nVars + // A - 4 + sG1*zkeyHeader.nVars + // B1 - 4 + sG2*zkeyHeader.nVars; // B2 - - // csHash - newMPCParams.csHash = await fdMPCParams.read(64); - - const nContributions = await fdMPCParams.readUBE32(); - newMPCParams.contributions = []; - for (let i=0; i newMPCParams.contributions.length) { - if (logger) logger.error("The impoerted file does not include new contributions"); - return false; - } - - for (let i=0; i. -*/ - -const sameRatio = sameRatio$2; - - - -async function phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger) { - - let sr; - const {fd, sections} = await readBinFile$1(zkeyFileName, "zkey", 2); - const zkey = await readHeader$1(fd, sections, false); - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkey.q); - const sG1 = curve.G1.F.n8*2; - - const mpcParams = await readMPCParams(fd, curve, sections); - - const accumulatedHasher = blake2b.create({ dkLen: 64 }); - accumulatedHasher.update(mpcParams.csHash); - let curDelta = curve.G1.g; - for (let i=0; i=0; i--) { - const c = mpcParams.contributions[i]; - if (logger) logger.info("-------------------------"); - if (logger) logger.info(formatHash(c.contributionHash, `contribution #${i+1} ${c.name ? c.name : ""}:`)); - if (c.type == 1) { - if (logger) logger.info(`Beacon generator: ${byteArray2hex(c.beaconHash)}`); - if (logger) logger.info(`Beacon iterations Exp: ${c.numIterationsExp}`); - } - } - if (logger) logger.info("-------------------------"); - - if (logger) logger.info("ZKey Ok!"); - - return true; - - - async function sectionHasSameRatio(groupName, fd1, sections1, fd2, sections2, idSection, g2sp, g2spx, sectionName) { - const MAX_CHUNK_SIZE = 1<<20; - const G = curve[groupName]; - const sG = G.F.n8*2; - await startReadUniqueSection$1(fd1, sections1, idSection); - await startReadUniqueSection$1(fd2, sections2, idSection); - - let R1 = G.zero; - let R2 = G.zero; - - const nPoints = sections1[idSection][0].size / sG; - - for (let i=0; i. -*/ - - -async function phase2verifyFromR1cs(r1csFileName, pTauFileName, zkeyFileName, logger) { - - // const initFileName = "~" + zkeyFileName + ".init"; - const initFileName = {type: "bigMem"}; - await newZKey(r1csFileName, pTauFileName, initFileName, logger); - - return await phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function phase2contribute(zkeyNameOld, zkeyNameNew, name, entropy, logger) { - - const {fd: fdOld, sections: sections} = await readBinFile$1(zkeyNameOld, "zkey", 2); - const zkey = await readHeader$1(fdOld, sections); - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkey.q); - - const mpcParams = await readMPCParams(fdOld, curve, sections); - - const fdNew = await createBinFile(zkeyNameNew, "zkey", 1, 10); - - - const rng = await getRandomRng(entropy); - - const transcriptHasher = blake2b.create({ dkLen: 64 }); - transcriptHasher.update(mpcParams.csHash); - for (let i=0; i. -*/ - - - -async function beacon(zkeyNameOld, zkeyNameNew, name, beaconHashStr, numIterationsExp, logger) { - const beaconHash = hex2ByteArray(beaconHashStr); - if ( (beaconHash.byteLength == 0) - || (beaconHash.byteLength*2 !=beaconHashStr.length)) - { - if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); - return false; - } - if (beaconHash.length>=256) { - if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); - return false; - } - - numIterationsExp = parseInt(numIterationsExp); - if ((numIterationsExp<10)||(numIterationsExp>63)) { - if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); - return false; - } - - - const {fd: fdOld, sections: sections} = await readBinFile$1(zkeyNameOld, "zkey", 2); - const zkey = await readHeader$1(fdOld, sections); - - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - - const curve = await getCurveFromQ(zkey.q); - - const mpcParams = await readMPCParams(fdOld, curve, sections); - - const fdNew = await createBinFile(zkeyNameNew, "zkey", 1, 10); - - const rng = await rngFromBeaconParams(beaconHash, numIterationsExp); - - const transcriptHasher = blake2b.create({ dkLen: 64 }); transcriptHasher.update(mpcParams.csHash); - for (let i=0; i. -*/ - - -async function bellmanContribute(curve, challengeFilename, responseFileName, entropy, logger) { - const rng = await getRandomRng(entropy); - - const delta = curve.Fr.fromRng(rng); - const invDelta = curve.Fr.inv(delta); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - const fdFrom = await readExisting$3(challengeFilename); - const fdTo = await createOverride(responseFileName); - - - await copy(sG1); // alpha1 - await copy(sG1); // beta1 - await copy(sG2); // beta2 - await copy(sG2); // gamma2 - const oldDelta1 = await readG1(); - const delta1 = curve.G1.timesFr(oldDelta1, delta); - await writeG1(delta1); - const oldDelta2 = await readG2(); - const delta2 = curve.G2.timesFr(oldDelta2, delta); - await writeG2(delta2); - - // IC - const nIC = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nIC); - await copy(nIC*sG1); - - // H - const nH = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nH); - await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nH, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "H", logger); - - // L - const nL = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nL); - await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nL, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "L", logger); - - // A - const nA = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nA); - await copy(nA*sG1); - - // B1 - const nB1 = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nB1); - await copy(nB1*sG1); - - // B2 - const nB2 = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nB2); - await copy(nB2*sG2); - - - ////////// - /// Read contributions - ////////// - const transcriptHasher = blake2b.create({ dkLen: 64 }); - const mpcParams = {}; - // csHash - mpcParams.csHash = await fdFrom.read(64); - transcriptHasher.update(mpcParams.csHash); - - const nContributions = await fdFrom.readUBE32(); - mpcParams.contributions = []; - for (let i=0; i. -*/ - - -const {stringifyBigInts: stringifyBigInts$3} = utils; - -async function zkeyExportVerificationKey(zkeyName, logger) { - if (logger) logger.info("EXPORT VERIFICATION KEY STARTED"); - - const {fd, sections} = await readBinFile$1(zkeyName, "zkey", 2); - const zkey = await readHeader$1(fd, sections); - - if (logger) logger.info("> Detected protocol: " + zkey.protocol); - - let res; - if (zkey.protocol === "groth16") { - res = await groth16Vk(zkey, fd, sections); - } else if (zkey.protocol === "plonk") { - res = await plonkVk(zkey); - } else if (zkey.protocolId && zkey.protocolId === FFLONK_PROTOCOL_ID) { - res = await exportFFlonkVk(zkey); - } else { - throw new Error("zkey file protocol unrecognized"); - } - - await fd.close(); - - if (logger) logger.info("EXPORT VERIFICATION KEY FINISHED"); - - return res; -} - - -async function groth16Vk(zkey, fd, sections) { - const curve = await getCurveFromQ(zkey.q); - const sG1 = curve.G1.F.n8 * 2; - - const alphaBeta = await curve.pairing(zkey.vk_alpha_1, zkey.vk_beta_2); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - - vk_alpha_1: curve.G1.toObject(zkey.vk_alpha_1), - - vk_beta_2: curve.G2.toObject(zkey.vk_beta_2), - vk_gamma_2: curve.G2.toObject(zkey.vk_gamma_2), - vk_delta_2: curve.G2.toObject(zkey.vk_delta_2), - - vk_alphabeta_12: curve.Gt.toObject(alphaBeta) - }; - - // Read IC Section - /////////// - await startReadUniqueSection$1(fd, sections, 3); - vKey.IC = []; - for (let i = 0; i <= zkey.nPublic; i++) { - const buff = await fd.read(sG1); - const P = curve.G1.toObject(buff); - vKey.IC.push(P); - } - await endReadSection$1(fd); - - vKey = stringifyBigInts$3(vKey); - - return vKey; -} - - -async function plonkVk(zkey) { - const curve = await getCurveFromQ(zkey.q); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - power: zkey.power, - - k1: curve.Fr.toObject(zkey.k1), - k2: curve.Fr.toObject(zkey.k2), - - Qm: curve.G1.toObject(zkey.Qm), - Ql: curve.G1.toObject(zkey.Ql), - Qr: curve.G1.toObject(zkey.Qr), - Qo: curve.G1.toObject(zkey.Qo), - Qc: curve.G1.toObject(zkey.Qc), - S1: curve.G1.toObject(zkey.S1), - S2: curve.G1.toObject(zkey.S2), - S3: curve.G1.toObject(zkey.S3), - - X_2: curve.G2.toObject(zkey.X_2), - - w: curve.Fr.toObject(curve.Fr.w[zkey.power]) - }; - - vKey = stringifyBigInts$3(vKey); - - return vKey; -} - -async function exportFFlonkVk(zkey, logger) { - const curve = await getCurveFromQ(zkey.q); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - power: zkey.power, - - k1: curve.Fr.toObject(zkey.k1), - k2: curve.Fr.toObject(zkey.k2), - - w: curve.Fr.toObject(curve.Fr.w[zkey.power]), - //wW: curve.Fr.toObject(curve.Fr.w[zkey.power + 1]), - w3: curve.Fr.toObject(zkey.w3), - w4: curve.Fr.toObject(zkey.w4), - w8: curve.Fr.toObject(zkey.w8), - wr: curve.Fr.toObject(zkey.wr), - - X_2: curve.G2.toObject(zkey.X_2), - - C0: curve.G1.toObject(zkey.C0), - }; - - return stringifyBigInts$3(vKey); -} - -/* - Copyright 2021 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const {unstringifyBigInts: unstringifyBigInts$6, stringifyBigInts: stringifyBigInts$2} = utils; - -async function fflonkExportSolidityVerifier(vk, templates, logger) { - if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER STARTED"); - - const curve = await getCurveFromName(vk.curve); - - // Precompute w3_2, w4_2 and w4_3 - let w3 = fromVkey(vk.w3); - vk.w3_2 = toVkey(curve.Fr.square(w3)); - - let w4 = fromVkey(vk.w4); - vk.w4_2 = toVkey(curve.Fr.square(w4)); - vk.w4_3 = toVkey(curve.Fr.mul(curve.Fr.square(w4), w4)); - - let w8 = fromVkey(vk.w8); - let acc = curve.Fr.one; - - for (let i = 1; i < 8; i++) { - acc = curve.Fr.mul(acc, w8); - vk["w8_" + i] = toVkey(acc); - } - - let template = templates[vk.protocol]; - - if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER FINISHED"); - - const {default: ejs} = await Promise.resolve().then(function () { return _virtual_ejs$1; }); - return ejs.render(template, vk); - - function fromVkey(str) { - const val = unstringifyBigInts$6(str); - return curve.Fr.fromObject(val); - } - - function toVkey(val) { - const str = curve.Fr.toObject(val); - return stringifyBigInts$2(str); - } -} - -// Not ready yet -// module.exports.generateVerifier_kimleeoh = generateVerifier_kimleeoh; - -async function exportSolidityVerifier(zKeyName, templates, logger) { - - const verificationKey = await zkeyExportVerificationKey(zKeyName, logger); - - if ("fflonk" === verificationKey.protocol) { - return fflonkExportSolidityVerifier(verificationKey, templates, logger); - } - - let template = templates[verificationKey.protocol]; - - const {default: ejs} = await Promise.resolve().then(function () { return _virtual_ejs$1; }); - - return ejs.render(template, verificationKey); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -var zkey = /*#__PURE__*/Object.freeze({ - __proto__: null, - beacon: beacon, - bellmanContribute: bellmanContribute, - contribute: phase2contribute, - exportBellman: phase2exportMPCParams, - exportJson: zkeyExportJson, - exportSolidityVerifier: exportSolidityVerifier, - exportVerificationKey: zkeyExportVerificationKey, - importBellman: phase2importMPCParams, - newZKey: newZKey, - verifyFromInit: phase2verifyFromInit, - verifyFromR1cs: phase2verifyFromR1cs -}); - -/* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - - -async function plonkSetup(r1csName, ptauName, zkeyName, logger) { - - if (globalThis.gc) {globalThis.gc();} - - const {fd: fdPTau, sections: sectionsPTau} = await readBinFile$1(ptauName, "ptau", 1, 1<<22, 1<<24); - const {curve, power} = await readPTauHeader(fdPTau, sectionsPTau); - const {fd: fdR1cs, sections: sectionsR1cs} = await readBinFile$1(r1csName, "r1cs", 1, 1<<22, 1<<24); - - const r1cs = await readR1csFd(fdR1cs, sectionsR1cs, {loadConstraints: true, loadCustomGates: true}); - - const sG1 = curve.G1.F.n8*2; - const G1 = curve.G1; - const sG2 = curve.G2.F.n8*2; - const Fr = curve.Fr; - const n8r = curve.Fr.n8; - - if (logger) logger.info("Reading r1cs"); - - const plonkConstraints = new BigArray(); - const plonkAdditions = new BigArray(); - let plonkNVars = r1cs.nVars; - - const nPublic = r1cs.nOutputs + r1cs.nPubInputs; - - await processConstraints(curve.Fr, r1cs, logger); - - if (globalThis.gc) {globalThis.gc();} - - const fdZKey = await createBinFile(zkeyName, "zkey", 1, 14, 1<<22, 1<<24); - - - if (r1cs.prime != curve.r) { - if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); - return -1; - } - - let cirPower = log2(plonkConstraints.length -1) +1; - if (cirPower < 3) cirPower = 3; // As the t polynomial is n+5 we need at least a power of 4 - const domainSize = 2 ** cirPower; - - if (logger) logger.info("Plonk constraints: " + plonkConstraints.length); - if (cirPower > power) { - if (logger) logger.error(`circuit too big for this power of tau ceremony. ${plonkConstraints.length} > 2**${power}`); - return -1; - } - - if (!sectionsPTau[12]) { - if (logger) logger.error("Powers of tau is not prepared."); - return -1; - } - - - const LPoints = new BigBuffer(domainSize*sG1); - const o = sectionsPTau[12][0].p + ((2 ** (cirPower)) -1)*sG1; - await fdPTau.readToBuffer(LPoints, 0, domainSize*sG1, o); - - const [k1, k2] = getK1K2(); - - const vk = {}; - - - await writeAdditions(3, "Additions"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(4, 0, "Amap"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(5, 1, "Bmap"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(6, 2, "Cmap"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(7, 3, "Qm"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(8, 4, "Ql"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(9, 5, "Qr"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(10, 6, "Qo"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(11, 7, "Qc"); - if (globalThis.gc) {globalThis.gc();} - await writeSigma(12, "sigma"); - if (globalThis.gc) {globalThis.gc();} - await writeLs(13, "lagrange polynomials"); - if (globalThis.gc) {globalThis.gc();} - - // Write PTau points - //////////// - - await startWriteSection(fdZKey, 14); - const buffOut = new BigBuffer((domainSize+6)*sG1); - await fdPTau.readToBuffer(buffOut, 0, (domainSize+6)*sG1, sectionsPTau[2][0].p); - await fdZKey.write(buffOut); - await endWriteSection(fdZKey); - if (globalThis.gc) {globalThis.gc();} - - - await writeHeaders(); - - await fdZKey.close(); - await fdR1cs.close(); - await fdPTau.close(); - - if (logger) logger.info("Setup Finished"); - - return ; - - async function processConstraints(Fr, r1cs, logger) { - - function normalize(linearComb) { - const ss = Object.keys(linearComb); - for (let i = 0; i < ss.length; i++) { - if (linearComb[ss[i]] == 0n) delete linearComb[ss[i]]; - } - } - - function join(linearComb1, k, linearComb2) { - const res = {}; - - for (let s in linearComb1) { - if (typeof res[s] == "undefined") { - res[s] = Fr.mul(k, linearComb1[s]); - } else { - res[s] = Fr.add(res[s], Fr.mul(k, linearComb1[s])); - } - } - - for (let s in linearComb2) { - if (typeof res[s] == "undefined") { - res[s] = linearComb2[s]; - } else { - res[s] = Fr.add(res[s], linearComb2[s]); - } - } - normalize(res); - return res; - } - - function reduceCoefs(linearComb, maxC) { - const res = { - k: Fr.zero, - s: [], - coefs: [] - }; - const cs = []; - - for (let s in linearComb) { - if (s == 0) { - res.k = Fr.add(res.k, linearComb[s]); - } else if (linearComb[s] != 0n) { - cs.push([Number(s), linearComb[s]]); - } - } - while (cs.length > maxC) { - const c1 = cs.shift(); - const c2 = cs.shift(); - - const sl = c1[0]; - const sr = c2[0]; - const so = plonkNVars++; - const qm = Fr.zero; - const ql = Fr.neg(c1[1]); - const qr = Fr.neg(c2[1]); - const qo = Fr.one; - const qc = Fr.zero; - - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - - plonkAdditions.push([sl, sr, c1[1], c2[1]]); - - cs.push([so, Fr.one]); - } - for (let i = 0; i < cs.length; i++) { - res.s[i] = cs[i][0]; - res.coefs[i] = cs[i][1]; - } - while (res.coefs.length < maxC) { - res.s.push(0); - res.coefs.push(Fr.zero); - } - return res; - } - - function addConstraintSum(lc) { - const C = reduceCoefs(lc, 3); - const sl = C.s[0]; - const sr = C.s[1]; - const so = C.s[2]; - const qm = Fr.zero; - const ql = C.coefs[0]; - const qr = C.coefs[1]; - const qo = C.coefs[2]; - const qc = C.k; - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - function addConstraintMul(lcA, lcB, lcC) { - const A = reduceCoefs(lcA, 1); - const B = reduceCoefs(lcB, 1); - const C = reduceCoefs(lcC, 1); - - - const sl = A.s[0]; - const sr = B.s[0]; - const so = C.s[0]; - const qm = Fr.mul(A.coefs[0], B.coefs[0]); - const ql = Fr.mul(A.coefs[0], B.k); - const qr = Fr.mul(A.k, B.coefs[0]); - const qo = Fr.neg(C.coefs[0]); - const qc = Fr.sub(Fr.mul(A.k, B.k), C.k); - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - function getLinearCombinationType(lc) { - let k = Fr.zero; - let n = 0; - const ss = Object.keys(lc); - for (let i = 0; i < ss.length; i++) { - if (lc[ss[i]] == 0n) { - delete lc[ss[i]]; - } else if (ss[i] == 0) { - k = Fr.add(k, lc[ss[i]]); - } else { - n++; - } - } - if (n > 0) return n.toString(); - if (k != Fr.zero) return "k"; - return "0"; - } - - function process(lcA, lcB, lcC) { - const lctA = getLinearCombinationType(lcA); - const lctB = getLinearCombinationType(lcB); - if ((lctA === "0") || (lctB === "0")) { - normalize(lcC); - addConstraintSum(lcC); - } else if (lctA === "k") { - const lcCC = join(lcB, lcA[0], lcC); - addConstraintSum(lcCC); - } else if (lctB === "k") { - const lcCC = join(lcA, lcB[0], lcC); - addConstraintSum(lcCC); - } else { - addConstraintMul(lcA, lcB, lcC); - } - } - - for (let s = 1; s <= nPublic; s++) { - const sl = s; - const sr = 0; - const so = 0; - const qm = Fr.zero; - const ql = Fr.one; - const qr = Fr.zero; - const qo = Fr.zero; - const qc = Fr.zero; - - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - for (let c = 0; c < r1cs.constraints.length; c++) { - if ((logger) && (c % 10000 === 0)) logger.debug(`processing constraints: ${c}/${r1cs.nConstraints}`); - process(...r1cs.constraints[c]); - } - } - - async function writeWitnessMap(sectionNum, posConstraint, name) { - await startWriteSection(fdZKey, sectionNum); - for (let i=0; i. -*/ - -class Proof { - constructor(curve, logger) { - this.curve = curve; - this.logger = logger; - - this.resetProof(); - } - - resetProof() { - this.polynomials = {}; - this.evaluations = {}; - } - - addPolynomial(key, polynomial) { - if (key in this.polynomials) { - this.logger.warn(`proof: polynomial.${key} already exist in proof`); - } - this.polynomials[key] = polynomial; - } - - getPolynomial(key) { - if (!(key in this.polynomials)) { - this.logger.warn(`proof: polynomial ${key} does not exist in proof`); - } - return this.polynomials[key]; - } - - addEvaluation(key, evaluation) { - if (key in this.evaluations) { - this.logger.warn(`proof: evaluations.${key} already exist in proof`); - } - this.evaluations[key] = evaluation; - } - - getEvaluation(key) { - if (!(key in this.evaluations)) { - this.logger.warn(`proof: evaluation ${key} does not exist in proof`); - } - return this.evaluations[key]; - } - - toObjectProof(splitFields = true) { - let res = splitFields ? {polynomials: {}, evaluations: {}} : {}; - - Object.keys(this.polynomials).forEach(key => { - const value = this.curve.G1.toObject(this.polynomials[key]); - if(splitFields) { - res.polynomials[key] = value; - } else { - res[key] = value; - } - }); - - Object.keys(this.evaluations).forEach(key => { - const value = this.curve.Fr.toObject(this.evaluations[key]); - if(splitFields) { - res.evaluations[key] = value; - } else { - res[key] = value; - } - }); - - return res; - } - - fromObjectProof(objectProof) { - this.resetProof(); - - Object.keys(objectProof.polynomials).forEach(key => { - this.polynomials[key] = this.curve.G1.fromObject(objectProof.polynomials[key]); - }); - - Object.keys(objectProof.evaluations).forEach(key => { - this.evaluations[key] = this.curve.Fr.fromObject(objectProof.evaluations[key]); - }); - } -} - -/** - * SHA3 (keccak) hash function, based on a new "Sponge function" design. - * Different from older hashes, the internal state is bigger than output size. - * - * Check out - * {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf | FIPS-202}, - * {@link https://keccak.team/keccak.html | Website}, and - * {@link https://crypto.stackexchange.com/q/15727 | the differences between - * SHA-3 and Keccak}. - * - * Check out `sha3-addons` module for cSHAKE, k12, and others. - * @module - */ -// No __PURE__ annotations in sha3 header: -// EVERYTHING is in fact used on every export. -// Various per round constants calculations -const _0n = BigInt(0); -const _1n = BigInt(1); -const _2n = BigInt(2); -const _7n = BigInt(7); -const _256n = BigInt(256); -// FIPS 202 Algorithm 5 rc(): when the outgoing bit is 1, the 8-bit LFSR xors -// taps 0, 4, 5, and 6, which compresses to the feedback mask `0x71`. -const _0x71n = BigInt(0x71); -const SHA3_PI = []; -const SHA3_ROTL = []; -const _SHA3_IOTA = []; // no pure annotation: var is always used -for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) { - // Pi - [x, y] = [y, (2 * x + 3 * y) % 5]; - SHA3_PI.push(2 * (5 * y + x)); - // Rotational - SHA3_ROTL.push((((round + 1) * (round + 2)) / 2) % 64); - // Iota - let t = _0n; - for (let j = 0; j < 7; j++) { - R = ((R << _1n) ^ ((R >> _7n) * _0x71n)) % _256n; - if (R & _2n) - t ^= _1n << ((_1n << BigInt(j)) - _1n); - } - _SHA3_IOTA.push(t); -} -const IOTAS = split(_SHA3_IOTA, true); -// `split(..., true)` keeps the local little-endian lane-word layout used by -// `state32`, so these `H` / `L` tables follow the file's first-word / -// second-word lane slots rather than `_u64.ts`'s usual high/low naming. -const SHA3_IOTA_H = IOTAS[0]; -const SHA3_IOTA_L = IOTAS[1]; -// Left rotation (without 0, 32, 64) -const rotlH = (h, l, s) => (s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s)); -const rotlL = (h, l, s) => (s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s)); -/** - * `keccakf1600` internal permutation, additionally allows adjusting the round count. - * @param s - 5x5 Keccak state encoded as 25 lanes split into 50 uint32 words - * in this file's local little-endian lane-word order - * @param rounds - number of rounds to execute - * @throws If `rounds` is outside the supported `1..24` range. {@link Error} - * @example - * Permute a Keccak state with the default 24 rounds. - * ```ts - * keccakP(new Uint32Array(50)); - * ``` - */ -function keccakP(s, rounds = 24) { - anumber(rounds, 'rounds'); - // This implementation precomputes only the standard Keccak-f[1600] 24-round Iota table. - if (rounds < 1 || rounds > 24) - throw new Error('"rounds" expected integer 1..24'); - const B = new Uint32Array(5 * 2); - // NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js) - for (let round = 24 - rounds; round < 24; round++) { - // Theta θ - for (let x = 0; x < 10; x++) - B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40]; - for (let x = 0; x < 10; x += 2) { - const idx1 = (x + 8) % 10; - const idx0 = (x + 2) % 10; - const B0 = B[idx0]; - const B1 = B[idx0 + 1]; - const Th = rotlH(B0, B1, 1) ^ B[idx1]; - const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1]; - for (let y = 0; y < 50; y += 10) { - s[x + y] ^= Th; - s[x + y + 1] ^= Tl; - } - } - // Rho (ρ) and Pi (π) - let curH = s[2]; - let curL = s[3]; - for (let t = 0; t < 24; t++) { - const shift = SHA3_ROTL[t]; - const Th = rotlH(curH, curL, shift); - const Tl = rotlL(curH, curL, shift); - const PI = SHA3_PI[t]; - curH = s[PI]; - curL = s[PI + 1]; - s[PI] = Th; - s[PI + 1] = Tl; - } - // Chi (χ) - // Same as: - // for (let x = 0; x < 10; x++) B[x] = s[y + x]; - // for (let x = 0; x < 10; x++) s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10]; - for (let y = 0; y < 50; y += 10) { - const b0 = s[y], b1 = s[y + 1], b2 = s[y + 2], b3 = s[y + 3]; - s[y] ^= ~s[y + 2] & s[y + 4]; - s[y + 1] ^= ~s[y + 3] & s[y + 5]; - s[y + 2] ^= ~s[y + 4] & s[y + 6]; - s[y + 3] ^= ~s[y + 5] & s[y + 7]; - s[y + 4] ^= ~s[y + 6] & s[y + 8]; - s[y + 5] ^= ~s[y + 7] & s[y + 9]; - s[y + 6] ^= ~s[y + 8] & b0; - s[y + 7] ^= ~s[y + 9] & b1; - s[y + 8] ^= ~b0 & b2; - s[y + 9] ^= ~b1 & b3; - } - // Iota (ι) - s[0] ^= SHA3_IOTA_H[round]; - s[1] ^= SHA3_IOTA_L[round]; - } - clean(B); -} -/** - * Keccak sponge function. - * @param blockLen - absorb/squeeze rate in bytes - * @param suffix - domain separation suffix byte - * @param outputLen - default digest length in bytes. This base sponge only - * requires a non-negative integer; wrappers that need positive output - * lengths must enforce that themselves. - * @param enableXOF - whether XOF output is allowed - * @param rounds - number of Keccak-f rounds - * @example - * Build a sponge state, absorb bytes, then finalize a digest. - * ```ts - * const hash = new Keccak(136, 0x06, 32); - * hash.update(new Uint8Array([1, 2, 3])); - * hash.digest(); - * ``` - */ -class Keccak { - state; - pos = 0; - posOut = 0; - finished = false; - state32; - destroyed = false; - blockLen; - suffix; - outputLen; - canXOF; - enableXOF = false; - rounds; - // NOTE: we accept arguments in bytes instead of bits here. - constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) { - this.blockLen = blockLen; - this.suffix = suffix; - this.outputLen = outputLen; - this.enableXOF = enableXOF; - this.canXOF = enableXOF; - this.rounds = rounds; - // Can be passed from user as dkLen - anumber(outputLen, 'outputLen'); - // 1600 = 5x5 matrix of 64bit. 1600 bits === 200 bytes - // 0 < blockLen < 200 - if (!(0 < blockLen && blockLen < 200)) - throw new Error('only keccak-f1600 function is supported'); - this.state = new Uint8Array(200); - this.state32 = u32(this.state); - } - clone() { - return this._cloneInto(); - } - keccak() { - swap32IfBE(this.state32); - keccakP(this.state32, this.rounds); - swap32IfBE(this.state32); - this.posOut = 0; - this.pos = 0; - } - update(data) { - aexists(this); - abytes(data); - const { blockLen, state } = this; - const len = data.length; - for (let pos = 0; pos < len;) { - const take = Math.min(blockLen - this.pos, len - pos); - for (let i = 0; i < take; i++) - state[this.pos++] ^= data[pos++]; - if (this.pos === blockLen) - this.keccak(); - } - return this; - } - finish() { - if (this.finished) - return; - this.finished = true; - const { state, suffix, pos, blockLen } = this; - // FIPS 202 appends the SHA3/SHAKE domain-separation suffix before pad10*1. - // These byte values already include the first padding bit, while the - // final `0x80` below supplies the closing `1` bit in the last rate byte. - state[pos] ^= suffix; - // If that combined suffix lands in the last rate byte and already sets - // bit 7, absorb it first so the final pad10*1 bit can be xored into a - // fresh block. - if ((suffix & 0x80) !== 0 && pos === blockLen - 1) - this.keccak(); - state[blockLen - 1] ^= 0x80; - this.keccak(); - } - writeInto(out) { - aexists(this, false); - abytes(out); - this.finish(); - const bufferOut = this.state; - const { blockLen } = this; - for (let pos = 0, len = out.length; pos < len;) { - if (this.posOut >= blockLen) - this.keccak(); - const take = Math.min(blockLen - this.posOut, len - pos); - out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos); - this.posOut += take; - pos += take; - } - return out; - } - xofInto(out) { - // Plain SHA3/Keccak usage with XOF is probably a mistake, but this base - // class is also reused by SHAKE/cSHAKE/KMAC/TupleHash/ParallelHash/ - // TurboSHAKE/KangarooTwelve wrappers that intentionally enable XOF. - if (!this.enableXOF) - throw new Error('XOF is not possible for this instance'); - return this.writeInto(out); - } - xof(bytes) { - anumber(bytes); - return this.xofInto(new Uint8Array(bytes)); - } - digestInto(out) { - aoutput(out, this); - if (this.finished) - throw new Error('digest() was already called'); - // `aoutput(...)` allows oversized buffers; digestInto() must fill only the advertised digest. - this.writeInto(out.subarray(0, this.outputLen)); - this.destroy(); - } - digest() { - const out = new Uint8Array(this.outputLen); - this.digestInto(out); - return out; - } - destroy() { - this.destroyed = true; - clean(this.state); - } - _cloneInto(to) { - const { blockLen, suffix, outputLen, rounds, enableXOF } = this; - to ||= new Keccak(blockLen, suffix, outputLen, enableXOF, rounds); - // Reused destinations can come from a different rate/capacity variant, so clone must rewrite - // the sponge geometry as well as the state words. - to.blockLen = blockLen; - to.state32.set(this.state32); - to.pos = this.pos; - to.posOut = this.posOut; - to.finished = this.finished; - to.rounds = rounds; - // Suffix can change in cSHAKE - to.suffix = suffix; - to.outputLen = outputLen; - to.enableXOF = enableXOF; - // Clones must preserve the public capability bit too; `_KMAC` reuses this path and deep clone - // tests compare instance fields directly, so leaving `canXOF` behind makes the clone lie. - to.canXOF = this.canXOF; - to.destroyed = this.destroyed; - return to; - } -} -const genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info); -/** - * Keccak-256 hash function. Different from SHA3-256. - * @param msg - message bytes to hash - * @returns Digest bytes. - * @example - * Hash a message with Keccak-256. - * ```ts - * keccak_256(new Uint8Array([97, 98, 99])); - * ``` - */ -const keccak_256 = /* @__PURE__ */ genKeccak(0x01, 136, 32); - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const POLYNOMIAL = 0; -const SCALAR = 1; - -class Keccak256Transcript { - constructor(curve) { - this.G1 = curve.G1; - this.Fr = curve.Fr; - - this.reset(); - } - - reset() { - this.data = []; - } - - addPolCommitment(polynomialCommitment) { - this.data.push({type: POLYNOMIAL, data: polynomialCommitment}); - } - - addScalar(scalar) { - this.data.push({type: SCALAR, data: scalar}); - } - - getChallenge() { - if(0 === this.data.length) { - throw new Error("Keccak256Transcript: No data to generate a transcript"); - } - - let nPolynomials = 0; - let nScalars = 0; - - this.data.forEach(element => POLYNOMIAL === element.type ? nPolynomials++ : nScalars++); - - let buffer = new Uint8Array(nScalars * this.Fr.n8 + nPolynomials * this.G1.F.n8 * 2); - let offset = 0; - - for (let i = 0; i < this.data.length; i++) { - if (POLYNOMIAL === this.data[i].type) { - this.G1.toRprUncompressed(buffer, offset, this.data[i].data); - offset += this.G1.F.n8 * 2; - } else { - this.Fr.toRprBE(buffer, offset, this.data[i].data); - offset += this.Fr.n8; - } - } - - const value = Scalar.fromRprBE(keccak_256(buffer)); - return this.Fr.e(value); - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -class MulZ { - static getZ1(Fr) { - return [ - Fr.zero, - Fr.add(Fr.e(-1), Fr.w[2]), - Fr.e(-2), - Fr.sub(Fr.e(-1), Fr.w[2]), - ]; - } - - static getZ2(Fr) { - return [ - Fr.zero, - Fr.add(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), - Fr.e(4), - Fr.sub(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), - ]; - } - - static getZ3(Fr) { - return [ - Fr.zero, - Fr.add(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), - Fr.e(-8), - Fr.sub(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), - ]; - - } - - static mul2(a, b, ap, bp, p, Fr) { - const Z1 = this.getZ1(Fr); - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - r = a_b; - - let a0 = Fr.add(a_bp, ap_b); - - let a1 = ap_bp; - - rz = a0; - if (p) { - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - } - - return [r, rz]; - } - - static mul3(a, b, c, ap, bp, cp, p, Fr) { - const Z1 = this.getZ1(Fr); - const Z2 = this.getZ2(Fr); - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - r = Fr.mul(a_b, c); - - let a0 = Fr.mul(ap_b, c); - a0 = Fr.add(a0, Fr.mul(a_bp, c)); - a0 = Fr.add(a0, Fr.mul(a_b, cp)); - - let a1 = Fr.mul(ap_bp, c); - a1 = Fr.add(a1, Fr.mul(a_bp, cp)); - a1 = Fr.add(a1, Fr.mul(ap_b, cp)); - - rz = a0; - if (p) { - const a2 = Fr.mul(ap_bp, cp); - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - rz = Fr.add(rz, Fr.mul(Z2[p], a2)); - } - - return [r, rz]; - } - - static mul4(a, b, c, d, ap, bp, cp, dp, p, Fr) { - const Z1 = this.getZ1(Fr); - const Z2 = this.getZ2(Fr); - const Z3 = this.getZ3(Fr); - - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - const c_d = Fr.mul(c, d); - const c_dp = Fr.mul(c, dp); - const cp_d = Fr.mul(cp, d); - const cp_dp = Fr.mul(cp, dp); - - r = Fr.mul(a_b, c_d); - - let a0 = Fr.mul(ap_b, c_d); - a0 = Fr.add(a0, Fr.mul(a_bp, c_d)); - a0 = Fr.add(a0, Fr.mul(a_b, cp_d)); - a0 = Fr.add(a0, Fr.mul(a_b, c_dp)); - - let a1 = Fr.mul(ap_bp, c_d); - a1 = Fr.add(a1, Fr.mul(ap_b, cp_d)); - a1 = Fr.add(a1, Fr.mul(ap_b, c_dp)); - a1 = Fr.add(a1, Fr.mul(a_bp, cp_d)); - a1 = Fr.add(a1, Fr.mul(a_bp, c_dp)); - a1 = Fr.add(a1, Fr.mul(a_b, cp_dp)); - - let a2 = Fr.mul(a_bp, cp_dp); - a2 = Fr.add(a2, Fr.mul(ap_b, cp_dp)); - a2 = Fr.add(a2, Fr.mul(ap_bp, c_dp)); - a2 = Fr.add(a2, Fr.mul(ap_bp, cp_d)); - - let a3 = Fr.mul(ap_bp, cp_dp); - - rz = a0; - if (p) { - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - rz = Fr.add(rz, Fr.mul(Z2[p], a2)); - rz = Fr.add(rz, Fr.mul(Z3[p], a3)); - } - - return [r, rz]; - } -} - -const ZKEY_PL_ADDITIONS_SECTION = 3; -const ZKEY_PL_A_MAP_SECTION = 4; -const ZKEY_PL_B_MAP_SECTION = 5; -const ZKEY_PL_C_MAP_SECTION = 6; -const ZKEY_PL_QM_SECTION = 7; -const ZKEY_PL_QL_SECTION = 8; -const ZKEY_PL_QR_SECTION = 9; -const ZKEY_PL_QO_SECTION = 10; -const ZKEY_PL_QC_SECTION = 11; -const ZKEY_PL_SIGMA_SECTION = 12; -const ZKEY_PL_LAGRANGE_SECTION = 13; -const ZKEY_PL_PTAU_SECTION = 14; - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -class Polynomial { - constructor(coefficients, curve, logger) { - this.coef = coefficients; - this.curve = curve; - this.Fr = curve.Fr; - this.G1 = curve.G1; - this.logger = logger; - } - - static async fromEvaluations(buffer, curve, logger) { - let coefficients = await curve.Fr.ifft(buffer); - - return new Polynomial(coefficients, curve, logger); - } - - static fromCoefficientsArray(array, curve, logger) { - const Fr = curve.Fr; - let buff = array.length > 2 << 14 ? - new BigBuffer(array.length * Fr.n8) : new Uint8Array(array.length * Fr.n8); - for (let i = 0; i < array.length; i++) buff.set(array[i], i * Fr.n8); - - return new Polynomial(buff, curve, logger); - } - - static fromPolynomial(polynomial, curve, logger) { - let length = polynomial.length(); - let Fr = curve.Fr; - - let buff = length > 2 << 14 ? - new BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - buff.set(polynomial.coef.slice(), 0); - - return new Polynomial(buff, curve, logger); - } - - isEqual(polynomial) { - const degree = this.degree(); - if (degree !== polynomial.degree()) return false; - - for (let i = 0; i < degree + 1; i++) { - if (!this.Fr.eq(this.getCoef(i), polynomial.getCoef(i))) return false; - } - - return true; - } - - blindCoefficients(blindingFactors) { - blindingFactors = blindingFactors || []; - - const blindedCoefficients = (this.length() + blindingFactors.length) > 2 << 14 ? - new BigBuffer((this.length() + blindingFactors.length) * this.Fr.n8) : - new Uint8Array((this.length() + blindingFactors.length) * this.Fr.n8); - - blindedCoefficients.set(this.coef, 0); - for (let i = 0; i < blindingFactors.length; i++) { - blindedCoefficients.set( - this.Fr.add( - blindedCoefficients.slice((this.length() + i) * this.Fr.n8, (this.length() + i + 1) * this.Fr.n8), - blindingFactors[i] - ), - (this.length() + i) * this.Fr.n8 - ); - blindedCoefficients.set( - this.Fr.sub( - blindedCoefficients.slice(i * this.Fr.n8, (i + 1) * this.Fr.n8), - blindingFactors[i] - ), - i * this.Fr.n8 - ); - } - this.coef = blindedCoefficients; - } - - getCoef(index) { - const i_n8 = index * this.Fr.n8; - - if (i_n8 + this.Fr.n8 > this.coef.byteLength) return this.Fr.zero; - - return this.coef.slice(i_n8, i_n8 + this.Fr.n8); - } - - setCoef(index, value) { - if (index > (this.length() - 1)) { - throw new Error("Coef index is not available"); - } - - this.coef.set(value, index * this.Fr.n8); - } - - static async to4T(buffer, domainSize, blindingFactors, Fr) { - blindingFactors = blindingFactors || []; - let a = await Fr.ifft(buffer); - - const a4 = (domainSize * 4) > 2 << 14 ? - new BigBuffer(domainSize * 4 * Fr.n8) : new Uint8Array(domainSize * 4 * Fr.n8); - a4.set(a, 0); - - const A4 = await Fr.fft(a4); - - if (blindingFactors.length === 0) { - return [a, A4]; - } - - const a1 = domainSize + blindingFactors.length > 2 << 14 ? - new BigBuffer((domainSize + blindingFactors.length) * Fr.n8) : - new Uint8Array((domainSize + blindingFactors.length) * Fr.n8); - - a1.set(a, 0); - for (let i = 0; i < blindingFactors.length; i++) { - a1.set( - Fr.add( - a1.slice((domainSize + i) * Fr.n8, (domainSize + i + 1) * Fr.n8), - blindingFactors[i] - ), - (domainSize + i) * Fr.n8 - ); - a1.set( - Fr.sub( - a1.slice(i * Fr.n8, (i + 1) * Fr.n8), - blindingFactors[i] - ), - i * Fr.n8 - ); - } - - return [a1, A4]; - } - - length() { - let length = this.coef.byteLength / this.Fr.n8; - if (length !== Math.floor(this.coef.byteLength / this.Fr.n8)) { - throw new Error("Polynomial coefficients buffer has incorrect size"); - } - if (0 === length) { - if (this.logger) { - this.logger.warn("Polynomial has length zero"); - } - } - return length; - } - - degree() { - for (let i = this.length() - 1; i > 0; i--) { - const i_n8 = i * this.Fr.n8; - if (!this.Fr.eq(this.Fr.zero, this.coef.slice(i_n8, i_n8 + this.Fr.n8))) { - return i; - } - } - - return 0; - } - - evaluate(point) { - let res = this.Fr.zero; - - for (let i = this.degree() + 1; i > 0; i--) { - let i_n8 = i * this.Fr.n8; - const currentCoefficient = this.coef.slice(i_n8 - this.Fr.n8, i_n8); - res = this.Fr.add(currentCoefficient, this.Fr.mul(res, point)); - } - - return res; - } - - fastEvaluate(point) { - const Fr = this.Fr; - let nThreads = 3; - - let nCoefs = this.degree() + 1; - let coefsThread = parseInt(nCoefs / nThreads); - let residualCoefs = nCoefs - coefsThread * nThreads; - - let res = []; - let xN = []; - - xN[0] = Fr.one; - - for (let i = 0; i < nThreads; i++) { - res[i] = Fr.zero; - - let nCoefs = i === (nThreads - 1) ? coefsThread + residualCoefs : coefsThread; - for (let j = nCoefs; j > 0; j--) { - res[i] = Fr.add(this.getCoef((i * coefsThread) + j - 1), Fr.mul(res[i], point)); - - if (i === 0) xN[0] = Fr.mul(xN[0], point); - } - } - - for (let i = 1; i < nThreads; i++) { - res[0] = Fr.add(res[0], Fr.mul(xN[i - 1], res[i])); - xN[i] = Fr.mul(xN[i - 1], xN[0]); - } - - return res[0]; - } - - add(polynomial, blindingValue) { - let other = false; - - if (polynomial.length() > this.length()) { - other = true; - } - - const thisLength = this.length(); - const polyLength = polynomial.length(); - for (let i = 0; i < Math.max(thisLength, polyLength); i++) { - const i_n8 = i * this.Fr.n8; - - const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - - if (blindingValue !== undefined) { - b = this.Fr.mul(b, blindingValue); - } - if (other) { - polynomial.coef.set(this.Fr.add(a, b), i_n8); - } else { - this.coef.set(this.Fr.add(a, b), i_n8); - } - } - if (other) { - delete this.coef; - this.coef = polynomial.coef; - } - } - - sub(polynomial, blindingValue) { - let other = false; - - if (polynomial.length() > this.length()) { - other = true; - } - - const thisLength = this.length(); - const polyLength = polynomial.length(); - for (let i = 0; i < Math.max(thisLength, polyLength); i++) { - const i_n8 = i * this.Fr.n8; - - const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - - if (blindingValue !== undefined) { - b = this.Fr.mul(b, blindingValue); - } - if (other) { - polynomial.coef.set(this.Fr.sub(a, b), i_n8); - } else { - this.coef.set(this.Fr.sub(a, b), i_n8); - } - } - if (other) { - delete this.coef; - this.coef = polynomial.coef; - } - } - - mulScalar(value) { - for (let i = 0; i < this.length(); i++) { - const i_n8 = i * this.Fr.n8; - - this.coef.set(this.Fr.mul(this.coef.slice(i_n8, i_n8 + this.Fr.n8), value), i_n8); - } - } - - addScalar(value) { - const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); - this.coef.set(this.Fr.add(currentValue, value), 0); - } - - subScalar(value) { - const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); - this.coef.set(this.Fr.sub(currentValue, value), 0); - } - - // Multiply current polynomial by the polynomial (X - value) - byXSubValue(value) { - const Fr = this.Fr; - const resize = !Fr.eq(Fr.zero, this.getCoef(this.length() - 1)); - - const length = resize ? this.length() + 1 : this.length(); - const buff = length > 2 << 14 ? new BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - let pol = new Polynomial(buff, this.curve, this.logger); - - // Step 0: Set current coefficients to the new buffer shifted one position - pol.coef.set(this.coef.slice(0, (length - 1) * Fr.n8), 32); - - // Step 1: multiply each coefficient by (-value) - this.mulScalar(Fr.neg(value)); - - // Step 2: Add current polynomial to destination polynomial - pol.add(this); - - // Swap buffers - this.coef = pol.coef; - } - - // Multiply current polynomial by the polynomial (X^n + value) - byXNSubValue(n, value) { - const Fr = this.Fr; - const resize = !(this.length() - n - 1 >= this.degree()); - - const length = resize ? this.length() + n : this.length(); - const buff = length > 2 << 14 ? new BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - let pol = new Polynomial(buff, this.curve, this.logger); - - // Step 0: Set current coefficients to the new buffer shifted one position - pol.coef.set(this.coef.slice(0, (this.degree() + 1) * 32, ), n * 32); - - // Step 1: multiply each coefficient by (- value) - this.mulScalar(value); - - // Step 2: Add current polynomial to destination polynomial - pol.add(this); - - // Swap buffers - this.coef = pol.coef; - } - - // Euclidean division - divBy(polynomial) { - const Fr = this.Fr; - const degreeA = this.degree(); - const degreeB = polynomial.degree(); - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - for (let i = degreeA - degreeB; i >= 0; i--) { - this.setCoef(i, Fr.div(polR.getCoef(i + degreeB), polynomial.getCoef(degreeB))); - for (let j = 0; j <= degreeB; j++) { - polR.setCoef(i + j, Fr.sub(polR.getCoef(i + j), Fr.mul(this.getCoef(i), polynomial.getCoef(j)))); - } - } - - return polR; - } - - // Division by a Polynomial of the form (x^m - beta) - divByMonic(m, beta) { - const Fr = this.Fr; - - let d = this.degree(); - - let buffer = this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - let quotient = new Polynomial(buffer, this.curve, this.logger); - - let bArr = []; - - // Add the m leading coefficients of this to quotient - for (let i = 0; i < m; i++) { - quotient.setCoef((d - i) - m, this.getCoef(d - i)); - bArr[i] = this.getCoef(d - i); - } - - let nThreads = m; - for (let k = 0; k < nThreads; k++) { - for (let i = d - 2 * m - k; i >= 0; i = i - nThreads) { - if (i < 0) break; - let idx = k; - bArr[idx] = Fr.add(this.getCoef(i + m), Fr.mul(bArr[idx], beta)); - - quotient.setCoef(i, bArr[idx]); - } - } - - this.coef = quotient.coef; - } - - divByVanishing(n, beta) { - if (this.degree() < n) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - const Fr = this.Fr; - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - for (let i = this.length() - 1; i >= n; i--) { - let leadingCoef = polR.getCoef(i); - if (Fr.eq(Fr.zero, leadingCoef)) continue; - - polR.setCoef(i, Fr.zero); - polR.setCoef(i - n, Fr.add(polR.getCoef(i - n), Fr.mul(beta, leadingCoef))); - this.setCoef(i - n, Fr.add(this.getCoef(i - n), leadingCoef)); - } - - return polR; - } - - divByVanishing2(m, beta) { - if (this.degree() < m) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - const Fr = this.Fr; - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - let nThreads = 3; - let nTotal = this.length() - m; - let nElementsChunk = Math.floor(nTotal / nThreads); - let nElementsLast = nTotal - (nThreads - 1) * nElementsChunk; - - console.log(nTotal); - console.log(nElementsChunk + " " + nElementsLast); - for (let k = 0; k < nThreads; k++) { - console.log("> Thread " + k); - for (let i = (k === 0 ? nElementsLast : nElementsChunk); i > 0; i--) { - let idxDst = i - 1; - if (k !== 0) idxDst += (k - 1) * nElementsChunk + nElementsLast; - let idxSrc = idxDst + m; - - let leadingCoef = polR.getCoef(idxSrc); - if (Fr.eq(Fr.zero, leadingCoef)) continue; - - polR.setCoef(idxSrc, Fr.zero); - polR.setCoef(idxDst, Fr.add(polR.getCoef(idxDst), Fr.mul(beta, leadingCoef))); - this.setCoef(idxDst, Fr.add(this.getCoef(idxDst), leadingCoef)); - console.log(idxDst + " <-- " + idxSrc); - } - } - - this.print(); - return polR; - } - - fastDivByVanishing(data) { - const Fr = this.Fr; - - for (let i = 0; i < data.length; i++) { - - let m = data[i][0]; - let beta = data[i][1]; - - if (this.degree() < m) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - let nThreads = 5; - let nElements = this.length() - m; - let nElementsBucket = Math.floor(nElements / nThreads / m); - let nElementsChunk = nElementsBucket * m; - let nElementsLast = nElements - nThreads * nElementsChunk; - - //In C++ implementation this buffer will be allocated only once outside the loop - let polTmp = new Polynomial(this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8), this.curve, this.logger); - - let ptr = this.coef; - this.coef = polTmp.coef; - polTmp.coef = ptr; - - // STEP 1: Setejar els m valors del següent bucket al chunk actual, PARALEL·LITZAR - for (let k = 0; k < nThreads; k++) { - let idx0 = (k + 1) * nElementsChunk + nElementsLast; - for (let i = 0; i < m; i++) { - this.setCoef(idx0 + i - m, polTmp.getCoef(idx0 + i)); - } - - for (let i = 0; i < nElementsChunk - m; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); - this.setCoef(offset - m, val); - } - } - - //STEP 2: Setejar els valors del elements last NO PARAL·LELITZAR - let idx0 = nElementsLast; - let pending = nElementsLast; - for (let i = 0; i < m && pending; i++) { - this.setCoef(idx0 - i - 1, polTmp.getCoef(idx0 + m - i - 1)); - pending--; - } - - for (let i = 0; i < pending; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); - this.setCoef(offset - m, val); - } - - //Step 3: calcular acumulats NO PARALEL·LITZAR - - let acc = []; - let betaPow = Fr.one; - for (let i = 0; i < nElementsBucket; i++) { - betaPow = Fr.mul(betaPow, beta); - } - let currentBeta = Fr.one; - - for (let k = nThreads; k > 0; k--) { - let idThread = k - 1; - let idx0 = idThread * nElementsChunk + nElementsLast; - acc[idThread] = []; - - for (let i = 0; i < m; i++) { - acc[idThread][i] = this.getCoef(idx0 + i); - - if (k !== nThreads) { - acc[idThread][i] = Fr.add(acc[idThread][i], Fr.mul(betaPow, acc[idThread + 1][i])); - } - } - currentBeta = Fr.mul(currentBeta, betaPow); - } - - //STEP 4 recalcular PARALEL·LITZAR - for (let k = 0; k < nThreads; k++) { - - let idx0 = k * nElementsChunk + nElementsLast; - let currentBeta = beta; //Quan hopassem a C++ i ho paralelitzem aquesta variable ha de ser privada - let currentM = m - 1; - - let limit = k === 0 ? nElementsLast : nElementsChunk; - for (let i = 0; i < limit; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(this.getCoef(offset), Fr.mul(currentBeta, acc[k][currentM])); - - this.setCoef(offset, val); - - // To avoid modular operations in each loop... - if (currentM === 0) { - currentM = m - 1; - currentBeta = Fr.mul(currentBeta, beta); - } else { - currentM--; - } - } - } - } - } - - - // Divide polynomial by X - value - divByXSubValue(value) { - const coefs = this.length() > 2 << 14 ? - new BigBuffer(this.length() * this.Fr.n8) : new Uint8Array(this.length() * this.Fr.n8); - - coefs.set(this.Fr.zero, (this.length() - 1) * this.Fr.n8); - coefs.set(this.coef.slice((this.length() - 1) * this.Fr.n8, this.length() * this.Fr.n8), (this.length() - 2) * this.Fr.n8); - for (let i = this.length() - 3; i >= 0; i--) { - let i_n8 = i * this.Fr.n8; - coefs.set( - this.Fr.add( - this.coef.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8), - this.Fr.mul(value, coefs.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8)) - ), - i * this.Fr.n8 - ); - } - if (!this.Fr.eq( - this.coef.slice(0, this.Fr.n8), - this.Fr.mul(this.Fr.neg(value), coefs.slice(0, this.Fr.n8)) - )) { - throw new Error("Polynomial does not divide"); - } - - this.coef = coefs; - } - - divZh(domainSize, extensions = 4) { - for (let i = 0; i < domainSize; i++) { - const i_n8 = i * this.Fr.n8; - this.coef.set(this.Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)), i_n8); - } - - const upperBound = this.coef.byteLength / this.Fr.n8; - for (let i = domainSize; i < upperBound; i++) { - const i_n8 = i * this.Fr.n8; - - const a = this.Fr.sub( - this.coef.slice((i - domainSize) * this.Fr.n8, (i - domainSize) * this.Fr.n8 + this.Fr.n8), - this.coef.slice(i_n8, i_n8 + this.Fr.n8) - ); - this.coef.set(a, i_n8); - if (i > (domainSize * (extensions-1) - extensions)) { - if (!this.Fr.isZero(a)) { - throw new Error("Polynomial is not divisible"); - } - } - } - - return this; - } - - divByZerofier(n, beta) { - let Fr = this.Fr; - const invBeta = Fr.inv(beta); - const invBetaNeg = Fr.neg(invBeta); - - let isOne = Fr.eq(Fr.one, invBetaNeg); - let isNegOne = Fr.eq(Fr.negone, invBetaNeg); - - if (!isOne) { - for (let i = 0; i < n; i++) { - const i_n8 = i * this.Fr.n8; - let element; - - // If invBetaNeg === -1 we'll save a multiplication changing it by a neg function call - if (isNegOne) { - element = Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)); - } else { - element = Fr.mul(invBetaNeg, this.coef.slice(i_n8, i_n8 + this.Fr.n8)); - } - - this.coef.set(element, i_n8); - } - } - - isOne = Fr.eq(Fr.one, invBeta); - isNegOne = Fr.eq(Fr.negone, invBeta); - - for (let i = n; i < this.length(); i++) { - const i_n8 = i * this.Fr.n8; - const i_prev_n8 = (i - n) * this.Fr.n8; - - let element = this.Fr.sub( - this.coef.slice(i_prev_n8, i_prev_n8 + this.Fr.n8), - this.coef.slice(i_n8, i_n8 + this.Fr.n8) - ); - - // If invBeta === 1 we'll not do anything - if(!isOne) { - // If invBeta === -1 we'll save a multiplication changing it by a neg function call - if(isNegOne) { - element = Fr.neg(element); - } else { - element = Fr.mul(invBeta, element); - } - } - - this.coef.set(element, i_n8); - - // Check if polynomial is divisible by checking if n high coefficients are zero - if (i > this.length() - n - 1) { - if (!this.Fr.isZero(element)) { - throw new Error("Polynomial is not divisible"); - } - } - } - - return this; - } - - // function divideByVanishing(f, n, p) { - // // polynomial division f(X) / (X^n - 1) with remainder - // // very cheap, 0 multiplications - // // strategy: - // // start with q(X) = 0, r(X) = f(X) - // // then start changing q, r while preserving the identity: - // // f(X) = q(X) * (X^n - 1) + r(X) - // // in every step, move highest-degree term of r into the product - // // => r eventually has degree < n and we're done - // let q = Array(f.length).fill(0n); - // let r = [...f]; - // for (let i = f.length - 1; i >= n; i--) { - // let leadingCoeff = r[i]; - // if (leadingCoeff === 0n) continue; - // r[i] = 0n; - // r[i - n] = mod(r[i - n] + leadingCoeff, p); - // q[i - n] = mod(q[i - n] + leadingCoeff, p); - // } - // return [q, r]; - // } - - byX() { - const coefs = (this.length() + 1) > 2 << 14 ? - new BigBuffer(this.coef.byteLength + this.Fr.n8) : new Uint8Array(this.coef.byteLength + this.Fr.n8); - coefs.set(this.Fr.zero, 0); - coefs.set(this.coef, this.Fr.n8); - - this.coef = coefs; - } - - // Compute a new polynomial f(x^n) from f(x) - // f(x) = a_0 + a_1·x + a_2·x^2 + ... + a_j·x^j - // f(x^n) = a_0 + a_1·x^n + a_2·x^2n + ... + a_j·x^jn - static - async expX(polynomial, n, truncate = false) { - const Fr = polynomial.Fr; - - if (n < 1) { - // n == 0 not allowed because it has no sense, but if it's necessary we have to return - // a zero degree polynomial with a constant coefficient equals to the sum of all the original coefficients - throw new Error("Compute a new polynomial to a zero or negative number is not allowed"); - } else if (1 === n) { - return await Polynomial.fromEvaluations(polynomial.coef, polynomial.curve, polynomial.logger); - } - - // length is the length of non-constant coefficients - // if truncate === true, the highest zero coefficients (if exist) will be removed - const length = truncate ? polynomial.degree() : (polynomial.length() - 1); - const bufferDst = (length * n + 1) > 2 << 14 ? - new BigBuffer((length * n + 1) * Fr.n8) : new Uint8Array((length * n + 1) * Fr.n8); - - // Copy constant coefficient as is because is not related to x - bufferDst.set(polynomial.getCoef(0), 0); - - for (let i = 1; i <= length; i++) { - const i_sFr = i * Fr.n8; - - const coef = polynomial.getCoef(i); - bufferDst.set(coef, i_sFr * n); - } - - return new Polynomial(bufferDst, polynomial.curve, polynomial.logger); - } - - split(numPols, degPols, blindingFactors) { - if (numPols < 1) { - throw new Error(`Polynomials can't be split in ${numPols} parts`); - } else if (1 === numPols) { - return [this]; - } - - //blinding factors can be void or must have a length of numPols - 1 - if (0 !== blindingFactors.length && blindingFactors.length < numPols - 1) { - throw new Error(`Blinding factors length must be ${numPols - 1}`); - } - - const chunkByteLength = (degPols + 1) * this.Fr.n8; - let res = []; - - // Check polynomial can be split in numChunks parts of chunkSize bytes... - const numRealPols = Math.ceil((this.degree() + 1) * this.Fr.n8 / chunkByteLength); - if (numRealPols < numPols) { - //throw new Error(`Polynomial is short to be split in ${numPols} parts of ${degPols} coefficients each.`); - for (let i = numRealPols; i < numPols; i++) { - res[i] = new Polynomial(new Uint8Array(this.Fr.n8), this.curve, this.logger); - } - } - - numPols = Math.min(numPols, numRealPols); - for (let i = 0; i < numPols; i++) { - const isLast = (numPols - 1) === i; - const byteLength = isLast ? this.coef.byteLength - ((numPols - 1) * chunkByteLength) : chunkByteLength + this.Fr.n8; - - let buff = (byteLength / this.Fr.n8) > 2 << 14 ? new BigBuffer(byteLength) : new Uint8Array(byteLength); - res[i] = new Polynomial(buff, this.curve, this.logger); - - const fr = i * chunkByteLength; - const to = isLast ? this.coef.byteLength : (i + 1) * chunkByteLength; - res[i].coef.set(this.coef.slice(fr, to), 0); - - // Add a blinding factor as higher degree - if (!isLast) { - res[i].coef.set(blindingFactors[i], chunkByteLength); - } - - // Sub blinding factor to the lowest degree - if (0 !== i) { - const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); - res[i].coef.set(lowestDegree, 0); - } - - if (isLast) { - res[i].truncate(); - } - } - - return res; - - // // compute t_low(X) - // let polTLow = new BigBuffer((chunkSize + 1) * n8r); - // polTLow.set(t.slice(0, zkey.domainSize * n8r), 0); - // // Add blinding scalar b_10 as a new coefficient n - // polTLow.set(ch.b[10], zkey.domainSize * n8r); - // - // // compute t_mid(X) - // let polTMid = new BigBuffer((zkey.domainSize + 1) * n8r); - // polTMid.set(t.slice(zkey.domainSize * n8r, zkey.domainSize * 2 * n8r), 0); - // // Subtract blinding scalar b_10 to the lowest coefficient of t_mid - // const lowestMid = Fr.sub(polTMid.slice(0, n8r), ch.b[10]); - // polTMid.set(lowestMid, 0); - // // Add blinding scalar b_11 as a new coefficient n - // polTMid.set(ch.b[11], zkey.domainSize * n8r); - // - // // compute t_high(X) - // let polTHigh = new BigBuffer((zkey.domainSize + 6) * n8r); - // polTHigh.set(t.slice(zkey.domainSize * 2 * n8r, (zkey.domainSize * 3 + 6) * n8r), 0); - // //Subtract blinding scalar b_11 to the lowest coefficient of t_high - // const lowestHigh = Fr.sub(polTHigh.slice(0, n8r), ch.b[11]); - // polTHigh.set(lowestHigh, 0); - // - // proof.T1 = await expTau(polTLow, "multiexp T1"); - // proof.T2 = await expTau(polTMid, "multiexp T2"); - // proof.T3 = await expTau(polTHigh, "multiexp T3"); - } - - // split2(degPols, blindingFactors) { - // let currentDegree = this.degree(); - // const numFilledPols = Math.ceil((currentDegree + 1) / (degPols + 1)); - // - // //blinding factors can be void or must have a length of numPols - 1 - // if (0 !== blindingFactors.length && blindingFactors.length < numFilledPols - 1) { - // throw new Error(`Blinding factors length must be ${numFilledPols - 1}`); - // } - // - // const chunkByteLength = (degPols + 1) * this.Fr.n8; - // - // // Check polynomial can be split in numChunks parts of chunkSize bytes... - // if (this.coef.byteLength / chunkByteLength <= numFilledPols - 1) { - // throw new Error(`Polynomial is short to be split in ${numFilledPols} parts of ${degPols} coefficients each.`); - // } - // - // let res = []; - // for (let i = 0; i < numFilledPols; i++) { - // const isLast = (numFilledPols - 1) === i; - // const byteLength = isLast ? (currentDegree + 1) * this.Fr.n8 - ((numFilledPols - 1) * chunkByteLength) : chunkByteLength + this.Fr.n8; - // - // res[i] = new Polynomial(new BigBuffer(byteLength), this.Fr, this.logger); - // const fr = i * chunkByteLength; - // const to = isLast ? (currentDegree + 1) * this.Fr.n8 : (i + 1) * chunkByteLength; - // res[i].coef.set(this.coef.slice(fr, to), 0); - // - // // Add a blinding factor as higher degree - // if (!isLast) { - // res[i].coef.set(blindingFactors[i], chunkByteLength); - // } - // - // // Sub blinding factor to the lowest degree - // if (0 !== i) { - // const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); - // res[i].coef.set(lowestDegree, 0); - // } - // } - // - // return res; - // } - - // merge(pols, overlap = true) { - // let length = 0; - // for (let i = 0; i < pols.length; i++) { - // length += pols[i].length(); - // } - // - // if (overlap) { - // length -= pols.length - 1; - // } - // - // let res = new Polynomial(new BigBuffer(length * this.Fr.n8)); - // for (let i = 0; i < pols.length; i++) { - // const byteLength = pols[i].coef.byteLength; - // if (0 === i) { - // res.coef.set(pols[i].coef, 0); - // } else { - // - // } - // } - // - // return res; - // } - - truncate() { - const deg = this.degree(); - if (deg + 1 < this.coef.byteLength / this.Fr.n8) { - const newCoefs = (deg + 1) > 2 << 14 ? - new BigBuffer((deg + 1) * this.Fr.n8) : new Uint8Array((deg + 1) * this.Fr.n8); - - newCoefs.set(this.coef.slice(0, (deg + 1) * this.Fr.n8), 0); - this.coef = newCoefs; - } - } - - static lagrangePolynomialInterpolation(xArr, yArr, curve) { - const Fr = curve.Fr; - let polynomial = computeLagrangePolynomial(0); - for (let i = 1; i < xArr.length; i++) { - polynomial.add(computeLagrangePolynomial(i)); - } - - return polynomial; - - function computeLagrangePolynomial(i) { - let polynomial; - - for (let j = 0; j < xArr.length; j++) { - if (j === i) continue; - - if (polynomial === undefined) { - let buff = (xArr.length) > 2 << 14 ? - new BigBuffer((xArr.length) * Fr.n8) : new Uint8Array((xArr.length) * Fr.n8); - polynomial = new Polynomial(buff, curve); - polynomial.setCoef(0, Fr.neg(xArr[j])); - polynomial.setCoef(1, Fr.one); - } else { - polynomial.byXSubValue(xArr[j]); - } - } - - let denominator = polynomial.evaluate(xArr[i]); - denominator = Fr.inv(denominator); - const mulFactor = Fr.mul(yArr[i], denominator); - - polynomial.mulScalar(mulFactor); - - return polynomial; - } - } - - static zerofierPolynomial(xArr, curve) { - const Fr = curve.Fr; - let buff = (xArr.length + 1) > 2 << 14 ? - new BigBuffer((xArr.length + 1) * Fr.n8) : new Uint8Array((xArr.length + 1) * Fr.n8); - let polynomial = new Polynomial(buff, curve); - - // Build a zerofier polynomial with the following form: - // zerofier(X) = (X-xArr[0])(X-xArr[1])...(X-xArr[n]) - polynomial.setCoef(0, Fr.neg(xArr[0])); - polynomial.setCoef(1, Fr.one); - - for (let i = 1; i < xArr.length; i++) { - polynomial.byXSubValue(xArr[i]); - } - - return polynomial; - } - - print() { - const Fr = this.Fr; - let res = ""; - for (let i = this.degree(); i >= 0; i--) { - const coef = this.getCoef(i); - if (!Fr.eq(Fr.zero, coef)) { - if (Fr.isNegative(coef)) { - res += " - "; - } else if (i !== this.degree()) { - res += " + "; - } - res += Fr.toString(coef); - if (i > 0) { - res += i > 1 ? "x^" + i : "x"; - } - } - } - console.log(res); - } - - async multiExponentiation(PTau, name) { - const n = this.coef.byteLength / this.Fr.n8; - const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); - const bm = await this.Fr.batchFromMontgomery(this.coef); - let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); - res = this.G1.toAffine(res); - return res; - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -class Evaluations { - constructor(evaluations, curve, logger) { - this.eval = evaluations; - this.curve = curve; - this.Fr = curve.Fr; - this.logger = logger; - } - - static async fromPolynomial(polynomial, extension, curve, logger) { - const coefficientsN = new BigBuffer(polynomial.length() * extension * curve.Fr.n8); - coefficientsN.set(polynomial.coef, 0); - - const evaluations = await curve.Fr.fft(coefficientsN); - - return new Evaluations(evaluations, curve, logger); - } - - getEvaluation(index) { - const i_n8 = index * this.Fr.n8; - - if (i_n8 + this.Fr.n8 > this.eval.byteLength) { - throw new Error("Evaluations.getEvaluation() out of bounds"); - } - - return this.eval.slice(i_n8, i_n8 + this.Fr.n8); - } - - length() { - let length = this.eval.byteLength / this.Fr.n8; - if (length !== Math.floor(this.eval.byteLength / this.Fr.n8)) { - throw new Error("Polynomial evaluations buffer has incorrect size"); - } - if (0 === length) { - this.logger.warn("Polynomial has length zero"); - } - return length; - } -} - -/* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const {stringifyBigInts: stringifyBigInts$1} = utils; - -async function plonk16Prove(zkeyFileName, witnessFileName, logger, options) { - const {fd: fdWtns, sections: sectionsWtns} = await readBinFile$1(witnessFileName, "wtns", 2, 1<<25, 1<<23); - - // Read witness file - if (logger) logger.debug("> Reading witness file"); - const wtns = await readHeader(fdWtns, sectionsWtns); - - // Read zkey file - if (logger) logger.debug("> Reading zkey file"); - const {fd: fdZKey, sections: zkeySections} = await readBinFile$1(zkeyFileName, "zkey", 2, 1<<25, 1<<23); - - const zkey = await readHeader$1(fdZKey, zkeySections, undefined, options); - if (zkey.protocol != "plonk") { - throw new Error("zkey file is not plonk"); - } - - if (!Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness != zkey.nVars -zkey.nAdditions) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); - } - - const curve = zkey.curve; - - const Fr = curve.Fr; - const n8r = curve.Fr.n8; - const sDomain = zkey.domainSize * n8r; - - if (logger) { - logger.debug("----------------------------"); - logger.debug(" PLONK PROVE SETTINGS"); - logger.debug(` Curve: ${curve.name}`); - logger.debug(` Circuit power: ${zkey.power}`); - logger.debug(` Domain size: ${zkey.domainSize}`); - logger.debug(` Vars: ${zkey.nVars}`); - logger.debug(` Public vars: ${zkey.nPublic}`); - logger.debug(` Constraints: ${zkey.nConstraints}`); - logger.debug(` Additions: ${zkey.nAdditions}`); - logger.debug("----------------------------"); - } - - //Read witness data - if (logger) logger.debug("> Reading witness file data"); - const buffWitness = await readSection$1(fdWtns, sectionsWtns, 2); - - // First element in plonk is not used and can be any value. (But always the same). - // We set it to zero to go faster in the exponentiations. - buffWitness.set(Fr.zero, 0); - const buffInternalWitness = new BigBuffer(n8r*zkey.nAdditions); - - let buffers = {}; - let polynomials = {}; - let evaluations = {}; - - let challenges = {}; - let proof = new Proof(curve, logger); - const transcript = new Keccak256Transcript(curve); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_ADDITIONS_SECTION}. Additions`); - await calculateAdditions(); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_SIGMA_SECTION}. Sigma1, Sigma2 & Sigma 3`); - if (logger) logger.debug("··· Reading Sigma polynomials "); - polynomials.Sigma1 = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.Sigma2 = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.Sigma3 = new Polynomial(new BigBuffer(sDomain), curve, logger); - - await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 5 * sDomain); - await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 10 * sDomain); - - if (logger) logger.debug("··· Reading Sigma evaluations"); - evaluations.Sigma1 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma2 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma3 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - - await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 6 * sDomain); - await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 11 * sDomain); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_PTAU_SECTION}. Powers of Tau`); - const PTau = await readSection$1(fdZKey, zkeySections, ZKEY_PL_PTAU_SECTION); - - let publicSignals = []; - - for (let i=1; i<= zkey.nPublic; i++) { - const pub = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8); - publicSignals.push(Scalar.fromRprLE(pub)); - } - - if (logger) logger.debug(""); - if (logger) logger.debug("> ROUND 1"); - await round1(); - - if (logger) logger.debug("> ROUND 2"); - await round2(); - - if (logger) logger.debug("> ROUND 3"); - await round3(); - - if (logger) logger.debug("> ROUND 4"); - await round4(); - - if (logger) logger.debug("> ROUND 5"); - await round5(); - - /////////////////////// - // Final adjustments // - /////////////////////// - - await fdZKey.close(); - await fdWtns.close(); - - // Prepare proof - let _proof = proof.toObjectProof(false); - _proof.protocol = "plonk"; - _proof.curve = curve.name; - - if (logger) logger.debug("PLONK PROVER FINISHED"); - - return { - proof: stringifyBigInts$1(_proof), - publicSignals: stringifyBigInts$1(publicSignals) - }; - - async function calculateAdditions() { - if (logger) logger.debug("··· Computing additions"); - const additionsBuff = await readSection$1(fdZKey, zkeySections, ZKEY_PL_ADDITIONS_SECTION); - - // sizes: wireId_x = 4 bytes (32 bits), factor_x = field size bits - // Addition form: wireId_a wireId_b factor_a factor_b (size is 4 + 4 + sFr + sFr) - const sSum = 8 + n8r * 2; - - for (let i = 0; i < zkey.nAdditions; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.debug(` addition ${i}/${zkey.nAdditions}`); - - // Read addition values - let offset = i * sSum; - const signalId1 = readUInt32(additionsBuff, offset); - offset += 4; - const signalId2 = readUInt32(additionsBuff, offset); - offset += 4; - const factor1 = additionsBuff.slice(offset, offset + n8r); - offset += n8r; - const factor2 = additionsBuff.slice(offset, offset + n8r); - - // Get witness value - const witness1 = getWitness(signalId1); - const witness2 = getWitness(signalId2); - - //Calculate final result - const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); - - buffInternalWitness.set(result, n8r * i); - } - } - - function readUInt32(b, o) { - const buff = b.slice(o, o+4); - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - return buffV.getUint32(0, true); - } - - function getWitness(idx) { - if (idx < zkey.nVars-zkey.nAdditions) { - return buffWitness.slice(idx*n8r, idx*n8r+n8r); - } else if (idx < zkey.nVars) { - return buffInternalWitness.slice((idx - (zkey.nVars-zkey.nAdditions))*n8r, (idx-(zkey.nVars-zkey.nAdditions))*n8r + n8r); - } else { - return curve.Fr.zero; - } - } - - async function round1() { - // STEP 1.1 - Generate random blinding scalars (b1, ..., b11) ∈ F - challenges.b = []; - for (let i=1; i<=11; i++) { - challenges.b[i] = curve.Fr.random(); - } - - // STEP 1.2 - Compute wire polynomials a(X), b(X) and c(X) - if (logger) logger.debug("> Computing A, B, C wire polynomials"); - await computeWirePolynomials(); - - // STEP 1.3 - Compute [a]_1, [b]_1, [c]_1 - if (logger) logger.debug("> Computing A, B, C MSM"); - let commitA = await polynomials.A.multiExponentiation(PTau, "A"); - let commitB = await polynomials.B.multiExponentiation(PTau, "B"); - let commitC = await polynomials.C.multiExponentiation(PTau, "C"); - - // First output of the prover is ([A]_1, [B]_1, [C]_1) - proof.addPolynomial("A", commitA); - proof.addPolynomial("B", commitB); - proof.addPolynomial("C", commitC); - - return 0; - } - - async function computeWirePolynomials() { - if (logger) logger.debug("··· Reading data from zkey file"); - - // Build A, B and C evaluations buffer from zkey and witness files - buffers.A = new BigBuffer(sDomain); - buffers.B = new BigBuffer(sDomain); - buffers.C = new BigBuffer(sDomain); - - // Read zkey file to the buffers - const aMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_PL_A_MAP_SECTION); - const bMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_PL_B_MAP_SECTION); - const cMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_PL_C_MAP_SECTION); - - // Compute all witness from signal ids and set them to A,B & C buffers - for (let i = 0; i < zkey.nConstraints; i++) { - const i_sFr = i * n8r; - const offset = i * 4; - - // Compute A value from a signal id - const signalIdA = readUInt32(aMapBuff, offset); - buffers.A.set(getWitness(signalIdA), i_sFr); - - // Compute B value from a signal id - const signalIdB = readUInt32(bMapBuff, offset); - buffers.B.set(getWitness(signalIdB), i_sFr); - - // Compute C value from a signal id - const signalIdC = readUInt32(cMapBuff, offset); - buffers.C.set(getWitness(signalIdC), i_sFr); - } - - buffers.A = await Fr.batchToMontgomery(buffers.A); - buffers.B = await Fr.batchToMontgomery(buffers.B); - buffers.C = await Fr.batchToMontgomery(buffers.C); - - // Compute the coefficients of the wire polynomials a(X), b(X) and c(X) from A,B & C buffers - if (logger) logger.debug("··· Computing A ifft"); - polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); - if (logger) logger.debug("··· Computing B ifft"); - polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); - if (logger) logger.debug("··· Computing C ifft"); - polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); - - // Compute extended evaluations of a(X), b(X) and c(X) polynomials - if (logger) logger.debug("··· Computing A fft"); - evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); - if (logger) logger.debug("··· Computing B fft"); - evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); - if (logger) logger.debug("··· Computing C fft"); - evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); - - // Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b - polynomials.A.blindCoefficients([challenges.b[2], challenges.b[1]]); - polynomials.B.blindCoefficients([challenges.b[4], challenges.b[3]]); - polynomials.C.blindCoefficients([challenges.b[6], challenges.b[5]]); - - // Check degrees - if (polynomials.A.degree() >= zkey.domainSize + 2) { - throw new Error("A Polynomial is not well calculated"); - } - if (polynomials.B.degree() >= zkey.domainSize + 2) { - throw new Error("B Polynomial is not well calculated"); - } - if (polynomials.C.degree() >= zkey.domainSize + 2) { - throw new Error("C Polynomial is not well calculated"); - } - } - - async function round2() { - // STEP 2.1 - Compute permutation challenge beta and gamma ∈ F - // Compute permutation challenge beta - if (logger) logger.debug("> Computing challenges beta and gamma"); - transcript.reset(); - - transcript.addPolCommitment(zkey.Qm); - transcript.addPolCommitment(zkey.Ql); - transcript.addPolCommitment(zkey.Qr); - transcript.addPolCommitment(zkey.Qo); - transcript.addPolCommitment(zkey.Qc); - transcript.addPolCommitment(zkey.S1); - transcript.addPolCommitment(zkey.S2); - transcript.addPolCommitment(zkey.S3); - - // Add A to the transcript - for (let i = 0; i < zkey.nPublic; i++) { - transcript.addScalar(buffers.A.slice(i * n8r, i * n8r + n8r)); - } - - // Add A, B, C to the transcript - transcript.addPolCommitment(proof.getPolynomial("A")); - transcript.addPolCommitment(proof.getPolynomial("B")); - transcript.addPolCommitment(proof.getPolynomial("C")); - - challenges.beta = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.beta: " + Fr.toString(challenges.beta, 16)); - - // Compute permutation challenge gamma - transcript.reset(); - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.gamma: " + Fr.toString(challenges.gamma, 16)); - - // STEP 2.2 - Compute permutation polynomial z(X) - if (logger) logger.debug("> Computing Z polynomial"); - await computeZ(); - - // STEP 2.3 - Compute permutation [z]_1 - if (logger) logger.debug("> Computing Z MSM"); - let commitZ = await polynomials.Z.multiExponentiation(PTau, "Z"); - - // Second output of the prover is ([Z]_1) - proof.addPolynomial("Z", commitZ); - } - - async function computeZ() { - if (logger) logger.debug("··· Computing Z evaluations"); - - let numArr = new BigBuffer(sDomain); - let denArr = new BigBuffer(sDomain); - - // Set the first values to 1 - numArr.set(Fr.one, 0); - denArr.set(Fr.one, 0); - - // Set initial omega - let w = Fr.one; - for (let i = 0; i < zkey.domainSize; i++) { - const i_n8r = i * n8r; - - const a = buffers.A.slice(i_n8r, i_n8r + n8r); - const b = buffers.B.slice(i_n8r, i_n8r + n8r); - const c = buffers.C.slice(i_n8r, i_n8r + n8r); - - // Z(X) := numArr / denArr - // numArr := (a + beta·ω + gamma)(b + beta·ω·k1 + gamma)(c + beta·ω·k2 + gamma) - const betaw = Fr.mul(challenges.beta, w); - - let n1 = Fr.add(a, betaw); - n1 = Fr.add(n1, challenges.gamma); - - let n2 = Fr.add(b, Fr.mul(zkey.k1, betaw)); - n2 = Fr.add(n2, challenges.gamma); - - let n3 = Fr.add(c, Fr.mul(zkey.k2, betaw)); - n3 = Fr.add(n3, challenges.gamma); - - let num = Fr.mul(n1, Fr.mul(n2, n3)); - - // denArr := (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma) - let d1 = Fr.add(a, Fr.mul(evaluations.Sigma1.getEvaluation(i * 4), challenges.beta)); - d1 = Fr.add(d1, challenges.gamma); - - let d2 = Fr.add(b, Fr.mul(evaluations.Sigma2.getEvaluation(i * 4), challenges.beta)); - d2 = Fr.add(d2, challenges.gamma); - - let d3 = Fr.add(c, Fr.mul(evaluations.Sigma3.getEvaluation(i * 4), challenges.beta)); - d3 = Fr.add(d3, challenges.gamma); - - let den = Fr.mul(d1, Fr.mul(d2, d3)); - - // Multiply current num value with the previous one saved in numArr - num = Fr.mul(numArr.slice(i_n8r, i_n8r + n8r), num); - numArr.set(num, ((i + 1) % zkey.domainSize) * n8r); - - // Multiply current den value with the previous one saved in denArr - den = Fr.mul(denArr.slice(i_n8r, i_n8r + n8r), den); - denArr.set(den, ((i + 1) % zkey.domainSize) * n8r); - - w = Fr.mul(w, Fr.w[zkey.power]); - } - - // Compute the inverse of denArr to compute in the next command the - // division numArr/denArr by multiplying num · 1/denArr - denArr = await Fr.batchInverse(denArr); - - // TODO: Do it in assembly and in parallel - // Multiply numArr · denArr where denArr was inverted in the previous command - for (let i = 0; i < zkey.domainSize; i++) { - const i_sFr = i * n8r; - - const z = Fr.mul(numArr.slice(i_sFr, i_sFr + n8r), denArr.slice(i_sFr, i_sFr + n8r)); - numArr.set(z, i_sFr); - } - - // From now on the values saved on numArr will be Z(X) buffer - buffers.Z = numArr; - - if (!Fr.eq(numArr.slice(0, n8r), Fr.one)) { - throw new Error("Copy constraints does not match"); - } - - // Compute polynomial coefficients z(X) from buffers.Z - if (logger) logger.debug("··· Computing Z ifft"); - polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); - - // Compute extended evaluations of z(X) polynomial - if (logger) logger.debug("··· Computing Z fft"); - evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); - - // Blind z(X) polynomial coefficients with blinding scalars b - polynomials.Z.blindCoefficients([challenges.b[9], challenges.b[8], challenges.b[7]]); - - // Check degree - if (polynomials.Z.degree() >= zkey.domainSize + 3) { - throw new Error("Z Polynomial is not well calculated"); - } - - delete buffers.Z; - } - - async function round3() { - if (logger) logger.debug("> Computing challenge alpha"); - - // STEP 3.1 - Compute evaluation challenge alpha ∈ F - transcript.reset(); - transcript.addScalar(challenges.beta); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.getPolynomial("Z")); - - challenges.alpha = transcript.getChallenge(); - challenges.alpha2 = Fr.square(challenges.alpha); - if (logger) logger.debug("··· challenges.alpha: " + Fr.toString(challenges.alpha, 16)); - - // Compute quotient polynomial T(X) - if (logger) logger.debug("> Computing T polynomial"); - await computeT(); - - // Compute [T1]_1, [T2]_1, [T3]_1 - if (logger) logger.debug("> Computing T MSM"); - let commitT1 = await polynomials.T1.multiExponentiation(PTau, "T1"); - let commitT2 = await polynomials.T2.multiExponentiation(PTau, "T2"); - let commitT3 = await polynomials.T3.multiExponentiation(PTau, "T3"); - - // Third output of the prover is ([T1]_1, [T2]_1, [T3]_1) - proof.addPolynomial("T1", commitT1); - proof.addPolynomial("T2", commitT2); - proof.addPolynomial("T3", commitT3); - } - - async function computeT() { - if (logger) - logger.debug(`··· Reading sections ${ZKEY_PL_QL_SECTION}, ${ZKEY_PL_QR_SECTION}` + - `, ${ZKEY_PL_QM_SECTION}, ${ZKEY_PL_QO_SECTION}, ${ZKEY_PL_QC_SECTION}. Q selectors`); - // Reserve memory for Q's evaluations - evaluations.QL = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QR = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QM = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QO = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QC = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QL_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QR_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QM_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QO_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QC_SECTION][0].p + sDomain); - - // Read Lagrange polynomials & evaluations from zkey file - evaluations.Lagrange = new Evaluations(new BigBuffer(sDomain * 4 * zkey.nPublic), curve, logger); - - for (let i = 0; i < zkey.nPublic; i++) { - await fdZKey.readToBuffer(evaluations.Lagrange.eval, i * sDomain * 4, sDomain * 4, zkeySections[ZKEY_PL_LAGRANGE_SECTION][0].p + i * 5 * sDomain + sDomain); - } - - buffers.T = new BigBuffer(sDomain * 4); - buffers.Tz = new BigBuffer(sDomain * 4); - - if (logger) logger.debug("··· Computing T evaluations"); - - let w = Fr.one; - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) - logger.debug(` T evaluation ${i}/${zkey.domainSize * 4}`); - - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - const z = evaluations.Z.getEvaluation(i); - const zw = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); - - const qm = evaluations.QM.getEvaluation(i); - const ql = evaluations.QL.getEvaluation(i); - const qr = evaluations.QR.getEvaluation(i); - const qo = evaluations.QO.getEvaluation(i); - const qc = evaluations.QC.getEvaluation(i); - const s1 = evaluations.Sigma1.getEvaluation(i); - const s2 = evaluations.Sigma2.getEvaluation(i); - const s3 = evaluations.Sigma3.getEvaluation(i); - - const ap = Fr.add(challenges.b[2], Fr.mul(challenges.b[1], w)); - const bp = Fr.add(challenges.b[4], Fr.mul(challenges.b[3], w)); - const cp = Fr.add(challenges.b[6], Fr.mul(challenges.b[5], w)); - - const w2 = Fr.square(w); - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], w2), Fr.mul(challenges.b[8], w)), challenges.b[9]); - const wW = Fr.mul(w, Fr.w[zkey.power]); - const wW2 = Fr.square(wW); - const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], wW2), Fr.mul(challenges.b[8], wW)), challenges.b[9]); - - let pi = Fr.zero; - for (let j = 0; j < zkey.nPublic; j++) { - const offset = (j * 4 * zkey.domainSize) + i; - - const lPol = evaluations.Lagrange.getEvaluation(offset); - const aVal = buffers.A.slice(j * n8r, (j + 1) * n8r); - - pi = Fr.sub(pi, Fr.mul(lPol, aVal)); - } - - // e1 := a(X)b(X)qM(X) + a(X)qL(X) + b(X)qR(X) + c(X)qO(X) + PI(X) + qC(X) - let [e1, e1z] = MulZ.mul2(a, b, ap, bp, i % 4, Fr); - e1 = Fr.mul(e1, qm); - e1z = Fr.mul(e1z, qm); - - e1 = Fr.add(e1, Fr.mul(a, ql)); - e1z = Fr.add(e1z, Fr.mul(ap, ql)); - - e1 = Fr.add(e1, Fr.mul(b, qr)); - e1z = Fr.add(e1z, Fr.mul(bp, qr)); - - e1 = Fr.add(e1, Fr.mul(c, qo)); - e1z = Fr.add(e1z, Fr.mul(cp, qo)); - - e1 = Fr.add(e1, pi); - e1 = Fr.add(e1, qc); - - // e2 := α[(a(X) + βX + γ)(b(X) + βk1X + γ)(c(X) + βk2X + γ)z(X)] - const betaw = Fr.mul(challenges.beta, w); - let e2a = a; - e2a = Fr.add(e2a, betaw); - e2a = Fr.add(e2a, challenges.gamma); - - let e2b = b; - e2b = Fr.add(e2b, Fr.mul(betaw, zkey.k1)); - e2b = Fr.add(e2b, challenges.gamma); - - let e2c = c; - e2c = Fr.add(e2c, Fr.mul(betaw, zkey.k2)); - e2c = Fr.add(e2c, challenges.gamma); - - let e2d = z; - - let [e2, e2z] = MulZ.mul4(e2a, e2b, e2c, e2d, ap, bp, cp, zp, i % 4, Fr); - e2 = Fr.mul(e2, challenges.alpha); - e2z = Fr.mul(e2z, challenges.alpha); - - // e3 := α[(a(X) + βSσ1(X) + γ)(b(X) + βSσ2(X) + γ)(c(X) + βSσ3(X) + γ)z(Xω)] - let e3a = a; - e3a = Fr.add(e3a, Fr.mul(challenges.beta, s1)); - e3a = Fr.add(e3a, challenges.gamma); - - let e3b = b; - e3b = Fr.add(e3b, Fr.mul(challenges.beta, s2)); - e3b = Fr.add(e3b, challenges.gamma); - - let e3c = c; - e3c = Fr.add(e3c, Fr.mul(challenges.beta, s3)); - e3c = Fr.add(e3c, challenges.gamma); - - let e3d = zw; - let [e3, e3z] = MulZ.mul4(e3a, e3b, e3c, e3d, ap, bp, cp, zWp, i % 4, Fr); - - e3 = Fr.mul(e3, challenges.alpha); - e3z = Fr.mul(e3z, challenges.alpha); - - // e4 := α^2(z(X)−1)L1(X) - let e4 = Fr.sub(z, Fr.one); - e4 = Fr.mul(e4, evaluations.Lagrange.getEvaluation(i)); - e4 = Fr.mul(e4, challenges.alpha2); - - let e4z = Fr.mul(zp, evaluations.Lagrange.getEvaluation(i)); - e4z = Fr.mul(e4z, challenges.alpha2); - - - let t = Fr.add(Fr.sub(Fr.add(e1, e2), e3), e4); - let tz = Fr.add(Fr.sub(Fr.add(e1z, e2z), e3z), e4z); - - buffers.T.set(t, i * n8r); - buffers.Tz.set(tz, i * n8r); - - w = Fr.mul(w, Fr.w[zkey.power + 2]); - } - - // Compute the coefficients of the polynomial T0(X) from buffers.T0 - if (logger) - logger.debug("··· Computing T ifft"); - polynomials.T = await Polynomial.fromEvaluations(buffers.T, curve, logger); - - // Divide the polynomial T0 by Z_H(X) - if (logger) - logger.debug("··· Computing T / ZH"); - polynomials.T.divZh(zkey.domainSize, 4); - - // Compute the coefficients of the polynomial Tz(X) from buffers.Tz - if (logger) - logger.debug("··· Computing Tz ifft"); - polynomials.Tz = await Polynomial.fromEvaluations(buffers.Tz, curve, logger); - - // Add the polynomial T1z to T1 to get the final polynomial T1 - polynomials.T.add(polynomials.Tz); - - // Check degree - if (polynomials.T.degree() >= zkey.domainSize * 3 + 6) { - throw new Error("T Polynomial is not well calculated"); - } - - // t(x) has degree 3n + 5, we are going to split t(x) into three smaller polynomials: - // T1' and T2' with a degree < n and T3' with a degree n+5 - // such that t(x) = T1'(X) + X^n T2'(X) + X^{2n} T3'(X) - // To randomize the parts we use blinding scalars b_10 and b_11 in a way that doesn't change t(X): - // T1(X) = T1'(X) + b_10 X^n - // T2(X) = T2'(X) - b_10 + b_11 X^n - // T3(X) = T3'(X) - b_11 - // such that - // t(X) = T1(X) + X^n T2(X) + X^2n T3(X) - if (logger) logger.debug("··· Computing T1, T2, T3 polynomials"); - polynomials.T1 = new Polynomial(new BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); - polynomials.T2 = new Polynomial(new BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); - polynomials.T3 = new Polynomial(new BigBuffer((zkey.domainSize + 6) * n8r), curve, logger); - - polynomials.T1.coef.set(polynomials.T.coef.slice(0, sDomain), 0); - polynomials.T2.coef.set(polynomials.T.coef.slice(sDomain, sDomain * 2), 0); - polynomials.T3.coef.set(polynomials.T.coef.slice(sDomain * 2, sDomain * 3 + 6 * n8r), 0); - - // Add blinding scalar b_10 as a new coefficient n - polynomials.T1.setCoef(zkey.domainSize, challenges.b[10]); - - // compute t_mid(X) - // Subtract blinding scalar b_10 to the lowest coefficient of t_mid - const lowestMid = Fr.sub(polynomials.T2.getCoef(0), challenges.b[10]); - polynomials.T2.setCoef(0, lowestMid); - polynomials.T2.setCoef(zkey.domainSize, challenges.b[11]); - - // compute t_high(X) - //Subtract blinding scalar b_11 to the lowest coefficient of t_high - const lowestHigh = Fr.sub(polynomials.T3.getCoef(0), challenges.b[11]); - polynomials.T3.setCoef(0, lowestHigh); - } - - async function round4() { - if (logger) logger.debug("> Computing challenge xi"); - - // STEP 4.1 - Compute evaluation challenge xi ∈ F - transcript.reset(); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.getPolynomial("T1")); - transcript.addPolCommitment(proof.getPolynomial("T2")); - transcript.addPolCommitment(proof.getPolynomial("T3")); - - challenges.xi = transcript.getChallenge(); - challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); - - if (logger) logger.debug("··· challenges.xi: " + Fr.toString(challenges.xi, 16)); - - // Fourth output of the prover is ( a(xi), b(xi), c(xi), s1(xi), s2(xi), z(xiw) ) - proof.addEvaluation("eval_a", polynomials.A.evaluate(challenges.xi)); - proof.addEvaluation("eval_b", polynomials.B.evaluate(challenges.xi)); - proof.addEvaluation("eval_c", polynomials.C.evaluate(challenges.xi)); - proof.addEvaluation("eval_s1", polynomials.Sigma1.evaluate(challenges.xi)); - proof.addEvaluation("eval_s2", polynomials.Sigma2.evaluate(challenges.xi)); - proof.addEvaluation("eval_zw", polynomials.Z.evaluate(challenges.xiw)); - } - - async function round5() { - if (logger) logger.debug("> Computing challenge v"); - - // STEP 5.1 - Compute evaluation challenge v ∈ F - transcript.reset(); - transcript.addScalar(challenges.xi); - transcript.addScalar(proof.getEvaluation("eval_a")); - transcript.addScalar(proof.getEvaluation("eval_b")); - transcript.addScalar(proof.getEvaluation("eval_c")); - transcript.addScalar(proof.getEvaluation("eval_s1")); - transcript.addScalar(proof.getEvaluation("eval_s2")); - transcript.addScalar(proof.getEvaluation("eval_zw")); - - challenges.v = []; - challenges.v[1] = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.v: " + Fr.toString(challenges.v[1], 16)); - - for (let i = 2; i < 6; i++) { - challenges.v[i] = Fr.mul(challenges.v[i - 1], challenges.v[1]); - } - - // STEP 5.2 Compute linearisation polynomial r(X) - if (logger) logger.debug("> Computing linearisation polynomial R(X)"); - await computeR(); - - //STEP 5.3 Compute opening proof polynomial Wxi(X) - if (logger) logger.debug("> Computing opening proof polynomial Wxi(X) polynomial"); - computeWxi(); - - //STEP 5.4 Compute opening proof polynomial Wxiw(X) - if (logger) logger.debug("> Computing opening proof polynomial Wxiw(X) polynomial"); - computeWxiw(); - - if (logger) logger.debug("> Computing Wxi, Wxiw MSM"); - let commitWxi = await polynomials.Wxi.multiExponentiation(PTau, "Wxi"); - let commitWxiw = await polynomials.Wxiw.multiExponentiation(PTau, "Wxiw"); - - // Fifth output of the prover is ([Wxi]_1, [Wxiw]_1) - proof.addPolynomial("Wxi", commitWxi); - proof.addPolynomial("Wxiw", commitWxiw); - } - - async function computeR() { - const Fr = curve.Fr; - - // Reserve memory for Q's polynomials - polynomials.QL = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QR = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QM = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QO = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QC = new Polynomial(new BigBuffer(sDomain), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[ZKEY_PL_QL_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[ZKEY_PL_QR_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[ZKEY_PL_QM_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[ZKEY_PL_QO_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[ZKEY_PL_QC_SECTION][0].p); - - challenges.xin = challenges.xi; - for (let i = 0; i < zkey.power; i++) { - challenges.xin = Fr.square(challenges.xin); - } - - challenges.zh = Fr.sub(challenges.xin, Fr.one); - - const L = []; - - const n = Fr.e(zkey.domainSize); - let w = Fr.one; - for (let i = 1; i <= Math.max(1, zkey.nPublic); i++) { - L[i] = Fr.div(Fr.mul(w, challenges.zh), Fr.mul(n, Fr.sub(challenges.xi, w))); - w = Fr.mul(w, Fr.w[zkey.power]); - } - - const eval_l1 = Fr.div( - Fr.sub(challenges.xin, Fr.one), - Fr.mul(n, Fr.sub(challenges.xi, Fr.one)) - ); - - if (logger) { - logger.debug("Lagrange Evaluations: "); - for (let i=1; i. -*/ - -const {unstringifyBigInts: unstringifyBigInts$5} = utils; - -async function plonkFullProve(_input, wasmFile, zkeyFileName, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$5(_input); - - const wtns= { - type: "mem" - }; - await wtnsCalculate(input, wasmFile, wtns, wtnsCalcOptions); - return await plonk16Prove(zkeyFileName, wtns, logger, proverOptions); -} - -/* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const { unstringifyBigInts: unstringifyBigInts$4 } = utils; - -async function plonkVerify(_vk_verifier, _publicSignals, _proof, logger) { - let vk_verifier = unstringifyBigInts$4(_vk_verifier); - _proof = unstringifyBigInts$4(_proof); - let publicSignals = unstringifyBigInts$4(_publicSignals); - - const curve = await getCurveFromName(vk_verifier.curve); - - const Fr = curve.Fr; - const G1 = curve.G1; - - if (logger) logger.info("PLONK VERIFIER STARTED"); - - let proof = fromObjectProof(curve,_proof); - vk_verifier = fromObjectVk$1(curve, vk_verifier); - - if (!isWellConstructed(curve, proof)) { - logger.error("Proof commitments are not valid."); - return false; - } - - if (publicSignals.length != vk_verifier.nPublic) { - if (logger) logger.error("Invalid number of public inputs"); - return false; - } - - if (!evaluationsAreValid$1(curve, proof)) { - if (logger) logger.error("Proof evaluations are not valid"); - return false; - } - - if (!publicInputsAreValid$1(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - const challenges = calculatechallenges(curve, proof, publicSignals, vk_verifier); - if (logger) { - logger.debug("beta: " + Fr.toString(challenges.beta, 16)); - logger.debug("gamma: " + Fr.toString(challenges.gamma, 16)); - logger.debug("alpha: " + Fr.toString(challenges.alpha, 16)); - logger.debug("xi: " + Fr.toString(challenges.xi, 16)); - for(let i=1;i<6;i++) { - if (logger) logger.debug("v: " + Fr.toString(challenges.v[i], 16)); - } - logger.debug("u: " + Fr.toString(challenges.u, 16)); - } - const L = calculateLagrangeEvaluations(curve, challenges, vk_verifier); - if (logger) { - for (let i=1; i. -*/ - -const { unstringifyBigInts: unstringifyBigInts$3} = utils; - -function p256$1(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0"+nstr; - nstr = `"0x${nstr}"`; - return nstr; -} - -async function plonkExportSolidityCallData(_proof, _pub) { - const proof = unstringifyBigInts$3(_proof); - const pub = unstringifyBigInts$3(_pub); - - await getCurveFromName(proof.curve); - - let inputs = ""; - for (let i=0; i. -*/ - -var plonk = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportSolidityCallData: plonkExportSolidityCallData, - fullProve: plonkFullProve, - prove: plonk16Prove, - setup: plonkSetup, - verify: plonkVerify -}); - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -// We export to zkey the signals and values of the a, b, c, ql, qr, qm, qo and qc - -// a, b and c are signals id (32-bit integers) -// ql, qr, qm, qo and qc are field values - -function getFFlonkConstantConstraint(signal1, Fr) { - return [signal1, 0, 0, Fr.one, Fr.zero, Fr.zero, Fr.zero, Fr.zero]; -} - -function getFFlonkAdditionConstraint(signal1, signal2, signalOut, ql, qr, qm, qo, qc) { - return [signal1, signal2, signalOut, ql, qr, qm, qo, qc]; -} - -function getFFlonkMultiplicationConstraint(signal1, signal2, signalOut, ql, qr, qm, qo, qc, Fr) { - return [signal1, signal2, signalOut, ql, qr, qm, qo, qc]; -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const LINEAR_COMBINATION_NULLABLE = 0; -const LINEAR_COMBINATION_CONSTANT = 1; -const LINEAR_COMBINATION_VARIABLE = 2; - -class r1csConstraintProcessor { - constructor(Fr, fnGetConstantConstraint, fnGetAdditionConstraint, fnGetMultiplicationConstraint, logger) { - this.Fr = Fr; - this.logger = logger; - this.fnGetAdditionConstraint = fnGetAdditionConstraint; - this.fnGetMultiplicationConstraint = fnGetMultiplicationConstraint; - } - - processR1csConstraint(settings, lcA, lcB, lcC) { - this.normalizeLinearCombination(lcA); - this.normalizeLinearCombination(lcB); - this.normalizeLinearCombination(lcC); - - const lctA = this.getLinearCombinationType(lcA); - const lctB = this.getLinearCombinationType(lcB); - - if ((lctA === LINEAR_COMBINATION_NULLABLE) || (lctB === LINEAR_COMBINATION_NULLABLE)) { - return this.processR1csAdditionConstraint(settings, lcC); - } else if (lctA === LINEAR_COMBINATION_CONSTANT) { - const lcCC = this.joinLinearCombinations(lcB, lcC, lcA[0]); - return this.processR1csAdditionConstraint(settings, lcCC); - } else if (lctB === LINEAR_COMBINATION_CONSTANT) { - const lcCC = this.joinLinearCombinations(lcA, lcC, lcB[0]); - return this.processR1csAdditionConstraint(settings, lcCC); - } else { - return this.processR1csMultiplicationConstraint(settings, lcA, lcB, lcC); - } - } - - getLinearCombinationType(linCom) { - // let k = this.Fr.zero; - // - // const signalIds = Object.keys(linCom); - // for (let i = 0; i < signalIds.length; i++) { - // if (signalIds[i] === "0") { - // k = this.Fr.add(k, linCom[signalIds[i]]); - // } else { - // return LINEAR_COMBINATION_VARIABLE; - // } - // } - // - // if (!this.Fr.eq(k, this.Fr.zero)) return LINEAR_COMBINATION_CONSTANT; - // - // return LINEAR_COMBINATION_NULLABLE; - - let k = this.Fr.zero; - let n = 0; - const ss = Object.keys(linCom); - for (let i = 0; i < ss.length; i++) { - if (linCom[ss[i]] == 0n) { - delete linCom[ss[i]]; - } else if (ss[i] == 0) { - k = this.Fr.add(k, linCom[ss[i]]); - } else { - n++; - } - } - if (n > 0) return LINEAR_COMBINATION_VARIABLE; - if (!this.Fr.isZero(k)) return LINEAR_COMBINATION_CONSTANT; - return LINEAR_COMBINATION_NULLABLE; - } - - normalizeLinearCombination(linCom) { - const signalIds = Object.keys(linCom); - for (let i = 0; i < signalIds.length; i++) { - if (this.Fr.isZero(linCom[signalIds[i]])) delete linCom[signalIds[i]]; - } - - return linCom; - } - - joinLinearCombinations(linCom1, linCom2, k) { - const res = {}; - - // for (let s in linCom1) { - // const val = this.Fr.mul(k, linCom1[s]); - // res[s] = !(s in res) ? val : this.Fr.add(val, res[s]); - // } - // - // for (let s in linCom2) { - // const val = this.Fr.mul(k, linCom2[s]); - // res[s] = !(s in res) ? val : this.Fr.add(val, res[s]); - // } - - for (let s in linCom1) { - if (typeof res[s] == "undefined") { - res[s] = this.Fr.mul(k, linCom1[s]); - } else { - res[s] = this.Fr.add(res[s], this.Fr.mul(k, linCom1[s])); - } - } - - for (let s in linCom2) { - if (typeof res[s] == "undefined") { - res[s] = linCom2[s]; - } else { - res[s] = this.Fr.add(res[s], linCom2[s]); - } - } - - return this.normalizeLinearCombination(res); - } - - reduceCoefs(settings, constraintsArr, additionsArr, linCom, maxC) { - const res = { - k: this.Fr.zero, - signals: [], - coefs: [] - }; - const cs = []; - - for (let signalId in linCom) { - if (signalId == 0) { - res.k = this.Fr.add(res.k, linCom[signalId]); - } else if (linCom[signalId] != 0n) { - cs.push([Number(signalId), linCom[signalId]]); - } - } - - while (cs.length > maxC) { - const c1 = cs.shift(); - const c2 = cs.shift(); - const so = settings.nVars++; - - const constraints = this.fnGetAdditionConstraint( - c1[0], c2[0], so, - this.Fr.neg(c1[1]), this.Fr.neg(c2[1]), this.Fr.zero, this.Fr.one, this.Fr.zero); - - constraintsArr.push(constraints); - additionsArr.push([c1[0], c2[0], c1[1], c2[1]]); - - cs.push([so, this.Fr.one]); - } - - for (let i = 0; i < cs.length; i++) { - res.signals[i] = cs[i][0]; - res.coefs[i] = cs[i][1]; - } - - while (res.coefs.length < maxC) { - res.signals.push(0); - res.coefs.push(this.Fr.zero); - } - - return res; - } - - processR1csAdditionConstraint(settings, linCom) { - const constraintsArr = []; - const additionsArr = []; - - const C = this.reduceCoefs(settings, constraintsArr, additionsArr, linCom, 3); - - const constraints = this.fnGetAdditionConstraint( - C.signals[0], C.signals[1], C.signals[2], - C.coefs[0], C.coefs[1], this.Fr.zero, C.coefs[2], C.k); - - constraintsArr.push(constraints); - - return [constraintsArr, additionsArr]; - } - - processR1csMultiplicationConstraint(settings, lcA, lcB, lcC) { - const constraintsArr = []; - const additionsArr = []; - - const A = this.reduceCoefs(settings, constraintsArr, additionsArr, lcA, 1); - const B = this.reduceCoefs(settings, constraintsArr, additionsArr, lcB, 1); - const C = this.reduceCoefs(settings, constraintsArr, additionsArr, lcC, 1); - - const constraints = this.fnGetMultiplicationConstraint( - A.signals[0], B.signals[0], C.signals[0], - this.Fr.mul(A.coefs[0], B.k), - this.Fr.mul(A.k, B.coefs[0]), - this.Fr.mul(A.coefs[0], B.coefs[0]), - this.Fr.neg(C.coefs[0]), - this.Fr.sub(this.Fr.mul(A.k, B.k), C.k)); - - constraintsArr.push(constraints); - - return [constraintsArr, additionsArr]; - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -class CPolynomial { - constructor(n, curve, logger) { - this.n = n; - this.polynomials = Array(n).fill(undefined); - this.curve = curve; - this.Fr = curve.Fr; - this.G1 = curve.G1; - this.logger = logger; - } - - addPolynomial(position, polynomial) { - if (position > this.n - 1) { - throw new Error("CPolynomial:addPolynomial, cannot add a polynomial to a position greater than n-1"); - } - - this.polynomials[position] = polynomial; - } - - degree() { - let degrees = this.polynomials.map( - (polynomial, index) => polynomial === undefined ? 0 : polynomial.degree() * this.n + index); - return Math.max(...degrees); - } - - getPolynomial() { - let degrees = this.polynomials.map(polynomial => polynomial === undefined ? 0 : polynomial.degree()); - const maxDegree = this.degree(); - const lengthBuffer = 2 ** (log2(maxDegree - 1) + 1); - const sFr = this.Fr.n8; - - let polynomial = new Polynomial(new BigBuffer(lengthBuffer * sFr), this.curve, this.logger); - - for (let i = 0; i < maxDegree; i++) { - const i_n8 = i * sFr; - const i_sFr = i_n8 * this.n; - - for (let j = 0; j < this.n; j++) { - if (this.polynomials[j] !== undefined) { - if (i <= degrees[j]) polynomial.coef.set(this.polynomials[j].coef.slice(i_n8, i_n8 + sFr), i_sFr + j * sFr); - } - } - } - - return polynomial; - } - - async multiExponentiation(PTau, name) { - let polynomial = this.getPolynomial(); - const n = polynomial.coef.byteLength / this.Fr.n8; - const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); - const bm = await this.Fr.batchFromMontgomery(polynomial.coef); - let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); - res = this.G1.toAffine(res); - return res; - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - - -async function fflonkSetup(r1csFilename, ptauFilename, zkeyFilename, logger) { - if (logger) logger.info("FFLONK SETUP STARTED"); - - if (globalThis.gc) globalThis.gc(); - - // Read PTau file - if (logger) logger.info("> Reading PTau file"); - const {fd: fdPTau, sections: pTauSections} = await readBinFile$1(ptauFilename, "ptau", 1, 1 << 22, 1 << 24); - if (!pTauSections[12]) { - throw new Error("Powers of Tau is not well prepared. Section 12 missing."); - } - - // Get curve defined in PTau - if (logger) logger.info("> Getting curve from PTau settings"); - const {curve} = await readPTauHeader(fdPTau, pTauSections); - - // Read r1cs file - if (logger) logger.info("> Reading r1cs file"); - const {fd: fdR1cs, sections: sectionsR1cs} = await readBinFile$1(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); - const r1cs = await readR1csFd(fdR1cs, sectionsR1cs, {loadConstraints: false, loadCustomGates: true}); - - // Potential error checks - if (r1cs.prime !== curve.r) { - throw new Error("r1cs curve does not match powers of tau ceremony curve"); - } - - // Initializations - const Fr = curve.Fr; - - const sFr = curve.Fr.n8; - const sG1 = curve.G1.F.n8 * 2; - const sG2 = curve.G2.F.n8 * 2; - - let polynomials = {}; - let evaluations = {}; - let PTau; - - let settings = { - nVars: r1cs.nVars, - nPublic: r1cs.nOutputs + r1cs.nPubInputs - }; - - const plonkConstraints = new BigArray(); - let plonkAdditions = new BigArray(); - - // Process constraints inside r1cs - if (logger) logger.info("> Processing FFlonk constraints"); - await computeFFConstraints(curve.Fr, r1cs, logger); - if (globalThis.gc) globalThis.gc(); - - // As the t polynomial is n+5 we need at least a power of 4 - //TODO check!!!! - // NOTE : plonkConstraints + 2 = #constraints + blinding coefficients for each wire polynomial - settings.cirPower = Math.max(FF_T_POL_DEG_MIN, log2((plonkConstraints.length + 2) - 1) + 1); - settings.domainSize = 2 ** settings.cirPower; - - if (pTauSections[2][0].size < (settings.domainSize * 9 + 18) * sG1) { - throw new Error("Powers of Tau is not big enough for this circuit size. Section 2 too small."); - } - if (pTauSections[3][0].size < sG2) { - throw new Error("Powers of Tau is not well prepared. Section 3 too small."); - } - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK SETUP SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${settings.cirPower}`); - logger.info(` Domain size: ${settings.domainSize}`); - logger.info(` Vars: ${settings.nVars}`); - logger.info(` Public vars: ${settings.nPublic}`); - logger.info(` Constraints: ${plonkConstraints.length}`); - logger.info(` Additions: ${plonkAdditions.length}`); - logger.info("----------------------------"); - } - - // Compute k1 and k2 to be used in the permutation checks - if (logger) logger.info("> computing k1 and k2"); - const [k1, k2] = computeK1K2(); - - // Compute omega 3 (w3) and omega 4 (w4) to be used in the prover and the verifier - // w3^3 = 1 and w4^4 = 1 - if (logger) logger.info("> computing w3"); - const w3 = computeW3(); - if (logger) logger.info("> computing w4"); - const w4 = computeW4(); - if (logger) logger.info("> computing w8"); - const w8 = computeW8(); - if (logger) logger.info("> computing wr"); - const wr = getOmegaCubicRoot(settings.cirPower, curve.Fr); - - // Write output zkey file - await writeZkeyFile(); - - await fdR1cs.close(); - await fdPTau.close(); - - if (logger) logger.info("FFLONK SETUP FINISHED"); - - return 0; - - async function computeFFConstraints(Fr, r1cs, logger) { - // Add public inputs and outputs - for (let i = 0; i < settings.nPublic; i++) { - plonkConstraints.push(getFFlonkConstantConstraint(i + 1, Fr)); - } - - // Add all constraints from r1cs file - const r1csProcessor = new r1csConstraintProcessor(Fr, getFFlonkConstantConstraint, getFFlonkAdditionConstraint, getFFlonkMultiplicationConstraint, logger); - - const bR1cs = await readSection$1(fdR1cs, sectionsR1cs, 2); - let bR1csPos = 0; - for (let i = 0; i < r1cs.nConstraints; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` processing r1cs constraints ${i}/${r1cs.nConstraints}`); - } - const [constraints, additions] = r1csProcessor.processR1csConstraint(settings, ...readConstraint()); - - plonkConstraints.push(...constraints); - plonkAdditions.push(...additions); - } - - function readConstraint() { - const c = []; - c[0] = readLC(); - c[1] = readLC(); - c[2] = readLC(); - return c; - } - - function readLC() { - const lc = {}; - - const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); - bR1csPos += 4; - const buffUL32V = new DataView(buffUL32.buffer); - const nIdx = buffUL32V.getUint32(0, true); - - const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); - bR1csPos += (4 + r1cs.n8) * nIdx; - const buffV = new DataView(buff.buffer); - for (let i = 0; i < nIdx; i++) { - const idx = buffV.getUint32(i * (4 + r1cs.n8), true); - const val = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); - lc[idx] = val; - } - return lc; - } - - return 0; - } - - async function writeZkeyFile() { - if (logger) logger.info("> Writing the zkey file"); - const fdZKey = await createBinFile(zkeyFilename, "zkey", 1, ZKEY_FF_NSECTIONS, 1 << 22, 1 << 24); - - if (logger) logger.info(`··· Writing Section ${HEADER_ZKEY_SECTION}. Zkey Header`); - await writeZkeyHeader(fdZKey); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_ADDITIONS_SECTION}. Additions`); - await writeAdditions(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_A_MAP_SECTION}. A Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_A_MAP_SECTION, 0, "A map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_B_MAP_SECTION}. B Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_B_MAP_SECTION, 1, "B map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_C_MAP_SECTION}. C Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_C_MAP_SECTION, 2, "C map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QL_SECTION}. QL`); - await writeQMap(fdZKey, ZKEY_FF_QL_SECTION, 3, "QL"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QR_SECTION}. QR`); - await writeQMap(fdZKey, ZKEY_FF_QR_SECTION, 4, "QR"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QM_SECTION}. QM`); - await writeQMap(fdZKey, ZKEY_FF_QM_SECTION, 5, "QM"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QO_SECTION}. QO`); - await writeQMap(fdZKey, ZKEY_FF_QO_SECTION, 6, "QO"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QC_SECTION}. QC`); - await writeQMap(fdZKey, ZKEY_FF_QC_SECTION, 7, "QC"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Sections ${ZKEY_FF_SIGMA1_SECTION},${ZKEY_FF_SIGMA2_SECTION},${ZKEY_FF_SIGMA3_SECTION}. Sigma1, Sigma2 & Sigma 3`); - await writeSigma(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_LAGRANGE_SECTION}. Lagrange Polynomials`); - await writeLagrangePolynomials(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_PTAU_SECTION}. Powers of Tau`); - await writePtau(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_C0_SECTION}. C0`); - await writeC0(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_HEADER_SECTION}. FFlonk Header`); - await writeFFlonkHeader(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info("> Writing the zkey file finished"); - - await fdZKey.close(); - } - - async function writeZkeyHeader(fdZKey) { - await startWriteSection(fdZKey, HEADER_ZKEY_SECTION); - await fdZKey.writeULE32(FFLONK_PROTOCOL_ID); - await endWriteSection(fdZKey); - } - - async function writeAdditions(fdZKey) { - await startWriteSection(fdZKey, ZKEY_FF_ADDITIONS_SECTION); - - // Written values are 2 * 32 bit integers (2 * 4 bytes) + 2 field size values ( 2 * sFr bytes) - const buffOut = new Uint8Array(8 + 2 * sFr); - const buffOutV = new DataView(buffOut.buffer); - - for (let i = 0; i < plonkAdditions.length; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) logger.info(` writing Additions: ${i}/${plonkAdditions.length}`); - - const addition = plonkAdditions[i]; - - buffOutV.setUint32(0, addition[0], true); - buffOutV.setUint32(4, addition[1], true); - buffOut.set(addition[2], 8); - buffOut.set(addition[3], 8 + sFr); - - await fdZKey.write(buffOut); - } - await endWriteSection(fdZKey); - } - - async function writeWitnessMap(fdZKey, sectionNum, posConstraint, name) { - await startWriteSection(fdZKey, sectionNum); - for (let i = 0; i < plonkConstraints.length; i++) { - if (logger && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing witness ${name}: ${i}/${plonkConstraints.length}`); - } - - await fdZKey.writeULE32(plonkConstraints[i][posConstraint]); - } - await endWriteSection(fdZKey); - } - - async function writeQMap(fdZKey, sectionNum, posConstraint, name) { - // Compute Q from q evaluations - let Q = new BigBuffer(settings.domainSize * sFr); - - for (let i = 0; i < plonkConstraints.length; i++) { - Q.set(plonkConstraints[i][posConstraint], i * sFr); - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing ${name}: ${i}/${plonkConstraints.length}`); - } - } - - polynomials[name] = await Polynomial.fromEvaluations(Q, curve, logger); - evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); - - // Write Q coefficients and evaluations - await startWriteSection(fdZKey, sectionNum); - await fdZKey.write(polynomials[name].coef); - await fdZKey.write(evaluations[name].eval); - await endWriteSection(fdZKey); - } - - async function writeSigma(fdZKey) { - // Compute sigma - const sigma = new BigBuffer(sFr * settings.domainSize * 3); - const lastSeen = new BigArray(settings.nVars); - const firstPos = new BigArray(settings.nVars); - - let w = Fr.one; - for (let i = 0; i < settings.domainSize; i++) { - if (i < plonkConstraints.length) { - buildSigma(plonkConstraints[i][0], i); - buildSigma(plonkConstraints[i][1], settings.domainSize + i); - buildSigma(plonkConstraints[i][2], settings.domainSize * 2 + i); - } else if (i < settings.domainSize - 2) { - buildSigma(0, i); - buildSigma(0, settings.domainSize + i); - buildSigma(0, settings.domainSize * 2 + i); - } else { - sigma.set(w, i * sFr); - sigma.set(Fr.mul(w, k1), (settings.domainSize + i) * sFr); - sigma.set(Fr.mul(w, k2), (settings.domainSize * 2 + i) * sFr); - } - - w = Fr.mul(w, Fr.w[settings.cirPower]); - - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing sigma phase1: ${i}/${plonkConstraints.length}`); - } - } - - for (let i = 0; i < settings.nVars; i++) { - if (typeof firstPos[i] !== "undefined") { - sigma.set(lastSeen[i], firstPos[i] * sFr); - } else { - // throw new Error("Variable not used"); - console.log("Variable not used"); - } - if ((logger) && (i !== 0) && (i % 500000 === 0)) logger.info(` writing sigma phase2: ${i}/${settings.nVars}`); - } - - if (globalThis.gc) globalThis.gc(); - - // Write sigma coefficients and evaluations - for (let i = 0; i < 3; i++) { - const sectionId = 0 === i ? ZKEY_FF_SIGMA1_SECTION : 1 === i ? ZKEY_FF_SIGMA2_SECTION : ZKEY_FF_SIGMA3_SECTION; - - let name = "S" + (i + 1); - polynomials[name] = await Polynomial.fromEvaluations(sigma.slice(settings.domainSize * sFr * i, settings.domainSize * sFr * (i + 1)), curve, logger); - evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); - await startWriteSection(fdZKey, sectionId); - await fdZKey.write(polynomials[name].coef); - await fdZKey.write(evaluations[name].eval); - await endWriteSection(fdZKey); - - if (globalThis.gc) globalThis.gc(); - } - - return 0; - - function buildSigma(signalId, idx) { - if (typeof lastSeen[signalId] === "undefined") { - firstPos[signalId] = idx; - } else { - sigma.set(lastSeen[signalId], idx * sFr); - } - let v; - if (idx < settings.domainSize) { - v = w; - } else if (idx < 2 * settings.domainSize) { - v = Fr.mul(w, k1); - } else { - v = Fr.mul(w, k2); - } - - lastSeen[signalId] = v; - } - } - - async function writeLagrangePolynomials(fdZKey) { - await startWriteSection(fdZKey, ZKEY_FF_LAGRANGE_SECTION); - - const l = Math.max(settings.nPublic, 1); - for (let i = 0; i < l; i++) { - let buff = new BigBuffer(settings.domainSize * sFr); - buff.set(Fr.one, i * sFr); - - await writeP4(fdZKey, buff); - } - await endWriteSection(fdZKey); - } - - async function writePtau(fdZKey) { - await startWriteSection(fdZKey, ZKEY_FF_PTAU_SECTION); - - // domainSize * 9 + 18 = maximum SRS length needed, specifically to commit C2 - PTau = new BigBuffer((settings.domainSize * 9 + 18) * sG1); - await fdPTau.readToBuffer(PTau, 0, (settings.domainSize * 9 + 18) * sG1, pTauSections[2][0].p); - - await fdZKey.write(PTau); - await endWriteSection(fdZKey); - } - - async function writeC0(fdZKey) { - // C0(X) := QL(X^8) + X · QR(X^8) + X^2 · QO(X^8) + X^3 · QM(X^8) + X^4 · QC(X^8) - // + X^5 · SIGMA1(X^8) + X^6 · SIGMA2(X^8) + X^7 · SIGMA3(X^8) - let C0 = new CPolynomial(8, curve, logger); - C0.addPolynomial(0, polynomials.QL); - C0.addPolynomial(1, polynomials.QR); - C0.addPolynomial(2, polynomials.QO); - C0.addPolynomial(3, polynomials.QM); - C0.addPolynomial(4, polynomials.QC); - C0.addPolynomial(5, polynomials.S1); - C0.addPolynomial(6, polynomials.S2); - C0.addPolynomial(7, polynomials.S3); - - polynomials.C0 = C0.getPolynomial(); - - // Check degree - if (polynomials.C0.degree() >= 8 * settings.domainSize) { - throw new Error("C0 Polynomial is not well calculated"); - } - - await startWriteSection(fdZKey, ZKEY_FF_C0_SECTION); - await fdZKey.write(polynomials.C0.coef); - await endWriteSection(fdZKey); - } - - async function writeFFlonkHeader(fdZKey) { - await startWriteSection(fdZKey, ZKEY_FF_HEADER_SECTION); - - const primeQ = curve.q; - const n8q = (Math.floor((Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; - await fdZKey.writeULE32(n8q); - await writeBigInt(fdZKey, primeQ, n8q); - - const primeR = curve.r; - const n8r = (Math.floor((Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; - await fdZKey.writeULE32(n8r); - await writeBigInt(fdZKey, primeR, n8r); - - // Total number of r1cs vars - await fdZKey.writeULE32(settings.nVars); - // Total number of r1cs public vars = outputs + public inputs - await fdZKey.writeULE32(settings.nPublic); - await fdZKey.writeULE32(settings.domainSize); - await fdZKey.writeULE32(plonkAdditions.length); - await fdZKey.writeULE32(plonkConstraints.length); - - await fdZKey.write(k1); - await fdZKey.write(k2); - - await fdZKey.write(w3); - await fdZKey.write(w4); - await fdZKey.write(w8); - await fdZKey.write(wr); - - let bX_2; - bX_2 = await fdPTau.read(sG2, pTauSections[3][0].p + sG2); - await fdZKey.write(bX_2); - - let commitC0 = await polynomials.C0.multiExponentiation(PTau, "C0"); - await fdZKey.write(commitC0); - - await endWriteSection(fdZKey); - } - - async function writeP4(fdZKey, buff) { - const [coefficients, evaluations4] = await Polynomial.to4T(buff, settings.domainSize, [], Fr); - await fdZKey.write(coefficients); - await fdZKey.write(evaluations4); - - return [coefficients, evaluations4]; - } - - function computeK1K2() { - let k1 = Fr.two; - while (isIncluded(k1, [], settings.cirPower)) Fr.add(k1, Fr.one); - let k2 = Fr.add(k1, Fr.one); - while (isIncluded(k2, [k1], settings.cirPower)) Fr.add(k2, Fr.one); - return [k1, k2]; - - function isIncluded(k, kArr, pow) { - const domainSize = 2 ** pow; - let w = Fr.one; - for (let i = 0; i < domainSize; i++) { - if (Fr.eq(k, w)) return true; - for (let j = 0; j < kArr.length; j++) { - if (Fr.eq(k, Fr.mul(kArr[j], w))) return true; - } - w = Fr.mul(w, Fr.w[pow]); - } - return false; - } - } - - function computeW3() { - let generator = Fr.e(31624); - - // Exponent is order(r - 1) / 3 - let orderRsub1 = 3648040478639879203707734290876212514758060733402672390616367364429301415936n; - let exponent = Scalar.div(orderRsub1, Scalar.e(3)); - - return Fr.exp(generator, exponent); - } - - function computeW4() { - return Fr.w[2]; - } - - function computeW8() { - return Fr.w[3]; - } - - function getOmegaCubicRoot(power, Fr) { - // Hardcorded 3th-root of Fr.w[28] - const firstRoot = Fr.e(467799165886069610036046866799264026481344299079011762026774533774345988080n); - - return Fr.exp(firstRoot, 2 ** (28 - power)); - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const { stringifyBigInts } = utils; - - -async function fflonkProve(zkeyFileName, witnessFileName, logger, options) { - if (logger) logger.info("FFLONK PROVER STARTED"); - - // Read witness file - if (logger) logger.info("> Reading witness file"); - const { - fd: fdWtns, - sections: wtnsSections - } = await readBinFile$1(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); - const wtns = await readHeader(fdWtns, wtnsSections); - - //Read zkey file - if (logger) logger.info("> Reading zkey file"); - const { - fd: fdZKey, - sections: zkeySections - } = await readBinFile$1(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); - - const zkey = await readHeader$1(fdZKey, zkeySections, undefined, options); - - if (zkey.protocolId !== FFLONK_PROTOCOL_ID) { - throw new Error("zkey file is not fflonk"); - } - - if (!Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness !== zkey.nVars - zkey.nAdditions) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); - } - - const curve = zkey.curve; - - const Fr = curve.Fr; - - const sFr = curve.Fr.n8; - const sG1 = curve.G1.F.n8 * 2; - const sDomain = zkey.domainSize * sFr; - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK PROVE SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${zkey.power}`); - logger.info(` Domain size: ${zkey.domainSize}`); - logger.info(` Vars: ${zkey.nVars}`); - logger.info(` Public vars: ${zkey.nPublic}`); - logger.info(` Constraints: ${zkey.nConstraints}`); - logger.info(` Additions: ${zkey.nAdditions}`); - logger.info("----------------------------"); - } - - //Read witness data - if (logger) logger.info("> Reading witness file data"); - const buffWitness = await readSection$1(fdWtns, wtnsSections, 2); - await fdWtns.close(); - - // First element in plonk is not used and can be any value. (But always the same). - // We set it to zero to go faster in the exponentiations. - buffWitness.set(Fr.zero, 0); - const buffInternalWitness = new BigBuffer(zkey.nAdditions * sFr); - - let buffers = {}; - let polynomials = {}; - let evaluations = {}; - - // To divide prime fields the Extended Euclidean Algorithm for computing modular inverses is needed. - // NOTE: This is the equivalent of compute 1/denominator and then multiply it by the numerator. - // The Extended Euclidean Algorithm is expensive in terms of computation. - // For the special case where we need to do many modular inverses, there's a simple mathematical trick - // that allows us to compute many inverses, called Montgomery batch inversion. - // More info: https://vitalik.ca/general/2018/07/21/starks_part_3.html - // Montgomery batch inversion reduces the n inverse computations to a single one - // To save this (single) inverse computation on-chain, will compute it in proving time and send it to the verifier. - // The verifier will have to check: - // 1) the denominator is correct multiplying by himself non-inverted -> a * 1/a == 1 - // 2) compute the rest of the denominators using the Montgomery batch inversion - // The inversions are: - // · denominator needed in step 8 and 9 of the verifier to multiply by 1/Z_H(xi) - // · denominator needed in step 10 and 11 of the verifier - // · denominator needed in the verifier when computing L_i^{S1}(X) and L_i^{S2}(X) - // · L_i i=1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) - let toInverse = {}; - - let challenges = {}; - let roots = {}; - - let proof = new Proof(curve, logger); - - if (logger) logger.info(`> Reading Section ${ZKEY_FF_ADDITIONS_SECTION}. Additions`); - await calculateAdditions(); - - if (logger) logger.info(`> Reading Sections ${ZKEY_FF_SIGMA1_SECTION},${ZKEY_FF_SIGMA2_SECTION},${ZKEY_FF_SIGMA3_SECTION}. Sigma1, Sigma2 & Sigma 3`); - if (logger) logger.info("··· Reading Sigma polynomials "); - polynomials.Sigma1 = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.Sigma2 = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.Sigma3 = new Polynomial(new BigBuffer(sDomain), curve, logger); - - await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA1_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA2_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA3_SECTION][0].p); - - if (logger) logger.info("··· Reading Sigma evaluations"); - evaluations.Sigma1 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma2 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma3 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - - await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA1_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA2_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA3_SECTION][0].p + sDomain); - - if (logger) logger.info(`> Reading Section ${ZKEY_FF_PTAU_SECTION}. Powers of Tau`); - const PTau = new BigBuffer(zkey.domainSize * 16 * sG1); - // domainSize * 9 + 18 = SRS length in the zkey saved in setup process. - // it corresponds to the maximum SRS length needed, specifically to commit C2 - // notice that the reserved buffers size is zkey.domainSize * 16 * sG1 because a power of two buffer size is needed - // the remaining buffer not filled from SRS are set to 0 - await fdZKey.readToBuffer(PTau, 0, (zkey.domainSize * 9 + 18) * sG1, zkeySections[ZKEY_FF_PTAU_SECTION][0].p); - - // START FFLONK PROVER PROTOCOL - if (globalThis.gc) globalThis.gc(); - - // ROUND 1. Compute C1(X) polynomial - if (logger) logger.info(""); - if (logger) logger.info("> ROUND 1"); - await round1(); - - delete polynomials.T0; - delete evaluations.QL; - delete evaluations.QR; - delete evaluations.QM; - delete evaluations.QO; - delete evaluations.QC; - if (globalThis.gc) globalThis.gc(); - - // ROUND 2. Compute C2(X) polynomial - if (logger) logger.info("> ROUND 2"); - await round2(); - - delete buffers.A; - delete buffers.B; - delete buffers.C; - delete evaluations.A; - delete evaluations.B; - delete evaluations.C; - delete evaluations.Sigma1; - delete evaluations.Sigma2; - delete evaluations.Sigma3; - delete evaluations.lagrange1; - delete evaluations.Z; - if (globalThis.gc) globalThis.gc(); - - // ROUND 3. Compute opening evaluations - if (logger) logger.info("> ROUND 3"); - await round3(); - - delete polynomials.A; - delete polynomials.B; - delete polynomials.C; - delete polynomials.Z; - delete polynomials.T1; - delete polynomials.T2; - delete polynomials.Sigma1; - delete polynomials.Sigma2; - delete polynomials.Sigma3; - delete polynomials.QL; - delete polynomials.QR; - delete polynomials.QM; - delete polynomials.QC; - delete polynomials.QO; - if (globalThis.gc) globalThis.gc(); - - // ROUND 4. Compute W(X) polynomial - if (logger) logger.info("> ROUND 4"); - await round4(); - if (globalThis.gc) globalThis.gc(); - - // ROUND 5. Compute W'(X) polynomial - if (logger) logger.info("> ROUND 5"); - await round5(); - - delete polynomials.C0; - delete polynomials.C1; - delete polynomials.C2; - delete polynomials.R1; - delete polynomials.R2; - delete polynomials.F; - delete polynomials.L; - delete polynomials.ZT; - delete polynomials.ZTS2; - await fdZKey.close(); - if (globalThis.gc) globalThis.gc(); - - proof.addEvaluation("inv", getMontgomeryBatchedInverse()); - - // Prepare proof - let _proof = proof.toObjectProof(); - _proof.protocol = "fflonk"; - _proof.curve = curve.name; - - // Prepare public inputs - let publicSignals = []; - - for (let i = 1; i <= zkey.nPublic; i++) { - const i_sFr = i * sFr; - - const pub = buffWitness.slice(i_sFr, i_sFr + sFr); - publicSignals.push(Scalar.fromRprLE(pub)); - } - - if (logger) logger.info("FFLONK PROVER FINISHED"); - - return { - proof: stringifyBigInts(_proof), - publicSignals: stringifyBigInts(publicSignals) - }; - - async function calculateAdditions() { - if (logger) logger.info("··· Computing additions"); - const additionsBuff = await readSection$1(fdZKey, zkeySections, ZKEY_FF_ADDITIONS_SECTION); - - // sizes: wireId_x = 4 bytes (32 bits), factor_x = field size bits - // Addition form: wireId_a wireId_b factor_a factor_b (size is 4 + 4 + sFr + sFr) - const sSum = 8 + sFr * 2; - - for (let i = 0; i < zkey.nAdditions; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` addition ${i}/${zkey.nAdditions}`); - - // Read addition values - let offset = i * sSum; - const signalId1 = readUInt32(additionsBuff, offset); - offset += 4; - const signalId2 = readUInt32(additionsBuff, offset); - offset += 4; - const factor1 = additionsBuff.slice(offset, offset + sFr); - offset += sFr; - const factor2 = additionsBuff.slice(offset, offset + sFr); - - // Get witness value - const witness1 = getWitness(signalId1); - const witness2 = getWitness(signalId2); - - //Calculate final result - const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); - - buffInternalWitness.set(result, sFr * i); - } - } - - function readUInt32(b, o) { - const buff = b.slice(o, o + 4); - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - return buffV.getUint32(0, true); - } - - function getWitness(idx) { - let diff = zkey.nVars - zkey.nAdditions; - if (idx < diff) { - return buffWitness.slice(idx * sFr, idx * sFr + sFr); - } else if (idx < zkey.nVars) { - const offset = (idx - diff) * sFr; - return buffInternalWitness.slice(offset, offset + sFr); - } - - return Fr.zero; - } - - async function round1() { - // STEP 1.1 - Generate random blinding scalars (b_1, ..., b9) ∈ F - challenges.b = []; - for (let i = 1; i <= 9; i++) { - challenges.b[i] = Fr.random(); - } - - // STEP 1.2 - Compute wire polynomials a(X), b(X) and c(X) - if (logger) logger.info("> Computing A, B, C wire polynomials"); - await computeWirePolynomials(); - - // STEP 1.3 - Compute the quotient polynomial T0(X) - if (logger) logger.info("> Computing T0 polynomial"); - await computeT0(); - - // STEP 1.4 - Compute the FFT-style combination polynomial C1(X) - if (logger) logger.info("> Computing C1 polynomial"); - await computeC1(); - - // The first output of the prover is ([C1]_1) - if (logger) logger.info("> Computing C1 multi exponentiation"); - let commitC1 = await polynomials.C1.multiExponentiation(PTau, "C1"); - proof.addPolynomial("C1", commitC1); - - return 0; - - async function computeWirePolynomials() { - if (logger) logger.info("··· Reading data from zkey file"); - // Build A, B and C evaluations buffer from zkey and witness files - buffers.A = new BigBuffer(sDomain); - buffers.B = new BigBuffer(sDomain); - buffers.C = new BigBuffer(sDomain); - - // Read zkey sections and fill the buffers - const aMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_FF_A_MAP_SECTION); - const bMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_FF_B_MAP_SECTION); - const cMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_FF_C_MAP_SECTION); - - // Compute all witness from signal ids and set them to A,B & C buffers - for (let i = 0; i < zkey.nConstraints; i++) { - const i_sFr = i * sFr; - const offset = i * 4; - - // Compute A value from a signal id - const signalIdA = readUInt32(aMapBuff, offset); - buffers.A.set(getWitness(signalIdA), i_sFr); - - // Compute B value from a signal id - const signalIdB = readUInt32(bMapBuff, offset); - buffers.B.set(getWitness(signalIdB), i_sFr); - - // Compute C value from a signal id - const signalIdC = readUInt32(cMapBuff, offset); - buffers.C.set(getWitness(signalIdC), i_sFr); - } - - // Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b - buffers.A.set(challenges.b[1], sDomain - 64); - buffers.A.set(challenges.b[2], sDomain - 32); - buffers.B.set(challenges.b[3], sDomain - 64); - buffers.B.set(challenges.b[4], sDomain - 32); - buffers.C.set(challenges.b[5], sDomain - 64); - buffers.C.set(challenges.b[6], sDomain - 32); - - buffers.A = await Fr.batchToMontgomery(buffers.A); - buffers.B = await Fr.batchToMontgomery(buffers.B); - buffers.C = await Fr.batchToMontgomery(buffers.C); - - // Compute the coefficients of the wire polynomials a(X), b(X) and c(X) from A,B & C buffers - if (logger) logger.info("··· Computing A ifft"); - polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); - if (logger) logger.info("··· Computing B ifft"); - polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); - if (logger) logger.info("··· Computing C ifft"); - polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); - - // Compute extended evaluations of a(X), b(X) and c(X) polynomials - if (logger) logger.info("··· Computing A fft"); - evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); - if (logger) logger.info("··· Computing B fft"); - evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); - if (logger) logger.info("··· Computing C fft"); - evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); - - // Check degrees - if (polynomials.A.degree() >= zkey.domainSize) { - throw new Error("A Polynomial is not well calculated"); - } - if (polynomials.B.degree() >= zkey.domainSize) { - throw new Error("B Polynomial is not well calculated"); - } - if (polynomials.C.degree() >= zkey.domainSize) { - throw new Error("C Polynomial is not well calculated"); - } - } - - async function computeT0() { - if (logger) logger.info(`··· Reading sections ${ZKEY_FF_QL_SECTION}, ${ZKEY_FF_QR_SECTION}` + - `, ${ZKEY_FF_QM_SECTION}, ${ZKEY_FF_QO_SECTION}, ${ZKEY_FF_QC_SECTION}. Q selectors`); - // Reserve memory for Q's evaluations - evaluations.QL = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QR = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QM = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QO = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QC = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QL_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QR_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QM_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QO_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QC_SECTION][0].p + sDomain); - - // Read Lagrange polynomials & evaluations from zkey file - const lagrangePolynomials = await readSection$1(fdZKey, zkeySections, ZKEY_FF_LAGRANGE_SECTION); - evaluations.lagrange1 = new Evaluations(lagrangePolynomials, curve, logger); - - // Reserve memory for buffers T0 - buffers.T0 = new BigBuffer(sDomain * 4); - - if (logger) logger.info("··· Computing T0 evaluations"); - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T0 evaluation ${i}/${zkey.domainSize * 4}`); - - // Get related evaluations to compute current T0 evaluation - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - - const ql = evaluations.QL.getEvaluation(i); - const qr = evaluations.QR.getEvaluation(i); - const qm = evaluations.QM.getEvaluation(i); - const qo = evaluations.QO.getEvaluation(i); - const qc = evaluations.QC.getEvaluation(i); - - // Compute current public input - let pi = Fr.zero; - for (let j = 0; j < zkey.nPublic; j++) { - const offset = (j * 5 * zkey.domainSize) + zkey.domainSize + i; - - const lPol = evaluations.lagrange1.getEvaluation(offset); - const aVal = buffers.A.slice(j * sFr, (j + 1) * sFr); - - pi = Fr.sub(pi, Fr.mul(lPol, aVal)); - } - - //T0(X) = [q_L(X)·a(X) + q_R(X)·b(X) + q_M(X)·a(X)·b(X) + q_O(X)·c(X) + q_C(X) + PI(X)] · 1/Z_H(X) - // Compute first T0(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - // expression 1 -> q_L(X)·a(X) - const e1 = Fr.mul(a, ql); - - // expression 2 -> q_R(X)·b(X) - const e2 = Fr.mul(b, qr); - - // expression 3 -> q_M(X)·a(X)·b(X) - const e3 = Fr.mul(Fr.mul(a, b), qm); - - // expression 4 -> q_O(X)·c(X) - const e4 = Fr.mul(c, qo); - - // t0 = expressions 1 + expression 2 + expression 3 + expression 4 + qc + pi - const t0 = Fr.add(e1, Fr.add(e2, Fr.add(e3, Fr.add(e4, Fr.add(qc, pi))))); - - buffers.T0.set(t0, i * sFr); - } - - if (logger) logger.info("buffer T0: " + buffers.T0.byteLength / sFr); - - // Compute the coefficients of the polynomial T0(X) from buffers.T0 - if (logger) logger.info("··· Computing T0 ifft"); - polynomials.T0 = await Polynomial.fromEvaluations(buffers.T0, curve, logger); - - if (logger) logger.info("T0 length: " + polynomials.T0.length()); - if (logger) logger.info("T0 degree: " + polynomials.T0.degree()); - - // Divide the polynomial T0 by Z_H(X) - if (logger) logger.info("··· Computing T0 / ZH"); - polynomials.T0.divByZerofier(zkey.domainSize, Fr.one); - - // Check degree - if (polynomials.T0.degree() >= 2 * zkey.domainSize - 2) { - throw new Error(`T0 Polynomial is not well calculated (degree is ${polynomials.T0.degree()} and must be less than ${2 * zkey.domainSize + 2}`); - } - - delete buffers.T0; - } - - async function computeC1() { - let C1 = new CPolynomial(4, curve, logger); - C1.addPolynomial(0, polynomials.A); - C1.addPolynomial(1, polynomials.B); - C1.addPolynomial(2, polynomials.C); - C1.addPolynomial(3, polynomials.T0); - - polynomials.C1 = C1.getPolynomial(); - - // Check degree - if (polynomials.C1.degree() >= 8 * zkey.domainSize - 8) { - throw new Error("C1 Polynomial is not well calculated"); - } - } - } - - async function round2() { - // STEP 2.1 - Compute permutation challenge beta and gamma ∈ F - // Compute permutation challenge beta - if (logger) logger.info("> Computing challenges beta and gamma"); - const transcript = new Keccak256Transcript(curve); - - // Add C0 to the transcript - transcript.addPolCommitment(zkey.C0); - - // Add A to the transcript - for (let i = 0; i < zkey.nPublic; i++) { - transcript.addScalar(buffers.A.slice(i * sFr, i * sFr + sFr)); - } - - // Add C1 to the transcript - transcript.addPolCommitment(proof.getPolynomial("C1")); - - challenges.beta = transcript.getChallenge(); - if (logger) logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); - - // Compute permutation challenge gamma - transcript.reset(); - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - if (logger) logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); - - // STEP 2.2 - Compute permutation polynomial z(X) - if (logger) logger.info("> Computing Z polynomial"); - await computeZ(); - - // STEP 2.3 - Compute quotient polynomial T1(X) and T2(X) - if (logger) logger.info("> Computing T1 polynomial"); - await computeT1(); - if (logger) logger.info("> Computing T2 polynomial"); - await computeT2(); - - // STEP 2.4 - Compute the FFT-style combination polynomial C2(X) - if (logger) logger.info("> Computing C2 polynomial"); - await computeC2(); - - // The second output of the prover is ([C2]_1) - if (logger) logger.info("> Computing C2 multi exponentiation"); - let commitC2 = await polynomials.C2.multiExponentiation(PTau, "C2"); - proof.addPolynomial("C2", commitC2); - - return 0; - - async function computeZ() { - if (logger) logger.info("··· Computing Z evaluations"); - - let numArr = new BigBuffer(sDomain); - let denArr = new BigBuffer(sDomain); - - // Set the first values to 1 - numArr.set(Fr.one, 0); - denArr.set(Fr.one, 0); - - // Set initial omega - let w = Fr.one; - for (let i = 0; i < zkey.domainSize; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` Z evaluation ${i}/${zkey.domainSize}`); - const i_sFr = i * sFr; - - // Z(X) := numArr / denArr - // numArr := (a + beta·ω + gamma)(b + beta·ω·k1 + gamma)(c + beta·ω·k2 + gamma) - const betaw = Fr.mul(challenges.beta, w); - - let num1 = buffers.A.slice(i_sFr, i_sFr + sFr); - num1 = Fr.add(num1, betaw); - num1 = Fr.add(num1, challenges.gamma); - - let num2 = buffers.B.slice(i_sFr, i_sFr + sFr); - num2 = Fr.add(num2, Fr.mul(zkey.k1, betaw)); - num2 = Fr.add(num2, challenges.gamma); - - let num3 = buffers.C.slice(i_sFr, i_sFr + sFr); - num3 = Fr.add(num3, Fr.mul(zkey.k2, betaw)); - num3 = Fr.add(num3, challenges.gamma); - - let num = Fr.mul(num1, Fr.mul(num2, num3)); - - // denArr := (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma) - let den1 = buffers.A.slice(i_sFr, i_sFr + sFr); - den1 = Fr.add(den1, Fr.mul(challenges.beta, evaluations.Sigma1.getEvaluation(i * 4))); - den1 = Fr.add(den1, challenges.gamma); - - let den2 = buffers.B.slice(i_sFr, i_sFr + sFr); - den2 = Fr.add(den2, Fr.mul(challenges.beta, evaluations.Sigma2.getEvaluation(i * 4))); - den2 = Fr.add(den2, challenges.gamma); - - let den3 = buffers.C.slice(i_sFr, i_sFr + sFr); - den3 = Fr.add(den3, Fr.mul(challenges.beta, evaluations.Sigma3.getEvaluation(i * 4))); - den3 = Fr.add(den3, challenges.gamma); - - let den = Fr.mul(den1, Fr.mul(den2, den3)); - - // Multiply current num value with the previous one saved in numArr - num = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), num); - numArr.set(num, ((i + 1) % zkey.domainSize) * sFr); - - // Multiply current den value with the previous one saved in denArr - den = Fr.mul(denArr.slice(i_sFr, i_sFr + sFr), den); - denArr.set(den, ((i + 1) % zkey.domainSize) * sFr); - - // Next omega - w = Fr.mul(w, Fr.w[zkey.power]); - } - // Compute the inverse of denArr to compute in the next command the - // division numArr/denArr by multiplying num · 1/denArr - denArr = await Fr.batchInverse(denArr); - - // TODO: Do it in assembly and in parallel - // Multiply numArr · denArr where denArr was inverted in the previous command - for (let i = 0; i < zkey.domainSize; i++) { - const i_sFr = i * sFr; - - const z = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), denArr.slice(i_sFr, i_sFr + sFr)); - numArr.set(z, i_sFr); - } - // From now on the values saved on numArr will be Z(X) buffer - buffers.Z = numArr; - - if (!Fr.eq(numArr.slice(0, sFr), Fr.one)) { - throw new Error("Copy constraints does not match"); - } - - // Compute polynomial coefficients z(X) from buffers.Z - if (logger) logger.info("··· Computing Z ifft"); - polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); - - // Compute extended evaluations of z(X) polynomial - if (logger) logger.info("··· Computing Z fft"); - evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); - - // Blind z(X) polynomial coefficients with blinding scalars b - polynomials.Z.blindCoefficients([challenges.b[9], challenges.b[8], challenges.b[7]]); - - // Check degree - if (polynomials.Z.degree() >= zkey.domainSize + 3) { - throw new Error("Z Polynomial is not well calculated"); - } - - delete buffers.Z; - } - - async function computeT1() { - if (logger) logger.info("··· Computing T1 evaluations"); - - buffers.T1 = new BigBuffer(sDomain * 2); - buffers.T1z = new BigBuffer(sDomain * 2); - - // Set initial omega - let omega = Fr.one; - for (let i = 0; i < zkey.domainSize * 2; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T1 evaluation ${i}/${zkey.domainSize * 4}`); - - const omega2 = Fr.square(omega); - - const z = evaluations.Z.getEvaluation(i * 2); - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); - - // T1(X) := (z(X) - 1) · L_1(X) - // Compute first T1(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - const lagrange1 = evaluations.lagrange1.getEvaluation(zkey.domainSize + i * 2); - let t1 = Fr.mul(Fr.sub(z, Fr.one), lagrange1); - let t1z = Fr.mul(zp, lagrange1); - - buffers.T1.set(t1, i * sFr); - buffers.T1z.set(t1z, i * sFr); - - // Compute next omega - omega = Fr.mul(omega, Fr.w[zkey.power + 1]); - } - - // Compute the coefficients of the polynomial T1(X) from buffers.T1 - if (logger) logger.info("··· Computing T1 ifft"); - polynomials.T1 = await Polynomial.fromEvaluations(buffers.T1, curve, logger); - - // Divide the polynomial T1 by Z_H(X) - polynomials.T1.divByZerofier(zkey.domainSize, Fr.one); - - // Compute the coefficients of the polynomial T1z(X) from buffers.T1z - if (logger) logger.info("··· Computing T1z ifft"); - polynomials.T1z = await Polynomial.fromEvaluations(buffers.T1z, curve, logger); - - // Add the polynomial T1z to T1 to get the final polynomial T1 - polynomials.T1.add(polynomials.T1z); - - // Check degree - if (polynomials.T1.degree() >= zkey.domainSize + 2) { - throw new Error("T1 Polynomial is not well calculated"); - } - - delete buffers.T1; - delete buffers.T1z; - delete polynomials.T1z; - } - - async function computeT2() { - if (logger) logger.info("··· Computing T2 evaluations"); - - buffers.T2 = new BigBuffer(sDomain * 4); - buffers.T2z = new BigBuffer(sDomain * 4); - - // Set initial omega - let omega = Fr.one; - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T2 evaluation ${i}/${zkey.domainSize * 4}`); - - const omega2 = Fr.square(omega); - const omegaW = Fr.mul(omega, Fr.w[zkey.power]); - const omegaW2 = Fr.square(omegaW); - - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - const z = evaluations.Z.getEvaluation(i); - const zW = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); - - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); - const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omegaW2), Fr.mul(challenges.b[8], omegaW)), challenges.b[9]); - - const sigma1 = evaluations.Sigma1.getEvaluation(i); - const sigma2 = evaluations.Sigma2.getEvaluation(i); - const sigma3 = evaluations.Sigma3.getEvaluation(i); - - // T2(X) := [ (a(X) + beta·X + gamma)(b(X) + beta·k1·X + gamma)(c(X) + beta·k2·X + gamma)z(X) - // -(a(X) + beta·sigma1(X) + gamma)(b(X) + beta·sigma2(X) + gamma)(c(X) + beta·sigma3(X) + gamma)z(Xω)] · 1/Z_H(X) - // Compute first T2(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - - // expression 1 -> (a(X) + beta·X + gamma)(b(X) + beta·k1·X + gamma)(c(X) + beta·k2·X + gamma)z(X) - const betaX = Fr.mul(challenges.beta, omega); - - let e11 = Fr.add(a, betaX); - e11 = Fr.add(e11, challenges.gamma); - - let e12 = Fr.add(b, Fr.mul(betaX, zkey.k1)); - e12 = Fr.add(e12, challenges.gamma); - - let e13 = Fr.add(c, Fr.mul(betaX, zkey.k2)); - e13 = Fr.add(e13, challenges.gamma); - - let e1 = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), z); - let e1z = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), zp); - // const [e1, e1z] = MulZ.mul4(e11, e12, e13, z, ap, bp, cp, zp, i % 4, Fr); - - // expression 2 -> (a(X) + beta·sigma1(X) + gamma)(b(X) + beta·sigma2(X) + gamma)(c(X) + beta·sigma3(X) + gamma)z(Xω) - let e21 = Fr.add(a, Fr.mul(challenges.beta, sigma1)); - e21 = Fr.add(e21, challenges.gamma); - - let e22 = Fr.add(b, Fr.mul(challenges.beta, sigma2)); - e22 = Fr.add(e22, challenges.gamma); - - let e23 = Fr.add(c, Fr.mul(challenges.beta, sigma3)); - e23 = Fr.add(e23, challenges.gamma); - - let e2 = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zW); - let e2z = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zWp); - // const [e2, e2z] = MulZ.mul4(e21, e22, e23, zW, ap, bp, cp, zWp, i % 4, Fr); - - let t2 = Fr.sub(e1, e2); - let t2z = Fr.sub(e1z, e2z); - - buffers.T2.set(t2, i * sFr); - buffers.T2z.set(t2z, i * sFr); - - // Compute next omega - omega = Fr.mul(omega, Fr.w[zkey.power + 2]); - } - - // Compute the coefficients of the polynomial T2(X) from buffers.T2 - if (logger) logger.info("··· Computing T2 ifft"); - polynomials.T2 = await Polynomial.fromEvaluations(buffers.T2, curve, logger); - - // Divide the polynomial T2 by Z_H(X) - if (logger) logger.info("··· Computing T2 / ZH"); - polynomials.T2.divByZerofier(zkey.domainSize, Fr.one); - - // Compute the coefficients of the polynomial T2z(X) from buffers.T2z - if (logger) logger.info("··· Computing T2z ifft"); - polynomials.T2z = await Polynomial.fromEvaluations(buffers.T2z, curve, logger); - - // Add the polynomial T2z to T2 to get the final polynomial T2 - polynomials.T2.add(polynomials.T2z); - - // Check degree - if (polynomials.T2.degree() >= 3 * zkey.domainSize) { - throw new Error("T2 Polynomial is not well calculated"); - } - - delete buffers.T2; - delete buffers.T2z; - delete polynomials.T2z; - } - - async function computeC2() { - let C2 = new CPolynomial(3, curve, logger); - C2.addPolynomial(0, polynomials.Z); - C2.addPolynomial(1, polynomials.T1); - C2.addPolynomial(2, polynomials.T2); - - polynomials.C2 = C2.getPolynomial(); - - // Check degree - if (polynomials.C2.degree() >= 9 * zkey.domainSize) { - throw new Error("C2 Polynomial is not well calculated"); - } - } - } - - async function round3() { - if (logger) logger.info("> Computing challenge xi"); - // STEP 3.1 - Compute evaluation challenge xi ∈ S - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.getPolynomial("C2")); - - // Obtain a xi_seeder from the transcript - // To force h1^4 = xi, h2^3 = xi and h_3^2 = xiω - // we compute xi = xi_seeder^12, h1 = xi_seeder^3, h2 = xi_seeder^4 and h3 = xi_seeder^6 - challenges.xiSeed = transcript.getChallenge(); - const xiSeed2 = Fr.square(challenges.xiSeed); - - // Compute omega8, omega4 and omega3 - roots.w8 = []; - roots.w8[0] = Fr.one; - for (let i = 1; i < 8; i++) { - roots.w8[i] = Fr.mul(roots.w8[i - 1], zkey.w8); - } - - roots.w4 = []; - roots.w4[0] = Fr.one; - for (let i = 1; i < 4; i++) { - roots.w4[i] = Fr.mul(roots.w4[i - 1], zkey.w4); - } - - roots.w3 = []; - roots.w3[0] = Fr.one; - roots.w3[1] = zkey.w3; - roots.w3[2] = Fr.square(zkey.w3); - - // Compute h0 = xiSeeder^3 - roots.S0 = {}; - roots.S0.h0w8 = []; - roots.S0.h0w8[0] = Fr.mul(xiSeed2, challenges.xiSeed); - for (let i = 1; i < 8; i++) { - roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], roots.w8[i]); - } - - // Compute h1 = xi_seeder^6 - roots.S1 = {}; - roots.S1.h1w4 = []; - roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); - for (let i = 1; i < 4; i++) { - roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], roots.w4[i]); - } - - // Compute h2 = xi_seeder^8 - roots.S2 = {}; - roots.S2.h2w3 = []; - roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); - roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], roots.w3[1]); - roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], roots.w3[2]); - - roots.S2.h3w3 = []; - // Multiply h3 by third-root-omega to obtain h_3^3 = xiω - // So, h3 = xi_seeder^8 ω^{1/3} - roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], zkey.wr); - roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], roots.w3[1]); - roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], roots.w3[2]); - - // Compute xi = xi_seeder^24 - challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); - - if (logger) logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); - - // Reserve memory for Q's polynomials - polynomials.QL = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QR = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QM = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QO = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QC = new Polynomial(new BigBuffer(sDomain), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[ZKEY_FF_QL_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[ZKEY_FF_QR_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[ZKEY_FF_QM_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[ZKEY_FF_QO_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[ZKEY_FF_QC_SECTION][0].p); - - // STEP 3.2 - Compute opening evaluations and add them to the proof (third output of the prover) - if (logger) logger.info("··· Computing evaluations"); - proof.addEvaluation("ql", polynomials.QL.evaluate(challenges.xi)); - proof.addEvaluation("qr", polynomials.QR.evaluate(challenges.xi)); - proof.addEvaluation("qm", polynomials.QM.evaluate(challenges.xi)); - proof.addEvaluation("qo", polynomials.QO.evaluate(challenges.xi)); - proof.addEvaluation("qc", polynomials.QC.evaluate(challenges.xi)); - proof.addEvaluation("s1", polynomials.Sigma1.evaluate(challenges.xi)); - proof.addEvaluation("s2", polynomials.Sigma2.evaluate(challenges.xi)); - proof.addEvaluation("s3", polynomials.Sigma3.evaluate(challenges.xi)); - proof.addEvaluation("a", polynomials.A.evaluate(challenges.xi)); - proof.addEvaluation("b", polynomials.B.evaluate(challenges.xi)); - proof.addEvaluation("c", polynomials.C.evaluate(challenges.xi)); - proof.addEvaluation("z", polynomials.Z.evaluate(challenges.xi)); - - challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); - proof.addEvaluation("zw", polynomials.Z.evaluate(challenges.xiw)); - proof.addEvaluation("t1w", polynomials.T1.evaluate(challenges.xiw)); - proof.addEvaluation("t2w", polynomials.T2.evaluate(challenges.xiw)); - } - - async function round4() { - if (logger) logger.info("> Computing challenge alpha"); - // STEP 4.1 - Compute challenge alpha ∈ F - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.xiSeed); - transcript.addScalar(proof.getEvaluation("ql")); - transcript.addScalar(proof.getEvaluation("qr")); - transcript.addScalar(proof.getEvaluation("qm")); - transcript.addScalar(proof.getEvaluation("qo")); - transcript.addScalar(proof.getEvaluation("qc")); - transcript.addScalar(proof.getEvaluation("s1")); - transcript.addScalar(proof.getEvaluation("s2")); - transcript.addScalar(proof.getEvaluation("s3")); - transcript.addScalar(proof.getEvaluation("a")); - transcript.addScalar(proof.getEvaluation("b")); - transcript.addScalar(proof.getEvaluation("c")); - transcript.addScalar(proof.getEvaluation("z")); - transcript.addScalar(proof.getEvaluation("zw")); - transcript.addScalar(proof.getEvaluation("t1w")); - transcript.addScalar(proof.getEvaluation("t2w")); - challenges.alpha = transcript.getChallenge(); - if (logger) logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); - - // STEP 4.2 - Compute F(X) - if (logger) logger.info("> Reading C0 polynomial"); - polynomials.C0 = new Polynomial(new BigBuffer(sDomain * 8), curve, logger); - await fdZKey.readToBuffer(polynomials.C0.coef, 0, sDomain * 8, zkeySections[ZKEY_FF_C0_SECTION][0].p); - - if (logger) logger.info("> Computing R0 polynomial"); - computeR0(); - if (logger) logger.info("> Computing R1 polynomial"); - computeR1(); - if (logger) logger.info("> Computing R2 polynomial"); - computeR2(); - - if (logger) logger.info("> Computing F polynomial"); - await computeF(); - - // The fourth output of the prover is ([W1]_1), where W1:=(f/Z_t)(x) - if (logger) logger.info("> Computing W1 multi exponentiation"); - let commitW1 = await polynomials.F.multiExponentiation(PTau, "W1"); - proof.addPolynomial("W1", commitW1); - - return 0; - - function computeR0() { - // COMPUTE R0 - // Compute the coefficients of R0(X) from 8 evaluations using lagrange interpolation. R0(X) ∈ F_{<8}[X] - // We decide to use Lagrange interpolations because the R0 degree is very small (deg(R0)===7), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R0 = Polynomial.lagrangePolynomialInterpolation( - [roots.S0.h0w8[0], roots.S0.h0w8[1], roots.S0.h0w8[2], roots.S0.h0w8[3], - roots.S0.h0w8[4], roots.S0.h0w8[5], roots.S0.h0w8[6], roots.S0.h0w8[7]], - [polynomials.C0.evaluate(roots.S0.h0w8[0]), polynomials.C0.evaluate(roots.S0.h0w8[1]), - polynomials.C0.evaluate(roots.S0.h0w8[2]), polynomials.C0.evaluate(roots.S0.h0w8[3]), - polynomials.C0.evaluate(roots.S0.h0w8[4]), polynomials.C0.evaluate(roots.S0.h0w8[5]), - polynomials.C0.evaluate(roots.S0.h0w8[6]), polynomials.C0.evaluate(roots.S0.h0w8[7])], curve); - - // Check the degree of r0(X) < 8 - if (polynomials.R0.degree() > 7) { - throw new Error("R0 Polynomial is not well calculated"); - } - } - - function computeR1() { - // COMPUTE R1 - // Compute the coefficients of R1(X) from 4 evaluations using lagrange interpolation. R1(X) ∈ F_{<4}[X] - // We decide to use Lagrange interpolations because the R1 degree is very small (deg(R1)===3), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R1 = Polynomial.lagrangePolynomialInterpolation( - [roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3]], - [polynomials.C1.evaluate(roots.S1.h1w4[0]), polynomials.C1.evaluate(roots.S1.h1w4[1]), - polynomials.C1.evaluate(roots.S1.h1w4[2]), polynomials.C1.evaluate(roots.S1.h1w4[3])], curve); - - // Check the degree of r1(X) < 4 - if (polynomials.R1.degree() > 3) { - throw new Error("R1 Polynomial is not well calculated"); - } - } - - function computeR2() { - // COMPUTE R2 - // Compute the coefficients of r2(X) from 6 evaluations using lagrange interpolation. r2(X) ∈ F_{<6}[X] - // We decide to use Lagrange interpolations because the R2.degree is very small (deg(R2)===5), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R2 = Polynomial.lagrangePolynomialInterpolation( - [roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], - [polynomials.C2.evaluate(roots.S2.h2w3[0]), polynomials.C2.evaluate(roots.S2.h2w3[1]), - polynomials.C2.evaluate(roots.S2.h2w3[2]), polynomials.C2.evaluate(roots.S2.h3w3[0]), - polynomials.C2.evaluate(roots.S2.h3w3[1]), polynomials.C2.evaluate(roots.S2.h3w3[2])], curve); - - // Check the degree of r2(X) < 6 - if (polynomials.R2.degree() > 5) { - throw new Error("R2 Polynomial is not well calculated"); - } - } - - async function computeF() { - if (logger) logger.info("··· Computing F polynomial"); - - // COMPUTE F(X) - polynomials.F = Polynomial.fromPolynomial(polynomials.C0, curve, logger); - polynomials.F.sub(polynomials.R0); - polynomials.F.divByZerofier(8, challenges.xi); - - let f2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); - f2.sub(polynomials.R1); - f2.mulScalar(challenges.alpha); - f2.divByZerofier(4, challenges.xi); - - let f3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); - f3.sub(polynomials.R2); - f3.mulScalar(Fr.square(challenges.alpha)); - f3.divByZerofier(3, challenges.xi); - f3.divByZerofier(3, challenges.xiw); - - polynomials.F.add(f2); - polynomials.F.add(f3); - - if (polynomials.F.degree() >= 9 * zkey.domainSize - 6) { - throw new Error("F Polynomial is not well calculated"); - } - } - } - - async function round5() { - if (logger) logger.info("> Computing challenge y"); - - // STEP 5.1 - Compute random evaluation point y ∈ F - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.getPolynomial("W1")); - - challenges.y = transcript.getChallenge(); - if (logger) logger.info("··· challenges.y: " + Fr.toString(challenges.y)); - - // STEP 5.2 - Compute L(X) - if (logger) logger.info("> Computing L polynomial"); - await computeL(); - - if (logger) logger.info("> Computing ZTS2 polynomial"); - await computeZTS2(); - - let ZTS2Y = polynomials.ZTS2.evaluate(challenges.y); - ZTS2Y = Fr.inv(ZTS2Y); - polynomials.L.mulScalar(ZTS2Y); - - const polDividend = Polynomial.fromCoefficientsArray([Fr.neg(challenges.y), Fr.one], curve); - if (logger) logger.info("> Computing W' = L / ZTS2 polynomial"); - const polRemainder = polynomials.L.divBy(polDividend); - - //Check polReminder degree is equal to zero - if (polRemainder.degree() > 0) { - throw new Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${polRemainder.degree()} and should be 0`); - } - - if (polynomials.L.degree() >= 9 * zkey.domainSize - 1) { - throw new Error("Degree of L(X)/(ZTS2(y)(X-y)) is not correct"); - } - - // The fifth output of the prover is ([W2]_1), where W2:=(f/Z_t)(x) - if (logger) logger.info("> Computing W' multi exponentiation"); - let commitW2 = await polynomials.L.multiExponentiation(PTau, "W2"); - proof.addPolynomial("W2", commitW2); - - return 0; - - async function computeL() { - if (logger) logger.info("··· Computing L polynomial"); - - const evalR0Y = polynomials.R0.evaluate(challenges.y); - const evalR1Y = polynomials.R1.evaluate(challenges.y); - const evalR2Y = polynomials.R2.evaluate(challenges.y); - - let mulL0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); - for (let i = 1; i < 8; i++) { - mulL0 = Fr.mul(mulL0, Fr.sub(challenges.y, roots.S0.h0w8[i])); - } - - let mulL1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); - for (let i = 1; i < 4; i++) { - mulL1 = Fr.mul(mulL1, Fr.sub(challenges.y, roots.S1.h1w4[i])); - } - - let mulL2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); - for (let i = 1; i < 3; i++) { - mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h2w3[i])); - } - for (let i = 0; i < 3; i++) { - mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h3w3[i])); - } - - let preL0 = Fr.mul(mulL1, mulL2); - let preL1 = Fr.mul(challenges.alpha, Fr.mul(mulL0, mulL2)); - let preL2 = Fr.mul(Fr.square(challenges.alpha), Fr.mul(mulL0, mulL1)); - - toInverse["denH1"] = mulL1; - toInverse["denH2"] = mulL2; - - // COMPUTE L(X) - polynomials.L = Polynomial.fromPolynomial(polynomials.C0, curve, logger); - polynomials.L.subScalar(evalR0Y); - polynomials.L.mulScalar(preL0); - - let l2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); - l2.subScalar(evalR1Y); - l2.mulScalar(preL1); - - let l3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); - l3.subScalar(evalR2Y); - l3.mulScalar(preL2); - - polynomials.L.add(l2); - polynomials.L.add(l3); - - if (logger) logger.info("> Computing ZT polynomial"); - await computeZT(); - - const evalZTY = polynomials.ZT.evaluate(challenges.y); - polynomials.F.mulScalar(evalZTY); - polynomials.L.sub(polynomials.F); - - // Check degree - if (polynomials.L.degree() >= 9 * zkey.domainSize) { - throw new Error("L Polynomial is not well calculated"); - } - - delete buffers.L; - } - - async function computeZT() { - polynomials.ZT = Polynomial.zerofierPolynomial( - [ - roots.S0.h0w8[0], roots.S0.h0w8[1], roots.S0.h0w8[2], roots.S0.h0w8[3], - roots.S0.h0w8[4], roots.S0.h0w8[5], roots.S0.h0w8[6], roots.S0.h0w8[7], - roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3], - roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], curve); - } - - async function computeZTS2() { - polynomials.ZTS2 = Polynomial.zerofierPolynomial( - [roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3], - roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], curve); - } - } - - function getMontgomeryBatchedInverse() { - // · denominator needed in step 8 and 9 of the verifier to multiply by 1/Z_H(xi) - let xiN = challenges.xi; - for (let i = 0; i < zkey.power; i++) { - xiN = Fr.square(xiN); - } - toInverse["zh"] = Fr.sub(xiN, Fr.one); - - // · denominator needed in step 10 and 11 of the verifier - // toInverse.denH1 & toInverse.denH2 -> Computed in round5, computeL() - - // · denominator needed in the verifier when computing L_i^{S0}(X), L_i^{S1}(X) and L_i^{S2}(X) - computeLiS0(toInverse, roots.S0.h0w8, challenges.y, curve); - - computeLiS1(toInverse, roots.S1.h1w4, challenges.y, curve); - - computeLiS2(toInverse, roots.S2.h2w3, roots.S2.h3w3, challenges.y, challenges.xi, challenges.xiw, curve); - - // · L_i i=1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) - const size = Math.max(1, zkey.nPublic); - - let w = Fr.one; - for (let i = 0; i < size; i++) { - toInverse["Li_" + (i + 1)] = Fr.mul(Fr.e(zkey.domainSize), Fr.sub(challenges.xi, w)); - w = Fr.mul(w, Fr.w[zkey.power]); - } - - let mulAccumulator = Fr.one; - for (const element of Object.values(toInverse)) { - if(Array.isArray(element)) { - for (const subElement of element) { - mulAccumulator = Fr.mul(mulAccumulator, subElement); - } - } else { - mulAccumulator = Fr.mul(mulAccumulator, element); - } - } - return Fr.inv(mulAccumulator); - - - function computeLiS0(toInverse, roots, x, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - toInverse[["LiS0_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); - } - - return Li; - } - - function computeLiS1(toInverse, roots, x, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - toInverse[["LiS1_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); - - } - - return Li; - } - - function computeLiS2(toInverse, S2, S2p, value, xi, xiw, curve) { - const Fr = curve.Fr; - - const Li = []; - - const _3h2 = Fr.mul(Fr.e(3), S2[0]); - const xisubxiw = Fr.sub(xi, xiw); - let den1 = Fr.mul(_3h2, xisubxiw); - for (let i = 0; i < 3; i++) { - const den2 = S2[2 * i % 3]; - const den3 = Fr.sub(value, S2[i]); - - toInverse[["LiS2_" + (i + 1)]] = Fr.mul(den1,Fr.mul(den2, den3)); - - } - - const _3h3 = Fr.mul(Fr.e(3), S2p[0]); - const xiwsubxi = Fr.sub(xiw, xi); - den1 = Fr.mul(_3h3, xiwsubxi); - for (let i = 0; i < 3; i++) { - const den2 = S2p[2 * i % 3]; - const den3 = Fr.sub(value, S2p[i]); - - toInverse[["LiS2_" + (i + 1 + 3)]] = Fr.mul(den1,Fr.mul(den2, den3)); - } - - return Li; - } - } -} - -/* - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const {unstringifyBigInts: unstringifyBigInts$2} = utils; - -async function fflonkFullProve(_input, wasmFilename, zkeyFilename, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$2(_input); - - const wtns= {type: "mem"}; - - // Compute the witness - await wtnsCalculate(input, wasmFilename, wtns, wtnsCalcOptions); - - // Compute the proof - return await fflonkProve(zkeyFilename, wtns, logger, proverOptions); -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const { unstringifyBigInts: unstringifyBigInts$1 } = utils; - -async function fflonkVerify(_vk_verifier, _publicSignals, _proof, logger) { - if (logger) logger.info("FFLONK VERIFIER STARTED"); - - _vk_verifier = unstringifyBigInts$1(_vk_verifier); - _proof = unstringifyBigInts$1(_proof); - - const curve = await getCurveFromName(_vk_verifier.curve); - - const vk = fromObjectVk(curve, _vk_verifier); - - // TODO ??? Compute wr^3 and check if it matches with w - - const proof = new Proof(curve, logger); - proof.fromObjectProof(_proof); - - const publicSignals = unstringifyBigInts$1(_publicSignals); - - if (publicSignals.length !== vk.nPublic) { - logger.error("Number of public signals does not match with vk"); - return false; - } - - const Fr = curve.Fr; - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK VERIFY SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${vk.power}`); - logger.info(` Domain size: ${2 ** vk.power}`); - logger.info(` Public vars: ${vk.nPublic}`); - logger.info("----------------------------"); - } - - // STEP 1 - Validate that all polynomial commitments ∈ G_1 - if (logger) logger.info("> Checking commitments belong to G1"); - if (!commitmentsBelongToG1(curve, proof, vk)) { - if (logger) logger.error("Proof commitments are not valid"); - return false; - } - - // STEP 2 - Validate that all evaluations ∈ F - if (logger) logger.info("> Checking evaluations belong to F"); - if (!evaluationsAreValid(curve, proof)) { - if (logger) logger.error("Proof evaluations are not valid."); - return false; - } - - // STEP 3 - Validate that w_i ∈ F for i ∈ [l] - if (logger) logger.info("> Checking public inputs belong to F"); - if (!publicInputsAreValid(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - // STEP 4 - Compute the challenges: beta, gamma, xi, alpha and y ∈ F - // as in prover description, from the common preprocessed inputs, public inputs and elements of π_SNARK - if (logger) logger.info("> Computing challenges"); - const { challenges, roots } = computeChallenges(curve, proof, vk, publicSignals, logger); - - // STEP 5 - Compute the zero polynomial evaluation Z_H(xi) = xi^n - 1 - if (logger) logger.info("> Computing Zero polynomial evaluation Z_H(xi)"); - challenges.zh = Fr.sub(challenges.xiN, Fr.one); - challenges.invzh = Fr.inv(challenges.zh); - - // STEP 6 - Compute the lagrange polynomial evaluation L_1(xi) - if (logger) logger.info("> Computing Lagrange evaluations"); - const lagrangeEvals = await computeLagrangeEvaluations(curve, challenges, vk); - - // STEP 7 - Compute public input evaluation PI(xi) - if (logger) logger.info("> Computing polynomial identities PI(X)"); - const pi = calculatePI(curve, publicSignals, lagrangeEvals); - - // STEP 8 - Compute polynomial r0 ∈ F_{<4}[X] - if (logger) logger.info("> Computing r0(y)"); - const r0 = computeR0(proof, challenges, roots, curve, logger); - - // STEP 9 - Compute polynomial r1 ∈ F_{<4}[X] - if (logger) logger.info("> Computing r1(y)"); - const r1 = computeR1(proof, challenges, roots, pi, curve, logger); - - // STEP 9 - Compute polynomial r2 ∈ F_{<6}[X] - if (logger) logger.info("> Computing r2(y)"); - const r2 = computeR2(proof, challenges, roots, lagrangeEvals[1], vk, curve, logger); - - if (logger) logger.info("> Computing F"); - const F = computeF(curve, proof, vk, challenges, roots); - - if (logger) logger.info("> Computing E"); - const E = computeE(curve, proof, challenges, vk, r0, r1, r2); - - if (logger) logger.info("> Computing J"); - const J = computeJ(curve, proof, challenges); - - if (logger) logger.info("> Validate all evaluations with a pairing"); - const res = await isValidPairing(curve, proof, challenges, vk, F, E, J); - - if (logger) { - if (res) { - logger.info("PROOF VERIFIED SUCCESSFULLY"); - } else { - logger.warn("Invalid Proof"); - } - } - - if (logger) logger.info("FFLONK VERIFIER FINISHED"); - - return res; - -} - -function fromObjectVk(curve, vk) { - const res = vk; - res.k1 = curve.Fr.fromObject(vk.k1); - res.k2 = curve.Fr.fromObject(vk.k2); - res.w = curve.Fr.fromObject(vk.w); - // res.wW = curve.Fr.fromObject(vk.wW); - res.w3 = curve.Fr.fromObject(vk.w3); - res.w4 = curve.Fr.fromObject(vk.w4); - res.w8 = curve.Fr.fromObject(vk.w8); - res.wr = curve.Fr.fromObject(vk.wr); - res.X_2 = curve.G2.fromObject(vk.X_2); - res.C0 = curve.G1.fromObject(vk.C0); - return res; -} - -function commitmentsBelongToG1(curve, proof, vk) { - const G1 = curve.G1; - return G1.isValid(proof.polynomials.C1) - && G1.isValid(proof.polynomials.C2) - && G1.isValid(proof.polynomials.W1) - && G1.isValid(proof.polynomials.W2) - && G1.isValid(vk.C0); -} - -function checkValueBelongToField(curve, value) { - return Scalar.geq(value, 0) && Scalar.lt(value, curve.r); -} - -function checkEvaluationIsValid(curve, evaluation) { - return checkValueBelongToField(curve, Scalar.fromRprLE(evaluation)); -} - -function evaluationsAreValid(curve, proof) { - return checkEvaluationIsValid(curve, proof.evaluations.ql) - && checkEvaluationIsValid(curve, proof.evaluations.qr) - && checkEvaluationIsValid(curve, proof.evaluations.qm) - && checkEvaluationIsValid(curve, proof.evaluations.qo) - && checkEvaluationIsValid(curve, proof.evaluations.qc) - && checkEvaluationIsValid(curve, proof.evaluations.s1) - && checkEvaluationIsValid(curve, proof.evaluations.s2) - && checkEvaluationIsValid(curve, proof.evaluations.s3) - && checkEvaluationIsValid(curve, proof.evaluations.a) - && checkEvaluationIsValid(curve, proof.evaluations.b) - && checkEvaluationIsValid(curve, proof.evaluations.c) - && checkEvaluationIsValid(curve, proof.evaluations.z) - && checkEvaluationIsValid(curve, proof.evaluations.zw) - && checkEvaluationIsValid(curve, proof.evaluations.t1w) - && checkEvaluationIsValid(curve, proof.evaluations.t2w); -} - -function publicInputsAreValid(curve, publicInputs) { - for(let i = 0; i < publicInputs.length; i++) { - if(!checkValueBelongToField(curve, publicInputs[i])) { - return false; - } - } - return true; -} - -function computeChallenges(curve, proof, vk, publicSignals, logger) { - const Fr = curve.Fr; - - const challenges = {}; - const roots = {}; - const transcript = new Keccak256Transcript(curve); - - // Add C0 to the transcript - transcript.addPolCommitment(vk.C0); - - for (let i = 0; i < publicSignals.length; i++) { - transcript.addScalar(Fr.e(publicSignals[i])); - } - - transcript.addPolCommitment(proof.polynomials.C1); - challenges.beta = transcript.getChallenge(); - transcript.reset(); - - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - - transcript.reset(); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.polynomials.C2); - const xiSeed = transcript.getChallenge(); - const xiSeed2 = Fr.square(xiSeed); - - let w8 = []; - w8[1] = vk.w8; - w8[2] = Fr.square(vk.w8); - w8[3] = Fr.mul(w8[2], vk.w8); - w8[4] = Fr.mul(w8[3], vk.w8); - w8[5] = Fr.mul(w8[4], vk.w8); - w8[6] = Fr.mul(w8[5], vk.w8); - w8[7] = Fr.mul(w8[6], vk.w8); - let w4 = []; - w4[1] = vk.w4; - w4[2] = Fr.square(vk.w4); - w4[3] = Fr.mul(w4[2], vk.w4); - let w3 = []; - w3[1] = vk.w3; - w3[2] = Fr.square(vk.w3); - - // const w4_2 = Fr.square(vk.w4); - // const w4_3 = Fr.mul(w4_2, vk.w4); - // const w3_2 = Fr.square(vk.w3); - - // Compute h0 = xiSeeder^3 - roots.S0 = {}; - roots.S0.h0w8 = []; - roots.S0.h0w8[0] = Fr.mul(xiSeed2, xiSeed); - for (let i = 1; i < 8; i++) { - roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], w8[i]); - } - - // Compute h1 = xi_seeder^6 - roots.S1 = {}; - roots.S1.h1w4 = []; - roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); - for (let i = 1; i < 4; i++) { - roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], w4[i]); - } - - // Compute h2 = xi_seeder^8 - roots.S2 = {}; - roots.S2.h2w3 = []; - roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); - roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], w3[1]); - roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], w3[2]); - - roots.S2.h3w3 = []; - // Multiply h3 by third-root-omega to obtain h_3^3 = xiω - // So, h3 = xi_seeder^8 ω^{1/3} - roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], vk.wr); - roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], w3[1]); - roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], w3[2]); - - // Compute xi = xi_seeder^12 - challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); - challenges.xiw = Fr.mul(challenges.xi, Fr.w[vk.power]); - - challenges.xiN = challenges.xi; - vk.domainSize = 1; - for (let i = 0; i < vk.power; i++) { - challenges.xiN = Fr.square(challenges.xiN); - vk.domainSize *= 2; - } - - transcript.reset(); - transcript.addScalar(xiSeed); - transcript.addScalar(proof.evaluations.ql); - transcript.addScalar(proof.evaluations.qr); - transcript.addScalar(proof.evaluations.qm); - transcript.addScalar(proof.evaluations.qo); - transcript.addScalar(proof.evaluations.qc); - transcript.addScalar(proof.evaluations.s1); - transcript.addScalar(proof.evaluations.s2); - transcript.addScalar(proof.evaluations.s3); - transcript.addScalar(proof.evaluations.a); - transcript.addScalar(proof.evaluations.b); - transcript.addScalar(proof.evaluations.c); - transcript.addScalar(proof.evaluations.z); - transcript.addScalar(proof.evaluations.zw); - transcript.addScalar(proof.evaluations.t1w); - transcript.addScalar(proof.evaluations.t2w); - challenges.alpha = transcript.getChallenge(); - - transcript.reset(); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.polynomials.W1); - challenges.y = transcript.getChallenge(); - - if (logger) { - logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); - logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); - logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); - logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); - logger.info("··· challenges.y: " + Fr.toString(challenges.y)); - } - - return { challenges: challenges, roots: roots }; -} - -async function computeLagrangeEvaluations(curve, challenges, vk) { - const Fr = curve.Fr; - - const size = Math.max(1, vk.nPublic); - const numArr = new BigBuffer(size * Fr.n8); - let denArr = new BigBuffer(size * Fr.n8); - - let w = Fr.one; - for (let i = 0; i < size; i++) { - const i_sFr = i * Fr.n8; - numArr.set(Fr.mul(w, challenges.zh), i_sFr); - denArr.set(Fr.mul(Fr.e(vk.domainSize), Fr.sub(challenges.xi, w)), i_sFr); - w = Fr.mul(w, vk.w); - } - - denArr = await Fr.batchInverse(denArr); - - let L = []; - for (let i = 0; i < size; i++) { - const i_sFr = i * Fr.n8; - L[i + 1] = Fr.mul(numArr.slice(i_sFr, i_sFr + Fr.n8), denArr.slice(i_sFr, i_sFr + Fr.n8)); - } - return L; -} - -function calculatePI(curve, publicSignals, lagrangeEvals) { - const Fr = curve.Fr; - - let pi = Fr.zero; - for (let i = 0; i < publicSignals.length; i++) { - const w = Fr.e(publicSignals[i]); - pi = Fr.sub(pi, Fr.mul(w, lagrangeEvals[i + 1])); - } - return pi; -} - -function computeR0(proof, challenges, roots, curve, logger) { - const Fr = curve.Fr; - - const Li = computeLagrangeLiSi(roots.S0.h0w8, challenges.y, challenges.xi, curve); - - // r0(y) = ∑_1^8 C_0(h_0 ω_8^{i-1}) L_i(y). To this end we need to compute - - // Compute the 8 C0 values - if (logger) logger.info("··· Computing r0(y)"); - - let res = Fr.zero; - for (let i = 0; i < 8; i++) { - let coefValues = []; - coefValues[1] = roots.S0.h0w8[i]; - for (let j = 2; j < 8; j++) { - coefValues[j] = Fr.mul(coefValues[j - 1], roots.S0.h0w8[i]); - } - - let c0 = Fr.add(proof.evaluations.ql, Fr.mul(proof.evaluations.qr, coefValues[1])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qo, coefValues[2])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qm, coefValues[3])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qc, coefValues[4])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s1, coefValues[5])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s2, coefValues[6])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s3, coefValues[7])); - - res = Fr.add(res, Fr.mul(c0, Li[i])); - } - - return res; -} - -function computeR1(proof, challenges, roots, pi, curve, logger) { - const Fr = curve.Fr; - - const Li = computeLagrangeLiSi(roots.S1.h1w4, challenges.y, challenges.xi, curve); - - // r1(y) = ∑_1^4 C_1(h_1 ω_4^{i-1}) L_i(y). To this end we need to compute - // Z1 = {C1(h_1}, C1(h_1 ω_4), C1(h_1 ω_4^2), C1(h_1 ω_4^3)} - // where C_1(h_1 ω_4^{i-1}) = eval.a + h_1 ω_4^i eval.b + (h_1 ω_4^i)^2 eval.c + (h_1 ω_4^i)^3 T0(xi), - // where T0(xi) = [ qL·a + qR·b + qM·a·b + qO·c + qC + PI(xi) ] / Z_H(xi) - - // Compute T0(xi) - if (logger) logger.info("··· Computing T0(xi)"); - let t0 = Fr.mul(proof.evaluations.ql, proof.evaluations.a); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qr, proof.evaluations.b)); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qm, Fr.mul(proof.evaluations.a, proof.evaluations.b))); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qo, proof.evaluations.c)); - t0 = Fr.add(t0, proof.evaluations.qc); - t0 = Fr.add(t0, pi); - t0 = Fr.mul(t0, challenges.invzh); - - // Compute the 4 C1 values - if (logger) logger.info("··· Computing C1(h_1ω_4^i) values"); - - let res = Fr.zero; - for (let i = 0; i < 4; i++) { - let c1 = proof.evaluations.a; - c1 = Fr.add(c1, Fr.mul(roots.S1.h1w4[i], proof.evaluations.b)); - const h1w4Squared = Fr.square(roots.S1.h1w4[i]); - c1 = Fr.add(c1, Fr.mul(h1w4Squared, proof.evaluations.c)); - c1 = Fr.add(c1, Fr.mul(Fr.mul(h1w4Squared, roots.S1.h1w4[i]), t0)); - - res = Fr.add(res, Fr.mul(c1, Li[i])); - } - - return res; -} - -function computeR2(proof, challenges, roots, lagrange1, vk, curve, logger) { - const Fr = curve.Fr; - - const LiS2 = computeLagrangeLiS2([roots.S2.h2w3, roots.S2.h3w3], challenges.y, challenges.xi, challenges.xiw, curve); - - // r2(y) = ∑_1^3 C_2(h_2 ω_3^{i-1}) L_i(y) + ∑_1^3 C_2(h_3 ω_3^{i-1}) L_{i+3}(y). To this end we need to compute - // Z2 = {[C2(h_2}, C2(h_2 ω_3), C2(h_2 ω_3^2)], [C2(h_3}, C2(h_3 ω_3), C2(h_3 ω_3^2)]} - // where C_2(h_2 ω_3^{i-1}) = eval.z + h_2 ω_2^i T1(xi) + (h_2 ω_3^i)^2 T2(xi), - // where C_2(h_3 ω_3^{i-1}) = eval.z + h_3 ω_2^i T1(xi) + (h_3 ω_3^i)^2 T2(xi), - // where T1(xi) = [ L_1(xi)(z-1)] / Z_H(xi) - // and T2(xi) = [ (a + beta·xi + gamma)(b + beta·xi·k1 + gamma)(c + beta·xi·k2 + gamma)z - // - (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma)zω ] / Z_H(xi) - - // Compute T1(xi) - if (logger) logger.info("··· Computing T1(xi)"); - let t1 = Fr.sub(proof.evaluations.z, Fr.one); - t1 = Fr.mul(t1, lagrange1); - t1 = Fr.mul(t1, challenges.invzh); - - // Compute T2(xi) - if (logger) logger.info("··· Computing T2(xi)"); - const betaxi = Fr.mul(challenges.beta, challenges.xi); - const t211 = Fr.add(proof.evaluations.a, Fr.add(betaxi, challenges.gamma)); - const t212 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(betaxi, vk.k1), challenges.gamma)); - const t213 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(betaxi, vk.k2), challenges.gamma)); - const t21 = Fr.mul(t211, Fr.mul(t212, Fr.mul(t213, proof.evaluations.z))); - - const t221 = Fr.add(proof.evaluations.a, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s1), challenges.gamma)); - const t222 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s2), challenges.gamma)); - const t223 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s3), challenges.gamma)); - const t22 = Fr.mul(t221, Fr.mul(t222, Fr.mul(t223, proof.evaluations.zw))); - - let t2 = Fr.sub(t21, t22); - t2 = Fr.mul(t2, challenges.invzh); - - // Compute the 6 C2 values - if (logger) logger.info("··· Computing C2(h_2ω_3^i) values"); - let res = Fr.zero; - for (let i = 0; i < 3; i++) { - let c2 = Fr.add(proof.evaluations.z, Fr.mul(roots.S2.h2w3[i], t1)); - c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h2w3[i]), t2)); - - res = Fr.add(res, Fr.mul(c2, LiS2[i])); - } - - if (logger) logger.info("··· Computing C2(h_3ω_3^i) values"); - for (let i = 0; i < 3; i++) { - let c2 = Fr.add(proof.evaluations.zw, Fr.mul(roots.S2.h3w3[i], proof.evaluations.t1w)); - c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h3w3[i]), proof.evaluations.t2w)); - - res = Fr.add(res, Fr.mul(c2, LiS2[i + 3])); - } - - return res; -} - -function computeF(curve, proof, vk, challenges, roots) { - const G1 = curve.G1; - const Fr = curve.Fr; - - let mulH0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); - for (let i = 1; i < 8; i++) { - mulH0 = Fr.mul(mulH0, Fr.sub(challenges.y, roots.S0.h0w8[i])); - } - - challenges.temp = mulH0; - - let mulH1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); - for (let i = 1; i < 4; i++) { - mulH1 = Fr.mul(mulH1, Fr.sub(challenges.y, roots.S1.h1w4[i])); - } - - let mulH2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); - for (let i = 1; i < 3; i++) { - mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h2w3[i])); - } - for (let i = 0; i < 3; i++) { - mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h3w3[i])); - } - - challenges.quotient1 = Fr.mul(challenges.alpha, Fr.div(mulH0, mulH1)); - challenges.quotient2 = Fr.mul(Fr.square(challenges.alpha), Fr.div(mulH0, mulH2)); - - let F2 = G1.timesFr(proof.polynomials.C1, challenges.quotient1); - let F3 = G1.timesFr(proof.polynomials.C2, challenges.quotient2); - - return G1.add(vk.C0, G1.add(F2, F3)); -} - -function computeE(curve, proof, challenges, vk, r0, r1, r2) { - const G1 = curve.G1; - const Fr = curve.Fr; - - let E2 = Fr.mul(r1, challenges.quotient1); - let E3 = Fr.mul(r2, challenges.quotient2); - - return G1.timesFr(G1.one, Fr.add(r0, Fr.add(E2, E3))); -} - -function computeJ(curve, proof, challenges) { - const G1 = curve.G1; - - return G1.timesFr(proof.polynomials.W1, challenges.temp); -} - -async function isValidPairing(curve, proof, challenges, vk, F, E, J) { - const G1 = curve.G1; - - let A1 = G1.timesFr(proof.polynomials.W2, challenges.y); - A1 = G1.add(G1.sub(G1.sub(F, E), J), A1); - const A2 = curve.G2.one; - - const B1 = proof.polynomials.W2; - const B2 = vk.X_2; - - return await curve.pairingEq(G1.neg(A1), A2, B1, B2); -} - - -function computeLagrangeLiSi(roots, x, xi, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const num = Fr.sub(Fr.exp(x, len), xi); - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - Li[i] = Fr.div(num, Fr.mul(Fr.mul(den1, den2), den3)); - } - - return Li; -} - -function computeLagrangeLiS2(roots, value, xi0, xi1, curve) { - const Fr = curve.Fr; - - const Li = []; - - const len = roots[0].length; - const n = len * roots.length; - - const num1 = Fr.exp(value, n); - const num2 = Fr.mul(Fr.add(xi0, xi1), Fr.exp(value, len)); - const num3 = Fr.mul(xi0, xi1); - const num = Fr.add(Fr.sub(num1, num2), num3); - - let den1 = Fr.mul(Fr.mul(Fr.e(len), roots[0][0]), Fr.sub(xi0, xi1)); - for (let i = 0; i < len; i++) { - const den2 = roots[0][(len - 1) * i % len]; - const den3 = Fr.sub(value, roots[0][i]); - - const den = Fr.mul(den1,Fr.mul(den2, den3)); - - Li[i] = Fr.div(num, den); - } - - den1 = Fr.mul(Fr.mul(Fr.e(len), roots[1][0]), Fr.sub(xi1, xi0)); - for (let i = 0; i < len; i++) { - const den2 = roots[1][(len - 1) * i % len]; - const den3 = Fr.sub(value, roots[1][i]); - - const den = Fr.mul(den1,Fr.mul(den2, den3)); - - Li[i + len] = Fr.div(num, den); - } - - return Li; -} - -/* - Copyright 2021 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const {unstringifyBigInts} = utils; - -function p256(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0" + nstr; - nstr = `0x${nstr}`; - return nstr; -} - -async function fflonkExportCallData(_pub, _proof) { - const proof = unstringifyBigInts(_proof); - const pub = unstringifyBigInts(_pub); - - await getCurveFromName(proof.curve); - - let inputs = ""; - for (let i = 0; i < pub.length; i++) { - if (inputs !== "") inputs = inputs + ","; - inputs = inputs + p256(pub[i]); - } - - return `[${p256(proof.polynomials.C1[0])}, ${p256(proof.polynomials.C1[1])},` + - `${p256(proof.polynomials.C2[0])},${p256(proof.polynomials.C2[1])},` + - `${p256(proof.polynomials.W1[0])},${p256(proof.polynomials.W1[1])},` + - `${p256(proof.polynomials.W2[0])},${p256(proof.polynomials.W2[1])},` + - `${p256(proof.evaluations.ql)},${p256(proof.evaluations.qr)},${p256(proof.evaluations.qm)},` + - `${p256(proof.evaluations.qo)},${p256(proof.evaluations.qc)},${p256(proof.evaluations.s1)},` + - `${p256(proof.evaluations.s2)},${p256(proof.evaluations.s3)},${p256(proof.evaluations.a)},` + - `${p256(proof.evaluations.b)},${p256(proof.evaluations.c)},${p256(proof.evaluations.z)},` + - `${p256(proof.evaluations.zw)},${p256(proof.evaluations.t1w)},${p256(proof.evaluations.t2w)},` + - `${p256(proof.evaluations.inv)}],` + - `[${inputs}]`; -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -var fflonk = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportSolidityCallData: fflonkExportCallData, - exportSolidityVerifier: fflonkExportSolidityVerifier, - fullProve: fflonkFullProve, - prove: fflonkProve, - setup: fflonkSetup, - verify: fflonkVerify -}); - -var _virtual_ejs = {}; - -var _virtual_ejs$1 = /*#__PURE__*/Object.freeze({ - __proto__: null, - default: _virtual_ejs +//#endregion +//#region src/fflonk_setup.js +async function di(i, c, l, d) { + d && d.info("FFLONK SETUP STARTED"), globalThis.gc && globalThis.gc(), d && d.info("> Reading PTau file"); + let { fd: f, sections: p } = await r(c, "ptau", 1, 1 << 22, 1 << 24); + if (!p[12]) throw Error("Powers of Tau is not well prepared. Section 12 missing."); + d && d.info("> Getting curve from PTau settings"); + let { curve: m } = await an(f, p); + d && d.info("> Reading r1cs file"); + let { fd: g, sections: _ } = await r(i, "r1cs", 1, 1 << 22, 1 << 24), v = await h(g, _, { + loadConstraints: !1, + loadCustomGates: !0 + }); + if (v.prime !== m.r) throw Error("r1cs curve does not match powers of tau ceremony curve"); + let y = m.Fr, b = m.Fr.n8, x = m.G1.F.n8 * 2, S = m.G2.F.n8 * 2, C = {}, w = {}, T, E = { + nVars: v.nVars, + nPublic: v.nOutputs + v.nPubInputs + }, D = new qn(), O = new qn(); + if (d && d.info("> Processing FFlonk constraints"), await F(m.Fr, v, d), globalThis.gc && globalThis.gc(), E.cirPower = Math.max(3, Ce(D.length + 2 - 1) + 1), E.domainSize = 2 ** E.cirPower, p[2][0].size < (E.domainSize * 9 + 18) * x) throw Error("Powers of Tau is not big enough for this circuit size. Section 2 too small."); + if (p[3][0].size < S) throw Error("Powers of Tau is not well prepared. Section 3 too small."); + d && (d.info("----------------------------"), d.info(" FFLONK SETUP SETTINGS"), d.info(` Curve: ${m.name}`), d.info(` Circuit power: ${E.cirPower}`), d.info(` Domain size: ${E.domainSize}`), d.info(` Vars: ${E.nVars}`), d.info(` Public vars: ${E.nPublic}`), d.info(` Constraints: ${D.length}`), d.info(` Additions: ${O.length}`), d.info("----------------------------")), d && d.info("> computing k1 and k2"); + let [k, A] = ie(); + d && d.info("> computing w3"); + let j = ae(); + d && d.info("> computing w4"); + let M = oe(); + d && d.info("> computing w8"); + let N = se(); + d && d.info("> computing wr"); + let P = ce(E.cirPower, m.Fr); + return await I(), await g.close(), await f.close(), d && d.info("FFLONK SETUP FINISHED"), 0; + async function F(t, n, r) { + for (let e = 0; e < E.nPublic; e++) D.push(ri(e + 1, t)); + let i = new li(t, ri, ii, ai, r), a = await e.readSection(g, _, 2), o = 0; + for (let e = 0; e < n.nConstraints; e++) { + r && e !== 0 && e % 5e5 == 0 && r.info(` processing r1cs constraints ${e}/${n.nConstraints}`); + let [t, a] = i.processR1csConstraint(E, ...s()); + D.push(...t), O.push(...a); + } + function s() { + let e = []; + return e[0] = c(), e[1] = c(), e[2] = c(), e; + } + function c() { + let e = {}, t = a.slice(o, o + 4); + o += 4; + let r = new DataView(t.buffer).getUint32(0, !0), i = a.slice(o, o + (4 + n.n8) * r); + o += (4 + n.n8) * r; + let s = new DataView(i.buffer); + for (let t = 0; t < r; t++) { + let r = s.getUint32(t * (4 + n.n8), !0); + e[r] = n.F.fromRprLE(i, t * (4 + n.n8) + 4); + } + return e; + } + return 0; + } + async function I() { + d && d.info("> Writing the zkey file"); + let e = await t(l, "zkey", 1, 17, 1 << 22, 1 << 24); + d && d.info("··· Writing Section 1. Zkey Header"), await ee(e), d && d.info("··· Writing Section 3. Additions"), await L(e), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 4. A Map"), await R(e, 4, 0, "A map"), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 5. B Map"), await R(e, 5, 1, "B map"), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 6. C Map"), await R(e, 6, 2, "C map"), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 7. QL"), await z(e, 7, 3, "QL"), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 8. QR"), await z(e, 8, 4, "QR"), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 9. QM"), await z(e, 9, 5, "QM"), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 10. QO"), await z(e, 10, 6, "QO"), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 11. QC"), await z(e, 11, 7, "QC"), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Sections 12,13,14. Sigma1, Sigma2 & Sigma 3"), await B(e), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 15. Lagrange Polynomials"), await te(e), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 16. Powers of Tau"), await ne(e), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 17. C0"), await V(e), globalThis.gc && globalThis.gc(), d && d.info("··· Writing Section 2. FFlonk Header"), await H(e), globalThis.gc && globalThis.gc(), d && d.info("> Writing the zkey file finished"), await e.close(); + } + async function ee(e) { + await a(e, 1), await e.writeULE32(10), await n(e); + } + async function L(e) { + await a(e, 3); + let t = new Uint8Array(8 + 2 * b), r = new DataView(t.buffer); + for (let n = 0; n < O.length; n++) { + d && n !== 0 && n % 5e5 == 0 && d.info(` writing Additions: ${n}/${O.length}`); + let i = O[n]; + r.setUint32(0, i[0], !0), r.setUint32(4, i[1], !0), t.set(i[2], 8), t.set(i[3], 8 + b), await e.write(t); + } + await n(e); + } + async function R(e, t, r, i) { + await a(e, t); + for (let t = 0; t < D.length; t++) d && t !== 0 && t % 5e5 == 0 && d.info(` writing witness ${i}: ${t}/${D.length}`), await e.writeULE32(D[t][r]); + await n(e); + } + async function z(e, t, r, i) { + let o = new s(E.domainSize * b); + for (let e = 0; e < D.length; e++) o.set(D[e][r], e * b), d && e !== 0 && e % 5e5 == 0 && d.info(` writing ${i}: ${e}/${D.length}`); + C[i] = await Y.fromEvaluations(o, m, d), w[i] = await X.fromPolynomial(C[i], 4, m, d), await a(e, t), await e.write(C[i].coef), await e.write(w[i].eval), await n(e); + } + async function B(e) { + let t = new s(b * E.domainSize * 3), r = new qn(E.nVars), i = new qn(E.nVars), o = y.one; + for (let e = 0; e < E.domainSize; e++) e < D.length ? (c(D[e][0], e), c(D[e][1], E.domainSize + e), c(D[e][2], E.domainSize * 2 + e)) : e < E.domainSize - 2 ? (c(0, e), c(0, E.domainSize + e), c(0, E.domainSize * 2 + e)) : (t.set(o, e * b), t.set(y.mul(o, k), (E.domainSize + e) * b), t.set(y.mul(o, A), (E.domainSize * 2 + e) * b)), o = y.mul(o, y.w[E.cirPower]), d && e !== 0 && e % 5e5 == 0 && d.info(` writing sigma phase1: ${e}/${D.length}`); + for (let e = 0; e < E.nVars; e++) i[e] === void 0 ? console.log("Variable not used") : t.set(r[e], i[e] * b), d && e !== 0 && e % 5e5 == 0 && d.info(` writing sigma phase2: ${e}/${E.nVars}`); + globalThis.gc && globalThis.gc(); + for (let r = 0; r < 3; r++) { + let i = r === 0 ? 12 : r === 1 ? 13 : 14, o = "S" + (r + 1); + C[o] = await Y.fromEvaluations(t.slice(E.domainSize * b * r, E.domainSize * b * (r + 1)), m, d), w[o] = await X.fromPolynomial(C[o], 4, m, d), await a(e, i), await e.write(C[o].coef), await e.write(w[o].eval), await n(e), globalThis.gc && globalThis.gc(); + } + return 0; + function c(e, n) { + r[e] === void 0 ? i[e] = n : t.set(r[e], n * b); + let a; + a = n < E.domainSize ? o : n < 2 * E.domainSize ? y.mul(o, k) : y.mul(o, A), r[e] = a; + } + } + async function te(e) { + await a(e, 15); + let t = Math.max(E.nPublic, 1); + for (let n = 0; n < t; n++) { + let t = new s(E.domainSize * b); + t.set(y.one, n * b), await re(e, t); + } + await n(e); + } + async function ne(e) { + await a(e, 16), T = new s((E.domainSize * 9 + 18) * x), await f.readToBuffer(T, 0, (E.domainSize * 9 + 18) * x, p[2][0].p), await e.write(T), await n(e); + } + async function V(e) { + let t = new ui(8, m, d); + if (t.addPolynomial(0, C.QL), t.addPolynomial(1, C.QR), t.addPolynomial(2, C.QO), t.addPolynomial(3, C.QM), t.addPolynomial(4, C.QC), t.addPolynomial(5, C.S1), t.addPolynomial(6, C.S2), t.addPolynomial(7, C.S3), C.C0 = t.getPolynomial(), C.C0.degree() >= 8 * E.domainSize) throw Error("C0 Polynomial is not well calculated"); + await a(e, 17), await e.write(C.C0.coef), await n(e); + } + async function H(e) { + await a(e, 2); + let t = m.q, r = (Math.floor((u.bitLength(t) - 1) / 64) + 1) * 8; + await e.writeULE32(r), await o(e, t, r); + let i = m.r, s = (Math.floor((u.bitLength(i) - 1) / 64) + 1) * 8; + await e.writeULE32(s), await o(e, i, s), await e.writeULE32(E.nVars), await e.writeULE32(E.nPublic), await e.writeULE32(E.domainSize), await e.writeULE32(O.length), await e.writeULE32(D.length), await e.write(k), await e.write(A), await e.write(j), await e.write(M), await e.write(N), await e.write(P); + let c; + c = await f.read(S, p[3][0].p + S), await e.write(c); + let l = await C.C0.multiExponentiation(T, "C0"); + await e.write(l), await n(e); + } + async function re(e, t) { + let [n, r] = await Y.to4T(t, E.domainSize, [], y); + return await e.write(n), await e.write(r), [n, r]; + } + function ie() { + let e = y.two; + for (; n(e, [], E.cirPower);) y.add(e, y.one); + let t = y.add(e, y.one); + for (; n(t, [e], E.cirPower);) y.add(t, y.one); + return [e, t]; + function n(e, t, n) { + let r = 2 ** n, i = y.one; + for (let a = 0; a < r; a++) { + if (y.eq(e, i)) return !0; + for (let n = 0; n < t.length; n++) if (y.eq(e, y.mul(t[n], i))) return !0; + i = y.mul(i, y.w[n]); + } + return !1; + } + } + function ae() { + let e = y.e(31624), t = u.div(3648040478639879203707734290876212514758060733402672390616367364429301415936n, u.e(3)); + return y.exp(e, t); + } + function oe() { + return y.w[2]; + } + function se() { + return y.w[3]; + } + function ce(e, t) { + let n = t.e(467799165886069610036046866799264026481344299079011762026774533774345988080n); + return t.exp(n, 2 ** (28 - e)); + } +} +//#endregion +//#region src/fflonk_prove.js +var { stringifyBigInts: fi } = p; +async function pi(t, n, r, i) { + r && r.info("FFLONK PROVER STARTED"), r && r.info("> Reading witness file"); + let { fd: a, sections: o } = await e.readBinFile(n, "wtns", 2, 1 << 25, 1 << 23), c = await nt(a, o); + r && r.info("> Reading zkey file"); + let { fd: l, sections: d } = await e.readBinFile(t, "zkey", 2, 1 << 25, 1 << 23), f = await He(l, d, void 0, i); + if (f.protocolId !== 10) throw Error("zkey file is not fflonk"); + if (!u.eq(f.r, c.q)) throw Error("Curve of the witness does not match the curve of the proving key"); + if (c.nWitness !== f.nVars - f.nAdditions) throw Error(`Invalid witness length. Circuit: ${f.nVars}, witness: ${c.nWitness}, ${f.nAdditions}`); + let p = f.curve, m = p.Fr, h = p.Fr.n8, g = p.G1.F.n8 * 2, _ = f.domainSize * h; + r && (r.info("----------------------------"), r.info(" FFLONK PROVE SETTINGS"), r.info(` Curve: ${p.name}`), r.info(` Circuit power: ${f.power}`), r.info(` Domain size: ${f.domainSize}`), r.info(` Vars: ${f.nVars}`), r.info(` Public vars: ${f.nPublic}`), r.info(` Constraints: ${f.nConstraints}`), r.info(` Additions: ${f.nAdditions}`), r.info("----------------------------")), r && r.info("> Reading witness file data"); + let v = await e.readSection(a, o, 2); + await a.close(), v.set(m.zero, 0); + let y = new s(f.nAdditions * h), b = {}, x = {}, S = {}, C = {}, w = {}, T = {}, E = new dr(p, r); + r && r.info("> Reading Section 3. Additions"), await A(), r && r.info("> Reading Sections 12,13,14. Sigma1, Sigma2 & Sigma 3"), r && r.info("··· Reading Sigma polynomials "), x.Sigma1 = new Y(new s(_), p, r), x.Sigma2 = new Y(new s(_), p, r), x.Sigma3 = new Y(new s(_), p, r), await l.readToBuffer(x.Sigma1.coef, 0, _, d[12][0].p), await l.readToBuffer(x.Sigma2.coef, 0, _, d[13][0].p), await l.readToBuffer(x.Sigma3.coef, 0, _, d[14][0].p), r && r.info("··· Reading Sigma evaluations"), S.Sigma1 = new X(new s(_ * 4), p, r), S.Sigma2 = new X(new s(_ * 4), p, r), S.Sigma3 = new X(new s(_ * 4), p, r), await l.readToBuffer(S.Sigma1.eval, 0, _ * 4, d[12][0].p + _), await l.readToBuffer(S.Sigma2.eval, 0, _ * 4, d[13][0].p + _), await l.readToBuffer(S.Sigma3.eval, 0, _ * 4, d[14][0].p + _), r && r.info("> Reading Section 16. Powers of Tau"); + let D = new s(f.domainSize * 16 * g); + await l.readToBuffer(D, 0, (f.domainSize * 9 + 18) * g, d[16][0].p), globalThis.gc && globalThis.gc(), r && r.info(""), r && r.info("> ROUND 1"), await N(), delete x.T0, delete S.QL, delete S.QR, delete S.QM, delete S.QO, delete S.QC, globalThis.gc && globalThis.gc(), r && r.info("> ROUND 2"), await P(), delete b.A, delete b.B, delete b.C, delete S.A, delete S.B, delete S.C, delete S.Sigma1, delete S.Sigma2, delete S.Sigma3, delete S.lagrange1, delete S.Z, globalThis.gc && globalThis.gc(), r && r.info("> ROUND 3"), await F(), delete x.A, delete x.B, delete x.C, delete x.Z, delete x.T1, delete x.T2, delete x.Sigma1, delete x.Sigma2, delete x.Sigma3, delete x.QL, delete x.QR, delete x.QM, delete x.QC, delete x.QO, globalThis.gc && globalThis.gc(), r && r.info("> ROUND 4"), await I(), globalThis.gc && globalThis.gc(), r && r.info("> ROUND 5"), await ee(), delete x.C0, delete x.C1, delete x.C2, delete x.R1, delete x.R2, delete x.F, delete x.L, delete x.ZT, delete x.ZTS2, await l.close(), globalThis.gc && globalThis.gc(), E.addEvaluation("inv", L()); + let O = E.toObjectProof(); + O.protocol = "fflonk", O.curve = p.name; + let k = []; + for (let e = 1; e <= f.nPublic; e++) { + let t = e * h, n = v.slice(t, t + h); + k.push(u.fromRprLE(n)); + } + return r && r.info("FFLONK PROVER FINISHED"), { + proof: fi(O), + publicSignals: fi(k) + }; + async function A() { + r && r.info("··· Computing additions"); + let t = await e.readSection(l, d, 3), n = 8 + h * 2; + for (let e = 0; e < f.nAdditions; e++) { + r && e !== 0 && e % 1e5 == 0 && r.info(` addition ${e}/${f.nAdditions}`); + let i = e * n, a = j(t, i); + i += 4; + let o = j(t, i); + i += 4; + let s = t.slice(i, i + h); + i += h; + let c = t.slice(i, i + h), l = M(a), u = M(o), d = m.add(m.mul(s, l), m.mul(c, u)); + y.set(d, h * e); + } + } + function j(e, t) { + let n = e.slice(t, t + 4); + return new DataView(n.buffer, n.byteOffset, n.byteLength).getUint32(0, !0); + } + function M(e) { + let t = f.nVars - f.nAdditions; + if (e < t) return v.slice(e * h, e * h + h); + if (e < f.nVars) { + let n = (e - t) * h; + return y.slice(n, n + h); + } + return m.zero; + } + async function N() { + w.b = []; + for (let e = 1; e <= 9; e++) w.b[e] = m.random(); + r && r.info("> Computing A, B, C wire polynomials"), await n(), r && r.info("> Computing T0 polynomial"), await i(), r && r.info("> Computing C1 polynomial"), await a(), r && r.info("> Computing C1 multi exponentiation"); + let t = await x.C1.multiExponentiation(D, "C1"); + return E.addPolynomial("C1", t), 0; + async function n() { + r && r.info("··· Reading data from zkey file"), b.A = new s(_), b.B = new s(_), b.C = new s(_); + let t = await e.readSection(l, d, 4), n = await e.readSection(l, d, 5), i = await e.readSection(l, d, 6); + for (let e = 0; e < f.nConstraints; e++) { + let r = e * h, a = e * 4, o = j(t, a); + b.A.set(M(o), r); + let s = j(n, a); + b.B.set(M(s), r); + let c = j(i, a); + b.C.set(M(c), r); + } + if (b.A.set(w.b[1], _ - 64), b.A.set(w.b[2], _ - 32), b.B.set(w.b[3], _ - 64), b.B.set(w.b[4], _ - 32), b.C.set(w.b[5], _ - 64), b.C.set(w.b[6], _ - 32), b.A = await m.batchToMontgomery(b.A), b.B = await m.batchToMontgomery(b.B), b.C = await m.batchToMontgomery(b.C), r && r.info("··· Computing A ifft"), x.A = await Y.fromEvaluations(b.A, p, r), r && r.info("··· Computing B ifft"), x.B = await Y.fromEvaluations(b.B, p, r), r && r.info("··· Computing C ifft"), x.C = await Y.fromEvaluations(b.C, p, r), r && r.info("··· Computing A fft"), S.A = await X.fromPolynomial(x.A, 4, p, r), r && r.info("··· Computing B fft"), S.B = await X.fromPolynomial(x.B, 4, p, r), r && r.info("··· Computing C fft"), S.C = await X.fromPolynomial(x.C, 4, p, r), x.A.degree() >= f.domainSize) throw Error("A Polynomial is not well calculated"); + if (x.B.degree() >= f.domainSize) throw Error("B Polynomial is not well calculated"); + if (x.C.degree() >= f.domainSize) throw Error("C Polynomial is not well calculated"); + } + async function i() { + r && r.info("··· Reading sections 7, 8, 9, 10, 11. Q selectors"), S.QL = new X(new s(_ * 4), p, r), S.QR = new X(new s(_ * 4), p, r), S.QM = new X(new s(_ * 4), p, r), S.QO = new X(new s(_ * 4), p, r), S.QC = new X(new s(_ * 4), p, r), await l.readToBuffer(S.QL.eval, 0, _ * 4, d[7][0].p + _), await l.readToBuffer(S.QR.eval, 0, _ * 4, d[8][0].p + _), await l.readToBuffer(S.QM.eval, 0, _ * 4, d[9][0].p + _), await l.readToBuffer(S.QO.eval, 0, _ * 4, d[10][0].p + _), await l.readToBuffer(S.QC.eval, 0, _ * 4, d[11][0].p + _), S.lagrange1 = new X(await e.readSection(l, d, 15), p, r), b.T0 = new s(_ * 4), r && r.info("··· Computing T0 evaluations"); + for (let e = 0; e < f.domainSize * 4; e++) { + r && e !== 0 && e % 1e5 == 0 && r.info(` T0 evaluation ${e}/${f.domainSize * 4}`); + let t = S.A.getEvaluation(e), n = S.B.getEvaluation(e), i = S.C.getEvaluation(e), a = S.QL.getEvaluation(e), o = S.QR.getEvaluation(e), s = S.QM.getEvaluation(e), c = S.QO.getEvaluation(e), l = S.QC.getEvaluation(e), u = m.zero; + for (let t = 0; t < f.nPublic; t++) { + let n = t * 5 * f.domainSize + f.domainSize + e, r = S.lagrange1.getEvaluation(n), i = b.A.slice(t * h, (t + 1) * h); + u = m.sub(u, m.mul(r, i)); + } + let d = m.mul(t, a), p = m.mul(n, o), g = m.mul(m.mul(t, n), s), _ = m.mul(i, c), v = m.add(d, m.add(p, m.add(g, m.add(_, m.add(l, u))))); + b.T0.set(v, e * h); + } + if (r && r.info("buffer T0: " + b.T0.byteLength / h), r && r.info("··· Computing T0 ifft"), x.T0 = await Y.fromEvaluations(b.T0, p, r), r && r.info("T0 length: " + x.T0.length()), r && r.info("T0 degree: " + x.T0.degree()), r && r.info("··· Computing T0 / ZH"), x.T0.divByZerofier(f.domainSize, m.one), x.T0.degree() >= 2 * f.domainSize - 2) throw Error(`T0 Polynomial is not well calculated (degree is ${x.T0.degree()} and must be less than ${2 * f.domainSize + 2}`); + delete b.T0; + } + async function a() { + let e = new ui(4, p, r); + if (e.addPolynomial(0, x.A), e.addPolynomial(1, x.B), e.addPolynomial(2, x.C), e.addPolynomial(3, x.T0), x.C1 = e.getPolynomial(), x.C1.degree() >= 8 * f.domainSize - 8) throw Error("C1 Polynomial is not well calculated"); + } + } + async function P() { + r && r.info("> Computing challenges beta and gamma"); + let e = new jr(p); + e.addPolCommitment(f.C0); + for (let t = 0; t < f.nPublic; t++) e.addScalar(b.A.slice(t * h, t * h + h)); + e.addPolCommitment(E.getPolynomial("C1")), w.beta = e.getChallenge(), r && r.info("··· challenges.beta: " + m.toString(w.beta)), e.reset(), e.addScalar(w.beta), w.gamma = e.getChallenge(), r && r.info("··· challenges.gamma: " + m.toString(w.gamma)), r && r.info("> Computing Z polynomial"), await n(), r && r.info("> Computing T1 polynomial"), await i(), r && r.info("> Computing T2 polynomial"), await a(), r && r.info("> Computing C2 polynomial"), await o(), r && r.info("> Computing C2 multi exponentiation"); + let t = await x.C2.multiExponentiation(D, "C2"); + return E.addPolynomial("C2", t), 0; + async function n() { + r && r.info("··· Computing Z evaluations"); + let e = new s(_), t = new s(_); + e.set(m.one, 0), t.set(m.one, 0); + let n = m.one; + for (let i = 0; i < f.domainSize; i++) { + r && i !== 0 && i % 1e5 == 0 && r.info(` Z evaluation ${i}/${f.domainSize}`); + let a = i * h, o = m.mul(w.beta, n), s = b.A.slice(a, a + h); + s = m.add(s, o), s = m.add(s, w.gamma); + let c = b.B.slice(a, a + h); + c = m.add(c, m.mul(f.k1, o)), c = m.add(c, w.gamma); + let l = b.C.slice(a, a + h); + l = m.add(l, m.mul(f.k2, o)), l = m.add(l, w.gamma); + let u = m.mul(s, m.mul(c, l)), d = b.A.slice(a, a + h); + d = m.add(d, m.mul(w.beta, S.Sigma1.getEvaluation(i * 4))), d = m.add(d, w.gamma); + let p = b.B.slice(a, a + h); + p = m.add(p, m.mul(w.beta, S.Sigma2.getEvaluation(i * 4))), p = m.add(p, w.gamma); + let g = b.C.slice(a, a + h); + g = m.add(g, m.mul(w.beta, S.Sigma3.getEvaluation(i * 4))), g = m.add(g, w.gamma); + let _ = m.mul(d, m.mul(p, g)); + u = m.mul(e.slice(a, a + h), u), e.set(u, (i + 1) % f.domainSize * h), _ = m.mul(t.slice(a, a + h), _), t.set(_, (i + 1) % f.domainSize * h), n = m.mul(n, m.w[f.power]); + } + t = await m.batchInverse(t); + for (let n = 0; n < f.domainSize; n++) { + let r = n * h, i = m.mul(e.slice(r, r + h), t.slice(r, r + h)); + e.set(i, r); + } + if (b.Z = e, !m.eq(e.slice(0, h), m.one)) throw Error("Copy constraints does not match"); + if (r && r.info("··· Computing Z ifft"), x.Z = await Y.fromEvaluations(b.Z, p, r), r && r.info("··· Computing Z fft"), S.Z = await X.fromPolynomial(x.Z, 4, p, r), x.Z.blindCoefficients([ + w.b[9], + w.b[8], + w.b[7] + ]), x.Z.degree() >= f.domainSize + 3) throw Error("Z Polynomial is not well calculated"); + delete b.Z; + } + async function i() { + r && r.info("··· Computing T1 evaluations"), b.T1 = new s(_ * 2), b.T1z = new s(_ * 2); + let e = m.one; + for (let t = 0; t < f.domainSize * 2; t++) { + r && t !== 0 && t % 1e5 == 0 && r.info(` T1 evaluation ${t}/${f.domainSize * 4}`); + let n = m.square(e), i = S.Z.getEvaluation(t * 2), a = m.add(m.add(m.mul(w.b[7], n), m.mul(w.b[8], e)), w.b[9]), o = S.lagrange1.getEvaluation(f.domainSize + t * 2), s = m.mul(m.sub(i, m.one), o), c = m.mul(a, o); + b.T1.set(s, t * h), b.T1z.set(c, t * h), e = m.mul(e, m.w[f.power + 1]); + } + if (r && r.info("··· Computing T1 ifft"), x.T1 = await Y.fromEvaluations(b.T1, p, r), x.T1.divByZerofier(f.domainSize, m.one), r && r.info("··· Computing T1z ifft"), x.T1z = await Y.fromEvaluations(b.T1z, p, r), x.T1.add(x.T1z), x.T1.degree() >= f.domainSize + 2) throw Error("T1 Polynomial is not well calculated"); + delete b.T1, delete b.T1z, delete x.T1z; + } + async function a() { + r && r.info("··· Computing T2 evaluations"), b.T2 = new s(_ * 4), b.T2z = new s(_ * 4); + let e = m.one; + for (let t = 0; t < f.domainSize * 4; t++) { + r && t !== 0 && t % 1e5 == 0 && r.info(` T2 evaluation ${t}/${f.domainSize * 4}`); + let n = m.square(e), i = m.mul(e, m.w[f.power]), a = m.square(i), o = S.A.getEvaluation(t), s = S.B.getEvaluation(t), c = S.C.getEvaluation(t), l = S.Z.getEvaluation(t), u = S.Z.getEvaluation((f.domainSize * 4 + 4 + t) % (f.domainSize * 4)), d = m.add(m.add(m.mul(w.b[7], n), m.mul(w.b[8], e)), w.b[9]), p = m.add(m.add(m.mul(w.b[7], a), m.mul(w.b[8], i)), w.b[9]), g = S.Sigma1.getEvaluation(t), _ = S.Sigma2.getEvaluation(t), v = S.Sigma3.getEvaluation(t), y = m.mul(w.beta, e), x = m.add(o, y); + x = m.add(x, w.gamma); + let C = m.add(s, m.mul(y, f.k1)); + C = m.add(C, w.gamma); + let T = m.add(c, m.mul(y, f.k2)); + T = m.add(T, w.gamma); + let E = m.mul(m.mul(m.mul(x, C), T), l), D = m.mul(m.mul(m.mul(x, C), T), d), O = m.add(o, m.mul(w.beta, g)); + O = m.add(O, w.gamma); + let k = m.add(s, m.mul(w.beta, _)); + k = m.add(k, w.gamma); + let A = m.add(c, m.mul(w.beta, v)); + A = m.add(A, w.gamma); + let j = m.mul(m.mul(m.mul(O, k), A), u), M = m.mul(m.mul(m.mul(O, k), A), p), N = m.sub(E, j), P = m.sub(D, M); + b.T2.set(N, t * h), b.T2z.set(P, t * h), e = m.mul(e, m.w[f.power + 2]); + } + if (r && r.info("··· Computing T2 ifft"), x.T2 = await Y.fromEvaluations(b.T2, p, r), r && r.info("··· Computing T2 / ZH"), x.T2.divByZerofier(f.domainSize, m.one), r && r.info("··· Computing T2z ifft"), x.T2z = await Y.fromEvaluations(b.T2z, p, r), x.T2.add(x.T2z), x.T2.degree() >= 3 * f.domainSize) throw Error("T2 Polynomial is not well calculated"); + delete b.T2, delete b.T2z, delete x.T2z; + } + async function o() { + let e = new ui(3, p, r); + if (e.addPolynomial(0, x.Z), e.addPolynomial(1, x.T1), e.addPolynomial(2, x.T2), x.C2 = e.getPolynomial(), x.C2.degree() >= 9 * f.domainSize) throw Error("C2 Polynomial is not well calculated"); + } + } + async function F() { + r && r.info("> Computing challenge xi"); + let e = new jr(p); + e.addScalar(w.gamma), e.addPolCommitment(E.getPolynomial("C2")), w.xiSeed = e.getChallenge(); + let t = m.square(w.xiSeed); + T.w8 = [], T.w8[0] = m.one; + for (let e = 1; e < 8; e++) T.w8[e] = m.mul(T.w8[e - 1], f.w8); + T.w4 = [], T.w4[0] = m.one; + for (let e = 1; e < 4; e++) T.w4[e] = m.mul(T.w4[e - 1], f.w4); + T.w3 = [], T.w3[0] = m.one, T.w3[1] = f.w3, T.w3[2] = m.square(f.w3), T.S0 = {}, T.S0.h0w8 = [], T.S0.h0w8[0] = m.mul(t, w.xiSeed); + for (let e = 1; e < 8; e++) T.S0.h0w8[e] = m.mul(T.S0.h0w8[0], T.w8[e]); + T.S1 = {}, T.S1.h1w4 = [], T.S1.h1w4[0] = m.square(T.S0.h0w8[0]); + for (let e = 1; e < 4; e++) T.S1.h1w4[e] = m.mul(T.S1.h1w4[0], T.w4[e]); + T.S2 = {}, T.S2.h2w3 = [], T.S2.h2w3[0] = m.mul(T.S1.h1w4[0], t), T.S2.h2w3[1] = m.mul(T.S2.h2w3[0], T.w3[1]), T.S2.h2w3[2] = m.mul(T.S2.h2w3[0], T.w3[2]), T.S2.h3w3 = [], T.S2.h3w3[0] = m.mul(T.S2.h2w3[0], f.wr), T.S2.h3w3[1] = m.mul(T.S2.h3w3[0], T.w3[1]), T.S2.h3w3[2] = m.mul(T.S2.h3w3[0], T.w3[2]), w.xi = m.mul(m.square(T.S2.h2w3[0]), T.S2.h2w3[0]), r && r.info("··· challenges.xi: " + m.toString(w.xi)), x.QL = new Y(new s(_), p, r), x.QR = new Y(new s(_), p, r), x.QM = new Y(new s(_), p, r), x.QO = new Y(new s(_), p, r), x.QC = new Y(new s(_), p, r), await l.readToBuffer(x.QL.coef, 0, _, d[7][0].p), await l.readToBuffer(x.QR.coef, 0, _, d[8][0].p), await l.readToBuffer(x.QM.coef, 0, _, d[9][0].p), await l.readToBuffer(x.QO.coef, 0, _, d[10][0].p), await l.readToBuffer(x.QC.coef, 0, _, d[11][0].p), r && r.info("··· Computing evaluations"), E.addEvaluation("ql", x.QL.evaluate(w.xi)), E.addEvaluation("qr", x.QR.evaluate(w.xi)), E.addEvaluation("qm", x.QM.evaluate(w.xi)), E.addEvaluation("qo", x.QO.evaluate(w.xi)), E.addEvaluation("qc", x.QC.evaluate(w.xi)), E.addEvaluation("s1", x.Sigma1.evaluate(w.xi)), E.addEvaluation("s2", x.Sigma2.evaluate(w.xi)), E.addEvaluation("s3", x.Sigma3.evaluate(w.xi)), E.addEvaluation("a", x.A.evaluate(w.xi)), E.addEvaluation("b", x.B.evaluate(w.xi)), E.addEvaluation("c", x.C.evaluate(w.xi)), E.addEvaluation("z", x.Z.evaluate(w.xi)), w.xiw = m.mul(w.xi, m.w[f.power]), E.addEvaluation("zw", x.Z.evaluate(w.xiw)), E.addEvaluation("t1w", x.T1.evaluate(w.xiw)), E.addEvaluation("t2w", x.T2.evaluate(w.xiw)); + } + async function I() { + r && r.info("> Computing challenge alpha"); + let e = new jr(p); + e.addScalar(w.xiSeed), e.addScalar(E.getEvaluation("ql")), e.addScalar(E.getEvaluation("qr")), e.addScalar(E.getEvaluation("qm")), e.addScalar(E.getEvaluation("qo")), e.addScalar(E.getEvaluation("qc")), e.addScalar(E.getEvaluation("s1")), e.addScalar(E.getEvaluation("s2")), e.addScalar(E.getEvaluation("s3")), e.addScalar(E.getEvaluation("a")), e.addScalar(E.getEvaluation("b")), e.addScalar(E.getEvaluation("c")), e.addScalar(E.getEvaluation("z")), e.addScalar(E.getEvaluation("zw")), e.addScalar(E.getEvaluation("t1w")), e.addScalar(E.getEvaluation("t2w")), w.alpha = e.getChallenge(), r && r.info("··· challenges.alpha: " + m.toString(w.alpha)), r && r.info("> Reading C0 polynomial"), x.C0 = new Y(new s(_ * 8), p, r), await l.readToBuffer(x.C0.coef, 0, _ * 8, d[17][0].p), r && r.info("> Computing R0 polynomial"), n(), r && r.info("> Computing R1 polynomial"), i(), r && r.info("> Computing R2 polynomial"), a(), r && r.info("> Computing F polynomial"), await o(), r && r.info("> Computing W1 multi exponentiation"); + let t = await x.F.multiExponentiation(D, "W1"); + return E.addPolynomial("W1", t), 0; + function n() { + if (x.R0 = Y.lagrangePolynomialInterpolation([ + T.S0.h0w8[0], + T.S0.h0w8[1], + T.S0.h0w8[2], + T.S0.h0w8[3], + T.S0.h0w8[4], + T.S0.h0w8[5], + T.S0.h0w8[6], + T.S0.h0w8[7] + ], [ + x.C0.evaluate(T.S0.h0w8[0]), + x.C0.evaluate(T.S0.h0w8[1]), + x.C0.evaluate(T.S0.h0w8[2]), + x.C0.evaluate(T.S0.h0w8[3]), + x.C0.evaluate(T.S0.h0w8[4]), + x.C0.evaluate(T.S0.h0w8[5]), + x.C0.evaluate(T.S0.h0w8[6]), + x.C0.evaluate(T.S0.h0w8[7]) + ], p), x.R0.degree() > 7) throw Error("R0 Polynomial is not well calculated"); + } + function i() { + if (x.R1 = Y.lagrangePolynomialInterpolation([ + T.S1.h1w4[0], + T.S1.h1w4[1], + T.S1.h1w4[2], + T.S1.h1w4[3] + ], [ + x.C1.evaluate(T.S1.h1w4[0]), + x.C1.evaluate(T.S1.h1w4[1]), + x.C1.evaluate(T.S1.h1w4[2]), + x.C1.evaluate(T.S1.h1w4[3]) + ], p), x.R1.degree() > 3) throw Error("R1 Polynomial is not well calculated"); + } + function a() { + if (x.R2 = Y.lagrangePolynomialInterpolation([ + T.S2.h2w3[0], + T.S2.h2w3[1], + T.S2.h2w3[2], + T.S2.h3w3[0], + T.S2.h3w3[1], + T.S2.h3w3[2] + ], [ + x.C2.evaluate(T.S2.h2w3[0]), + x.C2.evaluate(T.S2.h2w3[1]), + x.C2.evaluate(T.S2.h2w3[2]), + x.C2.evaluate(T.S2.h3w3[0]), + x.C2.evaluate(T.S2.h3w3[1]), + x.C2.evaluate(T.S2.h3w3[2]) + ], p), x.R2.degree() > 5) throw Error("R2 Polynomial is not well calculated"); + } + async function o() { + r && r.info("··· Computing F polynomial"), x.F = Y.fromPolynomial(x.C0, p, r), x.F.sub(x.R0), x.F.divByZerofier(8, w.xi); + let e = Y.fromPolynomial(x.C1, p, r); + e.sub(x.R1), e.mulScalar(w.alpha), e.divByZerofier(4, w.xi); + let t = Y.fromPolynomial(x.C2, p, r); + if (t.sub(x.R2), t.mulScalar(m.square(w.alpha)), t.divByZerofier(3, w.xi), t.divByZerofier(3, w.xiw), x.F.add(e), x.F.add(t), x.F.degree() >= 9 * f.domainSize - 6) throw Error("F Polynomial is not well calculated"); + } + } + async function ee() { + r && r.info("> Computing challenge y"); + let e = new jr(p); + e.addScalar(w.alpha), e.addPolCommitment(E.getPolynomial("W1")), w.y = e.getChallenge(), r && r.info("··· challenges.y: " + m.toString(w.y)), r && r.info("> Computing L polynomial"), await o(), r && r.info("> Computing ZTS2 polynomial"), await c(); + let t = x.ZTS2.evaluate(w.y); + t = m.inv(t), x.L.mulScalar(t); + let n = Y.fromCoefficientsArray([m.neg(w.y), m.one], p); + r && r.info("> Computing W' = L / ZTS2 polynomial"); + let i = x.L.divBy(n); + if (i.degree() > 0) throw Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${i.degree()} and should be 0`); + if (x.L.degree() >= 9 * f.domainSize - 1) throw Error("Degree of L(X)/(ZTS2(y)(X-y)) is not correct"); + r && r.info("> Computing W' multi exponentiation"); + let a = await x.L.multiExponentiation(D, "W2"); + return E.addPolynomial("W2", a), 0; + async function o() { + r && r.info("··· Computing L polynomial"); + let e = x.R0.evaluate(w.y), t = x.R1.evaluate(w.y), n = x.R2.evaluate(w.y), i = m.sub(w.y, T.S0.h0w8[0]); + for (let e = 1; e < 8; e++) i = m.mul(i, m.sub(w.y, T.S0.h0w8[e])); + let a = m.sub(w.y, T.S1.h1w4[0]); + for (let e = 1; e < 4; e++) a = m.mul(a, m.sub(w.y, T.S1.h1w4[e])); + let o = m.sub(w.y, T.S2.h2w3[0]); + for (let e = 1; e < 3; e++) o = m.mul(o, m.sub(w.y, T.S2.h2w3[e])); + for (let e = 0; e < 3; e++) o = m.mul(o, m.sub(w.y, T.S2.h3w3[e])); + let c = m.mul(a, o), l = m.mul(w.alpha, m.mul(i, o)), u = m.mul(m.square(w.alpha), m.mul(i, a)); + C.denH1 = a, C.denH2 = o, x.L = Y.fromPolynomial(x.C0, p, r), x.L.subScalar(e), x.L.mulScalar(c); + let d = Y.fromPolynomial(x.C1, p, r); + d.subScalar(t), d.mulScalar(l); + let h = Y.fromPolynomial(x.C2, p, r); + h.subScalar(n), h.mulScalar(u), x.L.add(d), x.L.add(h), r && r.info("> Computing ZT polynomial"), await s(); + let g = x.ZT.evaluate(w.y); + if (x.F.mulScalar(g), x.L.sub(x.F), x.L.degree() >= 9 * f.domainSize) throw Error("L Polynomial is not well calculated"); + delete b.L; + } + async function s() { + x.ZT = Y.zerofierPolynomial([ + T.S0.h0w8[0], + T.S0.h0w8[1], + T.S0.h0w8[2], + T.S0.h0w8[3], + T.S0.h0w8[4], + T.S0.h0w8[5], + T.S0.h0w8[6], + T.S0.h0w8[7], + T.S1.h1w4[0], + T.S1.h1w4[1], + T.S1.h1w4[2], + T.S1.h1w4[3], + T.S2.h2w3[0], + T.S2.h2w3[1], + T.S2.h2w3[2], + T.S2.h3w3[0], + T.S2.h3w3[1], + T.S2.h3w3[2] + ], p); + } + async function c() { + x.ZTS2 = Y.zerofierPolynomial([ + T.S1.h1w4[0], + T.S1.h1w4[1], + T.S1.h1w4[2], + T.S1.h1w4[3], + T.S2.h2w3[0], + T.S2.h2w3[1], + T.S2.h2w3[2], + T.S2.h3w3[0], + T.S2.h3w3[1], + T.S2.h3w3[2] + ], p); + } + } + function L() { + let e = w.xi; + for (let t = 0; t < f.power; t++) e = m.square(e); + C.zh = m.sub(e, m.one), i(C, T.S0.h0w8, w.y, p), a(C, T.S1.h1w4, w.y, p), o(C, T.S2.h2w3, T.S2.h3w3, w.y, w.xi, w.xiw, p); + let t = Math.max(1, f.nPublic), n = m.one; + for (let e = 0; e < t; e++) C["Li_" + (e + 1)] = m.mul(m.e(f.domainSize), m.sub(w.xi, n)), n = m.mul(n, m.w[f.power]); + let r = m.one; + for (let e of Object.values(C)) if (Array.isArray(e)) for (let t of e) r = m.mul(r, t); + else r = m.mul(r, e); + return m.inv(r); + function i(e, t, n, r) { + let i = r.Fr, a = t.length, o = i.mul(i.e(a), i.exp(t[0], a - 2)), s = []; + for (let r = 0; r < a; r++) { + let s = t[(a - 1) * r % a], c = i.sub(n, t[r]); + e[["LiS0_" + (r + 1)]] = i.mul(i.mul(o, s), c); + } + return s; + } + function a(e, t, n, r) { + let i = r.Fr, a = t.length, o = i.mul(i.e(a), i.exp(t[0], a - 2)), s = []; + for (let r = 0; r < a; r++) { + let s = t[(a - 1) * r % a], c = i.sub(n, t[r]); + e[["LiS1_" + (r + 1)]] = i.mul(i.mul(o, s), c); + } + return s; + } + function o(e, t, n, r, i, a, o) { + let s = o.Fr, c = [], l = s.mul(s.e(3), t[0]), u = s.sub(i, a), d = s.mul(l, u); + for (let n = 0; n < 3; n++) { + let i = t[2 * n % 3], a = s.sub(r, t[n]); + e[["LiS2_" + (n + 1)]] = s.mul(d, s.mul(i, a)); + } + let f = s.mul(s.e(3), n[0]), p = s.sub(a, i); + d = s.mul(f, p); + for (let t = 0; t < 3; t++) { + let i = n[2 * t % 3], a = s.sub(r, n[t]); + e[["LiS2_" + (t + 1 + 3)]] = s.mul(d, s.mul(i, a)); + } + return c; + } + } +} +//#endregion +//#region src/fflonk_full_prove.js +var { unstringifyBigInts: mi } = p; +async function hi(e, t, n, r, i, a) { + let o = mi(e), s = { type: "mem" }; + return await Vt(o, t, s, i), await pi(n, s, r, a); +} +//#endregion +//#region src/fflonk_verify.js +var { unstringifyBigInts: gi } = p; +async function _i(e, t, n, r) { + r && r.info("FFLONK VERIFIER STARTED"), e = gi(e), n = gi(n); + let i = await E(e.curve), a = vi(i, e), o = new dr(i, r); + o.fromObjectProof(n); + let s = gi(t); + if (s.length !== a.nPublic) return r.error("Number of public signals does not match with vk"), !1; + let c = i.Fr; + if (r && (r.info("----------------------------"), r.info(" FFLONK VERIFY SETTINGS"), r.info(` Curve: ${i.name}`), r.info(` Circuit power: ${a.power}`), r.info(` Domain size: ${2 ** a.power}`), r.info(` Public vars: ${a.nPublic}`), r.info("----------------------------")), r && r.info("> Checking commitments belong to G1"), !yi(i, o, a)) return r && r.error("Proof commitments are not valid"), !1; + if (r && r.info("> Checking evaluations belong to F"), !xi(i, o)) return r && r.error("Proof evaluations are not valid."), !1; + if (r && r.info("> Checking public inputs belong to F"), !Si(i, s)) return r && r.error("Public inputs are not valid."), !1; + r && r.info("> Computing challenges"); + let { challenges: l, roots: u } = Ci(i, o, a, s, r); + r && r.info("> Computing Zero polynomial evaluation Z_H(xi)"), l.zh = c.sub(l.xiN, c.one), l.invzh = c.inv(l.zh), r && r.info("> Computing Lagrange evaluations"); + let d = await wi(i, l, a); + r && r.info("> Computing polynomial identities PI(X)"); + let f = Ti(i, s, d); + r && r.info("> Computing r0(y)"); + let p = Ei(o, l, u, i, r); + r && r.info("> Computing r1(y)"); + let m = Di(o, l, u, f, i, r); + r && r.info("> Computing r2(y)"); + let h = Oi(o, l, u, d[1], a, i, r); + r && r.info("> Computing F"); + let g = ki(i, o, a, l, u); + r && r.info("> Computing E"); + let _ = Ai(i, o, l, a, p, m, h); + r && r.info("> Computing J"); + let v = ji(i, o, l); + r && r.info("> Validate all evaluations with a pairing"); + let y = await Mi(i, o, l, a, g, _, v); + return r && (y ? r.info("PROOF VERIFIED SUCCESSFULLY") : r.warn("Invalid Proof")), r && r.info("FFLONK VERIFIER FINISHED"), y; +} +function vi(e, t) { + let n = t; + return n.k1 = e.Fr.fromObject(t.k1), n.k2 = e.Fr.fromObject(t.k2), n.w = e.Fr.fromObject(t.w), n.w3 = e.Fr.fromObject(t.w3), n.w4 = e.Fr.fromObject(t.w4), n.w8 = e.Fr.fromObject(t.w8), n.wr = e.Fr.fromObject(t.wr), n.X_2 = e.G2.fromObject(t.X_2), n.C0 = e.G1.fromObject(t.C0), n; +} +function yi(e, t, n) { + let r = e.G1; + return r.isValid(t.polynomials.C1) && r.isValid(t.polynomials.C2) && r.isValid(t.polynomials.W1) && r.isValid(t.polynomials.W2) && r.isValid(n.C0); +} +function bi(e, t) { + return u.geq(t, 0) && u.lt(t, e.r); +} +function Q(e, t) { + return bi(e, u.fromRprLE(t)); +} +function xi(e, t) { + return Q(e, t.evaluations.ql) && Q(e, t.evaluations.qr) && Q(e, t.evaluations.qm) && Q(e, t.evaluations.qo) && Q(e, t.evaluations.qc) && Q(e, t.evaluations.s1) && Q(e, t.evaluations.s2) && Q(e, t.evaluations.s3) && Q(e, t.evaluations.a) && Q(e, t.evaluations.b) && Q(e, t.evaluations.c) && Q(e, t.evaluations.z) && Q(e, t.evaluations.zw) && Q(e, t.evaluations.t1w) && Q(e, t.evaluations.t2w); +} +function Si(e, t) { + for (let n = 0; n < t.length; n++) if (!bi(e, t[n])) return !1; + return !0; +} +function Ci(e, t, n, r, i) { + let a = e.Fr, o = {}, s = {}, c = new jr(e); + c.addPolCommitment(n.C0); + for (let e = 0; e < r.length; e++) c.addScalar(a.e(r[e])); + c.addPolCommitment(t.polynomials.C1), o.beta = c.getChallenge(), c.reset(), c.addScalar(o.beta), o.gamma = c.getChallenge(), c.reset(), c.addScalar(o.gamma), c.addPolCommitment(t.polynomials.C2); + let l = c.getChallenge(), u = a.square(l), d = []; + d[1] = n.w8, d[2] = a.square(n.w8), d[3] = a.mul(d[2], n.w8), d[4] = a.mul(d[3], n.w8), d[5] = a.mul(d[4], n.w8), d[6] = a.mul(d[5], n.w8), d[7] = a.mul(d[6], n.w8); + let f = []; + f[1] = n.w4, f[2] = a.square(n.w4), f[3] = a.mul(f[2], n.w4); + let p = []; + p[1] = n.w3, p[2] = a.square(n.w3), s.S0 = {}, s.S0.h0w8 = [], s.S0.h0w8[0] = a.mul(u, l); + for (let e = 1; e < 8; e++) s.S0.h0w8[e] = a.mul(s.S0.h0w8[0], d[e]); + s.S1 = {}, s.S1.h1w4 = [], s.S1.h1w4[0] = a.square(s.S0.h0w8[0]); + for (let e = 1; e < 4; e++) s.S1.h1w4[e] = a.mul(s.S1.h1w4[0], f[e]); + s.S2 = {}, s.S2.h2w3 = [], s.S2.h2w3[0] = a.mul(s.S1.h1w4[0], u), s.S2.h2w3[1] = a.mul(s.S2.h2w3[0], p[1]), s.S2.h2w3[2] = a.mul(s.S2.h2w3[0], p[2]), s.S2.h3w3 = [], s.S2.h3w3[0] = a.mul(s.S2.h2w3[0], n.wr), s.S2.h3w3[1] = a.mul(s.S2.h3w3[0], p[1]), s.S2.h3w3[2] = a.mul(s.S2.h3w3[0], p[2]), o.xi = a.mul(a.square(s.S2.h2w3[0]), s.S2.h2w3[0]), o.xiw = a.mul(o.xi, a.w[n.power]), o.xiN = o.xi, n.domainSize = 1; + for (let e = 0; e < n.power; e++) o.xiN = a.square(o.xiN), n.domainSize *= 2; + return c.reset(), c.addScalar(l), c.addScalar(t.evaluations.ql), c.addScalar(t.evaluations.qr), c.addScalar(t.evaluations.qm), c.addScalar(t.evaluations.qo), c.addScalar(t.evaluations.qc), c.addScalar(t.evaluations.s1), c.addScalar(t.evaluations.s2), c.addScalar(t.evaluations.s3), c.addScalar(t.evaluations.a), c.addScalar(t.evaluations.b), c.addScalar(t.evaluations.c), c.addScalar(t.evaluations.z), c.addScalar(t.evaluations.zw), c.addScalar(t.evaluations.t1w), c.addScalar(t.evaluations.t2w), o.alpha = c.getChallenge(), c.reset(), c.addScalar(o.alpha), c.addPolCommitment(t.polynomials.W1), o.y = c.getChallenge(), i && (i.info("··· challenges.beta: " + a.toString(o.beta)), i.info("··· challenges.gamma: " + a.toString(o.gamma)), i.info("··· challenges.xi: " + a.toString(o.xi)), i.info("··· challenges.alpha: " + a.toString(o.alpha)), i.info("··· challenges.y: " + a.toString(o.y))), { + challenges: o, + roots: s + }; +} +async function wi(e, t, n) { + let r = e.Fr, i = Math.max(1, n.nPublic), a = new s(i * r.n8), o = new s(i * r.n8), c = r.one; + for (let e = 0; e < i; e++) { + let i = e * r.n8; + a.set(r.mul(c, t.zh), i), o.set(r.mul(r.e(n.domainSize), r.sub(t.xi, c)), i), c = r.mul(c, n.w); + } + o = await r.batchInverse(o); + let l = []; + for (let e = 0; e < i; e++) { + let t = e * r.n8; + l[e + 1] = r.mul(a.slice(t, t + r.n8), o.slice(t, t + r.n8)); + } + return l; +} +function Ti(e, t, n) { + let r = e.Fr, i = r.zero; + for (let e = 0; e < t.length; e++) { + let a = r.e(t[e]); + i = r.sub(i, r.mul(a, n[e + 1])); + } + return i; +} +function Ei(e, t, n, r, i) { + let a = r.Fr, o = Ni(n.S0.h0w8, t.y, t.xi, r); + i && i.info("··· Computing r0(y)"); + let s = a.zero; + for (let t = 0; t < 8; t++) { + let r = []; + r[1] = n.S0.h0w8[t]; + for (let e = 2; e < 8; e++) r[e] = a.mul(r[e - 1], n.S0.h0w8[t]); + let i = a.add(e.evaluations.ql, a.mul(e.evaluations.qr, r[1])); + i = a.add(i, a.mul(e.evaluations.qo, r[2])), i = a.add(i, a.mul(e.evaluations.qm, r[3])), i = a.add(i, a.mul(e.evaluations.qc, r[4])), i = a.add(i, a.mul(e.evaluations.s1, r[5])), i = a.add(i, a.mul(e.evaluations.s2, r[6])), i = a.add(i, a.mul(e.evaluations.s3, r[7])), s = a.add(s, a.mul(i, o[t])); + } + return s; +} +function Di(e, t, n, r, i, a) { + let o = i.Fr, s = Ni(n.S1.h1w4, t.y, t.xi, i); + a && a.info("··· Computing T0(xi)"); + let c = o.mul(e.evaluations.ql, e.evaluations.a); + c = o.add(c, o.mul(e.evaluations.qr, e.evaluations.b)), c = o.add(c, o.mul(e.evaluations.qm, o.mul(e.evaluations.a, e.evaluations.b))), c = o.add(c, o.mul(e.evaluations.qo, e.evaluations.c)), c = o.add(c, e.evaluations.qc), c = o.add(c, r), c = o.mul(c, t.invzh), a && a.info("··· Computing C1(h_1ω_4^i) values"); + let l = o.zero; + for (let t = 0; t < 4; t++) { + let r = e.evaluations.a; + r = o.add(r, o.mul(n.S1.h1w4[t], e.evaluations.b)); + let i = o.square(n.S1.h1w4[t]); + r = o.add(r, o.mul(i, e.evaluations.c)), r = o.add(r, o.mul(o.mul(i, n.S1.h1w4[t]), c)), l = o.add(l, o.mul(r, s[t])); + } + return l; +} +function Oi(e, t, n, r, i, a, o) { + let s = a.Fr, c = Pi([n.S2.h2w3, n.S2.h3w3], t.y, t.xi, t.xiw, a); + o && o.info("··· Computing T1(xi)"); + let l = s.sub(e.evaluations.z, s.one); + l = s.mul(l, r), l = s.mul(l, t.invzh), o && o.info("··· Computing T2(xi)"); + let u = s.mul(t.beta, t.xi), d = s.add(e.evaluations.a, s.add(u, t.gamma)), f = s.add(e.evaluations.b, s.add(s.mul(u, i.k1), t.gamma)), p = s.add(e.evaluations.c, s.add(s.mul(u, i.k2), t.gamma)), m = s.mul(d, s.mul(f, s.mul(p, e.evaluations.z))), h = s.add(e.evaluations.a, s.add(s.mul(t.beta, e.evaluations.s1), t.gamma)), g = s.add(e.evaluations.b, s.add(s.mul(t.beta, e.evaluations.s2), t.gamma)), _ = s.add(e.evaluations.c, s.add(s.mul(t.beta, e.evaluations.s3), t.gamma)), v = s.mul(h, s.mul(g, s.mul(_, e.evaluations.zw))), y = s.sub(m, v); + y = s.mul(y, t.invzh), o && o.info("··· Computing C2(h_2ω_3^i) values"); + let b = s.zero; + for (let t = 0; t < 3; t++) { + let r = s.add(e.evaluations.z, s.mul(n.S2.h2w3[t], l)); + r = s.add(r, s.mul(s.square(n.S2.h2w3[t]), y)), b = s.add(b, s.mul(r, c[t])); + } + o && o.info("··· Computing C2(h_3ω_3^i) values"); + for (let t = 0; t < 3; t++) { + let r = s.add(e.evaluations.zw, s.mul(n.S2.h3w3[t], e.evaluations.t1w)); + r = s.add(r, s.mul(s.square(n.S2.h3w3[t]), e.evaluations.t2w)), b = s.add(b, s.mul(r, c[t + 3])); + } + return b; +} +function ki(e, t, n, r, i) { + let a = e.G1, o = e.Fr, s = o.sub(r.y, i.S0.h0w8[0]); + for (let e = 1; e < 8; e++) s = o.mul(s, o.sub(r.y, i.S0.h0w8[e])); + r.temp = s; + let c = o.sub(r.y, i.S1.h1w4[0]); + for (let e = 1; e < 4; e++) c = o.mul(c, o.sub(r.y, i.S1.h1w4[e])); + let l = o.sub(r.y, i.S2.h2w3[0]); + for (let e = 1; e < 3; e++) l = o.mul(l, o.sub(r.y, i.S2.h2w3[e])); + for (let e = 0; e < 3; e++) l = o.mul(l, o.sub(r.y, i.S2.h3w3[e])); + r.quotient1 = o.mul(r.alpha, o.div(s, c)), r.quotient2 = o.mul(o.square(r.alpha), o.div(s, l)); + let u = a.timesFr(t.polynomials.C1, r.quotient1), d = a.timesFr(t.polynomials.C2, r.quotient2); + return a.add(n.C0, a.add(u, d)); +} +function Ai(e, t, n, r, i, a, o) { + let s = e.G1, c = e.Fr, l = c.mul(a, n.quotient1), u = c.mul(o, n.quotient2); + return s.timesFr(s.one, c.add(i, c.add(l, u))); +} +function ji(e, t, n) { + return e.G1.timesFr(t.polynomials.W1, n.temp); +} +async function Mi(e, t, n, r, i, a, o) { + let s = e.G1, c = s.timesFr(t.polynomials.W2, n.y); + c = s.add(s.sub(s.sub(i, a), o), c); + let l = e.G2.one, u = t.polynomials.W2, d = r.X_2; + return await e.pairingEq(s.neg(c), l, u, d); +} +function Ni(e, t, n, r) { + let i = r.Fr, a = e.length, o = i.sub(i.exp(t, a), n), s = i.mul(i.e(a), i.exp(e[0], a - 2)), c = []; + for (let n = 0; n < a; n++) { + let r = e[(a - 1) * n % a], l = i.sub(t, e[n]); + c[n] = i.div(o, i.mul(i.mul(s, r), l)); + } + return c; +} +function Pi(e, t, n, r, i) { + let a = i.Fr, o = [], s = e[0].length, c = s * e.length, l = a.exp(t, c), u = a.mul(a.add(n, r), a.exp(t, s)), d = a.mul(n, r), f = a.add(a.sub(l, u), d), p = a.mul(a.mul(a.e(s), e[0][0]), a.sub(n, r)); + for (let n = 0; n < s; n++) { + let r = e[0][(s - 1) * n % s], i = a.sub(t, e[0][n]), c = a.mul(p, a.mul(r, i)); + o[n] = a.div(f, c); + } + p = a.mul(a.mul(a.e(s), e[1][0]), a.sub(r, n)); + for (let n = 0; n < s; n++) { + let r = e[1][(s - 1) * n % s], i = a.sub(t, e[1][n]), c = a.mul(p, a.mul(r, i)); + o[n + s] = a.div(f, c); + } + return o; +} +//#endregion +//#region src/fflonk_export_calldata.js +var { unstringifyBigInts: Fi } = p; +function $(e) { + let t = e.toString(16); + for (; t.length < 64;) t = "0" + t; + return t = `0x${t}`, t; +} +async function Ii(e, t) { + let n = Fi(t), r = Fi(e); + await E(n.curve); + let i = ""; + for (let e = 0; e < r.length; e++) i !== "" && (i += ","), i += $(r[e]); + return `[${$(n.polynomials.C1[0])}, ${$(n.polynomials.C1[1])},${$(n.polynomials.C2[0])},${$(n.polynomials.C2[1])},${$(n.polynomials.W1[0])},${$(n.polynomials.W1[1])},${$(n.polynomials.W2[0])},${$(n.polynomials.W2[1])},${$(n.evaluations.ql)},${$(n.evaluations.qr)},${$(n.evaluations.qm)},${$(n.evaluations.qo)},${$(n.evaluations.qc)},${$(n.evaluations.s1)},${$(n.evaluations.s2)},${$(n.evaluations.s3)},${$(n.evaluations.a)},${$(n.evaluations.b)},${$(n.evaluations.c)},${$(n.evaluations.z)},${$(n.evaluations.zw)},${$(n.evaluations.t1w)},${$(n.evaluations.t2w)},${$(n.evaluations.inv)}],[${i}]`; +} +//#endregion +//#region src/fflonk.js +var Li = /* @__PURE__ */ v({ + exportSolidityCallData: () => Ii, + exportSolidityVerifier: () => null, + fullProve: () => hi, + prove: () => pi, + setup: () => di, + verify: () => _i }); - -export { curves, fflonk, groth16, plonk, powersoftau as powersOfTau, r1cs, wtns, zkey as zKey }; +//#endregion +export { y as curves, Li as fflonk, Qt as groth16, ni as plonk, jn as powersOfTau, Ln as r1cs, Un as wtns, lr as zKey }; diff --git a/build/cli.cjs b/build/cli.cjs old mode 100755 new mode 100644 index c6ca01d1..235b7fde --- a/build/cli.cjs +++ b/build/cli.cjs @@ -1,14135 +1,8918 @@ -#!/usr/bin/node --expose-gc - -'use strict'; - -var fs = require('fs'); -var url = require('url'); -var r1csfile = require('r1csfile'); -var fastFile = require('fastfile'); -var ffjavascript = require('ffjavascript'); -var blake2_js = require('@noble/hashes/blake2.js'); -var utils_js = require('@noble/hashes/utils.js'); -var readline = require('readline'); -var crypto = require('crypto'); -var path = require('path'); -var binFileUtils = require('@iden3/binfileutils'); -var circom_runtime = require('circom_runtime'); -var sha3_js = require('@noble/hashes/sha3.js'); -var Logger = require('logplease'); - -var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; -function _interopNamespaceDefault(e) { - var n = Object.create(null); - if (e) { - Object.keys(e).forEach(function (k) { - if (k !== 'default') { - var d = Object.getOwnPropertyDescriptor(e, k); - Object.defineProperty(n, k, d.get ? d : { - enumerable: true, - get: function () { return e[k]; } - }); - } - }); - } - n.default = e; - return Object.freeze(n); -} - -var fastFile__namespace = /*#__PURE__*/_interopNamespaceDefault(fastFile); -var binFileUtils__namespace = /*#__PURE__*/_interopNamespaceDefault(binFileUtils); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - +#!/usr/bin/env node +//#region \0rolldown/runtime.js +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { + key = keys[i]; + if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { + get: ((k) => from[k]).bind(null, key), + enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable + }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { + value: mod, + enumerable: true +}) : target, mod)); +//#endregion +let fs = require("fs"); +fs = __toESM(fs, 1); +let url = require("url"); +url = __toESM(url, 1); +let r1csfile = require("r1csfile"); +let fastfile = require("fastfile"); +fastfile = __toESM(fastfile, 1); +let ffjavascript = require("ffjavascript"); +let _noble_hashes_blake2_js = require("@noble/hashes/blake2.js"); +let _noble_hashes_utils_js = require("@noble/hashes/utils.js"); +let readline = require("readline"); +readline = __toESM(readline, 1); +let crypto = require("crypto"); +crypto = __toESM(crypto, 1); +let path = require("path"); +path = __toESM(path, 1); +let _iden3_binfileutils = require("@iden3/binfileutils"); +_iden3_binfileutils = __toESM(_iden3_binfileutils, 1); +let circom_runtime = require("circom_runtime"); +let _noble_hashes_sha3_js = require("@noble/hashes/sha3.js"); +let logplease = require("logplease"); +logplease = __toESM(logplease, 1); +//#region src/loadsyms.js async function loadSymbols(symFileName) { - const sym = { - labelIdx2Name: [ "one" ], - varIdx2Name: [ "one" ], - componentIdx2Name: [] - }; - const fd = await fastFile__namespace.readExisting(symFileName); - const buff = await fd.read(fd.totalSize); - const symsStr = new TextDecoder("utf-8").decode(buff); - const lines = symsStr.split("\n"); - for (let i=0; i. -*/ - + const sym = { + labelIdx2Name: ["one"], + varIdx2Name: ["one"], + componentIdx2Name: [] + }; + const fd = await fastfile.readExisting(symFileName); + const buff = await fd.read(fd.totalSize); + const lines = new TextDecoder("utf-8").decode(buff).split("\n"); + for (let i = 0; i < lines.length; i++) { + const arr = lines[i].split(","); + if (arr.length != 4) continue; + if (sym.varIdx2Name[arr[1]]) sym.varIdx2Name[arr[1]] += "|" + arr[3]; + else sym.varIdx2Name[arr[1]] = arr[3]; + sym.labelIdx2Name[arr[0]] = arr[3]; + if (!sym.componentIdx2Name[arr[2]]) sym.componentIdx2Name[arr[2]] = extractComponent(arr[3]); + } + await fd.close(); + return sym; + function extractComponent(name) { + const arr = name.split("."); + arr.pop(); + return arr.join("."); + } +} +//#endregion +//#region src/r1cs_print.js function r1csPrint$1(r1cs, syms, logger) { - for (let i=0; i { - let S = ""; - const keys = Object.keys(lc); - keys.forEach( (k) => { - let name = syms.varIdx2Name[k]; - if (name == "one") name = "1"; - - let vs = r1cs.curve.Fr.toString(lc[k]); - if (vs == "1") vs = ""; // Do not show ones - if (vs == "-1") vs = "-"; // Do not show ones - if ((S!="")&&(vs[0]!="-")) vs = "+"+vs; - if (S!="") vs = " "+vs; - S= S + vs + name; - }); - return S; - }; - const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`; - if (logger) logger.info(S); - } - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const bls12381r$1 = ffjavascript.Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); -const bn128r$1 = ffjavascript.Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - + for (let i = 0; i < r1cs.constraints.length; i++) printCostraint(r1cs.constraints[i]); + function printCostraint(c) { + const lc2str = (lc) => { + let S = ""; + Object.keys(lc).forEach((k) => { + let name = syms.varIdx2Name[k]; + if (name == "one") name = "1"; + let vs = r1cs.curve.Fr.toString(lc[k]); + if (vs == "1") vs = ""; + if (vs == "-1") vs = "-"; + if (S != "" && vs[0] != "-") vs = "+" + vs; + if (S != "") vs = " " + vs; + S = S + vs + name; + }); + return S; + }; + const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`; + if (logger) logger.info(S); + } +} +//#endregion +//#region src/r1cs_info.js +var bls12381r$1 = ffjavascript.Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); +var bn128r$1 = ffjavascript.Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); async function r1csInfo$1(r1csName, logger) { - - // Only the header (section 1) is needed for these counts; loading the - // constraints + wire-to-label map would read the whole (potentially many-GB) - // file for nothing. - const cir = await r1csfile.readR1cs(r1csName, {loadConstraints: false, loadMap: false}); - - if (ffjavascript.Scalar.eq(cir.prime, bn128r$1)) { - if (logger) logger.info("Curve: bn-128"); - } else if (ffjavascript.Scalar.eq(cir.prime, bls12381r$1)) { - if (logger) logger.info("Curve: bls12-381"); - } else { - if (logger) logger.info(`Unknown Curve. Prime: ${ffjavascript.Scalar.toString(cir.prime)}`); - } - if (logger) logger.info(`# of Wires: ${cir.nVars}`); - if (logger) logger.info(`# of Constraints: ${cir.nConstraints}`); - if (logger) logger.info(`# of Private Inputs: ${cir.nPrvInputs}`); - if (logger) logger.info(`# of Public Inputs: ${cir.nPubInputs}`); - if (logger) logger.info(`# of Labels: ${cir.nLabels}`); - if (logger) logger.info(`# of Outputs: ${cir.nOutputs}`); - - return cir; -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - - -function log2( V ) -{ - return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) ); -} - - + const cir = await (0, r1csfile.readR1cs)(r1csName, { + loadConstraints: false, + loadMap: false + }); + if (ffjavascript.Scalar.eq(cir.prime, bn128r$1)) { + if (logger) logger.info("Curve: bn-128"); + } else if (ffjavascript.Scalar.eq(cir.prime, bls12381r$1)) { + if (logger) logger.info("Curve: bls12-381"); + } else if (logger) logger.info(`Unknown Curve. Prime: ${ffjavascript.Scalar.toString(cir.prime)}`); + if (logger) logger.info(`# of Wires: ${cir.nVars}`); + if (logger) logger.info(`# of Constraints: ${cir.nConstraints}`); + if (logger) logger.info(`# of Private Inputs: ${cir.nPrvInputs}`); + if (logger) logger.info(`# of Public Inputs: ${cir.nPubInputs}`); + if (logger) logger.info(`# of Labels: ${cir.nLabels}`); + if (logger) logger.info(`# of Outputs: ${cir.nOutputs}`); + return cir; +} +//#endregion +//#region src/misc.js +var _revTable = []; +for (let i = 0; i < 256; i++) _revTable[i] = _revSlow(i, 8); +function _revSlow(idx, bits) { + let res = 0; + let a = idx; + for (let i = 0; i < bits; i++) { + res <<= 1; + res = res | a & 1; + a >>= 1; + } + return res; +} +function log2(V) { + return ((V & 4294901760) !== 0 ? (V &= 4294901760, 16) : 0) | ((V & 4278255360) !== 0 ? (V &= 4278255360, 8) : 0) | ((V & 4042322160) !== 0 ? (V &= 4042322160, 4) : 0) | ((V & 3435973836) !== 0 ? (V &= 3435973836, 2) : 0) | (V & 2863311530) !== 0; +} function formatHash(b, title) { - const a = new DataView(b.buffer, b.byteOffset, b.byteLength); - let S = ""; - for (let i=0; i<4; i++) { - if (i>0) S += "\n"; - S += "\t\t"; - for (let j=0; j<4; j++) { - if (j>0) S += " "; - S += a.getUint32(i*16+j*4).toString(16).padStart(8, "0"); - } - } - if (title) S = title + "\n" + S; - return S; -} - + const a = new DataView(b.buffer, b.byteOffset, b.byteLength); + let S = ""; + for (let i = 0; i < 4; i++) { + if (i > 0) S += "\n"; + S += " "; + for (let j = 0; j < 4; j++) { + if (j > 0) S += " "; + S += a.getUint32(i * 16 + j * 4).toString(16).padStart(8, "0"); + } + } + if (title) S = title + "\n" + S; + return S; +} function hashIsEqual(h1, h2) { - if (h1.byteLength != h2.byteLength) return false; - var dv1 = new Int8Array(h1); - var dv2 = new Int8Array(h2); - for (var i = 0 ; i != h1.byteLength ; i++) - { - if (dv1[i] != dv2[i]) return false; - } - return true; -} - + if (h1.byteLength != h2.byteLength) return false; + var dv1 = new Int8Array(h1); + var dv2 = new Int8Array(h2); + for (var i = 0; i != h1.byteLength; i++) if (dv1[i] != dv2[i]) return false; + return true; +} function cloneHasher(h) { - return h.clone(); + return h.clone(); } - function fromPartialHash(partial) { - // NOTE: this is unsafe and uses internal API - const buf = partial.subarray(0, 128); - const rest = utils_js.u32(partial.subarray(128)); - const res = blake2_js.blake2b.create({ dkLen: 64 }); - res.buffer.set(buf); - (res.v0l = rest[0] | 0), (res.v0h = rest[1] | 0); - (res.v1l = rest[2] | 0), (res.v1h = rest[3] | 0); - (res.v2l = rest[4] | 0), (res.v2h = rest[5] | 0); - (res.v3l = rest[6] | 0), (res.v3h = rest[7] | 0); - (res.v4l = rest[8] | 0), (res.v4h = rest[9] | 0); - (res.v5l = rest[10] | 0), (res.v5h = rest[11] | 0); - (res.v6l = rest[12] | 0), (res.v6h = rest[13] | 0); - (res.v7l = rest[14] | 0), (res.v7h = rest[15] | 0); - const shift = 2 ** 32; - const len = rest[16] + rest[17] * shift; - const pos = rest[18] + rest[19] * shift; - res.length = len + pos; - res.pos = pos; - return res; -} - -function toPartialHash(hash){ - // NOTE: this is unsafe and uses internal API - const res = new Uint8Array(216); - const res32 = utils_js.u32(res.subarray(128)); - res.set(hash.buffer); - (res32[0] = hash.v0l), (res32[1] = hash.v0h); - (res32[2] = hash.v1l), (res32[3] = hash.v1h); - (res32[4] = hash.v2l), (res32[5] = hash.v2h); - (res32[6] = hash.v3l), (res32[7] = hash.v3h); - (res32[8] = hash.v4l), (res32[9] = hash.v4h); - (res32[10] = hash.v5l), (res32[11] = hash.v5h); - (res32[12] = hash.v6l), (res32[13] = hash.v6h); - (res32[14] = hash.v7l), (res32[15] = hash.v7h); - res32[18] = hash.pos; - res32[16] = hash.length-hash.pos; - return res; -} - + const buf = partial.subarray(0, 128); + const rest = (0, _noble_hashes_utils_js.u32)(partial.subarray(128)); + const res = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + res.buffer.set(buf); + res.v0l = rest[0] | 0, res.v0h = rest[1] | 0; + res.v1l = rest[2] | 0, res.v1h = rest[3] | 0; + res.v2l = rest[4] | 0, res.v2h = rest[5] | 0; + res.v3l = rest[6] | 0, res.v3h = rest[7] | 0; + res.v4l = rest[8] | 0, res.v4h = rest[9] | 0; + res.v5l = rest[10] | 0, res.v5h = rest[11] | 0; + res.v6l = rest[12] | 0, res.v6h = rest[13] | 0; + res.v7l = rest[14] | 0, res.v7h = rest[15] | 0; + const shift = 2 ** 32; + const len = rest[16] + rest[17] * shift; + const pos = rest[18] + rest[19] * shift; + res.length = len + pos; + res.pos = pos; + return res; +} +function toPartialHash(hash) { + const res = /* @__PURE__ */ new Uint8Array(216); + const res32 = (0, _noble_hashes_utils_js.u32)(res.subarray(128)); + res.set(hash.buffer); + res32[0] = hash.v0l, res32[1] = hash.v0h; + res32[2] = hash.v1l, res32[3] = hash.v1h; + res32[4] = hash.v2l, res32[5] = hash.v2h; + res32[6] = hash.v3l, res32[7] = hash.v3h; + res32[8] = hash.v4l, res32[9] = hash.v4h; + res32[10] = hash.v5l, res32[11] = hash.v5h; + res32[12] = hash.v6l, res32[13] = hash.v6h; + res32[14] = hash.v7l, res32[15] = hash.v7h; + res32[18] = hash.pos; + res32[16] = hash.length - hash.pos; + return res; +} async function sameRatio$2(curve, g1s, g1sx, g2s, g2sx) { - if (curve.G1.isZero(g1s)) return false; - if (curve.G1.isZero(g1sx)) return false; - if (curve.G2.isZero(g2s)) return false; - if (curve.G2.isZero(g2sx)) return false; - // return curve.F12.eq(curve.pairing(g1s, g2sx), curve.pairing(g1sx, g2s)); - const res = await curve.pairingEq(g1s, g2sx, curve.G1.neg(g1sx), g2s); - return res; -} - - + if (curve.G1.isZero(g1s)) return false; + if (curve.G1.isZero(g1sx)) return false; + if (curve.G2.isZero(g2s)) return false; + if (curve.G2.isZero(g2sx)) return false; + return await curve.pairingEq(g1s, g2sx, curve.G1.neg(g1sx), g2s); +} function askEntropy() { - // Use the browser prompt only when a real DOM window exists. "not Node" is - // NOT the same as "browser" (Bun/Deno/edge/SES have neither window nor are - // classic Node), so detect the actual API. - if (typeof window !== "undefined" && typeof window.prompt === "function") { - return window.prompt("Enter a random text. (Entropy): ", ""); - } else { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); - - return new Promise((resolve) => { - rl.question("Enter a random text. (Entropy): ", (input) => resolve(input) ); - }); - } -} - + if (typeof window !== "undefined" && typeof window.prompt === "function") return window.prompt("Enter a random text. (Entropy): ", ""); + else { + const rl = readline.default.createInterface({ + input: process.stdin, + output: process.stdout + }); + return new Promise((resolve) => { + rl.question("Enter a random text. (Entropy): ", (input) => resolve(input)); + }); + } +} function getRandomBytes(n) { - let array = new Uint8Array(n); - if (crypto && crypto.randomFillSync) { // Node: no per-call size limit - crypto.randomFillSync(array); - } else if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) { - // Web Crypto caps each call at 65536 bytes; fill in windows. - for (let i = 0; i < n; i += 65536) { - globalThis.crypto.getRandomValues(array.subarray(i, Math.min(i + 65536, n))); - } - } else { - throw new Error("No secure random source available"); - } - return array; -} - + let array = new Uint8Array(n); + if (crypto.default && crypto.default.randomFillSync) crypto.default.randomFillSync(array); + else if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) for (let i = 0; i < n; i += 65536) globalThis.crypto.getRandomValues(array.subarray(i, Math.min(i + 65536, n))); + else throw new Error("No secure random source available"); + return array; +} async function sha256digest(data) { - if (crypto && crypto.createHash) { // Node - return crypto.createHash("sha256").update(data).digest(); - } else { - // Web Crypto: pass the view (data), not data.buffer, so byteOffset and - // byteLength of subarray views are respected. - const buffer = await globalThis.crypto.subtle.digest("SHA-256", data); - return new Uint8Array(buffer); - } -} - + if (crypto.default && crypto.default.createHash) return crypto.default.createHash("sha256").update(data).digest(); + else { + const buffer = await globalThis.crypto.subtle.digest("SHA-256", data); + return new Uint8Array(buffer); + } +} /** - * @param {Uint8Array} data - * @param {number} offset - */ +* @param {Uint8Array} data +* @param {number} offset +*/ function readUInt32BE(data, offset) { - return new DataView(data.buffer).getUint32(offset, false); + return new DataView(data.buffer).getUint32(offset, false); } - async function getRandomRng(entropy) { - // Generate a random Rng - while (!entropy) { - entropy = await askEntropy(); - } - const hasher = blake2_js.blake2b.create(64); - hasher.update(getRandomBytes(64)); - const enc = new TextEncoder(); // always utf-8 - hasher.update(enc.encode(entropy)); - const hash = hasher.digest(); - - const seed = []; - for (let i=0;i<8;i++) { - seed[i] = readUInt32BE(hash, i*4); - } - const rng = new ffjavascript.ChaCha(seed); - return rng; -} - + while (!entropy) entropy = await askEntropy(); + const hasher = _noble_hashes_blake2_js.blake2b.create(64); + hasher.update(getRandomBytes(64)); + const enc = new TextEncoder(); + hasher.update(enc.encode(entropy)); + const hash = hasher.digest(); + const seed = []; + for (let i = 0; i < 8; i++) seed[i] = readUInt32BE(hash, i * 4); + return new ffjavascript.ChaCha(seed); +} async function rngFromBeaconParams(beaconHash, numIterationsExp) { - let nIterationsInner; - let nIterationsOuter; - if (numIterationsExp<32) { - nIterationsInner = (1 << numIterationsExp) >>> 0; - nIterationsOuter = 1; - } else { - nIterationsInner = 0x100000000; - nIterationsOuter = (1 << (numIterationsExp-32)) >>> 0; - } - - let curHash = beaconHash; - for (let i=0; i>> 0; + nIterationsOuter = 1; + } else { + nIterationsInner = 4294967296; + nIterationsOuter = 1 << numIterationsExp - 32 >>> 0; + } + let curHash = beaconHash; + for (let i = 0; i < nIterationsOuter; i++) for (let j = 0; j < nIterationsInner; j++) curHash = await sha256digest(curHash); + const curHashV = new DataView(curHash.buffer, curHash.byteOffset, curHash.byteLength); + const seed = []; + for (let i = 0; i < 8; i++) seed[i] = curHashV.getUint32(i * 4, false); + return new ffjavascript.ChaCha(seed); +} function hex2ByteArray(s) { - if (s instanceof Uint8Array) return s; - if (s.slice(0,2) == "0x") s= s.slice(2); - return new Uint8Array(s.match(/[\da-f]{2}/gi).map(function (h) { - return parseInt(h, 16); - })); + if (s instanceof Uint8Array) return s; + if (s.slice(0, 2) == "0x") s = s.slice(2); + return new Uint8Array(s.match(/[\da-f]{2}/gi).map(function(h) { + return parseInt(h, 16); + })); } - function byteArray2hex(byteArray) { - return Array.prototype.map.call(byteArray, function(byte) { - return ("0" + (byte & 0xFF).toString(16)).slice(-2); - }).join(""); + return Array.prototype.map.call(byteArray, function(byte) { + return ("0" + (byte & 255).toString(16)).slice(-2); + }).join(""); } - function stringifyBigIntsWithField(Fr, o) { - if (o instanceof Uint8Array) { - return Fr.toString(o); - } else if (Array.isArray(o)) { - return o.map(stringifyBigIntsWithField.bind(null, Fr)); - } else if (typeof o == "object") { - const res = {}; - const keys = Object.keys(o); - keys.forEach( (k) => { - res[k] = stringifyBigIntsWithField(Fr, o[k]); - }); - return res; - } else if ((typeof(o) == "bigint") || o.eq !== undefined) { - return o.toString(10); - } else { - return o; - } -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - - + if (o instanceof Uint8Array) return Fr.toString(o); + else if (Array.isArray(o)) return o.map(stringifyBigIntsWithField.bind(null, Fr)); + else if (typeof o == "object") { + const res = {}; + Object.keys(o).forEach((k) => { + res[k] = stringifyBigIntsWithField(Fr, o[k]); + }); + return res; + } else if (typeof o == "bigint" || o.eq !== void 0) return o.toString(10); + else return o; +} +//#endregion +//#region src/r1cs_export_json.js async function r1csExportJson(r1csFileName, logger) { - - const cir = await r1csfile.readR1cs(r1csFileName, true, true, true, logger); - const Fr=cir.curve.Fr; - delete cir.curve; - delete cir.F; - - return stringifyBigIntsWithField(Fr, cir); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const __dirname$2 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)))); - -let pkgS; + const cir = await (0, r1csfile.readR1cs)(r1csFileName, true, true, true, logger); + const Fr = cir.curve.Fr; + delete cir.curve; + delete cir.F; + return stringifyBigIntsWithField(Fr, cir); +} +//#endregion +//#region src/clprocessor.js +var __dirname$2 = path.default.dirname(url.default.fileURLToPath(require("url").pathToFileURL(__filename).href)); +var pkgS; try { - pkgS = fs.readFileSync(path.join(__dirname$2, "package.json")); + pkgS = fs.default.readFileSync(path.default.join(__dirname$2, "package.json")); } catch { - pkgS = fs.readFileSync(path.join(__dirname$2, "..","package.json")); + pkgS = fs.default.readFileSync(path.default.join(__dirname$2, "..", "package.json")); } - -const pkg = JSON.parse(pkgS); -const version = pkg.version; -let selectedCommand = null; - +var version = JSON.parse(pkgS).version; +var selectedCommand = null; async function clProcessor(commands) { - const cl = []; - const argv = {}; - for (let i=2; i 1) { - argv[arr[0]] = arr.slice(1).join("="); - } else { - argv[arr[0]] = true; - } - } else { - cl.push(process.argv[i]); - } - } - for (let i=0; i0) console.log("Invalid number of parameters"); - helpCmd(cmd); - return 99; - } - return res; - } - } - if (cl.length>0) console.log("Invalid command"); - helpAll(); - return 99; - - function calculateMatch(cmd, cl) { - const alias = []; - const m = parseLine(cmd.cmd); - alias.push(m); - if (cmd.alias) { - if (Array.isArray(cmd.alias)) { - for (let i=0; i1) ? arr1[1] : null - }; - } - - - function areParamsValid(cmd, params) { - while ((params.length)&&(!params[params.length-1])) params.pop(); - const pl = parseLine(cmd); - if (params.length > pl.params.length) return false; - let minParams = pl.params.length; - while ((minParams>0)&&(pl.params[minParams-1][0] == "[")) minParams --; - if (params.length < minParams) return false; - - for (let i=0; (i< pl.params.length)&&(pl.params[i][0]=="<"); i++) { - if (typeof params[i] == "undefined") return false; - } - return true; - } - - function getOptions(options) { - const res = {}; - const opts = options.match(/(\S+)/g); - for (let i=0; i 1) argv[arr[0]] = arr.slice(1).join("="); + else argv[arr[0]] = true; + } else cl.push(process.argv[i]); + for (let i = 0; i < commands.length; i++) { + const cmd = commands[i]; + const m = calculateMatch(commands[i], cl); + let res; + if (m) { + if (argv.h || argv.help) { + helpCmd(cmd); + return; + } + if (areParamsValid(cmd.cmd, m)) if (cmd.options) { + const options = getOptions(cmd.options); + res = await cmd.action(m, options); + } else res = await cmd.action(m, {}); + else { + if (m.length > 0) console.log("Invalid number of parameters"); + helpCmd(cmd); + return 99; + } + return res; + } + } + if (cl.length > 0) console.log("Invalid command"); + helpAll(); + return 99; + function calculateMatch(cmd, cl) { + const alias = []; + const m = parseLine(cmd.cmd); + alias.push(m); + if (cmd.alias) if (Array.isArray(cmd.alias)) for (let i = 0; i < cmd.alias.length; i++) { + const a = parseLine(cmd.alias[i]); + alias.push({ + cmd: a.cmd, + params: m.params + }); + } + else { + const a = parseLine(cmd.alias); + alias.push({ + cmd: a.cmd, + params: m.params + }); + } + for (let i = 0; i < cl.length; i++) for (let j = 0; j < alias.length; j++) { + const w = alias[j].cmd.shift(); + if (cl[i].toUpperCase() == w.toUpperCase()) { + if (alias[j].cmd.length == 0) return buildRemaining(alias[j].params, cl.slice(i + 1)); + } else { + alias.splice(j, 1); + j--; + } + } + return null; + function buildRemaining(defParams, cl) { + const res = []; + let p = 0; + for (let i = 0; i < defParams.length; i++) if (defParams[i][0] == "-") res.push(getOption(defParams[i]).val); + else if (p < cl.length) res.push(cl[p++]); + else res.push(null); + while (p < cl.length) res.push(cl[p++]); + return res; + } + } + function parseLine(l) { + const words = l.match(/(\S+)/g); + for (let i = 0; i < words.length; i++) if (words[i][0] == "<" || words[i][0] == "[" || words[i][0] == "-") return { + cmd: words.slice(0, i), + params: words.slice(i) + }; + return { + cmd: words, + params: [] + }; + } + function getOption(o) { + const arr1 = o.slice(1).split(":"); + const arr2 = arr1[0].split("|"); + for (let i = 0; i < arr2.length; i++) if (argv[arr2[i]]) return { + key: arr2[0], + val: argv[arr2[i]] + }; + return { + key: arr2[0], + val: arr1.length > 1 ? arr1[1] : null + }; + } + function areParamsValid(cmd, params) { + while (params.length && !params[params.length - 1]) params.pop(); + const pl = parseLine(cmd); + if (params.length > pl.params.length) return false; + let minParams = pl.params.length; + while (minParams > 0 && pl.params[minParams - 1][0] == "[") minParams--; + if (params.length < minParams) return false; + for (let i = 0; i < pl.params.length && pl.params[i][0] == "<"; i++) if (typeof params[i] == "undefined") return false; + return true; + } + function getOptions(options) { + const res = {}; + const opts = options.match(/(\S+)/g); + for (let i = 0; i < opts.length; i++) { + const o = getOption(opts[i]); + res[o.key] = o.val; + } + return res; + } + function printVersion() { + console.log("snarkjs@" + version); + } + function epilog() { + console.log(` Copyright (C) 2018 0kims association This program comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under certain conditions; see the COPYING file in the official repo directory at https://github.com/iden3/snarkjs `); - } - - function helpAll() { - printVersion(); - epilog(); - console.log(""); - console.log("Usage:"); - console.log(" snarkjs ... "); - console.log(" or snarkjs ... "); - console.log(""); - console.log("Type snarkjs --help to get more information for that command"); - console.log(""); - console.log("Full Command Description"); - console.log("============ ================="); - for (let i=0; i. -*/ - - + } + function helpAll() { + printVersion(); + epilog(); + console.log(""); + console.log("Usage:"); + console.log(" snarkjs ... "); + console.log(" or snarkjs ... "); + console.log(""); + console.log("Type snarkjs --help to get more information for that command"); + console.log(""); + console.log("Full Command Description"); + console.log("============ ================="); + for (let i = 0; i < commands.length; i++) { + const cmd = commands[i]; + let S = ""; + const pl = parseLine(cmd.cmd); + S += pl.cmd.join(" "); + while (S.length < 30) S = S + " "; + S += cmd.description; + console.log(S); + S = " Usage: snarkjs "; + if (cmd.alias) if (Array.isArray(cmd.alias)) S += cmd.alias[0]; + else S += cmd.alias; + else S += pl.cmd.join(" "); + S += " " + pl.params.join(" "); + console.log(S); + } + } + function helpCmd(cmd) { + if (typeof cmd == "undefined") cmd = selectedCommand; + if (typeof cmd == "undefined") return helpAll(); + printVersion(); + epilog(); + console.log(""); + if (cmd.longDescription) console.log(cmd.longDescription); + else console.log(cmd.description); + console.log("Usage: "); + console.log(" snarkjs " + cmd.cmd); + const pl = parseLine(cmd.cmd); + let S = " or snarkjs "; + if (cmd.alias) if (Array.isArray(cmd.alias)) S += cmd.alias[0]; + else S += cmd.alias; + else S += pl.cmd.join(" "); + S += " " + pl.params.join(" "); + console.log(S); + console.log(""); + } +} +//#endregion +//#region src/keypair.js function hashToG2(curve, hash) { - const hashV = new DataView(hash.buffer, hash.byteOffset, hash.byteLength); - const seed = []; - for (let i=0; i<8; i++) { - seed[i] = hashV.getUint32(i*4); - } - - const rng = new ffjavascript.ChaCha(seed); - - const g2_sp = curve.G2.fromRng(rng); - - return g2_sp; -} - + const hashV = new DataView(hash.buffer, hash.byteOffset, hash.byteLength); + const seed = []; + for (let i = 0; i < 8; i++) seed[i] = hashV.getUint32(i * 4); + const rng = new ffjavascript.ChaCha(seed); + return curve.G2.fromRng(rng); +} function getG2sp(curve, persinalization, challenge, g1s, g1sx) { - - const h = blake2_js.blake2b.create({ dkLen: 64 }); - const b1 = new Uint8Array([persinalization]); - h.update(b1); - h.update(challenge); - const b3 = curve.G1.toUncompressed(g1s); - h.update( b3); - const b4 = curve.G1.toUncompressed(g1sx); - h.update( b4); - const hash =h.digest(); - - return hashToG2(curve, hash); -} - -function calculatePubKey(k, curve, personalization, challengeHash, rng ) { - k.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); - k.g1_sx = curve.G1.toAffine(curve.G1.timesFr(k.g1_s, k.prvKey)); - k.g2_sp = curve.G2.toAffine(getG2sp(curve, personalization, challengeHash, k.g1_s, k.g1_sx)); - k.g2_spx = curve.G2.toAffine(curve.G2.timesFr(k.g2_sp, k.prvKey)); - return k; -} - + const h = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + const b1 = new Uint8Array([persinalization]); + h.update(b1); + h.update(challenge); + const b3 = curve.G1.toUncompressed(g1s); + h.update(b3); + const b4 = curve.G1.toUncompressed(g1sx); + h.update(b4); + return hashToG2(curve, h.digest()); +} +function calculatePubKey(k, curve, personalization, challengeHash, rng) { + k.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + k.g1_sx = curve.G1.toAffine(curve.G1.timesFr(k.g1_s, k.prvKey)); + k.g2_sp = curve.G2.toAffine(getG2sp(curve, personalization, challengeHash, k.g1_s, k.g1_sx)); + k.g2_spx = curve.G2.toAffine(curve.G2.timesFr(k.g2_sp, k.prvKey)); + return k; +} function createPTauKey(curve, challengeHash, rng) { - const key = { - tau: {}, - alpha: {}, - beta: {} - }; - key.tau.prvKey = curve.Fr.fromRng(rng); - key.alpha.prvKey = curve.Fr.fromRng(rng); - key.beta.prvKey = curve.Fr.fromRng(rng); - calculatePubKey(key.tau, curve, 0, challengeHash, rng); - calculatePubKey(key.alpha, curve, 1, challengeHash, rng); - calculatePubKey(key.beta, curve, 2, challengeHash, rng); - return key; -} - -const bls12381r = ffjavascript.Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); -const bn128r = ffjavascript.Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - -const bls12381q = ffjavascript.Scalar.e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16); -const bn128q = ffjavascript.Scalar.e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); - + const key = { + tau: {}, + alpha: {}, + beta: {} + }; + key.tau.prvKey = curve.Fr.fromRng(rng); + key.alpha.prvKey = curve.Fr.fromRng(rng); + key.beta.prvKey = curve.Fr.fromRng(rng); + calculatePubKey(key.tau, curve, 0, challengeHash, rng); + calculatePubKey(key.alpha, curve, 1, challengeHash, rng); + calculatePubKey(key.beta, curve, 2, challengeHash, rng); + return key; +} +//#endregion +//#region src/curves.js +var bls12381r = ffjavascript.Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); +var bn128r = ffjavascript.Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); +var bls12381q = ffjavascript.Scalar.e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16); +var bn128q = ffjavascript.Scalar.e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); async function getCurveFromR(r, options) { - let curve; - // check that options param is defined and that options.singleThread is defined - let singleThread = options; - if (ffjavascript.Scalar.eq(r, bn128r)) { - curve = await ffjavascript.buildBn128(singleThread); - } else if (ffjavascript.Scalar.eq(r, bls12381r)) { - curve = await ffjavascript.buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${ffjavascript.Scalar.toString(r)}`); - } - return curve; -} - + let curve; + let singleThread = options && options.singleThread; + if (ffjavascript.Scalar.eq(r, bn128r)) curve = await (0, ffjavascript.buildBn128)(singleThread); + else if (ffjavascript.Scalar.eq(r, bls12381r)) curve = await (0, ffjavascript.buildBls12381)(singleThread); + else throw new Error(`Curve not supported: ${ffjavascript.Scalar.toString(r)}`); + return curve; +} async function getCurveFromQ(q, options) { - let curve; - let singleThread = options && options.singleThread; - if (ffjavascript.Scalar.eq(q, bn128q)) { - curve = await ffjavascript.buildBn128(singleThread); - } else if (ffjavascript.Scalar.eq(q, bls12381q)) { - curve = await ffjavascript.buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${ffjavascript.Scalar.toString(q)}`); - } - return curve; -} - + let curve; + let singleThread = options && options.singleThread; + if (ffjavascript.Scalar.eq(q, bn128q)) curve = await (0, ffjavascript.buildBn128)(singleThread); + else if (ffjavascript.Scalar.eq(q, bls12381q)) curve = await (0, ffjavascript.buildBls12381)(singleThread); + else throw new Error(`Curve not supported: ${ffjavascript.Scalar.toString(q)}`); + return curve; +} async function getCurveFromName(name, options) { - let curve; - let singleThread = options; - const normName = normalizeName(name); - if (["BN128", "BN254", "ALTBN128"].indexOf(normName) >= 0) { - curve = await ffjavascript.buildBn128(singleThread); - } else if (["BLS12381"].indexOf(normName) >= 0) { - curve = await ffjavascript.buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${name}`); - } - return curve; - - function normalizeName(n) { - return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); - } - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + let curve; + let singleThread = options && options.singleThread; + const normName = normalizeName(name); + if ([ + "BN128", + "BN254", + "ALTBN128" + ].indexOf(normName) >= 0) curve = await (0, ffjavascript.buildBn128)(singleThread); + else if (["BLS12381"].indexOf(normName) >= 0) curve = await (0, ffjavascript.buildBls12381)(singleThread); + else throw new Error(`Curve not supported: ${name}`); + return curve; + function normalizeName(n) { + return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); + } +} +//#endregion +//#region src/powersoftau_utils.js async function writePTauHeader(fd, curve, power, ceremonyPower) { - // Write the header - /////////// - - if (! ceremonyPower) ceremonyPower = power; - await fd.writeULE32(1); // Header type - const pHeaderSize = fd.pos; - await fd.writeULE64(0); // Temporally set to 0 length - - await fd.writeULE32(curve.F1.n64*8); - - const buff = new Uint8Array(curve.F1.n8); - ffjavascript.Scalar.toRprLE(buff, 0, curve.q, curve.F1.n8); - await fd.write(buff); - await fd.writeULE32(power); // power - await fd.writeULE32(ceremonyPower); // power - - const headerSize = fd.pos - pHeaderSize - 8; - - const oldPos = fd.pos; - - await fd.writeULE64(headerSize, pHeaderSize); - - fd.pos = oldPos; -} - + if (!ceremonyPower) ceremonyPower = power; + await fd.writeULE32(1); + const pHeaderSize = fd.pos; + await fd.writeULE64(0); + await fd.writeULE32(curve.F1.n64 * 8); + const buff = new Uint8Array(curve.F1.n8); + ffjavascript.Scalar.toRprLE(buff, 0, curve.q, curve.F1.n8); + await fd.write(buff); + await fd.writeULE32(power); + await fd.writeULE32(ceremonyPower); + const headerSize = fd.pos - pHeaderSize - 8; + const oldPos = fd.pos; + await fd.writeULE64(headerSize, pHeaderSize); + fd.pos = oldPos; +} async function readPTauHeader(fd, sections) { - if (!sections[1]) throw new Error(fd.fileName + ": File has no header"); - if (sections[1].length>1) throw new Error(fd.fileName +": File has more than one header"); - - fd.pos = sections[1][0].p; - const n8 = await fd.readULE32(); - const buff = await fd.read(n8); - const q = ffjavascript.Scalar.fromRprLE(buff); - - const curve = await getCurveFromQ(q); - - if (curve.F1.n64*8 != n8) throw new Error(fd.fileName +": Invalid size"); - - const power = await fd.readULE32(); - const ceremonyPower = await fd.readULE32(); - - if (fd.pos-sections[1][0].p != sections[1][0].size) throw new Error("Invalid PTau header size"); - - return {curve, power, ceremonyPower}; -} - - + if (!sections[1]) throw new Error(fd.fileName + ": File has no header"); + if (sections[1].length > 1) throw new Error(fd.fileName + ": File has more than one header"); + fd.pos = sections[1][0].p; + const n8 = await fd.readULE32(); + const buff = await fd.read(n8); + const curve = await getCurveFromQ(ffjavascript.Scalar.fromRprLE(buff)); + if (curve.F1.n64 * 8 != n8) throw new Error(fd.fileName + ": Invalid size"); + const power = await fd.readULE32(); + const ceremonyPower = await fd.readULE32(); + if (fd.pos - sections[1][0].p != sections[1][0].size) throw new Error("Invalid PTau header size"); + return { + curve, + power, + ceremonyPower + }; +} async function readPtauPubKey(fd, curve, montgomery) { - - const buff = await fd.read(curve.F1.n8*2*6 + curve.F2.n8*2*3); - - return fromPtauPubKeyRpr(buff, 0, curve, montgomery); + return fromPtauPubKeyRpr(await fd.read(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3), 0, curve, montgomery); } - function fromPtauPubKeyRpr(buff, pos, curve, montgomery) { - - const key = { - tau: {}, - alpha: {}, - beta: {} - }; - - key.tau.g1_s = readG1(); - key.tau.g1_sx = readG1(); - key.alpha.g1_s = readG1(); - key.alpha.g1_sx = readG1(); - key.beta.g1_s = readG1(); - key.beta.g1_sx = readG1(); - key.tau.g2_spx = readG2(); - key.alpha.g2_spx = readG2(); - key.beta.g2_spx = readG2(); - - return key; - - function readG1() { - let p; - if (montgomery) { - p = curve.G1.fromRprLEM( buff, pos ); - } else { - p = curve.G1.fromRprUncompressed( buff, pos ); - } - pos += curve.G1.F.n8*2; - return p; - } - - function readG2() { - let p; - if (montgomery) { - p = curve.G2.fromRprLEM( buff, pos ); - } else { - p = curve.G2.fromRprUncompressed( buff, pos ); - } - pos += curve.G2.F.n8*2; - return p; - } -} - + const key = { + tau: {}, + alpha: {}, + beta: {} + }; + key.tau.g1_s = readG1(); + key.tau.g1_sx = readG1(); + key.alpha.g1_s = readG1(); + key.alpha.g1_sx = readG1(); + key.beta.g1_s = readG1(); + key.beta.g1_sx = readG1(); + key.tau.g2_spx = readG2(); + key.alpha.g2_spx = readG2(); + key.beta.g2_spx = readG2(); + return key; + function readG1() { + let p; + if (montgomery) p = curve.G1.fromRprLEM(buff, pos); + else p = curve.G1.fromRprUncompressed(buff, pos); + pos += curve.G1.F.n8 * 2; + return p; + } + function readG2() { + let p; + if (montgomery) p = curve.G2.fromRprLEM(buff, pos); + else p = curve.G2.fromRprUncompressed(buff, pos); + pos += curve.G2.F.n8 * 2; + return p; + } +} function toPtauPubKeyRpr(buff, pos, curve, key, montgomery) { - - writeG1(key.tau.g1_s); - writeG1(key.tau.g1_sx); - writeG1(key.alpha.g1_s); - writeG1(key.alpha.g1_sx); - writeG1(key.beta.g1_s); - writeG1(key.beta.g1_sx); - writeG2(key.tau.g2_spx); - writeG2(key.alpha.g2_spx); - writeG2(key.beta.g2_spx); - - async function writeG1(p) { - if (montgomery) { - curve.G1.toRprLEM(buff, pos, p); - } else { - curve.G1.toRprUncompressed(buff, pos, p); - } - pos += curve.F1.n8*2; - } - - async function writeG2(p) { - if (montgomery) { - curve.G2.toRprLEM(buff, pos, p); - } else { - curve.G2.toRprUncompressed(buff, pos, p); - } - pos += curve.F2.n8*2; - } - - return buff; -} - + writeG1(key.tau.g1_s); + writeG1(key.tau.g1_sx); + writeG1(key.alpha.g1_s); + writeG1(key.alpha.g1_sx); + writeG1(key.beta.g1_s); + writeG1(key.beta.g1_sx); + writeG2(key.tau.g2_spx); + writeG2(key.alpha.g2_spx); + writeG2(key.beta.g2_spx); + async function writeG1(p) { + if (montgomery) curve.G1.toRprLEM(buff, pos, p); + else curve.G1.toRprUncompressed(buff, pos, p); + pos += curve.F1.n8 * 2; + } + async function writeG2(p) { + if (montgomery) curve.G2.toRprLEM(buff, pos, p); + else curve.G2.toRprUncompressed(buff, pos, p); + pos += curve.F2.n8 * 2; + } + return buff; +} async function writePtauPubKey(fd, curve, key, montgomery) { - const buff = new Uint8Array(curve.F1.n8*2*6 + curve.F2.n8*2*3); - toPtauPubKeyRpr(buff, 0, curve, key, montgomery); - await fd.write(buff); + const buff = new Uint8Array(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + toPtauPubKeyRpr(buff, 0, curve, key, montgomery); + await fd.write(buff); } - async function readContribution$1(fd, curve) { - const c = {}; - - c.tauG1 = await readG1(); - c.tauG2 = await readG2(); - c.alphaG1 = await readG1(); - c.betaG1 = await readG1(); - c.betaG2 = await readG2(); - c.key = await readPtauPubKey(fd, curve, true); - c.partialHash = await fd.read(216); - c.nextChallenge = await fd.read(64); - c.type = await fd.readULE32(); - - const buffV = new Uint8Array(curve.G1.F.n8*2*6+curve.G2.F.n8*2*3); - toPtauPubKeyRpr(buffV, 0, curve, c.key, false); - - const responseHasher = fromPartialHash(c.partialHash); - responseHasher.update(buffV); - c.responseHash = responseHasher.digest(); - - const paramLength = await fd.readULE32(); - const curPos = fd.pos; - let lastType =0; - while (fd.pos-curPos < paramLength) { - const buffType = await readDV(1); - if (buffType[0]<= lastType) throw new Error("Parameters in the contribution must be sorted"); - lastType = buffType[0]; - if (buffType[0]==1) { // Name - const buffLen = await readDV(1); - const buffStr = await readDV(buffLen[0]); - c.name = new TextDecoder().decode(buffStr); - } else if (buffType[0]==2) { - const buffExp = await readDV(1); - c.numIterationsExp = buffExp[0]; - } else if (buffType[0]==3) { - const buffLen = await readDV(1); - c.beaconHash = await readDV(buffLen[0]); - } else { - throw new Error("Parameter not recognized"); - } - } - if (fd.pos != curPos + paramLength) { - throw new Error("Parameters do not match"); - } - - return c; - - async function readG1() { - const pBuff = await fd.read(curve.G1.F.n8*2); - return curve.G1.fromRprLEM( pBuff ); - } - - async function readG2() { - const pBuff = await fd.read(curve.G2.F.n8*2); - return curve.G2.fromRprLEM( pBuff ); - } - - async function readDV(n) { - const b = await fd.read(n); - return new Uint8Array(b); - } -} - + const c = {}; + c.tauG1 = await readG1(); + c.tauG2 = await readG2(); + c.alphaG1 = await readG1(); + c.betaG1 = await readG1(); + c.betaG2 = await readG2(); + c.key = await readPtauPubKey(fd, curve, true); + c.partialHash = await fd.read(216); + c.nextChallenge = await fd.read(64); + c.type = await fd.readULE32(); + const buffV = new Uint8Array(curve.G1.F.n8 * 2 * 6 + curve.G2.F.n8 * 2 * 3); + toPtauPubKeyRpr(buffV, 0, curve, c.key, false); + const responseHasher = fromPartialHash(c.partialHash); + responseHasher.update(buffV); + c.responseHash = responseHasher.digest(); + const paramLength = await fd.readULE32(); + const curPos = fd.pos; + let lastType = 0; + while (fd.pos - curPos < paramLength) { + const buffType = await readDV(1); + if (buffType[0] <= lastType) throw new Error("Parameters in the contribution must be sorted"); + lastType = buffType[0]; + if (buffType[0] == 1) { + const buffStr = await readDV((await readDV(1))[0]); + c.name = new TextDecoder().decode(buffStr); + } else if (buffType[0] == 2) c.numIterationsExp = (await readDV(1))[0]; + else if (buffType[0] == 3) c.beaconHash = await readDV((await readDV(1))[0]); + else throw new Error("Parameter not recognized"); + } + if (fd.pos != curPos + paramLength) throw new Error("Parameters do not match"); + return c; + async function readG1() { + const pBuff = await fd.read(curve.G1.F.n8 * 2); + return curve.G1.fromRprLEM(pBuff); + } + async function readG2() { + const pBuff = await fd.read(curve.G2.F.n8 * 2); + return curve.G2.fromRprLEM(pBuff); + } + async function readDV(n) { + const b = await fd.read(n); + return new Uint8Array(b); + } +} async function readContributions(fd, curve, sections) { - if (!sections[7]) throw new Error(fd.fileName + ": File has no contributions"); - if (sections[7][0].length>1) throw new Error(fd.fileName +": File has more than one contributions section"); - - fd.pos = sections[7][0].p; - const nContributions = await fd.readULE32(); - const contributions = []; - for (let i=0; i 1) throw new Error(fd.fileName + ": File has more than one contributions section"); + fd.pos = sections[7][0].p; + const nContributions = await fd.readULE32(); + const contributions = []; + for (let i = 0; i < nContributions; i++) { + const c = await readContribution$1(fd, curve); + c.id = i + 1; + contributions.push(c); + } + if (fd.pos - sections[7][0].p != sections[7][0].size) throw new Error("Invalid contribution section size"); + return contributions; +} async function writeContribution$1(fd, curve, contribution) { - - const buffG1 = new Uint8Array(curve.F1.n8*2); - const buffG2 = new Uint8Array(curve.F2.n8*2); - await writeG1(contribution.tauG1); - await writeG2(contribution.tauG2); - await writeG1(contribution.alphaG1); - await writeG1(contribution.betaG1); - await writeG2(contribution.betaG2); - await writePtauPubKey(fd, curve, contribution.key, true); - await fd.write(contribution.partialHash); - await fd.write(contribution.nextChallenge); - await fd.writeULE32(contribution.type || 0); - - const params = []; - if (contribution.name) { - params.push(1); // Param Name - const nameData = new TextEncoder("utf-8").encode(contribution.name.substring(0,64)); - params.push(nameData.byteLength); - for (let i=0; i0) { - const paramsBuff = new Uint8Array(params); - await fd.writeULE32(paramsBuff.byteLength); - await fd.write(paramsBuff); - } else { - await fd.writeULE32(0); - } - - - async function writeG1(p) { - curve.G1.toRprLEM(buffG1, 0, p); - await fd.write(buffG1); - } - - async function writeG2(p) { - curve.G2.toRprLEM(buffG2, 0, p); - await fd.write(buffG2); - } - -} - + const buffG1 = new Uint8Array(curve.F1.n8 * 2); + const buffG2 = new Uint8Array(curve.F2.n8 * 2); + await writeG1(contribution.tauG1); + await writeG2(contribution.tauG2); + await writeG1(contribution.alphaG1); + await writeG1(contribution.betaG1); + await writeG2(contribution.betaG2); + await writePtauPubKey(fd, curve, contribution.key, true); + await fd.write(contribution.partialHash); + await fd.write(contribution.nextChallenge); + await fd.writeULE32(contribution.type || 0); + const params = []; + if (contribution.name) { + params.push(1); + const nameData = new TextEncoder("utf-8").encode(contribution.name.substring(0, 64)); + params.push(nameData.byteLength); + for (let i = 0; i < nameData.byteLength; i++) params.push(nameData[i]); + } + if (contribution.type == 1) { + params.push(2); + params.push(contribution.numIterationsExp); + params.push(3); + params.push(contribution.beaconHash.byteLength); + for (let i = 0; i < contribution.beaconHash.byteLength; i++) params.push(contribution.beaconHash[i]); + } + if (params.length > 0) { + const paramsBuff = new Uint8Array(params); + await fd.writeULE32(paramsBuff.byteLength); + await fd.write(paramsBuff); + } else await fd.writeULE32(0); + async function writeG1(p) { + curve.G1.toRprLEM(buffG1, 0, p); + await fd.write(buffG1); + } + async function writeG2(p) { + curve.G2.toRprLEM(buffG2, 0, p); + await fd.write(buffG2); + } +} async function writeContributions(fd, curve, contributions) { - - await fd.writeULE32(7); // Header type - const pContributionsSize = fd.pos; - await fd.writeULE64(0); // Temporally set to 0 length - - await fd.writeULE32(contributions.length); - for (let i=0; i< contributions.length; i++) { - await writeContribution$1(fd, curve, contributions[i]); - } - const contributionsSize = fd.pos - pContributionsSize - 8; - - const oldPos = fd.pos; - - await fd.writeULE64(contributionsSize, pContributionsSize); - fd.pos = oldPos; -} - + await fd.writeULE32(7); + const pContributionsSize = fd.pos; + await fd.writeULE64(0); + await fd.writeULE32(contributions.length); + for (let i = 0; i < contributions.length; i++) await writeContribution$1(fd, curve, contributions[i]); + const contributionsSize = fd.pos - pContributionsSize - 8; + const oldPos = fd.pos; + await fd.writeULE64(contributionsSize, pContributionsSize); + fd.pos = oldPos; +} function calculateFirstChallengeHash(curve, power, logger) { - if (logger) logger.debug("Calculating First Challenge Hash"); - - const hasher = blake2_js.blake2b.create({ dkLen: 64 }); - - const vG1 = new Uint8Array(curve.G1.F.n8*2); - const vG2 = new Uint8Array(curve.G2.F.n8*2); - curve.G1.toRprUncompressed(vG1, 0, curve.G1.g); - curve.G2.toRprUncompressed(vG2, 0, curve.G2.g); - - hasher.update(blake2_js.blake2b.create({ dkLen: 64 }).digest()); - - let n; - - n=(2 ** power)*2 -1; - if (logger) logger.debug("Calculate Initial Hash: tauG1"); - hashBlock(vG1, n); - n= 2 ** power; - if (logger) logger.debug("Calculate Initial Hash: tauG2"); - hashBlock(vG2, n); - if (logger) logger.debug("Calculate Initial Hash: alphaTauG1"); - hashBlock(vG1, n); - if (logger) logger.debug("Calculate Initial Hash: betaTauG1"); - hashBlock(vG1, n); - hasher.update(vG2); - - return hasher.digest(); - - function hashBlock(buff, n) { - // this block size is a good compromise between speed and the maximum - // input size of the Blake2b update method (65,535,720 bytes). - const blockSize = 341000; - const nBlocks = Math.floor(n / blockSize); - const rem = n % blockSize; - const bigBuff = new Uint8Array(blockSize * buff.byteLength); - for (let i=0; i. -*/ - - + return createPTauKey(curve, challengeHash, await rngFromBeaconParams(beaconHash, numIterationsExp)); +} +//#endregion +//#region src/powersoftau_new.js async function newAccumulator(curve, power, fileName, logger) { - - const fd = await binFileUtils__namespace.createBinFile(fileName, "ptau", 1, 7); - - await writePTauHeader(fd, curve, power, 0); - - const buffG1 = curve.G1.oneAffine; - const buffG2 = curve.G2.oneAffine; - - // Write tauG1 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 2); - const nTauG1 = (2 ** power) * 2 -1; - for (let i=0; i< nTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("tauG1: " + i); - } - await binFileUtils__namespace.endWriteSection(fd); - - // Write tauG2 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 3); - const nTauG2 = (2 ** power); - for (let i=0; i< nTauG2; i++) { - await fd.write(buffG2); - if ((logger)&&((i%100000) == 0)&&i) logger.log("tauG2: " + i); - } - await binFileUtils__namespace.endWriteSection(fd); - - // Write alphaTauG1 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 4); - const nAlfaTauG1 = (2 ** power); - for (let i=0; i< nAlfaTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("alphaTauG1: " + i); - } - await binFileUtils__namespace.endWriteSection(fd); - - // Write betaTauG1 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 5); - const nBetaTauG1 = (2 ** power); - for (let i=0; i< nBetaTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("betaTauG1: " + i); - } - await binFileUtils__namespace.endWriteSection(fd); - - // Write betaG2 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 6); - await fd.write(buffG2); - await binFileUtils__namespace.endWriteSection(fd); - - // Contributions - /////////// - await binFileUtils__namespace.startWriteSection(fd, 7); - await fd.writeULE32(0); // 0 Contributions - await binFileUtils__namespace.endWriteSection(fd); - - await fd.close(); - - const firstChallengeHash = calculateFirstChallengeHash(curve, power, logger); - - if (logger) logger.debug(formatHash(blake2_js.blake2b.create({ dkLen: 64 }).digest(), "Blank Contribution Hash:")); - - if (logger) logger.info(formatHash(firstChallengeHash, "First Contribution Hash:")); - - return firstChallengeHash; - -} - -// Format of the outpu -// Hash of the last contribution 64Bytes -// 2^N * 2 -1 TauG1 points (uncompressed) -// 2^N TauG2 Points (uncompressed) -// 2^N AlphaTauG1 Points (uncompressed) -// 2^N BetaTauG1 Points (uncompressed) -// BetaG2 (uncompressed) - - + const fd = await _iden3_binfileutils.createBinFile(fileName, "ptau", 1, 7); + await writePTauHeader(fd, curve, power, 0); + const buffG1 = curve.G1.oneAffine; + const buffG2 = curve.G2.oneAffine; + await _iden3_binfileutils.startWriteSection(fd, 2); + const nTauG1 = 2 ** power * 2 - 1; + for (let i = 0; i < nTauG1; i++) { + await fd.write(buffG1); + if (logger && i % 1e5 == 0 && i) logger.log("tauG1: " + i); + } + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 3); + const nTauG2 = 2 ** power; + for (let i = 0; i < nTauG2; i++) { + await fd.write(buffG2); + if (logger && i % 1e5 == 0 && i) logger.log("tauG2: " + i); + } + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 4); + const nAlfaTauG1 = 2 ** power; + for (let i = 0; i < nAlfaTauG1; i++) { + await fd.write(buffG1); + if (logger && i % 1e5 == 0 && i) logger.log("alphaTauG1: " + i); + } + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 5); + const nBetaTauG1 = 2 ** power; + for (let i = 0; i < nBetaTauG1; i++) { + await fd.write(buffG1); + if (logger && i % 1e5 == 0 && i) logger.log("betaTauG1: " + i); + } + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 6); + await fd.write(buffG2); + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 7); + await fd.writeULE32(0); + await _iden3_binfileutils.endWriteSection(fd); + await fd.close(); + const firstChallengeHash = calculateFirstChallengeHash(curve, power, logger); + if (logger) logger.debug(formatHash(_noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }).digest(), "Blank Contribution Hash:")); + if (logger) logger.info(formatHash(firstChallengeHash, "First Contribution Hash:")); + return firstChallengeHash; +} +//#endregion +//#region src/powersoftau_export_challenge.js async function exportChallenge(pTauFilename, challengeFilename, logger) { - const {fd: fdFrom, sections} = await binFileUtils__namespace.readBinFile(pTauFilename, "ptau", 1); - - const {curve, power} = await readPTauHeader(fdFrom, sections); - - const contributions = await readContributions(fdFrom, curve, sections); - let lastResponseHash, curChallengeHash; - if (contributions.length == 0) { - lastResponseHash = blake2_js.blake2b.create({ dkLen: 64 }).digest(); - curChallengeHash = calculateFirstChallengeHash(curve, power); - } else { - lastResponseHash = contributions[contributions.length-1].responseHash; - curChallengeHash = contributions[contributions.length-1].nextChallenge; - } - - if (logger) logger.info(formatHash(lastResponseHash, "Last Response Hash: ")); - - if (logger) logger.info(formatHash(curChallengeHash, "New Challenge Hash: ")); - - - const fdTo = await fastFile__namespace.createOverride(challengeFilename); - - const toHash = blake2_js.blake2b.create({ dkLen: 64 }); - await fdTo.write(lastResponseHash); - toHash.update(lastResponseHash); - - await exportSection(2, "G1", (2 ** power) * 2 -1, "tauG1"); - await exportSection(3, "G2", (2 ** power) , "tauG2"); - await exportSection(4, "G1", (2 ** power) , "alphaTauG1"); - await exportSection(5, "G1", (2 ** power) , "betaTauG1"); - await exportSection(6, "G2", 1 , "betaG2"); - - await fdFrom.close(); - await fdTo.close(); - - const calcCurChallengeHash = toHash.digest(); - - if (!hashIsEqual (curChallengeHash, calcCurChallengeHash)) { - if (logger) logger.info(formatHash(calcCurChallengeHash, "Calc Curret Challenge Hash: ")); - - if (logger) logger.error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); - throw new Error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); - } - - return curChallengeHash; - - async function exportSection(sectionId, groupName, nPoints, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPointsChunk = Math.floor((1<<24)/sG); - - await binFileUtils__namespace.startReadUniqueSection(fdFrom, sections, sectionId); - for (let i=0; i< nPoints; i+= nPointsChunk) { - if (logger) logger.debug(`Exporting ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - let buff; - buff = await fdFrom.read(n*sG); - buff = await G.batchLEMtoU(buff); - await fdTo.write(buff); - toHash.update(buff); - } - await binFileUtils__namespace.endReadSection(fdFrom); - } - - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const { fd: fdFrom, sections } = await _iden3_binfileutils.readBinFile(pTauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fdFrom, sections); + const contributions = await readContributions(fdFrom, curve, sections); + let lastResponseHash, curChallengeHash; + if (contributions.length == 0) { + lastResponseHash = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }).digest(); + curChallengeHash = calculateFirstChallengeHash(curve, power); + } else { + lastResponseHash = contributions[contributions.length - 1].responseHash; + curChallengeHash = contributions[contributions.length - 1].nextChallenge; + } + if (logger) logger.info(formatHash(lastResponseHash, "Last Response Hash: ")); + if (logger) logger.info(formatHash(curChallengeHash, "New Challenge Hash: ")); + const fdTo = await fastfile.createOverride(challengeFilename); + const toHash = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + await fdTo.write(lastResponseHash); + toHash.update(lastResponseHash); + await exportSection(2, "G1", 2 ** power * 2 - 1, "tauG1"); + await exportSection(3, "G2", 2 ** power, "tauG2"); + await exportSection(4, "G1", 2 ** power, "alphaTauG1"); + await exportSection(5, "G1", 2 ** power, "betaTauG1"); + await exportSection(6, "G2", 1, "betaG2"); + await fdFrom.close(); + await fdTo.close(); + const calcCurChallengeHash = toHash.digest(); + if (!hashIsEqual(curChallengeHash, calcCurChallengeHash)) { + if (logger) logger.info(formatHash(calcCurChallengeHash, "Calc Curret Challenge Hash: ")); + if (logger) logger.error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); + throw new Error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); + } + return curChallengeHash; + async function exportSection(sectionId, groupName, nPoints, sectionName) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const nPointsChunk = Math.floor((1 << 24) / sG); + await _iden3_binfileutils.startReadUniqueSection(fdFrom, sections, sectionId); + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Exporting ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + let buff; + buff = await fdFrom.read(n * sG); + buff = await G.batchLEMtoU(buff); + await fdTo.write(buff); + toHash.update(buff); + } + await _iden3_binfileutils.endReadSection(fdFrom); + } +} +//#endregion +//#region src/powersoftau_import.js async function importResponse(oldPtauFilename, contributionFilename, newPTauFilename, name, importPoints, logger) { - - const noHash = new Uint8Array(64); - for (let i=0; i<64; i++) noHash[i] = 0xFF; - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - const contributions = await readContributions(fdOld, curve, sections); - const currentContribution = {}; - - if (name) currentContribution.name = name; - - const sG1 = curve.F1.n8*2; - const scG1 = curve.F1.n8; // Compressed size - const sG2 = curve.F2.n8*2; - const scG2 = curve.F2.n8; // Compressed size - - const fdResponse = await fastFile__namespace.readExisting(contributionFilename); - - if (fdResponse.totalSize != - 64 + // Old Hash - ((2 ** power)*2-1)*scG1 + - (2 ** power)*scG2 + - (2 ** power)*scG1 + - (2 ** power)*scG1 + - scG2 + - sG1*6 + sG2*3) - throw new Error("Size of the contribution is invalid"); - - let lastChallengeHash; - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, importPoints ? 7: 2); - await writePTauHeader(fdNew, curve, power); - - const contributionPreviousHash = await fdResponse.read(64); - - if (hashIsEqual(noHash,lastChallengeHash)) { - lastChallengeHash = contributionPreviousHash; - contributions[contributions.length-1].nextChallenge = lastChallengeHash; - } - - if(!hashIsEqual(contributionPreviousHash,lastChallengeHash)) - throw new Error("Wrong contribution. This contribution is not based on the previous hash"); - - const hasherResponse = blake2_js.blake2b.create({ dkLen: 64 }); - hasherResponse.update(contributionPreviousHash); - - const startSections = []; - let res; - res = await processSection(fdResponse, fdNew, "G1", 2, (2 ** power) * 2 -1, [1], "tauG1"); - currentContribution.tauG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G2", 3, (2 ** power) , [1], "tauG2"); - currentContribution.tauG2 = res[0]; - res = await processSection(fdResponse, fdNew, "G1", 4, (2 ** power) , [0], "alphaG1"); - currentContribution.alphaG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G1", 5, (2 ** power) , [0], "betaG1"); - currentContribution.betaG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G2", 6, 1 , [0], "betaG2"); - currentContribution.betaG2 = res[0]; - - currentContribution.partialHash = toPartialHash(hasherResponse); - - - const buffKey = await fdResponse.read(curve.F1.n8*2*6+curve.F2.n8*2*3); - - currentContribution.key = fromPtauPubKeyRpr(buffKey, 0, curve, false); - - hasherResponse.update(new Uint8Array(buffKey)); - const hashResponse = hasherResponse.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - if (importPoints) { - const nextChallengeHasher = blake2_js.blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(nextChallengeHasher, fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G2", 3, (2 ** power) , "tauG2", logger); - await hashSection(nextChallengeHasher, fdNew, "G1", 4, (2 ** power) , "alphaTauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G1", 5, (2 ** power) , "betaTauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G2", 6, 1 , "betaG2", logger); - - currentContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(currentContribution.nextChallenge, "Next Challenge Hash: ")); - } else { - currentContribution.nextChallenge = noHash; - } - - contributions.push(currentContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdResponse.close(); - await fdNew.close(); - await fdOld.close(); - - return currentContribution.nextChallenge; - - async function processSection(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - if (importPoints) { - return await processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); - } else { - return await processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); - } - } - - async function processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - - const G = curve[groupName]; - const scG = G.F.n8; - const sG = G.F.n8*2; - - const singularPoints = []; - - await binFileUtils__namespace.startWriteSection(fdTo, sectionId); - const nPointsChunk = Math.floor((1<<24)/sG); - - startSections[sectionId] = fdTo.pos; - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffC = await fdFrom.read(n * scG); - hasherResponse.update(buffC); - - const buffLEM = await G.batchCtoLEM(buffC); - - await fdTo.write(buffLEM); - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprLEM(buffLEM, (sp-i)*sG); - singularPoints.push(P); - } - } - } - - await binFileUtils__namespace.endWriteSection(fdTo); - - return singularPoints; - } - - - async function processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - - const G = curve[groupName]; - const scG = G.F.n8; - - const singularPoints = []; - - const nPointsChunk = Math.floor((1<<24)/scG); - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffC = await fdFrom.read(n * scG); - hasherResponse.update(buffC); - - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprCompressed(buffC, (sp-i)*scG); - singularPoints.push(P); - } - } - } - - return singularPoints; - } - - - async function hashSection(nextChallengeHasher, fdTo, groupName, sectionId, nPoints, sectionName, logger) { - - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPointsChunk = Math.floor((1<<24)/sG); - - const oldPos = fdTo.pos; - fdTo.pos = startSections[sectionId]; - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Hashing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffLEM = await fdTo.read(n * sG); - - const buffU = await G.batchLEMtoU(buffLEM); - - nextChallengeHasher.update(buffU); - } - - fdTo.pos = oldPos; - } - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const sameRatio$1 = sameRatio$2; - + const noHash = /* @__PURE__ */ new Uint8Array(64); + for (let i = 0; i < 64; i++) noHash[i] = 255; + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fdOld, sections); + const contributions = await readContributions(fdOld, curve, sections); + const currentContribution = {}; + if (name) currentContribution.name = name; + const sG1 = curve.F1.n8 * 2; + const scG1 = curve.F1.n8; + const sG2 = curve.F2.n8 * 2; + const scG2 = curve.F2.n8; + const fdResponse = await fastfile.readExisting(contributionFilename); + if (fdResponse.totalSize != 64 + (2 ** power * 2 - 1) * scG1 + 2 ** power * scG2 + 2 ** power * scG1 + 2 ** power * scG1 + scG2 + sG1 * 6 + sG2 * 3) throw new Error("Size of the contribution is invalid"); + let lastChallengeHash; + if (contributions.length > 0) lastChallengeHash = contributions[contributions.length - 1].nextChallenge; + else lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, importPoints ? 7 : 2); + await writePTauHeader(fdNew, curve, power); + const contributionPreviousHash = await fdResponse.read(64); + if (hashIsEqual(noHash, lastChallengeHash)) { + lastChallengeHash = contributionPreviousHash; + contributions[contributions.length - 1].nextChallenge = lastChallengeHash; + } + if (!hashIsEqual(contributionPreviousHash, lastChallengeHash)) throw new Error("Wrong contribution. This contribution is not based on the previous hash"); + const hasherResponse = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hasherResponse.update(contributionPreviousHash); + const startSections = []; + let res; + res = await processSection(fdResponse, fdNew, "G1", 2, 2 ** power * 2 - 1, [1], "tauG1"); + currentContribution.tauG1 = res[0]; + res = await processSection(fdResponse, fdNew, "G2", 3, 2 ** power, [1], "tauG2"); + currentContribution.tauG2 = res[0]; + res = await processSection(fdResponse, fdNew, "G1", 4, 2 ** power, [0], "alphaG1"); + currentContribution.alphaG1 = res[0]; + res = await processSection(fdResponse, fdNew, "G1", 5, 2 ** power, [0], "betaG1"); + currentContribution.betaG1 = res[0]; + res = await processSection(fdResponse, fdNew, "G2", 6, 1, [0], "betaG2"); + currentContribution.betaG2 = res[0]; + currentContribution.partialHash = toPartialHash(hasherResponse); + const buffKey = await fdResponse.read(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + currentContribution.key = fromPtauPubKeyRpr(buffKey, 0, curve, false); + hasherResponse.update(new Uint8Array(buffKey)); + const hashResponse = hasherResponse.digest(); + if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); + if (importPoints) { + const nextChallengeHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + nextChallengeHasher.update(hashResponse); + await hashSection(nextChallengeHasher, fdNew, "G1", 2, 2 ** power * 2 - 1, "tauG1", logger); + await hashSection(nextChallengeHasher, fdNew, "G2", 3, 2 ** power, "tauG2", logger); + await hashSection(nextChallengeHasher, fdNew, "G1", 4, 2 ** power, "alphaTauG1", logger); + await hashSection(nextChallengeHasher, fdNew, "G1", 5, 2 ** power, "betaTauG1", logger); + await hashSection(nextChallengeHasher, fdNew, "G2", 6, 1, "betaG2", logger); + currentContribution.nextChallenge = nextChallengeHasher.digest(); + if (logger) logger.info(formatHash(currentContribution.nextChallenge, "Next Challenge Hash: ")); + } else currentContribution.nextChallenge = noHash; + contributions.push(currentContribution); + await writeContributions(fdNew, curve, contributions); + await fdResponse.close(); + await fdNew.close(); + await fdOld.close(); + return currentContribution.nextChallenge; + async function processSection(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { + if (importPoints) return await processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); + else return await processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); + } + async function processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { + const G = curve[groupName]; + const scG = G.F.n8; + const sG = G.F.n8 * 2; + const singularPoints = []; + await _iden3_binfileutils.startWriteSection(fdTo, sectionId); + const nPointsChunk = Math.floor((1 << 24) / sG); + startSections[sectionId] = fdTo.pos; + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + const buffC = await fdFrom.read(n * scG); + hasherResponse.update(buffC); + const buffLEM = await G.batchCtoLEM(buffC); + await fdTo.write(buffLEM); + for (let j = 0; j < singularPointIndexes.length; j++) { + const sp = singularPointIndexes[j]; + if (sp >= i && sp < i + n) { + const P = G.fromRprLEM(buffLEM, (sp - i) * sG); + singularPoints.push(P); + } + } + } + await _iden3_binfileutils.endWriteSection(fdTo); + return singularPoints; + } + async function processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { + const G = curve[groupName]; + const scG = G.F.n8; + const singularPoints = []; + const nPointsChunk = Math.floor((1 << 24) / scG); + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + const buffC = await fdFrom.read(n * scG); + hasherResponse.update(buffC); + for (let j = 0; j < singularPointIndexes.length; j++) { + const sp = singularPointIndexes[j]; + if (sp >= i && sp < i + n) { + const P = G.fromRprCompressed(buffC, (sp - i) * scG); + singularPoints.push(P); + } + } + } + return singularPoints; + } + async function hashSection(nextChallengeHasher, fdTo, groupName, sectionId, nPoints, sectionName, logger) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const nPointsChunk = Math.floor((1 << 24) / sG); + const oldPos = fdTo.pos; + fdTo.pos = startSections[sectionId]; + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Hashing ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + const buffLEM = await fdTo.read(n * sG); + const buffU = await G.batchLEMtoU(buffLEM); + nextChallengeHasher.update(buffU); + } + fdTo.pos = oldPos; + } +} +//#endregion +//#region src/powersoftau_verify.js +var sameRatio$1 = sameRatio$2; async function verifyContribution(curve, cur, prev, logger) { - let sr; - if (cur.type == 1) { // Verify the beacon. - const beaconKey = await keyFromBeacon(curve, prev.nextChallenge, cur.beaconHash, cur.numIterationsExp); - - if (!curve.G1.eq(cur.key.tau.g1_s, beaconKey.tau.g1_s)) { - if (logger) logger.error(`BEACON key (tauG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.tau.g1_sx, beaconKey.tau.g1_sx)) { - if (logger) logger.error(`BEACON key (tauG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.tau.g2_spx, beaconKey.tau.g2_spx)) { - if (logger) logger.error(`BEACON key (tauG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - - if (!curve.G1.eq(cur.key.alpha.g1_s, beaconKey.alpha.g1_s)) { - if (logger) logger.error(`BEACON key (alphaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.alpha.g1_sx, beaconKey.alpha.g1_sx)) { - if (logger) logger.error(`BEACON key (alphaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.alpha.g2_spx, beaconKey.alpha.g2_spx)) { - if (logger) logger.error(`BEACON key (alphaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - - if (!curve.G1.eq(cur.key.beta.g1_s, beaconKey.beta.g1_s)) { - if (logger) logger.error(`BEACON key (betaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.beta.g1_sx, beaconKey.beta.g1_sx)) { - if (logger) logger.error(`BEACON key (betaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.beta.g2_spx, beaconKey.beta.g2_spx)) { - if (logger) logger.error(`BEACON key (betaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - } - - cur.key.tau.g2_sp = curve.G2.toAffine(getG2sp(curve, 0, prev.nextChallenge, cur.key.tau.g1_s, cur.key.tau.g1_sx)); - cur.key.alpha.g2_sp = curve.G2.toAffine(getG2sp(curve, 1, prev.nextChallenge, cur.key.alpha.g1_s, cur.key.alpha.g1_sx)); - cur.key.beta.g2_sp = curve.G2.toAffine(getG2sp(curve, 2, prev.nextChallenge, cur.key.beta.g1_s, cur.key.beta.g1_sx)); - - sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, cur.key.tau.g2_sp, cur.key.tau.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (tau) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, cur.key.alpha.g1_s, cur.key.alpha.g1_sx, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (alpha) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, cur.key.beta.g2_sp, cur.key.beta.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (beta) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, prev.tauG1, cur.tauG1, cur.key.tau.g2_sp, cur.key.tau.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID tau*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, prev.tauG2, cur.tauG2); - if (sr !== true) { - if (logger) logger.error("INVALID tau*G2. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, prev.alphaG1, cur.alphaG1, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID alpha*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, prev.betaG1, cur.betaG1, cur.key.beta.g2_sp, cur.key.beta.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID beta*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, prev.betaG2, cur.betaG2); - if (sr !== true) { - if (logger) logger.error("INVALID beta*G2. challenge #"+cur.id+"It does not follow the previous contribution"); - return false; - } - - if (logger) logger.info("Powers Of tau file OK!"); - return true; -} - + let sr; + if (cur.type == 1) { + const beaconKey = await keyFromBeacon(curve, prev.nextChallenge, cur.beaconHash, cur.numIterationsExp); + if (!curve.G1.eq(cur.key.tau.g1_s, beaconKey.tau.g1_s)) { + if (logger) logger.error(`BEACON key (tauG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.tau.g1_sx, beaconKey.tau.g1_sx)) { + if (logger) logger.error(`BEACON key (tauG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G2.eq(cur.key.tau.g2_spx, beaconKey.tau.g2_spx)) { + if (logger) logger.error(`BEACON key (tauG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.alpha.g1_s, beaconKey.alpha.g1_s)) { + if (logger) logger.error(`BEACON key (alphaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.alpha.g1_sx, beaconKey.alpha.g1_sx)) { + if (logger) logger.error(`BEACON key (alphaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G2.eq(cur.key.alpha.g2_spx, beaconKey.alpha.g2_spx)) { + if (logger) logger.error(`BEACON key (alphaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.beta.g1_s, beaconKey.beta.g1_s)) { + if (logger) logger.error(`BEACON key (betaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.beta.g1_sx, beaconKey.beta.g1_sx)) { + if (logger) logger.error(`BEACON key (betaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G2.eq(cur.key.beta.g2_spx, beaconKey.beta.g2_spx)) { + if (logger) logger.error(`BEACON key (betaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + } + cur.key.tau.g2_sp = curve.G2.toAffine(getG2sp(curve, 0, prev.nextChallenge, cur.key.tau.g1_s, cur.key.tau.g1_sx)); + cur.key.alpha.g2_sp = curve.G2.toAffine(getG2sp(curve, 1, prev.nextChallenge, cur.key.alpha.g1_s, cur.key.alpha.g1_sx)); + cur.key.beta.g2_sp = curve.G2.toAffine(getG2sp(curve, 2, prev.nextChallenge, cur.key.beta.g1_s, cur.key.beta.g1_sx)); + sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, cur.key.tau.g2_sp, cur.key.tau.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID key (tau) in challenge #" + cur.id); + return false; + } + sr = await sameRatio$1(curve, cur.key.alpha.g1_s, cur.key.alpha.g1_sx, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID key (alpha) in challenge #" + cur.id); + return false; + } + sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, cur.key.beta.g2_sp, cur.key.beta.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID key (beta) in challenge #" + cur.id); + return false; + } + sr = await sameRatio$1(curve, prev.tauG1, cur.tauG1, cur.key.tau.g2_sp, cur.key.tau.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID tau*G1. challenge #" + cur.id + " It does not follow the previous contribution"); + return false; + } + sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, prev.tauG2, cur.tauG2); + if (sr !== true) { + if (logger) logger.error("INVALID tau*G2. challenge #" + cur.id + " It does not follow the previous contribution"); + return false; + } + sr = await sameRatio$1(curve, prev.alphaG1, cur.alphaG1, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID alpha*G1. challenge #" + cur.id + " It does not follow the previous contribution"); + return false; + } + sr = await sameRatio$1(curve, prev.betaG1, cur.betaG1, cur.key.beta.g2_sp, cur.key.beta.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID beta*G1. challenge #" + cur.id + " It does not follow the previous contribution"); + return false; + } + sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, prev.betaG2, cur.betaG2); + if (sr !== true) { + if (logger) logger.error("INVALID beta*G2. challenge #" + cur.id + "It does not follow the previous contribution"); + return false; + } + if (logger) logger.info("Powers Of tau file OK!"); + return true; +} async function verify(tauFilename, logger) { - let sr; - - const {fd, sections} = await binFileUtils__namespace.readBinFile(tauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fd, sections); - const contrs = await readContributions(fd, curve, sections); - - if (logger) logger.debug("power: 2**" + power); - // Verify Last contribution - - if (logger) logger.debug("Computing initial contribution hash"); - const initialContribution = { - tauG1: curve.G1.g, - tauG2: curve.G2.g, - alphaG1: curve.G1.g, - betaG1: curve.G1.g, - betaG2: curve.G2.g, - nextChallenge: calculateFirstChallengeHash(curve, ceremonyPower, logger), - responseHash: blake2_js.blake2b.create({ dkLen: 64 }).digest() - }; - - if (contrs.length == 0) { - if (logger) logger.error("This file has no contribution! It cannot be used in production"); - return false; - } - - let prevContr; - if (contrs.length>1) { - prevContr = contrs[contrs.length-2]; - } else { - prevContr = initialContribution; - } - const curContr = contrs[contrs.length-1]; - if (logger) logger.debug("Validating contribution #"+contrs[contrs.length-1].id); - const res = await verifyContribution(curve, curContr, prevContr, logger); - if (!res) return false; - - - const nextContributionHasher = blake2_js.blake2b.create({ dkLen: 64 }); - nextContributionHasher.update(curContr.responseHash); - - // Verify powers and compute nextChallengeHash - - // await test(); - - // Verify Section tau*G1 - if (logger) logger.debug("Verifying powers in tau*G1 section"); - const rTau1 = await processSection(2, "G1", "tauG1", (2 ** power)*2-1, [0, 1], logger); - sr = await sameRatio$1(curve, rTau1.R1, rTau1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("tauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curve.G1.g, rTau1.singularPoints[0])) { - if (logger) logger.error("First element of tau*G1 section must be the generator"); - return false; - } - if (!curve.G1.eq(curContr.tauG1, rTau1.singularPoints[1])) { - if (logger) logger.error("Second element of tau*G1 section does not match the one in the contribution section"); - return false; - } - - // await test(); - - // Verify Section tau*G2 - if (logger) logger.debug("Verifying powers in tau*G2 section"); - const rTau2 = await processSection(3, "G2", "tauG2", 2 ** power, [0, 1], logger); - sr = await sameRatio$1(curve, curve.G1.g, curContr.tauG1, rTau2.R1, rTau2.R2); - if (sr !== true) { - if (logger) logger.error("tauG2 section. Powers do not match"); - return false; - } - if (!curve.G2.eq(curve.G2.g, rTau2.singularPoints[0])) { - if (logger) logger.error("First element of tau*G2 section must be the generator"); - return false; - } - if (!curve.G2.eq(curContr.tauG2, rTau2.singularPoints[1])) { - if (logger) logger.error("Second element of tau*G2 section does not match the one in the contribution section"); - return false; - } - - // Verify Section alpha*tau*G1 - if (logger) logger.debug("Verifying powers in alpha*tau*G1 section"); - const rAlphaTauG1 = await processSection(4, "G1", "alphatauG1", 2 ** power, [0], logger); - sr = await sameRatio$1(curve, rAlphaTauG1.R1, rAlphaTauG1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("alphaTauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curContr.alphaG1, rAlphaTauG1.singularPoints[0])) { - if (logger) logger.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"); - return false; - } - - // Verify Section beta*tau*G1 - if (logger) logger.debug("Verifying powers in beta*tau*G1 section"); - const rBetaTauG1 = await processSection(5, "G1", "betatauG1", 2 ** power, [0], logger); - sr = await sameRatio$1(curve, rBetaTauG1.R1, rBetaTauG1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("betaTauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curContr.betaG1, rBetaTauG1.singularPoints[0])) { - if (logger) logger.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"); - return false; - } - - //Verify Beta G2 - const betaG2 = await processSectionBetaG2(logger); - if (!curve.G2.eq(curContr.betaG2, betaG2)) { - if (logger) logger.error("betaG2 element in betaG2 section does not match the one in the contribution section"); - return false; - } - - - const nextContributionHash = nextContributionHasher.digest(); - - // Check the nextChallengeHash - if (power == ceremonyPower) { - if (!hashIsEqual(nextContributionHash,curContr.nextChallenge)) { - if (logger) logger.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"); - return false; - } - } - - if (logger) logger.info(formatHash(nextContributionHash, "Next challenge hash: ")); - - // Verify Previous contributions - - printContribution(curContr, prevContr); - for (let i = contrs.length-2; i>=0; i--) { - const curContr = contrs[i]; - const prevContr = (i>0) ? contrs[i-1] : initialContribution; - const res = await verifyContribution(curve, curContr, prevContr, logger); - if (!res) return false; - printContribution(curContr, prevContr); - } - if (logger) logger.info("-----------------------------------------------------"); - - if ((!sections[12]) || (!sections[13]) || (!sections[14]) || (!sections[15])) { - if (logger) logger.warn( - "this file does not contain phase2 precalculated values. Please run: \n" + - " snarkjs \"powersoftau preparephase2\" to prepare this file to be used in the phase2 ceremony." - ); - } else { - let res; - res = await verifyLagrangeEvaluations("G1", 2, 12, "tauG1", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G2", 3, 13, "tauG2", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G1", 4, 14, "alphaTauG1", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G1", 5, 15, "betaTauG1", logger); - if (!res) return false; - } - - await fd.close(); - - if (logger) logger.info("Powers of Tau Ok!"); - - return true; - - function printContribution(curContr, prevContr) { - if (!logger) return; - logger.info("-----------------------------------------------------"); - logger.info(`Contribution #${curContr.id}: ${curContr.name ||""}`); - - logger.info(formatHash(curContr.nextChallenge, "Next Challenge: ")); - - const buffV = new Uint8Array(curve.G1.F.n8*2*6+curve.G2.F.n8*2*3); - toPtauPubKeyRpr(buffV, 0, curve, curContr.key, false); - - const responseHasher = fromPartialHash(curContr.partialHash); - responseHasher.update(buffV); - const responseHash = responseHasher.digest(); - - logger.info(formatHash(responseHash, "Response Hash:")); - - logger.info(formatHash(prevContr.nextChallenge, "Response Hash:")); - - if (curContr.type == 1) { - logger.info(`Beacon generator: ${byteArray2hex(curContr.beaconHash)}`); - logger.info(`Beacon iterations Exp: ${curContr.numIterationsExp}`); - } - - } - - async function processSectionBetaG2(logger) { - const G = curve.G2; - const sG = G.F.n8*2; - const buffUv = new Uint8Array(sG); - - if (!sections[6]) { - logger.error("File has no BetaG2 section"); - throw new Error("File has no BetaG2 section"); - } - if (sections[6].length>1) { - logger.error("File has no BetaG2 section"); - throw new Error("File has more than one GetaG2 section"); - } - fd.pos = sections[6][0].p; - - const buff = await fd.read(sG); - const P = G.fromRprLEM(buff); - - G.toRprUncompressed(buffUv, 0, P); - nextContributionHasher.update(buffUv); - - return P; - } - - async function processSection(idSection, groupName, sectionName, nPoints, singularPointIndexes, logger) { - const MAX_CHUNK_SIZE = 1<<16; - const G = curve[groupName]; - const sG = G.F.n8*2; - await binFileUtils__namespace.startReadUniqueSection(fd, sections, idSection); - - const singularPoints = []; - - let R1 = G.zero; - let R2 = G.zero; - - let lastBase = G.zero; - - for (let i=0; i0) { - const firstBase = G.fromRprLEM(bases, 0); - const r = readUInt32BE(getRandomBytes(4), 0); - - R1 = G.add(R1, G.timesScalar(lastBase, r)); - R2 = G.add(R2, G.timesScalar(firstBase, r)); - } - - const r1 = await G.multiExpAffine(bases.slice(0, (n-1)*sG), scalars); - const r2 = await G.multiExpAffine(bases.slice(sG), scalars); - - R1 = G.add(R1, r1); - R2 = G.add(R2, r2); - - lastBase = G.fromRprLEM( bases, (n-1)*sG); - - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprLEM(bases, (sp-i)*sG); - singularPoints.push(P); - } - } - - } - await binFileUtils__namespace.endReadSection(fd); - - return { - R1: R1, - R2: R2, - singularPoints: singularPoints - }; - - } - - async function verifyLagrangeEvaluations(gName, tauSection, lagrangeSection, sectionName, logger) { - - if (logger) logger.debug(`Verifying phase2 calculated values ${sectionName}...`); - const G = curve[gName]; - const sG = G.F.n8*2; - - const seed= new Array(8); - for (let i=0; i<8; i++) { - seed[i] = readUInt32BE(getRandomBytes(4), 0); - } - - for (let p=0; p<= power; p ++) { - const res = await verifyPower(p); - if (!res) return false; - } - - if (tauSection == 2) { - const res = await verifyPower(power+1); - if (!res) return false; - } - - return true; - - async function verifyPower(p) { - if (logger) logger.debug(`Power ${p}...`); - const n8r = curve.Fr.n8; - const nPoints = 2 ** p; - let buff_r = new Uint32Array(nPoints); - let buffG; - - let rng = new ffjavascript.ChaCha(seed); - - if (logger) logger.debug(`Creating random numbers Powers${p}...`); - for (let i=0; i. -*/ - - -/* - This function creates a new section in the fdTo file with id idSection. - It multiplies the points in fdFrom by first, first*inc, first*inc^2, .... - nPoint Times. - It also updates the newChallengeHasher with the new points -*/ - + let sr; + const { fd, sections } = await _iden3_binfileutils.readBinFile(tauFilename, "ptau", 1); + const { curve, power, ceremonyPower } = await readPTauHeader(fd, sections); + const contrs = await readContributions(fd, curve, sections); + if (logger) logger.debug("power: 2**" + power); + if (logger) logger.debug("Computing initial contribution hash"); + const initialContribution = { + tauG1: curve.G1.g, + tauG2: curve.G2.g, + alphaG1: curve.G1.g, + betaG1: curve.G1.g, + betaG2: curve.G2.g, + nextChallenge: calculateFirstChallengeHash(curve, ceremonyPower, logger), + responseHash: _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }).digest() + }; + if (contrs.length == 0) { + if (logger) logger.error("This file has no contribution! It cannot be used in production"); + return false; + } + let prevContr; + if (contrs.length > 1) prevContr = contrs[contrs.length - 2]; + else prevContr = initialContribution; + const curContr = contrs[contrs.length - 1]; + if (logger) logger.debug("Validating contribution #" + contrs[contrs.length - 1].id); + if (!await verifyContribution(curve, curContr, prevContr, logger)) return false; + const nextContributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + nextContributionHasher.update(curContr.responseHash); + if (logger) logger.debug("Verifying powers in tau*G1 section"); + const rTau1 = await processSection(2, "G1", "tauG1", 2 ** power * 2 - 1, [0, 1], logger); + sr = await sameRatio$1(curve, rTau1.R1, rTau1.R2, curve.G2.g, curContr.tauG2); + if (sr !== true) { + if (logger) logger.error("tauG1 section. Powers do not match"); + return false; + } + if (!curve.G1.eq(curve.G1.g, rTau1.singularPoints[0])) { + if (logger) logger.error("First element of tau*G1 section must be the generator"); + return false; + } + if (!curve.G1.eq(curContr.tauG1, rTau1.singularPoints[1])) { + if (logger) logger.error("Second element of tau*G1 section does not match the one in the contribution section"); + return false; + } + if (logger) logger.debug("Verifying powers in tau*G2 section"); + const rTau2 = await processSection(3, "G2", "tauG2", 2 ** power, [0, 1], logger); + sr = await sameRatio$1(curve, curve.G1.g, curContr.tauG1, rTau2.R1, rTau2.R2); + if (sr !== true) { + if (logger) logger.error("tauG2 section. Powers do not match"); + return false; + } + if (!curve.G2.eq(curve.G2.g, rTau2.singularPoints[0])) { + if (logger) logger.error("First element of tau*G2 section must be the generator"); + return false; + } + if (!curve.G2.eq(curContr.tauG2, rTau2.singularPoints[1])) { + if (logger) logger.error("Second element of tau*G2 section does not match the one in the contribution section"); + return false; + } + if (logger) logger.debug("Verifying powers in alpha*tau*G1 section"); + const rAlphaTauG1 = await processSection(4, "G1", "alphatauG1", 2 ** power, [0], logger); + sr = await sameRatio$1(curve, rAlphaTauG1.R1, rAlphaTauG1.R2, curve.G2.g, curContr.tauG2); + if (sr !== true) { + if (logger) logger.error("alphaTauG1 section. Powers do not match"); + return false; + } + if (!curve.G1.eq(curContr.alphaG1, rAlphaTauG1.singularPoints[0])) { + if (logger) logger.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"); + return false; + } + if (logger) logger.debug("Verifying powers in beta*tau*G1 section"); + const rBetaTauG1 = await processSection(5, "G1", "betatauG1", 2 ** power, [0], logger); + sr = await sameRatio$1(curve, rBetaTauG1.R1, rBetaTauG1.R2, curve.G2.g, curContr.tauG2); + if (sr !== true) { + if (logger) logger.error("betaTauG1 section. Powers do not match"); + return false; + } + if (!curve.G1.eq(curContr.betaG1, rBetaTauG1.singularPoints[0])) { + if (logger) logger.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"); + return false; + } + const betaG2 = await processSectionBetaG2(logger); + if (!curve.G2.eq(curContr.betaG2, betaG2)) { + if (logger) logger.error("betaG2 element in betaG2 section does not match the one in the contribution section"); + return false; + } + const nextContributionHash = nextContributionHasher.digest(); + if (power == ceremonyPower) { + if (!hashIsEqual(nextContributionHash, curContr.nextChallenge)) { + if (logger) logger.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"); + return false; + } + } + if (logger) logger.info(formatHash(nextContributionHash, "Next challenge hash: ")); + printContribution(curContr, prevContr); + for (let i = contrs.length - 2; i >= 0; i--) { + const curContr = contrs[i]; + const prevContr = i > 0 ? contrs[i - 1] : initialContribution; + if (!await verifyContribution(curve, curContr, prevContr, logger)) return false; + printContribution(curContr, prevContr, logger); + } + if (logger) logger.info("-----------------------------------------------------"); + if (!sections[12] || !sections[13] || !sections[14] || !sections[15]) { + if (logger) logger.warn("this file does not contain phase2 precalculated values. Please run: \n snarkjs \"powersoftau preparephase2\" to prepare this file to be used in the phase2 ceremony."); + } else { + let res; + res = await verifyLagrangeEvaluations("G1", 2, 12, "tauG1", logger); + if (!res) return false; + res = await verifyLagrangeEvaluations("G2", 3, 13, "tauG2", logger); + if (!res) return false; + res = await verifyLagrangeEvaluations("G1", 4, 14, "alphaTauG1", logger); + if (!res) return false; + res = await verifyLagrangeEvaluations("G1", 5, 15, "betaTauG1", logger); + if (!res) return false; + } + await fd.close(); + if (logger) logger.info("Powers of Tau Ok!"); + return true; + function printContribution(curContr, prevContr) { + if (!logger) return; + logger.info("-----------------------------------------------------"); + logger.info(`Contribution #${curContr.id}: ${curContr.name || ""}`); + logger.info(formatHash(curContr.nextChallenge, "Next Challenge: ")); + const buffV = new Uint8Array(curve.G1.F.n8 * 2 * 6 + curve.G2.F.n8 * 2 * 3); + toPtauPubKeyRpr(buffV, 0, curve, curContr.key, false); + const responseHasher = fromPartialHash(curContr.partialHash); + responseHasher.update(buffV); + const responseHash = responseHasher.digest(); + logger.info(formatHash(responseHash, "Response Hash:")); + logger.info(formatHash(prevContr.nextChallenge, "Response Hash:")); + if (curContr.type == 1) { + logger.info(`Beacon generator: ${byteArray2hex(curContr.beaconHash)}`); + logger.info(`Beacon iterations Exp: ${curContr.numIterationsExp}`); + } + } + async function processSectionBetaG2(logger) { + const G = curve.G2; + const sG = G.F.n8 * 2; + const buffUv = new Uint8Array(sG); + if (!sections[6]) { + logger.error("File has no BetaG2 section"); + throw new Error("File has no BetaG2 section"); + } + if (sections[6].length > 1) { + logger.error("File has no BetaG2 section"); + throw new Error("File has more than one GetaG2 section"); + } + fd.pos = sections[6][0].p; + const buff = await fd.read(sG); + const P = G.fromRprLEM(buff); + G.toRprUncompressed(buffUv, 0, P); + nextContributionHasher.update(buffUv); + return P; + } + async function processSection(idSection, groupName, sectionName, nPoints, singularPointIndexes, logger) { + const MAX_CHUNK_SIZE = 65536; + const G = curve[groupName]; + const sG = G.F.n8 * 2; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, idSection); + const singularPoints = []; + let R1 = G.zero; + let R2 = G.zero; + let lastBase = G.zero; + for (let i = 0; i < nPoints; i += MAX_CHUNK_SIZE) { + if (logger) logger.debug(`points relations: ${sectionName}: ${i}/${nPoints} `); + const n = Math.min(nPoints - i, MAX_CHUNK_SIZE); + const bases = await fd.read(n * sG); + const basesU = await G.batchLEMtoU(bases); + nextContributionHasher.update(basesU); + const scalars = getRandomBytes(4 * (n - 1)); + if (i > 0) { + const firstBase = G.fromRprLEM(bases, 0); + const r = readUInt32BE(getRandomBytes(4), 0); + R1 = G.add(R1, G.timesScalar(lastBase, r)); + R2 = G.add(R2, G.timesScalar(firstBase, r)); + } + const r1 = await G.multiExpAffine(bases.slice(0, (n - 1) * sG), scalars); + const r2 = await G.multiExpAffine(bases.slice(sG), scalars); + R1 = G.add(R1, r1); + R2 = G.add(R2, r2); + lastBase = G.fromRprLEM(bases, (n - 1) * sG); + for (let j = 0; j < singularPointIndexes.length; j++) { + const sp = singularPointIndexes[j]; + if (sp >= i && sp < i + n) { + const P = G.fromRprLEM(bases, (sp - i) * sG); + singularPoints.push(P); + } + } + } + await _iden3_binfileutils.endReadSection(fd); + return { + R1, + R2, + singularPoints + }; + } + async function verifyLagrangeEvaluations(gName, tauSection, lagrangeSection, sectionName, logger) { + if (logger) logger.debug(`Verifying phase2 calculated values ${sectionName}...`); + const G = curve[gName]; + const sG = G.F.n8 * 2; + const seed = new Array(8); + for (let i = 0; i < 8; i++) seed[i] = readUInt32BE(getRandomBytes(4), 0); + for (let p = 0; p <= power; p++) if (!await verifyPower(p)) return false; + if (tauSection == 2) { + if (!await verifyPower(power + 1)) return false; + } + return true; + async function verifyPower(p) { + if (logger) logger.debug(`Power ${p}...`); + const n8r = curve.Fr.n8; + const nPoints = 2 ** p; + let buff_r = new Uint32Array(nPoints); + let buffG; + let rng = new ffjavascript.ChaCha(seed); + if (logger) logger.debug(`Creating random numbers Powers${p}...`); + for (let i = 0; i < nPoints; i++) if (p == power + 1 && i == nPoints - 1) buff_r[i] = 0; + else buff_r[i] = rng.nextU32(); + buff_r = new Uint8Array(buff_r.buffer, buff_r.byteOffset, buff_r.byteLength); + if (logger) logger.debug(`reading points Powers${p}...`); + await _iden3_binfileutils.startReadUniqueSection(fd, sections, tauSection); + buffG = new ffjavascript.BigBuffer(nPoints * sG); + if (p == power + 1) { + await fd.readToBuffer(buffG, 0, (nPoints - 1) * sG); + buffG.set(curve.G1.zeroAffine, (nPoints - 1) * sG); + } else await fd.readToBuffer(buffG, 0, nPoints * sG); + await _iden3_binfileutils.endReadSection(fd, true); + const resTau = await G.multiExpAffine(buffG, buff_r, logger, sectionName + "_" + p); + buff_r = new ffjavascript.BigBuffer(nPoints * n8r); + rng = new ffjavascript.ChaCha(seed); + const buff4 = /* @__PURE__ */ new Uint8Array(4); + const buff4V = new DataView(buff4.buffer); + if (logger) logger.debug(`Creating random numbers Powers${p}...`); + for (let i = 0; i < nPoints; i++) if (i != nPoints - 1 || p != power + 1) { + buff4V.setUint32(0, rng.nextU32(), true); + buff_r.set(buff4, i * n8r); + } + if (logger) logger.debug(`batchToMontgomery ${p}...`); + buff_r = await curve.Fr.batchToMontgomery(buff_r); + if (logger) logger.debug(`fft ${p}...`); + buff_r = await curve.Fr.fft(buff_r); + if (logger) logger.debug(`batchFromMontgomery ${p}...`); + buff_r = await curve.Fr.batchFromMontgomery(buff_r); + if (logger) logger.debug(`reading points Lagrange${p}...`); + await _iden3_binfileutils.startReadUniqueSection(fd, sections, lagrangeSection); + fd.pos += sG * (2 ** p - 1); + await fd.readToBuffer(buffG, 0, nPoints * sG); + await _iden3_binfileutils.endReadSection(fd, true); + const resLagrange = await G.multiExpAffine(buffG, buff_r, logger, sectionName + "_" + p + "_transformed"); + if (!G.eq(resTau, resLagrange)) { + if (logger) logger.error("Phase2 caclutation does not match with powers of tau"); + return false; + } + return true; + } + } +} +//#endregion +//#region src/mpc_applykey.js async function applyKeyToSection(fdOld, sections, fdNew, idSection, curve, groupName, first, inc, sectionName, logger) { - const MAX_CHUNK_SIZE = 1 << 16; - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPoints = sections[idSection][0].size / sG; - - await binFileUtils__namespace.startReadUniqueSection(fdOld, sections,idSection ); - await binFileUtils__namespace.startWriteSection(fdNew, idSection); - - let t = first; - for (let i=0; i. -*/ - - + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const chunkSize = Math.floor((1 << 20) / sG); + let t = first; + for (let i = 0; i < nPoints; i += chunkSize) { + if (logger) logger.debug(`Applying key ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, chunkSize); + const buffInU = await fdOld.read(n * sG); + const buffInLEM = await G.batchUtoLEM(buffInU); + const buffOutLEM = await G.batchApplyKey(buffInLEM, t, inc); + let buffOut; + if (formatOut == "COMPRESSED") buffOut = await G.batchLEMtoC(buffOutLEM); + else buffOut = await G.batchLEMtoU(buffOutLEM); + if (responseHasher) responseHasher.update(buffOut); + await fdNew.write(buffOut); + t = curve.Fr.mul(t, curve.Fr.exp(inc, n)); + } +} +//#endregion +//#region src/powersoftau_challenge_contribute.js async function challengeContribute(curve, challengeFilename, responseFileName, entropy, logger) { - const fdFrom = await fastFile__namespace.readExisting(challengeFilename); - - - const sG1 = curve.F1.n64*8*2; - const sG2 = curve.F2.n64*8*2; - const domainSize = (fdFrom.totalSize + sG1 - 64 - sG2) / (4*sG1 + sG2); - let e = domainSize; - let power = 0; - while (e>1) { - e = e /2; - power += 1; - } - - if (2 ** power != domainSize) throw new Error("Invalid file size"); - if (logger) logger.debug("Power to tau size: "+power); - - const rng = await getRandomRng(entropy); - - const fdTo = await fastFile__namespace.createOverride(responseFileName); - - // Calculate the hash - const challengeHasher = blake2_js.blake2b.create({ dkLen: 64 }); - for (let i=0; i { - logger.debug(k + ".g1_s: " + curve.G1.toString(key[k].g1_s, 16)); - logger.debug(k + ".g1_sx: " + curve.G1.toString(key[k].g1_sx, 16)); - logger.debug(k + ".g2_sp: " + curve.G2.toString(key[k].g2_sp, 16)); - logger.debug(k + ".g2_spx: " + curve.G2.toString(key[k].g2_spx, 16)); - logger.debug(""); - }); - } - - const responseHasher = blake2_js.blake2b.create({ dkLen: 64 }); - - await fdTo.write(challengeHash); - responseHasher.update(challengeHash); - - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power)*2-1, curve.Fr.one , key.tau.prvKey, "COMPRESSED", "tauG1" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", (2 ** power) , curve.Fr.one , key.tau.prvKey, "COMPRESSED", "tauG2" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power) , key.alpha.prvKey, key.tau.prvKey, "COMPRESSED", "alphaTauG1", logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power) , key.beta.prvKey , key.tau.prvKey, "COMPRESSED", "betaTauG1" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", 1 , key.beta.prvKey , key.tau.prvKey, "COMPRESSED", "betaTauG2" , logger ); - - // Write and hash key - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - toPtauPubKeyRpr(buffKey, 0, curve, key, false); - await fdTo.write(buffKey); - responseHasher.update(buffKey); - const responseHash = responseHasher.digest(); - if (logger) logger.info(formatHash(responseHash, "Contribution Response Hash: ")); - - await fdTo.close(); - await fdFrom.close(); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function beacon$1(oldPtauFilename, newPTauFilename, name, beaconHashStr,numIterationsExp, logger) { - const beaconHash = hex2ByteArray(beaconHashStr); - if ( (beaconHash.byteLength == 0) - || (beaconHash.byteLength*2 !=beaconHashStr.length)) - { - if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); - return false; - } - if (beaconHash.length>=256) { - if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); - return false; - } - - numIterationsExp = parseInt(numIterationsExp); - if ((numIterationsExp<10)||(numIterationsExp>63)) { - if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); - return false; - } - - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - if (power != ceremonyPower) { - if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); - return false; - } - if (sections[12]) { - if (logger) logger.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); - } - const contributions = await readContributions(fdOld, curve, sections); - const curContribution = { - name: name, - type: 1, // Beacon - numIterationsExp: numIterationsExp, - beaconHash: beaconHash - }; - - let lastChallengeHash; - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - curContribution.key = await keyFromBeacon(curve, lastChallengeHash, beaconHash, numIterationsExp); - - const responseHasher = blake2_js.blake2b.create({ dkLen: 64 }); - responseHasher.update(lastChallengeHash); - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, 7); - await writePTauHeader(fdNew, curve, power); - - const startSections = []; - - let firstPoints; - firstPoints = await processSection(2, "G1", (2 ** power) * 2 -1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1", logger ); - curContribution.tauG1 = firstPoints[1]; - firstPoints = await processSection(3, "G2", (2 ** power) , curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2", logger ); - curContribution.tauG2 = firstPoints[1]; - firstPoints = await processSection(4, "G1", (2 ** power) , curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1", logger ); - curContribution.alphaG1 = firstPoints[0]; - firstPoints = await processSection(5, "G1", (2 ** power) , curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1", logger ); - curContribution.betaG1 = firstPoints[0]; - firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2", logger ); - curContribution.betaG2 = firstPoints[0]; - - curContribution.partialHash = toPartialHash(responseHasher); - - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - - toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); - - responseHasher.update(new Uint8Array(buffKey)); - const hashResponse = responseHasher.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - const nextChallengeHasher = blake2_js.blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1", logger); - await hashSection(fdNew, "G2", 3, (2 ** power) , "tauG2", logger); - await hashSection(fdNew, "G1", 4, (2 ** power) , "alphaTauG1", logger); - await hashSection(fdNew, "G1", 5, (2 ** power) , "betaTauG1", logger); - await hashSection(fdNew, "G2", 6, 1 , "betaG2", logger); - - curContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); - - contributions.push(curContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdOld.close(); - await fdNew.close(); - - return hashResponse; - - async function processSection(sectionId, groupName, NPoints, first, inc, sectionName, logger) { - const res = []; - fdOld.pos = sections[sectionId][0].p; - - await binFileUtils__namespace.startWriteSection(fdNew, sectionId); - - startSections[sectionId] = fdNew.pos; - - const G = curve[groupName]; - const sG = G.F.n8*2; - const chunkSize = Math.floor((1<<20) / sG); // 128Mb chunks - let t = first; - for (let i=0 ; i. -*/ - - + const fdFrom = await fastfile.readExisting(challengeFilename); + const sG1 = curve.F1.n64 * 8 * 2; + const sG2 = curve.F2.n64 * 8 * 2; + const domainSize = (fdFrom.totalSize + sG1 - 64 - sG2) / (4 * sG1 + sG2); + let e = domainSize; + let power = 0; + while (e > 1) { + e = e / 2; + power += 1; + } + if (2 ** power != domainSize) throw new Error("Invalid file size"); + if (logger) logger.debug("Power to tau size: " + power); + const rng = await getRandomRng(entropy); + const fdTo = await fastfile.createOverride(responseFileName); + const challengeHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + for (let i = 0; i < fdFrom.totalSize; i += fdFrom.pageSize) { + if (logger) logger.debug(`Hashing challenge ${i}/${fdFrom.totalSize}`); + const s = Math.min(fdFrom.totalSize - i, fdFrom.pageSize); + const buff = await fdFrom.read(s); + challengeHasher.update(buff); + } + const claimedHash = await fdFrom.read(64, 0); + if (logger) logger.info(formatHash(claimedHash, "Claimed Previous Response Hash: ")); + const challengeHash = challengeHasher.digest(); + if (logger) logger.info(formatHash(challengeHash, "Current Challenge Hash: ")); + const key = createPTauKey(curve, challengeHash, rng); + if (logger) [ + "tau", + "alpha", + "beta" + ].forEach((k) => { + logger.debug(k + ".g1_s: " + curve.G1.toString(key[k].g1_s, 16)); + logger.debug(k + ".g1_sx: " + curve.G1.toString(key[k].g1_sx, 16)); + logger.debug(k + ".g2_sp: " + curve.G2.toString(key[k].g2_sp, 16)); + logger.debug(k + ".g2_spx: " + curve.G2.toString(key[k].g2_spx, 16)); + logger.debug(""); + }); + const responseHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + await fdTo.write(challengeHash); + responseHasher.update(challengeHash); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", 2 ** power * 2 - 1, curve.Fr.one, key.tau.prvKey, "COMPRESSED", "tauG1", logger); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", 2 ** power, curve.Fr.one, key.tau.prvKey, "COMPRESSED", "tauG2", logger); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", 2 ** power, key.alpha.prvKey, key.tau.prvKey, "COMPRESSED", "alphaTauG1", logger); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", 2 ** power, key.beta.prvKey, key.tau.prvKey, "COMPRESSED", "betaTauG1", logger); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", 1, key.beta.prvKey, key.tau.prvKey, "COMPRESSED", "betaTauG2", logger); + const buffKey = new Uint8Array(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + toPtauPubKeyRpr(buffKey, 0, curve, key, false); + await fdTo.write(buffKey); + responseHasher.update(buffKey); + const responseHash = responseHasher.digest(); + if (logger) logger.info(formatHash(responseHash, "Contribution Response Hash: ")); + await fdTo.close(); + await fdFrom.close(); +} +//#endregion +//#region src/powersoftau_beacon.js +async function beacon$1(oldPtauFilename, newPTauFilename, name, beaconHashStr, numIterationsExp, logger) { + const beaconHash = hex2ByteArray(beaconHashStr); + if (beaconHash.byteLength == 0 || beaconHash.byteLength * 2 != beaconHashStr.length) { + if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); + return false; + } + if (beaconHash.length >= 256) { + if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); + return false; + } + numIterationsExp = parseInt(numIterationsExp); + if (numIterationsExp < 10 || numIterationsExp > 63) { + if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); + return false; + } + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power, ceremonyPower } = await readPTauHeader(fdOld, sections); + if (power != ceremonyPower) { + if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); + return false; + } + if (sections[12]) { + if (logger) logger.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); + } + const contributions = await readContributions(fdOld, curve, sections); + const curContribution = { + name, + type: 1, + numIterationsExp, + beaconHash + }; + let lastChallengeHash; + if (contributions.length > 0) lastChallengeHash = contributions[contributions.length - 1].nextChallenge; + else lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); + curContribution.key = await keyFromBeacon(curve, lastChallengeHash, beaconHash, numIterationsExp); + const responseHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + responseHasher.update(lastChallengeHash); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, 7); + await writePTauHeader(fdNew, curve, power); + const startSections = []; + let firstPoints; + firstPoints = await processSection(2, "G1", 2 ** power * 2 - 1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1", logger); + curContribution.tauG1 = firstPoints[1]; + firstPoints = await processSection(3, "G2", 2 ** power, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2", logger); + curContribution.tauG2 = firstPoints[1]; + firstPoints = await processSection(4, "G1", 2 ** power, curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1", logger); + curContribution.alphaG1 = firstPoints[0]; + firstPoints = await processSection(5, "G1", 2 ** power, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1", logger); + curContribution.betaG1 = firstPoints[0]; + firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2", logger); + curContribution.betaG2 = firstPoints[0]; + curContribution.partialHash = toPartialHash(responseHasher); + const buffKey = new Uint8Array(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); + responseHasher.update(new Uint8Array(buffKey)); + const hashResponse = responseHasher.digest(); + if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); + const nextChallengeHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + nextChallengeHasher.update(hashResponse); + await hashSection(fdNew, "G1", 2, 2 ** power * 2 - 1, "tauG1", logger); + await hashSection(fdNew, "G2", 3, 2 ** power, "tauG2", logger); + await hashSection(fdNew, "G1", 4, 2 ** power, "alphaTauG1", logger); + await hashSection(fdNew, "G1", 5, 2 ** power, "betaTauG1", logger); + await hashSection(fdNew, "G2", 6, 1, "betaG2", logger); + curContribution.nextChallenge = nextChallengeHasher.digest(); + if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); + contributions.push(curContribution); + await writeContributions(fdNew, curve, contributions); + await fdOld.close(); + await fdNew.close(); + return hashResponse; + async function processSection(sectionId, groupName, NPoints, first, inc, sectionName, logger) { + const res = []; + fdOld.pos = sections[sectionId][0].p; + await _iden3_binfileutils.startWriteSection(fdNew, sectionId); + startSections[sectionId] = fdNew.pos; + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const chunkSize = Math.floor((1 << 20) / sG); + let t = first; + for (let i = 0; i < NPoints; i += chunkSize) { + if (logger) logger.debug(`applying key${sectionName}: ${i}/${NPoints}`); + const n = Math.min(NPoints - i, chunkSize); + const buffIn = await fdOld.read(n * sG); + const buffOutLEM = await G.batchApplyKey(buffIn, t, inc); + const promiseWrite = fdNew.write(buffOutLEM); + const buffOutC = await G.batchLEMtoC(buffOutLEM); + responseHasher.update(buffOutC); + await promiseWrite; + if (i == 0) for (let j = 0; j < Math.min(2, NPoints); j++) res.push(G.fromRprLEM(buffOutLEM, j * sG)); + t = curve.Fr.mul(t, curve.Fr.exp(inc, n)); + } + await _iden3_binfileutils.endWriteSection(fdNew); + return res; + } + async function hashSection(fdTo, groupName, sectionId, nPoints, sectionName, logger) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const nPointsChunk = Math.floor((1 << 24) / sG); + const oldPos = fdTo.pos; + fdTo.pos = startSections[sectionId]; + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Hashing ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + const buffLEM = await fdTo.read(n * sG); + const buffU = await G.batchLEMtoU(buffLEM); + nextChallengeHasher.update(buffU); + } + fdTo.pos = oldPos; + } +} +//#endregion +//#region src/powersoftau_contribute.js async function contribute(oldPtauFilename, newPTauFilename, name, entropy, logger) { - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - if (power != ceremonyPower) { - if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); - throw new Error("This file has been reduced. You cannot contribute into a reduced file."); - } - if (sections[12]) { - if (logger) logger.warn("WARNING: Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); - } - const contributions = await readContributions(fdOld, curve, sections); - const curContribution = { - name: name, - type: 0, // Beacon - }; - - let lastChallengeHash; - - const rng = await getRandomRng(entropy); - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - // Generate a random key - - - curContribution.key = createPTauKey(curve, lastChallengeHash, rng); - - - const responseHasher = blake2_js.blake2b.create({ dkLen: 64 }); - responseHasher.update(lastChallengeHash); - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, 7); - await writePTauHeader(fdNew, curve, power); - - const startSections = []; - - let firstPoints; - firstPoints = await processSection(2, "G1", (2 ** power) * 2 -1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1" ); - curContribution.tauG1 = firstPoints[1]; - firstPoints = await processSection(3, "G2", (2 ** power) , curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2" ); - curContribution.tauG2 = firstPoints[1]; - firstPoints = await processSection(4, "G1", (2 ** power) , curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1" ); - curContribution.alphaG1 = firstPoints[0]; - firstPoints = await processSection(5, "G1", (2 ** power) , curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1" ); - curContribution.betaG1 = firstPoints[0]; - firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2" ); - curContribution.betaG2 = firstPoints[0]; - - curContribution.partialHash = toPartialHash(responseHasher); - - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - - toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); - - responseHasher.update(new Uint8Array(buffKey)); - const hashResponse = responseHasher.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - const nextChallengeHasher = blake2_js.blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1"); - await hashSection(fdNew, "G2", 3, (2 ** power) , "tauG2"); - await hashSection(fdNew, "G1", 4, (2 ** power) , "alphaTauG1"); - await hashSection(fdNew, "G1", 5, (2 ** power) , "betaTauG1"); - await hashSection(fdNew, "G2", 6, 1 , "betaG2"); - - curContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); - - contributions.push(curContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdOld.close(); - await fdNew.close(); - - return hashResponse; - - async function processSection(sectionId, groupName, NPoints, first, inc, sectionName) { - const res = []; - fdOld.pos = sections[sectionId][0].p; - - await binFileUtils__namespace.startWriteSection(fdNew, sectionId); - - startSections[sectionId] = fdNew.pos; - - const G = curve[groupName]; - const sG = G.F.n8*2; - const chunkSize = Math.floor((1<<20) / sG); // 128Mb chunks - let t = first; - for (let i=0 ; i. -*/ - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power, ceremonyPower } = await readPTauHeader(fdOld, sections); + if (power != ceremonyPower) { + if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); + throw new Error("This file has been reduced. You cannot contribute into a reduced file."); + } + if (sections[12]) { + if (logger) logger.warn("WARNING: Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); + } + const contributions = await readContributions(fdOld, curve, sections); + const curContribution = { + name, + type: 0 + }; + let lastChallengeHash; + const rng = await getRandomRng(entropy); + if (contributions.length > 0) lastChallengeHash = contributions[contributions.length - 1].nextChallenge; + else lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); + curContribution.key = createPTauKey(curve, lastChallengeHash, rng); + const responseHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + responseHasher.update(lastChallengeHash); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, 7); + await writePTauHeader(fdNew, curve, power); + const startSections = []; + let firstPoints; + firstPoints = await processSection(2, "G1", 2 ** power * 2 - 1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1"); + curContribution.tauG1 = firstPoints[1]; + firstPoints = await processSection(3, "G2", 2 ** power, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2"); + curContribution.tauG2 = firstPoints[1]; + firstPoints = await processSection(4, "G1", 2 ** power, curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1"); + curContribution.alphaG1 = firstPoints[0]; + firstPoints = await processSection(5, "G1", 2 ** power, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1"); + curContribution.betaG1 = firstPoints[0]; + firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2"); + curContribution.betaG2 = firstPoints[0]; + curContribution.partialHash = toPartialHash(responseHasher); + const buffKey = new Uint8Array(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); + responseHasher.update(new Uint8Array(buffKey)); + const hashResponse = responseHasher.digest(); + if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); + const nextChallengeHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + nextChallengeHasher.update(hashResponse); + await hashSection(fdNew, "G1", 2, 2 ** power * 2 - 1, "tauG1"); + await hashSection(fdNew, "G2", 3, 2 ** power, "tauG2"); + await hashSection(fdNew, "G1", 4, 2 ** power, "alphaTauG1"); + await hashSection(fdNew, "G1", 5, 2 ** power, "betaTauG1"); + await hashSection(fdNew, "G2", 6, 1, "betaG2"); + curContribution.nextChallenge = nextChallengeHasher.digest(); + if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); + contributions.push(curContribution); + await writeContributions(fdNew, curve, contributions); + await fdOld.close(); + await fdNew.close(); + return hashResponse; + async function processSection(sectionId, groupName, NPoints, first, inc, sectionName) { + const res = []; + fdOld.pos = sections[sectionId][0].p; + await _iden3_binfileutils.startWriteSection(fdNew, sectionId); + startSections[sectionId] = fdNew.pos; + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const chunkSize = Math.floor((1 << 20) / sG); + let t = first; + for (let i = 0; i < NPoints; i += chunkSize) { + if (logger) logger.debug(`processing: ${sectionName}: ${i}/${NPoints}`); + const n = Math.min(NPoints - i, chunkSize); + const buffIn = await fdOld.read(n * sG); + const buffOutLEM = await G.batchApplyKey(buffIn, t, inc); + const promiseWrite = fdNew.write(buffOutLEM); + const buffOutC = await G.batchLEMtoC(buffOutLEM); + responseHasher.update(buffOutC); + await promiseWrite; + if (i == 0) for (let j = 0; j < Math.min(2, NPoints); j++) res.push(G.fromRprLEM(buffOutLEM, j * sG)); + t = curve.Fr.mul(t, curve.Fr.exp(inc, n)); + } + await _iden3_binfileutils.endWriteSection(fdNew); + return res; + } + async function hashSection(fdTo, groupName, sectionId, nPoints, sectionName) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const nPointsChunk = Math.floor((1 << 24) / sG); + const oldPos = fdTo.pos; + fdTo.pos = startSections[sectionId]; + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger && i) logger.debug(`Hashing ${sectionName}: ` + i); + const n = Math.min(nPoints - i, nPointsChunk); + const buffLEM = await fdTo.read(n * sG); + const buffU = await G.batchLEMtoU(buffLEM); + nextChallengeHasher.update(buffU); + } + fdTo.pos = oldPos; + } +} +//#endregion +//#region src/powersoftau_preparephase2.js async function preparePhase2(oldPtauFilename, newPTauFilename, logger) { - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, 11); - await writePTauHeader(fdNew, curve, power); - - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 2); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 3); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 4); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 5); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 6); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 7); - - await processSection(2, 12, "G1", "tauG1" ); - await processSection(3, 13, "G2", "tauG2" ); - await processSection(4, 14, "G1", "alphaTauG1" ); - await processSection(5, 15, "G1", "betaTauG1" ); - - await fdOld.close(); - await fdNew.close(); - - // await fs.promises.unlink(newPTauFilename+ ".tmp"); - - return; - - async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { - if (logger) logger.debug("Starting section: "+sectionName); - - await binFileUtils__namespace.startWriteSection(fdNew, newSectionId); - - for (let p=0; p<=power; p++) { - await processSectionPower(p); - } - - if (oldSectionId == 2) { - await processSectionPower(power+1); - } - - await binFileUtils__namespace.endWriteSection(fdNew); - - - async function processSectionPower(p) { - const nPoints = 2 ** p; - const G = curve[Gstr]; - const sGin = G.F.n8*2; - - let buff; - buff = new ffjavascript.BigBuffer(nPoints*sGin); - - await binFileUtils__namespace.startReadUniqueSection(fdOld, sections, oldSectionId); - if ((oldSectionId == 2)&&(p==power+1)) { - await fdOld.readToBuffer(buff, 0,(nPoints-1)*sGin ); - buff.set(curve.G1.zeroAffine, (nPoints-1)*sGin ); - } else { - await fdOld.readToBuffer(buff, 0,nPoints*sGin ); - } - await binFileUtils__namespace.endReadSection(fdOld, true); - - - buff = await G.lagrangeEvaluations(buff, "affine", "affine", logger, sectionName); - await fdNew.write(buff); - - /* - if (p <= curve.Fr.s) { - buff = await G.ifft(buff, "affine", "affine", logger, sectionName); - await fdNew.write(buff); - } else if (p == curve.Fr.s+1) { - const smallM = 1<. -*/ - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fdOld, sections); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, 11); + await writePTauHeader(fdNew, curve, power); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + await processSection(2, 12, "G1", "tauG1"); + await processSection(3, 13, "G2", "tauG2"); + await processSection(4, 14, "G1", "alphaTauG1"); + await processSection(5, 15, "G1", "betaTauG1"); + await fdOld.close(); + await fdNew.close(); + return; + async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { + if (logger) logger.debug("Starting section: " + sectionName); + await _iden3_binfileutils.startWriteSection(fdNew, newSectionId); + for (let p = 0; p <= power; p++) await processSectionPower(p); + if (oldSectionId == 2) await processSectionPower(power + 1); + await _iden3_binfileutils.endWriteSection(fdNew); + async function processSectionPower(p) { + const nPoints = 2 ** p; + const G = curve[Gstr]; + const sGin = G.F.n8 * 2; + let buff; + buff = new ffjavascript.BigBuffer(nPoints * sGin); + await _iden3_binfileutils.startReadUniqueSection(fdOld, sections, oldSectionId); + if (oldSectionId == 2 && p == power + 1) { + await fdOld.readToBuffer(buff, 0, (nPoints - 1) * sGin); + buff.set(curve.G1.zeroAffine, (nPoints - 1) * sGin); + } else await fdOld.readToBuffer(buff, 0, nPoints * sGin); + await _iden3_binfileutils.endReadSection(fdOld, true); + buff = await G.lagrangeEvaluations(buff, "affine", "affine", logger, sectionName); + await fdNew.write(buff); + } + } +} +//#endregion +//#region src/powersoftau_truncate.js async function truncate(ptauFilename, template, logger) { - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(ptauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - for (let p=1; p. -*/ - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(ptauFilename, "ptau", 1); + const { curve, power, ceremonyPower } = await readPTauHeader(fdOld, sections); + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + for (let p = 1; p < power; p++) await generateTruncate(p); + await fdOld.close(); + return true; + async function generateTruncate(p) { + let sP = p.toString(); + while (sP.length < 2) sP = "0" + sP; + if (logger) logger.debug("Writing Power: " + sP); + const fdNew = await _iden3_binfileutils.createBinFile(template + sP + ".ptau", "ptau", 1, 11); + await writePTauHeader(fdNew, curve, p, ceremonyPower); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 2, (2 ** p * 2 - 1) * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3, 2 ** p * sG2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4, 2 ** p * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5, 2 ** p * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6, sG2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 12, (2 ** (p + 1) * 2 - 1) * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 13, (2 ** p * 2 - 1) * sG2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 14, (2 ** p * 2 - 1) * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 15, (2 ** p * 2 - 1) * sG1); + await fdNew.close(); + } +} +//#endregion +//#region src/powersoftau_convert.js async function convert(oldPtauFilename, newPTauFilename, logger) { - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, 11); - await writePTauHeader(fdNew, curve, power); - - // const fdTmp = await fastFile.createOverride(newPTauFilename+ ".tmp"); - - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 2); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 3); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 4); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 5); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 6); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 7); - - await processSection(2, 12, "G1", "tauG1" ); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 13); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 14); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 15); - - await fdOld.close(); - await fdNew.close(); - - // await fs.promises.unlink(newPTauFilename+ ".tmp"); - - return; - - async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { - if (logger) logger.debug("Starting section: "+sectionName); - - await binFileUtils__namespace.startWriteSection(fdNew, newSectionId); - - const size = sections[newSectionId][0].size; - const chunkSize = fdOld.pageSize; - await binFileUtils__namespace.startReadUniqueSection(fdOld, sections, newSectionId); - for (let p=0; p. -*/ - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fdOld, sections); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, 11); + await writePTauHeader(fdNew, curve, power); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + await processSection(2, 12, "G1", "tauG1"); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 13); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 14); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 15); + await fdOld.close(); + await fdNew.close(); + return; + async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { + if (logger) logger.debug("Starting section: " + sectionName); + await _iden3_binfileutils.startWriteSection(fdNew, newSectionId); + const size = sections[newSectionId][0].size; + const chunkSize = fdOld.pageSize; + await _iden3_binfileutils.startReadUniqueSection(fdOld, sections, newSectionId); + for (let p = 0; p < size; p += chunkSize) { + const l = Math.min(size - p, chunkSize); + const buff = await fdOld.read(l); + await fdNew.write(buff); + } + await _iden3_binfileutils.endReadSection(fdOld); + if (oldSectionId == 2) await processSectionPower(power + 1); + await _iden3_binfileutils.endWriteSection(fdNew); + async function processSectionPower(p) { + const nPoints = 2 ** p; + const G = curve[Gstr]; + const sGin = G.F.n8 * 2; + let buff; + buff = new ffjavascript.BigBuffer(nPoints * sGin); + await _iden3_binfileutils.startReadUniqueSection(fdOld, sections, oldSectionId); + if (oldSectionId == 2 && p == power + 1) { + await fdOld.readToBuffer(buff, 0, (nPoints - 1) * sGin); + buff.set(curve.G1.zeroAffine, (nPoints - 1) * sGin); + } else await fdOld.readToBuffer(buff, 0, nPoints * sGin); + await _iden3_binfileutils.endReadSection(fdOld, true); + buff = await G.lagrangeEvaluations(buff, "affine", "affine", logger, sectionName); + await fdNew.write(buff); + } + } +} +//#endregion +//#region src/powersoftau_export_json.js async function exportJson(pTauFilename, verbose) { - const {fd, sections} = await binFileUtils__namespace.readBinFile(pTauFilename, "ptau", 1); - - const {curve, power} = await readPTauHeader(fd, sections); - - const pTau = {}; - pTau.q = curve.q; - pTau.power = power; - pTau.contributions = await readContributions(fd, curve, sections); - - pTau.tauG1 = await exportSection(2, "G1", (2 ** power)*2 -1, "tauG1"); - pTau.tauG2 = await exportSection(3, "G2", (2 ** power), "tauG2"); - pTau.alphaTauG1 = await exportSection(4, "G1", (2 ** power), "alphaTauG1"); - pTau.betaTauG1 = await exportSection(5, "G1", (2 ** power), "betaTauG1"); - pTau.betaG2 = await exportSection(6, "G2", 1, "betaG2"); - - pTau.lTauG1 = await exportLagrange(12, "G1", "lTauG1"); - pTau.lTauG2 = await exportLagrange(13, "G2", "lTauG2"); - pTau.lAlphaTauG1 = await exportLagrange(14, "G1", "lAlphaTauG2"); - pTau.lBetaTauG1 = await exportLagrange(15, "G1", "lBetaTauG2"); - - await fd.close(); - - return stringifyBigIntsWithField(curve.Fr, pTau); - - - - async function exportSection(sectionId, groupName, nPoints, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - - const res = []; - await binFileUtils__namespace.startReadUniqueSection(fd, sections, sectionId); - for (let i=0; i< nPoints; i++) { - if ((verbose)&&i&&(i%10000 == 0)) console.log(`${sectionName}: ` + i); - const buff = await fd.read(sG); - res.push(G.fromRprLEM(buff, 0)); - } - await binFileUtils__namespace.endReadSection(fd); - - return res; - } - - async function exportLagrange(sectionId, groupName, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - - const res = []; - await binFileUtils__namespace.startReadUniqueSection(fd, sections, sectionId); - for (let p=0; p<=power; p++) { - if (verbose) console.log(`${sectionName}: Power: ${p}`); - res[p] = []; - const nPoints = (2 ** p); - for (let i=0; i. -*/ - -const SUBARRAY_SIZE = 0x40000; - -const BigArrayHandler = { - get: function(obj, prop) { - if (!isNaN(prop)) { - return obj.getElement(prop); - } else return obj[prop]; - }, - set: function(obj, prop, value) { - if (!isNaN(prop)) { - return obj.setElement(prop, value); - } else { - obj[prop] = value; - return true; - } - } + const { fd, sections } = await _iden3_binfileutils.readBinFile(pTauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fd, sections); + const pTau = {}; + pTau.q = curve.q; + pTau.power = power; + pTau.contributions = await readContributions(fd, curve, sections); + pTau.tauG1 = await exportSection(2, "G1", 2 ** power * 2 - 1, "tauG1"); + pTau.tauG2 = await exportSection(3, "G2", 2 ** power, "tauG2"); + pTau.alphaTauG1 = await exportSection(4, "G1", 2 ** power, "alphaTauG1"); + pTau.betaTauG1 = await exportSection(5, "G1", 2 ** power, "betaTauG1"); + pTau.betaG2 = await exportSection(6, "G2", 1, "betaG2"); + pTau.lTauG1 = await exportLagrange(12, "G1", "lTauG1"); + pTau.lTauG2 = await exportLagrange(13, "G2", "lTauG2"); + pTau.lAlphaTauG1 = await exportLagrange(14, "G1", "lAlphaTauG2"); + pTau.lBetaTauG1 = await exportLagrange(15, "G1", "lBetaTauG2"); + await fd.close(); + return stringifyBigIntsWithField(curve.Fr, pTau); + async function exportSection(sectionId, groupName, nPoints, sectionName) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const res = []; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, sectionId); + for (let i = 0; i < nPoints; i++) { + if (verbose && i && i % 1e4 == 0) console.log(`${sectionName}: ` + i); + const buff = await fd.read(sG); + res.push(G.fromRprLEM(buff, 0)); + } + await _iden3_binfileutils.endReadSection(fd); + return res; + } + async function exportLagrange(sectionId, groupName, sectionName) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const res = []; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, sectionId); + for (let p = 0; p <= power; p++) { + if (verbose) console.log(`${sectionName}: Power: ${p}`); + res[p] = []; + const nPoints = 2 ** p; + for (let i = 0; i < nPoints; i++) { + if (verbose && i && i % 1e4 == 0) console.log(`${sectionName}: ${i}/${nPoints}`); + const buff = await fd.read(sG); + res[p].push(G.fromRprLEM(buff, 0)); + } + } + await _iden3_binfileutils.endReadSection(fd, true); + return res; + } +} +//#endregion +//#region src/bigarray.js +var SUBARRAY_SIZE = 262144; +var BigArrayHandler = { + get: function(obj, prop) { + if (!isNaN(prop)) return obj.getElement(prop); + else return obj[prop]; + }, + set: function(obj, prop, value) { + if (!isNaN(prop)) return obj.setElement(prop, value); + else { + obj[prop] = value; + return true; + } + } }; - -class _BigArray { - constructor (initSize) { - this.length = initSize || 0; - this.arr = new Array(SUBARRAY_SIZE); - - for (let i=0; i= this.length) this.length = idx+1; - return true; - } - getKeys() { - const newA = new BigArray(); - for (let i=0; i. -*/ - - +var _BigArray = class { + constructor(initSize) { + this.length = initSize || 0; + this.arr = new Array(SUBARRAY_SIZE); + for (let i = 0; i < initSize; i += SUBARRAY_SIZE) this.arr[i / SUBARRAY_SIZE] = new Array(Math.min(SUBARRAY_SIZE, initSize - i)); + return this; + } + push() { + for (let i = 0; i < arguments.length; i++) this.setElement(this.length, arguments[i]); + } + slice(f, t) { + const arr = new Array(t - f); + for (let i = f; i < t; i++) arr[i - f] = this.getElement(i); + return arr; + } + getElement(idx) { + idx = parseInt(idx); + const idx1 = Math.floor(idx / SUBARRAY_SIZE); + const idx2 = idx % SUBARRAY_SIZE; + return this.arr[idx1] ? this.arr[idx1][idx2] : void 0; + } + setElement(idx, value) { + idx = parseInt(idx); + const idx1 = Math.floor(idx / SUBARRAY_SIZE); + if (!this.arr[idx1]) this.arr[idx1] = new Array(SUBARRAY_SIZE); + const idx2 = idx % SUBARRAY_SIZE; + this.arr[idx1][idx2] = value; + if (idx >= this.length) this.length = idx + 1; + return true; + } + getKeys() { + const newA = new BigArray(); + for (let i = 0; i < this.arr.length; i++) if (this.arr[i]) { + for (let j = 0; j < this.arr[i].length; j++) if (typeof this.arr[i][j] !== "undefined") newA.push(i * SUBARRAY_SIZE + j); + } + return newA; + } +}; +var BigArray = class { + constructor(initSize) { + const obj = new _BigArray(initSize); + return new Proxy(obj, BigArrayHandler); + } +}; +//#endregion +//#region src/zkey_new.js async function newZKey(r1csName, ptauName, zkeyName, logger) { - - const TAU_G1 = 0; - const TAU_G2 = 1; - const ALPHATAU_G1 = 2; - const BETATAU_G1 = 3; - const csHasher = blake2_js.blake2b.create({ dkLen: 64 }); - - const {fd: fdPTau, sections: sectionsPTau} = await binFileUtils.readBinFile(ptauName, "ptau", 1, 1<<22, 1<<24); - const {curve, power} = await readPTauHeader(fdPTau, sectionsPTau); - const {fd: fdR1cs, sections: sectionsR1cs} = await binFileUtils.readBinFile(r1csName, "r1cs", 1, 1<<22, 1<<24); - const r1cs = await r1csfile.readR1csHeader(fdR1cs, sectionsR1cs, false); - - const fdZKey = await binFileUtils.createBinFile(zkeyName, "zkey", 1, 10, 1<<22, 1<<24); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - if (r1cs.prime != curve.r) { - if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); - return -1; - } - - const cirPower = log2(r1cs.nConstraints + r1cs.nPubInputs + r1cs.nOutputs +1 -1) +1; - - if (cirPower > power) { - if (logger) logger.error(`circuit too big for this power of tau ceremony. ${r1cs.nConstraints}*2 > 2**${power}`); - return -1; - } - - if (!sectionsPTau[12]) { - if (logger) logger.error("Powers of tau is not prepared."); - return -1; - } - - const nPublic = r1cs.nOutputs + r1cs.nPubInputs; - const domainSize = 2 ** cirPower; - - // Write the header - /////////// - await binFileUtils.startWriteSection(fdZKey, 1); - await fdZKey.writeULE32(1); // Groth - await binFileUtils.endWriteSection(fdZKey); - - // Write the Groth header section - /////////// - - await binFileUtils.startWriteSection(fdZKey, 2); - const primeQ = curve.q; - const n8q = (Math.floor( (ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) +1)*8; - - const primeR = curve.r; - const n8r = (Math.floor( (ffjavascript.Scalar.bitLength(primeR) - 1) / 64) +1)*8; - const Rr = ffjavascript.Scalar.mod(ffjavascript.Scalar.shl(1, n8r*8), primeR); - const R2r = curve.Fr.e(ffjavascript.Scalar.mod(ffjavascript.Scalar.mul(Rr,Rr), primeR)); - - await fdZKey.writeULE32(n8q); - await binFileUtils.writeBigInt(fdZKey, primeQ, n8q); - await fdZKey.writeULE32(n8r); - await binFileUtils.writeBigInt(fdZKey, primeR, n8r); - await fdZKey.writeULE32(r1cs.nVars); // Total number of bars - await fdZKey.writeULE32(nPublic); // Total number of public vars (not including ONE) - await fdZKey.writeULE32(domainSize); // domainSize - - let bAlpha1; - bAlpha1 = await fdPTau.read(sG1, sectionsPTau[4][0].p); - await fdZKey.write(bAlpha1); - bAlpha1 = await curve.G1.batchLEMtoU(bAlpha1); - csHasher.update(bAlpha1); - - let bBeta1; - bBeta1 = await fdPTau.read(sG1, sectionsPTau[5][0].p); - await fdZKey.write(bBeta1); - bBeta1 = await curve.G1.batchLEMtoU(bBeta1); - csHasher.update(bBeta1); - - let bBeta2; - bBeta2 = await fdPTau.read(sG2, sectionsPTau[6][0].p); - await fdZKey.write(bBeta2); - bBeta2 = await curve.G2.batchLEMtoU(bBeta2); - csHasher.update(bBeta2); - - const bg1 = new Uint8Array(sG1); - curve.G1.toRprLEM(bg1, 0, curve.G1.g); - const bg2 = new Uint8Array(sG2); - curve.G2.toRprLEM(bg2, 0, curve.G2.g); - const bg1U = new Uint8Array(sG1); - curve.G1.toRprUncompressed(bg1U, 0, curve.G1.g); - const bg2U = new Uint8Array(sG2); - curve.G2.toRprUncompressed(bg2U, 0, curve.G2.g); - - await fdZKey.write(bg2); // gamma2 - await fdZKey.write(bg1); // delta1 - await fdZKey.write(bg2); // delta2 - csHasher.update(bg2U); // gamma2 - csHasher.update(bg1U); // delta1 - csHasher.update(bg2U); // delta2 - await binFileUtils.endWriteSection(fdZKey); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Reading r1cs"); - let sR1cs = await binFileUtils.readSection(fdR1cs, sectionsR1cs, 2); - await fdR1cs.close(); - - let A = new BigArray(r1cs.nVars); - let B1 = new BigArray(r1cs.nVars); - let B2 = new BigArray(r1cs.nVars); - let C = new BigArray(r1cs.nVars- nPublic -1); - let IC = new Array(nPublic+1); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Reading tauG1"); - let sTauG1 = await binFileUtils.readSection(fdPTau, sectionsPTau, 12, (domainSize -1)*sG1, domainSize*sG1); - if (logger) logger.info("Reading tauG2"); - let sTauG2 = await binFileUtils.readSection(fdPTau, sectionsPTau, 13, (domainSize -1)*sG2, domainSize*sG2); - if (logger) logger.info("Reading alphatauG1"); - let sAlphaTauG1 = await binFileUtils.readSection(fdPTau, sectionsPTau, 14, (domainSize -1)*sG1, domainSize*sG1); - if (logger) logger.info("Reading betatauG1"); - let sBetaTauG1 = await binFileUtils.readSection(fdPTau, sectionsPTau, 15, (domainSize -1)*sG1, domainSize*sG1); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("processConstraints"); - await processConstraints(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints"); - await composeAndWritePoints(3, "G1", IC, "IC"); - - IC = null; - // const gc = runInNewContext("gc"); // nocommit - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("writeHs"); - await writeHs(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("hashHPoints"); - await hashHPoints(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 8 G1 C"); - await composeAndWritePoints(8, "G1", C, "C"); - - C = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 5 G1 A"); - await composeAndWritePoints(5, "G1", A, "A"); - - A = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 6 G1 B1"); - await composeAndWritePoints(6, "G1", B1, "B1"); - - B1 = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 7 G2 B2"); - await composeAndWritePoints(7, "G2", B2, "B2"); - - B2 = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Contributions section"); - const csHash = csHasher.digest(); - // Contributions section - await binFileUtils.startWriteSection(fdZKey, 10); - await fdZKey.write(csHash); - await fdZKey.writeULE32(0); - await binFileUtils.endWriteSection(fdZKey); - - if (logger) logger.info(formatHash(csHash, "Circuit hash: ")); - - - await fdZKey.close(); - await fdPTau.close(); - - return csHash; - - async function writeHs() { - await binFileUtils.startWriteSection(fdZKey, 9); - const buffOut = new ffjavascript.BigBuffer(domainSize*sG1); - if (cirPower < curve.Fr.s) { - let sTauG1 = await binFileUtils.readSection(fdPTau, sectionsPTau, 12, (domainSize*2-1)*sG1, domainSize*2*sG1); - for (let i=0; i< domainSize; i++) { - if ((logger)&&(i%10000 == 0)) logger.debug(`splitting buffer: ${i}/${domainSize}`); - const buff = sTauG1.slice( (i*2+1)*sG1, (i*2+1)*sG1 + sG1 ); - buffOut.set(buff, i*sG1); - } - } else if (cirPower == curve.Fr.s) { - const o = sectionsPTau[12][0].p + ((2 ** (cirPower+1)) -1)*sG1; - await fdPTau.readToBuffer(buffOut, 0, domainSize*sG1, o + domainSize*sG1); - } else { - if (logger) logger.error("Circuit too big"); - throw new Error("Circuit too big for this curve"); - } - await fdZKey.write(buffOut); - await binFileUtils.endWriteSection(fdZKey); - } - - async function processConstraints() { - const buffCoeff = new Uint8Array(12 + curve.Fr.n8); - const buffCoeffV = new DataView(buffCoeff.buffer); - const bOne = new Uint8Array(curve.Fr.n8); - curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); - - let r1csPos = 0; - - function r1cs_readULE32() { - const buff = sR1cs.slice(r1csPos, r1csPos+4); - r1csPos += 4; - const buffV = new DataView(buff.buffer); - return buffV.getUint32(0, true); - } - - const coefs = new BigArray(); - for (let c=0; c=0) { - n = curve.Fr.fromRprLE(sR1cs.slice(c[3], c[3] + curve.Fr.n8), 0); - } else { - n = curve.Fr.fromRprLE(bOne, 0); - } - const nR2 = curve.Fr.mul(n, R2r); - curve.Fr.toRprLE(buffCoeff, 12, nR2); - buffSection.set(buffCoeff, coefsPos); - coefsPos += buffCoeff.length; - } - - } - - async function composeAndWritePoints(idSection, groupName, arr, sectionName) { - const CHUNK_SIZE= 1<<15; - const G = curve[groupName]; - - hashU32(arr.length); - await binFileUtils.startWriteSection(fdZKey, idSection); - - let opPromises = []; - - let i=0; - while (i { - if (logger) logger.debug(`Writing points end ${sectionName}: ${_i}/${arr.length}`); - return r; - })); - i += n; - t++; - } - - const result = await Promise.all(opPromises); - - for (let k=0; k 2<<14) { - bBases = new ffjavascript.BigBuffer(acc*sGin); - bScalars = new ffjavascript.BigBuffer(acc*curve.Fr.n8); - } else { - bBases = new Uint8Array(acc*sGin); - bScalars = new Uint8Array(acc*curve.Fr.n8); - } - let pB =0; - let pS =0; - - const sBuffs = [ - sTauG1, - sTauG2, - sAlphaTauG1, - sBetaTauG1 - ]; - - const bOne = new Uint8Array(curve.Fr.n8); - curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); - - let offset = 0; - for (let i=0; i=0) { - bScalars.set( - sR1cs.slice( - arr[i][j][2], - arr[i][j][2] + curve.Fr.n8 - ), - offset*curve.Fr.n8 - ); - } else { - bScalars.set(bOne, offset*curve.Fr.n8); - } - offset ++; - } - } - - if (arr.length>1) { - const task = []; - task.push({cmd: "ALLOCSET", var: 0, buff: bBases}); - task.push({cmd: "ALLOCSET", var: 1, buff: bScalars}); - task.push({cmd: "ALLOC", var: 2, len: arr.length*sGmid}); - pB = 0; - pS = 0; - let pD =0; - for (let i=0; i. -*/ - -// FFlonk constants -const FF_T_POL_DEG_MIN = 3; - -// ZKEY constants -const ZKEY_FF_NSECTIONS = 17; - -const ZKEY_FF_HEADER_SECTION = 2; -const ZKEY_FF_ADDITIONS_SECTION = 3; -const ZKEY_FF_A_MAP_SECTION = 4; -const ZKEY_FF_B_MAP_SECTION = 5; -const ZKEY_FF_C_MAP_SECTION = 6; -const ZKEY_FF_QL_SECTION = 7; -const ZKEY_FF_QR_SECTION = 8; -const ZKEY_FF_QM_SECTION = 9; -const ZKEY_FF_QO_SECTION = 10; -const ZKEY_FF_QC_SECTION = 11; -const ZKEY_FF_SIGMA1_SECTION = 12; -const ZKEY_FF_SIGMA2_SECTION = 13; -const ZKEY_FF_SIGMA3_SECTION = 14; -const ZKEY_FF_LAGRANGE_SECTION = 15; -const ZKEY_FF_PTAU_SECTION = 16; -const ZKEY_FF_C0_SECTION = 17; - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const TAU_G1 = 0; + const TAU_G2 = 1; + const ALPHATAU_G1 = 2; + const BETATAU_G1 = 3; + const csHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + const { fd: fdPTau, sections: sectionsPTau } = await (0, _iden3_binfileutils.readBinFile)(ptauName, "ptau", 1, 1 << 22, 1 << 24); + const { curve, power } = await readPTauHeader(fdPTau, sectionsPTau); + const { fd: fdR1cs, sections: sectionsR1cs } = await (0, _iden3_binfileutils.readBinFile)(r1csName, "r1cs", 1, 1 << 22, 1 << 24); + const r1cs = await (0, r1csfile.readR1csHeader)(fdR1cs, sectionsR1cs, false); + const fdZKey = await (0, _iden3_binfileutils.createBinFile)(zkeyName, "zkey", 1, 10, 1 << 22, 1 << 24); + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + if (r1cs.prime != curve.r) { + if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); + return -1; + } + const cirPower = log2(r1cs.nConstraints + r1cs.nPubInputs + r1cs.nOutputs + 1 - 1) + 1; + if (cirPower > power) { + if (logger) logger.error(`circuit too big for this power of tau ceremony. ${r1cs.nConstraints}*2 > 2**${power}`); + return -1; + } + if (!sectionsPTau[12]) { + if (logger) logger.error("Powers of tau is not prepared."); + return -1; + } + const nPublic = r1cs.nOutputs + r1cs.nPubInputs; + const domainSize = 2 ** cirPower; + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 1); + await fdZKey.writeULE32(1); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 2); + const primeQ = curve.q; + const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; + const primeR = curve.r; + const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; + const Rr = ffjavascript.Scalar.mod(ffjavascript.Scalar.shl(1, n8r * 8), primeR); + const R2r = curve.Fr.e(ffjavascript.Scalar.mod(ffjavascript.Scalar.mul(Rr, Rr), primeR)); + await fdZKey.writeULE32(n8q); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeQ, n8q); + await fdZKey.writeULE32(n8r); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeR, n8r); + await fdZKey.writeULE32(r1cs.nVars); + await fdZKey.writeULE32(nPublic); + await fdZKey.writeULE32(domainSize); + let bAlpha1; + bAlpha1 = await fdPTau.read(sG1, sectionsPTau[4][0].p); + await fdZKey.write(bAlpha1); + bAlpha1 = await curve.G1.batchLEMtoU(bAlpha1); + csHasher.update(bAlpha1); + let bBeta1; + bBeta1 = await fdPTau.read(sG1, sectionsPTau[5][0].p); + await fdZKey.write(bBeta1); + bBeta1 = await curve.G1.batchLEMtoU(bBeta1); + csHasher.update(bBeta1); + let bBeta2; + bBeta2 = await fdPTau.read(sG2, sectionsPTau[6][0].p); + await fdZKey.write(bBeta2); + bBeta2 = await curve.G2.batchLEMtoU(bBeta2); + csHasher.update(bBeta2); + const bg1 = new Uint8Array(sG1); + curve.G1.toRprLEM(bg1, 0, curve.G1.g); + const bg2 = new Uint8Array(sG2); + curve.G2.toRprLEM(bg2, 0, curve.G2.g); + const bg1U = new Uint8Array(sG1); + curve.G1.toRprUncompressed(bg1U, 0, curve.G1.g); + const bg2U = new Uint8Array(sG2); + curve.G2.toRprUncompressed(bg2U, 0, curve.G2.g); + await fdZKey.write(bg2); + await fdZKey.write(bg1); + await fdZKey.write(bg2); + csHasher.update(bg2U); + csHasher.update(bg1U); + csHasher.update(bg2U); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + if (logger) logger.info(memUsage()); + if (logger) logger.info("Reading r1cs"); + let sR1cs = await (0, _iden3_binfileutils.readSection)(fdR1cs, sectionsR1cs, 2); + await fdR1cs.close(); + let A = new BigArray(r1cs.nVars); + let B1 = new BigArray(r1cs.nVars); + let B2 = new BigArray(r1cs.nVars); + let C = new BigArray(r1cs.nVars - nPublic - 1); + let IC = new Array(nPublic + 1); + if (logger) logger.info(memUsage()); + if (logger) logger.info("Reading tauG1"); + let sTauG1 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 12, (domainSize - 1) * sG1, domainSize * sG1); + if (logger) logger.info("Reading tauG2"); + let sTauG2 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 13, (domainSize - 1) * sG2, domainSize * sG2); + if (logger) logger.info("Reading alphatauG1"); + let sAlphaTauG1 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 14, (domainSize - 1) * sG1, domainSize * sG1); + if (logger) logger.info("Reading betatauG1"); + let sBetaTauG1 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 15, (domainSize - 1) * sG1, domainSize * sG1); + if (logger) logger.info(memUsage()); + if (logger) logger.info("processConstraints"); + await processConstraints(); + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints"); + await composeAndWritePoints(3, "G1", IC, "IC"); + IC = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("writeHs"); + await writeHs(); + if (logger) logger.info(memUsage()); + if (logger) logger.info("hashHPoints"); + await hashHPoints(); + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints 8 G1 C"); + await composeAndWritePoints(8, "G1", C, "C"); + C = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints 5 G1 A"); + await composeAndWritePoints(5, "G1", A, "A"); + A = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints 6 G1 B1"); + await composeAndWritePoints(6, "G1", B1, "B1"); + B1 = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints 7 G2 B2"); + await composeAndWritePoints(7, "G2", B2, "B2"); + B2 = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("Contributions section"); + const csHash = csHasher.digest(); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 10); + await fdZKey.write(csHash); + await fdZKey.writeULE32(0); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + if (logger) logger.info(formatHash(csHash, "Circuit hash: ")); + await fdZKey.close(); + await fdPTau.close(); + return csHash; + async function writeHs() { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 9); + const buffOut = new ffjavascript.BigBuffer(domainSize * sG1); + if (cirPower < curve.Fr.s) { + let sTauG1 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 12, (domainSize * 2 - 1) * sG1, domainSize * 2 * sG1); + for (let i = 0; i < domainSize; i++) { + if (logger && i % 1e4 == 0) logger.debug(`splitting buffer: ${i}/${domainSize}`); + const buff = sTauG1.slice((i * 2 + 1) * sG1, (i * 2 + 1) * sG1 + sG1); + buffOut.set(buff, i * sG1); + } + } else if (cirPower == curve.Fr.s) { + const o = sectionsPTau[12][0].p + (2 ** (cirPower + 1) - 1) * sG1; + await fdPTau.readToBuffer(buffOut, 0, domainSize * sG1, o + domainSize * sG1); + } else { + if (logger) logger.error("Circuit too big"); + throw new Error("Circuit too big for this curve"); + } + await fdZKey.write(buffOut); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function processConstraints() { + const buffCoeff = new Uint8Array(12 + curve.Fr.n8); + const buffCoeffV = new DataView(buffCoeff.buffer); + const bOne = new Uint8Array(curve.Fr.n8); + curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); + let r1csPos = 0; + function r1cs_readULE32() { + const buff = sR1cs.slice(r1csPos, r1csPos + 4); + r1csPos += 4; + return new DataView(buff.buffer).getUint32(0, true); + } + const coefs = new BigArray(); + for (let c = 0; c < r1cs.nConstraints; c++) { + if (logger && c % 1e4 == 0) logger.debug(`processing constraints: ${c}/${r1cs.nConstraints}`); + const nA = r1cs_readULE32(); + for (let i = 0; i < nA; i++) { + const s = r1cs_readULE32(); + const coefp = r1csPos; + r1csPos += curve.Fr.n8; + const l1t = TAU_G1; + const l1 = sG1 * c; + const l2t = BETATAU_G1; + const l2 = sG1 * c; + if (typeof A[s] === "undefined") A[s] = []; + A[s].push([ + l1t, + l1, + coefp + ]); + if (s <= nPublic) { + if (typeof IC[s] === "undefined") IC[s] = []; + IC[s].push([ + l2t, + l2, + coefp + ]); + } else { + if (typeof C[s - nPublic - 1] === "undefined") C[s - nPublic - 1] = []; + C[s - nPublic - 1].push([ + l2t, + l2, + coefp + ]); + } + coefs.push([ + 0, + c, + s, + coefp + ]); + } + const nB = r1cs_readULE32(); + for (let i = 0; i < nB; i++) { + const s = r1cs_readULE32(); + const coefp = r1csPos; + r1csPos += curve.Fr.n8; + const l1t = TAU_G1; + const l1 = sG1 * c; + const l2t = TAU_G2; + const l2 = sG2 * c; + const l3t = ALPHATAU_G1; + const l3 = sG1 * c; + if (typeof B1[s] === "undefined") B1[s] = []; + B1[s].push([ + l1t, + l1, + coefp + ]); + if (typeof B2[s] === "undefined") B2[s] = []; + B2[s].push([ + l2t, + l2, + coefp + ]); + if (s <= nPublic) { + if (typeof IC[s] === "undefined") IC[s] = []; + IC[s].push([ + l3t, + l3, + coefp + ]); + } else { + if (typeof C[s - nPublic - 1] === "undefined") C[s - nPublic - 1] = []; + C[s - nPublic - 1].push([ + l3t, + l3, + coefp + ]); + } + coefs.push([ + 1, + c, + s, + coefp + ]); + } + const nC = r1cs_readULE32(); + for (let i = 0; i < nC; i++) { + const s = r1cs_readULE32(); + const coefp = r1csPos; + r1csPos += curve.Fr.n8; + const l1t = TAU_G1; + const l1 = sG1 * c; + if (s <= nPublic) { + if (typeof IC[s] === "undefined") IC[s] = []; + IC[s].push([ + l1t, + l1, + coefp + ]); + } else { + if (typeof C[s - nPublic - 1] === "undefined") C[s - nPublic - 1] = []; + C[s - nPublic - 1].push([ + l1t, + l1, + coefp + ]); + } + } + } + for (let s = 0; s <= nPublic; s++) { + const l1t = TAU_G1; + const l1 = sG1 * (r1cs.nConstraints + s); + const l2t = BETATAU_G1; + const l2 = sG1 * (r1cs.nConstraints + s); + if (typeof A[s] === "undefined") A[s] = []; + A[s].push([ + l1t, + l1, + -1 + ]); + if (typeof IC[s] === "undefined") IC[s] = []; + IC[s].push([ + l2t, + l2, + -1 + ]); + coefs.push([ + 0, + r1cs.nConstraints + s, + s, + -1 + ]); + } + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 4); + const buffSection = new ffjavascript.BigBuffer(coefs.length * (12 + curve.Fr.n8) + 4); + const buff4 = /* @__PURE__ */ new Uint8Array(4); + new DataView(buff4.buffer).setUint32(0, coefs.length, true); + buffSection.set(buff4); + let coefsPos = 4; + for (let i = 0; i < coefs.length; i++) { + if (logger && i % 1e5 == 0) logger.debug(`writing coeffs: ${i}/${coefs.length}`); + writeCoef(coefs[i]); + } + await fdZKey.write(buffSection); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + function writeCoef(c) { + buffCoeffV.setUint32(0, c[0], true); + buffCoeffV.setUint32(4, c[1], true); + buffCoeffV.setUint32(8, c[2], true); + let n; + if (c[3] >= 0) n = curve.Fr.fromRprLE(sR1cs.slice(c[3], c[3] + curve.Fr.n8), 0); + else n = curve.Fr.fromRprLE(bOne, 0); + const nR2 = curve.Fr.mul(n, R2r); + curve.Fr.toRprLE(buffCoeff, 12, nR2); + buffSection.set(buffCoeff, coefsPos); + coefsPos += buffCoeff.length; + } + } + async function composeAndWritePoints(idSection, groupName, arr, sectionName) { + const CHUNK_SIZE = 32768; + const G = curve[groupName]; + hashU32(arr.length); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, idSection); + let opPromises = []; + let i = 0; + while (i < arr.length) { + let t = 0; + while (i < arr.length && t < curve.tm.concurrency) { + if (logger) logger.debug(`Writing points start ${sectionName}: ${i}/${arr.length}`); + let n = 1; + let nP = arr[i] ? arr[i].length : 0; + while (i + n < arr.length && nP + (arr[i + n] ? arr[i + n].length : 0) < CHUNK_SIZE && n < CHUNK_SIZE) { + nP += arr[i + n] ? arr[i + n].length : 0; + n++; + } + if (logger) logger.info("before slice:"); + if (logger) logger.info(memUsage()); + const subArr = arr.slice(i, i + n); + if (logger) logger.info("after slice:"); + if (logger) logger.info(memUsage()); + const _i = i; + opPromises.push(composeAndWritePointsThread(groupName, subArr, logger, sectionName).then((r) => { + if (logger) logger.debug(`Writing points end ${sectionName}: ${_i}/${arr.length}`); + return r; + })); + i += n; + t++; + } + const result = await Promise.all(opPromises); + for (let k = 0; k < result.length; k++) { + await fdZKey.write(result[k][0]); + const buff = await G.batchLEMtoU(result[k][0]); + csHasher.update(buff); + } + opPromises = []; + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function composeAndWritePointsThread(groupName, arr, logger, sectionName) { + const G = curve[groupName]; + const sGin = G.F.n8 * 2; + const sGmid = G.F.n8 * 3; + const sGout = G.F.n8 * 2; + let fnExp, fnMultiExp, fnBatchToAffine, fnZero; + if (groupName == "G1") { + fnExp = "g1m_timesScalarAffine"; + fnMultiExp = "g1m_multiexpAffine"; + fnBatchToAffine = "g1m_batchToAffine"; + fnZero = "g1m_zero"; + } else if (groupName == "G2") { + fnExp = "g2m_timesScalarAffine"; + fnMultiExp = "g2m_multiexpAffine"; + fnBatchToAffine = "g2m_batchToAffine"; + fnZero = "g2m_zero"; + } else throw new Error("Invalid group"); + let acc = 0; + for (let i = 0; i < arr.length; i++) acc += arr[i] ? arr[i].length : 0; + let bBases, bScalars; + if (acc > 32768) { + bBases = new ffjavascript.BigBuffer(acc * sGin); + bScalars = new ffjavascript.BigBuffer(acc * curve.Fr.n8); + } else { + bBases = new Uint8Array(acc * sGin); + bScalars = new Uint8Array(acc * curve.Fr.n8); + } + let pB = 0; + let pS = 0; + const sBuffs = [ + sTauG1, + sTauG2, + sAlphaTauG1, + sBetaTauG1 + ]; + const bOne = new Uint8Array(curve.Fr.n8); + curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); + let offset = 0; + for (let i = 0; i < arr.length; i++) { + if (!arr[i]) continue; + for (let j = 0; j < arr[i].length; j++) { + if (logger && j && j % 1e4 == 0) logger.debug(`Configuring big array ${sectionName}: ${j}/${arr[i].length}`); + bBases.set(sBuffs[arr[i][j][0]].slice(arr[i][j][1], arr[i][j][1] + sGin), offset * sGin); + if (arr[i][j][2] >= 0) bScalars.set(sR1cs.slice(arr[i][j][2], arr[i][j][2] + curve.Fr.n8), offset * curve.Fr.n8); + else bScalars.set(bOne, offset * curve.Fr.n8); + offset++; + } + } + if (arr.length > 1) { + const task = []; + task.push({ + cmd: "ALLOCSET", + var: 0, + buff: bBases + }); + task.push({ + cmd: "ALLOCSET", + var: 1, + buff: bScalars + }); + task.push({ + cmd: "ALLOC", + var: 2, + len: arr.length * sGmid + }); + pB = 0; + pS = 0; + let pD = 0; + for (let i = 0; i < arr.length; i++) { + if (!arr[i]) { + task.push({ + cmd: "CALL", + fnName: fnZero, + params: [{ + var: 2, + offset: pD + }] + }); + pD += sGmid; + continue; + } + if (arr[i].length == 1) task.push({ + cmd: "CALL", + fnName: fnExp, + params: [ + { + var: 0, + offset: pB + }, + { + var: 1, + offset: pS + }, + { val: curve.Fr.n8 }, + { + var: 2, + offset: pD + } + ] + }); + else task.push({ + cmd: "CALL", + fnName: fnMultiExp, + params: [ + { + var: 0, + offset: pB + }, + { + var: 1, + offset: pS + }, + { val: curve.Fr.n8 }, + { val: arr[i].length }, + { + var: 2, + offset: pD + } + ] + }); + pB += sGin * arr[i].length; + pS += curve.Fr.n8 * arr[i].length; + pD += sGmid; + } + task.push({ + cmd: "CALL", + fnName: fnBatchToAffine, + params: [ + { var: 2 }, + { val: arr.length }, + { var: 2 } + ] + }); + task.push({ + cmd: "GET", + out: 0, + var: 2, + len: arr.length * sGout + }); + return await curve.tm.queueAction(task); + } else { + let res = await G.multiExpAffine(bBases, bScalars, logger, sectionName); + res = [G.toAffine(res)]; + return res; + } + } + async function hashHPoints() { + const CHUNK_SIZE = 16384; + hashU32(domainSize - 1); + for (let i = 0; i < domainSize - 1; i += CHUNK_SIZE) { + if (logger) logger.debug(`HashingHPoints: ${i}/${domainSize}`); + const n = Math.min(domainSize - 1, CHUNK_SIZE); + await hashHPointsChunk(i, n); + } + } + async function hashHPointsChunk(offset, nPoints) { + const buff1 = await fdPTau.read(nPoints * sG1, sectionsPTau[2][0].p + (offset + domainSize) * sG1); + const buff2 = await fdPTau.read(nPoints * sG1, sectionsPTau[2][0].p + offset * sG1); + const concurrency = curve.tm.concurrency; + const nPointsPerThread = Math.floor(nPoints / concurrency); + const opPromises = []; + for (let i = 0; i < concurrency; i++) { + let n; + if (i < concurrency - 1) n = nPointsPerThread; + else n = nPoints - i * nPointsPerThread; + if (n == 0) continue; + const subBuff1 = buff1.slice(i * nPointsPerThread * sG1, (i * nPointsPerThread + n) * sG1); + const subBuff2 = buff2.slice(i * nPointsPerThread * sG1, (i * nPointsPerThread + n) * sG1); + opPromises.push(hashHPointsThread(subBuff1, subBuff2)); + } + const result = await Promise.all(opPromises); + for (let i = 0; i < result.length; i++) csHasher.update(result[i][0]); + } + async function hashHPointsThread(buff1, buff2) { + const nPoints = buff1.byteLength / sG1; + const sGmid = curve.G1.F.n8 * 3; + const task = []; + task.push({ + cmd: "ALLOCSET", + var: 0, + buff: buff1 + }); + task.push({ + cmd: "ALLOCSET", + var: 1, + buff: buff2 + }); + task.push({ + cmd: "ALLOC", + var: 2, + len: nPoints * sGmid + }); + for (let i = 0; i < nPoints; i++) task.push({ + cmd: "CALL", + fnName: "g1m_subAffine", + params: [ + { + var: 0, + offset: i * sG1 + }, + { + var: 1, + offset: i * sG1 + }, + { + var: 2, + offset: i * sGmid + } + ] + }); + task.push({ + cmd: "CALL", + fnName: "g1m_batchToAffine", + params: [ + { var: 2 }, + { val: nPoints }, + { var: 2 } + ] + }); + task.push({ + cmd: "CALL", + fnName: "g1m_batchLEMtoU", + params: [ + { var: 2 }, + { val: nPoints }, + { var: 2 } + ] + }); + task.push({ + cmd: "GET", + out: 0, + var: 2, + len: nPoints * sG1 + }); + return await curve.tm.queueAction(task); + } + function hashU32(n) { + const buff = /* @__PURE__ */ new Uint8Array(4); + new DataView(buff.buffer, buff.byteOffset, buff.byteLength).setUint32(0, n, false); + csHasher.update(buff); + } + function memUsage() { + let m = process.memoryUsage(); + for (const i in m) m[i] = Math.round(m[i] / (1024 * 1024)); + return m; + } +} +//#endregion +//#region src/zkey_utils.js async function writeHeader(fd, zkey) { - - // Write the header - /////////// - await binFileUtils__namespace.startWriteSection(fd, 1); - await fd.writeULE32(1); // Groth - await binFileUtils__namespace.endWriteSection(fd); - - // Write the Groth header section - /////////// - - const curve = await getCurveFromQ(zkey.q); - - await binFileUtils__namespace.startWriteSection(fd, 2); - const primeQ = curve.q; - const n8q = (Math.floor( (ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) +1)*8; - - const primeR = curve.r; - const n8r = (Math.floor( (ffjavascript.Scalar.bitLength(primeR) - 1) / 64) +1)*8; - - await fd.writeULE32(n8q); - await binFileUtils__namespace.writeBigInt(fd, primeQ, n8q); - await fd.writeULE32(n8r); - await binFileUtils__namespace.writeBigInt(fd, primeR, n8r); - await fd.writeULE32(zkey.nVars); // Total number of bars - await fd.writeULE32(zkey.nPublic); // Total number of public vars (not including ONE) - await fd.writeULE32(zkey.domainSize); // domainSize - await writeG1(fd, curve, zkey.vk_alpha_1); - await writeG1(fd, curve, zkey.vk_beta_1); - await writeG2(fd, curve, zkey.vk_beta_2); - await writeG2(fd, curve, zkey.vk_gamma_2); - await writeG1(fd, curve, zkey.vk_delta_1); - await writeG2(fd, curve, zkey.vk_delta_2); - - await binFileUtils__namespace.endWriteSection(fd); - - -} - + await _iden3_binfileutils.startWriteSection(fd, 1); + await fd.writeULE32(1); + await _iden3_binfileutils.endWriteSection(fd); + const curve = await getCurveFromQ(zkey.q); + await _iden3_binfileutils.startWriteSection(fd, 2); + const primeQ = curve.q; + const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; + const primeR = curve.r; + const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; + await fd.writeULE32(n8q); + await _iden3_binfileutils.writeBigInt(fd, primeQ, n8q); + await fd.writeULE32(n8r); + await _iden3_binfileutils.writeBigInt(fd, primeR, n8r); + await fd.writeULE32(zkey.nVars); + await fd.writeULE32(zkey.nPublic); + await fd.writeULE32(zkey.domainSize); + await writeG1(fd, curve, zkey.vk_alpha_1); + await writeG1(fd, curve, zkey.vk_beta_1); + await writeG2(fd, curve, zkey.vk_beta_2); + await writeG2(fd, curve, zkey.vk_gamma_2); + await writeG1(fd, curve, zkey.vk_delta_1); + await writeG2(fd, curve, zkey.vk_delta_2); + await _iden3_binfileutils.endWriteSection(fd); +} async function writeG1(fd, curve, p) { - const buff = new Uint8Array(curve.G1.F.n8*2); - curve.G1.toRprLEM(buff, 0, p); - await fd.write(buff); + const buff = new Uint8Array(curve.G1.F.n8 * 2); + curve.G1.toRprLEM(buff, 0, p); + await fd.write(buff); } - async function writeG2(fd, curve, p) { - const buff = new Uint8Array(curve.G2.F.n8*2); - curve.G2.toRprLEM(buff, 0, p); - await fd.write(buff); + const buff = new Uint8Array(curve.G2.F.n8 * 2); + curve.G2.toRprLEM(buff, 0, p); + await fd.write(buff); } - async function readG1(fd, curve, toObject) { - const buff = await fd.read(curve.G1.F.n8*2); - const res = curve.G1.fromRprLEM(buff, 0); - return toObject ? curve.G1.toObject(res) : res; + const buff = await fd.read(curve.G1.F.n8 * 2); + const res = curve.G1.fromRprLEM(buff, 0); + return toObject ? curve.G1.toObject(res) : res; } - async function readG2(fd, curve, toObject) { - const buff = await fd.read(curve.G2.F.n8*2); - const res = curve.G2.fromRprLEM(buff, 0); - return toObject ? curve.G2.toObject(res) : res; + const buff = await fd.read(curve.G2.F.n8 * 2); + const res = curve.G2.fromRprLEM(buff, 0); + return toObject ? curve.G2.toObject(res) : res; } - - async function readHeader$1(fd, sections, toObject, options) { - // Read Header - ///////////////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 1); - const protocolId = await fd.readULE32(); - await binFileUtils__namespace.endReadSection(fd); - - if (protocolId === GROTH16_PROTOCOL_ID) { - return await readHeaderGroth16(fd, sections, toObject, options); - } else if (protocolId === PLONK_PROTOCOL_ID) { - return await readHeaderPlonk(fd, sections, toObject, options); - } else if (protocolId === FFLONK_PROTOCOL_ID) { - return await readHeaderFFlonk(fd, sections, toObject, options); - } else { - throw new Error("Protocol not supported: "); - } -} - - - - + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 1); + const protocolId = await fd.readULE32(); + await _iden3_binfileutils.endReadSection(fd); + if (protocolId === 1) return await readHeaderGroth16(fd, sections, toObject, options); + else if (protocolId === 2) return await readHeaderPlonk(fd, sections, toObject, options); + else if (protocolId === 10) return await readHeaderFFlonk(fd, sections, toObject, options); + else throw new Error("Protocol not supported: "); +} async function readHeaderGroth16(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "groth16"; - - // Read Groth Header - ///////////////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 2); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await binFileUtils__namespace.readBigInt(fd, n8q); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await binFileUtils__namespace.readBigInt(fd, n8r); - zkey.curve = await getCurveFromQ(zkey.q, options); - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.vk_alpha_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_beta_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_beta_2 = await readG2(fd, zkey.curve, toObject); - zkey.vk_gamma_2 = await readG2(fd, zkey.curve, toObject); - zkey.vk_delta_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_delta_2 = await readG2(fd, zkey.curve, toObject); - await binFileUtils__namespace.endReadSection(fd); - - return zkey; - -} - + const zkey = {}; + zkey.protocol = "groth16"; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 2); + const n8q = await fd.readULE32(); + zkey.n8q = n8q; + zkey.q = await _iden3_binfileutils.readBigInt(fd, n8q); + const n8r = await fd.readULE32(); + zkey.n8r = n8r; + zkey.r = await _iden3_binfileutils.readBigInt(fd, n8r); + zkey.curve = await getCurveFromQ(zkey.q, options); + zkey.nVars = await fd.readULE32(); + zkey.nPublic = await fd.readULE32(); + zkey.domainSize = await fd.readULE32(); + zkey.power = log2(zkey.domainSize); + zkey.vk_alpha_1 = await readG1(fd, zkey.curve, toObject); + zkey.vk_beta_1 = await readG1(fd, zkey.curve, toObject); + zkey.vk_beta_2 = await readG2(fd, zkey.curve, toObject); + zkey.vk_gamma_2 = await readG2(fd, zkey.curve, toObject); + zkey.vk_delta_1 = await readG1(fd, zkey.curve, toObject); + zkey.vk_delta_2 = await readG2(fd, zkey.curve, toObject); + await _iden3_binfileutils.endReadSection(fd); + return zkey; +} async function readHeaderPlonk(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "plonk"; - - // Read Plonk Header - ///////////////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 2); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await binFileUtils__namespace.readBigInt(fd, n8q); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await binFileUtils__namespace.readBigInt(fd, n8r); - zkey.curve = await getCurveFromQ(zkey.q, options); - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.nAdditions = await fd.readULE32(); - zkey.nConstraints = await fd.readULE32(); - zkey.k1 = await fd.read(n8r); - zkey.k2 = await fd.read(n8r); - - zkey.Qm = await readG1(fd, zkey.curve, toObject); - zkey.Ql = await readG1(fd, zkey.curve, toObject); - zkey.Qr = await readG1(fd, zkey.curve, toObject); - zkey.Qo = await readG1(fd, zkey.curve, toObject); - zkey.Qc = await readG1(fd, zkey.curve, toObject); - zkey.S1 = await readG1(fd, zkey.curve, toObject); - zkey.S2 = await readG1(fd, zkey.curve, toObject); - zkey.S3 = await readG1(fd, zkey.curve, toObject); - zkey.X_2 = await readG2(fd, zkey.curve, toObject); - - await binFileUtils__namespace.endReadSection(fd); - - return zkey; -} - + const zkey = {}; + zkey.protocol = "plonk"; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 2); + const n8q = await fd.readULE32(); + zkey.n8q = n8q; + zkey.q = await _iden3_binfileutils.readBigInt(fd, n8q); + const n8r = await fd.readULE32(); + zkey.n8r = n8r; + zkey.r = await _iden3_binfileutils.readBigInt(fd, n8r); + zkey.curve = await getCurveFromQ(zkey.q, options); + zkey.nVars = await fd.readULE32(); + zkey.nPublic = await fd.readULE32(); + zkey.domainSize = await fd.readULE32(); + zkey.power = log2(zkey.domainSize); + zkey.nAdditions = await fd.readULE32(); + zkey.nConstraints = await fd.readULE32(); + zkey.k1 = await fd.read(n8r); + zkey.k2 = await fd.read(n8r); + zkey.Qm = await readG1(fd, zkey.curve, toObject); + zkey.Ql = await readG1(fd, zkey.curve, toObject); + zkey.Qr = await readG1(fd, zkey.curve, toObject); + zkey.Qo = await readG1(fd, zkey.curve, toObject); + zkey.Qc = await readG1(fd, zkey.curve, toObject); + zkey.S1 = await readG1(fd, zkey.curve, toObject); + zkey.S2 = await readG1(fd, zkey.curve, toObject); + zkey.S3 = await readG1(fd, zkey.curve, toObject); + zkey.X_2 = await readG2(fd, zkey.curve, toObject); + await _iden3_binfileutils.endReadSection(fd); + return zkey; +} async function readHeaderFFlonk(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "fflonk"; - zkey.protocolId = FFLONK_PROTOCOL_ID; - - await binFileUtils__namespace.startReadUniqueSection(fd, sections, ZKEY_FF_HEADER_SECTION); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await binFileUtils__namespace.readBigInt(fd, n8q); - zkey.curve = await getCurveFromQ(zkey.q, options); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await binFileUtils__namespace.readBigInt(fd, n8r); - - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.nAdditions = await fd.readULE32(); - zkey.nConstraints = await fd.readULE32(); - - zkey.k1 = await fd.read(n8r); - zkey.k2 = await fd.read(n8r); - - zkey.w3 = await fd.read(n8r); - zkey.w4 = await fd.read(n8r); - zkey.w8 = await fd.read(n8r); - zkey.wr = await fd.read(n8r); - - zkey.X_2 = await readG2(fd, zkey.curve, toObject); - - zkey.C0 = await readG1(fd, zkey.curve, toObject); - - await binFileUtils__namespace.endReadSection(fd); - - return zkey; -} - + const zkey = {}; + zkey.protocol = "fflonk"; + zkey.protocolId = 10; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 2); + const n8q = await fd.readULE32(); + zkey.n8q = n8q; + zkey.q = await _iden3_binfileutils.readBigInt(fd, n8q); + zkey.curve = await getCurveFromQ(zkey.q, options); + const n8r = await fd.readULE32(); + zkey.n8r = n8r; + zkey.r = await _iden3_binfileutils.readBigInt(fd, n8r); + zkey.nVars = await fd.readULE32(); + zkey.nPublic = await fd.readULE32(); + zkey.domainSize = await fd.readULE32(); + zkey.power = log2(zkey.domainSize); + zkey.nAdditions = await fd.readULE32(); + zkey.nConstraints = await fd.readULE32(); + zkey.k1 = await fd.read(n8r); + zkey.k2 = await fd.read(n8r); + zkey.w3 = await fd.read(n8r); + zkey.w4 = await fd.read(n8r); + zkey.w8 = await fd.read(n8r); + zkey.wr = await fd.read(n8r); + zkey.X_2 = await readG2(fd, zkey.curve, toObject); + zkey.C0 = await readG1(fd, zkey.curve, toObject); + await _iden3_binfileutils.endReadSection(fd); + return zkey; +} async function readZKey(fileName, toObject) { - const {fd, sections} = await binFileUtils__namespace.readBinFile(fileName, "zkey", 1); - - const zkey = await readHeader$1(fd, sections, toObject); - - const Fr = new ffjavascript.F1Field(zkey.r); - const Rr = ffjavascript.Scalar.mod(ffjavascript.Scalar.shl(1, zkey.n8r*8), zkey.r); - const Rri = Fr.inv(Rr); - const Rri2 = Fr.mul(Rri, Rri); - - let curve = await getCurveFromQ(zkey.q); - - // Read IC Section - /////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 3); - zkey.IC = []; - for (let i=0; i<= zkey.nPublic; i++) { - const P = await readG1(fd, curve, toObject); - zkey.IC.push(P); - } - await binFileUtils__namespace.endReadSection(fd); - - - // Read Coefs - /////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 4); - const nCCoefs = await fd.readULE32(); - zkey.ccoefs = []; - for (let i=0; i0) { - const paramsBuff = new Uint8Array(params); - await fd.writeULE32(paramsBuff.byteLength); - await fd.write(paramsBuff); - } else { - await fd.writeULE32(0); - } - -} - + await writeG1(fd, curve, c.deltaAfter); + await writeG1(fd, curve, c.delta.g1_s); + await writeG1(fd, curve, c.delta.g1_sx); + await writeG2(fd, curve, c.delta.g2_spx); + await fd.write(c.transcript); + await fd.writeULE32(c.type || 0); + const params = []; + if (c.name) { + params.push(1); + const nameData = new TextEncoder("utf-8").encode(c.name.substring(0, 64)); + params.push(nameData.byteLength); + for (let i = 0; i < nameData.byteLength; i++) params.push(nameData[i]); + } + if (c.type == 1) { + params.push(2); + params.push(c.numIterationsExp); + params.push(3); + params.push(c.beaconHash.byteLength); + for (let i = 0; i < c.beaconHash.byteLength; i++) params.push(c.beaconHash[i]); + } + if (params.length > 0) { + const paramsBuff = new Uint8Array(params); + await fd.writeULE32(paramsBuff.byteLength); + await fd.write(paramsBuff); + } else await fd.writeULE32(0); +} async function writeMPCParams(fd, curve, mpcParams) { - await binFileUtils__namespace.startWriteSection(fd, 10); - await fd.write(mpcParams.csHash); - await fd.writeULE32(mpcParams.contributions.length); - for (let i=0; i. -*/ - - + const { fd: fdZKey, sections: sectionsZKey } = await _iden3_binfileutils.readBinFile(zkeyName, "zkey", 2); + const zkey = await readHeader$1(fdZKey, sectionsZKey); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkey.q); + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + const mpcParams = await readMPCParams(fdZKey, curve, sectionsZKey); + const fdMPCParams = await fastfile.createOverride(mpcparamsName); + await writeG1(zkey.vk_alpha_1); + await writeG1(zkey.vk_beta_1); + await writeG2(zkey.vk_beta_2); + await writeG2(zkey.vk_gamma_2); + await writeG1(zkey.vk_delta_1); + await writeG2(zkey.vk_delta_2); + let buffBasesIC; + buffBasesIC = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 3); + buffBasesIC = await curve.G1.batchLEMtoU(buffBasesIC); + await writePointArray("G1", buffBasesIC); + const buffBasesH_Lodd = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 9); + let buffBasesH_Tau; + buffBasesH_Tau = await curve.G1.fft(buffBasesH_Lodd, "affine", "jacobian", logger); + buffBasesH_Tau = await curve.G1.batchApplyKey(buffBasesH_Tau, curve.Fr.neg(curve.Fr.e(2)), curve.Fr.w[zkey.power + 1], "jacobian", "affine", logger); + buffBasesH_Tau = buffBasesH_Tau.slice(0, buffBasesH_Tau.byteLength - sG1); + buffBasesH_Tau = await curve.G1.batchLEMtoU(buffBasesH_Tau); + await writePointArray("G1", buffBasesH_Tau); + let buffBasesC; + buffBasesC = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 8); + buffBasesC = await curve.G1.batchLEMtoU(buffBasesC); + await writePointArray("G1", buffBasesC); + let buffBasesA; + buffBasesA = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 5); + buffBasesA = await curve.G1.batchLEMtoU(buffBasesA); + await writePointArray("G1", buffBasesA); + let buffBasesB1; + buffBasesB1 = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 6); + buffBasesB1 = await curve.G1.batchLEMtoU(buffBasesB1); + await writePointArray("G1", buffBasesB1); + let buffBasesB2; + buffBasesB2 = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 7); + buffBasesB2 = await curve.G2.batchLEMtoU(buffBasesB2); + await writePointArray("G2", buffBasesB2); + await fdMPCParams.write(mpcParams.csHash); + await writeU32(mpcParams.contributions.length); + for (let i = 0; i < mpcParams.contributions.length; i++) { + const c = mpcParams.contributions[i]; + await writeG1(c.deltaAfter); + await writeG1(c.delta.g1_s); + await writeG1(c.delta.g1_sx); + await writeG2(c.delta.g2_spx); + await fdMPCParams.write(c.transcript); + } + await fdZKey.close(); + await fdMPCParams.close(); + async function writeG1(P) { + const buff = new Uint8Array(sG1); + curve.G1.toRprUncompressed(buff, 0, P); + await fdMPCParams.write(buff); + } + async function writeG2(P) { + const buff = new Uint8Array(sG2); + curve.G2.toRprUncompressed(buff, 0, P); + await fdMPCParams.write(buff); + } + async function writePointArray(groupName, buff) { + let sG; + if (groupName == "G1") sG = sG1; + else sG = sG2; + const buffSize = /* @__PURE__ */ new Uint8Array(4); + new DataView(buffSize.buffer, buffSize.byteOffset, buffSize.byteLength).setUint32(0, buff.byteLength / sG, false); + await fdMPCParams.write(buffSize); + await fdMPCParams.write(buff); + } + async function writeU32(n) { + const buffSize = /* @__PURE__ */ new Uint8Array(4); + new DataView(buffSize.buffer, buffSize.byteOffset, buffSize.byteLength).setUint32(0, n, false); + await fdMPCParams.write(buffSize); + } +} +//#endregion +//#region src/zkey_import_bellman.js async function phase2importMPCParams(zkeyNameOld, mpcparamsName, zkeyNameNew, name, logger) { - - const {fd: fdZKeyOld, sections: sectionsZKeyOld} = await binFileUtils__namespace.readBinFile(zkeyNameOld, "zkey", 2); - const zkeyHeader = await readHeader$1(fdZKeyOld, sectionsZKeyOld, false); - if (zkeyHeader.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkeyHeader.q); - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - const oldMPCParams = await readMPCParams(fdZKeyOld, curve, sectionsZKeyOld); - const newMPCParams = {}; - - const fdMPCParams = await fastFile__namespace.readExisting(mpcparamsName); - - fdMPCParams.pos = - sG1*3 + sG2*3 + // vKey - 8 + sG1*zkeyHeader.nVars + // IC + C - 4 + sG1*(zkeyHeader.domainSize-1) + // H - 4 + sG1*zkeyHeader.nVars + // A - 4 + sG1*zkeyHeader.nVars + // B1 - 4 + sG2*zkeyHeader.nVars; // B2 - - // csHash - newMPCParams.csHash = await fdMPCParams.read(64); - - const nContributions = await fdMPCParams.readUBE32(); - newMPCParams.contributions = []; - for (let i=0; i newMPCParams.contributions.length) { - if (logger) logger.error("The impoerted file does not include new contributions"); - return false; - } - - for (let i=0; i. -*/ - -const sameRatio = sameRatio$2; - - - + const { fd: fdZKeyOld, sections: sectionsZKeyOld } = await _iden3_binfileutils.readBinFile(zkeyNameOld, "zkey", 2); + const zkeyHeader = await readHeader$1(fdZKeyOld, sectionsZKeyOld, false); + if (zkeyHeader.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkeyHeader.q); + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + const oldMPCParams = await readMPCParams(fdZKeyOld, curve, sectionsZKeyOld); + const newMPCParams = {}; + const fdMPCParams = await fastfile.readExisting(mpcparamsName); + fdMPCParams.pos = sG1 * 3 + sG2 * 3 + 8 + sG1 * zkeyHeader.nVars + 4 + sG1 * (zkeyHeader.domainSize - 1) + 4 + sG1 * zkeyHeader.nVars + 4 + sG1 * zkeyHeader.nVars + 4 + sG2 * zkeyHeader.nVars; + newMPCParams.csHash = await fdMPCParams.read(64); + const nContributions = await fdMPCParams.readUBE32(); + newMPCParams.contributions = []; + for (let i = 0; i < nContributions; i++) { + const c = { delta: {} }; + c.deltaAfter = await readG1(fdMPCParams); + c.delta.g1_s = await readG1(fdMPCParams); + c.delta.g1_sx = await readG1(fdMPCParams); + c.delta.g2_spx = await readG2(fdMPCParams); + c.transcript = await fdMPCParams.read(64); + if (i < oldMPCParams.contributions.length) { + c.type = oldMPCParams.contributions[i].type; + if (c.type == 1) { + c.beaconHash = oldMPCParams.contributions[i].beaconHash; + c.numIterationsExp = oldMPCParams.contributions[i].numIterationsExp; + } + if (oldMPCParams.contributions[i].name) c.name = oldMPCParams.contributions[i].name; + } + newMPCParams.contributions.push(c); + } + if (!hashIsEqual(newMPCParams.csHash, oldMPCParams.csHash)) { + if (logger) logger.error("Hash of the original circuit does not match with the MPC one"); + return false; + } + if (oldMPCParams.contributions.length > newMPCParams.contributions.length) { + if (logger) logger.error("The impoerted file does not include new contributions"); + return false; + } + for (let i = 0; i < oldMPCParams.contributions.length; i++) if (!contributionIsEqual(oldMPCParams.contributions[i], newMPCParams.contributions[i])) { + if (logger) logger.error(`Previous contribution ${i} does not match`); + return false; + } + if (name) for (let i = oldMPCParams.contributions.length; i < newMPCParams.contributions.length; i++) newMPCParams.contributions[i].name = name; + const fdZKeyNew = await _iden3_binfileutils.createBinFile(zkeyNameNew, "zkey", 1, 10); + fdMPCParams.pos = 0; + fdMPCParams.pos += sG1; + fdMPCParams.pos += sG1; + fdMPCParams.pos += sG2; + fdMPCParams.pos += sG2; + zkeyHeader.vk_delta_1 = await readG1(fdMPCParams); + zkeyHeader.vk_delta_2 = await readG2(fdMPCParams); + await writeHeader(fdZKeyNew, zkeyHeader); + if (await fdMPCParams.readUBE32() != zkeyHeader.nPublic + 1) { + if (logger) logger.error("Invalid number of points in IC"); + await fdZKeyNew.discard(); + return false; + } + fdMPCParams.pos += sG1 * (zkeyHeader.nPublic + 1); + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 3); + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 4); + if (await fdMPCParams.readUBE32() != zkeyHeader.domainSize - 1) { + if (logger) logger.error("Invalid number of points in H"); + await fdZKeyNew.discard(); + return false; + } + let buffH; + const buffTauU = await fdMPCParams.read(sG1 * (zkeyHeader.domainSize - 1)); + const buffTauLEM = await curve.G1.batchUtoLEM(buffTauU); + buffH = new Uint8Array(zkeyHeader.domainSize * sG1); + buffH.set(buffTauLEM); + curve.G1.toRprLEM(buffH, sG1 * (zkeyHeader.domainSize - 1), curve.G1.zeroAffine); + const n2Inv = curve.Fr.neg(curve.Fr.inv(curve.Fr.e(2))); + const wInv = curve.Fr.inv(curve.Fr.w[zkeyHeader.power + 1]); + buffH = await curve.G1.batchApplyKey(buffH, n2Inv, wInv, "affine", "jacobian", logger); + buffH = await curve.G1.ifft(buffH, "jacobian", "affine", logger); + await _iden3_binfileutils.startWriteSection(fdZKeyNew, 9); + await fdZKeyNew.write(buffH); + await _iden3_binfileutils.endWriteSection(fdZKeyNew); + if (await fdMPCParams.readUBE32() != zkeyHeader.nVars - zkeyHeader.nPublic - 1) { + if (logger) logger.error("Invalid number of points in L"); + await fdZKeyNew.discard(); + return false; + } + let buffL; + buffL = await fdMPCParams.read(sG1 * (zkeyHeader.nVars - zkeyHeader.nPublic - 1)); + buffL = await curve.G1.batchUtoLEM(buffL); + await _iden3_binfileutils.startWriteSection(fdZKeyNew, 8); + await fdZKeyNew.write(buffL); + await _iden3_binfileutils.endWriteSection(fdZKeyNew); + if (await fdMPCParams.readUBE32() != zkeyHeader.nVars) { + if (logger) logger.error("Invalid number of points in A"); + await fdZKeyNew.discard(); + return false; + } + fdMPCParams.pos += sG1 * zkeyHeader.nVars; + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 5); + if (await fdMPCParams.readUBE32() != zkeyHeader.nVars) { + if (logger) logger.error("Invalid number of points in B1"); + await fdZKeyNew.discard(); + return false; + } + fdMPCParams.pos += sG1 * zkeyHeader.nVars; + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 6); + if (await fdMPCParams.readUBE32() != zkeyHeader.nVars) { + if (logger) logger.error("Invalid number of points in B2"); + await fdZKeyNew.discard(); + return false; + } + fdMPCParams.pos += sG2 * zkeyHeader.nVars; + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 7); + await writeMPCParams(fdZKeyNew, curve, newMPCParams); + await fdMPCParams.close(); + await fdZKeyNew.close(); + await fdZKeyOld.close(); + return true; + async function readG1(fd) { + const buff = await fd.read(curve.G1.F.n8 * 2); + return curve.G1.fromRprUncompressed(buff, 0); + } + async function readG2(fd) { + const buff = await fd.read(curve.G2.F.n8 * 2); + return curve.G2.fromRprUncompressed(buff, 0); + } + function contributionIsEqual(c1, c2) { + if (!curve.G1.eq(c1.deltaAfter, c2.deltaAfter)) return false; + if (!curve.G1.eq(c1.delta.g1_s, c2.delta.g1_s)) return false; + if (!curve.G1.eq(c1.delta.g1_sx, c2.delta.g1_sx)) return false; + if (!curve.G2.eq(c1.delta.g2_spx, c2.delta.g2_spx)) return false; + if (!hashIsEqual(c1.transcript, c2.transcript)) return false; + return true; + } +} +//#endregion +//#region src/zkey_verify_frominit.js +var sameRatio = sameRatio$2; async function phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger) { - - let sr; - const {fd, sections} = await binFileUtils__namespace.readBinFile(zkeyFileName, "zkey", 2); - const zkey = await readHeader$1(fd, sections, false); - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkey.q); - const sG1 = curve.G1.F.n8*2; - - const mpcParams = await readMPCParams(fd, curve, sections); - - const accumulatedHasher = blake2_js.blake2b.create({ dkLen: 64 }); - accumulatedHasher.update(mpcParams.csHash); - let curDelta = curve.G1.g; - for (let i=0; i=0; i--) { - const c = mpcParams.contributions[i]; - if (logger) logger.info("-------------------------"); - if (logger) logger.info(formatHash(c.contributionHash, `contribution #${i+1} ${c.name ? c.name : ""}:`)); - if (c.type == 1) { - if (logger) logger.info(`Beacon generator: ${byteArray2hex(c.beaconHash)}`); - if (logger) logger.info(`Beacon iterations Exp: ${c.numIterationsExp}`); - } - } - if (logger) logger.info("-------------------------"); - - if (logger) logger.info("ZKey Ok!"); - - return true; - - - async function sectionHasSameRatio(groupName, fd1, sections1, fd2, sections2, idSection, g2sp, g2spx, sectionName) { - const MAX_CHUNK_SIZE = 1<<20; - const G = curve[groupName]; - const sG = G.F.n8*2; - await binFileUtils__namespace.startReadUniqueSection(fd1, sections1, idSection); - await binFileUtils__namespace.startReadUniqueSection(fd2, sections2, idSection); - - let R1 = G.zero; - let R2 = G.zero; - - const nPoints = sections1[idSection][0].size / sG; - - for (let i=0; i. -*/ - - + let sr; + const { fd, sections } = await _iden3_binfileutils.readBinFile(zkeyFileName, "zkey", 2); + const zkey = await readHeader$1(fd, sections, false); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkey.q); + const sG1 = curve.G1.F.n8 * 2; + const mpcParams = await readMPCParams(fd, curve, sections); + const accumulatedHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + accumulatedHasher.update(mpcParams.csHash); + let curDelta = curve.G1.g; + for (let i = 0; i < mpcParams.contributions.length; i++) { + const c = mpcParams.contributions[i]; + const ourHasher = cloneHasher(accumulatedHasher); + hashG1(ourHasher, curve, c.delta.g1_s); + hashG1(ourHasher, curve, c.delta.g1_sx); + if (!hashIsEqual(ourHasher.digest(), c.transcript)) { + console.log(`INVALID(${i}): Inconsistent transcript `); + return false; + } + const delta_g2_sp = hashToG2(curve, c.transcript); + sr = await sameRatio(curve, c.delta.g1_s, c.delta.g1_sx, delta_g2_sp, c.delta.g2_spx); + if (sr !== true) { + console.log(`INVALID(${i}): public key G1 and G2 do not have the same ration `); + return false; + } + sr = await sameRatio(curve, curDelta, c.deltaAfter, delta_g2_sp, c.delta.g2_spx); + if (sr !== true) { + console.log(`INVALID(${i}): deltaAfter does not fillow the public key `); + return false; + } + if (c.type == 1) { + const rng = await rngFromBeaconParams(c.beaconHash, c.numIterationsExp); + const expected_prvKey = curve.Fr.fromRng(rng); + const expected_g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + const expected_g1_sx = curve.G1.toAffine(curve.G1.timesFr(expected_g1_s, expected_prvKey)); + if (curve.G1.eq(expected_g1_s, c.delta.g1_s) !== true) { + console.log(`INVALID(${i}): Key of the beacon does not match. g1_s `); + return false; + } + if (curve.G1.eq(expected_g1_sx, c.delta.g1_sx) !== true) { + console.log(`INVALID(${i}): Key of the beacon does not match. g1_sx `); + return false; + } + } + hashPubKey(accumulatedHasher, curve, c); + const contributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hashPubKey(contributionHasher, curve, c); + c.contributionHash = contributionHasher.digest(); + curDelta = c.deltaAfter; + } + const { fd: fdInit, sections: sectionsInit } = await _iden3_binfileutils.readBinFile(initFileName, "zkey", 2); + const zkeyInit = await readHeader$1(fdInit, sectionsInit, false); + if (zkeyInit.protocol != "groth16") throw new Error("zkeyinit file is not groth16"); + if (!ffjavascript.Scalar.eq(zkeyInit.q, zkey.q) || !ffjavascript.Scalar.eq(zkeyInit.r, zkey.r) || zkeyInit.n8q != zkey.n8q || zkeyInit.n8r != zkey.n8r) { + if (logger) logger.error("INVALID: Different curves"); + return false; + } + if (zkeyInit.nVars != zkey.nVars || zkeyInit.nPublic != zkey.nPublic || zkeyInit.domainSize != zkey.domainSize) { + if (logger) logger.error("INVALID: Different circuit parameters"); + return false; + } + if (!curve.G1.eq(zkey.vk_alpha_1, zkeyInit.vk_alpha_1)) { + if (logger) logger.error("INVALID: Invalid alpha1"); + return false; + } + if (!curve.G1.eq(zkey.vk_beta_1, zkeyInit.vk_beta_1)) { + if (logger) logger.error("INVALID: Invalid beta1"); + return false; + } + if (!curve.G2.eq(zkey.vk_beta_2, zkeyInit.vk_beta_2)) { + if (logger) logger.error("INVALID: Invalid beta2"); + return false; + } + if (!curve.G2.eq(zkey.vk_gamma_2, zkeyInit.vk_gamma_2)) { + if (logger) logger.error("INVALID: Invalid gamma2"); + return false; + } + if (!curve.G1.eq(zkey.vk_delta_1, curDelta)) { + if (logger) logger.error("INVALID: Invalid delta1"); + return false; + } + sr = await sameRatio(curve, curve.G1.g, curDelta, curve.G2.g, zkey.vk_delta_2); + if (sr !== true) { + if (logger) logger.error("INVALID: Invalid delta2"); + return false; + } + const mpcParamsInit = await readMPCParams(fdInit, curve, sectionsInit); + if (!hashIsEqual(mpcParams.csHash, mpcParamsInit.csHash)) { + if (logger) logger.error("INVALID: Circuit does not match"); + return false; + } + if (sections[8][0].size != sG1 * (zkey.nVars - zkey.nPublic - 1)) { + if (logger) logger.error("INVALID: Invalid L section size"); + return false; + } + if (sections[9][0].size != sG1 * zkey.domainSize) { + if (logger) logger.error("INVALID: Invalid H section size"); + return false; + } + let ss; + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 3); + if (!ss) { + if (logger) logger.error("INVALID: IC section is not identical"); + return false; + } + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 4); + if (!ss) { + if (logger) logger.error("Coeffs section is not identical"); + return false; + } + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 5); + if (!ss) { + if (logger) logger.error("A section is not identical"); + return false; + } + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 6); + if (!ss) { + if (logger) logger.error("B1 section is not identical"); + return false; + } + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 7); + if (!ss) { + if (logger) logger.error("B2 section is not identical"); + return false; + } + sr = await sectionHasSameRatio("G1", fdInit, sectionsInit, fd, sections, 8, zkey.vk_delta_2, zkeyInit.vk_delta_2, "L section"); + if (sr !== true) { + if (logger) logger.error("L section does not match"); + return false; + } + sr = await sameRatioH(); + if (sr !== true) { + if (logger) logger.error("H section does not match"); + return false; + } + if (logger) logger.info(formatHash(mpcParams.csHash, "Circuit Hash: ")); + await fd.close(); + await fdInit.close(); + for (let i = mpcParams.contributions.length - 1; i >= 0; i--) { + const c = mpcParams.contributions[i]; + if (logger) logger.info("-------------------------"); + if (logger) logger.info(formatHash(c.contributionHash, `contribution #${i + 1} ${c.name ? c.name : ""}:`)); + if (c.type == 1) { + if (logger) logger.info(`Beacon generator: ${byteArray2hex(c.beaconHash)}`); + if (logger) logger.info(`Beacon iterations Exp: ${c.numIterationsExp}`); + } + } + if (logger) logger.info("-------------------------"); + if (logger) logger.info("ZKey Ok!"); + return true; + async function sectionHasSameRatio(groupName, fd1, sections1, fd2, sections2, idSection, g2sp, g2spx, sectionName) { + const MAX_CHUNK_SIZE = 1 << 20; + const G = curve[groupName]; + const sG = G.F.n8 * 2; + await _iden3_binfileutils.startReadUniqueSection(fd1, sections1, idSection); + await _iden3_binfileutils.startReadUniqueSection(fd2, sections2, idSection); + let R1 = G.zero; + let R2 = G.zero; + const nPoints = sections1[idSection][0].size / sG; + for (let i = 0; i < nPoints; i += MAX_CHUNK_SIZE) { + if (logger) logger.debug(`Same ratio check ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, MAX_CHUNK_SIZE); + const bases1 = await fd1.read(n * sG); + const bases2 = await fd2.read(n * sG); + const scalars = getRandomBytes(4 * n); + const r1 = await G.multiExpAffine(bases1, scalars); + const r2 = await G.multiExpAffine(bases2, scalars); + R1 = G.add(R1, r1); + R2 = G.add(R2, r2); + } + await _iden3_binfileutils.endReadSection(fd1); + await _iden3_binfileutils.endReadSection(fd2); + if (nPoints == 0) return true; + sr = await sameRatio(curve, R1, R2, g2sp, g2spx); + if (sr !== true) return false; + return true; + } + async function sameRatioH() { + const MAX_CHUNK_SIZE = 1 << 20; + const G = curve.G1; + const Fr = curve.Fr; + const sG = G.F.n8 * 2; + const { fd: fdPTau, sections: sectionsPTau } = await _iden3_binfileutils.readBinFile(pTauFileName, "ptau", 1); + let buff_r = new ffjavascript.BigBuffer(zkey.domainSize * zkey.n8r); + const seed = new Array(8); + for (let i = 0; i < 8; i++) seed[i] = readUInt32BE(getRandomBytes(4), 0); + const rng = new ffjavascript.ChaCha(seed); + for (let i = 0; i < zkey.domainSize - 1; i++) { + const e = Fr.fromRng(rng); + Fr.toRprLE(buff_r, i * zkey.n8r, e); + } + Fr.toRprLE(buff_r, (zkey.domainSize - 1) * zkey.n8r, Fr.zero); + let R1 = G.zero; + for (let i = 0; i < zkey.domainSize; i += MAX_CHUNK_SIZE) { + if (logger) logger.debug(`H Verification(tau): ${i}/${zkey.domainSize}`); + const n = Math.min(zkey.domainSize - i, MAX_CHUNK_SIZE); + const buffB = await batchSubtract(await fdPTau.read(sG * n, sectionsPTau[2][0].p + zkey.domainSize * sG + i * sG), await fdPTau.read(sG * n, sectionsPTau[2][0].p + i * sG)); + const buffS = buff_r.slice(i * zkey.n8r, (i + n) * zkey.n8r); + const r = await G.multiExpAffine(buffB, buffS); + R1 = G.add(R1, r); + } + buff_r = await Fr.batchToMontgomery(buff_r); + let first; + if (zkey.power < Fr.s) first = Fr.neg(Fr.e(2)); + else { + const small_m = 2 ** Fr.s; + const shift_to_small_m = Fr.exp(Fr.shift, small_m); + first = Fr.sub(shift_to_small_m, Fr.one); + } + const inc = zkey.power < Fr.s ? Fr.w[zkey.power + 1] : Fr.shift; + buff_r = await Fr.batchApplyKey(buff_r, first, inc); + buff_r = await Fr.fft(buff_r); + buff_r = await Fr.batchFromMontgomery(buff_r); + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 9); + let R2 = G.zero; + for (let i = 0; i < zkey.domainSize; i += MAX_CHUNK_SIZE) { + if (logger) logger.debug(`H Verification(lagrange): ${i}/${zkey.domainSize}`); + const n = Math.min(zkey.domainSize - i, MAX_CHUNK_SIZE); + const buff = await fd.read(sG * n); + const buffS = buff_r.slice(i * zkey.n8r, (i + n) * zkey.n8r); + const r = await G.multiExpAffine(buff, buffS); + R2 = G.add(R2, r); + } + await _iden3_binfileutils.endReadSection(fd); + sr = await sameRatio(curve, R1, R2, zkey.vk_delta_2, zkeyInit.vk_delta_2); + if (sr !== true) return false; + return true; + } + async function batchSubtract(buff1, buff2) { + const sG = curve.G1.F.n8 * 2; + const nPoints = buff1.byteLength / sG; + const concurrency = curve.tm.concurrency; + const nPointsPerThread = Math.floor(nPoints / concurrency); + const opPromises = []; + for (let i = 0; i < concurrency; i++) { + let n; + if (i < concurrency - 1) n = nPointsPerThread; + else n = nPoints - i * nPointsPerThread; + if (n == 0) continue; + const subBuff1 = buff1.slice(i * nPointsPerThread * sG1, (i * nPointsPerThread + n) * sG1); + const subBuff2 = buff2.slice(i * nPointsPerThread * sG1, (i * nPointsPerThread + n) * sG1); + opPromises.push(batchSubtractThread(subBuff1, subBuff2)); + } + const result = await Promise.all(opPromises); + const fullBuffOut = new Uint8Array(nPoints * sG); + let p = 0; + for (let i = 0; i < result.length; i++) { + fullBuffOut.set(result[i][0], p); + p += result[i][0].byteLength; + } + return fullBuffOut; + } + async function batchSubtractThread(buff1, buff2) { + const sG1 = curve.G1.F.n8 * 2; + const sGmid = curve.G1.F.n8 * 3; + const nPoints = buff1.byteLength / sG1; + const task = []; + task.push({ + cmd: "ALLOCSET", + var: 0, + buff: buff1 + }); + task.push({ + cmd: "ALLOCSET", + var: 1, + buff: buff2 + }); + task.push({ + cmd: "ALLOC", + var: 2, + len: nPoints * sGmid + }); + for (let i = 0; i < nPoints; i++) task.push({ + cmd: "CALL", + fnName: "g1m_subAffine", + params: [ + { + var: 0, + offset: i * sG1 + }, + { + var: 1, + offset: i * sG1 + }, + { + var: 2, + offset: i * sGmid + } + ] + }); + task.push({ + cmd: "CALL", + fnName: "g1m_batchToAffine", + params: [ + { var: 2 }, + { val: nPoints }, + { var: 2 } + ] + }); + task.push({ + cmd: "GET", + out: 0, + var: 2, + len: nPoints * sG1 + }); + return await curve.tm.queueAction(task); + } +} +//#endregion +//#region src/zkey_verify_fromr1cs.js async function phase2verifyFromR1cs(r1csFileName, pTauFileName, zkeyFileName, logger) { - - // const initFileName = "~" + zkeyFileName + ".init"; - const initFileName = {type: "bigMem"}; - await newZKey(r1csFileName, pTauFileName, initFileName, logger); - - return await phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const initFileName = { type: "bigMem" }; + await newZKey(r1csFileName, pTauFileName, initFileName, logger); + return await phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger); +} +//#endregion +//#region src/zkey_contribute.js async function phase2contribute(zkeyNameOld, zkeyNameNew, name, entropy, logger) { - - const {fd: fdOld, sections: sections} = await binFileUtils__namespace.readBinFile(zkeyNameOld, "zkey", 2); - const zkey = await readHeader$1(fdOld, sections); - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkey.q); - - const mpcParams = await readMPCParams(fdOld, curve, sections); - - const fdNew = await binFileUtils__namespace.createBinFile(zkeyNameNew, "zkey", 1, 10); - - - const rng = await getRandomRng(entropy); - - const transcriptHasher = blake2_js.blake2b.create({ dkLen: 64 }); - transcriptHasher.update(mpcParams.csHash); - for (let i=0; i. -*/ - - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(zkeyNameOld, "zkey", 2); + const zkey = await readHeader$1(fdOld, sections); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkey.q); + const mpcParams = await readMPCParams(fdOld, curve, sections); + const fdNew = await _iden3_binfileutils.createBinFile(zkeyNameNew, "zkey", 1, 10); + const rng = await getRandomRng(entropy); + const transcriptHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + transcriptHasher.update(mpcParams.csHash); + for (let i = 0; i < mpcParams.contributions.length; i++) hashPubKey(transcriptHasher, curve, mpcParams.contributions[i]); + const curContribution = {}; + curContribution.delta = {}; + curContribution.delta.prvKey = curve.Fr.fromRng(rng); + curContribution.delta.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + curContribution.delta.g1_sx = curve.G1.toAffine(curve.G1.timesFr(curContribution.delta.g1_s, curContribution.delta.prvKey)); + hashG1(transcriptHasher, curve, curContribution.delta.g1_s); + hashG1(transcriptHasher, curve, curContribution.delta.g1_sx); + curContribution.transcript = transcriptHasher.digest(); + curContribution.delta.g2_sp = hashToG2(curve, curContribution.transcript); + curContribution.delta.g2_spx = curve.G2.toAffine(curve.G2.timesFr(curContribution.delta.g2_sp, curContribution.delta.prvKey)); + zkey.vk_delta_1 = curve.G1.timesFr(zkey.vk_delta_1, curContribution.delta.prvKey); + zkey.vk_delta_2 = curve.G2.timesFr(zkey.vk_delta_2, curContribution.delta.prvKey); + curContribution.deltaAfter = zkey.vk_delta_1; + curContribution.type = 0; + if (name) curContribution.name = name; + mpcParams.contributions.push(curContribution); + await writeHeader(fdNew, zkey); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + const invDelta = curve.Fr.inv(curContribution.delta.prvKey); + await applyKeyToSection(fdOld, sections, fdNew, 8, curve, "G1", invDelta, curve.Fr.e(1), "L Section", logger); + await applyKeyToSection(fdOld, sections, fdNew, 9, curve, "G1", invDelta, curve.Fr.e(1), "H Section", logger); + await writeMPCParams(fdNew, curve, mpcParams); + await fdOld.close(); + await fdNew.close(); + const contributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hashPubKey(contributionHasher, curve, curContribution); + const contributionHash = contributionHasher.digest(); + if (logger) logger.info(formatHash(mpcParams.csHash, "Circuit Hash: ")); + if (logger) logger.info(formatHash(contributionHash, "Contribution Hash: ")); + return contributionHash; +} +//#endregion +//#region src/zkey_beacon.js async function beacon(zkeyNameOld, zkeyNameNew, name, beaconHashStr, numIterationsExp, logger) { - const beaconHash = hex2ByteArray(beaconHashStr); - if ( (beaconHash.byteLength == 0) - || (beaconHash.byteLength*2 !=beaconHashStr.length)) - { - if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); - return false; - } - if (beaconHash.length>=256) { - if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); - return false; - } - - numIterationsExp = parseInt(numIterationsExp); - if ((numIterationsExp<10)||(numIterationsExp>63)) { - if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); - return false; - } - - - const {fd: fdOld, sections: sections} = await binFileUtils__namespace.readBinFile(zkeyNameOld, "zkey", 2); - const zkey = await readHeader$1(fdOld, sections); - - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - - const curve = await getCurveFromQ(zkey.q); - - const mpcParams = await readMPCParams(fdOld, curve, sections); - - const fdNew = await binFileUtils__namespace.createBinFile(zkeyNameNew, "zkey", 1, 10); - - const rng = await rngFromBeaconParams(beaconHash, numIterationsExp); - - const transcriptHasher = blake2_js.blake2b.create({ dkLen: 64 }); transcriptHasher.update(mpcParams.csHash); - for (let i=0; i= 256) { + if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); + return false; + } + numIterationsExp = parseInt(numIterationsExp); + if (numIterationsExp < 10 || numIterationsExp > 63) { + if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); + return false; + } + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(zkeyNameOld, "zkey", 2); + const zkey = await readHeader$1(fdOld, sections); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkey.q); + const mpcParams = await readMPCParams(fdOld, curve, sections); + const fdNew = await _iden3_binfileutils.createBinFile(zkeyNameNew, "zkey", 1, 10); + const rng = await rngFromBeaconParams(beaconHash, numIterationsExp); + const transcriptHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + transcriptHasher.update(mpcParams.csHash); + for (let i = 0; i < mpcParams.contributions.length; i++) hashPubKey(transcriptHasher, curve, mpcParams.contributions[i]); + const curContribution = {}; + curContribution.delta = {}; + curContribution.delta.prvKey = curve.Fr.fromRng(rng); + curContribution.delta.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + curContribution.delta.g1_sx = curve.G1.toAffine(curve.G1.timesFr(curContribution.delta.g1_s, curContribution.delta.prvKey)); + hashG1(transcriptHasher, curve, curContribution.delta.g1_s); + hashG1(transcriptHasher, curve, curContribution.delta.g1_sx); + curContribution.transcript = transcriptHasher.digest(); + curContribution.delta.g2_sp = hashToG2(curve, curContribution.transcript); + curContribution.delta.g2_spx = curve.G2.toAffine(curve.G2.timesFr(curContribution.delta.g2_sp, curContribution.delta.prvKey)); + zkey.vk_delta_1 = curve.G1.timesFr(zkey.vk_delta_1, curContribution.delta.prvKey); + zkey.vk_delta_2 = curve.G2.timesFr(zkey.vk_delta_2, curContribution.delta.prvKey); + curContribution.deltaAfter = zkey.vk_delta_1; + curContribution.type = 1; + curContribution.numIterationsExp = numIterationsExp; + curContribution.beaconHash = beaconHash; + if (name) curContribution.name = name; + mpcParams.contributions.push(curContribution); + await writeHeader(fdNew, zkey); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + const invDelta = curve.Fr.inv(curContribution.delta.prvKey); + await applyKeyToSection(fdOld, sections, fdNew, 8, curve, "G1", invDelta, curve.Fr.e(1), "L Section", logger); + await applyKeyToSection(fdOld, sections, fdNew, 9, curve, "G1", invDelta, curve.Fr.e(1), "H Section", logger); + await writeMPCParams(fdNew, curve, mpcParams); + await fdOld.close(); + await fdNew.close(); + const contributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hashPubKey(contributionHasher, curve, curContribution); + const contributionHash = contributionHasher.digest(); + if (logger) logger.info(formatHash(contributionHash, "Contribution Hash: ")); + return contributionHash; +} +//#endregion +//#region src/zkey_export_json.js async function zkeyExportJson$1(zkeyFileName) { - - const zKey = await readZKey(zkeyFileName, true); - delete zKey.curve; - delete zKey.F; - - return ffjavascript.utils.stringifyBigInts(zKey); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const zKey = await readZKey(zkeyFileName, true); + delete zKey.curve; + delete zKey.F; + return ffjavascript.utils.stringifyBigInts(zKey); +} +//#endregion +//#region src/zkey_bellman_contribute.js async function bellmanContribute(curve, challengeFilename, responseFileName, entropy, logger) { - const rng = await getRandomRng(entropy); - - const delta = curve.Fr.fromRng(rng); - const invDelta = curve.Fr.inv(delta); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - const fdFrom = await fastFile__namespace.readExisting(challengeFilename); - const fdTo = await fastFile__namespace.createOverride(responseFileName); - - - await copy(sG1); // alpha1 - await copy(sG1); // beta1 - await copy(sG2); // beta2 - await copy(sG2); // gamma2 - const oldDelta1 = await readG1(); - const delta1 = curve.G1.timesFr(oldDelta1, delta); - await writeG1(delta1); - const oldDelta2 = await readG2(); - const delta2 = curve.G2.timesFr(oldDelta2, delta); - await writeG2(delta2); - - // IC - const nIC = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nIC); - await copy(nIC*sG1); - - // H - const nH = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nH); - await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nH, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "H", logger); - - // L - const nL = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nL); - await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nL, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "L", logger); - - // A - const nA = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nA); - await copy(nA*sG1); - - // B1 - const nB1 = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nB1); - await copy(nB1*sG1); - - // B2 - const nB2 = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nB2); - await copy(nB2*sG2); - - - ////////// - /// Read contributions - ////////// - const transcriptHasher = blake2_js.blake2b.create({ dkLen: 64 }); - const mpcParams = {}; - // csHash - mpcParams.csHash = await fdFrom.read(64); - transcriptHasher.update(mpcParams.csHash); - - const nContributions = await fdFrom.readUBE32(); - mpcParams.contributions = []; - for (let i=0; i. -*/ - - -const {stringifyBigInts: stringifyBigInts$5} = ffjavascript.utils; - + const rng = await getRandomRng(entropy); + const delta = curve.Fr.fromRng(rng); + const invDelta = curve.Fr.inv(delta); + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + const fdFrom = await fastfile.readExisting(challengeFilename); + const fdTo = await fastfile.createOverride(responseFileName); + await copy(sG1); + await copy(sG1); + await copy(sG2); + await copy(sG2); + const oldDelta1 = await readG1(); + const delta1 = curve.G1.timesFr(oldDelta1, delta); + await writeG1(delta1); + const oldDelta2 = await readG2(); + await writeG2(curve.G2.timesFr(oldDelta2, delta)); + const nIC = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nIC); + await copy(nIC * sG1); + const nH = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nH); + await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nH, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "H", logger); + const nL = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nL); + await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nL, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "L", logger); + const nA = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nA); + await copy(nA * sG1); + const nB1 = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nB1); + await copy(nB1 * sG1); + const nB2 = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nB2); + await copy(nB2 * sG2); + const transcriptHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + const mpcParams = {}; + mpcParams.csHash = await fdFrom.read(64); + transcriptHasher.update(mpcParams.csHash); + const nContributions = await fdFrom.readUBE32(); + mpcParams.contributions = []; + for (let i = 0; i < nContributions; i++) { + const c = { delta: {} }; + c.deltaAfter = await readG1(); + c.delta.g1_s = await readG1(); + c.delta.g1_sx = await readG1(); + c.delta.g2_spx = await readG2(); + c.transcript = await fdFrom.read(64); + mpcParams.contributions.push(c); + hashPubKey(transcriptHasher, curve, c); + } + const curContribution = {}; + curContribution.delta = {}; + curContribution.delta.prvKey = delta; + curContribution.delta.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + curContribution.delta.g1_sx = curve.G1.toAffine(curve.G1.timesFr(curContribution.delta.g1_s, delta)); + hashG1(transcriptHasher, curve, curContribution.delta.g1_s); + hashG1(transcriptHasher, curve, curContribution.delta.g1_sx); + curContribution.transcript = transcriptHasher.digest(); + curContribution.delta.g2_sp = hashToG2(curve, curContribution.transcript); + curContribution.delta.g2_spx = curve.G2.toAffine(curve.G2.timesFr(curContribution.delta.g2_sp, delta)); + curContribution.deltaAfter = delta1; + curContribution.type = 0; + mpcParams.contributions.push(curContribution); + await fdTo.write(mpcParams.csHash); + await fdTo.writeUBE32(mpcParams.contributions.length); + for (let i = 0; i < mpcParams.contributions.length; i++) { + const c = mpcParams.contributions[i]; + await writeG1(c.deltaAfter); + await writeG1(c.delta.g1_s); + await writeG1(c.delta.g1_sx); + await writeG2(c.delta.g2_spx); + await fdTo.write(c.transcript); + } + const contributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hashPubKey(contributionHasher, curve, curContribution); + const contributionHash = contributionHasher.digest(); + if (logger) logger.info(formatHash(contributionHash, "Contribution Hash: ")); + await fdTo.close(); + await fdFrom.close(); + return contributionHash; + async function copy(nBytes) { + const CHUNK_SIZE = fdFrom.pageSize * 2; + for (let i = 0; i < nBytes; i += CHUNK_SIZE) { + const n = Math.min(nBytes - i, CHUNK_SIZE); + const buff = await fdFrom.read(n); + await fdTo.write(buff); + } + } + async function readG1() { + const buff = await fdFrom.read(curve.G1.F.n8 * 2); + return curve.G1.fromRprUncompressed(buff, 0); + } + async function readG2() { + const buff = await fdFrom.read(curve.G2.F.n8 * 2); + return curve.G2.fromRprUncompressed(buff, 0); + } + async function writeG1(P) { + const buff = new Uint8Array(sG1); + curve.G1.toRprUncompressed(buff, 0, P); + await fdTo.write(buff); + } + async function writeG2(P) { + const buff = new Uint8Array(sG2); + curve.G2.toRprUncompressed(buff, 0, P); + await fdTo.write(buff); + } +} +//#endregion +//#region src/zkey_export_verificationkey.js +var { stringifyBigInts: stringifyBigInts$5 } = ffjavascript.utils; async function zkeyExportVerificationKey(zkeyName, logger) { - if (logger) logger.info("EXPORT VERIFICATION KEY STARTED"); - - const {fd, sections} = await binFileUtils__namespace.readBinFile(zkeyName, "zkey", 2); - const zkey = await readHeader$1(fd, sections); - - if (logger) logger.info("> Detected protocol: " + zkey.protocol); - - let res; - if (zkey.protocol === "groth16") { - res = await groth16Vk(zkey, fd, sections); - } else if (zkey.protocol === "plonk") { - res = await plonkVk(zkey); - } else if (zkey.protocolId && zkey.protocolId === FFLONK_PROTOCOL_ID) { - res = await exportFFlonkVk(zkey); - } else { - throw new Error("zkey file protocol unrecognized"); - } - - await fd.close(); - - if (logger) logger.info("EXPORT VERIFICATION KEY FINISHED"); - - return res; -} - - + if (logger) logger.info("EXPORT VERIFICATION KEY STARTED"); + const { fd, sections } = await _iden3_binfileutils.readBinFile(zkeyName, "zkey", 2); + const zkey = await readHeader$1(fd, sections); + if (logger) logger.info("> Detected protocol: " + zkey.protocol); + let res; + if (zkey.protocol === "groth16") res = await groth16Vk(zkey, fd, sections); + else if (zkey.protocol === "plonk") res = await plonkVk(zkey); + else if (zkey.protocolId && zkey.protocolId === 10) res = await exportFFlonkVk(zkey, logger); + else throw new Error("zkey file protocol unrecognized"); + await fd.close(); + if (logger) logger.info("EXPORT VERIFICATION KEY FINISHED"); + return res; +} async function groth16Vk(zkey, fd, sections) { - const curve = await getCurveFromQ(zkey.q); - const sG1 = curve.G1.F.n8 * 2; - - const alphaBeta = await curve.pairing(zkey.vk_alpha_1, zkey.vk_beta_2); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - - vk_alpha_1: curve.G1.toObject(zkey.vk_alpha_1), - - vk_beta_2: curve.G2.toObject(zkey.vk_beta_2), - vk_gamma_2: curve.G2.toObject(zkey.vk_gamma_2), - vk_delta_2: curve.G2.toObject(zkey.vk_delta_2), - - vk_alphabeta_12: curve.Gt.toObject(alphaBeta) - }; - - // Read IC Section - /////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 3); - vKey.IC = []; - for (let i = 0; i <= zkey.nPublic; i++) { - const buff = await fd.read(sG1); - const P = curve.G1.toObject(buff); - vKey.IC.push(P); - } - await binFileUtils__namespace.endReadSection(fd); - - vKey = stringifyBigInts$5(vKey); - - return vKey; -} - - + const curve = await getCurveFromQ(zkey.q); + const sG1 = curve.G1.F.n8 * 2; + const alphaBeta = await curve.pairing(zkey.vk_alpha_1, zkey.vk_beta_2); + let vKey = { + protocol: zkey.protocol, + curve: curve.name, + nPublic: zkey.nPublic, + vk_alpha_1: curve.G1.toObject(zkey.vk_alpha_1), + vk_beta_2: curve.G2.toObject(zkey.vk_beta_2), + vk_gamma_2: curve.G2.toObject(zkey.vk_gamma_2), + vk_delta_2: curve.G2.toObject(zkey.vk_delta_2), + vk_alphabeta_12: curve.Gt.toObject(alphaBeta) + }; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 3); + vKey.IC = []; + for (let i = 0; i <= zkey.nPublic; i++) { + const buff = await fd.read(sG1); + const P = curve.G1.toObject(buff); + vKey.IC.push(P); + } + await _iden3_binfileutils.endReadSection(fd); + vKey = stringifyBigInts$5(vKey); + return vKey; +} async function plonkVk(zkey) { - const curve = await getCurveFromQ(zkey.q); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - power: zkey.power, - - k1: curve.Fr.toObject(zkey.k1), - k2: curve.Fr.toObject(zkey.k2), - - Qm: curve.G1.toObject(zkey.Qm), - Ql: curve.G1.toObject(zkey.Ql), - Qr: curve.G1.toObject(zkey.Qr), - Qo: curve.G1.toObject(zkey.Qo), - Qc: curve.G1.toObject(zkey.Qc), - S1: curve.G1.toObject(zkey.S1), - S2: curve.G1.toObject(zkey.S2), - S3: curve.G1.toObject(zkey.S3), - - X_2: curve.G2.toObject(zkey.X_2), - - w: curve.Fr.toObject(curve.Fr.w[zkey.power]) - }; - - vKey = stringifyBigInts$5(vKey); - - return vKey; -} - + const curve = await getCurveFromQ(zkey.q); + let vKey = { + protocol: zkey.protocol, + curve: curve.name, + nPublic: zkey.nPublic, + power: zkey.power, + k1: curve.Fr.toObject(zkey.k1), + k2: curve.Fr.toObject(zkey.k2), + Qm: curve.G1.toObject(zkey.Qm), + Ql: curve.G1.toObject(zkey.Ql), + Qr: curve.G1.toObject(zkey.Qr), + Qo: curve.G1.toObject(zkey.Qo), + Qc: curve.G1.toObject(zkey.Qc), + S1: curve.G1.toObject(zkey.S1), + S2: curve.G1.toObject(zkey.S2), + S3: curve.G1.toObject(zkey.S3), + X_2: curve.G2.toObject(zkey.X_2), + w: curve.Fr.toObject(curve.Fr.w[zkey.power]) + }; + vKey = stringifyBigInts$5(vKey); + return vKey; +} async function exportFFlonkVk(zkey, logger) { - const curve = await getCurveFromQ(zkey.q); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - power: zkey.power, - - k1: curve.Fr.toObject(zkey.k1), - k2: curve.Fr.toObject(zkey.k2), - - w: curve.Fr.toObject(curve.Fr.w[zkey.power]), - //wW: curve.Fr.toObject(curve.Fr.w[zkey.power + 1]), - w3: curve.Fr.toObject(zkey.w3), - w4: curve.Fr.toObject(zkey.w4), - w8: curve.Fr.toObject(zkey.w8), - wr: curve.Fr.toObject(zkey.wr), - - X_2: curve.G2.toObject(zkey.X_2), - - C0: curve.G1.toObject(zkey.C0), - }; - - return stringifyBigInts$5(vKey); -} - -/* - Copyright 2021 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const {unstringifyBigInts: unstringifyBigInts$b, stringifyBigInts: stringifyBigInts$4} = ffjavascript.utils; - + const curve = await getCurveFromQ(zkey.q); + return stringifyBigInts$5({ + protocol: zkey.protocol, + curve: curve.name, + nPublic: zkey.nPublic, + power: zkey.power, + k1: curve.Fr.toObject(zkey.k1), + k2: curve.Fr.toObject(zkey.k2), + w: curve.Fr.toObject(curve.Fr.w[zkey.power]), + w3: curve.Fr.toObject(zkey.w3), + w4: curve.Fr.toObject(zkey.w4), + w8: curve.Fr.toObject(zkey.w8), + wr: curve.Fr.toObject(zkey.wr), + X_2: curve.G2.toObject(zkey.X_2), + C0: curve.G1.toObject(zkey.C0) + }); +} +//#endregion +//#region src/fflonk_export_solidity_verifier.js +var { unstringifyBigInts: unstringifyBigInts$11, stringifyBigInts: stringifyBigInts$4 } = ffjavascript.utils; async function fflonkExportSolidityVerifier(vk, templates, logger) { - if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER STARTED"); - - const curve = await getCurveFromName(vk.curve); - - // Precompute w3_2, w4_2 and w4_3 - let w3 = fromVkey(vk.w3); - vk.w3_2 = toVkey(curve.Fr.square(w3)); - - let w4 = fromVkey(vk.w4); - vk.w4_2 = toVkey(curve.Fr.square(w4)); - vk.w4_3 = toVkey(curve.Fr.mul(curve.Fr.square(w4), w4)); - - let w8 = fromVkey(vk.w8); - let acc = curve.Fr.one; - - for (let i = 1; i < 8; i++) { - acc = curve.Fr.mul(acc, w8); - vk["w8_" + i] = toVkey(acc); - } - - let template = templates[vk.protocol]; - - if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER FINISHED"); - - const {default: ejs} = await import('ejs'); - return ejs.render(template, vk); - - function fromVkey(str) { - const val = unstringifyBigInts$b(str); - return curve.Fr.fromObject(val); - } - - function toVkey(val) { - const str = curve.Fr.toObject(val); - return stringifyBigInts$4(str); - } -} - -// Not ready yet -// module.exports.generateVerifier_kimleeoh = generateVerifier_kimleeoh; - + if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER STARTED"); + const curve = await getCurveFromName(vk.curve); + let w3 = fromVkey(vk.w3); + vk.w3_2 = toVkey(curve.Fr.square(w3)); + let w4 = fromVkey(vk.w4); + vk.w4_2 = toVkey(curve.Fr.square(w4)); + vk.w4_3 = toVkey(curve.Fr.mul(curve.Fr.square(w4), w4)); + let w8 = fromVkey(vk.w8); + let acc = curve.Fr.one; + for (let i = 1; i < 8; i++) { + acc = curve.Fr.mul(acc, w8); + vk["w8_" + i] = toVkey(acc); + } + let template = templates[vk.protocol]; + if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER FINISHED"); + const { default: ejs } = await import("ejs"); + return ejs.render(template, vk); + function fromVkey(str) { + const val = unstringifyBigInts$11(str); + return curve.Fr.fromObject(val); + } + function toVkey(val) { + return stringifyBigInts$4(curve.Fr.toObject(val)); + } +} +//#endregion +//#region src/zkey_export_solidityverifier.js async function exportSolidityVerifier(zKeyName, templates, logger) { - - const verificationKey = await zkeyExportVerificationKey(zKeyName, logger); - - if ("fflonk" === verificationKey.protocol) { - return fflonkExportSolidityVerifier(verificationKey, templates, logger); - } - - let template = templates[verificationKey.protocol]; - - const {default: ejs} = await import('ejs'); - - return ejs.render(template, verificationKey); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - - + const verificationKey = await zkeyExportVerificationKey(zKeyName, logger); + if ("fflonk" === verificationKey.protocol) return fflonkExportSolidityVerifier(verificationKey, templates, logger); + let template = templates[verificationKey.protocol]; + const { default: ejs } = await import("ejs"); + return ejs.render(template, verificationKey); +} +//#endregion +//#region src/wtns_utils.js async function write(fd, witness, prime) { - - await binFileUtils__namespace.startWriteSection(fd, 1); - const n8 = (Math.floor( (ffjavascript.Scalar.bitLength(prime) - 1) / 64) +1)*8; - await fd.writeULE32(n8); - await binFileUtils__namespace.writeBigInt(fd, prime, n8); - await fd.writeULE32(witness.length); - await binFileUtils__namespace.endWriteSection(fd); - - await binFileUtils__namespace.startWriteSection(fd, 2); - for (let i=0; i. -*/ - -const {stringifyBigInts: stringifyBigInts$3} = ffjavascript.utils; - + const { fd, sections } = await _iden3_binfileutils.readBinFile(fileName, "wtns", 2); + const { n8, nWitness } = await readHeader(fd, sections); + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 2); + const res = []; + for (let i = 0; i < nWitness; i++) { + const v = await _iden3_binfileutils.readBigInt(fd, n8); + res.push(v); + } + await _iden3_binfileutils.endReadSection(fd); + await fd.close(); + return res; +} +//#endregion +//#region src/groth16_prove.js +var { stringifyBigInts: stringifyBigInts$3 } = ffjavascript.utils; async function groth16Prove$1(zkeyFileName, witnessFileName, logger, options) { - // Opt-in periodic memory-usage logging (heap/RSS/external/ArrayBuffers). - // options.memoryLogging: true (1s interval) or an interval in ms. - // Node-only: process.memoryUsage does not exist in browsers. - let memTimer = null; - if (logger && options && options.memoryLogging - && typeof process !== "undefined" && typeof process.memoryUsage === "function") { - const interval = Number(options.memoryLogging) > 1 ? Number(options.memoryLogging) : 1000; - memTimer = monitorMemoryUsage(logger, interval); - } - try { - return await _groth16Prove(zkeyFileName, witnessFileName, logger, options); - } finally { - if (memTimer) { - clearInterval(memTimer); - memUsage(logger); - } - } -} - + let memTimer = null; + if (logger && options && options.memoryLogging && typeof process !== "undefined" && typeof process.memoryUsage === "function") memTimer = monitorMemoryUsage(logger, Number(options.memoryLogging) > 1 ? Number(options.memoryLogging) : 1e3); + try { + return await _groth16Prove(zkeyFileName, witnessFileName, logger, options); + } finally { + if (memTimer) { + clearInterval(memTimer); + memUsage(logger); + } + } +} async function _groth16Prove(zkeyFileName, witnessFileName, logger, options) { - - const {fd: fdWtns, sections: sectionsWtns} = await binFileUtils__namespace.readBinFile(witnessFileName, "wtns", 2, 1<<25, 1<<23); - - const wtns = await readHeader(fdWtns, sectionsWtns); - - const {fd: fdZKey, sections: sectionsZKey} = await binFileUtils__namespace.readBinFile(zkeyFileName, "zkey", 2, 1<<25, 1<<23); - - const zkey = await readHeader$1(fdZKey, sectionsZKey, undefined, options); - - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness != zkey.nVars) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}`); - } - - const curve = zkey.curve; - const Fr = curve.Fr; - const G1 = curve.G1; - const G2 = curve.G2; - - options = options || {}; - - // MSM batching mode, threaded to every multiexp below: - // "auto" (default) use the batch-affine MSM module only for - // cache-friendly chunk sizes (where it is measurably faster); - // "enabled" always use it (best for small/medium circuits); - // "disabled" never use it (plain in-module multiexp; lowest memory). - const msmBatching = options.msmBatching || "auto"; - if (msmBatching !== "auto" && msmBatching !== "enabled" && msmBatching !== "disabled") { - throw new Error(`groth16Prove: invalid msmBatching "${msmBatching}" (expected "auto", "enabled" or "disabled")`); - } - // msmGlv / msmGls: "auto" (default -- use the G1/G2 endomorphism MSM paths - // where the curve supports them; the wasm still gates internally on chunk - // sizes) or "disabled" (generic batch accumulation). A/B and debugging - // aids, like msmBatching. - const msmGlv = options.msmGlv || "auto"; - const msmGls = options.msmGls || "auto"; - for (const [name, v] of [["msmGlv", msmGlv], ["msmGls", msmGls]]) { - if (v !== "auto" && v !== "disabled") { - throw new Error(`groth16Prove: invalid ${name} "${v}" (expected "auto" or "disabled")`); - } - } - const msmOpts = { batch: msmBatching, glv: msmGlv, gls: msmGls }; - - const power = log2(zkey.domainSize); - - if (logger) logger.debug("Reading Wtns"); - const buffWitness = await binFileUtils__namespace.readSection(fdWtns, sectionsWtns, 2); - - // Reader for a zkey section that returns an arbitrary sub-range directly from - // disk, used to feed multiExp bases to the workers in chunks instead of - // reading the whole (potentially hundreds of MB) section into one buffer and - // slicing it. Bounds the bases resident in RAM to a few in-flight chunks. - const mkSectionReader = (idSection) => { - const start = sectionsZKey[idSection][0].p; - const size = sectionsZKey[idSection][0].size; - return async (off, len) => { - if (off + len > size) throw new Error(`groth16Prove: read out of range of section ${idSection}`); - const buff = new Uint8Array(len); - await fdZKey.readToBuffer(buff, 0, len, start + off); - return buff; - }; - }; - - let resH; - let resHPromise; - let buffPodd_T; - - let abcPromise = (async function (){ - let buffA_T, buffB_T, buffC_T; - - await (async function (){ - if (logger) logger.debug("Reading Coeffs"); - const buffCoeffs = await binFileUtils__namespace.readSection(fdZKey, sectionsZKey, 4); - - if (logger) logger.debug("Building ABC"); - - if (options.buildABC === "js") { - [buffA_T, buffB_T, buffC_T] = await buildABC1(curve, zkey, buffWitness, buffCoeffs, logger); - } else if (options.buildABC === "stream") { - const p = pickStreamParams(curve, zkey, buffCoeffs, options); - [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); - } else { - // Default: streaming build (bounded worker memory, tunable - // parallelism). The per-chunk witness gather keeps the witness - // out of WASM entirely, so there is no witness size limit. - const p = pickStreamParams(curve, zkey, buffCoeffs, options); - if (logger) logger.debug(`buildABC: stream nChunks=${p.nChunks} maxInFlight=${p.maxInFlight}`); - [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); - } - })(); - - - // Do not call gc() here. gc() is a stop-the-world pause that blocks the - // Node.js event loop. If the pause exceeds the worker idle-termination - // timeout (1s), a worker closes its port while the main thread is blocked, - // and the next task dispatched to it is silently dropped → hang. The - // coefficients buffer goes out of scope at the end of the inner IIFE above - // and is reclaimed by V8's incremental GC automatically. - - const inc = power === Fr.s ? curve.Fr.shift : curve.Fr.w[power+1]; - - let buffAodd_T, buffBodd_T, buffCodd_T; - // The IFFT input (buffX_T) is dropped immediately, and the FFT input - // (buffXodd) goes out of scope right after -- so both can be consumed - // (consume=true), skipping ffjavascript's defensive full-input copy. - await Promise.all([ - (async function () { - let buffA = await Fr.ifft(buffA_T, "", "", logger, "IFFT_A", true); - buffA_T = null; - const buffAodd = await Fr.batchApplyKey(buffA, Fr.e(1), inc); - buffAodd_T = await Fr.fft(buffAodd, "", "", logger, "FFT_A", true); - })(), - (async function () { - let buffB = await Fr.ifft(buffB_T, "", "", logger, "IFFT_B", true); - buffB_T = null; - const buffBodd = await Fr.batchApplyKey(buffB, Fr.e(1), inc); - buffBodd_T = await Fr.fft(buffBodd, "", "", logger, "FFT_B", true); - })(), - (async function () { - let buffC = await Fr.ifft(buffC_T, "", "", logger, "IFFT_C", true); - buffC_T = null; - const buffCodd = await Fr.batchApplyKey(buffC, Fr.e(1), inc); - buffCodd_T = await Fr.fft(buffCodd, "", "", logger, "FFT_C", true); - })(), - ]); - - if (logger) logger.debug("Join ABC"); - buffPodd_T = await joinABC(curve, zkey, buffAodd_T, buffBodd_T, buffCodd_T, logger); - if (logger) logger.debug("Join ABC finished"); - buffAodd_T = null; - buffBodd_T = null; - buffCodd_T = null; - - if (globalThis.gc) {globalThis.gc();} - })(); - //await abcPromise; - - let proof = {}; - - async function calcPiA(){ - if (logger) logger.debug("Reading A Points"); - proof.pi_a = await curve.G1.multiExpAffineChunked(mkSectionReader(5), sectionsZKey[5][0].size, buffWitness, logger, "multiexp A", msmOpts); - } - - let piaPromise = calcPiA(); - //await piaPromise; - - let pib1; - - async function calcPiB1() { - if (logger) logger.debug("Reading B1 Points"); - pib1 = await curve.G1.multiExpAffineChunked(mkSectionReader(6), sectionsZKey[6][0].size, buffWitness, logger, "multiexp B1", msmOpts); - } - - let pib1Promise = calcPiB1(); - //await pib1Promise; - - async function calcPiB() { - if (logger) logger.debug("Reading B2 Points"); - proof.pi_b = await curve.G2.multiExpAffineChunked(mkSectionReader(7), sectionsZKey[7][0].size, buffWitness, logger, "multiexp B2", msmOpts); - } - - let pibPromise = calcPiB(); - //await pibPromise; - - let picPromise = (async function (){ - if (logger) logger.debug("Reading C Points"); - proof.pi_c = await curve.G1.multiExpAffineChunked(mkSectionReader(8), sectionsZKey[8][0].size, buffWitness.slice((zkey.nPublic+1)*curve.Fr.n8), logger, "multiexp C", msmOpts); - })(); - //await picPromise; - - resHPromise = (async function (){ - if (logger) logger.debug("Reading H Points"); - await abcPromise; - resH = await curve.G1.multiExpAffineChunked(mkSectionReader(9), sectionsZKey[9][0].size, buffPodd_T, logger, "multiexp H", msmOpts); - })(); - //await resHPromise; - - - const r = curve.Fr.random(); - const s = curve.Fr.random(); - - await piaPromise; - proof.pi_a = G1.add( proof.pi_a, zkey.vk_alpha_1 ); - proof.pi_a = G1.add( proof.pi_a, G1.timesFr( zkey.vk_delta_1, r )); - - await pibPromise; - proof.pi_b = G2.add( proof.pi_b, zkey.vk_beta_2 ); - proof.pi_b = G2.add( proof.pi_b, G2.timesFr( zkey.vk_delta_2, s )); - - await pib1Promise; - pib1 = G1.add( pib1, zkey.vk_beta_1 ); - pib1 = G1.add( pib1, G1.timesFr( zkey.vk_delta_1, s )); - - await Promise.all([picPromise, resHPromise]); - proof.pi_c = G1.add(proof.pi_c, resH); - - - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( proof.pi_a, s )); - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( pib1, r )); - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( zkey.vk_delta_1, Fr.neg(Fr.mul(r,s) ))); - - - let publicSignals = []; - - for (let i=1; i<= zkey.nPublic; i++) { - const b = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8); - publicSignals.push(ffjavascript.Scalar.fromRprLE(b)); - } - - proof.pi_a = G1.toObject(G1.toAffine(proof.pi_a)); - proof.pi_b = G2.toObject(G2.toAffine(proof.pi_b)); - proof.pi_c = G1.toObject(G1.toAffine(proof.pi_c)); - - proof.protocol = "groth16"; - proof.curve = curve.name; - - await fdZKey.close(); - await fdWtns.close(); - - proof = stringifyBigInts$3(proof); - publicSignals = stringifyBigInts$3(publicSignals); - - return {proof, publicSignals}; -} - - + const { fd: fdWtns, sections: sectionsWtns } = await _iden3_binfileutils.readBinFile(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); + const wtns = await readHeader(fdWtns, sectionsWtns); + const { fd: fdZKey, sections: sectionsZKey } = await _iden3_binfileutils.readBinFile(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); + const zkey = await readHeader$1(fdZKey, sectionsZKey, void 0, options); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) throw new Error("Curve of the witness does not match the curve of the proving key"); + if (wtns.nWitness != zkey.nVars) throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}`); + const curve = zkey.curve; + const Fr = curve.Fr; + const G1 = curve.G1; + const G2 = curve.G2; + options = options || {}; + const msmBatching = options.msmBatching || "auto"; + if (msmBatching !== "auto" && msmBatching !== "enabled" && msmBatching !== "disabled") throw new Error(`groth16Prove: invalid msmBatching "${msmBatching}" (expected "auto", "enabled" or "disabled")`); + const msmGlv = options.msmGlv || "auto"; + const msmGls = options.msmGls || "auto"; + for (const [name, v] of [["msmGlv", msmGlv], ["msmGls", msmGls]]) if (v !== "auto" && v !== "disabled") throw new Error(`groth16Prove: invalid ${name} "${v}" (expected "auto" or "disabled")`); + const msmOpts = { + batch: msmBatching, + glv: msmGlv, + gls: msmGls + }; + const power = log2(zkey.domainSize); + if (logger) logger.debug("Reading Wtns"); + const buffWitness = await _iden3_binfileutils.readSection(fdWtns, sectionsWtns, 2); + const mkSectionReader = (idSection) => { + const start = sectionsZKey[idSection][0].p; + const size = sectionsZKey[idSection][0].size; + return async (off, len) => { + if (off + len > size) throw new Error(`groth16Prove: read out of range of section ${idSection}`); + const buff = new Uint8Array(len); + await fdZKey.readToBuffer(buff, 0, len, start + off); + return buff; + }; + }; + let resH; + let resHPromise; + let buffPodd_T; + let abcPromise = (async function() { + let buffA_T, buffB_T, buffC_T; + await (async function() { + if (logger) logger.debug("Reading Coeffs"); + const buffCoeffs = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 4); + if (logger) logger.debug("Building ABC"); + if (options.buildABC === "js") [buffA_T, buffB_T, buffC_T] = await buildABC1(curve, zkey, buffWitness, buffCoeffs, logger); + else if (options.buildABC === "stream") { + const p = pickStreamParams(curve, zkey, buffCoeffs, options); + [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); + } else { + const p = pickStreamParams(curve, zkey, buffCoeffs, options); + if (logger) logger.debug(`buildABC: stream nChunks=${p.nChunks} maxInFlight=${p.maxInFlight}`); + [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); + } + })(); + const inc = power === Fr.s ? curve.Fr.shift : curve.Fr.w[power + 1]; + let buffAodd_T, buffBodd_T, buffCodd_T; + await Promise.all([ + (async function() { + let buffA = await Fr.ifft(buffA_T, "", "", logger, "IFFT_A", true); + buffA_T = null; + const buffAodd = await Fr.batchApplyKey(buffA, Fr.e(1), inc); + buffAodd_T = await Fr.fft(buffAodd, "", "", logger, "FFT_A", true); + })(), + (async function() { + let buffB = await Fr.ifft(buffB_T, "", "", logger, "IFFT_B", true); + buffB_T = null; + const buffBodd = await Fr.batchApplyKey(buffB, Fr.e(1), inc); + buffBodd_T = await Fr.fft(buffBodd, "", "", logger, "FFT_B", true); + })(), + (async function() { + let buffC = await Fr.ifft(buffC_T, "", "", logger, "IFFT_C", true); + buffC_T = null; + const buffCodd = await Fr.batchApplyKey(buffC, Fr.e(1), inc); + buffCodd_T = await Fr.fft(buffCodd, "", "", logger, "FFT_C", true); + })() + ]); + if (logger) logger.debug("Join ABC"); + buffPodd_T = await joinABC(curve, zkey, buffAodd_T, buffBodd_T, buffCodd_T, logger); + if (logger) logger.debug("Join ABC finished"); + buffAodd_T = null; + buffBodd_T = null; + buffCodd_T = null; + if (globalThis.gc) globalThis.gc(); + })(); + let proof = {}; + async function calcPiA() { + if (logger) logger.debug("Reading A Points"); + proof.pi_a = await curve.G1.multiExpAffineChunked(mkSectionReader(5), sectionsZKey[5][0].size, buffWitness, logger, "multiexp A", msmOpts); + } + let piaPromise = calcPiA(); + let pib1; + async function calcPiB1() { + if (logger) logger.debug("Reading B1 Points"); + pib1 = await curve.G1.multiExpAffineChunked(mkSectionReader(6), sectionsZKey[6][0].size, buffWitness, logger, "multiexp B1", msmOpts); + } + let pib1Promise = calcPiB1(); + async function calcPiB() { + if (logger) logger.debug("Reading B2 Points"); + proof.pi_b = await curve.G2.multiExpAffineChunked(mkSectionReader(7), sectionsZKey[7][0].size, buffWitness, logger, "multiexp B2", msmOpts); + } + let pibPromise = calcPiB(); + let picPromise = (async function() { + if (logger) logger.debug("Reading C Points"); + proof.pi_c = await curve.G1.multiExpAffineChunked(mkSectionReader(8), sectionsZKey[8][0].size, buffWitness.slice((zkey.nPublic + 1) * curve.Fr.n8), logger, "multiexp C", msmOpts); + })(); + resHPromise = (async function() { + if (logger) logger.debug("Reading H Points"); + await abcPromise; + resH = await curve.G1.multiExpAffineChunked(mkSectionReader(9), sectionsZKey[9][0].size, buffPodd_T, logger, "multiexp H", msmOpts); + })(); + const r = curve.Fr.random(); + const s = curve.Fr.random(); + await piaPromise; + proof.pi_a = G1.add(proof.pi_a, zkey.vk_alpha_1); + proof.pi_a = G1.add(proof.pi_a, G1.timesFr(zkey.vk_delta_1, r)); + await pibPromise; + proof.pi_b = G2.add(proof.pi_b, zkey.vk_beta_2); + proof.pi_b = G2.add(proof.pi_b, G2.timesFr(zkey.vk_delta_2, s)); + await pib1Promise; + pib1 = G1.add(pib1, zkey.vk_beta_1); + pib1 = G1.add(pib1, G1.timesFr(zkey.vk_delta_1, s)); + await Promise.all([picPromise, resHPromise]); + proof.pi_c = G1.add(proof.pi_c, resH); + proof.pi_c = G1.add(proof.pi_c, G1.timesFr(proof.pi_a, s)); + proof.pi_c = G1.add(proof.pi_c, G1.timesFr(pib1, r)); + proof.pi_c = G1.add(proof.pi_c, G1.timesFr(zkey.vk_delta_1, Fr.neg(Fr.mul(r, s)))); + let publicSignals = []; + for (let i = 1; i <= zkey.nPublic; i++) { + const b = buffWitness.slice(i * Fr.n8, i * Fr.n8 + Fr.n8); + publicSignals.push(ffjavascript.Scalar.fromRprLE(b)); + } + proof.pi_a = G1.toObject(G1.toAffine(proof.pi_a)); + proof.pi_b = G2.toObject(G2.toAffine(proof.pi_b)); + proof.pi_c = G1.toObject(G1.toAffine(proof.pi_c)); + proof.protocol = "groth16"; + proof.curve = curve.name; + await fdZKey.close(); + await fdWtns.close(); + proof = stringifyBigInts$3(proof); + publicSignals = stringifyBigInts$3(publicSignals); + return { + proof, + publicSignals + }; +} async function buildABC1(curve, zkey, witness, coeffs, logger) { - const n8 = curve.Fr.n8; - const sCoef = 4*3 + zkey.n8r; - const nCoef = (coeffs.byteLength-4) / sCoef; - - const outBuffA = new ffjavascript.BigBuffer(zkey.domainSize * n8); - const outBuffB = new ffjavascript.BigBuffer(zkey.domainSize * n8); - const outBuffC = new ffjavascript.BigBuffer(zkey.domainSize * n8); - - const outBuf = [ outBuffA, outBuffB ]; - for (let i=0; i coeffsDV[Math.floor(pos / PAGE_LEN)].getUint32(pos % PAGE_LEN, true); - } else { - const coeffsDV = new DataView(coeffs.buffer, coeffs.byteOffset, coeffs.byteLength); - getUint32 = (pos) => coeffsDV.getUint32(pos, true); - } - function getCutPoint(v) { - let m = 0, n = getUint32(0); - while (m < n) { - const k = Math.floor((n + m) / 2); - const va = getUint32(4 + k * sCoef + 4); - if (va > v) n = k - 1; else if (va < v) m = k + 1; else n = k; - } - return 4 + m * sCoef; - } - - const elementsPerChunk = Math.floor((domainSize - 1) / nChunks) + 1; - const cutPoints = []; - for (let i = 0; i < nChunks; i++) cutPoints.push(getCutPoint(i * elementsPerChunk)); - cutPoints.push(coeffs.byteLength); - - // Return a flat Uint8Array when the domain fits under BigBuffer's 1 GiB page, - // so the downstream IFFT can consume it in place (skip its defensive copy). - // Larger domains stay paged BigBuffers (the IFFT flattens those as before). - const outBytes = domainSize * n8; - const mkOut = () => (outBytes < (1 << 30)) ? new Uint8Array(outBytes) : new ffjavascript.BigBuffer(outBytes); - const outBuffA = mkOut(); - const outBuffB = mkOut(); - const outBuffC = mkOut(); - - const inFlight = new Set(); - const tasks = []; - for (let i = 0; i < nChunks; i++) { - const outOffset = i * elementsPerChunk; - const n = Math.min(elementsPerChunk, domainSize - outOffset); - if (n <= 0) break; - const cpA = cutPoints[i], cpB = cutPoints[i + 1]; - while (inFlight.size >= maxInFlight) await Promise.race(inFlight); - if (logger) logger.debug(`buildABCStream: ${i}/${nChunks}`); - const op = (async () => { - // Gather the witness values this chunk references into a compact - // buffer (one entry per coefficient, in coefficient order) and - // rewrite each coefficient's s-index to its sequential position. - // The witness itself never enters WASM, so its size is unbounded - // (it can stay a BigBuffer) and each task ships only what it uses - // -- typically much less than a full witness copy per task. - const coeffChunk = coeffs.slice(cpA, cpB); - const nCoefChunk = (cpB - cpA) / sCoef; - const gathered = new Uint8Array(nCoefChunk * n8); - // Hot loop (one iteration per coefficient): use typed-array lane - // copies instead of set(subarray) -- per-element memcpy dispatch - // dominated the profile otherwise. Uint32 lanes on purpose: the - // data is integer bit patterns, and Float64Array stores may - // legally canonicalize NaN-patterned lanes (SetValueInBuffer is - // implementation-defined for NaN encodings). The s-field offsets - // are 4-byte aligned (sCoef and the +8 offset are multiples of 4). - const chunkU32 = new Uint32Array(coeffChunk.buffer, coeffChunk.byteOffset, coeffChunk.byteLength >> 2); - const sStep = sCoef >> 2; - const laneFast = !!witness.buffer && ((witness.byteOffset & 3) === 0) && (n8 === 32); - if (laneFast) { - const wU32 = new Uint32Array(witness.buffer, witness.byteOffset, witness.byteLength >> 2); - const gU32 = new Uint32Array(gathered.buffer); - for (let j = 0; j < nCoefChunk; j++) { - const si = chunkU32[j * sStep + 2]; - const so = si << 3, go = j << 3; - gU32[go] = wU32[so]; gU32[go + 1] = wU32[so + 1]; - gU32[go + 2] = wU32[so + 2]; gU32[go + 3] = wU32[so + 3]; - gU32[go + 4] = wU32[so + 4]; gU32[go + 5] = wU32[so + 5]; - gU32[go + 6] = wU32[so + 6]; gU32[go + 7] = wU32[so + 7]; - chunkU32[j * sStep + 2] = j; - } - } else { - const witnessIsView = !!witness.buffer; - for (let j = 0; j < nCoefChunk; j++) { - const s = chunkU32[j * sStep + 2]; - if (witnessIsView) gathered.set(witness.subarray(s * n8, (s + 1) * n8), j * n8); - else gathered.set(witness.slice(s * n8, (s + 1) * n8), j * n8); - chunkU32[j * sStep + 2] = j; - } - } - const task = [ - {cmd: "ALLOCSET", var: 0, buff: coeffChunk}, - {cmd: "ALLOCSET", var: 1, buff: gathered}, - {cmd: "ALLOC", var: 2, len: n * n8}, - {cmd: "ALLOC", var: 3, len: n * n8}, - {cmd: "ALLOC", var: 4, len: n * n8}, - {cmd: "CALL", fnName: "qap_buildABC", params: [ - {var: 0}, {val: nCoefChunk}, {var: 1}, - {var: 2}, {var: 3}, {var: 4}, - {val: outOffset}, {val: n}, {val: 0}, {val: nCoefChunk}, - ]}, - {cmd: "GET", out: 0, var: 2, len: n * n8}, - {cmd: "GET", out: 1, var: 3, len: n * n8}, - {cmd: "GET", out: 2, var: 4, len: n * n8}, - ]; - const r = await curve.tm.queueAction(task, [coeffChunk.buffer, gathered.buffer]); - outBuffA.set(r[0], outOffset * n8); - outBuffB.set(r[1], outOffset * n8); - outBuffC.set(r[2], outOffset * n8); - })(); - const slot = op.finally(() => inFlight.delete(slot)); - inFlight.add(slot); - tasks.push(slot); - } - await Promise.all(tasks); - return [outBuffA, outBuffB, outBuffC]; -} - + const n8 = curve.Fr.n8; + const sCoef = 12 + zkey.n8r; + const domainSize = zkey.domainSize; + let getUint32; + if (coeffs instanceof ffjavascript.BigBuffer) { + const coeffsDV = []; + const PAGE_LEN = coeffs.buffers[0].length; + for (let i = 0; i < coeffs.buffers.length; i++) coeffsDV.push(new DataView(coeffs.buffers[i].buffer)); + getUint32 = (pos) => coeffsDV[Math.floor(pos / PAGE_LEN)].getUint32(pos % PAGE_LEN, true); + } else { + const coeffsDV = new DataView(coeffs.buffer, coeffs.byteOffset, coeffs.byteLength); + getUint32 = (pos) => coeffsDV.getUint32(pos, true); + } + function getCutPoint(v) { + let m = 0, n = getUint32(0); + while (m < n) { + const k = Math.floor((n + m) / 2); + const va = getUint32(4 + k * sCoef + 4); + if (va > v) n = k - 1; + else if (va < v) m = k + 1; + else n = k; + } + return 4 + m * sCoef; + } + const elementsPerChunk = Math.floor((domainSize - 1) / nChunks) + 1; + const cutPoints = []; + for (let i = 0; i < nChunks; i++) cutPoints.push(getCutPoint(i * elementsPerChunk)); + cutPoints.push(coeffs.byteLength); + const outBytes = domainSize * n8; + const mkOut = () => outBytes < 1 << 30 ? new Uint8Array(outBytes) : new ffjavascript.BigBuffer(outBytes); + const outBuffA = mkOut(); + const outBuffB = mkOut(); + const outBuffC = mkOut(); + const inFlight = /* @__PURE__ */ new Set(); + const tasks = []; + for (let i = 0; i < nChunks; i++) { + const outOffset = i * elementsPerChunk; + const n = Math.min(elementsPerChunk, domainSize - outOffset); + if (n <= 0) break; + const cpA = cutPoints[i], cpB = cutPoints[i + 1]; + while (inFlight.size >= maxInFlight) await Promise.race(inFlight); + if (logger) logger.debug(`buildABCStream: ${i}/${nChunks}`); + const slot = (async () => { + const coeffChunk = coeffs.slice(cpA, cpB); + const nCoefChunk = (cpB - cpA) / sCoef; + const gathered = new Uint8Array(nCoefChunk * n8); + const chunkU32 = new Uint32Array(coeffChunk.buffer, coeffChunk.byteOffset, coeffChunk.byteLength >> 2); + const sStep = sCoef >> 2; + if (!!witness.buffer && (witness.byteOffset & 3) === 0 && n8 === 32) { + const wU32 = new Uint32Array(witness.buffer, witness.byteOffset, witness.byteLength >> 2); + const gU32 = new Uint32Array(gathered.buffer); + for (let j = 0; j < nCoefChunk; j++) { + const so = chunkU32[j * sStep + 2] << 3, go = j << 3; + gU32[go] = wU32[so]; + gU32[go + 1] = wU32[so + 1]; + gU32[go + 2] = wU32[so + 2]; + gU32[go + 3] = wU32[so + 3]; + gU32[go + 4] = wU32[so + 4]; + gU32[go + 5] = wU32[so + 5]; + gU32[go + 6] = wU32[so + 6]; + gU32[go + 7] = wU32[so + 7]; + chunkU32[j * sStep + 2] = j; + } + } else { + const witnessIsView = !!witness.buffer; + for (let j = 0; j < nCoefChunk; j++) { + const s = chunkU32[j * sStep + 2]; + if (witnessIsView) gathered.set(witness.subarray(s * n8, (s + 1) * n8), j * n8); + else gathered.set(witness.slice(s * n8, (s + 1) * n8), j * n8); + chunkU32[j * sStep + 2] = j; + } + } + const task = [ + { + cmd: "ALLOCSET", + var: 0, + buff: coeffChunk + }, + { + cmd: "ALLOCSET", + var: 1, + buff: gathered + }, + { + cmd: "ALLOC", + var: 2, + len: n * n8 + }, + { + cmd: "ALLOC", + var: 3, + len: n * n8 + }, + { + cmd: "ALLOC", + var: 4, + len: n * n8 + }, + { + cmd: "CALL", + fnName: "qap_buildABC", + params: [ + { var: 0 }, + { val: nCoefChunk }, + { var: 1 }, + { var: 2 }, + { var: 3 }, + { var: 4 }, + { val: outOffset }, + { val: n }, + { val: 0 }, + { val: nCoefChunk } + ] + }, + { + cmd: "GET", + out: 0, + var: 2, + len: n * n8 + }, + { + cmd: "GET", + out: 1, + var: 3, + len: n * n8 + }, + { + cmd: "GET", + out: 2, + var: 4, + len: n * n8 + } + ]; + const r = await curve.tm.queueAction(task, [coeffChunk.buffer, gathered.buffer]); + outBuffA.set(r[0], outOffset * n8); + outBuffB.set(r[1], outOffset * n8); + outBuffC.set(r[2], outOffset * n8); + })().finally(() => inFlight.delete(slot)); + inFlight.add(slot); + tasks.push(slot); + } + await Promise.all(tasks); + return [ + outBuffA, + outBuffB, + outBuffC + ]; +} async function joinABC(curve, zkey, a, b, c, logger) { - const MAX_CHUNK_SIZE = 1 << 16; - - const n8 = curve.Fr.n8; - const nElements = Math.floor(a.byteLength / curve.Fr.n8); - - const promises = []; - - for (let i=0; i { - memUsage(logger); - }, interval); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const { unstringifyBigInts: unstringifyBigInts$a} = ffjavascript.utils; - + if (!logger) return; + const used = process.memoryUsage(); + logger.info(" ", "\x1B[0m Heap:\x1B[32m", `${Math.round(used.heapUsed / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m / \x1B[32m", `${Math.round(used.heapTotal / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m RSS:\x1B[32m", `${Math.round(used.rss / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m External:\x1B[32m", `${Math.round(used.external / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m ArrBuffers:\x1B[32m", `${Math.round(used.arrayBuffers / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m"); +} +function monitorMemoryUsage(logger, interval = 5e3) { + return setInterval(() => { + memUsage(logger); + }, interval); +} +//#endregion +//#region src/wtns_calculate.js +var { unstringifyBigInts: unstringifyBigInts$10 } = ffjavascript.utils; async function wtnsCalculate$1(_input, wasmFileName, wtnsFileName, options) { - const input = unstringifyBigInts$a(_input); - - const fdWasm = await fastFile__namespace.readExisting(wasmFileName); - const wasm = await fdWasm.read(fdWasm.totalSize); - await fdWasm.close(); - - const wc = await circom_runtime.WitnessCalculatorBuilder(wasm, options); - if (wc.circom_version() === 1) { - const w = await wc.calculateBinWitness(input); - - const fdWtns = await binFileUtils__namespace.createBinFile(wtnsFileName, "wtns", 2, 2); - - await writeBin(fdWtns, w, wc.prime); - await fdWtns.close(); - } else { - const fdWtns = await fastFile__namespace.createOverride(wtnsFileName); - - const w = await wc.calculateWTNSBin(input); - - await fdWtns.write(w); - await fdWtns.close(); - } -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const {unstringifyBigInts: unstringifyBigInts$9} = ffjavascript.utils; - + const input = unstringifyBigInts$10(_input); + const fdWasm = await fastfile.readExisting(wasmFileName); + const wasm = await fdWasm.read(fdWasm.totalSize); + await fdWasm.close(); + const wc = await (0, circom_runtime.WitnessCalculatorBuilder)(wasm, options); + if (wc.circom_version() === 1) { + const w = await wc.calculateBinWitness(input); + const fdWtns = await _iden3_binfileutils.createBinFile(wtnsFileName, "wtns", 2, 2); + await writeBin(fdWtns, w, wc.prime); + await fdWtns.close(); + } else { + const fdWtns = await fastfile.createOverride(wtnsFileName); + const w = await wc.calculateWTNSBin(input); + await fdWtns.write(w); + await fdWtns.close(); + } +} +//#endregion +//#region src/groth16_fullprove.js +var { unstringifyBigInts: unstringifyBigInts$9 } = ffjavascript.utils; async function groth16FullProve$1(_input, wasmFile, zkeyFileName, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$9(_input); - - const wtns= { - type: "mem" - }; - await wtnsCalculate$1(input, wasmFile, wtns, wtnsCalcOptions); - return await groth16Prove$1(zkeyFileName, wtns, logger, proverOptions); -} - -/* - Copyright 2018 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const {unstringifyBigInts: unstringifyBigInts$8} = ffjavascript.utils; - + const input = unstringifyBigInts$9(_input); + const wtns = { type: "mem" }; + await wtnsCalculate$1(input, wasmFile, wtns, wtnsCalcOptions); + return await groth16Prove$1(zkeyFileName, wtns, logger, proverOptions); +} +//#endregion +//#region src/groth16_verify.js +var { unstringifyBigInts: unstringifyBigInts$8 } = ffjavascript.utils; async function groth16Verify$1(_vk_verifier, _publicSignals, _proof, logger) { -/* - let cpub = vk_verifier.IC[0]; - for (let s= 0; s< vk_verifier.nPublic; s++) { - cpub = G1.add( cpub, G1.timesScalar( vk_verifier.IC[s+1], publicSignals[s])); - } -*/ - - const vk_verifier = unstringifyBigInts$8(_vk_verifier); - const proof = unstringifyBigInts$8(_proof); - const publicSignals = unstringifyBigInts$8(_publicSignals); - - const curve = await getCurveFromName(vk_verifier.curve); - - const IC0 = curve.G1.fromObject(vk_verifier.IC[0]); - const IC = new Uint8Array(curve.G1.F.n8*2 * publicSignals.length); - const w = new Uint8Array(curve.Fr.n8 * publicSignals.length); - - if (!publicInputsAreValid$2(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - for (let i=0; i. -*/ -const { unstringifyBigInts: unstringifyBigInts$7} = ffjavascript.utils; - + for (let i = 0; i < publicInputs.length; i++) if (!checkValueBelongToField$2(curve, publicInputs[i])) return false; + return true; +} +//#endregion +//#region src/groth16_exportsoliditycalldata.js +var { unstringifyBigInts: unstringifyBigInts$7 } = ffjavascript.utils; function p256$2(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0"+nstr; - nstr = `"0x${nstr}"`; - return nstr; + let nstr = n.toString(16); + while (nstr.length < 64) nstr = "0" + nstr; + nstr = `"0x${nstr}"`; + return nstr; } - async function groth16ExportSolidityCallData(_proof, _pub) { - const proof = unstringifyBigInts$7(_proof); - const pub = unstringifyBigInts$7(_pub); - - let inputs = ""; - for (let i=0; i. -*/ - - - + const proof = unstringifyBigInts$7(_proof); + const pub = unstringifyBigInts$7(_pub); + let inputs = ""; + for (let i = 0; i < pub.length; i++) { + if (inputs != "") inputs = inputs + ","; + inputs = inputs + p256$2(pub[i]); + } + let S; + S = `[${p256$2(proof.pi_a[0])}, ${p256$2(proof.pi_a[1])}],[[${p256$2(proof.pi_b[0][1])}, ${p256$2(proof.pi_b[0][0])}],[${p256$2(proof.pi_b[1][1])}, ${p256$2(proof.pi_b[1][0])}]],[${p256$2(proof.pi_c[0])}, ${p256$2(proof.pi_c[1])}],[${inputs}]`; + return S; +} +//#endregion +//#region src/plonk_setup.js async function plonkSetup$1(r1csName, ptauName, zkeyName, logger) { - - if (globalThis.gc) {globalThis.gc();} - - const {fd: fdPTau, sections: sectionsPTau} = await binFileUtils.readBinFile(ptauName, "ptau", 1, 1<<22, 1<<24); - const {curve, power} = await readPTauHeader(fdPTau, sectionsPTau); - const {fd: fdR1cs, sections: sectionsR1cs} = await binFileUtils.readBinFile(r1csName, "r1cs", 1, 1<<22, 1<<24); - - const r1cs = await r1csfile.readR1csFd(fdR1cs, sectionsR1cs, {loadConstraints: true, loadCustomGates: true}); - - const sG1 = curve.G1.F.n8*2; - const G1 = curve.G1; - const sG2 = curve.G2.F.n8*2; - const Fr = curve.Fr; - const n8r = curve.Fr.n8; - - if (logger) logger.info("Reading r1cs"); - - const plonkConstraints = new BigArray(); - const plonkAdditions = new BigArray(); - let plonkNVars = r1cs.nVars; - - const nPublic = r1cs.nOutputs + r1cs.nPubInputs; - - await processConstraints(curve.Fr, r1cs, logger); - - if (globalThis.gc) {globalThis.gc();} - - const fdZKey = await binFileUtils.createBinFile(zkeyName, "zkey", 1, 14, 1<<22, 1<<24); - - - if (r1cs.prime != curve.r) { - if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); - return -1; - } - - let cirPower = log2(plonkConstraints.length -1) +1; - if (cirPower < 3) cirPower = 3; // As the t polynomial is n+5 we need at least a power of 4 - const domainSize = 2 ** cirPower; - - if (logger) logger.info("Plonk constraints: " + plonkConstraints.length); - if (cirPower > power) { - if (logger) logger.error(`circuit too big for this power of tau ceremony. ${plonkConstraints.length} > 2**${power}`); - return -1; - } - - if (!sectionsPTau[12]) { - if (logger) logger.error("Powers of tau is not prepared."); - return -1; - } - - - const LPoints = new ffjavascript.BigBuffer(domainSize*sG1); - const o = sectionsPTau[12][0].p + ((2 ** (cirPower)) -1)*sG1; - await fdPTau.readToBuffer(LPoints, 0, domainSize*sG1, o); - - const [k1, k2] = getK1K2(); - - const vk = {}; - - - await writeAdditions(3, "Additions"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(4, 0, "Amap"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(5, 1, "Bmap"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(6, 2, "Cmap"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(7, 3, "Qm"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(8, 4, "Ql"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(9, 5, "Qr"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(10, 6, "Qo"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(11, 7, "Qc"); - if (globalThis.gc) {globalThis.gc();} - await writeSigma(12, "sigma"); - if (globalThis.gc) {globalThis.gc();} - await writeLs(13, "lagrange polynomials"); - if (globalThis.gc) {globalThis.gc();} - - // Write PTau points - //////////// - - await binFileUtils.startWriteSection(fdZKey, 14); - const buffOut = new ffjavascript.BigBuffer((domainSize+6)*sG1); - await fdPTau.readToBuffer(buffOut, 0, (domainSize+6)*sG1, sectionsPTau[2][0].p); - await fdZKey.write(buffOut); - await binFileUtils.endWriteSection(fdZKey); - if (globalThis.gc) {globalThis.gc();} - - - await writeHeaders(); - - await fdZKey.close(); - await fdR1cs.close(); - await fdPTau.close(); - - if (logger) logger.info("Setup Finished"); - - return ; - - async function processConstraints(Fr, r1cs, logger) { - - function normalize(linearComb) { - const ss = Object.keys(linearComb); - for (let i = 0; i < ss.length; i++) { - if (linearComb[ss[i]] == 0n) delete linearComb[ss[i]]; - } - } - - function join(linearComb1, k, linearComb2) { - const res = {}; - - for (let s in linearComb1) { - if (typeof res[s] == "undefined") { - res[s] = Fr.mul(k, linearComb1[s]); - } else { - res[s] = Fr.add(res[s], Fr.mul(k, linearComb1[s])); - } - } - - for (let s in linearComb2) { - if (typeof res[s] == "undefined") { - res[s] = linearComb2[s]; - } else { - res[s] = Fr.add(res[s], linearComb2[s]); - } - } - normalize(res); - return res; - } - - function reduceCoefs(linearComb, maxC) { - const res = { - k: Fr.zero, - s: [], - coefs: [] - }; - const cs = []; - - for (let s in linearComb) { - if (s == 0) { - res.k = Fr.add(res.k, linearComb[s]); - } else if (linearComb[s] != 0n) { - cs.push([Number(s), linearComb[s]]); - } - } - while (cs.length > maxC) { - const c1 = cs.shift(); - const c2 = cs.shift(); - - const sl = c1[0]; - const sr = c2[0]; - const so = plonkNVars++; - const qm = Fr.zero; - const ql = Fr.neg(c1[1]); - const qr = Fr.neg(c2[1]); - const qo = Fr.one; - const qc = Fr.zero; - - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - - plonkAdditions.push([sl, sr, c1[1], c2[1]]); - - cs.push([so, Fr.one]); - } - for (let i = 0; i < cs.length; i++) { - res.s[i] = cs[i][0]; - res.coefs[i] = cs[i][1]; - } - while (res.coefs.length < maxC) { - res.s.push(0); - res.coefs.push(Fr.zero); - } - return res; - } - - function addConstraintSum(lc) { - const C = reduceCoefs(lc, 3); - const sl = C.s[0]; - const sr = C.s[1]; - const so = C.s[2]; - const qm = Fr.zero; - const ql = C.coefs[0]; - const qr = C.coefs[1]; - const qo = C.coefs[2]; - const qc = C.k; - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - function addConstraintMul(lcA, lcB, lcC) { - const A = reduceCoefs(lcA, 1); - const B = reduceCoefs(lcB, 1); - const C = reduceCoefs(lcC, 1); - - - const sl = A.s[0]; - const sr = B.s[0]; - const so = C.s[0]; - const qm = Fr.mul(A.coefs[0], B.coefs[0]); - const ql = Fr.mul(A.coefs[0], B.k); - const qr = Fr.mul(A.k, B.coefs[0]); - const qo = Fr.neg(C.coefs[0]); - const qc = Fr.sub(Fr.mul(A.k, B.k), C.k); - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - function getLinearCombinationType(lc) { - let k = Fr.zero; - let n = 0; - const ss = Object.keys(lc); - for (let i = 0; i < ss.length; i++) { - if (lc[ss[i]] == 0n) { - delete lc[ss[i]]; - } else if (ss[i] == 0) { - k = Fr.add(k, lc[ss[i]]); - } else { - n++; - } - } - if (n > 0) return n.toString(); - if (k != Fr.zero) return "k"; - return "0"; - } - - function process(lcA, lcB, lcC) { - const lctA = getLinearCombinationType(lcA); - const lctB = getLinearCombinationType(lcB); - if ((lctA === "0") || (lctB === "0")) { - normalize(lcC); - addConstraintSum(lcC); - } else if (lctA === "k") { - const lcCC = join(lcB, lcA[0], lcC); - addConstraintSum(lcCC); - } else if (lctB === "k") { - const lcCC = join(lcA, lcB[0], lcC); - addConstraintSum(lcCC); - } else { - addConstraintMul(lcA, lcB, lcC); - } - } - - for (let s = 1; s <= nPublic; s++) { - const sl = s; - const sr = 0; - const so = 0; - const qm = Fr.zero; - const ql = Fr.one; - const qr = Fr.zero; - const qo = Fr.zero; - const qc = Fr.zero; - - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - for (let c = 0; c < r1cs.constraints.length; c++) { - if ((logger) && (c % 10000 === 0)) logger.debug(`processing constraints: ${c}/${r1cs.nConstraints}`); - process(...r1cs.constraints[c]); - } - } - - async function writeWitnessMap(sectionNum, posConstraint, name) { - await binFileUtils.startWriteSection(fdZKey, sectionNum); - for (let i=0; i. -*/ - -class Proof { - constructor(curve, logger) { - this.curve = curve; - this.logger = logger; - - this.resetProof(); - } - - resetProof() { - this.polynomials = {}; - this.evaluations = {}; - } - - addPolynomial(key, polynomial) { - if (key in this.polynomials) { - this.logger.warn(`proof: polynomial.${key} already exist in proof`); - } - this.polynomials[key] = polynomial; - } - - getPolynomial(key) { - if (!(key in this.polynomials)) { - this.logger.warn(`proof: polynomial ${key} does not exist in proof`); - } - return this.polynomials[key]; - } - - addEvaluation(key, evaluation) { - if (key in this.evaluations) { - this.logger.warn(`proof: evaluations.${key} already exist in proof`); - } - this.evaluations[key] = evaluation; - } - - getEvaluation(key) { - if (!(key in this.evaluations)) { - this.logger.warn(`proof: evaluation ${key} does not exist in proof`); - } - return this.evaluations[key]; - } - - toObjectProof(splitFields = true) { - let res = splitFields ? {polynomials: {}, evaluations: {}} : {}; - - Object.keys(this.polynomials).forEach(key => { - const value = this.curve.G1.toObject(this.polynomials[key]); - if(splitFields) { - res.polynomials[key] = value; - } else { - res[key] = value; - } - }); - - Object.keys(this.evaluations).forEach(key => { - const value = this.curve.Fr.toObject(this.evaluations[key]); - if(splitFields) { - res.evaluations[key] = value; - } else { - res[key] = value; - } - }); - - return res; - } - - fromObjectProof(objectProof) { - this.resetProof(); - - Object.keys(objectProof.polynomials).forEach(key => { - this.polynomials[key] = this.curve.G1.fromObject(objectProof.polynomials[key]); - }); - - Object.keys(objectProof.evaluations).forEach(key => { - this.evaluations[key] = this.curve.Fr.fromObject(objectProof.evaluations[key]); - }); - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const POLYNOMIAL = 0; -const SCALAR = 1; - -class Keccak256Transcript { - constructor(curve) { - this.G1 = curve.G1; - this.Fr = curve.Fr; - - this.reset(); - } - - reset() { - this.data = []; - } - - addPolCommitment(polynomialCommitment) { - this.data.push({type: POLYNOMIAL, data: polynomialCommitment}); - } - - addScalar(scalar) { - this.data.push({type: SCALAR, data: scalar}); - } - - getChallenge() { - if(0 === this.data.length) { - throw new Error("Keccak256Transcript: No data to generate a transcript"); - } - - let nPolynomials = 0; - let nScalars = 0; - - this.data.forEach(element => POLYNOMIAL === element.type ? nPolynomials++ : nScalars++); - - let buffer = new Uint8Array(nScalars * this.Fr.n8 + nPolynomials * this.G1.F.n8 * 2); - let offset = 0; - - for (let i = 0; i < this.data.length; i++) { - if (POLYNOMIAL === this.data[i].type) { - this.G1.toRprUncompressed(buffer, offset, this.data[i].data); - offset += this.G1.F.n8 * 2; - } else { - this.Fr.toRprBE(buffer, offset, this.data[i].data); - offset += this.Fr.n8; - } - } - - const value = ffjavascript.Scalar.fromRprBE(sha3_js.keccak_256(buffer)); - return this.Fr.e(value); - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -class MulZ { - static getZ1(Fr) { - return [ - Fr.zero, - Fr.add(Fr.e(-1), Fr.w[2]), - Fr.e(-2), - Fr.sub(Fr.e(-1), Fr.w[2]), - ]; - } - - static getZ2(Fr) { - return [ - Fr.zero, - Fr.add(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), - Fr.e(4), - Fr.sub(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), - ]; - } - - static getZ3(Fr) { - return [ - Fr.zero, - Fr.add(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), - Fr.e(-8), - Fr.sub(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), - ]; - - } - - static mul2(a, b, ap, bp, p, Fr) { - const Z1 = this.getZ1(Fr); - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - r = a_b; - - let a0 = Fr.add(a_bp, ap_b); - - let a1 = ap_bp; - - rz = a0; - if (p) { - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - } - - return [r, rz]; - } - - static mul3(a, b, c, ap, bp, cp, p, Fr) { - const Z1 = this.getZ1(Fr); - const Z2 = this.getZ2(Fr); - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - r = Fr.mul(a_b, c); - - let a0 = Fr.mul(ap_b, c); - a0 = Fr.add(a0, Fr.mul(a_bp, c)); - a0 = Fr.add(a0, Fr.mul(a_b, cp)); - - let a1 = Fr.mul(ap_bp, c); - a1 = Fr.add(a1, Fr.mul(a_bp, cp)); - a1 = Fr.add(a1, Fr.mul(ap_b, cp)); - - rz = a0; - if (p) { - const a2 = Fr.mul(ap_bp, cp); - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - rz = Fr.add(rz, Fr.mul(Z2[p], a2)); - } - - return [r, rz]; - } - - static mul4(a, b, c, d, ap, bp, cp, dp, p, Fr) { - const Z1 = this.getZ1(Fr); - const Z2 = this.getZ2(Fr); - const Z3 = this.getZ3(Fr); - - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - const c_d = Fr.mul(c, d); - const c_dp = Fr.mul(c, dp); - const cp_d = Fr.mul(cp, d); - const cp_dp = Fr.mul(cp, dp); - - r = Fr.mul(a_b, c_d); - - let a0 = Fr.mul(ap_b, c_d); - a0 = Fr.add(a0, Fr.mul(a_bp, c_d)); - a0 = Fr.add(a0, Fr.mul(a_b, cp_d)); - a0 = Fr.add(a0, Fr.mul(a_b, c_dp)); - - let a1 = Fr.mul(ap_bp, c_d); - a1 = Fr.add(a1, Fr.mul(ap_b, cp_d)); - a1 = Fr.add(a1, Fr.mul(ap_b, c_dp)); - a1 = Fr.add(a1, Fr.mul(a_bp, cp_d)); - a1 = Fr.add(a1, Fr.mul(a_bp, c_dp)); - a1 = Fr.add(a1, Fr.mul(a_b, cp_dp)); - - let a2 = Fr.mul(a_bp, cp_dp); - a2 = Fr.add(a2, Fr.mul(ap_b, cp_dp)); - a2 = Fr.add(a2, Fr.mul(ap_bp, c_dp)); - a2 = Fr.add(a2, Fr.mul(ap_bp, cp_d)); - - let a3 = Fr.mul(ap_bp, cp_dp); - - rz = a0; - if (p) { - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - rz = Fr.add(rz, Fr.mul(Z2[p], a2)); - rz = Fr.add(rz, Fr.mul(Z3[p], a3)); - } - - return [r, rz]; - } -} - -const ZKEY_PL_ADDITIONS_SECTION = 3; -const ZKEY_PL_A_MAP_SECTION = 4; -const ZKEY_PL_B_MAP_SECTION = 5; -const ZKEY_PL_C_MAP_SECTION = 6; -const ZKEY_PL_QM_SECTION = 7; -const ZKEY_PL_QL_SECTION = 8; -const ZKEY_PL_QR_SECTION = 9; -const ZKEY_PL_QO_SECTION = 10; -const ZKEY_PL_QC_SECTION = 11; -const ZKEY_PL_SIGMA_SECTION = 12; -const ZKEY_PL_LAGRANGE_SECTION = 13; -const ZKEY_PL_PTAU_SECTION = 14; - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -class Polynomial { - constructor(coefficients, curve, logger) { - this.coef = coefficients; - this.curve = curve; - this.Fr = curve.Fr; - this.G1 = curve.G1; - this.logger = logger; - } - - static async fromEvaluations(buffer, curve, logger) { - let coefficients = await curve.Fr.ifft(buffer); - - return new Polynomial(coefficients, curve, logger); - } - - static fromCoefficientsArray(array, curve, logger) { - const Fr = curve.Fr; - let buff = array.length > 2 << 14 ? - new ffjavascript.BigBuffer(array.length * Fr.n8) : new Uint8Array(array.length * Fr.n8); - for (let i = 0; i < array.length; i++) buff.set(array[i], i * Fr.n8); - - return new Polynomial(buff, curve, logger); - } - - static fromPolynomial(polynomial, curve, logger) { - let length = polynomial.length(); - let Fr = curve.Fr; - - let buff = length > 2 << 14 ? - new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - buff.set(polynomial.coef.slice(), 0); - - return new Polynomial(buff, curve, logger); - } - - isEqual(polynomial) { - const degree = this.degree(); - if (degree !== polynomial.degree()) return false; - - for (let i = 0; i < degree + 1; i++) { - if (!this.Fr.eq(this.getCoef(i), polynomial.getCoef(i))) return false; - } - - return true; - } - - blindCoefficients(blindingFactors) { - blindingFactors = blindingFactors || []; - - const blindedCoefficients = (this.length() + blindingFactors.length) > 2 << 14 ? - new ffjavascript.BigBuffer((this.length() + blindingFactors.length) * this.Fr.n8) : - new Uint8Array((this.length() + blindingFactors.length) * this.Fr.n8); - - blindedCoefficients.set(this.coef, 0); - for (let i = 0; i < blindingFactors.length; i++) { - blindedCoefficients.set( - this.Fr.add( - blindedCoefficients.slice((this.length() + i) * this.Fr.n8, (this.length() + i + 1) * this.Fr.n8), - blindingFactors[i] - ), - (this.length() + i) * this.Fr.n8 - ); - blindedCoefficients.set( - this.Fr.sub( - blindedCoefficients.slice(i * this.Fr.n8, (i + 1) * this.Fr.n8), - blindingFactors[i] - ), - i * this.Fr.n8 - ); - } - this.coef = blindedCoefficients; - } - - getCoef(index) { - const i_n8 = index * this.Fr.n8; - - if (i_n8 + this.Fr.n8 > this.coef.byteLength) return this.Fr.zero; - - return this.coef.slice(i_n8, i_n8 + this.Fr.n8); - } - - setCoef(index, value) { - if (index > (this.length() - 1)) { - throw new Error("Coef index is not available"); - } - - this.coef.set(value, index * this.Fr.n8); - } - - static async to4T(buffer, domainSize, blindingFactors, Fr) { - blindingFactors = blindingFactors || []; - let a = await Fr.ifft(buffer); - - const a4 = (domainSize * 4) > 2 << 14 ? - new ffjavascript.BigBuffer(domainSize * 4 * Fr.n8) : new Uint8Array(domainSize * 4 * Fr.n8); - a4.set(a, 0); - - const A4 = await Fr.fft(a4); - - if (blindingFactors.length === 0) { - return [a, A4]; - } - - const a1 = domainSize + blindingFactors.length > 2 << 14 ? - new ffjavascript.BigBuffer((domainSize + blindingFactors.length) * Fr.n8) : - new Uint8Array((domainSize + blindingFactors.length) * Fr.n8); - - a1.set(a, 0); - for (let i = 0; i < blindingFactors.length; i++) { - a1.set( - Fr.add( - a1.slice((domainSize + i) * Fr.n8, (domainSize + i + 1) * Fr.n8), - blindingFactors[i] - ), - (domainSize + i) * Fr.n8 - ); - a1.set( - Fr.sub( - a1.slice(i * Fr.n8, (i + 1) * Fr.n8), - blindingFactors[i] - ), - i * Fr.n8 - ); - } - - return [a1, A4]; - } - - length() { - let length = this.coef.byteLength / this.Fr.n8; - if (length !== Math.floor(this.coef.byteLength / this.Fr.n8)) { - throw new Error("Polynomial coefficients buffer has incorrect size"); - } - if (0 === length) { - if (this.logger) { - this.logger.warn("Polynomial has length zero"); - } - } - return length; - } - - degree() { - for (let i = this.length() - 1; i > 0; i--) { - const i_n8 = i * this.Fr.n8; - if (!this.Fr.eq(this.Fr.zero, this.coef.slice(i_n8, i_n8 + this.Fr.n8))) { - return i; - } - } - - return 0; - } - - evaluate(point) { - let res = this.Fr.zero; - - for (let i = this.degree() + 1; i > 0; i--) { - let i_n8 = i * this.Fr.n8; - const currentCoefficient = this.coef.slice(i_n8 - this.Fr.n8, i_n8); - res = this.Fr.add(currentCoefficient, this.Fr.mul(res, point)); - } - - return res; - } - - fastEvaluate(point) { - const Fr = this.Fr; - let nThreads = 3; - - let nCoefs = this.degree() + 1; - let coefsThread = parseInt(nCoefs / nThreads); - let residualCoefs = nCoefs - coefsThread * nThreads; - - let res = []; - let xN = []; - - xN[0] = Fr.one; - - for (let i = 0; i < nThreads; i++) { - res[i] = Fr.zero; - - let nCoefs = i === (nThreads - 1) ? coefsThread + residualCoefs : coefsThread; - for (let j = nCoefs; j > 0; j--) { - res[i] = Fr.add(this.getCoef((i * coefsThread) + j - 1), Fr.mul(res[i], point)); - - if (i === 0) xN[0] = Fr.mul(xN[0], point); - } - } - - for (let i = 1; i < nThreads; i++) { - res[0] = Fr.add(res[0], Fr.mul(xN[i - 1], res[i])); - xN[i] = Fr.mul(xN[i - 1], xN[0]); - } - - return res[0]; - } - - add(polynomial, blindingValue) { - let other = false; - - if (polynomial.length() > this.length()) { - other = true; - } - - const thisLength = this.length(); - const polyLength = polynomial.length(); - for (let i = 0; i < Math.max(thisLength, polyLength); i++) { - const i_n8 = i * this.Fr.n8; - - const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - - if (blindingValue !== undefined) { - b = this.Fr.mul(b, blindingValue); - } - if (other) { - polynomial.coef.set(this.Fr.add(a, b), i_n8); - } else { - this.coef.set(this.Fr.add(a, b), i_n8); - } - } - if (other) { - delete this.coef; - this.coef = polynomial.coef; - } - } - - sub(polynomial, blindingValue) { - let other = false; - - if (polynomial.length() > this.length()) { - other = true; - } - - const thisLength = this.length(); - const polyLength = polynomial.length(); - for (let i = 0; i < Math.max(thisLength, polyLength); i++) { - const i_n8 = i * this.Fr.n8; - - const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - - if (blindingValue !== undefined) { - b = this.Fr.mul(b, blindingValue); - } - if (other) { - polynomial.coef.set(this.Fr.sub(a, b), i_n8); - } else { - this.coef.set(this.Fr.sub(a, b), i_n8); - } - } - if (other) { - delete this.coef; - this.coef = polynomial.coef; - } - } - - mulScalar(value) { - for (let i = 0; i < this.length(); i++) { - const i_n8 = i * this.Fr.n8; - - this.coef.set(this.Fr.mul(this.coef.slice(i_n8, i_n8 + this.Fr.n8), value), i_n8); - } - } - - addScalar(value) { - const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); - this.coef.set(this.Fr.add(currentValue, value), 0); - } - - subScalar(value) { - const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); - this.coef.set(this.Fr.sub(currentValue, value), 0); - } - - // Multiply current polynomial by the polynomial (X - value) - byXSubValue(value) { - const Fr = this.Fr; - const resize = !Fr.eq(Fr.zero, this.getCoef(this.length() - 1)); - - const length = resize ? this.length() + 1 : this.length(); - const buff = length > 2 << 14 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - let pol = new Polynomial(buff, this.curve, this.logger); - - // Step 0: Set current coefficients to the new buffer shifted one position - pol.coef.set(this.coef.slice(0, (length - 1) * Fr.n8), 32); - - // Step 1: multiply each coefficient by (-value) - this.mulScalar(Fr.neg(value)); - - // Step 2: Add current polynomial to destination polynomial - pol.add(this); - - // Swap buffers - this.coef = pol.coef; - } - - // Multiply current polynomial by the polynomial (X^n + value) - byXNSubValue(n, value) { - const Fr = this.Fr; - const resize = !(this.length() - n - 1 >= this.degree()); - - const length = resize ? this.length() + n : this.length(); - const buff = length > 2 << 14 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - let pol = new Polynomial(buff, this.curve, this.logger); - - // Step 0: Set current coefficients to the new buffer shifted one position - pol.coef.set(this.coef.slice(0, (this.degree() + 1) * 32, ), n * 32); - - // Step 1: multiply each coefficient by (- value) - this.mulScalar(value); - - // Step 2: Add current polynomial to destination polynomial - pol.add(this); - - // Swap buffers - this.coef = pol.coef; - } - - // Euclidean division - divBy(polynomial) { - const Fr = this.Fr; - const degreeA = this.degree(); - const degreeB = polynomial.degree(); - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - for (let i = degreeA - degreeB; i >= 0; i--) { - this.setCoef(i, Fr.div(polR.getCoef(i + degreeB), polynomial.getCoef(degreeB))); - for (let j = 0; j <= degreeB; j++) { - polR.setCoef(i + j, Fr.sub(polR.getCoef(i + j), Fr.mul(this.getCoef(i), polynomial.getCoef(j)))); - } - } - - return polR; - } - - // Division by a Polynomial of the form (x^m - beta) - divByMonic(m, beta) { - const Fr = this.Fr; - - let d = this.degree(); - - let buffer = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - let quotient = new Polynomial(buffer, this.curve, this.logger); - - let bArr = []; - - // Add the m leading coefficients of this to quotient - for (let i = 0; i < m; i++) { - quotient.setCoef((d - i) - m, this.getCoef(d - i)); - bArr[i] = this.getCoef(d - i); - } - - let nThreads = m; - for (let k = 0; k < nThreads; k++) { - for (let i = d - 2 * m - k; i >= 0; i = i - nThreads) { - if (i < 0) break; - let idx = k; - bArr[idx] = Fr.add(this.getCoef(i + m), Fr.mul(bArr[idx], beta)); - - quotient.setCoef(i, bArr[idx]); - } - } - - this.coef = quotient.coef; - } - - divByVanishing(n, beta) { - if (this.degree() < n) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - const Fr = this.Fr; - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - for (let i = this.length() - 1; i >= n; i--) { - let leadingCoef = polR.getCoef(i); - if (Fr.eq(Fr.zero, leadingCoef)) continue; - - polR.setCoef(i, Fr.zero); - polR.setCoef(i - n, Fr.add(polR.getCoef(i - n), Fr.mul(beta, leadingCoef))); - this.setCoef(i - n, Fr.add(this.getCoef(i - n), leadingCoef)); - } - - return polR; - } - - divByVanishing2(m, beta) { - if (this.degree() < m) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - const Fr = this.Fr; - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - let nThreads = 3; - let nTotal = this.length() - m; - let nElementsChunk = Math.floor(nTotal / nThreads); - let nElementsLast = nTotal - (nThreads - 1) * nElementsChunk; - - console.log(nTotal); - console.log(nElementsChunk + " " + nElementsLast); - for (let k = 0; k < nThreads; k++) { - console.log("> Thread " + k); - for (let i = (k === 0 ? nElementsLast : nElementsChunk); i > 0; i--) { - let idxDst = i - 1; - if (k !== 0) idxDst += (k - 1) * nElementsChunk + nElementsLast; - let idxSrc = idxDst + m; - - let leadingCoef = polR.getCoef(idxSrc); - if (Fr.eq(Fr.zero, leadingCoef)) continue; - - polR.setCoef(idxSrc, Fr.zero); - polR.setCoef(idxDst, Fr.add(polR.getCoef(idxDst), Fr.mul(beta, leadingCoef))); - this.setCoef(idxDst, Fr.add(this.getCoef(idxDst), leadingCoef)); - console.log(idxDst + " <-- " + idxSrc); - } - } - - this.print(); - return polR; - } - - fastDivByVanishing(data) { - const Fr = this.Fr; - - for (let i = 0; i < data.length; i++) { - - let m = data[i][0]; - let beta = data[i][1]; - - if (this.degree() < m) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - let nThreads = 5; - let nElements = this.length() - m; - let nElementsBucket = Math.floor(nElements / nThreads / m); - let nElementsChunk = nElementsBucket * m; - let nElementsLast = nElements - nThreads * nElementsChunk; - - //In C++ implementation this buffer will be allocated only once outside the loop - let polTmp = new Polynomial(this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8), this.curve, this.logger); - - let ptr = this.coef; - this.coef = polTmp.coef; - polTmp.coef = ptr; - - // STEP 1: Setejar els m valors del següent bucket al chunk actual, PARALEL·LITZAR - for (let k = 0; k < nThreads; k++) { - let idx0 = (k + 1) * nElementsChunk + nElementsLast; - for (let i = 0; i < m; i++) { - this.setCoef(idx0 + i - m, polTmp.getCoef(idx0 + i)); - } - - for (let i = 0; i < nElementsChunk - m; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); - this.setCoef(offset - m, val); - } - } - - //STEP 2: Setejar els valors del elements last NO PARAL·LELITZAR - let idx0 = nElementsLast; - let pending = nElementsLast; - for (let i = 0; i < m && pending; i++) { - this.setCoef(idx0 - i - 1, polTmp.getCoef(idx0 + m - i - 1)); - pending--; - } - - for (let i = 0; i < pending; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); - this.setCoef(offset - m, val); - } - - //Step 3: calcular acumulats NO PARALEL·LITZAR - - let acc = []; - let betaPow = Fr.one; - for (let i = 0; i < nElementsBucket; i++) { - betaPow = Fr.mul(betaPow, beta); - } - let currentBeta = Fr.one; - - for (let k = nThreads; k > 0; k--) { - let idThread = k - 1; - let idx0 = idThread * nElementsChunk + nElementsLast; - acc[idThread] = []; - - for (let i = 0; i < m; i++) { - acc[idThread][i] = this.getCoef(idx0 + i); - - if (k !== nThreads) { - acc[idThread][i] = Fr.add(acc[idThread][i], Fr.mul(betaPow, acc[idThread + 1][i])); - } - } - currentBeta = Fr.mul(currentBeta, betaPow); - } - - //STEP 4 recalcular PARALEL·LITZAR - for (let k = 0; k < nThreads; k++) { - - let idx0 = k * nElementsChunk + nElementsLast; - let currentBeta = beta; //Quan hopassem a C++ i ho paralelitzem aquesta variable ha de ser privada - let currentM = m - 1; - - let limit = k === 0 ? nElementsLast : nElementsChunk; - for (let i = 0; i < limit; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(this.getCoef(offset), Fr.mul(currentBeta, acc[k][currentM])); - - this.setCoef(offset, val); - - // To avoid modular operations in each loop... - if (currentM === 0) { - currentM = m - 1; - currentBeta = Fr.mul(currentBeta, beta); - } else { - currentM--; - } - } - } - } - } - - - // Divide polynomial by X - value - divByXSubValue(value) { - const coefs = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * this.Fr.n8) : new Uint8Array(this.length() * this.Fr.n8); - - coefs.set(this.Fr.zero, (this.length() - 1) * this.Fr.n8); - coefs.set(this.coef.slice((this.length() - 1) * this.Fr.n8, this.length() * this.Fr.n8), (this.length() - 2) * this.Fr.n8); - for (let i = this.length() - 3; i >= 0; i--) { - let i_n8 = i * this.Fr.n8; - coefs.set( - this.Fr.add( - this.coef.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8), - this.Fr.mul(value, coefs.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8)) - ), - i * this.Fr.n8 - ); - } - if (!this.Fr.eq( - this.coef.slice(0, this.Fr.n8), - this.Fr.mul(this.Fr.neg(value), coefs.slice(0, this.Fr.n8)) - )) { - throw new Error("Polynomial does not divide"); - } - - this.coef = coefs; - } - - divZh(domainSize, extensions = 4) { - for (let i = 0; i < domainSize; i++) { - const i_n8 = i * this.Fr.n8; - this.coef.set(this.Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)), i_n8); - } - - const upperBound = this.coef.byteLength / this.Fr.n8; - for (let i = domainSize; i < upperBound; i++) { - const i_n8 = i * this.Fr.n8; - - const a = this.Fr.sub( - this.coef.slice((i - domainSize) * this.Fr.n8, (i - domainSize) * this.Fr.n8 + this.Fr.n8), - this.coef.slice(i_n8, i_n8 + this.Fr.n8) - ); - this.coef.set(a, i_n8); - if (i > (domainSize * (extensions-1) - extensions)) { - if (!this.Fr.isZero(a)) { - throw new Error("Polynomial is not divisible"); - } - } - } - - return this; - } - - divByZerofier(n, beta) { - let Fr = this.Fr; - const invBeta = Fr.inv(beta); - const invBetaNeg = Fr.neg(invBeta); - - let isOne = Fr.eq(Fr.one, invBetaNeg); - let isNegOne = Fr.eq(Fr.negone, invBetaNeg); - - if (!isOne) { - for (let i = 0; i < n; i++) { - const i_n8 = i * this.Fr.n8; - let element; - - // If invBetaNeg === -1 we'll save a multiplication changing it by a neg function call - if (isNegOne) { - element = Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)); - } else { - element = Fr.mul(invBetaNeg, this.coef.slice(i_n8, i_n8 + this.Fr.n8)); - } - - this.coef.set(element, i_n8); - } - } - - isOne = Fr.eq(Fr.one, invBeta); - isNegOne = Fr.eq(Fr.negone, invBeta); - - for (let i = n; i < this.length(); i++) { - const i_n8 = i * this.Fr.n8; - const i_prev_n8 = (i - n) * this.Fr.n8; - - let element = this.Fr.sub( - this.coef.slice(i_prev_n8, i_prev_n8 + this.Fr.n8), - this.coef.slice(i_n8, i_n8 + this.Fr.n8) - ); - - // If invBeta === 1 we'll not do anything - if(!isOne) { - // If invBeta === -1 we'll save a multiplication changing it by a neg function call - if(isNegOne) { - element = Fr.neg(element); - } else { - element = Fr.mul(invBeta, element); - } - } - - this.coef.set(element, i_n8); - - // Check if polynomial is divisible by checking if n high coefficients are zero - if (i > this.length() - n - 1) { - if (!this.Fr.isZero(element)) { - throw new Error("Polynomial is not divisible"); - } - } - } - - return this; - } - - // function divideByVanishing(f, n, p) { - // // polynomial division f(X) / (X^n - 1) with remainder - // // very cheap, 0 multiplications - // // strategy: - // // start with q(X) = 0, r(X) = f(X) - // // then start changing q, r while preserving the identity: - // // f(X) = q(X) * (X^n - 1) + r(X) - // // in every step, move highest-degree term of r into the product - // // => r eventually has degree < n and we're done - // let q = Array(f.length).fill(0n); - // let r = [...f]; - // for (let i = f.length - 1; i >= n; i--) { - // let leadingCoeff = r[i]; - // if (leadingCoeff === 0n) continue; - // r[i] = 0n; - // r[i - n] = mod(r[i - n] + leadingCoeff, p); - // q[i - n] = mod(q[i - n] + leadingCoeff, p); - // } - // return [q, r]; - // } - - byX() { - const coefs = (this.length() + 1) > 2 << 14 ? - new ffjavascript.BigBuffer(this.coef.byteLength + this.Fr.n8) : new Uint8Array(this.coef.byteLength + this.Fr.n8); - coefs.set(this.Fr.zero, 0); - coefs.set(this.coef, this.Fr.n8); - - this.coef = coefs; - } - - // Compute a new polynomial f(x^n) from f(x) - // f(x) = a_0 + a_1·x + a_2·x^2 + ... + a_j·x^j - // f(x^n) = a_0 + a_1·x^n + a_2·x^2n + ... + a_j·x^jn - static - async expX(polynomial, n, truncate = false) { - const Fr = polynomial.Fr; - - if (n < 1) { - // n == 0 not allowed because it has no sense, but if it's necessary we have to return - // a zero degree polynomial with a constant coefficient equals to the sum of all the original coefficients - throw new Error("Compute a new polynomial to a zero or negative number is not allowed"); - } else if (1 === n) { - return await Polynomial.fromEvaluations(polynomial.coef, polynomial.curve, polynomial.logger); - } - - // length is the length of non-constant coefficients - // if truncate === true, the highest zero coefficients (if exist) will be removed - const length = truncate ? polynomial.degree() : (polynomial.length() - 1); - const bufferDst = (length * n + 1) > 2 << 14 ? - new ffjavascript.BigBuffer((length * n + 1) * Fr.n8) : new Uint8Array((length * n + 1) * Fr.n8); - - // Copy constant coefficient as is because is not related to x - bufferDst.set(polynomial.getCoef(0), 0); - - for (let i = 1; i <= length; i++) { - const i_sFr = i * Fr.n8; - - const coef = polynomial.getCoef(i); - bufferDst.set(coef, i_sFr * n); - } - - return new Polynomial(bufferDst, polynomial.curve, polynomial.logger); - } - - split(numPols, degPols, blindingFactors) { - if (numPols < 1) { - throw new Error(`Polynomials can't be split in ${numPols} parts`); - } else if (1 === numPols) { - return [this]; - } - - //blinding factors can be void or must have a length of numPols - 1 - if (0 !== blindingFactors.length && blindingFactors.length < numPols - 1) { - throw new Error(`Blinding factors length must be ${numPols - 1}`); - } - - const chunkByteLength = (degPols + 1) * this.Fr.n8; - let res = []; - - // Check polynomial can be split in numChunks parts of chunkSize bytes... - const numRealPols = Math.ceil((this.degree() + 1) * this.Fr.n8 / chunkByteLength); - if (numRealPols < numPols) { - //throw new Error(`Polynomial is short to be split in ${numPols} parts of ${degPols} coefficients each.`); - for (let i = numRealPols; i < numPols; i++) { - res[i] = new Polynomial(new Uint8Array(this.Fr.n8), this.curve, this.logger); - } - } - - numPols = Math.min(numPols, numRealPols); - for (let i = 0; i < numPols; i++) { - const isLast = (numPols - 1) === i; - const byteLength = isLast ? this.coef.byteLength - ((numPols - 1) * chunkByteLength) : chunkByteLength + this.Fr.n8; - - let buff = (byteLength / this.Fr.n8) > 2 << 14 ? new ffjavascript.BigBuffer(byteLength) : new Uint8Array(byteLength); - res[i] = new Polynomial(buff, this.curve, this.logger); - - const fr = i * chunkByteLength; - const to = isLast ? this.coef.byteLength : (i + 1) * chunkByteLength; - res[i].coef.set(this.coef.slice(fr, to), 0); - - // Add a blinding factor as higher degree - if (!isLast) { - res[i].coef.set(blindingFactors[i], chunkByteLength); - } - - // Sub blinding factor to the lowest degree - if (0 !== i) { - const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); - res[i].coef.set(lowestDegree, 0); - } - - if (isLast) { - res[i].truncate(); - } - } - - return res; - - // // compute t_low(X) - // let polTLow = new BigBuffer((chunkSize + 1) * n8r); - // polTLow.set(t.slice(0, zkey.domainSize * n8r), 0); - // // Add blinding scalar b_10 as a new coefficient n - // polTLow.set(ch.b[10], zkey.domainSize * n8r); - // - // // compute t_mid(X) - // let polTMid = new BigBuffer((zkey.domainSize + 1) * n8r); - // polTMid.set(t.slice(zkey.domainSize * n8r, zkey.domainSize * 2 * n8r), 0); - // // Subtract blinding scalar b_10 to the lowest coefficient of t_mid - // const lowestMid = Fr.sub(polTMid.slice(0, n8r), ch.b[10]); - // polTMid.set(lowestMid, 0); - // // Add blinding scalar b_11 as a new coefficient n - // polTMid.set(ch.b[11], zkey.domainSize * n8r); - // - // // compute t_high(X) - // let polTHigh = new BigBuffer((zkey.domainSize + 6) * n8r); - // polTHigh.set(t.slice(zkey.domainSize * 2 * n8r, (zkey.domainSize * 3 + 6) * n8r), 0); - // //Subtract blinding scalar b_11 to the lowest coefficient of t_high - // const lowestHigh = Fr.sub(polTHigh.slice(0, n8r), ch.b[11]); - // polTHigh.set(lowestHigh, 0); - // - // proof.T1 = await expTau(polTLow, "multiexp T1"); - // proof.T2 = await expTau(polTMid, "multiexp T2"); - // proof.T3 = await expTau(polTHigh, "multiexp T3"); - } - - // split2(degPols, blindingFactors) { - // let currentDegree = this.degree(); - // const numFilledPols = Math.ceil((currentDegree + 1) / (degPols + 1)); - // - // //blinding factors can be void or must have a length of numPols - 1 - // if (0 !== blindingFactors.length && blindingFactors.length < numFilledPols - 1) { - // throw new Error(`Blinding factors length must be ${numFilledPols - 1}`); - // } - // - // const chunkByteLength = (degPols + 1) * this.Fr.n8; - // - // // Check polynomial can be split in numChunks parts of chunkSize bytes... - // if (this.coef.byteLength / chunkByteLength <= numFilledPols - 1) { - // throw new Error(`Polynomial is short to be split in ${numFilledPols} parts of ${degPols} coefficients each.`); - // } - // - // let res = []; - // for (let i = 0; i < numFilledPols; i++) { - // const isLast = (numFilledPols - 1) === i; - // const byteLength = isLast ? (currentDegree + 1) * this.Fr.n8 - ((numFilledPols - 1) * chunkByteLength) : chunkByteLength + this.Fr.n8; - // - // res[i] = new Polynomial(new BigBuffer(byteLength), this.Fr, this.logger); - // const fr = i * chunkByteLength; - // const to = isLast ? (currentDegree + 1) * this.Fr.n8 : (i + 1) * chunkByteLength; - // res[i].coef.set(this.coef.slice(fr, to), 0); - // - // // Add a blinding factor as higher degree - // if (!isLast) { - // res[i].coef.set(blindingFactors[i], chunkByteLength); - // } - // - // // Sub blinding factor to the lowest degree - // if (0 !== i) { - // const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); - // res[i].coef.set(lowestDegree, 0); - // } - // } - // - // return res; - // } - - // merge(pols, overlap = true) { - // let length = 0; - // for (let i = 0; i < pols.length; i++) { - // length += pols[i].length(); - // } - // - // if (overlap) { - // length -= pols.length - 1; - // } - // - // let res = new Polynomial(new BigBuffer(length * this.Fr.n8)); - // for (let i = 0; i < pols.length; i++) { - // const byteLength = pols[i].coef.byteLength; - // if (0 === i) { - // res.coef.set(pols[i].coef, 0); - // } else { - // - // } - // } - // - // return res; - // } - - truncate() { - const deg = this.degree(); - if (deg + 1 < this.coef.byteLength / this.Fr.n8) { - const newCoefs = (deg + 1) > 2 << 14 ? - new ffjavascript.BigBuffer((deg + 1) * this.Fr.n8) : new Uint8Array((deg + 1) * this.Fr.n8); - - newCoefs.set(this.coef.slice(0, (deg + 1) * this.Fr.n8), 0); - this.coef = newCoefs; - } - } - - static lagrangePolynomialInterpolation(xArr, yArr, curve) { - const Fr = curve.Fr; - let polynomial = computeLagrangePolynomial(0); - for (let i = 1; i < xArr.length; i++) { - polynomial.add(computeLagrangePolynomial(i)); - } - - return polynomial; - - function computeLagrangePolynomial(i) { - let polynomial; - - for (let j = 0; j < xArr.length; j++) { - if (j === i) continue; - - if (polynomial === undefined) { - let buff = (xArr.length) > 2 << 14 ? - new ffjavascript.BigBuffer((xArr.length) * Fr.n8) : new Uint8Array((xArr.length) * Fr.n8); - polynomial = new Polynomial(buff, curve); - polynomial.setCoef(0, Fr.neg(xArr[j])); - polynomial.setCoef(1, Fr.one); - } else { - polynomial.byXSubValue(xArr[j]); - } - } - - let denominator = polynomial.evaluate(xArr[i]); - denominator = Fr.inv(denominator); - const mulFactor = Fr.mul(yArr[i], denominator); - - polynomial.mulScalar(mulFactor); - - return polynomial; - } - } - - static zerofierPolynomial(xArr, curve) { - const Fr = curve.Fr; - let buff = (xArr.length + 1) > 2 << 14 ? - new ffjavascript.BigBuffer((xArr.length + 1) * Fr.n8) : new Uint8Array((xArr.length + 1) * Fr.n8); - let polynomial = new Polynomial(buff, curve); - - // Build a zerofier polynomial with the following form: - // zerofier(X) = (X-xArr[0])(X-xArr[1])...(X-xArr[n]) - polynomial.setCoef(0, Fr.neg(xArr[0])); - polynomial.setCoef(1, Fr.one); - - for (let i = 1; i < xArr.length; i++) { - polynomial.byXSubValue(xArr[i]); - } - - return polynomial; - } - - print() { - const Fr = this.Fr; - let res = ""; - for (let i = this.degree(); i >= 0; i--) { - const coef = this.getCoef(i); - if (!Fr.eq(Fr.zero, coef)) { - if (Fr.isNegative(coef)) { - res += " - "; - } else if (i !== this.degree()) { - res += " + "; - } - res += Fr.toString(coef); - if (i > 0) { - res += i > 1 ? "x^" + i : "x"; - } - } - } - console.log(res); - } - - async multiExponentiation(PTau, name) { - const n = this.coef.byteLength / this.Fr.n8; - const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); - const bm = await this.Fr.batchFromMontgomery(this.coef); - let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); - res = this.G1.toAffine(res); - return res; - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -class Evaluations { - constructor(evaluations, curve, logger) { - this.eval = evaluations; - this.curve = curve; - this.Fr = curve.Fr; - this.logger = logger; - } - - static async fromPolynomial(polynomial, extension, curve, logger) { - const coefficientsN = new ffjavascript.BigBuffer(polynomial.length() * extension * curve.Fr.n8); - coefficientsN.set(polynomial.coef, 0); - - const evaluations = await curve.Fr.fft(coefficientsN); - - return new Evaluations(evaluations, curve, logger); - } - - getEvaluation(index) { - const i_n8 = index * this.Fr.n8; - - if (i_n8 + this.Fr.n8 > this.eval.byteLength) { - throw new Error("Evaluations.getEvaluation() out of bounds"); - } - - return this.eval.slice(i_n8, i_n8 + this.Fr.n8); - } - - length() { - let length = this.eval.byteLength / this.Fr.n8; - if (length !== Math.floor(this.eval.byteLength / this.Fr.n8)) { - throw new Error("Polynomial evaluations buffer has incorrect size"); - } - if (0 === length) { - this.logger.warn("Polynomial has length zero"); - } - return length; - } -} - -/* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const {stringifyBigInts: stringifyBigInts$2} = ffjavascript.utils; - + if (globalThis.gc) globalThis.gc(); + const { fd: fdPTau, sections: sectionsPTau } = await (0, _iden3_binfileutils.readBinFile)(ptauName, "ptau", 1, 1 << 22, 1 << 24); + const { curve, power } = await readPTauHeader(fdPTau, sectionsPTau); + const { fd: fdR1cs, sections: sectionsR1cs } = await (0, _iden3_binfileutils.readBinFile)(r1csName, "r1cs", 1, 1 << 22, 1 << 24); + const r1cs = await (0, r1csfile.readR1csFd)(fdR1cs, sectionsR1cs, { + loadConstraints: true, + loadCustomGates: true + }); + const sG1 = curve.G1.F.n8 * 2; + const G1 = curve.G1; + const sG2 = curve.G2.F.n8 * 2; + const Fr = curve.Fr; + const n8r = curve.Fr.n8; + if (logger) logger.info("Reading r1cs"); + const plonkConstraints = new BigArray(); + const plonkAdditions = new BigArray(); + let plonkNVars = r1cs.nVars; + const nPublic = r1cs.nOutputs + r1cs.nPubInputs; + await processConstraints(curve.Fr, r1cs, logger); + if (globalThis.gc) globalThis.gc(); + const fdZKey = await (0, _iden3_binfileutils.createBinFile)(zkeyName, "zkey", 1, 14, 1 << 22, 1 << 24); + if (r1cs.prime != curve.r) { + if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); + return -1; + } + let cirPower = log2(plonkConstraints.length - 1) + 1; + if (cirPower < 3) cirPower = 3; + const domainSize = 2 ** cirPower; + if (logger) logger.info("Plonk constraints: " + plonkConstraints.length); + if (cirPower > power) { + if (logger) logger.error(`circuit too big for this power of tau ceremony. ${plonkConstraints.length} > 2**${power}`); + return -1; + } + if (!sectionsPTau[12]) { + if (logger) logger.error("Powers of tau is not prepared."); + return -1; + } + const LPoints = new ffjavascript.BigBuffer(domainSize * sG1); + const o = sectionsPTau[12][0].p + (2 ** cirPower - 1) * sG1; + await fdPTau.readToBuffer(LPoints, 0, domainSize * sG1, o); + const [k1, k2] = getK1K2(); + const vk = {}; + await writeAdditions(3, "Additions"); + if (globalThis.gc) globalThis.gc(); + await writeWitnessMap(4, 0, "Amap"); + if (globalThis.gc) globalThis.gc(); + await writeWitnessMap(5, 1, "Bmap"); + if (globalThis.gc) globalThis.gc(); + await writeWitnessMap(6, 2, "Cmap"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(7, 3, "Qm"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(8, 4, "Ql"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(9, 5, "Qr"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(10, 6, "Qo"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(11, 7, "Qc"); + if (globalThis.gc) globalThis.gc(); + await writeSigma(12, "sigma"); + if (globalThis.gc) globalThis.gc(); + await writeLs(13, "lagrange polynomials"); + if (globalThis.gc) globalThis.gc(); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 14); + const buffOut = new ffjavascript.BigBuffer((domainSize + 6) * sG1); + await fdPTau.readToBuffer(buffOut, 0, (domainSize + 6) * sG1, sectionsPTau[2][0].p); + await fdZKey.write(buffOut); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + if (globalThis.gc) globalThis.gc(); + await writeHeaders(); + await fdZKey.close(); + await fdR1cs.close(); + await fdPTau.close(); + if (logger) logger.info("Setup Finished"); + return; + async function processConstraints(Fr, r1cs, logger) { + function normalize(linearComb) { + const ss = Object.keys(linearComb); + for (let i = 0; i < ss.length; i++) if (linearComb[ss[i]] == 0n) delete linearComb[ss[i]]; + } + function join(linearComb1, k, linearComb2) { + const res = {}; + for (let s in linearComb1) if (typeof res[s] == "undefined") res[s] = Fr.mul(k, linearComb1[s]); + else res[s] = Fr.add(res[s], Fr.mul(k, linearComb1[s])); + for (let s in linearComb2) if (typeof res[s] == "undefined") res[s] = linearComb2[s]; + else res[s] = Fr.add(res[s], linearComb2[s]); + normalize(res); + return res; + } + function reduceCoefs(linearComb, maxC) { + const res = { + k: Fr.zero, + s: [], + coefs: [] + }; + const cs = []; + for (let s in linearComb) if (s == 0) res.k = Fr.add(res.k, linearComb[s]); + else if (linearComb[s] != 0n) cs.push([Number(s), linearComb[s]]); + while (cs.length > maxC) { + const c1 = cs.shift(); + const c2 = cs.shift(); + const sl = c1[0]; + const sr = c2[0]; + const so = plonkNVars++; + const qm = Fr.zero; + const ql = Fr.neg(c1[1]); + const qr = Fr.neg(c2[1]); + const qo = Fr.one; + const qc = Fr.zero; + plonkConstraints.push([ + sl, + sr, + so, + qm, + ql, + qr, + qo, + qc + ]); + plonkAdditions.push([ + sl, + sr, + c1[1], + c2[1] + ]); + cs.push([so, Fr.one]); + } + for (let i = 0; i < cs.length; i++) { + res.s[i] = cs[i][0]; + res.coefs[i] = cs[i][1]; + } + while (res.coefs.length < maxC) { + res.s.push(0); + res.coefs.push(Fr.zero); + } + return res; + } + function addConstraintSum(lc) { + const C = reduceCoefs(lc, 3); + const sl = C.s[0]; + const sr = C.s[1]; + const so = C.s[2]; + const qm = Fr.zero; + const ql = C.coefs[0]; + const qr = C.coefs[1]; + const qo = C.coefs[2]; + const qc = C.k; + plonkConstraints.push([ + sl, + sr, + so, + qm, + ql, + qr, + qo, + qc + ]); + } + function addConstraintMul(lcA, lcB, lcC) { + const A = reduceCoefs(lcA, 1); + const B = reduceCoefs(lcB, 1); + const C = reduceCoefs(lcC, 1); + const sl = A.s[0]; + const sr = B.s[0]; + const so = C.s[0]; + const qm = Fr.mul(A.coefs[0], B.coefs[0]); + const ql = Fr.mul(A.coefs[0], B.k); + const qr = Fr.mul(A.k, B.coefs[0]); + const qo = Fr.neg(C.coefs[0]); + const qc = Fr.sub(Fr.mul(A.k, B.k), C.k); + plonkConstraints.push([ + sl, + sr, + so, + qm, + ql, + qr, + qo, + qc + ]); + } + function getLinearCombinationType(lc) { + let k = Fr.zero; + let n = 0; + const ss = Object.keys(lc); + for (let i = 0; i < ss.length; i++) if (lc[ss[i]] == 0n) delete lc[ss[i]]; + else if (ss[i] == 0) k = Fr.add(k, lc[ss[i]]); + else n++; + if (n > 0) return n.toString(); + if (k != Fr.zero) return "k"; + return "0"; + } + function process(lcA, lcB, lcC) { + const lctA = getLinearCombinationType(lcA); + const lctB = getLinearCombinationType(lcB); + if (lctA === "0" || lctB === "0") { + normalize(lcC); + addConstraintSum(lcC); + } else if (lctA === "k") addConstraintSum(join(lcB, lcA[0], lcC)); + else if (lctB === "k") addConstraintSum(join(lcA, lcB[0], lcC)); + else addConstraintMul(lcA, lcB, lcC); + } + for (let s = 1; s <= nPublic; s++) { + const sl = s; + const sr = 0; + const so = 0; + const qm = Fr.zero; + const ql = Fr.one; + const qr = Fr.zero; + const qo = Fr.zero; + const qc = Fr.zero; + plonkConstraints.push([ + sl, + sr, + so, + qm, + ql, + qr, + qo, + qc + ]); + } + for (let c = 0; c < r1cs.constraints.length; c++) { + if (logger && c % 1e4 === 0) logger.debug(`processing constraints: ${c}/${r1cs.nConstraints}`); + process(...r1cs.constraints[c]); + } + } + async function writeWitnessMap(sectionNum, posConstraint, name) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + for (let i = 0; i < plonkConstraints.length; i++) { + await fdZKey.writeULE32(plonkConstraints[i][posConstraint]); + if (logger && i % 1e6 == 0) logger.debug(`writing ${name}: ${i}/${plonkConstraints.length}`); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeQMap(sectionNum, posConstraint, name) { + let Q = new ffjavascript.BigBuffer(domainSize * n8r); + for (let i = 0; i < plonkConstraints.length; i++) { + Q.set(plonkConstraints[i][posConstraint], i * n8r); + if (logger && i % 1e6 == 0) logger.debug(`writing ${name}: ${i}/${plonkConstraints.length}`); + } + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + await writeP4(Q); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + Q = await Fr.batchFromMontgomery(Q); + vk[name] = await curve.G1.multiExpAffine(LPoints, Q, logger, "multiexp " + name); + } + async function writeP4(buff) { + const q = await Fr.ifft(buff); + const q4 = new ffjavascript.BigBuffer(domainSize * n8r * 4); + q4.set(q, 0); + const Q4 = await Fr.fft(q4); + await fdZKey.write(q); + await fdZKey.write(Q4); + } + async function writeAdditions(sectionNum, name) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + const buffOut = new Uint8Array(8 + 2 * n8r); + const buffOutV = new DataView(buffOut.buffer); + for (let i = 0; i < plonkAdditions.length; i++) { + const addition = plonkAdditions[i]; + let o = 0; + buffOutV.setUint32(o, addition[0], true); + o += 4; + buffOutV.setUint32(o, addition[1], true); + o += 4; + buffOut.set(addition[2], o); + o += n8r; + buffOut.set(addition[3], o); + o += n8r; + await fdZKey.write(buffOut); + if (logger && i % 1e6 == 0) logger.debug(`writing ${name}: ${i}/${plonkAdditions.length}`); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeSigma(sectionNum, name) { + const sigma = new ffjavascript.BigBuffer(n8r * domainSize * 3); + const lastAparence = new BigArray(plonkNVars); + const firstPos = new BigArray(plonkNVars); + let w = Fr.one; + for (let i = 0; i < domainSize; i++) { + if (i < plonkConstraints.length) { + buildSigma(plonkConstraints[i][0], i); + buildSigma(plonkConstraints[i][1], domainSize + i); + buildSigma(plonkConstraints[i][2], domainSize * 2 + i); + } else { + buildSigma(0, i); + buildSigma(0, domainSize + i); + buildSigma(0, domainSize * 2 + i); + } + w = Fr.mul(w, Fr.w[cirPower]); + if (logger && i % 1e6 == 0) logger.debug(`writing ${name} phase1: ${i}/${plonkConstraints.length}`); + } + for (let s = 0; s < plonkNVars; s++) { + if (typeof firstPos[s] !== "undefined") sigma.set(lastAparence[s], firstPos[s] * n8r); + else console.log("Variable not used"); + if (logger && s % 1e6 == 0) logger.debug(`writing ${name} phase2: ${s}/${plonkNVars}`); + } + if (globalThis.gc) globalThis.gc(); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + let S1 = sigma.slice(0, domainSize * n8r); + await writeP4(S1); + if (globalThis.gc) globalThis.gc(); + let S2 = sigma.slice(domainSize * n8r, domainSize * n8r * 2); + await writeP4(S2); + if (globalThis.gc) globalThis.gc(); + let S3 = sigma.slice(domainSize * n8r * 2, domainSize * n8r * 3); + await writeP4(S3); + if (globalThis.gc) globalThis.gc(); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + S1 = await Fr.batchFromMontgomery(S1); + S2 = await Fr.batchFromMontgomery(S2); + S3 = await Fr.batchFromMontgomery(S3); + vk.S1 = await curve.G1.multiExpAffine(LPoints, S1, logger, "multiexp S1"); + if (globalThis.gc) globalThis.gc(); + vk.S2 = await curve.G1.multiExpAffine(LPoints, S2, logger, "multiexp S2"); + if (globalThis.gc) globalThis.gc(); + vk.S3 = await curve.G1.multiExpAffine(LPoints, S3, logger, "multiexp S3"); + if (globalThis.gc) globalThis.gc(); + function buildSigma(s, p) { + if (typeof lastAparence[s] === "undefined") firstPos[s] = p; + else sigma.set(lastAparence[s], p * n8r); + let v; + if (p < domainSize) v = w; + else if (p < 2 * domainSize) v = Fr.mul(w, k1); + else v = Fr.mul(w, k2); + lastAparence[s] = v; + } + } + async function writeLs(sectionNum, name) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + const l = Math.max(nPublic, 1); + for (let i = 0; i < l; i++) { + let buff = new ffjavascript.BigBuffer(domainSize * n8r); + buff.set(Fr.one, i * n8r); + await writeP4(buff); + if (logger) logger.debug(`writing ${name} ${i}/${l}`); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeHeaders() { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 1); + await fdZKey.writeULE32(2); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 2); + const primeQ = curve.q; + const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; + const primeR = curve.r; + const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; + await fdZKey.writeULE32(n8q); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeQ, n8q); + await fdZKey.writeULE32(n8r); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeR, n8r); + await fdZKey.writeULE32(plonkNVars); + await fdZKey.writeULE32(nPublic); + await fdZKey.writeULE32(domainSize); + await fdZKey.writeULE32(plonkAdditions.length); + await fdZKey.writeULE32(plonkConstraints.length); + await fdZKey.write(k1); + await fdZKey.write(k2); + await fdZKey.write(G1.toAffine(vk.Qm)); + await fdZKey.write(G1.toAffine(vk.Ql)); + await fdZKey.write(G1.toAffine(vk.Qr)); + await fdZKey.write(G1.toAffine(vk.Qo)); + await fdZKey.write(G1.toAffine(vk.Qc)); + await fdZKey.write(G1.toAffine(vk.S1)); + await fdZKey.write(G1.toAffine(vk.S2)); + await fdZKey.write(G1.toAffine(vk.S3)); + let bX_2; + bX_2 = await fdPTau.read(sG2, sectionsPTau[3][0].p + sG2); + await fdZKey.write(bX_2); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + function getK1K2() { + let k1 = Fr.two; + while (isIncluded(k1, [], cirPower)) Fr.add(k1, Fr.one); + let k2 = Fr.add(k1, Fr.one); + while (isIncluded(k2, [k1], cirPower)) Fr.add(k2, Fr.one); + return [k1, k2]; + function isIncluded(k, kArr, pow) { + const domainSize = 2 ** pow; + let w = Fr.one; + for (let i = 0; i < domainSize; i++) { + if (Fr.eq(k, w)) return true; + for (let j = 0; j < kArr.length; j++) if (Fr.eq(k, Fr.mul(kArr[j], w))) return true; + w = Fr.mul(w, Fr.w[pow]); + } + return false; + } + } +} +//#endregion +//#region src/proof.js +var Proof = class { + constructor(curve, logger) { + this.curve = curve; + this.logger = logger; + this.resetProof(); + } + resetProof() { + this.polynomials = {}; + this.evaluations = {}; + } + addPolynomial(key, polynomial) { + if (key in this.polynomials) this.logger.warn(`proof: polynomial.${key} already exist in proof`); + this.polynomials[key] = polynomial; + } + getPolynomial(key) { + if (!(key in this.polynomials)) this.logger.warn(`proof: polynomial ${key} does not exist in proof`); + return this.polynomials[key]; + } + addEvaluation(key, evaluation) { + if (key in this.evaluations) this.logger.warn(`proof: evaluations.${key} already exist in proof`); + this.evaluations[key] = evaluation; + } + getEvaluation(key) { + if (!(key in this.evaluations)) this.logger.warn(`proof: evaluation ${key} does not exist in proof`); + return this.evaluations[key]; + } + toObjectProof(splitFields = true) { + let res = splitFields ? { + polynomials: {}, + evaluations: {} + } : {}; + Object.keys(this.polynomials).forEach((key) => { + const value = this.curve.G1.toObject(this.polynomials[key]); + if (splitFields) res.polynomials[key] = value; + else res[key] = value; + }); + Object.keys(this.evaluations).forEach((key) => { + const value = this.curve.Fr.toObject(this.evaluations[key]); + if (splitFields) res.evaluations[key] = value; + else res[key] = value; + }); + return res; + } + fromObjectProof(objectProof) { + this.resetProof(); + Object.keys(objectProof.polynomials).forEach((key) => { + this.polynomials[key] = this.curve.G1.fromObject(objectProof.polynomials[key]); + }); + Object.keys(objectProof.evaluations).forEach((key) => { + this.evaluations[key] = this.curve.Fr.fromObject(objectProof.evaluations[key]); + }); + } +}; +//#endregion +//#region src/Keccak256Transcript.js +var POLYNOMIAL = 0; +var SCALAR = 1; +var Keccak256Transcript = class { + constructor(curve) { + this.G1 = curve.G1; + this.Fr = curve.Fr; + this.reset(); + } + reset() { + this.data = []; + } + addPolCommitment(polynomialCommitment) { + this.data.push({ + type: POLYNOMIAL, + data: polynomialCommitment + }); + } + addScalar(scalar) { + this.data.push({ + type: SCALAR, + data: scalar + }); + } + getChallenge() { + if (0 === this.data.length) throw new Error("Keccak256Transcript: No data to generate a transcript"); + let nPolynomials = 0; + let nScalars = 0; + this.data.forEach((element) => POLYNOMIAL === element.type ? nPolynomials++ : nScalars++); + let buffer = new Uint8Array(nScalars * this.Fr.n8 + nPolynomials * this.G1.F.n8 * 2); + let offset = 0; + for (let i = 0; i < this.data.length; i++) if (POLYNOMIAL === this.data[i].type) { + this.G1.toRprUncompressed(buffer, offset, this.data[i].data); + offset += this.G1.F.n8 * 2; + } else { + this.Fr.toRprBE(buffer, offset, this.data[i].data); + offset += this.Fr.n8; + } + const value = ffjavascript.Scalar.fromRprBE((0, _noble_hashes_sha3_js.keccak_256)(buffer)); + return this.Fr.e(value); + } +}; +//#endregion +//#region src/mul_z.js +var MulZ = class { + static getZ1(Fr) { + return [ + Fr.zero, + Fr.add(Fr.e(-1), Fr.w[2]), + Fr.e(-2), + Fr.sub(Fr.e(-1), Fr.w[2]) + ]; + } + static getZ2(Fr) { + return [ + Fr.zero, + Fr.add(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), + Fr.e(4), + Fr.sub(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])) + ]; + } + static getZ3(Fr) { + return [ + Fr.zero, + Fr.add(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), + Fr.e(-8), + Fr.sub(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])) + ]; + } + static mul2(a, b, ap, bp, p, Fr) { + const Z1 = this.getZ1(Fr); + let r, rz; + const a_b = Fr.mul(a, b); + const a_bp = Fr.mul(a, bp); + const ap_b = Fr.mul(ap, b); + const ap_bp = Fr.mul(ap, bp); + r = a_b; + let a0 = Fr.add(a_bp, ap_b); + let a1 = ap_bp; + rz = a0; + if (p) rz = Fr.add(rz, Fr.mul(Z1[p], a1)); + return [r, rz]; + } + static mul3(a, b, c, ap, bp, cp, p, Fr) { + const Z1 = this.getZ1(Fr); + const Z2 = this.getZ2(Fr); + let r, rz; + const a_b = Fr.mul(a, b); + const a_bp = Fr.mul(a, bp); + const ap_b = Fr.mul(ap, b); + const ap_bp = Fr.mul(ap, bp); + r = Fr.mul(a_b, c); + let a0 = Fr.mul(ap_b, c); + a0 = Fr.add(a0, Fr.mul(a_bp, c)); + a0 = Fr.add(a0, Fr.mul(a_b, cp)); + let a1 = Fr.mul(ap_bp, c); + a1 = Fr.add(a1, Fr.mul(a_bp, cp)); + a1 = Fr.add(a1, Fr.mul(ap_b, cp)); + rz = a0; + if (p) { + const a2 = Fr.mul(ap_bp, cp); + rz = Fr.add(rz, Fr.mul(Z1[p], a1)); + rz = Fr.add(rz, Fr.mul(Z2[p], a2)); + } + return [r, rz]; + } + static mul4(a, b, c, d, ap, bp, cp, dp, p, Fr) { + const Z1 = this.getZ1(Fr); + const Z2 = this.getZ2(Fr); + const Z3 = this.getZ3(Fr); + let r, rz; + const a_b = Fr.mul(a, b); + const a_bp = Fr.mul(a, bp); + const ap_b = Fr.mul(ap, b); + const ap_bp = Fr.mul(ap, bp); + const c_d = Fr.mul(c, d); + const c_dp = Fr.mul(c, dp); + const cp_d = Fr.mul(cp, d); + const cp_dp = Fr.mul(cp, dp); + r = Fr.mul(a_b, c_d); + let a0 = Fr.mul(ap_b, c_d); + a0 = Fr.add(a0, Fr.mul(a_bp, c_d)); + a0 = Fr.add(a0, Fr.mul(a_b, cp_d)); + a0 = Fr.add(a0, Fr.mul(a_b, c_dp)); + let a1 = Fr.mul(ap_bp, c_d); + a1 = Fr.add(a1, Fr.mul(ap_b, cp_d)); + a1 = Fr.add(a1, Fr.mul(ap_b, c_dp)); + a1 = Fr.add(a1, Fr.mul(a_bp, cp_d)); + a1 = Fr.add(a1, Fr.mul(a_bp, c_dp)); + a1 = Fr.add(a1, Fr.mul(a_b, cp_dp)); + let a2 = Fr.mul(a_bp, cp_dp); + a2 = Fr.add(a2, Fr.mul(ap_b, cp_dp)); + a2 = Fr.add(a2, Fr.mul(ap_bp, c_dp)); + a2 = Fr.add(a2, Fr.mul(ap_bp, cp_d)); + let a3 = Fr.mul(ap_bp, cp_dp); + rz = a0; + if (p) { + rz = Fr.add(rz, Fr.mul(Z1[p], a1)); + rz = Fr.add(rz, Fr.mul(Z2[p], a2)); + rz = Fr.add(rz, Fr.mul(Z3[p], a3)); + } + return [r, rz]; + } +}; +//#endregion +//#region src/polynomial/polynomial.js +var Polynomial = class Polynomial { + constructor(coefficients, curve, logger) { + this.coef = coefficients; + this.curve = curve; + this.Fr = curve.Fr; + this.G1 = curve.G1; + this.logger = logger; + } + static async fromEvaluations(buffer, curve, logger) { + return new Polynomial(await curve.Fr.ifft(buffer), curve, logger); + } + static fromCoefficientsArray(array, curve, logger) { + const Fr = curve.Fr; + let buff = array.length > 32768 ? new ffjavascript.BigBuffer(array.length * Fr.n8) : new Uint8Array(array.length * Fr.n8); + for (let i = 0; i < array.length; i++) buff.set(array[i], i * Fr.n8); + return new Polynomial(buff, curve, logger); + } + static fromPolynomial(polynomial, curve, logger) { + let length = polynomial.length(); + let Fr = curve.Fr; + let buff = length > 32768 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); + buff.set(polynomial.coef.slice(), 0); + return new Polynomial(buff, curve, logger); + } + isEqual(polynomial) { + const degree = this.degree(); + if (degree !== polynomial.degree()) return false; + for (let i = 0; i < degree + 1; i++) if (!this.Fr.eq(this.getCoef(i), polynomial.getCoef(i))) return false; + return true; + } + blindCoefficients(blindingFactors) { + blindingFactors = blindingFactors || []; + const blindedCoefficients = this.length() + blindingFactors.length > 32768 ? new ffjavascript.BigBuffer((this.length() + blindingFactors.length) * this.Fr.n8) : new Uint8Array((this.length() + blindingFactors.length) * this.Fr.n8); + blindedCoefficients.set(this.coef, 0); + for (let i = 0; i < blindingFactors.length; i++) { + blindedCoefficients.set(this.Fr.add(blindedCoefficients.slice((this.length() + i) * this.Fr.n8, (this.length() + i + 1) * this.Fr.n8), blindingFactors[i]), (this.length() + i) * this.Fr.n8); + blindedCoefficients.set(this.Fr.sub(blindedCoefficients.slice(i * this.Fr.n8, (i + 1) * this.Fr.n8), blindingFactors[i]), i * this.Fr.n8); + } + this.coef = blindedCoefficients; + } + getCoef(index) { + const i_n8 = index * this.Fr.n8; + if (i_n8 + this.Fr.n8 > this.coef.byteLength) return this.Fr.zero; + return this.coef.slice(i_n8, i_n8 + this.Fr.n8); + } + setCoef(index, value) { + if (index > this.length() - 1) throw new Error("Coef index is not available"); + this.coef.set(value, index * this.Fr.n8); + } + static async to4T(buffer, domainSize, blindingFactors, Fr) { + blindingFactors = blindingFactors || []; + let a = await Fr.ifft(buffer); + const a4 = domainSize * 4 > 32768 ? new ffjavascript.BigBuffer(domainSize * 4 * Fr.n8) : new Uint8Array(domainSize * 4 * Fr.n8); + a4.set(a, 0); + const A4 = await Fr.fft(a4); + if (blindingFactors.length === 0) return [a, A4]; + const a1 = domainSize + blindingFactors.length > 32768 ? new ffjavascript.BigBuffer((domainSize + blindingFactors.length) * Fr.n8) : new Uint8Array((domainSize + blindingFactors.length) * Fr.n8); + a1.set(a, 0); + for (let i = 0; i < blindingFactors.length; i++) { + a1.set(Fr.add(a1.slice((domainSize + i) * Fr.n8, (domainSize + i + 1) * Fr.n8), blindingFactors[i]), (domainSize + i) * Fr.n8); + a1.set(Fr.sub(a1.slice(i * Fr.n8, (i + 1) * Fr.n8), blindingFactors[i]), i * Fr.n8); + } + return [a1, A4]; + } + length() { + let length = this.coef.byteLength / this.Fr.n8; + if (length !== Math.floor(this.coef.byteLength / this.Fr.n8)) throw new Error("Polynomial coefficients buffer has incorrect size"); + if (0 === length) { + if (this.logger) this.logger.warn("Polynomial has length zero"); + } + return length; + } + degree() { + for (let i = this.length() - 1; i > 0; i--) { + const i_n8 = i * this.Fr.n8; + if (!this.Fr.eq(this.Fr.zero, this.coef.slice(i_n8, i_n8 + this.Fr.n8))) return i; + } + return 0; + } + evaluate(point) { + let res = this.Fr.zero; + for (let i = this.degree() + 1; i > 0; i--) { + let i_n8 = i * this.Fr.n8; + const currentCoefficient = this.coef.slice(i_n8 - this.Fr.n8, i_n8); + res = this.Fr.add(currentCoefficient, this.Fr.mul(res, point)); + } + return res; + } + fastEvaluate(point) { + const Fr = this.Fr; + let nThreads = 3; + let nCoefs = this.degree() + 1; + let coefsThread = parseInt(nCoefs / nThreads); + let residualCoefs = nCoefs - coefsThread * nThreads; + let res = []; + let xN = []; + xN[0] = Fr.one; + for (let i = 0; i < nThreads; i++) { + res[i] = Fr.zero; + let nCoefs = i === nThreads - 1 ? coefsThread + residualCoefs : coefsThread; + for (let j = nCoefs; j > 0; j--) { + res[i] = Fr.add(this.getCoef(i * coefsThread + j - 1), Fr.mul(res[i], point)); + if (i === 0) xN[0] = Fr.mul(xN[0], point); + } + } + for (let i = 1; i < nThreads; i++) { + res[0] = Fr.add(res[0], Fr.mul(xN[i - 1], res[i])); + xN[i] = Fr.mul(xN[i - 1], xN[0]); + } + return res[0]; + } + add(polynomial, blindingValue) { + let other = false; + if (polynomial.length() > this.length()) other = true; + const thisLength = this.length(); + const polyLength = polynomial.length(); + for (let i = 0; i < Math.max(thisLength, polyLength); i++) { + const i_n8 = i * this.Fr.n8; + const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; + let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; + if (blindingValue !== void 0) b = this.Fr.mul(b, blindingValue); + if (other) polynomial.coef.set(this.Fr.add(a, b), i_n8); + else this.coef.set(this.Fr.add(a, b), i_n8); + } + if (other) { + delete this.coef; + this.coef = polynomial.coef; + } + } + sub(polynomial, blindingValue) { + let other = false; + if (polynomial.length() > this.length()) other = true; + const thisLength = this.length(); + const polyLength = polynomial.length(); + for (let i = 0; i < Math.max(thisLength, polyLength); i++) { + const i_n8 = i * this.Fr.n8; + const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; + let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; + if (blindingValue !== void 0) b = this.Fr.mul(b, blindingValue); + if (other) polynomial.coef.set(this.Fr.sub(a, b), i_n8); + else this.coef.set(this.Fr.sub(a, b), i_n8); + } + if (other) { + delete this.coef; + this.coef = polynomial.coef; + } + } + mulScalar(value) { + for (let i = 0; i < this.length(); i++) { + const i_n8 = i * this.Fr.n8; + this.coef.set(this.Fr.mul(this.coef.slice(i_n8, i_n8 + this.Fr.n8), value), i_n8); + } + } + addScalar(value) { + const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); + this.coef.set(this.Fr.add(currentValue, value), 0); + } + subScalar(value) { + const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); + this.coef.set(this.Fr.sub(currentValue, value), 0); + } + byXSubValue(value) { + const Fr = this.Fr; + const length = !Fr.eq(Fr.zero, this.getCoef(this.length() - 1)) ? this.length() + 1 : this.length(); + let pol = new Polynomial(length > 32768 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8), this.curve, this.logger); + pol.coef.set(this.coef.slice(0, (length - 1) * Fr.n8), 32); + this.mulScalar(Fr.neg(value)); + pol.add(this); + this.coef = pol.coef; + } + byXNSubValue(n, value) { + const Fr = this.Fr; + const length = !(this.length() - n - 1 >= this.degree()) ? this.length() + n : this.length(); + let pol = new Polynomial(length > 32768 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8), this.curve, this.logger); + pol.coef.set(this.coef.slice(0, (this.degree() + 1) * 32), n * 32); + this.mulScalar(value); + pol.add(this); + this.coef = pol.coef; + } + divBy(polynomial) { + const Fr = this.Fr; + const degreeA = this.degree(); + const degreeB = polynomial.degree(); + let polR = new Polynomial(this.coef, this.curve, this.logger); + this.coef = this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); + for (let i = degreeA - degreeB; i >= 0; i--) { + this.setCoef(i, Fr.div(polR.getCoef(i + degreeB), polynomial.getCoef(degreeB))); + for (let j = 0; j <= degreeB; j++) polR.setCoef(i + j, Fr.sub(polR.getCoef(i + j), Fr.mul(this.getCoef(i), polynomial.getCoef(j)))); + } + return polR; + } + divByMonic(m, beta) { + const Fr = this.Fr; + let d = this.degree(); + let quotient = new Polynomial(this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8), this.curve, this.logger); + let bArr = []; + for (let i = 0; i < m; i++) { + quotient.setCoef(d - i - m, this.getCoef(d - i)); + bArr[i] = this.getCoef(d - i); + } + let nThreads = m; + let j = 0; + for (let k = 0; k < nThreads; k++) for (let i = d - 2 * m - k; i >= 0; i = i - nThreads) { + if (i < 0) break; + let idx = k; + bArr[idx] = Fr.add(this.getCoef(i + m), Fr.mul(bArr[idx], beta)); + quotient.setCoef(i, bArr[idx]); + j = (j + 1) % m; + } + this.coef = quotient.coef; + } + divByVanishing(n, beta) { + if (this.degree() < n) throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); + const Fr = this.Fr; + let polR = new Polynomial(this.coef, this.curve, this.logger); + this.coef = this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); + for (let i = this.length() - 1; i >= n; i--) { + let leadingCoef = polR.getCoef(i); + if (Fr.eq(Fr.zero, leadingCoef)) continue; + polR.setCoef(i, Fr.zero); + polR.setCoef(i - n, Fr.add(polR.getCoef(i - n), Fr.mul(beta, leadingCoef))); + this.setCoef(i - n, Fr.add(this.getCoef(i - n), leadingCoef)); + } + return polR; + } + divByVanishing2(m, beta) { + if (this.degree() < m) throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); + const Fr = this.Fr; + let polR = new Polynomial(this.coef, this.curve, this.logger); + this.coef = this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); + let nThreads = 3; + let nTotal = this.length() - m; + let nElementsChunk = Math.floor(nTotal / nThreads); + let nElementsLast = nTotal - (nThreads - 1) * nElementsChunk; + console.log(nTotal); + console.log(nElementsChunk + " " + nElementsLast); + for (let k = 0; k < nThreads; k++) { + console.log("> Thread " + k); + for (let i = k === 0 ? nElementsLast : nElementsChunk; i > 0; i--) { + let idxDst = i - 1; + if (k !== 0) idxDst += (k - 1) * nElementsChunk + nElementsLast; + let idxSrc = idxDst + m; + let leadingCoef = polR.getCoef(idxSrc); + if (Fr.eq(Fr.zero, leadingCoef)) continue; + polR.setCoef(idxSrc, Fr.zero); + polR.setCoef(idxDst, Fr.add(polR.getCoef(idxDst), Fr.mul(beta, leadingCoef))); + this.setCoef(idxDst, Fr.add(this.getCoef(idxDst), leadingCoef)); + console.log(idxDst + " <-- " + idxSrc); + } + } + this.print(); + return polR; + } + fastDivByVanishing(data) { + const Fr = this.Fr; + for (let i = 0; i < data.length; i++) { + let m = data[i][0]; + let beta = data[i][1]; + if (this.degree() < m) throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); + let nThreads = 5; + let nElements = this.length() - m; + let nElementsBucket = Math.floor(nElements / nThreads / m); + let nElementsChunk = nElementsBucket * m; + let nElementsLast = nElements - nThreads * nElementsChunk; + let polTmp = new Polynomial(this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8), this.curve, this.logger); + let ptr = this.coef; + this.coef = polTmp.coef; + polTmp.coef = ptr; + for (let k = 0; k < nThreads; k++) { + let idx0 = (k + 1) * nElementsChunk + nElementsLast; + for (let i = 0; i < m; i++) this.setCoef(idx0 + i - m, polTmp.getCoef(idx0 + i)); + for (let i = 0; i < nElementsChunk - m; i++) { + let offset = idx0 - i - 1; + let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); + this.setCoef(offset - m, val); + } + } + let idx0 = nElementsLast; + let pending = nElementsLast; + for (let i = 0; i < m && pending; i++) { + this.setCoef(idx0 - i - 1, polTmp.getCoef(idx0 + m - i - 1)); + pending--; + } + for (let i = 0; i < pending; i++) { + let offset = idx0 - i - 1; + let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); + this.setCoef(offset - m, val); + } + let acc = []; + let betaPow = Fr.one; + for (let i = 0; i < nElementsBucket; i++) betaPow = Fr.mul(betaPow, beta); + let currentBeta = Fr.one; + for (let k = nThreads; k > 0; k--) { + let idThread = k - 1; + let idx0 = idThread * nElementsChunk + nElementsLast; + acc[idThread] = []; + for (let i = 0; i < m; i++) { + acc[idThread][i] = this.getCoef(idx0 + i); + if (k !== nThreads) acc[idThread][i] = Fr.add(acc[idThread][i], Fr.mul(betaPow, acc[idThread + 1][i])); + } + currentBeta = Fr.mul(currentBeta, betaPow); + } + for (let k = 0; k < nThreads; k++) { + let idx0 = k * nElementsChunk + nElementsLast; + let currentBeta = beta; + let currentM = m - 1; + let limit = k === 0 ? nElementsLast : nElementsChunk; + for (let i = 0; i < limit; i++) { + let offset = idx0 - i - 1; + let val = Fr.add(this.getCoef(offset), Fr.mul(currentBeta, acc[k][currentM])); + this.setCoef(offset, val); + if (currentM === 0) { + currentM = m - 1; + currentBeta = Fr.mul(currentBeta, beta); + } else currentM--; + } + } + } + } + divByXSubValue(value) { + const coefs = this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * this.Fr.n8) : new Uint8Array(this.length() * this.Fr.n8); + coefs.set(this.Fr.zero, (this.length() - 1) * this.Fr.n8); + coefs.set(this.coef.slice((this.length() - 1) * this.Fr.n8, this.length() * this.Fr.n8), (this.length() - 2) * this.Fr.n8); + for (let i = this.length() - 3; i >= 0; i--) { + let i_n8 = i * this.Fr.n8; + coefs.set(this.Fr.add(this.coef.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8), this.Fr.mul(value, coefs.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8))), i * this.Fr.n8); + } + if (!this.Fr.eq(this.coef.slice(0, this.Fr.n8), this.Fr.mul(this.Fr.neg(value), coefs.slice(0, this.Fr.n8)))) throw new Error("Polynomial does not divide"); + this.coef = coefs; + } + divZh(domainSize, extensions = 4) { + for (let i = 0; i < domainSize; i++) { + const i_n8 = i * this.Fr.n8; + this.coef.set(this.Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)), i_n8); + } + const upperBound = this.coef.byteLength / this.Fr.n8; + for (let i = domainSize; i < upperBound; i++) { + const i_n8 = i * this.Fr.n8; + const a = this.Fr.sub(this.coef.slice((i - domainSize) * this.Fr.n8, (i - domainSize) * this.Fr.n8 + this.Fr.n8), this.coef.slice(i_n8, i_n8 + this.Fr.n8)); + this.coef.set(a, i_n8); + if (i > domainSize * (extensions - 1) - extensions) { + if (!this.Fr.isZero(a)) throw new Error("Polynomial is not divisible"); + } + } + return this; + } + divByZerofier(n, beta) { + let Fr = this.Fr; + const invBeta = Fr.inv(beta); + const invBetaNeg = Fr.neg(invBeta); + let isOne = Fr.eq(Fr.one, invBetaNeg); + let isNegOne = Fr.eq(Fr.negone, invBetaNeg); + if (!isOne) for (let i = 0; i < n; i++) { + const i_n8 = i * this.Fr.n8; + let element; + if (isNegOne) element = Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)); + else element = Fr.mul(invBetaNeg, this.coef.slice(i_n8, i_n8 + this.Fr.n8)); + this.coef.set(element, i_n8); + } + isOne = Fr.eq(Fr.one, invBeta); + isNegOne = Fr.eq(Fr.negone, invBeta); + for (let i = n; i < this.length(); i++) { + const i_n8 = i * this.Fr.n8; + const i_prev_n8 = (i - n) * this.Fr.n8; + let element = this.Fr.sub(this.coef.slice(i_prev_n8, i_prev_n8 + this.Fr.n8), this.coef.slice(i_n8, i_n8 + this.Fr.n8)); + if (!isOne) if (isNegOne) element = Fr.neg(element); + else element = Fr.mul(invBeta, element); + this.coef.set(element, i_n8); + if (i > this.length() - n - 1) { + if (!this.Fr.isZero(element)) throw new Error("Polynomial is not divisible"); + } + } + return this; + } + byX() { + const coefs = this.length() + 1 > 32768 ? new ffjavascript.BigBuffer(this.coef.byteLength + this.Fr.n8) : new Uint8Array(this.coef.byteLength + this.Fr.n8); + coefs.set(this.Fr.zero, 0); + coefs.set(this.coef, this.Fr.n8); + this.coef = coefs; + } + static async expX(polynomial, n, truncate = false) { + const Fr = polynomial.Fr; + if (n < 1) throw new Error("Compute a new polynomial to a zero or negative number is not allowed"); + else if (1 === n) return await Polynomial.fromEvaluations(polynomial.coef, polynomial.curve, polynomial.logger); + const length = truncate ? polynomial.degree() : polynomial.length() - 1; + const bufferDst = length * n + 1 > 32768 ? new ffjavascript.BigBuffer((length * n + 1) * Fr.n8) : new Uint8Array((length * n + 1) * Fr.n8); + bufferDst.set(polynomial.getCoef(0), 0); + for (let i = 1; i <= length; i++) { + const i_sFr = i * Fr.n8; + const coef = polynomial.getCoef(i); + bufferDst.set(coef, i_sFr * n); + } + return new Polynomial(bufferDst, polynomial.curve, polynomial.logger); + } + split(numPols, degPols, blindingFactors) { + if (numPols < 1) throw new Error(`Polynomials can't be split in ${numPols} parts`); + else if (1 === numPols) return [this]; + if (0 !== blindingFactors.length && blindingFactors.length < numPols - 1) throw new Error(`Blinding factors length must be ${numPols - 1}`); + const chunkByteLength = (degPols + 1) * this.Fr.n8; + let res = []; + const numRealPols = Math.ceil((this.degree() + 1) * this.Fr.n8 / chunkByteLength); + if (numRealPols < numPols) for (let i = numRealPols; i < numPols; i++) res[i] = new Polynomial(new Uint8Array(this.Fr.n8), this.curve, this.logger); + numPols = Math.min(numPols, numRealPols); + for (let i = 0; i < numPols; i++) { + const isLast = numPols - 1 === i; + const byteLength = isLast ? this.coef.byteLength - (numPols - 1) * chunkByteLength : chunkByteLength + this.Fr.n8; + res[i] = new Polynomial(byteLength / this.Fr.n8 > 32768 ? new ffjavascript.BigBuffer(byteLength) : new Uint8Array(byteLength), this.curve, this.logger); + const fr = i * chunkByteLength; + const to = isLast ? this.coef.byteLength : (i + 1) * chunkByteLength; + res[i].coef.set(this.coef.slice(fr, to), 0); + if (!isLast) res[i].coef.set(blindingFactors[i], chunkByteLength); + if (0 !== i) { + const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); + res[i].coef.set(lowestDegree, 0); + } + if (isLast) res[i].truncate(); + } + return res; + } + truncate() { + const deg = this.degree(); + if (deg + 1 < this.coef.byteLength / this.Fr.n8) { + const newCoefs = deg + 1 > 32768 ? new ffjavascript.BigBuffer((deg + 1) * this.Fr.n8) : new Uint8Array((deg + 1) * this.Fr.n8); + newCoefs.set(this.coef.slice(0, (deg + 1) * this.Fr.n8), 0); + this.coef = newCoefs; + } + } + static lagrangePolynomialInterpolation(xArr, yArr, curve) { + const Fr = curve.Fr; + let polynomial = computeLagrangePolynomial(0); + for (let i = 1; i < xArr.length; i++) polynomial.add(computeLagrangePolynomial(i)); + return polynomial; + function computeLagrangePolynomial(i) { + let polynomial; + for (let j = 0; j < xArr.length; j++) { + if (j === i) continue; + if (polynomial === void 0) { + polynomial = new Polynomial(xArr.length > 32768 ? new ffjavascript.BigBuffer(xArr.length * Fr.n8) : new Uint8Array(xArr.length * Fr.n8), curve); + polynomial.setCoef(0, Fr.neg(xArr[j])); + polynomial.setCoef(1, Fr.one); + } else polynomial.byXSubValue(xArr[j]); + } + let denominator = polynomial.evaluate(xArr[i]); + denominator = Fr.inv(denominator); + const mulFactor = Fr.mul(yArr[i], denominator); + polynomial.mulScalar(mulFactor); + return polynomial; + } + } + static zerofierPolynomial(xArr, curve) { + const Fr = curve.Fr; + let polynomial = new Polynomial(xArr.length + 1 > 32768 ? new ffjavascript.BigBuffer((xArr.length + 1) * Fr.n8) : new Uint8Array((xArr.length + 1) * Fr.n8), curve); + polynomial.setCoef(0, Fr.neg(xArr[0])); + polynomial.setCoef(1, Fr.one); + for (let i = 1; i < xArr.length; i++) polynomial.byXSubValue(xArr[i]); + return polynomial; + } + print() { + const Fr = this.Fr; + let res = ""; + for (let i = this.degree(); i >= 0; i--) { + const coef = this.getCoef(i); + if (!Fr.eq(Fr.zero, coef)) { + if (Fr.isNegative(coef)) res += " - "; + else if (i !== this.degree()) res += " + "; + res += Fr.toString(coef); + if (i > 0) res += i > 1 ? "x^" + i : "x"; + } + } + console.log(res); + } + async multiExponentiation(PTau, name) { + const n = this.coef.byteLength / this.Fr.n8; + const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); + const bm = await this.Fr.batchFromMontgomery(this.coef); + let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); + res = this.G1.toAffine(res); + return res; + } +}; +//#endregion +//#region src/polynomial/evaluations.js +var Evaluations = class Evaluations { + constructor(evaluations, curve, logger) { + this.eval = evaluations; + this.curve = curve; + this.Fr = curve.Fr; + this.logger = logger; + } + static async fromPolynomial(polynomial, extension, curve, logger) { + const coefficientsN = new ffjavascript.BigBuffer(polynomial.length() * extension * curve.Fr.n8); + coefficientsN.set(polynomial.coef, 0); + return new Evaluations(await curve.Fr.fft(coefficientsN), curve, logger); + } + getEvaluation(index) { + const i_n8 = index * this.Fr.n8; + if (i_n8 + this.Fr.n8 > this.eval.byteLength) throw new Error("Evaluations.getEvaluation() out of bounds"); + return this.eval.slice(i_n8, i_n8 + this.Fr.n8); + } + length() { + let length = this.eval.byteLength / this.Fr.n8; + if (length !== Math.floor(this.eval.byteLength / this.Fr.n8)) throw new Error("Polynomial evaluations buffer has incorrect size"); + if (0 === length) this.logger.warn("Polynomial has length zero"); + return length; + } +}; +//#endregion +//#region src/plonk_prove.js +var { stringifyBigInts: stringifyBigInts$2 } = ffjavascript.utils; async function plonk16Prove(zkeyFileName, witnessFileName, logger, options) { - const {fd: fdWtns, sections: sectionsWtns} = await binFileUtils__namespace.readBinFile(witnessFileName, "wtns", 2, 1<<25, 1<<23); - - // Read witness file - if (logger) logger.debug("> Reading witness file"); - const wtns = await readHeader(fdWtns, sectionsWtns); - - // Read zkey file - if (logger) logger.debug("> Reading zkey file"); - const {fd: fdZKey, sections: zkeySections} = await binFileUtils__namespace.readBinFile(zkeyFileName, "zkey", 2, 1<<25, 1<<23); - - const zkey = await readHeader$1(fdZKey, zkeySections, undefined, options); - if (zkey.protocol != "plonk") { - throw new Error("zkey file is not plonk"); - } - - if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness != zkey.nVars -zkey.nAdditions) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); - } - - const curve = zkey.curve; - - const Fr = curve.Fr; - const n8r = curve.Fr.n8; - const sDomain = zkey.domainSize * n8r; - - if (logger) { - logger.debug("----------------------------"); - logger.debug(" PLONK PROVE SETTINGS"); - logger.debug(` Curve: ${curve.name}`); - logger.debug(` Circuit power: ${zkey.power}`); - logger.debug(` Domain size: ${zkey.domainSize}`); - logger.debug(` Vars: ${zkey.nVars}`); - logger.debug(` Public vars: ${zkey.nPublic}`); - logger.debug(` Constraints: ${zkey.nConstraints}`); - logger.debug(` Additions: ${zkey.nAdditions}`); - logger.debug("----------------------------"); - } - - //Read witness data - if (logger) logger.debug("> Reading witness file data"); - const buffWitness = await binFileUtils__namespace.readSection(fdWtns, sectionsWtns, 2); - - // First element in plonk is not used and can be any value. (But always the same). - // We set it to zero to go faster in the exponentiations. - buffWitness.set(Fr.zero, 0); - const buffInternalWitness = new ffjavascript.BigBuffer(n8r*zkey.nAdditions); - - let buffers = {}; - let polynomials = {}; - let evaluations = {}; - - let challenges = {}; - let proof = new Proof(curve, logger); - const transcript = new Keccak256Transcript(curve); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_ADDITIONS_SECTION}. Additions`); - await calculateAdditions(); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_SIGMA_SECTION}. Sigma1, Sigma2 & Sigma 3`); - if (logger) logger.debug("··· Reading Sigma polynomials "); - polynomials.Sigma1 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.Sigma2 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.Sigma3 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - - await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 5 * sDomain); - await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 10 * sDomain); - - if (logger) logger.debug("··· Reading Sigma evaluations"); - evaluations.Sigma1 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma2 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma3 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - - await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 6 * sDomain); - await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 11 * sDomain); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_PTAU_SECTION}. Powers of Tau`); - const PTau = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_PTAU_SECTION); - - let publicSignals = []; - - for (let i=1; i<= zkey.nPublic; i++) { - const pub = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8); - publicSignals.push(ffjavascript.Scalar.fromRprLE(pub)); - } - - if (logger) logger.debug(""); - if (logger) logger.debug("> ROUND 1"); - await round1(); - - if (logger) logger.debug("> ROUND 2"); - await round2(); - - if (logger) logger.debug("> ROUND 3"); - await round3(); - - if (logger) logger.debug("> ROUND 4"); - await round4(); - - if (logger) logger.debug("> ROUND 5"); - await round5(); - - /////////////////////// - // Final adjustments // - /////////////////////// - - await fdZKey.close(); - await fdWtns.close(); - - // Prepare proof - let _proof = proof.toObjectProof(false); - _proof.protocol = "plonk"; - _proof.curve = curve.name; - - if (logger) logger.debug("PLONK PROVER FINISHED"); - - return { - proof: stringifyBigInts$2(_proof), - publicSignals: stringifyBigInts$2(publicSignals) - }; - - async function calculateAdditions() { - if (logger) logger.debug("··· Computing additions"); - const additionsBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_ADDITIONS_SECTION); - - // sizes: wireId_x = 4 bytes (32 bits), factor_x = field size bits - // Addition form: wireId_a wireId_b factor_a factor_b (size is 4 + 4 + sFr + sFr) - const sSum = 8 + n8r * 2; - - for (let i = 0; i < zkey.nAdditions; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.debug(` addition ${i}/${zkey.nAdditions}`); - - // Read addition values - let offset = i * sSum; - const signalId1 = readUInt32(additionsBuff, offset); - offset += 4; - const signalId2 = readUInt32(additionsBuff, offset); - offset += 4; - const factor1 = additionsBuff.slice(offset, offset + n8r); - offset += n8r; - const factor2 = additionsBuff.slice(offset, offset + n8r); - - // Get witness value - const witness1 = getWitness(signalId1); - const witness2 = getWitness(signalId2); - - //Calculate final result - const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); - - buffInternalWitness.set(result, n8r * i); - } - } - - function readUInt32(b, o) { - const buff = b.slice(o, o+4); - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - return buffV.getUint32(0, true); - } - - function getWitness(idx) { - if (idx < zkey.nVars-zkey.nAdditions) { - return buffWitness.slice(idx*n8r, idx*n8r+n8r); - } else if (idx < zkey.nVars) { - return buffInternalWitness.slice((idx - (zkey.nVars-zkey.nAdditions))*n8r, (idx-(zkey.nVars-zkey.nAdditions))*n8r + n8r); - } else { - return curve.Fr.zero; - } - } - - async function round1() { - // STEP 1.1 - Generate random blinding scalars (b1, ..., b11) ∈ F - challenges.b = []; - for (let i=1; i<=11; i++) { - challenges.b[i] = curve.Fr.random(); - } - - // STEP 1.2 - Compute wire polynomials a(X), b(X) and c(X) - if (logger) logger.debug("> Computing A, B, C wire polynomials"); - await computeWirePolynomials(); - - // STEP 1.3 - Compute [a]_1, [b]_1, [c]_1 - if (logger) logger.debug("> Computing A, B, C MSM"); - let commitA = await polynomials.A.multiExponentiation(PTau, "A"); - let commitB = await polynomials.B.multiExponentiation(PTau, "B"); - let commitC = await polynomials.C.multiExponentiation(PTau, "C"); - - // First output of the prover is ([A]_1, [B]_1, [C]_1) - proof.addPolynomial("A", commitA); - proof.addPolynomial("B", commitB); - proof.addPolynomial("C", commitC); - - return 0; - } - - async function computeWirePolynomials() { - if (logger) logger.debug("··· Reading data from zkey file"); - - // Build A, B and C evaluations buffer from zkey and witness files - buffers.A = new ffjavascript.BigBuffer(sDomain); - buffers.B = new ffjavascript.BigBuffer(sDomain); - buffers.C = new ffjavascript.BigBuffer(sDomain); - - // Read zkey file to the buffers - const aMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_A_MAP_SECTION); - const bMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_B_MAP_SECTION); - const cMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_C_MAP_SECTION); - - // Compute all witness from signal ids and set them to A,B & C buffers - for (let i = 0; i < zkey.nConstraints; i++) { - const i_sFr = i * n8r; - const offset = i * 4; - - // Compute A value from a signal id - const signalIdA = readUInt32(aMapBuff, offset); - buffers.A.set(getWitness(signalIdA), i_sFr); - - // Compute B value from a signal id - const signalIdB = readUInt32(bMapBuff, offset); - buffers.B.set(getWitness(signalIdB), i_sFr); - - // Compute C value from a signal id - const signalIdC = readUInt32(cMapBuff, offset); - buffers.C.set(getWitness(signalIdC), i_sFr); - } - - buffers.A = await Fr.batchToMontgomery(buffers.A); - buffers.B = await Fr.batchToMontgomery(buffers.B); - buffers.C = await Fr.batchToMontgomery(buffers.C); - - // Compute the coefficients of the wire polynomials a(X), b(X) and c(X) from A,B & C buffers - if (logger) logger.debug("··· Computing A ifft"); - polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); - if (logger) logger.debug("··· Computing B ifft"); - polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); - if (logger) logger.debug("··· Computing C ifft"); - polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); - - // Compute extended evaluations of a(X), b(X) and c(X) polynomials - if (logger) logger.debug("··· Computing A fft"); - evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); - if (logger) logger.debug("··· Computing B fft"); - evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); - if (logger) logger.debug("··· Computing C fft"); - evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); - - // Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b - polynomials.A.blindCoefficients([challenges.b[2], challenges.b[1]]); - polynomials.B.blindCoefficients([challenges.b[4], challenges.b[3]]); - polynomials.C.blindCoefficients([challenges.b[6], challenges.b[5]]); - - // Check degrees - if (polynomials.A.degree() >= zkey.domainSize + 2) { - throw new Error("A Polynomial is not well calculated"); - } - if (polynomials.B.degree() >= zkey.domainSize + 2) { - throw new Error("B Polynomial is not well calculated"); - } - if (polynomials.C.degree() >= zkey.domainSize + 2) { - throw new Error("C Polynomial is not well calculated"); - } - } - - async function round2() { - // STEP 2.1 - Compute permutation challenge beta and gamma ∈ F - // Compute permutation challenge beta - if (logger) logger.debug("> Computing challenges beta and gamma"); - transcript.reset(); - - transcript.addPolCommitment(zkey.Qm); - transcript.addPolCommitment(zkey.Ql); - transcript.addPolCommitment(zkey.Qr); - transcript.addPolCommitment(zkey.Qo); - transcript.addPolCommitment(zkey.Qc); - transcript.addPolCommitment(zkey.S1); - transcript.addPolCommitment(zkey.S2); - transcript.addPolCommitment(zkey.S3); - - // Add A to the transcript - for (let i = 0; i < zkey.nPublic; i++) { - transcript.addScalar(buffers.A.slice(i * n8r, i * n8r + n8r)); - } - - // Add A, B, C to the transcript - transcript.addPolCommitment(proof.getPolynomial("A")); - transcript.addPolCommitment(proof.getPolynomial("B")); - transcript.addPolCommitment(proof.getPolynomial("C")); - - challenges.beta = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.beta: " + Fr.toString(challenges.beta, 16)); - - // Compute permutation challenge gamma - transcript.reset(); - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.gamma: " + Fr.toString(challenges.gamma, 16)); - - // STEP 2.2 - Compute permutation polynomial z(X) - if (logger) logger.debug("> Computing Z polynomial"); - await computeZ(); - - // STEP 2.3 - Compute permutation [z]_1 - if (logger) logger.debug("> Computing Z MSM"); - let commitZ = await polynomials.Z.multiExponentiation(PTau, "Z"); - - // Second output of the prover is ([Z]_1) - proof.addPolynomial("Z", commitZ); - } - - async function computeZ() { - if (logger) logger.debug("··· Computing Z evaluations"); - - let numArr = new ffjavascript.BigBuffer(sDomain); - let denArr = new ffjavascript.BigBuffer(sDomain); - - // Set the first values to 1 - numArr.set(Fr.one, 0); - denArr.set(Fr.one, 0); - - // Set initial omega - let w = Fr.one; - for (let i = 0; i < zkey.domainSize; i++) { - const i_n8r = i * n8r; - - const a = buffers.A.slice(i_n8r, i_n8r + n8r); - const b = buffers.B.slice(i_n8r, i_n8r + n8r); - const c = buffers.C.slice(i_n8r, i_n8r + n8r); - - // Z(X) := numArr / denArr - // numArr := (a + beta·ω + gamma)(b + beta·ω·k1 + gamma)(c + beta·ω·k2 + gamma) - const betaw = Fr.mul(challenges.beta, w); - - let n1 = Fr.add(a, betaw); - n1 = Fr.add(n1, challenges.gamma); - - let n2 = Fr.add(b, Fr.mul(zkey.k1, betaw)); - n2 = Fr.add(n2, challenges.gamma); - - let n3 = Fr.add(c, Fr.mul(zkey.k2, betaw)); - n3 = Fr.add(n3, challenges.gamma); - - let num = Fr.mul(n1, Fr.mul(n2, n3)); - - // denArr := (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma) - let d1 = Fr.add(a, Fr.mul(evaluations.Sigma1.getEvaluation(i * 4), challenges.beta)); - d1 = Fr.add(d1, challenges.gamma); - - let d2 = Fr.add(b, Fr.mul(evaluations.Sigma2.getEvaluation(i * 4), challenges.beta)); - d2 = Fr.add(d2, challenges.gamma); - - let d3 = Fr.add(c, Fr.mul(evaluations.Sigma3.getEvaluation(i * 4), challenges.beta)); - d3 = Fr.add(d3, challenges.gamma); - - let den = Fr.mul(d1, Fr.mul(d2, d3)); - - // Multiply current num value with the previous one saved in numArr - num = Fr.mul(numArr.slice(i_n8r, i_n8r + n8r), num); - numArr.set(num, ((i + 1) % zkey.domainSize) * n8r); - - // Multiply current den value with the previous one saved in denArr - den = Fr.mul(denArr.slice(i_n8r, i_n8r + n8r), den); - denArr.set(den, ((i + 1) % zkey.domainSize) * n8r); - - w = Fr.mul(w, Fr.w[zkey.power]); - } - - // Compute the inverse of denArr to compute in the next command the - // division numArr/denArr by multiplying num · 1/denArr - denArr = await Fr.batchInverse(denArr); - - // TODO: Do it in assembly and in parallel - // Multiply numArr · denArr where denArr was inverted in the previous command - for (let i = 0; i < zkey.domainSize; i++) { - const i_sFr = i * n8r; - - const z = Fr.mul(numArr.slice(i_sFr, i_sFr + n8r), denArr.slice(i_sFr, i_sFr + n8r)); - numArr.set(z, i_sFr); - } - - // From now on the values saved on numArr will be Z(X) buffer - buffers.Z = numArr; - - if (!Fr.eq(numArr.slice(0, n8r), Fr.one)) { - throw new Error("Copy constraints does not match"); - } - - // Compute polynomial coefficients z(X) from buffers.Z - if (logger) logger.debug("··· Computing Z ifft"); - polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); - - // Compute extended evaluations of z(X) polynomial - if (logger) logger.debug("··· Computing Z fft"); - evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); - - // Blind z(X) polynomial coefficients with blinding scalars b - polynomials.Z.blindCoefficients([challenges.b[9], challenges.b[8], challenges.b[7]]); - - // Check degree - if (polynomials.Z.degree() >= zkey.domainSize + 3) { - throw new Error("Z Polynomial is not well calculated"); - } - - delete buffers.Z; - } - - async function round3() { - if (logger) logger.debug("> Computing challenge alpha"); - - // STEP 3.1 - Compute evaluation challenge alpha ∈ F - transcript.reset(); - transcript.addScalar(challenges.beta); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.getPolynomial("Z")); - - challenges.alpha = transcript.getChallenge(); - challenges.alpha2 = Fr.square(challenges.alpha); - if (logger) logger.debug("··· challenges.alpha: " + Fr.toString(challenges.alpha, 16)); - - // Compute quotient polynomial T(X) - if (logger) logger.debug("> Computing T polynomial"); - await computeT(); - - // Compute [T1]_1, [T2]_1, [T3]_1 - if (logger) logger.debug("> Computing T MSM"); - let commitT1 = await polynomials.T1.multiExponentiation(PTau, "T1"); - let commitT2 = await polynomials.T2.multiExponentiation(PTau, "T2"); - let commitT3 = await polynomials.T3.multiExponentiation(PTau, "T3"); - - // Third output of the prover is ([T1]_1, [T2]_1, [T3]_1) - proof.addPolynomial("T1", commitT1); - proof.addPolynomial("T2", commitT2); - proof.addPolynomial("T3", commitT3); - } - - async function computeT() { - if (logger) - logger.debug(`··· Reading sections ${ZKEY_PL_QL_SECTION}, ${ZKEY_PL_QR_SECTION}` + - `, ${ZKEY_PL_QM_SECTION}, ${ZKEY_PL_QO_SECTION}, ${ZKEY_PL_QC_SECTION}. Q selectors`); - // Reserve memory for Q's evaluations - evaluations.QL = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QR = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QM = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QO = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QC = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QL_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QR_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QM_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QO_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QC_SECTION][0].p + sDomain); - - // Read Lagrange polynomials & evaluations from zkey file - evaluations.Lagrange = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4 * zkey.nPublic), curve, logger); - - for (let i = 0; i < zkey.nPublic; i++) { - await fdZKey.readToBuffer(evaluations.Lagrange.eval, i * sDomain * 4, sDomain * 4, zkeySections[ZKEY_PL_LAGRANGE_SECTION][0].p + i * 5 * sDomain + sDomain); - } - - buffers.T = new ffjavascript.BigBuffer(sDomain * 4); - buffers.Tz = new ffjavascript.BigBuffer(sDomain * 4); - - if (logger) logger.debug("··· Computing T evaluations"); - - let w = Fr.one; - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) - logger.debug(` T evaluation ${i}/${zkey.domainSize * 4}`); - - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - const z = evaluations.Z.getEvaluation(i); - const zw = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); - - const qm = evaluations.QM.getEvaluation(i); - const ql = evaluations.QL.getEvaluation(i); - const qr = evaluations.QR.getEvaluation(i); - const qo = evaluations.QO.getEvaluation(i); - const qc = evaluations.QC.getEvaluation(i); - const s1 = evaluations.Sigma1.getEvaluation(i); - const s2 = evaluations.Sigma2.getEvaluation(i); - const s3 = evaluations.Sigma3.getEvaluation(i); - - const ap = Fr.add(challenges.b[2], Fr.mul(challenges.b[1], w)); - const bp = Fr.add(challenges.b[4], Fr.mul(challenges.b[3], w)); - const cp = Fr.add(challenges.b[6], Fr.mul(challenges.b[5], w)); - - const w2 = Fr.square(w); - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], w2), Fr.mul(challenges.b[8], w)), challenges.b[9]); - const wW = Fr.mul(w, Fr.w[zkey.power]); - const wW2 = Fr.square(wW); - const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], wW2), Fr.mul(challenges.b[8], wW)), challenges.b[9]); - - let pi = Fr.zero; - for (let j = 0; j < zkey.nPublic; j++) { - const offset = (j * 4 * zkey.domainSize) + i; - - const lPol = evaluations.Lagrange.getEvaluation(offset); - const aVal = buffers.A.slice(j * n8r, (j + 1) * n8r); - - pi = Fr.sub(pi, Fr.mul(lPol, aVal)); - } - - // e1 := a(X)b(X)qM(X) + a(X)qL(X) + b(X)qR(X) + c(X)qO(X) + PI(X) + qC(X) - let [e1, e1z] = MulZ.mul2(a, b, ap, bp, i % 4, Fr); - e1 = Fr.mul(e1, qm); - e1z = Fr.mul(e1z, qm); - - e1 = Fr.add(e1, Fr.mul(a, ql)); - e1z = Fr.add(e1z, Fr.mul(ap, ql)); - - e1 = Fr.add(e1, Fr.mul(b, qr)); - e1z = Fr.add(e1z, Fr.mul(bp, qr)); - - e1 = Fr.add(e1, Fr.mul(c, qo)); - e1z = Fr.add(e1z, Fr.mul(cp, qo)); - - e1 = Fr.add(e1, pi); - e1 = Fr.add(e1, qc); - - // e2 := α[(a(X) + βX + γ)(b(X) + βk1X + γ)(c(X) + βk2X + γ)z(X)] - const betaw = Fr.mul(challenges.beta, w); - let e2a = a; - e2a = Fr.add(e2a, betaw); - e2a = Fr.add(e2a, challenges.gamma); - - let e2b = b; - e2b = Fr.add(e2b, Fr.mul(betaw, zkey.k1)); - e2b = Fr.add(e2b, challenges.gamma); - - let e2c = c; - e2c = Fr.add(e2c, Fr.mul(betaw, zkey.k2)); - e2c = Fr.add(e2c, challenges.gamma); - - let e2d = z; - - let [e2, e2z] = MulZ.mul4(e2a, e2b, e2c, e2d, ap, bp, cp, zp, i % 4, Fr); - e2 = Fr.mul(e2, challenges.alpha); - e2z = Fr.mul(e2z, challenges.alpha); - - // e3 := α[(a(X) + βSσ1(X) + γ)(b(X) + βSσ2(X) + γ)(c(X) + βSσ3(X) + γ)z(Xω)] - let e3a = a; - e3a = Fr.add(e3a, Fr.mul(challenges.beta, s1)); - e3a = Fr.add(e3a, challenges.gamma); - - let e3b = b; - e3b = Fr.add(e3b, Fr.mul(challenges.beta, s2)); - e3b = Fr.add(e3b, challenges.gamma); - - let e3c = c; - e3c = Fr.add(e3c, Fr.mul(challenges.beta, s3)); - e3c = Fr.add(e3c, challenges.gamma); - - let e3d = zw; - let [e3, e3z] = MulZ.mul4(e3a, e3b, e3c, e3d, ap, bp, cp, zWp, i % 4, Fr); - - e3 = Fr.mul(e3, challenges.alpha); - e3z = Fr.mul(e3z, challenges.alpha); - - // e4 := α^2(z(X)−1)L1(X) - let e4 = Fr.sub(z, Fr.one); - e4 = Fr.mul(e4, evaluations.Lagrange.getEvaluation(i)); - e4 = Fr.mul(e4, challenges.alpha2); - - let e4z = Fr.mul(zp, evaluations.Lagrange.getEvaluation(i)); - e4z = Fr.mul(e4z, challenges.alpha2); - - - let t = Fr.add(Fr.sub(Fr.add(e1, e2), e3), e4); - let tz = Fr.add(Fr.sub(Fr.add(e1z, e2z), e3z), e4z); - - buffers.T.set(t, i * n8r); - buffers.Tz.set(tz, i * n8r); - - w = Fr.mul(w, Fr.w[zkey.power + 2]); - } - - // Compute the coefficients of the polynomial T0(X) from buffers.T0 - if (logger) - logger.debug("··· Computing T ifft"); - polynomials.T = await Polynomial.fromEvaluations(buffers.T, curve, logger); - - // Divide the polynomial T0 by Z_H(X) - if (logger) - logger.debug("··· Computing T / ZH"); - polynomials.T.divZh(zkey.domainSize, 4); - - // Compute the coefficients of the polynomial Tz(X) from buffers.Tz - if (logger) - logger.debug("··· Computing Tz ifft"); - polynomials.Tz = await Polynomial.fromEvaluations(buffers.Tz, curve, logger); - - // Add the polynomial T1z to T1 to get the final polynomial T1 - polynomials.T.add(polynomials.Tz); - - // Check degree - if (polynomials.T.degree() >= zkey.domainSize * 3 + 6) { - throw new Error("T Polynomial is not well calculated"); - } - - // t(x) has degree 3n + 5, we are going to split t(x) into three smaller polynomials: - // T1' and T2' with a degree < n and T3' with a degree n+5 - // such that t(x) = T1'(X) + X^n T2'(X) + X^{2n} T3'(X) - // To randomize the parts we use blinding scalars b_10 and b_11 in a way that doesn't change t(X): - // T1(X) = T1'(X) + b_10 X^n - // T2(X) = T2'(X) - b_10 + b_11 X^n - // T3(X) = T3'(X) - b_11 - // such that - // t(X) = T1(X) + X^n T2(X) + X^2n T3(X) - if (logger) logger.debug("··· Computing T1, T2, T3 polynomials"); - polynomials.T1 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); - polynomials.T2 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); - polynomials.T3 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 6) * n8r), curve, logger); - - polynomials.T1.coef.set(polynomials.T.coef.slice(0, sDomain), 0); - polynomials.T2.coef.set(polynomials.T.coef.slice(sDomain, sDomain * 2), 0); - polynomials.T3.coef.set(polynomials.T.coef.slice(sDomain * 2, sDomain * 3 + 6 * n8r), 0); - - // Add blinding scalar b_10 as a new coefficient n - polynomials.T1.setCoef(zkey.domainSize, challenges.b[10]); - - // compute t_mid(X) - // Subtract blinding scalar b_10 to the lowest coefficient of t_mid - const lowestMid = Fr.sub(polynomials.T2.getCoef(0), challenges.b[10]); - polynomials.T2.setCoef(0, lowestMid); - polynomials.T2.setCoef(zkey.domainSize, challenges.b[11]); - - // compute t_high(X) - //Subtract blinding scalar b_11 to the lowest coefficient of t_high - const lowestHigh = Fr.sub(polynomials.T3.getCoef(0), challenges.b[11]); - polynomials.T3.setCoef(0, lowestHigh); - } - - async function round4() { - if (logger) logger.debug("> Computing challenge xi"); - - // STEP 4.1 - Compute evaluation challenge xi ∈ F - transcript.reset(); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.getPolynomial("T1")); - transcript.addPolCommitment(proof.getPolynomial("T2")); - transcript.addPolCommitment(proof.getPolynomial("T3")); - - challenges.xi = transcript.getChallenge(); - challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); - - if (logger) logger.debug("··· challenges.xi: " + Fr.toString(challenges.xi, 16)); - - // Fourth output of the prover is ( a(xi), b(xi), c(xi), s1(xi), s2(xi), z(xiw) ) - proof.addEvaluation("eval_a", polynomials.A.evaluate(challenges.xi)); - proof.addEvaluation("eval_b", polynomials.B.evaluate(challenges.xi)); - proof.addEvaluation("eval_c", polynomials.C.evaluate(challenges.xi)); - proof.addEvaluation("eval_s1", polynomials.Sigma1.evaluate(challenges.xi)); - proof.addEvaluation("eval_s2", polynomials.Sigma2.evaluate(challenges.xi)); - proof.addEvaluation("eval_zw", polynomials.Z.evaluate(challenges.xiw)); - } - - async function round5() { - if (logger) logger.debug("> Computing challenge v"); - - // STEP 5.1 - Compute evaluation challenge v ∈ F - transcript.reset(); - transcript.addScalar(challenges.xi); - transcript.addScalar(proof.getEvaluation("eval_a")); - transcript.addScalar(proof.getEvaluation("eval_b")); - transcript.addScalar(proof.getEvaluation("eval_c")); - transcript.addScalar(proof.getEvaluation("eval_s1")); - transcript.addScalar(proof.getEvaluation("eval_s2")); - transcript.addScalar(proof.getEvaluation("eval_zw")); - - challenges.v = []; - challenges.v[1] = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.v: " + Fr.toString(challenges.v[1], 16)); - - for (let i = 2; i < 6; i++) { - challenges.v[i] = Fr.mul(challenges.v[i - 1], challenges.v[1]); - } - - // STEP 5.2 Compute linearisation polynomial r(X) - if (logger) logger.debug("> Computing linearisation polynomial R(X)"); - await computeR(); - - //STEP 5.3 Compute opening proof polynomial Wxi(X) - if (logger) logger.debug("> Computing opening proof polynomial Wxi(X) polynomial"); - computeWxi(); - - //STEP 5.4 Compute opening proof polynomial Wxiw(X) - if (logger) logger.debug("> Computing opening proof polynomial Wxiw(X) polynomial"); - computeWxiw(); - - if (logger) logger.debug("> Computing Wxi, Wxiw MSM"); - let commitWxi = await polynomials.Wxi.multiExponentiation(PTau, "Wxi"); - let commitWxiw = await polynomials.Wxiw.multiExponentiation(PTau, "Wxiw"); - - // Fifth output of the prover is ([Wxi]_1, [Wxiw]_1) - proof.addPolynomial("Wxi", commitWxi); - proof.addPolynomial("Wxiw", commitWxiw); - } - - async function computeR() { - const Fr = curve.Fr; - - // Reserve memory for Q's polynomials - polynomials.QL = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QR = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QM = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QO = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QC = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[ZKEY_PL_QL_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[ZKEY_PL_QR_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[ZKEY_PL_QM_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[ZKEY_PL_QO_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[ZKEY_PL_QC_SECTION][0].p); - - challenges.xin = challenges.xi; - for (let i = 0; i < zkey.power; i++) { - challenges.xin = Fr.square(challenges.xin); - } - - challenges.zh = Fr.sub(challenges.xin, Fr.one); - - const L = []; - - const n = Fr.e(zkey.domainSize); - let w = Fr.one; - for (let i = 1; i <= Math.max(1, zkey.nPublic); i++) { - L[i] = Fr.div(Fr.mul(w, challenges.zh), Fr.mul(n, Fr.sub(challenges.xi, w))); - w = Fr.mul(w, Fr.w[zkey.power]); - } - - const eval_l1 = Fr.div( - Fr.sub(challenges.xin, Fr.one), - Fr.mul(n, Fr.sub(challenges.xi, Fr.one)) - ); - - if (logger) { - logger.debug("Lagrange Evaluations: "); - for (let i=1; i. -*/ - -const {unstringifyBigInts: unstringifyBigInts$6} = ffjavascript.utils; - + const { fd: fdWtns, sections: sectionsWtns } = await _iden3_binfileutils.readBinFile(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); + if (logger) logger.debug("> Reading witness file"); + const wtns = await readHeader(fdWtns, sectionsWtns); + if (logger) logger.debug("> Reading zkey file"); + const { fd: fdZKey, sections: zkeySections } = await _iden3_binfileutils.readBinFile(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); + const zkey = await readHeader$1(fdZKey, zkeySections, void 0, options); + if (zkey.protocol != "plonk") throw new Error("zkey file is not plonk"); + if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) throw new Error("Curve of the witness does not match the curve of the proving key"); + if (wtns.nWitness != zkey.nVars - zkey.nAdditions) throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); + const curve = zkey.curve; + const Fr = curve.Fr; + const n8r = curve.Fr.n8; + const sDomain = zkey.domainSize * n8r; + if (logger) { + logger.debug("----------------------------"); + logger.debug(" PLONK PROVE SETTINGS"); + logger.debug(` Curve: ${curve.name}`); + logger.debug(` Circuit power: ${zkey.power}`); + logger.debug(` Domain size: ${zkey.domainSize}`); + logger.debug(` Vars: ${zkey.nVars}`); + logger.debug(` Public vars: ${zkey.nPublic}`); + logger.debug(` Constraints: ${zkey.nConstraints}`); + logger.debug(` Additions: ${zkey.nAdditions}`); + logger.debug("----------------------------"); + } + if (logger) logger.debug("> Reading witness file data"); + const buffWitness = await _iden3_binfileutils.readSection(fdWtns, sectionsWtns, 2); + buffWitness.set(Fr.zero, 0); + const buffInternalWitness = new ffjavascript.BigBuffer(n8r * zkey.nAdditions); + let buffers = {}; + let polynomials = {}; + let evaluations = {}; + let challenges = {}; + let proof = new Proof(curve, logger); + const transcript = new Keccak256Transcript(curve); + if (logger) logger.debug(`> Reading Section 3. Additions`); + await calculateAdditions(); + if (logger) logger.debug(`> Reading Section 12. Sigma1, Sigma2 & Sigma 3`); + if (logger) logger.debug("··· Reading Sigma polynomials "); + polynomials.Sigma1 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.Sigma2 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.Sigma3 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[12][0].p); + await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[12][0].p + 5 * sDomain); + await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[12][0].p + 10 * sDomain); + if (logger) logger.debug("··· Reading Sigma evaluations"); + evaluations.Sigma1 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.Sigma2 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.Sigma3 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[12][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[12][0].p + 6 * sDomain); + await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[12][0].p + 11 * sDomain); + if (logger) logger.debug(`> Reading Section 14. Powers of Tau`); + const PTau = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 14); + let publicSignals = []; + for (let i = 1; i <= zkey.nPublic; i++) { + const pub = buffWitness.slice(i * Fr.n8, i * Fr.n8 + Fr.n8); + publicSignals.push(ffjavascript.Scalar.fromRprLE(pub)); + } + if (logger) logger.debug(""); + if (logger) logger.debug("> ROUND 1"); + await round1(); + if (logger) logger.debug("> ROUND 2"); + await round2(); + if (logger) logger.debug("> ROUND 3"); + await round3(); + if (logger) logger.debug("> ROUND 4"); + await round4(); + if (logger) logger.debug("> ROUND 5"); + await round5(); + await fdZKey.close(); + await fdWtns.close(); + let _proof = proof.toObjectProof(false); + _proof.protocol = "plonk"; + _proof.curve = curve.name; + if (logger) logger.debug("PLONK PROVER FINISHED"); + return { + proof: stringifyBigInts$2(_proof), + publicSignals: stringifyBigInts$2(publicSignals) + }; + async function calculateAdditions() { + if (logger) logger.debug("··· Computing additions"); + const additionsBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 3); + const sSum = 8 + n8r * 2; + for (let i = 0; i < zkey.nAdditions; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.debug(` addition ${i}/${zkey.nAdditions}`); + let offset = i * sSum; + const signalId1 = readUInt32(additionsBuff, offset); + offset += 4; + const signalId2 = readUInt32(additionsBuff, offset); + offset += 4; + const factor1 = additionsBuff.slice(offset, offset + n8r); + offset += n8r; + const factor2 = additionsBuff.slice(offset, offset + n8r); + const witness1 = getWitness(signalId1); + const witness2 = getWitness(signalId2); + const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); + buffInternalWitness.set(result, n8r * i); + } + } + function readUInt32(b, o) { + const buff = b.slice(o, o + 4); + return new DataView(buff.buffer, buff.byteOffset, buff.byteLength).getUint32(0, true); + } + function getWitness(idx) { + if (idx < zkey.nVars - zkey.nAdditions) return buffWitness.slice(idx * n8r, idx * n8r + n8r); + else if (idx < zkey.nVars) return buffInternalWitness.slice((idx - (zkey.nVars - zkey.nAdditions)) * n8r, (idx - (zkey.nVars - zkey.nAdditions)) * n8r + n8r); + else return curve.Fr.zero; + } + async function round1() { + challenges.b = []; + for (let i = 1; i <= 11; i++) challenges.b[i] = curve.Fr.random(); + if (logger) logger.debug("> Computing A, B, C wire polynomials"); + await computeWirePolynomials(); + if (logger) logger.debug("> Computing A, B, C MSM"); + let commitA = await polynomials.A.multiExponentiation(PTau, "A"); + let commitB = await polynomials.B.multiExponentiation(PTau, "B"); + let commitC = await polynomials.C.multiExponentiation(PTau, "C"); + proof.addPolynomial("A", commitA); + proof.addPolynomial("B", commitB); + proof.addPolynomial("C", commitC); + return 0; + } + async function computeWirePolynomials() { + if (logger) logger.debug("··· Reading data from zkey file"); + buffers.A = new ffjavascript.BigBuffer(sDomain); + buffers.B = new ffjavascript.BigBuffer(sDomain); + buffers.C = new ffjavascript.BigBuffer(sDomain); + const aMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 4); + const bMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 5); + const cMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 6); + for (let i = 0; i < zkey.nConstraints; i++) { + const i_sFr = i * n8r; + const offset = i * 4; + const signalIdA = readUInt32(aMapBuff, offset); + buffers.A.set(getWitness(signalIdA), i_sFr); + const signalIdB = readUInt32(bMapBuff, offset); + buffers.B.set(getWitness(signalIdB), i_sFr); + const signalIdC = readUInt32(cMapBuff, offset); + buffers.C.set(getWitness(signalIdC), i_sFr); + } + buffers.A = await Fr.batchToMontgomery(buffers.A); + buffers.B = await Fr.batchToMontgomery(buffers.B); + buffers.C = await Fr.batchToMontgomery(buffers.C); + if (logger) logger.debug("··· Computing A ifft"); + polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); + if (logger) logger.debug("··· Computing B ifft"); + polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); + if (logger) logger.debug("··· Computing C ifft"); + polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); + if (logger) logger.debug("··· Computing A fft"); + evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); + if (logger) logger.debug("··· Computing B fft"); + evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); + if (logger) logger.debug("··· Computing C fft"); + evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); + polynomials.A.blindCoefficients([challenges.b[2], challenges.b[1]]); + polynomials.B.blindCoefficients([challenges.b[4], challenges.b[3]]); + polynomials.C.blindCoefficients([challenges.b[6], challenges.b[5]]); + if (polynomials.A.degree() >= zkey.domainSize + 2) throw new Error("A Polynomial is not well calculated"); + if (polynomials.B.degree() >= zkey.domainSize + 2) throw new Error("B Polynomial is not well calculated"); + if (polynomials.C.degree() >= zkey.domainSize + 2) throw new Error("C Polynomial is not well calculated"); + } + async function round2() { + if (logger) logger.debug("> Computing challenges beta and gamma"); + transcript.reset(); + transcript.addPolCommitment(zkey.Qm); + transcript.addPolCommitment(zkey.Ql); + transcript.addPolCommitment(zkey.Qr); + transcript.addPolCommitment(zkey.Qo); + transcript.addPolCommitment(zkey.Qc); + transcript.addPolCommitment(zkey.S1); + transcript.addPolCommitment(zkey.S2); + transcript.addPolCommitment(zkey.S3); + for (let i = 0; i < zkey.nPublic; i++) transcript.addScalar(buffers.A.slice(i * n8r, i * n8r + n8r)); + transcript.addPolCommitment(proof.getPolynomial("A")); + transcript.addPolCommitment(proof.getPolynomial("B")); + transcript.addPolCommitment(proof.getPolynomial("C")); + challenges.beta = transcript.getChallenge(); + if (logger) logger.debug("··· challenges.beta: " + Fr.toString(challenges.beta, 16)); + transcript.reset(); + transcript.addScalar(challenges.beta); + challenges.gamma = transcript.getChallenge(); + if (logger) logger.debug("··· challenges.gamma: " + Fr.toString(challenges.gamma, 16)); + if (logger) logger.debug("> Computing Z polynomial"); + await computeZ(); + if (logger) logger.debug("> Computing Z MSM"); + let commitZ = await polynomials.Z.multiExponentiation(PTau, "Z"); + proof.addPolynomial("Z", commitZ); + } + async function computeZ() { + if (logger) logger.debug("··· Computing Z evaluations"); + let numArr = new ffjavascript.BigBuffer(sDomain); + let denArr = new ffjavascript.BigBuffer(sDomain); + numArr.set(Fr.one, 0); + denArr.set(Fr.one, 0); + let w = Fr.one; + for (let i = 0; i < zkey.domainSize; i++) { + const i_n8r = i * n8r; + const a = buffers.A.slice(i_n8r, i_n8r + n8r); + const b = buffers.B.slice(i_n8r, i_n8r + n8r); + const c = buffers.C.slice(i_n8r, i_n8r + n8r); + const betaw = Fr.mul(challenges.beta, w); + let n1 = Fr.add(a, betaw); + n1 = Fr.add(n1, challenges.gamma); + let n2 = Fr.add(b, Fr.mul(zkey.k1, betaw)); + n2 = Fr.add(n2, challenges.gamma); + let n3 = Fr.add(c, Fr.mul(zkey.k2, betaw)); + n3 = Fr.add(n3, challenges.gamma); + let num = Fr.mul(n1, Fr.mul(n2, n3)); + let d1 = Fr.add(a, Fr.mul(evaluations.Sigma1.getEvaluation(i * 4), challenges.beta)); + d1 = Fr.add(d1, challenges.gamma); + let d2 = Fr.add(b, Fr.mul(evaluations.Sigma2.getEvaluation(i * 4), challenges.beta)); + d2 = Fr.add(d2, challenges.gamma); + let d3 = Fr.add(c, Fr.mul(evaluations.Sigma3.getEvaluation(i * 4), challenges.beta)); + d3 = Fr.add(d3, challenges.gamma); + let den = Fr.mul(d1, Fr.mul(d2, d3)); + num = Fr.mul(numArr.slice(i_n8r, i_n8r + n8r), num); + numArr.set(num, (i + 1) % zkey.domainSize * n8r); + den = Fr.mul(denArr.slice(i_n8r, i_n8r + n8r), den); + denArr.set(den, (i + 1) % zkey.domainSize * n8r); + w = Fr.mul(w, Fr.w[zkey.power]); + } + denArr = await Fr.batchInverse(denArr); + for (let i = 0; i < zkey.domainSize; i++) { + const i_sFr = i * n8r; + const z = Fr.mul(numArr.slice(i_sFr, i_sFr + n8r), denArr.slice(i_sFr, i_sFr + n8r)); + numArr.set(z, i_sFr); + } + buffers.Z = numArr; + if (!Fr.eq(numArr.slice(0, n8r), Fr.one)) throw new Error("Copy constraints does not match"); + if (logger) logger.debug("··· Computing Z ifft"); + polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); + if (logger) logger.debug("··· Computing Z fft"); + evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); + polynomials.Z.blindCoefficients([ + challenges.b[9], + challenges.b[8], + challenges.b[7] + ]); + if (polynomials.Z.degree() >= zkey.domainSize + 3) throw new Error("Z Polynomial is not well calculated"); + delete buffers.Z; + } + async function round3() { + if (logger) logger.debug("> Computing challenge alpha"); + transcript.reset(); + transcript.addScalar(challenges.beta); + transcript.addScalar(challenges.gamma); + transcript.addPolCommitment(proof.getPolynomial("Z")); + challenges.alpha = transcript.getChallenge(); + challenges.alpha2 = Fr.square(challenges.alpha); + if (logger) logger.debug("··· challenges.alpha: " + Fr.toString(challenges.alpha, 16)); + if (logger) logger.debug("> Computing T polynomial"); + await computeT(); + if (logger) logger.debug("> Computing T MSM"); + let commitT1 = await polynomials.T1.multiExponentiation(PTau, "T1"); + let commitT2 = await polynomials.T2.multiExponentiation(PTau, "T2"); + let commitT3 = await polynomials.T3.multiExponentiation(PTau, "T3"); + proof.addPolynomial("T1", commitT1); + proof.addPolynomial("T2", commitT2); + proof.addPolynomial("T3", commitT3); + } + async function computeT() { + if (logger) logger.debug(`··· Reading sections 8, 9, 7, 10, 11. Q selectors`); + evaluations.QL = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QR = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QM = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QO = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QC = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[8][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[9][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[7][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[10][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[11][0].p + sDomain); + evaluations.Lagrange = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4 * zkey.nPublic), curve, logger); + for (let i = 0; i < zkey.nPublic; i++) await fdZKey.readToBuffer(evaluations.Lagrange.eval, i * sDomain * 4, sDomain * 4, zkeySections[13][0].p + i * 5 * sDomain + sDomain); + buffers.T = new ffjavascript.BigBuffer(sDomain * 4); + buffers.Tz = new ffjavascript.BigBuffer(sDomain * 4); + if (logger) logger.debug("··· Computing T evaluations"); + let w = Fr.one; + for (let i = 0; i < zkey.domainSize * 4; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.debug(` T evaluation ${i}/${zkey.domainSize * 4}`); + const a = evaluations.A.getEvaluation(i); + const b = evaluations.B.getEvaluation(i); + const c = evaluations.C.getEvaluation(i); + const z = evaluations.Z.getEvaluation(i); + const zw = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); + const qm = evaluations.QM.getEvaluation(i); + const ql = evaluations.QL.getEvaluation(i); + const qr = evaluations.QR.getEvaluation(i); + const qo = evaluations.QO.getEvaluation(i); + const qc = evaluations.QC.getEvaluation(i); + const s1 = evaluations.Sigma1.getEvaluation(i); + const s2 = evaluations.Sigma2.getEvaluation(i); + const s3 = evaluations.Sigma3.getEvaluation(i); + const ap = Fr.add(challenges.b[2], Fr.mul(challenges.b[1], w)); + const bp = Fr.add(challenges.b[4], Fr.mul(challenges.b[3], w)); + const cp = Fr.add(challenges.b[6], Fr.mul(challenges.b[5], w)); + const w2 = Fr.square(w); + const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], w2), Fr.mul(challenges.b[8], w)), challenges.b[9]); + const wW = Fr.mul(w, Fr.w[zkey.power]); + const wW2 = Fr.square(wW); + const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], wW2), Fr.mul(challenges.b[8], wW)), challenges.b[9]); + let pi = Fr.zero; + for (let j = 0; j < zkey.nPublic; j++) { + const offset = j * 4 * zkey.domainSize + i; + const lPol = evaluations.Lagrange.getEvaluation(offset); + const aVal = buffers.A.slice(j * n8r, (j + 1) * n8r); + pi = Fr.sub(pi, Fr.mul(lPol, aVal)); + } + let [e1, e1z] = MulZ.mul2(a, b, ap, bp, i % 4, Fr); + e1 = Fr.mul(e1, qm); + e1z = Fr.mul(e1z, qm); + e1 = Fr.add(e1, Fr.mul(a, ql)); + e1z = Fr.add(e1z, Fr.mul(ap, ql)); + e1 = Fr.add(e1, Fr.mul(b, qr)); + e1z = Fr.add(e1z, Fr.mul(bp, qr)); + e1 = Fr.add(e1, Fr.mul(c, qo)); + e1z = Fr.add(e1z, Fr.mul(cp, qo)); + e1 = Fr.add(e1, pi); + e1 = Fr.add(e1, qc); + const betaw = Fr.mul(challenges.beta, w); + let e2a = a; + e2a = Fr.add(e2a, betaw); + e2a = Fr.add(e2a, challenges.gamma); + let e2b = b; + e2b = Fr.add(e2b, Fr.mul(betaw, zkey.k1)); + e2b = Fr.add(e2b, challenges.gamma); + let e2c = c; + e2c = Fr.add(e2c, Fr.mul(betaw, zkey.k2)); + e2c = Fr.add(e2c, challenges.gamma); + let e2d = z; + let [e2, e2z] = MulZ.mul4(e2a, e2b, e2c, e2d, ap, bp, cp, zp, i % 4, Fr); + e2 = Fr.mul(e2, challenges.alpha); + e2z = Fr.mul(e2z, challenges.alpha); + let e3a = a; + e3a = Fr.add(e3a, Fr.mul(challenges.beta, s1)); + e3a = Fr.add(e3a, challenges.gamma); + let e3b = b; + e3b = Fr.add(e3b, Fr.mul(challenges.beta, s2)); + e3b = Fr.add(e3b, challenges.gamma); + let e3c = c; + e3c = Fr.add(e3c, Fr.mul(challenges.beta, s3)); + e3c = Fr.add(e3c, challenges.gamma); + let e3d = zw; + let [e3, e3z] = MulZ.mul4(e3a, e3b, e3c, e3d, ap, bp, cp, zWp, i % 4, Fr); + e3 = Fr.mul(e3, challenges.alpha); + e3z = Fr.mul(e3z, challenges.alpha); + let e4 = Fr.sub(z, Fr.one); + e4 = Fr.mul(e4, evaluations.Lagrange.getEvaluation(i)); + e4 = Fr.mul(e4, challenges.alpha2); + let e4z = Fr.mul(zp, evaluations.Lagrange.getEvaluation(i)); + e4z = Fr.mul(e4z, challenges.alpha2); + let t = Fr.add(Fr.sub(Fr.add(e1, e2), e3), e4); + let tz = Fr.add(Fr.sub(Fr.add(e1z, e2z), e3z), e4z); + buffers.T.set(t, i * n8r); + buffers.Tz.set(tz, i * n8r); + w = Fr.mul(w, Fr.w[zkey.power + 2]); + } + if (logger) logger.debug("··· Computing T ifft"); + polynomials.T = await Polynomial.fromEvaluations(buffers.T, curve, logger); + if (logger) logger.debug("··· Computing T / ZH"); + polynomials.T.divZh(zkey.domainSize, 4); + if (logger) logger.debug("··· Computing Tz ifft"); + polynomials.Tz = await Polynomial.fromEvaluations(buffers.Tz, curve, logger); + polynomials.T.add(polynomials.Tz); + if (polynomials.T.degree() >= zkey.domainSize * 3 + 6) throw new Error("T Polynomial is not well calculated"); + if (logger) logger.debug("··· Computing T1, T2, T3 polynomials"); + polynomials.T1 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); + polynomials.T2 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); + polynomials.T3 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 6) * n8r), curve, logger); + polynomials.T1.coef.set(polynomials.T.coef.slice(0, sDomain), 0); + polynomials.T2.coef.set(polynomials.T.coef.slice(sDomain, sDomain * 2), 0); + polynomials.T3.coef.set(polynomials.T.coef.slice(sDomain * 2, sDomain * 3 + 6 * n8r), 0); + polynomials.T1.setCoef(zkey.domainSize, challenges.b[10]); + const lowestMid = Fr.sub(polynomials.T2.getCoef(0), challenges.b[10]); + polynomials.T2.setCoef(0, lowestMid); + polynomials.T2.setCoef(zkey.domainSize, challenges.b[11]); + const lowestHigh = Fr.sub(polynomials.T3.getCoef(0), challenges.b[11]); + polynomials.T3.setCoef(0, lowestHigh); + } + async function round4() { + if (logger) logger.debug("> Computing challenge xi"); + transcript.reset(); + transcript.addScalar(challenges.alpha); + transcript.addPolCommitment(proof.getPolynomial("T1")); + transcript.addPolCommitment(proof.getPolynomial("T2")); + transcript.addPolCommitment(proof.getPolynomial("T3")); + challenges.xi = transcript.getChallenge(); + challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); + if (logger) logger.debug("··· challenges.xi: " + Fr.toString(challenges.xi, 16)); + proof.addEvaluation("eval_a", polynomials.A.evaluate(challenges.xi)); + proof.addEvaluation("eval_b", polynomials.B.evaluate(challenges.xi)); + proof.addEvaluation("eval_c", polynomials.C.evaluate(challenges.xi)); + proof.addEvaluation("eval_s1", polynomials.Sigma1.evaluate(challenges.xi)); + proof.addEvaluation("eval_s2", polynomials.Sigma2.evaluate(challenges.xi)); + proof.addEvaluation("eval_zw", polynomials.Z.evaluate(challenges.xiw)); + } + async function round5() { + if (logger) logger.debug("> Computing challenge v"); + transcript.reset(); + transcript.addScalar(challenges.xi); + transcript.addScalar(proof.getEvaluation("eval_a")); + transcript.addScalar(proof.getEvaluation("eval_b")); + transcript.addScalar(proof.getEvaluation("eval_c")); + transcript.addScalar(proof.getEvaluation("eval_s1")); + transcript.addScalar(proof.getEvaluation("eval_s2")); + transcript.addScalar(proof.getEvaluation("eval_zw")); + challenges.v = []; + challenges.v[1] = transcript.getChallenge(); + if (logger) logger.debug("··· challenges.v: " + Fr.toString(challenges.v[1], 16)); + for (let i = 2; i < 6; i++) challenges.v[i] = Fr.mul(challenges.v[i - 1], challenges.v[1]); + if (logger) logger.debug("> Computing linearisation polynomial R(X)"); + await computeR(); + if (logger) logger.debug("> Computing opening proof polynomial Wxi(X) polynomial"); + computeWxi(); + if (logger) logger.debug("> Computing opening proof polynomial Wxiw(X) polynomial"); + computeWxiw(); + if (logger) logger.debug("> Computing Wxi, Wxiw MSM"); + let commitWxi = await polynomials.Wxi.multiExponentiation(PTau, "Wxi"); + let commitWxiw = await polynomials.Wxiw.multiExponentiation(PTau, "Wxiw"); + proof.addPolynomial("Wxi", commitWxi); + proof.addPolynomial("Wxiw", commitWxiw); + } + async function computeR() { + const Fr = curve.Fr; + polynomials.QL = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QR = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QM = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QO = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QC = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[8][0].p); + await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[9][0].p); + await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[7][0].p); + await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[10][0].p); + await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[11][0].p); + challenges.xin = challenges.xi; + for (let i = 0; i < zkey.power; i++) challenges.xin = Fr.square(challenges.xin); + challenges.zh = Fr.sub(challenges.xin, Fr.one); + const L = []; + const n = Fr.e(zkey.domainSize); + let w = Fr.one; + for (let i = 1; i <= Math.max(1, zkey.nPublic); i++) { + L[i] = Fr.div(Fr.mul(w, challenges.zh), Fr.mul(n, Fr.sub(challenges.xi, w))); + w = Fr.mul(w, Fr.w[zkey.power]); + } + const eval_l1 = Fr.div(Fr.sub(challenges.xin, Fr.one), Fr.mul(n, Fr.sub(challenges.xi, Fr.one))); + if (logger) { + logger.debug("Lagrange Evaluations: "); + for (let i = 1; i < L.length; i++) logger.debug(`L${i}(xi)=` + Fr.toString(L[i], 16)); + } + let eval_pi = Fr.zero; + for (let i = 0; i < publicSignals.length; i++) { + const w = Fr.e(publicSignals[i]); + eval_pi = Fr.sub(eval_pi, Fr.mul(w, L[i + 1])); + } + if (logger) logger.debug("PI: " + Fr.toString(eval_pi, 16)); + const coef_ab = Fr.mul(proof.evaluations.eval_a, proof.evaluations.eval_b); + let e2a = proof.evaluations.eval_a; + const betaxi = Fr.mul(challenges.beta, challenges.xi); + e2a = Fr.add(e2a, betaxi); + e2a = Fr.add(e2a, challenges.gamma); + let e2b = proof.evaluations.eval_b; + e2b = Fr.add(e2b, Fr.mul(betaxi, zkey.k1)); + e2b = Fr.add(e2b, challenges.gamma); + let e2c = proof.evaluations.eval_c; + e2c = Fr.add(e2c, Fr.mul(betaxi, zkey.k2)); + e2c = Fr.add(e2c, challenges.gamma); + const e2 = Fr.mul(Fr.mul(Fr.mul(e2a, e2b), e2c), challenges.alpha); + let e3a = proof.evaluations.eval_a; + e3a = Fr.add(e3a, Fr.mul(challenges.beta, proof.evaluations.eval_s1)); + e3a = Fr.add(e3a, challenges.gamma); + let e3b = proof.evaluations.eval_b; + e3b = Fr.add(e3b, Fr.mul(challenges.beta, proof.evaluations.eval_s2)); + e3b = Fr.add(e3b, challenges.gamma); + let e3 = Fr.mul(e3a, e3b); + e3 = Fr.mul(e3, proof.evaluations.eval_zw); + e3 = Fr.mul(e3, challenges.alpha); + const e4 = Fr.mul(eval_l1, challenges.alpha2); + polynomials.R = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 6) * n8r), curve, logger); + polynomials.R.add(polynomials.QM, coef_ab); + polynomials.R.add(polynomials.QL, proof.evaluations.eval_a); + polynomials.R.add(polynomials.QR, proof.evaluations.eval_b); + polynomials.R.add(polynomials.QO, proof.evaluations.eval_c); + polynomials.R.add(polynomials.QC); + polynomials.R.add(polynomials.Z, e2); + polynomials.R.sub(polynomials.Sigma3, Fr.mul(e3, challenges.beta)); + polynomials.R.add(polynomials.Z, e4); + let tmp = Polynomial.fromPolynomial(polynomials.T3, curve, logger); + tmp.mulScalar(Fr.square(challenges.xin)); + tmp.add(polynomials.T2, challenges.xin); + tmp.add(polynomials.T1); + tmp.mulScalar(challenges.zh); + polynomials.R.sub(tmp); + let r0 = Fr.sub(eval_pi, Fr.mul(e3, Fr.add(proof.evaluations.eval_c, challenges.gamma))); + r0 = Fr.sub(r0, e4); + if (logger) logger.debug("r0: " + Fr.toString(r0, 16)); + polynomials.R.addScalar(r0); + } + function computeWxi() { + polynomials.Wxi = new Polynomial(new ffjavascript.BigBuffer(sDomain + 6 * n8r), curve, logger); + polynomials.Wxi.add(polynomials.R); + polynomials.Wxi.add(polynomials.A, challenges.v[1]); + polynomials.Wxi.add(polynomials.B, challenges.v[2]); + polynomials.Wxi.add(polynomials.C, challenges.v[3]); + polynomials.Wxi.add(polynomials.Sigma1, challenges.v[4]); + polynomials.Wxi.add(polynomials.Sigma2, challenges.v[5]); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[1], proof.evaluations.eval_a)); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[2], proof.evaluations.eval_b)); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[3], proof.evaluations.eval_c)); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[4], proof.evaluations.eval_s1)); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[5], proof.evaluations.eval_s2)); + polynomials.Wxi.divByZerofier(1, challenges.xi); + } + async function computeWxiw() { + polynomials.Wxiw = Polynomial.fromPolynomial(polynomials.Z, curve, logger); + polynomials.Wxiw.subScalar(proof.evaluations.eval_zw); + polynomials.Wxiw.divByZerofier(1, challenges.xiw); + } +} +//#endregion +//#region src/plonk_fullprove.js +var { unstringifyBigInts: unstringifyBigInts$6 } = ffjavascript.utils; async function plonkFullProve$1(_input, wasmFile, zkeyFileName, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$6(_input); - - const wtns= { - type: "mem" - }; - await wtnsCalculate$1(input, wasmFile, wtns, wtnsCalcOptions); - return await plonk16Prove(zkeyFileName, wtns, logger, proverOptions); -} - -/* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const { unstringifyBigInts: unstringifyBigInts$5 } = ffjavascript.utils; - + const input = unstringifyBigInts$6(_input); + const wtns = { type: "mem" }; + await wtnsCalculate$1(input, wasmFile, wtns, wtnsCalcOptions); + return await plonk16Prove(zkeyFileName, wtns, logger, proverOptions); +} +//#endregion +//#region src/plonk_verify.js +var { unstringifyBigInts: unstringifyBigInts$5 } = ffjavascript.utils; async function plonkVerify$1(_vk_verifier, _publicSignals, _proof, logger) { - let vk_verifier = unstringifyBigInts$5(_vk_verifier); - _proof = unstringifyBigInts$5(_proof); - let publicSignals = unstringifyBigInts$5(_publicSignals); - - const curve = await getCurveFromName(vk_verifier.curve); - - const Fr = curve.Fr; - const G1 = curve.G1; - - if (logger) logger.info("PLONK VERIFIER STARTED"); - - let proof = fromObjectProof(curve,_proof); - vk_verifier = fromObjectVk$1(curve, vk_verifier); - - if (!isWellConstructed(curve, proof)) { - logger.error("Proof commitments are not valid."); - return false; - } - - if (publicSignals.length != vk_verifier.nPublic) { - if (logger) logger.error("Invalid number of public inputs"); - return false; - } - - if (!evaluationsAreValid$1(curve, proof)) { - if (logger) logger.error("Proof evaluations are not valid"); - return false; - } - - if (!publicInputsAreValid$1(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - const challenges = calculatechallenges(curve, proof, publicSignals, vk_verifier); - if (logger) { - logger.debug("beta: " + Fr.toString(challenges.beta, 16)); - logger.debug("gamma: " + Fr.toString(challenges.gamma, 16)); - logger.debug("alpha: " + Fr.toString(challenges.alpha, 16)); - logger.debug("xi: " + Fr.toString(challenges.xi, 16)); - for(let i=1;i<6;i++) { - if (logger) logger.debug("v: " + Fr.toString(challenges.v[i], 16)); - } - logger.debug("u: " + Fr.toString(challenges.u, 16)); - } - const L = calculateLagrangeEvaluations(curve, challenges, vk_verifier); - if (logger) { - for (let i=1; i. -*/ - -const { unstringifyBigInts: unstringifyBigInts$4} = ffjavascript.utils; - + const G1 = curve.G1; + const Fr = curve.Fr; + let A1 = proof.Wxi; + A1 = G1.add(A1, G1.timesFr(proof.Wxiw, challenges.u)); + let B1 = G1.timesFr(proof.Wxi, challenges.xi); + const s = Fr.mul(Fr.mul(challenges.u, challenges.xi), Fr.w[vk.power]); + B1 = G1.add(B1, G1.timesFr(proof.Wxiw, s)); + B1 = G1.add(B1, F); + B1 = G1.sub(B1, E); + return await curve.pairingEq(G1.neg(A1), vk.X_2, B1, curve.G2.one); +} +//#endregion +//#region src/plonk_exportsoliditycalldata.js +var { unstringifyBigInts: unstringifyBigInts$4 } = ffjavascript.utils; function p256$1(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0"+nstr; - nstr = `"0x${nstr}"`; - return nstr; + let nstr = n.toString(16); + while (nstr.length < 64) nstr = "0" + nstr; + nstr = `"0x${nstr}"`; + return nstr; } - async function plonkExportSolidityCallData(_proof, _pub) { - const proof = unstringifyBigInts$4(_proof); - const pub = unstringifyBigInts$4(_pub); - - await getCurveFromName(proof.curve); - - let inputs = ""; - for (let i=0; i. -*/ - -// We export to zkey the signals and values of the a, b, c, ql, qr, qm, qo and qc - -// a, b and c are signals id (32-bit integers) -// ql, qr, qm, qo and qc are field values - + const proof = unstringifyBigInts$4(_proof); + const pub = unstringifyBigInts$4(_pub); + await getCurveFromName(proof.curve); + let inputs = ""; + for (let i = 0; i < pub.length; i++) { + if (inputs != "") inputs = inputs + ","; + inputs = inputs + p256$1(pub[i]); + } + return `[${p256$1(proof.A[0])}, ${p256$1(proof.A[1])},${p256$1(proof.B[0])},${p256$1(proof.B[1])},${p256$1(proof.C[0])},${p256$1(proof.C[1])},${p256$1(proof.Z[0])},${p256$1(proof.Z[1])},${p256$1(proof.T1[0])},${p256$1(proof.T1[1])},${p256$1(proof.T2[0])},${p256$1(proof.T2[1])},${p256$1(proof.T3[0])},${p256$1(proof.T3[1])},${p256$1(proof.Wxi[0])},${p256$1(proof.Wxi[1])},${p256$1(proof.Wxiw[0])},${p256$1(proof.Wxiw[1])},${p256$1(proof.eval_a)},${p256$1(proof.eval_b)},${p256$1(proof.eval_c)},${p256$1(proof.eval_s1)},${p256$1(proof.eval_s2)},${p256$1(proof.eval_zw)}][${inputs}]`; +} +//#endregion +//#region src/plonk_equation.js function getFFlonkConstantConstraint(signal1, Fr) { - return [signal1, 0, 0, Fr.one, Fr.zero, Fr.zero, Fr.zero, Fr.zero]; + return [ + signal1, + 0, + 0, + Fr.one, + Fr.zero, + Fr.zero, + Fr.zero, + Fr.zero + ]; } - function getFFlonkAdditionConstraint(signal1, signal2, signalOut, ql, qr, qm, qo, qc) { - return [signal1, signal2, signalOut, ql, qr, qm, qo, qc]; + return [ + signal1, + signal2, + signalOut, + ql, + qr, + qm, + qo, + qc + ]; } - function getFFlonkMultiplicationConstraint(signal1, signal2, signalOut, ql, qr, qm, qo, qc, Fr) { - return [signal1, signal2, signalOut, ql, qr, qm, qo, qc]; -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const LINEAR_COMBINATION_NULLABLE = 0; -const LINEAR_COMBINATION_CONSTANT = 1; -const LINEAR_COMBINATION_VARIABLE = 2; - -class r1csConstraintProcessor { - constructor(Fr, fnGetConstantConstraint, fnGetAdditionConstraint, fnGetMultiplicationConstraint, logger) { - this.Fr = Fr; - this.logger = logger; - this.fnGetAdditionConstraint = fnGetAdditionConstraint; - this.fnGetMultiplicationConstraint = fnGetMultiplicationConstraint; - } - - processR1csConstraint(settings, lcA, lcB, lcC) { - this.normalizeLinearCombination(lcA); - this.normalizeLinearCombination(lcB); - this.normalizeLinearCombination(lcC); - - const lctA = this.getLinearCombinationType(lcA); - const lctB = this.getLinearCombinationType(lcB); - - if ((lctA === LINEAR_COMBINATION_NULLABLE) || (lctB === LINEAR_COMBINATION_NULLABLE)) { - return this.processR1csAdditionConstraint(settings, lcC); - } else if (lctA === LINEAR_COMBINATION_CONSTANT) { - const lcCC = this.joinLinearCombinations(lcB, lcC, lcA[0]); - return this.processR1csAdditionConstraint(settings, lcCC); - } else if (lctB === LINEAR_COMBINATION_CONSTANT) { - const lcCC = this.joinLinearCombinations(lcA, lcC, lcB[0]); - return this.processR1csAdditionConstraint(settings, lcCC); - } else { - return this.processR1csMultiplicationConstraint(settings, lcA, lcB, lcC); - } - } - - getLinearCombinationType(linCom) { - // let k = this.Fr.zero; - // - // const signalIds = Object.keys(linCom); - // for (let i = 0; i < signalIds.length; i++) { - // if (signalIds[i] === "0") { - // k = this.Fr.add(k, linCom[signalIds[i]]); - // } else { - // return LINEAR_COMBINATION_VARIABLE; - // } - // } - // - // if (!this.Fr.eq(k, this.Fr.zero)) return LINEAR_COMBINATION_CONSTANT; - // - // return LINEAR_COMBINATION_NULLABLE; - - let k = this.Fr.zero; - let n = 0; - const ss = Object.keys(linCom); - for (let i = 0; i < ss.length; i++) { - if (linCom[ss[i]] == 0n) { - delete linCom[ss[i]]; - } else if (ss[i] == 0) { - k = this.Fr.add(k, linCom[ss[i]]); - } else { - n++; - } - } - if (n > 0) return LINEAR_COMBINATION_VARIABLE; - if (!this.Fr.isZero(k)) return LINEAR_COMBINATION_CONSTANT; - return LINEAR_COMBINATION_NULLABLE; - } - - normalizeLinearCombination(linCom) { - const signalIds = Object.keys(linCom); - for (let i = 0; i < signalIds.length; i++) { - if (this.Fr.isZero(linCom[signalIds[i]])) delete linCom[signalIds[i]]; - } - - return linCom; - } - - joinLinearCombinations(linCom1, linCom2, k) { - const res = {}; - - // for (let s in linCom1) { - // const val = this.Fr.mul(k, linCom1[s]); - // res[s] = !(s in res) ? val : this.Fr.add(val, res[s]); - // } - // - // for (let s in linCom2) { - // const val = this.Fr.mul(k, linCom2[s]); - // res[s] = !(s in res) ? val : this.Fr.add(val, res[s]); - // } - - for (let s in linCom1) { - if (typeof res[s] == "undefined") { - res[s] = this.Fr.mul(k, linCom1[s]); - } else { - res[s] = this.Fr.add(res[s], this.Fr.mul(k, linCom1[s])); - } - } - - for (let s in linCom2) { - if (typeof res[s] == "undefined") { - res[s] = linCom2[s]; - } else { - res[s] = this.Fr.add(res[s], linCom2[s]); - } - } - - return this.normalizeLinearCombination(res); - } - - reduceCoefs(settings, constraintsArr, additionsArr, linCom, maxC) { - const res = { - k: this.Fr.zero, - signals: [], - coefs: [] - }; - const cs = []; - - for (let signalId in linCom) { - if (signalId == 0) { - res.k = this.Fr.add(res.k, linCom[signalId]); - } else if (linCom[signalId] != 0n) { - cs.push([Number(signalId), linCom[signalId]]); - } - } - - while (cs.length > maxC) { - const c1 = cs.shift(); - const c2 = cs.shift(); - const so = settings.nVars++; - - const constraints = this.fnGetAdditionConstraint( - c1[0], c2[0], so, - this.Fr.neg(c1[1]), this.Fr.neg(c2[1]), this.Fr.zero, this.Fr.one, this.Fr.zero); - - constraintsArr.push(constraints); - additionsArr.push([c1[0], c2[0], c1[1], c2[1]]); - - cs.push([so, this.Fr.one]); - } - - for (let i = 0; i < cs.length; i++) { - res.signals[i] = cs[i][0]; - res.coefs[i] = cs[i][1]; - } - - while (res.coefs.length < maxC) { - res.signals.push(0); - res.coefs.push(this.Fr.zero); - } - - return res; - } - - processR1csAdditionConstraint(settings, linCom) { - const constraintsArr = []; - const additionsArr = []; - - const C = this.reduceCoefs(settings, constraintsArr, additionsArr, linCom, 3); - - const constraints = this.fnGetAdditionConstraint( - C.signals[0], C.signals[1], C.signals[2], - C.coefs[0], C.coefs[1], this.Fr.zero, C.coefs[2], C.k); - - constraintsArr.push(constraints); - - return [constraintsArr, additionsArr]; - } - - processR1csMultiplicationConstraint(settings, lcA, lcB, lcC) { - const constraintsArr = []; - const additionsArr = []; - - const A = this.reduceCoefs(settings, constraintsArr, additionsArr, lcA, 1); - const B = this.reduceCoefs(settings, constraintsArr, additionsArr, lcB, 1); - const C = this.reduceCoefs(settings, constraintsArr, additionsArr, lcC, 1); - - const constraints = this.fnGetMultiplicationConstraint( - A.signals[0], B.signals[0], C.signals[0], - this.Fr.mul(A.coefs[0], B.k), - this.Fr.mul(A.k, B.coefs[0]), - this.Fr.mul(A.coefs[0], B.coefs[0]), - this.Fr.neg(C.coefs[0]), - this.Fr.sub(this.Fr.mul(A.k, B.k), C.k)); - - constraintsArr.push(constraints); - - return [constraintsArr, additionsArr]; - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -class CPolynomial { - constructor(n, curve, logger) { - this.n = n; - this.polynomials = Array(n).fill(undefined); - this.curve = curve; - this.Fr = curve.Fr; - this.G1 = curve.G1; - this.logger = logger; - } - - addPolynomial(position, polynomial) { - if (position > this.n - 1) { - throw new Error("CPolynomial:addPolynomial, cannot add a polynomial to a position greater than n-1"); - } - - this.polynomials[position] = polynomial; - } - - degree() { - let degrees = this.polynomials.map( - (polynomial, index) => polynomial === undefined ? 0 : polynomial.degree() * this.n + index); - return Math.max(...degrees); - } - - getPolynomial() { - let degrees = this.polynomials.map(polynomial => polynomial === undefined ? 0 : polynomial.degree()); - const maxDegree = this.degree(); - const lengthBuffer = 2 ** (log2(maxDegree - 1) + 1); - const sFr = this.Fr.n8; - - let polynomial = new Polynomial(new ffjavascript.BigBuffer(lengthBuffer * sFr), this.curve, this.logger); - - for (let i = 0; i < maxDegree; i++) { - const i_n8 = i * sFr; - const i_sFr = i_n8 * this.n; - - for (let j = 0; j < this.n; j++) { - if (this.polynomials[j] !== undefined) { - if (i <= degrees[j]) polynomial.coef.set(this.polynomials[j].coef.slice(i_n8, i_n8 + sFr), i_sFr + j * sFr); - } - } - } - - return polynomial; - } - - async multiExponentiation(PTau, name) { - let polynomial = this.getPolynomial(); - const n = polynomial.coef.byteLength / this.Fr.n8; - const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); - const bm = await this.Fr.batchFromMontgomery(polynomial.coef); - let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); - res = this.G1.toAffine(res); - return res; - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - - + return [ + signal1, + signal2, + signalOut, + ql, + qr, + qm, + qo, + qc + ]; +} +//#endregion +//#region src/r1cs_constraint_processor.js +var LINEAR_COMBINATION_NULLABLE = 0; +var LINEAR_COMBINATION_CONSTANT = 1; +var LINEAR_COMBINATION_VARIABLE = 2; +var r1csConstraintProcessor = class { + constructor(Fr, fnGetConstantConstraint, fnGetAdditionConstraint, fnGetMultiplicationConstraint, logger) { + this.Fr = Fr; + this.logger = logger; + this.fnGetAdditionConstraint = fnGetAdditionConstraint; + this.fnGetMultiplicationConstraint = fnGetMultiplicationConstraint; + } + processR1csConstraint(settings, lcA, lcB, lcC) { + this.normalizeLinearCombination(lcA); + this.normalizeLinearCombination(lcB); + this.normalizeLinearCombination(lcC); + const lctA = this.getLinearCombinationType(lcA); + const lctB = this.getLinearCombinationType(lcB); + if (lctA === LINEAR_COMBINATION_NULLABLE || lctB === LINEAR_COMBINATION_NULLABLE) return this.processR1csAdditionConstraint(settings, lcC); + else if (lctA === LINEAR_COMBINATION_CONSTANT) { + const lcCC = this.joinLinearCombinations(lcB, lcC, lcA[0]); + return this.processR1csAdditionConstraint(settings, lcCC); + } else if (lctB === LINEAR_COMBINATION_CONSTANT) { + const lcCC = this.joinLinearCombinations(lcA, lcC, lcB[0]); + return this.processR1csAdditionConstraint(settings, lcCC); + } else return this.processR1csMultiplicationConstraint(settings, lcA, lcB, lcC); + } + getLinearCombinationType(linCom) { + let k = this.Fr.zero; + let n = 0; + const ss = Object.keys(linCom); + for (let i = 0; i < ss.length; i++) if (linCom[ss[i]] == 0n) delete linCom[ss[i]]; + else if (ss[i] == 0) k = this.Fr.add(k, linCom[ss[i]]); + else n++; + if (n > 0) return LINEAR_COMBINATION_VARIABLE; + if (!this.Fr.isZero(k)) return LINEAR_COMBINATION_CONSTANT; + return LINEAR_COMBINATION_NULLABLE; + } + normalizeLinearCombination(linCom) { + const signalIds = Object.keys(linCom); + for (let i = 0; i < signalIds.length; i++) if (this.Fr.isZero(linCom[signalIds[i]])) delete linCom[signalIds[i]]; + return linCom; + } + joinLinearCombinations(linCom1, linCom2, k) { + const res = {}; + for (let s in linCom1) if (typeof res[s] == "undefined") res[s] = this.Fr.mul(k, linCom1[s]); + else res[s] = this.Fr.add(res[s], this.Fr.mul(k, linCom1[s])); + for (let s in linCom2) if (typeof res[s] == "undefined") res[s] = linCom2[s]; + else res[s] = this.Fr.add(res[s], linCom2[s]); + return this.normalizeLinearCombination(res); + } + reduceCoefs(settings, constraintsArr, additionsArr, linCom, maxC) { + const res = { + k: this.Fr.zero, + signals: [], + coefs: [] + }; + const cs = []; + for (let signalId in linCom) if (signalId == 0) res.k = this.Fr.add(res.k, linCom[signalId]); + else if (linCom[signalId] != 0n) cs.push([Number(signalId), linCom[signalId]]); + while (cs.length > maxC) { + const c1 = cs.shift(); + const c2 = cs.shift(); + const so = settings.nVars++; + const constraints = this.fnGetAdditionConstraint(c1[0], c2[0], so, this.Fr.neg(c1[1]), this.Fr.neg(c2[1]), this.Fr.zero, this.Fr.one, this.Fr.zero); + constraintsArr.push(constraints); + additionsArr.push([ + c1[0], + c2[0], + c1[1], + c2[1] + ]); + cs.push([so, this.Fr.one]); + } + for (let i = 0; i < cs.length; i++) { + res.signals[i] = cs[i][0]; + res.coefs[i] = cs[i][1]; + } + while (res.coefs.length < maxC) { + res.signals.push(0); + res.coefs.push(this.Fr.zero); + } + return res; + } + processR1csAdditionConstraint(settings, linCom) { + const constraintsArr = []; + const additionsArr = []; + const C = this.reduceCoefs(settings, constraintsArr, additionsArr, linCom, 3); + const constraints = this.fnGetAdditionConstraint(C.signals[0], C.signals[1], C.signals[2], C.coefs[0], C.coefs[1], this.Fr.zero, C.coefs[2], C.k); + constraintsArr.push(constraints); + return [constraintsArr, additionsArr]; + } + processR1csMultiplicationConstraint(settings, lcA, lcB, lcC) { + const constraintsArr = []; + const additionsArr = []; + const A = this.reduceCoefs(settings, constraintsArr, additionsArr, lcA, 1); + const B = this.reduceCoefs(settings, constraintsArr, additionsArr, lcB, 1); + const C = this.reduceCoefs(settings, constraintsArr, additionsArr, lcC, 1); + const constraints = this.fnGetMultiplicationConstraint(A.signals[0], B.signals[0], C.signals[0], this.Fr.mul(A.coefs[0], B.k), this.Fr.mul(A.k, B.coefs[0]), this.Fr.mul(A.coefs[0], B.coefs[0]), this.Fr.neg(C.coefs[0]), this.Fr.sub(this.Fr.mul(A.k, B.k), C.k)); + constraintsArr.push(constraints); + return [constraintsArr, additionsArr]; + } +}; +//#endregion +//#region src/polynomial/cpolynomial.js +var CPolynomial = class { + constructor(n, curve, logger) { + this.n = n; + this.polynomials = Array(n).fill(void 0); + this.curve = curve; + this.Fr = curve.Fr; + this.G1 = curve.G1; + this.logger = logger; + } + addPolynomial(position, polynomial) { + if (position > this.n - 1) throw new Error("CPolynomial:addPolynomial, cannot add a polynomial to a position greater than n-1"); + this.polynomials[position] = polynomial; + } + degree() { + let degrees = this.polynomials.map((polynomial, index) => polynomial === void 0 ? 0 : polynomial.degree() * this.n + index); + return Math.max(...degrees); + } + getPolynomial() { + let degrees = this.polynomials.map((polynomial) => polynomial === void 0 ? 0 : polynomial.degree()); + const maxDegree = this.degree(); + const lengthBuffer = 2 ** (log2(maxDegree - 1) + 1); + const sFr = this.Fr.n8; + let polynomial = new Polynomial(new ffjavascript.BigBuffer(lengthBuffer * sFr), this.curve, this.logger); + for (let i = 0; i < maxDegree; i++) { + const i_n8 = i * sFr; + const i_sFr = i_n8 * this.n; + for (let j = 0; j < this.n; j++) if (this.polynomials[j] !== void 0) { + if (i <= degrees[j]) polynomial.coef.set(this.polynomials[j].coef.slice(i_n8, i_n8 + sFr), i_sFr + j * sFr); + } + } + return polynomial; + } + async multiExponentiation(PTau, name) { + let polynomial = this.getPolynomial(); + const n = polynomial.coef.byteLength / this.Fr.n8; + const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); + const bm = await this.Fr.batchFromMontgomery(polynomial.coef); + let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); + res = this.G1.toAffine(res); + return res; + } +}; +//#endregion +//#region src/fflonk_setup.js async function fflonkSetup$1(r1csFilename, ptauFilename, zkeyFilename, logger) { - if (logger) logger.info("FFLONK SETUP STARTED"); - - if (globalThis.gc) globalThis.gc(); - - // Read PTau file - if (logger) logger.info("> Reading PTau file"); - const {fd: fdPTau, sections: pTauSections} = await binFileUtils.readBinFile(ptauFilename, "ptau", 1, 1 << 22, 1 << 24); - if (!pTauSections[12]) { - throw new Error("Powers of Tau is not well prepared. Section 12 missing."); - } - - // Get curve defined in PTau - if (logger) logger.info("> Getting curve from PTau settings"); - const {curve} = await readPTauHeader(fdPTau, pTauSections); - - // Read r1cs file - if (logger) logger.info("> Reading r1cs file"); - const {fd: fdR1cs, sections: sectionsR1cs} = await binFileUtils.readBinFile(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); - const r1cs = await r1csfile.readR1csFd(fdR1cs, sectionsR1cs, {loadConstraints: false, loadCustomGates: true}); - - // Potential error checks - if (r1cs.prime !== curve.r) { - throw new Error("r1cs curve does not match powers of tau ceremony curve"); - } - - // Initializations - const Fr = curve.Fr; - - const sFr = curve.Fr.n8; - const sG1 = curve.G1.F.n8 * 2; - const sG2 = curve.G2.F.n8 * 2; - - let polynomials = {}; - let evaluations = {}; - let PTau; - - let settings = { - nVars: r1cs.nVars, - nPublic: r1cs.nOutputs + r1cs.nPubInputs - }; - - const plonkConstraints = new BigArray(); - let plonkAdditions = new BigArray(); - - // Process constraints inside r1cs - if (logger) logger.info("> Processing FFlonk constraints"); - await computeFFConstraints(curve.Fr, r1cs, logger); - if (globalThis.gc) globalThis.gc(); - - // As the t polynomial is n+5 we need at least a power of 4 - //TODO check!!!! - // NOTE : plonkConstraints + 2 = #constraints + blinding coefficients for each wire polynomial - settings.cirPower = Math.max(FF_T_POL_DEG_MIN, log2((plonkConstraints.length + 2) - 1) + 1); - settings.domainSize = 2 ** settings.cirPower; - - if (pTauSections[2][0].size < (settings.domainSize * 9 + 18) * sG1) { - throw new Error("Powers of Tau is not big enough for this circuit size. Section 2 too small."); - } - if (pTauSections[3][0].size < sG2) { - throw new Error("Powers of Tau is not well prepared. Section 3 too small."); - } - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK SETUP SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${settings.cirPower}`); - logger.info(` Domain size: ${settings.domainSize}`); - logger.info(` Vars: ${settings.nVars}`); - logger.info(` Public vars: ${settings.nPublic}`); - logger.info(` Constraints: ${plonkConstraints.length}`); - logger.info(` Additions: ${plonkAdditions.length}`); - logger.info("----------------------------"); - } - - // Compute k1 and k2 to be used in the permutation checks - if (logger) logger.info("> computing k1 and k2"); - const [k1, k2] = computeK1K2(); - - // Compute omega 3 (w3) and omega 4 (w4) to be used in the prover and the verifier - // w3^3 = 1 and w4^4 = 1 - if (logger) logger.info("> computing w3"); - const w3 = computeW3(); - if (logger) logger.info("> computing w4"); - const w4 = computeW4(); - if (logger) logger.info("> computing w8"); - const w8 = computeW8(); - if (logger) logger.info("> computing wr"); - const wr = getOmegaCubicRoot(settings.cirPower, curve.Fr); - - // Write output zkey file - await writeZkeyFile(); - - await fdR1cs.close(); - await fdPTau.close(); - - if (logger) logger.info("FFLONK SETUP FINISHED"); - - return 0; - - async function computeFFConstraints(Fr, r1cs, logger) { - // Add public inputs and outputs - for (let i = 0; i < settings.nPublic; i++) { - plonkConstraints.push(getFFlonkConstantConstraint(i + 1, Fr)); - } - - // Add all constraints from r1cs file - const r1csProcessor = new r1csConstraintProcessor(Fr, getFFlonkConstantConstraint, getFFlonkAdditionConstraint, getFFlonkMultiplicationConstraint, logger); - - const bR1cs = await binFileUtils__namespace.readSection(fdR1cs, sectionsR1cs, 2); - let bR1csPos = 0; - for (let i = 0; i < r1cs.nConstraints; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` processing r1cs constraints ${i}/${r1cs.nConstraints}`); - } - const [constraints, additions] = r1csProcessor.processR1csConstraint(settings, ...readConstraint()); - - plonkConstraints.push(...constraints); - plonkAdditions.push(...additions); - } - - function readConstraint() { - const c = []; - c[0] = readLC(); - c[1] = readLC(); - c[2] = readLC(); - return c; - } - - function readLC() { - const lc = {}; - - const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); - bR1csPos += 4; - const buffUL32V = new DataView(buffUL32.buffer); - const nIdx = buffUL32V.getUint32(0, true); - - const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); - bR1csPos += (4 + r1cs.n8) * nIdx; - const buffV = new DataView(buff.buffer); - for (let i = 0; i < nIdx; i++) { - const idx = buffV.getUint32(i * (4 + r1cs.n8), true); - const val = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); - lc[idx] = val; - } - return lc; - } - - return 0; - } - - async function writeZkeyFile() { - if (logger) logger.info("> Writing the zkey file"); - const fdZKey = await binFileUtils.createBinFile(zkeyFilename, "zkey", 1, ZKEY_FF_NSECTIONS, 1 << 22, 1 << 24); - - if (logger) logger.info(`··· Writing Section ${HEADER_ZKEY_SECTION}. Zkey Header`); - await writeZkeyHeader(fdZKey); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_ADDITIONS_SECTION}. Additions`); - await writeAdditions(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_A_MAP_SECTION}. A Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_A_MAP_SECTION, 0, "A map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_B_MAP_SECTION}. B Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_B_MAP_SECTION, 1, "B map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_C_MAP_SECTION}. C Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_C_MAP_SECTION, 2, "C map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QL_SECTION}. QL`); - await writeQMap(fdZKey, ZKEY_FF_QL_SECTION, 3, "QL"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QR_SECTION}. QR`); - await writeQMap(fdZKey, ZKEY_FF_QR_SECTION, 4, "QR"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QM_SECTION}. QM`); - await writeQMap(fdZKey, ZKEY_FF_QM_SECTION, 5, "QM"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QO_SECTION}. QO`); - await writeQMap(fdZKey, ZKEY_FF_QO_SECTION, 6, "QO"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QC_SECTION}. QC`); - await writeQMap(fdZKey, ZKEY_FF_QC_SECTION, 7, "QC"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Sections ${ZKEY_FF_SIGMA1_SECTION},${ZKEY_FF_SIGMA2_SECTION},${ZKEY_FF_SIGMA3_SECTION}. Sigma1, Sigma2 & Sigma 3`); - await writeSigma(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_LAGRANGE_SECTION}. Lagrange Polynomials`); - await writeLagrangePolynomials(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_PTAU_SECTION}. Powers of Tau`); - await writePtau(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_C0_SECTION}. C0`); - await writeC0(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_HEADER_SECTION}. FFlonk Header`); - await writeFFlonkHeader(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info("> Writing the zkey file finished"); - - await fdZKey.close(); - } - - async function writeZkeyHeader(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, HEADER_ZKEY_SECTION); - await fdZKey.writeULE32(FFLONK_PROTOCOL_ID); - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeAdditions(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_ADDITIONS_SECTION); - - // Written values are 2 * 32 bit integers (2 * 4 bytes) + 2 field size values ( 2 * sFr bytes) - const buffOut = new Uint8Array(8 + 2 * sFr); - const buffOutV = new DataView(buffOut.buffer); - - for (let i = 0; i < plonkAdditions.length; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) logger.info(` writing Additions: ${i}/${plonkAdditions.length}`); - - const addition = plonkAdditions[i]; - - buffOutV.setUint32(0, addition[0], true); - buffOutV.setUint32(4, addition[1], true); - buffOut.set(addition[2], 8); - buffOut.set(addition[3], 8 + sFr); - - await fdZKey.write(buffOut); - } - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeWitnessMap(fdZKey, sectionNum, posConstraint, name) { - await binFileUtils.startWriteSection(fdZKey, sectionNum); - for (let i = 0; i < plonkConstraints.length; i++) { - if (logger && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing witness ${name}: ${i}/${plonkConstraints.length}`); - } - - await fdZKey.writeULE32(plonkConstraints[i][posConstraint]); - } - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeQMap(fdZKey, sectionNum, posConstraint, name) { - // Compute Q from q evaluations - let Q = new ffjavascript.BigBuffer(settings.domainSize * sFr); - - for (let i = 0; i < plonkConstraints.length; i++) { - Q.set(plonkConstraints[i][posConstraint], i * sFr); - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing ${name}: ${i}/${plonkConstraints.length}`); - } - } - - polynomials[name] = await Polynomial.fromEvaluations(Q, curve, logger); - evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); - - // Write Q coefficients and evaluations - await binFileUtils.startWriteSection(fdZKey, sectionNum); - await fdZKey.write(polynomials[name].coef); - await fdZKey.write(evaluations[name].eval); - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeSigma(fdZKey) { - // Compute sigma - const sigma = new ffjavascript.BigBuffer(sFr * settings.domainSize * 3); - const lastSeen = new BigArray(settings.nVars); - const firstPos = new BigArray(settings.nVars); - - let w = Fr.one; - for (let i = 0; i < settings.domainSize; i++) { - if (i < plonkConstraints.length) { - buildSigma(plonkConstraints[i][0], i); - buildSigma(plonkConstraints[i][1], settings.domainSize + i); - buildSigma(plonkConstraints[i][2], settings.domainSize * 2 + i); - } else if (i < settings.domainSize - 2) { - buildSigma(0, i); - buildSigma(0, settings.domainSize + i); - buildSigma(0, settings.domainSize * 2 + i); - } else { - sigma.set(w, i * sFr); - sigma.set(Fr.mul(w, k1), (settings.domainSize + i) * sFr); - sigma.set(Fr.mul(w, k2), (settings.domainSize * 2 + i) * sFr); - } - - w = Fr.mul(w, Fr.w[settings.cirPower]); - - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing sigma phase1: ${i}/${plonkConstraints.length}`); - } - } - - for (let i = 0; i < settings.nVars; i++) { - if (typeof firstPos[i] !== "undefined") { - sigma.set(lastSeen[i], firstPos[i] * sFr); - } else { - // throw new Error("Variable not used"); - console.log("Variable not used"); - } - if ((logger) && (i !== 0) && (i % 500000 === 0)) logger.info(` writing sigma phase2: ${i}/${settings.nVars}`); - } - - if (globalThis.gc) globalThis.gc(); - - // Write sigma coefficients and evaluations - for (let i = 0; i < 3; i++) { - const sectionId = 0 === i ? ZKEY_FF_SIGMA1_SECTION : 1 === i ? ZKEY_FF_SIGMA2_SECTION : ZKEY_FF_SIGMA3_SECTION; - - let name = "S" + (i + 1); - polynomials[name] = await Polynomial.fromEvaluations(sigma.slice(settings.domainSize * sFr * i, settings.domainSize * sFr * (i + 1)), curve, logger); - evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); - await binFileUtils.startWriteSection(fdZKey, sectionId); - await fdZKey.write(polynomials[name].coef); - await fdZKey.write(evaluations[name].eval); - await binFileUtils.endWriteSection(fdZKey); - - if (globalThis.gc) globalThis.gc(); - } - - return 0; - - function buildSigma(signalId, idx) { - if (typeof lastSeen[signalId] === "undefined") { - firstPos[signalId] = idx; - } else { - sigma.set(lastSeen[signalId], idx * sFr); - } - let v; - if (idx < settings.domainSize) { - v = w; - } else if (idx < 2 * settings.domainSize) { - v = Fr.mul(w, k1); - } else { - v = Fr.mul(w, k2); - } - - lastSeen[signalId] = v; - } - } - - async function writeLagrangePolynomials(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_LAGRANGE_SECTION); - - const l = Math.max(settings.nPublic, 1); - for (let i = 0; i < l; i++) { - let buff = new ffjavascript.BigBuffer(settings.domainSize * sFr); - buff.set(Fr.one, i * sFr); - - await writeP4(fdZKey, buff); - } - await binFileUtils.endWriteSection(fdZKey); - } - - async function writePtau(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_PTAU_SECTION); - - // domainSize * 9 + 18 = maximum SRS length needed, specifically to commit C2 - PTau = new ffjavascript.BigBuffer((settings.domainSize * 9 + 18) * sG1); - await fdPTau.readToBuffer(PTau, 0, (settings.domainSize * 9 + 18) * sG1, pTauSections[2][0].p); - - await fdZKey.write(PTau); - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeC0(fdZKey) { - // C0(X) := QL(X^8) + X · QR(X^8) + X^2 · QO(X^8) + X^3 · QM(X^8) + X^4 · QC(X^8) - // + X^5 · SIGMA1(X^8) + X^6 · SIGMA2(X^8) + X^7 · SIGMA3(X^8) - let C0 = new CPolynomial(8, curve, logger); - C0.addPolynomial(0, polynomials.QL); - C0.addPolynomial(1, polynomials.QR); - C0.addPolynomial(2, polynomials.QO); - C0.addPolynomial(3, polynomials.QM); - C0.addPolynomial(4, polynomials.QC); - C0.addPolynomial(5, polynomials.S1); - C0.addPolynomial(6, polynomials.S2); - C0.addPolynomial(7, polynomials.S3); - - polynomials.C0 = C0.getPolynomial(); - - // Check degree - if (polynomials.C0.degree() >= 8 * settings.domainSize) { - throw new Error("C0 Polynomial is not well calculated"); - } - - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_C0_SECTION); - await fdZKey.write(polynomials.C0.coef); - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeFFlonkHeader(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_HEADER_SECTION); - - const primeQ = curve.q; - const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; - await fdZKey.writeULE32(n8q); - await binFileUtils.writeBigInt(fdZKey, primeQ, n8q); - - const primeR = curve.r; - const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; - await fdZKey.writeULE32(n8r); - await binFileUtils.writeBigInt(fdZKey, primeR, n8r); - - // Total number of r1cs vars - await fdZKey.writeULE32(settings.nVars); - // Total number of r1cs public vars = outputs + public inputs - await fdZKey.writeULE32(settings.nPublic); - await fdZKey.writeULE32(settings.domainSize); - await fdZKey.writeULE32(plonkAdditions.length); - await fdZKey.writeULE32(plonkConstraints.length); - - await fdZKey.write(k1); - await fdZKey.write(k2); - - await fdZKey.write(w3); - await fdZKey.write(w4); - await fdZKey.write(w8); - await fdZKey.write(wr); - - let bX_2; - bX_2 = await fdPTau.read(sG2, pTauSections[3][0].p + sG2); - await fdZKey.write(bX_2); - - let commitC0 = await polynomials.C0.multiExponentiation(PTau, "C0"); - await fdZKey.write(commitC0); - - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeP4(fdZKey, buff) { - const [coefficients, evaluations4] = await Polynomial.to4T(buff, settings.domainSize, [], Fr); - await fdZKey.write(coefficients); - await fdZKey.write(evaluations4); - - return [coefficients, evaluations4]; - } - - function computeK1K2() { - let k1 = Fr.two; - while (isIncluded(k1, [], settings.cirPower)) Fr.add(k1, Fr.one); - let k2 = Fr.add(k1, Fr.one); - while (isIncluded(k2, [k1], settings.cirPower)) Fr.add(k2, Fr.one); - return [k1, k2]; - - function isIncluded(k, kArr, pow) { - const domainSize = 2 ** pow; - let w = Fr.one; - for (let i = 0; i < domainSize; i++) { - if (Fr.eq(k, w)) return true; - for (let j = 0; j < kArr.length; j++) { - if (Fr.eq(k, Fr.mul(kArr[j], w))) return true; - } - w = Fr.mul(w, Fr.w[pow]); - } - return false; - } - } - - function computeW3() { - let generator = Fr.e(31624); - - // Exponent is order(r - 1) / 3 - let orderRsub1 = 3648040478639879203707734290876212514758060733402672390616367364429301415936n; - let exponent = ffjavascript.Scalar.div(orderRsub1, ffjavascript.Scalar.e(3)); - - return Fr.exp(generator, exponent); - } - - function computeW4() { - return Fr.w[2]; - } - - function computeW8() { - return Fr.w[3]; - } - - function getOmegaCubicRoot(power, Fr) { - // Hardcorded 3th-root of Fr.w[28] - const firstRoot = Fr.e(467799165886069610036046866799264026481344299079011762026774533774345988080n); - - return Fr.exp(firstRoot, 2 ** (28 - power)); - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const { stringifyBigInts: stringifyBigInts$1 } = ffjavascript.utils; - - + if (logger) logger.info("FFLONK SETUP STARTED"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> Reading PTau file"); + const { fd: fdPTau, sections: pTauSections } = await (0, _iden3_binfileutils.readBinFile)(ptauFilename, "ptau", 1, 1 << 22, 1 << 24); + if (!pTauSections[12]) throw new Error("Powers of Tau is not well prepared. Section 12 missing."); + if (logger) logger.info("> Getting curve from PTau settings"); + const { curve } = await readPTauHeader(fdPTau, pTauSections); + if (logger) logger.info("> Reading r1cs file"); + const { fd: fdR1cs, sections: sectionsR1cs } = await (0, _iden3_binfileutils.readBinFile)(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); + const r1cs = await (0, r1csfile.readR1csFd)(fdR1cs, sectionsR1cs, { + loadConstraints: false, + loadCustomGates: true + }); + if (r1cs.prime !== curve.r) throw new Error("r1cs curve does not match powers of tau ceremony curve"); + const Fr = curve.Fr; + const sFr = curve.Fr.n8; + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + let polynomials = {}; + let evaluations = {}; + let PTau; + let settings = { + nVars: r1cs.nVars, + nPublic: r1cs.nOutputs + r1cs.nPubInputs + }; + const plonkConstraints = new BigArray(); + let plonkAdditions = new BigArray(); + if (logger) logger.info("> Processing FFlonk constraints"); + await computeFFConstraints(curve.Fr, r1cs, logger); + if (globalThis.gc) globalThis.gc(); + settings.cirPower = Math.max(3, log2(plonkConstraints.length + 2 - 1) + 1); + settings.domainSize = 2 ** settings.cirPower; + if (pTauSections[2][0].size < (settings.domainSize * 9 + 18) * sG1) throw new Error("Powers of Tau is not big enough for this circuit size. Section 2 too small."); + if (pTauSections[3][0].size < sG2) throw new Error("Powers of Tau is not well prepared. Section 3 too small."); + if (logger) { + logger.info("----------------------------"); + logger.info(" FFLONK SETUP SETTINGS"); + logger.info(` Curve: ${curve.name}`); + logger.info(` Circuit power: ${settings.cirPower}`); + logger.info(` Domain size: ${settings.domainSize}`); + logger.info(` Vars: ${settings.nVars}`); + logger.info(` Public vars: ${settings.nPublic}`); + logger.info(` Constraints: ${plonkConstraints.length}`); + logger.info(` Additions: ${plonkAdditions.length}`); + logger.info("----------------------------"); + } + if (logger) logger.info("> computing k1 and k2"); + const [k1, k2] = computeK1K2(); + if (logger) logger.info("> computing w3"); + const w3 = computeW3(); + if (logger) logger.info("> computing w4"); + const w4 = computeW4(); + if (logger) logger.info("> computing w8"); + const w8 = computeW8(); + if (logger) logger.info("> computing wr"); + const wr = getOmegaCubicRoot(settings.cirPower, curve.Fr); + await writeZkeyFile(); + await fdR1cs.close(); + await fdPTau.close(); + if (logger) logger.info("FFLONK SETUP FINISHED"); + return 0; + async function computeFFConstraints(Fr, r1cs, logger) { + for (let i = 0; i < settings.nPublic; i++) plonkConstraints.push(getFFlonkConstantConstraint(i + 1, Fr)); + const r1csProcessor = new r1csConstraintProcessor(Fr, getFFlonkConstantConstraint, getFFlonkAdditionConstraint, getFFlonkMultiplicationConstraint, logger); + const bR1cs = await _iden3_binfileutils.readSection(fdR1cs, sectionsR1cs, 2); + let bR1csPos = 0; + for (let i = 0; i < r1cs.nConstraints; i++) { + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` processing r1cs constraints ${i}/${r1cs.nConstraints}`); + const [constraints, additions] = r1csProcessor.processR1csConstraint(settings, ...readConstraint()); + plonkConstraints.push(...constraints); + plonkAdditions.push(...additions); + } + function readConstraint() { + const c = []; + c[0] = readLC(); + c[1] = readLC(); + c[2] = readLC(); + return c; + } + function readLC() { + const lc = {}; + const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); + bR1csPos += 4; + const nIdx = new DataView(buffUL32.buffer).getUint32(0, true); + const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); + bR1csPos += (4 + r1cs.n8) * nIdx; + const buffV = new DataView(buff.buffer); + for (let i = 0; i < nIdx; i++) { + const idx = buffV.getUint32(i * (4 + r1cs.n8), true); + lc[idx] = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); + } + return lc; + } + return 0; + } + async function writeZkeyFile() { + if (logger) logger.info("> Writing the zkey file"); + const fdZKey = await (0, _iden3_binfileutils.createBinFile)(zkeyFilename, "zkey", 1, 17, 1 << 22, 1 << 24); + if (logger) logger.info(`··· Writing Section 1. Zkey Header`); + await writeZkeyHeader(fdZKey); + if (logger) logger.info(`··· Writing Section 3. Additions`); + await writeAdditions(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 4. A Map`); + await writeWitnessMap(fdZKey, 4, 0, "A map"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 5. B Map`); + await writeWitnessMap(fdZKey, 5, 1, "B map"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 6. C Map`); + await writeWitnessMap(fdZKey, 6, 2, "C map"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 7. QL`); + await writeQMap(fdZKey, 7, 3, "QL"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 8. QR`); + await writeQMap(fdZKey, 8, 4, "QR"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 9. QM`); + await writeQMap(fdZKey, 9, 5, "QM"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 10. QO`); + await writeQMap(fdZKey, 10, 6, "QO"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 11. QC`); + await writeQMap(fdZKey, 11, 7, "QC"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Sections 12,13,14. Sigma1, Sigma2 & Sigma 3`); + await writeSigma(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 15. Lagrange Polynomials`); + await writeLagrangePolynomials(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 16. Powers of Tau`); + await writePtau(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 17. C0`); + await writeC0(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 2. FFlonk Header`); + await writeFFlonkHeader(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> Writing the zkey file finished"); + await fdZKey.close(); + } + async function writeZkeyHeader(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 1); + await fdZKey.writeULE32(10); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeAdditions(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 3); + const buffOut = new Uint8Array(8 + 2 * sFr); + const buffOutV = new DataView(buffOut.buffer); + for (let i = 0; i < plonkAdditions.length; i++) { + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing Additions: ${i}/${plonkAdditions.length}`); + const addition = plonkAdditions[i]; + buffOutV.setUint32(0, addition[0], true); + buffOutV.setUint32(4, addition[1], true); + buffOut.set(addition[2], 8); + buffOut.set(addition[3], 8 + sFr); + await fdZKey.write(buffOut); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeWitnessMap(fdZKey, sectionNum, posConstraint, name) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + for (let i = 0; i < plonkConstraints.length; i++) { + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing witness ${name}: ${i}/${plonkConstraints.length}`); + await fdZKey.writeULE32(plonkConstraints[i][posConstraint]); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeQMap(fdZKey, sectionNum, posConstraint, name) { + let Q = new ffjavascript.BigBuffer(settings.domainSize * sFr); + for (let i = 0; i < plonkConstraints.length; i++) { + Q.set(plonkConstraints[i][posConstraint], i * sFr); + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing ${name}: ${i}/${plonkConstraints.length}`); + } + polynomials[name] = await Polynomial.fromEvaluations(Q, curve, logger); + evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + await fdZKey.write(polynomials[name].coef); + await fdZKey.write(evaluations[name].eval); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeSigma(fdZKey) { + const sigma = new ffjavascript.BigBuffer(sFr * settings.domainSize * 3); + const lastSeen = new BigArray(settings.nVars); + const firstPos = new BigArray(settings.nVars); + let w = Fr.one; + for (let i = 0; i < settings.domainSize; i++) { + if (i < plonkConstraints.length) { + buildSigma(plonkConstraints[i][0], i); + buildSigma(plonkConstraints[i][1], settings.domainSize + i); + buildSigma(plonkConstraints[i][2], settings.domainSize * 2 + i); + } else if (i < settings.domainSize - 2) { + buildSigma(0, i); + buildSigma(0, settings.domainSize + i); + buildSigma(0, settings.domainSize * 2 + i); + } else { + sigma.set(w, i * sFr); + sigma.set(Fr.mul(w, k1), (settings.domainSize + i) * sFr); + sigma.set(Fr.mul(w, k2), (settings.domainSize * 2 + i) * sFr); + } + w = Fr.mul(w, Fr.w[settings.cirPower]); + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing sigma phase1: ${i}/${plonkConstraints.length}`); + } + for (let i = 0; i < settings.nVars; i++) { + if (typeof firstPos[i] !== "undefined") sigma.set(lastSeen[i], firstPos[i] * sFr); + else console.log("Variable not used"); + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing sigma phase2: ${i}/${settings.nVars}`); + } + if (globalThis.gc) globalThis.gc(); + for (let i = 0; i < 3; i++) { + const sectionId = 0 === i ? 12 : 1 === i ? 13 : 14; + let name = "S" + (i + 1); + polynomials[name] = await Polynomial.fromEvaluations(sigma.slice(settings.domainSize * sFr * i, settings.domainSize * sFr * (i + 1)), curve, logger); + evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionId); + await fdZKey.write(polynomials[name].coef); + await fdZKey.write(evaluations[name].eval); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + if (globalThis.gc) globalThis.gc(); + } + return 0; + function buildSigma(signalId, idx) { + if (typeof lastSeen[signalId] === "undefined") firstPos[signalId] = idx; + else sigma.set(lastSeen[signalId], idx * sFr); + let v; + if (idx < settings.domainSize) v = w; + else if (idx < 2 * settings.domainSize) v = Fr.mul(w, k1); + else v = Fr.mul(w, k2); + lastSeen[signalId] = v; + } + } + async function writeLagrangePolynomials(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 15); + const l = Math.max(settings.nPublic, 1); + for (let i = 0; i < l; i++) { + let buff = new ffjavascript.BigBuffer(settings.domainSize * sFr); + buff.set(Fr.one, i * sFr); + await writeP4(fdZKey, buff); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writePtau(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 16); + PTau = new ffjavascript.BigBuffer((settings.domainSize * 9 + 18) * sG1); + await fdPTau.readToBuffer(PTau, 0, (settings.domainSize * 9 + 18) * sG1, pTauSections[2][0].p); + await fdZKey.write(PTau); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeC0(fdZKey) { + let C0 = new CPolynomial(8, curve, logger); + C0.addPolynomial(0, polynomials.QL); + C0.addPolynomial(1, polynomials.QR); + C0.addPolynomial(2, polynomials.QO); + C0.addPolynomial(3, polynomials.QM); + C0.addPolynomial(4, polynomials.QC); + C0.addPolynomial(5, polynomials.S1); + C0.addPolynomial(6, polynomials.S2); + C0.addPolynomial(7, polynomials.S3); + polynomials.C0 = C0.getPolynomial(); + if (polynomials.C0.degree() >= 8 * settings.domainSize) throw new Error("C0 Polynomial is not well calculated"); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 17); + await fdZKey.write(polynomials.C0.coef); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeFFlonkHeader(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 2); + const primeQ = curve.q; + const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; + await fdZKey.writeULE32(n8q); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeQ, n8q); + const primeR = curve.r; + const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; + await fdZKey.writeULE32(n8r); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeR, n8r); + await fdZKey.writeULE32(settings.nVars); + await fdZKey.writeULE32(settings.nPublic); + await fdZKey.writeULE32(settings.domainSize); + await fdZKey.writeULE32(plonkAdditions.length); + await fdZKey.writeULE32(plonkConstraints.length); + await fdZKey.write(k1); + await fdZKey.write(k2); + await fdZKey.write(w3); + await fdZKey.write(w4); + await fdZKey.write(w8); + await fdZKey.write(wr); + let bX_2; + bX_2 = await fdPTau.read(sG2, pTauSections[3][0].p + sG2); + await fdZKey.write(bX_2); + let commitC0 = await polynomials.C0.multiExponentiation(PTau, "C0"); + await fdZKey.write(commitC0); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeP4(fdZKey, buff) { + const [coefficients, evaluations4] = await Polynomial.to4T(buff, settings.domainSize, [], Fr); + await fdZKey.write(coefficients); + await fdZKey.write(evaluations4); + return [coefficients, evaluations4]; + } + function computeK1K2() { + let k1 = Fr.two; + while (isIncluded(k1, [], settings.cirPower)) Fr.add(k1, Fr.one); + let k2 = Fr.add(k1, Fr.one); + while (isIncluded(k2, [k1], settings.cirPower)) Fr.add(k2, Fr.one); + return [k1, k2]; + function isIncluded(k, kArr, pow) { + const domainSize = 2 ** pow; + let w = Fr.one; + for (let i = 0; i < domainSize; i++) { + if (Fr.eq(k, w)) return true; + for (let j = 0; j < kArr.length; j++) if (Fr.eq(k, Fr.mul(kArr[j], w))) return true; + w = Fr.mul(w, Fr.w[pow]); + } + return false; + } + } + function computeW3() { + let generator = Fr.e(31624); + let exponent = ffjavascript.Scalar.div(3648040478639879203707734290876212514758060733402672390616367364429301415936n, ffjavascript.Scalar.e(3)); + return Fr.exp(generator, exponent); + } + function computeW4() { + return Fr.w[2]; + } + function computeW8() { + return Fr.w[3]; + } + function getOmegaCubicRoot(power, Fr) { + const firstRoot = Fr.e(467799165886069610036046866799264026481344299079011762026774533774345988080n); + return Fr.exp(firstRoot, 2 ** (28 - power)); + } +} +//#endregion +//#region src/fflonk_prove.js +var { stringifyBigInts: stringifyBigInts$1 } = ffjavascript.utils; async function fflonkProve$1(zkeyFileName, witnessFileName, logger, options) { - if (logger) logger.info("FFLONK PROVER STARTED"); - - // Read witness file - if (logger) logger.info("> Reading witness file"); - const { - fd: fdWtns, - sections: wtnsSections - } = await binFileUtils__namespace.readBinFile(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); - const wtns = await readHeader(fdWtns, wtnsSections); - - //Read zkey file - if (logger) logger.info("> Reading zkey file"); - const { - fd: fdZKey, - sections: zkeySections - } = await binFileUtils__namespace.readBinFile(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); - - const zkey = await readHeader$1(fdZKey, zkeySections, undefined, options); - - if (zkey.protocolId !== FFLONK_PROTOCOL_ID) { - throw new Error("zkey file is not fflonk"); - } - - if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness !== zkey.nVars - zkey.nAdditions) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); - } - - const curve = zkey.curve; - - const Fr = curve.Fr; - - const sFr = curve.Fr.n8; - const sG1 = curve.G1.F.n8 * 2; - const sDomain = zkey.domainSize * sFr; - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK PROVE SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${zkey.power}`); - logger.info(` Domain size: ${zkey.domainSize}`); - logger.info(` Vars: ${zkey.nVars}`); - logger.info(` Public vars: ${zkey.nPublic}`); - logger.info(` Constraints: ${zkey.nConstraints}`); - logger.info(` Additions: ${zkey.nAdditions}`); - logger.info("----------------------------"); - } - - //Read witness data - if (logger) logger.info("> Reading witness file data"); - const buffWitness = await binFileUtils__namespace.readSection(fdWtns, wtnsSections, 2); - await fdWtns.close(); - - // First element in plonk is not used and can be any value. (But always the same). - // We set it to zero to go faster in the exponentiations. - buffWitness.set(Fr.zero, 0); - const buffInternalWitness = new ffjavascript.BigBuffer(zkey.nAdditions * sFr); - - let buffers = {}; - let polynomials = {}; - let evaluations = {}; - - // To divide prime fields the Extended Euclidean Algorithm for computing modular inverses is needed. - // NOTE: This is the equivalent of compute 1/denominator and then multiply it by the numerator. - // The Extended Euclidean Algorithm is expensive in terms of computation. - // For the special case where we need to do many modular inverses, there's a simple mathematical trick - // that allows us to compute many inverses, called Montgomery batch inversion. - // More info: https://vitalik.ca/general/2018/07/21/starks_part_3.html - // Montgomery batch inversion reduces the n inverse computations to a single one - // To save this (single) inverse computation on-chain, will compute it in proving time and send it to the verifier. - // The verifier will have to check: - // 1) the denominator is correct multiplying by himself non-inverted -> a * 1/a == 1 - // 2) compute the rest of the denominators using the Montgomery batch inversion - // The inversions are: - // · denominator needed in step 8 and 9 of the verifier to multiply by 1/Z_H(xi) - // · denominator needed in step 10 and 11 of the verifier - // · denominator needed in the verifier when computing L_i^{S1}(X) and L_i^{S2}(X) - // · L_i i=1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) - let toInverse = {}; - - let challenges = {}; - let roots = {}; - - let proof = new Proof(curve, logger); - - if (logger) logger.info(`> Reading Section ${ZKEY_FF_ADDITIONS_SECTION}. Additions`); - await calculateAdditions(); - - if (logger) logger.info(`> Reading Sections ${ZKEY_FF_SIGMA1_SECTION},${ZKEY_FF_SIGMA2_SECTION},${ZKEY_FF_SIGMA3_SECTION}. Sigma1, Sigma2 & Sigma 3`); - if (logger) logger.info("··· Reading Sigma polynomials "); - polynomials.Sigma1 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.Sigma2 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.Sigma3 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - - await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA1_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA2_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA3_SECTION][0].p); - - if (logger) logger.info("··· Reading Sigma evaluations"); - evaluations.Sigma1 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma2 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma3 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - - await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA1_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA2_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA3_SECTION][0].p + sDomain); - - if (logger) logger.info(`> Reading Section ${ZKEY_FF_PTAU_SECTION}. Powers of Tau`); - const PTau = new ffjavascript.BigBuffer(zkey.domainSize * 16 * sG1); - // domainSize * 9 + 18 = SRS length in the zkey saved in setup process. - // it corresponds to the maximum SRS length needed, specifically to commit C2 - // notice that the reserved buffers size is zkey.domainSize * 16 * sG1 because a power of two buffer size is needed - // the remaining buffer not filled from SRS are set to 0 - await fdZKey.readToBuffer(PTau, 0, (zkey.domainSize * 9 + 18) * sG1, zkeySections[ZKEY_FF_PTAU_SECTION][0].p); - - // START FFLONK PROVER PROTOCOL - if (globalThis.gc) globalThis.gc(); - - // ROUND 1. Compute C1(X) polynomial - if (logger) logger.info(""); - if (logger) logger.info("> ROUND 1"); - await round1(); - - delete polynomials.T0; - delete evaluations.QL; - delete evaluations.QR; - delete evaluations.QM; - delete evaluations.QO; - delete evaluations.QC; - if (globalThis.gc) globalThis.gc(); - - // ROUND 2. Compute C2(X) polynomial - if (logger) logger.info("> ROUND 2"); - await round2(); - - delete buffers.A; - delete buffers.B; - delete buffers.C; - delete evaluations.A; - delete evaluations.B; - delete evaluations.C; - delete evaluations.Sigma1; - delete evaluations.Sigma2; - delete evaluations.Sigma3; - delete evaluations.lagrange1; - delete evaluations.Z; - if (globalThis.gc) globalThis.gc(); - - // ROUND 3. Compute opening evaluations - if (logger) logger.info("> ROUND 3"); - await round3(); - - delete polynomials.A; - delete polynomials.B; - delete polynomials.C; - delete polynomials.Z; - delete polynomials.T1; - delete polynomials.T2; - delete polynomials.Sigma1; - delete polynomials.Sigma2; - delete polynomials.Sigma3; - delete polynomials.QL; - delete polynomials.QR; - delete polynomials.QM; - delete polynomials.QC; - delete polynomials.QO; - if (globalThis.gc) globalThis.gc(); - - // ROUND 4. Compute W(X) polynomial - if (logger) logger.info("> ROUND 4"); - await round4(); - if (globalThis.gc) globalThis.gc(); - - // ROUND 5. Compute W'(X) polynomial - if (logger) logger.info("> ROUND 5"); - await round5(); - - delete polynomials.C0; - delete polynomials.C1; - delete polynomials.C2; - delete polynomials.R1; - delete polynomials.R2; - delete polynomials.F; - delete polynomials.L; - delete polynomials.ZT; - delete polynomials.ZTS2; - await fdZKey.close(); - if (globalThis.gc) globalThis.gc(); - - proof.addEvaluation("inv", getMontgomeryBatchedInverse()); - - // Prepare proof - let _proof = proof.toObjectProof(); - _proof.protocol = "fflonk"; - _proof.curve = curve.name; - - // Prepare public inputs - let publicSignals = []; - - for (let i = 1; i <= zkey.nPublic; i++) { - const i_sFr = i * sFr; - - const pub = buffWitness.slice(i_sFr, i_sFr + sFr); - publicSignals.push(ffjavascript.Scalar.fromRprLE(pub)); - } - - if (logger) logger.info("FFLONK PROVER FINISHED"); - - return { - proof: stringifyBigInts$1(_proof), - publicSignals: stringifyBigInts$1(publicSignals) - }; - - async function calculateAdditions() { - if (logger) logger.info("··· Computing additions"); - const additionsBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_ADDITIONS_SECTION); - - // sizes: wireId_x = 4 bytes (32 bits), factor_x = field size bits - // Addition form: wireId_a wireId_b factor_a factor_b (size is 4 + 4 + sFr + sFr) - const sSum = 8 + sFr * 2; - - for (let i = 0; i < zkey.nAdditions; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` addition ${i}/${zkey.nAdditions}`); - - // Read addition values - let offset = i * sSum; - const signalId1 = readUInt32(additionsBuff, offset); - offset += 4; - const signalId2 = readUInt32(additionsBuff, offset); - offset += 4; - const factor1 = additionsBuff.slice(offset, offset + sFr); - offset += sFr; - const factor2 = additionsBuff.slice(offset, offset + sFr); - - // Get witness value - const witness1 = getWitness(signalId1); - const witness2 = getWitness(signalId2); - - //Calculate final result - const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); - - buffInternalWitness.set(result, sFr * i); - } - } - - function readUInt32(b, o) { - const buff = b.slice(o, o + 4); - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - return buffV.getUint32(0, true); - } - - function getWitness(idx) { - let diff = zkey.nVars - zkey.nAdditions; - if (idx < diff) { - return buffWitness.slice(idx * sFr, idx * sFr + sFr); - } else if (idx < zkey.nVars) { - const offset = (idx - diff) * sFr; - return buffInternalWitness.slice(offset, offset + sFr); - } - - return Fr.zero; - } - - async function round1() { - // STEP 1.1 - Generate random blinding scalars (b_1, ..., b9) ∈ F - challenges.b = []; - for (let i = 1; i <= 9; i++) { - challenges.b[i] = Fr.random(); - } - - // STEP 1.2 - Compute wire polynomials a(X), b(X) and c(X) - if (logger) logger.info("> Computing A, B, C wire polynomials"); - await computeWirePolynomials(); - - // STEP 1.3 - Compute the quotient polynomial T0(X) - if (logger) logger.info("> Computing T0 polynomial"); - await computeT0(); - - // STEP 1.4 - Compute the FFT-style combination polynomial C1(X) - if (logger) logger.info("> Computing C1 polynomial"); - await computeC1(); - - // The first output of the prover is ([C1]_1) - if (logger) logger.info("> Computing C1 multi exponentiation"); - let commitC1 = await polynomials.C1.multiExponentiation(PTau, "C1"); - proof.addPolynomial("C1", commitC1); - - return 0; - - async function computeWirePolynomials() { - if (logger) logger.info("··· Reading data from zkey file"); - // Build A, B and C evaluations buffer from zkey and witness files - buffers.A = new ffjavascript.BigBuffer(sDomain); - buffers.B = new ffjavascript.BigBuffer(sDomain); - buffers.C = new ffjavascript.BigBuffer(sDomain); - - // Read zkey sections and fill the buffers - const aMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_A_MAP_SECTION); - const bMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_B_MAP_SECTION); - const cMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_C_MAP_SECTION); - - // Compute all witness from signal ids and set them to A,B & C buffers - for (let i = 0; i < zkey.nConstraints; i++) { - const i_sFr = i * sFr; - const offset = i * 4; - - // Compute A value from a signal id - const signalIdA = readUInt32(aMapBuff, offset); - buffers.A.set(getWitness(signalIdA), i_sFr); - - // Compute B value from a signal id - const signalIdB = readUInt32(bMapBuff, offset); - buffers.B.set(getWitness(signalIdB), i_sFr); - - // Compute C value from a signal id - const signalIdC = readUInt32(cMapBuff, offset); - buffers.C.set(getWitness(signalIdC), i_sFr); - } - - // Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b - buffers.A.set(challenges.b[1], sDomain - 64); - buffers.A.set(challenges.b[2], sDomain - 32); - buffers.B.set(challenges.b[3], sDomain - 64); - buffers.B.set(challenges.b[4], sDomain - 32); - buffers.C.set(challenges.b[5], sDomain - 64); - buffers.C.set(challenges.b[6], sDomain - 32); - - buffers.A = await Fr.batchToMontgomery(buffers.A); - buffers.B = await Fr.batchToMontgomery(buffers.B); - buffers.C = await Fr.batchToMontgomery(buffers.C); - - // Compute the coefficients of the wire polynomials a(X), b(X) and c(X) from A,B & C buffers - if (logger) logger.info("··· Computing A ifft"); - polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); - if (logger) logger.info("··· Computing B ifft"); - polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); - if (logger) logger.info("··· Computing C ifft"); - polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); - - // Compute extended evaluations of a(X), b(X) and c(X) polynomials - if (logger) logger.info("··· Computing A fft"); - evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); - if (logger) logger.info("··· Computing B fft"); - evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); - if (logger) logger.info("··· Computing C fft"); - evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); - - // Check degrees - if (polynomials.A.degree() >= zkey.domainSize) { - throw new Error("A Polynomial is not well calculated"); - } - if (polynomials.B.degree() >= zkey.domainSize) { - throw new Error("B Polynomial is not well calculated"); - } - if (polynomials.C.degree() >= zkey.domainSize) { - throw new Error("C Polynomial is not well calculated"); - } - } - - async function computeT0() { - if (logger) logger.info(`··· Reading sections ${ZKEY_FF_QL_SECTION}, ${ZKEY_FF_QR_SECTION}` + - `, ${ZKEY_FF_QM_SECTION}, ${ZKEY_FF_QO_SECTION}, ${ZKEY_FF_QC_SECTION}. Q selectors`); - // Reserve memory for Q's evaluations - evaluations.QL = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QR = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QM = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QO = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QC = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QL_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QR_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QM_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QO_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QC_SECTION][0].p + sDomain); - - // Read Lagrange polynomials & evaluations from zkey file - const lagrangePolynomials = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_LAGRANGE_SECTION); - evaluations.lagrange1 = new Evaluations(lagrangePolynomials, curve, logger); - - // Reserve memory for buffers T0 - buffers.T0 = new ffjavascript.BigBuffer(sDomain * 4); - - if (logger) logger.info("··· Computing T0 evaluations"); - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T0 evaluation ${i}/${zkey.domainSize * 4}`); - - // Get related evaluations to compute current T0 evaluation - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - - const ql = evaluations.QL.getEvaluation(i); - const qr = evaluations.QR.getEvaluation(i); - const qm = evaluations.QM.getEvaluation(i); - const qo = evaluations.QO.getEvaluation(i); - const qc = evaluations.QC.getEvaluation(i); - - // Compute current public input - let pi = Fr.zero; - for (let j = 0; j < zkey.nPublic; j++) { - const offset = (j * 5 * zkey.domainSize) + zkey.domainSize + i; - - const lPol = evaluations.lagrange1.getEvaluation(offset); - const aVal = buffers.A.slice(j * sFr, (j + 1) * sFr); - - pi = Fr.sub(pi, Fr.mul(lPol, aVal)); - } - - //T0(X) = [q_L(X)·a(X) + q_R(X)·b(X) + q_M(X)·a(X)·b(X) + q_O(X)·c(X) + q_C(X) + PI(X)] · 1/Z_H(X) - // Compute first T0(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - // expression 1 -> q_L(X)·a(X) - const e1 = Fr.mul(a, ql); - - // expression 2 -> q_R(X)·b(X) - const e2 = Fr.mul(b, qr); - - // expression 3 -> q_M(X)·a(X)·b(X) - const e3 = Fr.mul(Fr.mul(a, b), qm); - - // expression 4 -> q_O(X)·c(X) - const e4 = Fr.mul(c, qo); - - // t0 = expressions 1 + expression 2 + expression 3 + expression 4 + qc + pi - const t0 = Fr.add(e1, Fr.add(e2, Fr.add(e3, Fr.add(e4, Fr.add(qc, pi))))); - - buffers.T0.set(t0, i * sFr); - } - - if (logger) logger.info("buffer T0: " + buffers.T0.byteLength / sFr); - - // Compute the coefficients of the polynomial T0(X) from buffers.T0 - if (logger) logger.info("··· Computing T0 ifft"); - polynomials.T0 = await Polynomial.fromEvaluations(buffers.T0, curve, logger); - - if (logger) logger.info("T0 length: " + polynomials.T0.length()); - if (logger) logger.info("T0 degree: " + polynomials.T0.degree()); - - // Divide the polynomial T0 by Z_H(X) - if (logger) logger.info("··· Computing T0 / ZH"); - polynomials.T0.divByZerofier(zkey.domainSize, Fr.one); - - // Check degree - if (polynomials.T0.degree() >= 2 * zkey.domainSize - 2) { - throw new Error(`T0 Polynomial is not well calculated (degree is ${polynomials.T0.degree()} and must be less than ${2 * zkey.domainSize + 2}`); - } - - delete buffers.T0; - } - - async function computeC1() { - let C1 = new CPolynomial(4, curve, logger); - C1.addPolynomial(0, polynomials.A); - C1.addPolynomial(1, polynomials.B); - C1.addPolynomial(2, polynomials.C); - C1.addPolynomial(3, polynomials.T0); - - polynomials.C1 = C1.getPolynomial(); - - // Check degree - if (polynomials.C1.degree() >= 8 * zkey.domainSize - 8) { - throw new Error("C1 Polynomial is not well calculated"); - } - } - } - - async function round2() { - // STEP 2.1 - Compute permutation challenge beta and gamma ∈ F - // Compute permutation challenge beta - if (logger) logger.info("> Computing challenges beta and gamma"); - const transcript = new Keccak256Transcript(curve); - - // Add C0 to the transcript - transcript.addPolCommitment(zkey.C0); - - // Add A to the transcript - for (let i = 0; i < zkey.nPublic; i++) { - transcript.addScalar(buffers.A.slice(i * sFr, i * sFr + sFr)); - } - - // Add C1 to the transcript - transcript.addPolCommitment(proof.getPolynomial("C1")); - - challenges.beta = transcript.getChallenge(); - if (logger) logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); - - // Compute permutation challenge gamma - transcript.reset(); - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - if (logger) logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); - - // STEP 2.2 - Compute permutation polynomial z(X) - if (logger) logger.info("> Computing Z polynomial"); - await computeZ(); - - // STEP 2.3 - Compute quotient polynomial T1(X) and T2(X) - if (logger) logger.info("> Computing T1 polynomial"); - await computeT1(); - if (logger) logger.info("> Computing T2 polynomial"); - await computeT2(); - - // STEP 2.4 - Compute the FFT-style combination polynomial C2(X) - if (logger) logger.info("> Computing C2 polynomial"); - await computeC2(); - - // The second output of the prover is ([C2]_1) - if (logger) logger.info("> Computing C2 multi exponentiation"); - let commitC2 = await polynomials.C2.multiExponentiation(PTau, "C2"); - proof.addPolynomial("C2", commitC2); - - return 0; - - async function computeZ() { - if (logger) logger.info("··· Computing Z evaluations"); - - let numArr = new ffjavascript.BigBuffer(sDomain); - let denArr = new ffjavascript.BigBuffer(sDomain); - - // Set the first values to 1 - numArr.set(Fr.one, 0); - denArr.set(Fr.one, 0); - - // Set initial omega - let w = Fr.one; - for (let i = 0; i < zkey.domainSize; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` Z evaluation ${i}/${zkey.domainSize}`); - const i_sFr = i * sFr; - - // Z(X) := numArr / denArr - // numArr := (a + beta·ω + gamma)(b + beta·ω·k1 + gamma)(c + beta·ω·k2 + gamma) - const betaw = Fr.mul(challenges.beta, w); - - let num1 = buffers.A.slice(i_sFr, i_sFr + sFr); - num1 = Fr.add(num1, betaw); - num1 = Fr.add(num1, challenges.gamma); - - let num2 = buffers.B.slice(i_sFr, i_sFr + sFr); - num2 = Fr.add(num2, Fr.mul(zkey.k1, betaw)); - num2 = Fr.add(num2, challenges.gamma); - - let num3 = buffers.C.slice(i_sFr, i_sFr + sFr); - num3 = Fr.add(num3, Fr.mul(zkey.k2, betaw)); - num3 = Fr.add(num3, challenges.gamma); - - let num = Fr.mul(num1, Fr.mul(num2, num3)); - - // denArr := (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma) - let den1 = buffers.A.slice(i_sFr, i_sFr + sFr); - den1 = Fr.add(den1, Fr.mul(challenges.beta, evaluations.Sigma1.getEvaluation(i * 4))); - den1 = Fr.add(den1, challenges.gamma); - - let den2 = buffers.B.slice(i_sFr, i_sFr + sFr); - den2 = Fr.add(den2, Fr.mul(challenges.beta, evaluations.Sigma2.getEvaluation(i * 4))); - den2 = Fr.add(den2, challenges.gamma); - - let den3 = buffers.C.slice(i_sFr, i_sFr + sFr); - den3 = Fr.add(den3, Fr.mul(challenges.beta, evaluations.Sigma3.getEvaluation(i * 4))); - den3 = Fr.add(den3, challenges.gamma); - - let den = Fr.mul(den1, Fr.mul(den2, den3)); - - // Multiply current num value with the previous one saved in numArr - num = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), num); - numArr.set(num, ((i + 1) % zkey.domainSize) * sFr); - - // Multiply current den value with the previous one saved in denArr - den = Fr.mul(denArr.slice(i_sFr, i_sFr + sFr), den); - denArr.set(den, ((i + 1) % zkey.domainSize) * sFr); - - // Next omega - w = Fr.mul(w, Fr.w[zkey.power]); - } - // Compute the inverse of denArr to compute in the next command the - // division numArr/denArr by multiplying num · 1/denArr - denArr = await Fr.batchInverse(denArr); - - // TODO: Do it in assembly and in parallel - // Multiply numArr · denArr where denArr was inverted in the previous command - for (let i = 0; i < zkey.domainSize; i++) { - const i_sFr = i * sFr; - - const z = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), denArr.slice(i_sFr, i_sFr + sFr)); - numArr.set(z, i_sFr); - } - // From now on the values saved on numArr will be Z(X) buffer - buffers.Z = numArr; - - if (!Fr.eq(numArr.slice(0, sFr), Fr.one)) { - throw new Error("Copy constraints does not match"); - } - - // Compute polynomial coefficients z(X) from buffers.Z - if (logger) logger.info("··· Computing Z ifft"); - polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); - - // Compute extended evaluations of z(X) polynomial - if (logger) logger.info("··· Computing Z fft"); - evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); - - // Blind z(X) polynomial coefficients with blinding scalars b - polynomials.Z.blindCoefficients([challenges.b[9], challenges.b[8], challenges.b[7]]); - - // Check degree - if (polynomials.Z.degree() >= zkey.domainSize + 3) { - throw new Error("Z Polynomial is not well calculated"); - } - - delete buffers.Z; - } - - async function computeT1() { - if (logger) logger.info("··· Computing T1 evaluations"); - - buffers.T1 = new ffjavascript.BigBuffer(sDomain * 2); - buffers.T1z = new ffjavascript.BigBuffer(sDomain * 2); - - // Set initial omega - let omega = Fr.one; - for (let i = 0; i < zkey.domainSize * 2; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T1 evaluation ${i}/${zkey.domainSize * 4}`); - - const omega2 = Fr.square(omega); - - const z = evaluations.Z.getEvaluation(i * 2); - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); - - // T1(X) := (z(X) - 1) · L_1(X) - // Compute first T1(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - const lagrange1 = evaluations.lagrange1.getEvaluation(zkey.domainSize + i * 2); - let t1 = Fr.mul(Fr.sub(z, Fr.one), lagrange1); - let t1z = Fr.mul(zp, lagrange1); - - buffers.T1.set(t1, i * sFr); - buffers.T1z.set(t1z, i * sFr); - - // Compute next omega - omega = Fr.mul(omega, Fr.w[zkey.power + 1]); - } - - // Compute the coefficients of the polynomial T1(X) from buffers.T1 - if (logger) logger.info("··· Computing T1 ifft"); - polynomials.T1 = await Polynomial.fromEvaluations(buffers.T1, curve, logger); - - // Divide the polynomial T1 by Z_H(X) - polynomials.T1.divByZerofier(zkey.domainSize, Fr.one); - - // Compute the coefficients of the polynomial T1z(X) from buffers.T1z - if (logger) logger.info("··· Computing T1z ifft"); - polynomials.T1z = await Polynomial.fromEvaluations(buffers.T1z, curve, logger); - - // Add the polynomial T1z to T1 to get the final polynomial T1 - polynomials.T1.add(polynomials.T1z); - - // Check degree - if (polynomials.T1.degree() >= zkey.domainSize + 2) { - throw new Error("T1 Polynomial is not well calculated"); - } - - delete buffers.T1; - delete buffers.T1z; - delete polynomials.T1z; - } - - async function computeT2() { - if (logger) logger.info("··· Computing T2 evaluations"); - - buffers.T2 = new ffjavascript.BigBuffer(sDomain * 4); - buffers.T2z = new ffjavascript.BigBuffer(sDomain * 4); - - // Set initial omega - let omega = Fr.one; - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T2 evaluation ${i}/${zkey.domainSize * 4}`); - - const omega2 = Fr.square(omega); - const omegaW = Fr.mul(omega, Fr.w[zkey.power]); - const omegaW2 = Fr.square(omegaW); - - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - const z = evaluations.Z.getEvaluation(i); - const zW = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); - - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); - const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omegaW2), Fr.mul(challenges.b[8], omegaW)), challenges.b[9]); - - const sigma1 = evaluations.Sigma1.getEvaluation(i); - const sigma2 = evaluations.Sigma2.getEvaluation(i); - const sigma3 = evaluations.Sigma3.getEvaluation(i); - - // T2(X) := [ (a(X) + beta·X + gamma)(b(X) + beta·k1·X + gamma)(c(X) + beta·k2·X + gamma)z(X) - // -(a(X) + beta·sigma1(X) + gamma)(b(X) + beta·sigma2(X) + gamma)(c(X) + beta·sigma3(X) + gamma)z(Xω)] · 1/Z_H(X) - // Compute first T2(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - - // expression 1 -> (a(X) + beta·X + gamma)(b(X) + beta·k1·X + gamma)(c(X) + beta·k2·X + gamma)z(X) - const betaX = Fr.mul(challenges.beta, omega); - - let e11 = Fr.add(a, betaX); - e11 = Fr.add(e11, challenges.gamma); - - let e12 = Fr.add(b, Fr.mul(betaX, zkey.k1)); - e12 = Fr.add(e12, challenges.gamma); - - let e13 = Fr.add(c, Fr.mul(betaX, zkey.k2)); - e13 = Fr.add(e13, challenges.gamma); - - let e1 = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), z); - let e1z = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), zp); - // const [e1, e1z] = MulZ.mul4(e11, e12, e13, z, ap, bp, cp, zp, i % 4, Fr); - - // expression 2 -> (a(X) + beta·sigma1(X) + gamma)(b(X) + beta·sigma2(X) + gamma)(c(X) + beta·sigma3(X) + gamma)z(Xω) - let e21 = Fr.add(a, Fr.mul(challenges.beta, sigma1)); - e21 = Fr.add(e21, challenges.gamma); - - let e22 = Fr.add(b, Fr.mul(challenges.beta, sigma2)); - e22 = Fr.add(e22, challenges.gamma); - - let e23 = Fr.add(c, Fr.mul(challenges.beta, sigma3)); - e23 = Fr.add(e23, challenges.gamma); - - let e2 = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zW); - let e2z = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zWp); - // const [e2, e2z] = MulZ.mul4(e21, e22, e23, zW, ap, bp, cp, zWp, i % 4, Fr); - - let t2 = Fr.sub(e1, e2); - let t2z = Fr.sub(e1z, e2z); - - buffers.T2.set(t2, i * sFr); - buffers.T2z.set(t2z, i * sFr); - - // Compute next omega - omega = Fr.mul(omega, Fr.w[zkey.power + 2]); - } - - // Compute the coefficients of the polynomial T2(X) from buffers.T2 - if (logger) logger.info("··· Computing T2 ifft"); - polynomials.T2 = await Polynomial.fromEvaluations(buffers.T2, curve, logger); - - // Divide the polynomial T2 by Z_H(X) - if (logger) logger.info("··· Computing T2 / ZH"); - polynomials.T2.divByZerofier(zkey.domainSize, Fr.one); - - // Compute the coefficients of the polynomial T2z(X) from buffers.T2z - if (logger) logger.info("··· Computing T2z ifft"); - polynomials.T2z = await Polynomial.fromEvaluations(buffers.T2z, curve, logger); - - // Add the polynomial T2z to T2 to get the final polynomial T2 - polynomials.T2.add(polynomials.T2z); - - // Check degree - if (polynomials.T2.degree() >= 3 * zkey.domainSize) { - throw new Error("T2 Polynomial is not well calculated"); - } - - delete buffers.T2; - delete buffers.T2z; - delete polynomials.T2z; - } - - async function computeC2() { - let C2 = new CPolynomial(3, curve, logger); - C2.addPolynomial(0, polynomials.Z); - C2.addPolynomial(1, polynomials.T1); - C2.addPolynomial(2, polynomials.T2); - - polynomials.C2 = C2.getPolynomial(); - - // Check degree - if (polynomials.C2.degree() >= 9 * zkey.domainSize) { - throw new Error("C2 Polynomial is not well calculated"); - } - } - } - - async function round3() { - if (logger) logger.info("> Computing challenge xi"); - // STEP 3.1 - Compute evaluation challenge xi ∈ S - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.getPolynomial("C2")); - - // Obtain a xi_seeder from the transcript - // To force h1^4 = xi, h2^3 = xi and h_3^2 = xiω - // we compute xi = xi_seeder^12, h1 = xi_seeder^3, h2 = xi_seeder^4 and h3 = xi_seeder^6 - challenges.xiSeed = transcript.getChallenge(); - const xiSeed2 = Fr.square(challenges.xiSeed); - - // Compute omega8, omega4 and omega3 - roots.w8 = []; - roots.w8[0] = Fr.one; - for (let i = 1; i < 8; i++) { - roots.w8[i] = Fr.mul(roots.w8[i - 1], zkey.w8); - } - - roots.w4 = []; - roots.w4[0] = Fr.one; - for (let i = 1; i < 4; i++) { - roots.w4[i] = Fr.mul(roots.w4[i - 1], zkey.w4); - } - - roots.w3 = []; - roots.w3[0] = Fr.one; - roots.w3[1] = zkey.w3; - roots.w3[2] = Fr.square(zkey.w3); - - // Compute h0 = xiSeeder^3 - roots.S0 = {}; - roots.S0.h0w8 = []; - roots.S0.h0w8[0] = Fr.mul(xiSeed2, challenges.xiSeed); - for (let i = 1; i < 8; i++) { - roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], roots.w8[i]); - } - - // Compute h1 = xi_seeder^6 - roots.S1 = {}; - roots.S1.h1w4 = []; - roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); - for (let i = 1; i < 4; i++) { - roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], roots.w4[i]); - } - - // Compute h2 = xi_seeder^8 - roots.S2 = {}; - roots.S2.h2w3 = []; - roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); - roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], roots.w3[1]); - roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], roots.w3[2]); - - roots.S2.h3w3 = []; - // Multiply h3 by third-root-omega to obtain h_3^3 = xiω - // So, h3 = xi_seeder^8 ω^{1/3} - roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], zkey.wr); - roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], roots.w3[1]); - roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], roots.w3[2]); - - // Compute xi = xi_seeder^24 - challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); - - if (logger) logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); - - // Reserve memory for Q's polynomials - polynomials.QL = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QR = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QM = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QO = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QC = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[ZKEY_FF_QL_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[ZKEY_FF_QR_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[ZKEY_FF_QM_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[ZKEY_FF_QO_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[ZKEY_FF_QC_SECTION][0].p); - - // STEP 3.2 - Compute opening evaluations and add them to the proof (third output of the prover) - if (logger) logger.info("··· Computing evaluations"); - proof.addEvaluation("ql", polynomials.QL.evaluate(challenges.xi)); - proof.addEvaluation("qr", polynomials.QR.evaluate(challenges.xi)); - proof.addEvaluation("qm", polynomials.QM.evaluate(challenges.xi)); - proof.addEvaluation("qo", polynomials.QO.evaluate(challenges.xi)); - proof.addEvaluation("qc", polynomials.QC.evaluate(challenges.xi)); - proof.addEvaluation("s1", polynomials.Sigma1.evaluate(challenges.xi)); - proof.addEvaluation("s2", polynomials.Sigma2.evaluate(challenges.xi)); - proof.addEvaluation("s3", polynomials.Sigma3.evaluate(challenges.xi)); - proof.addEvaluation("a", polynomials.A.evaluate(challenges.xi)); - proof.addEvaluation("b", polynomials.B.evaluate(challenges.xi)); - proof.addEvaluation("c", polynomials.C.evaluate(challenges.xi)); - proof.addEvaluation("z", polynomials.Z.evaluate(challenges.xi)); - - challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); - proof.addEvaluation("zw", polynomials.Z.evaluate(challenges.xiw)); - proof.addEvaluation("t1w", polynomials.T1.evaluate(challenges.xiw)); - proof.addEvaluation("t2w", polynomials.T2.evaluate(challenges.xiw)); - } - - async function round4() { - if (logger) logger.info("> Computing challenge alpha"); - // STEP 4.1 - Compute challenge alpha ∈ F - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.xiSeed); - transcript.addScalar(proof.getEvaluation("ql")); - transcript.addScalar(proof.getEvaluation("qr")); - transcript.addScalar(proof.getEvaluation("qm")); - transcript.addScalar(proof.getEvaluation("qo")); - transcript.addScalar(proof.getEvaluation("qc")); - transcript.addScalar(proof.getEvaluation("s1")); - transcript.addScalar(proof.getEvaluation("s2")); - transcript.addScalar(proof.getEvaluation("s3")); - transcript.addScalar(proof.getEvaluation("a")); - transcript.addScalar(proof.getEvaluation("b")); - transcript.addScalar(proof.getEvaluation("c")); - transcript.addScalar(proof.getEvaluation("z")); - transcript.addScalar(proof.getEvaluation("zw")); - transcript.addScalar(proof.getEvaluation("t1w")); - transcript.addScalar(proof.getEvaluation("t2w")); - challenges.alpha = transcript.getChallenge(); - if (logger) logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); - - // STEP 4.2 - Compute F(X) - if (logger) logger.info("> Reading C0 polynomial"); - polynomials.C0 = new Polynomial(new ffjavascript.BigBuffer(sDomain * 8), curve, logger); - await fdZKey.readToBuffer(polynomials.C0.coef, 0, sDomain * 8, zkeySections[ZKEY_FF_C0_SECTION][0].p); - - if (logger) logger.info("> Computing R0 polynomial"); - computeR0(); - if (logger) logger.info("> Computing R1 polynomial"); - computeR1(); - if (logger) logger.info("> Computing R2 polynomial"); - computeR2(); - - if (logger) logger.info("> Computing F polynomial"); - await computeF(); - - // The fourth output of the prover is ([W1]_1), where W1:=(f/Z_t)(x) - if (logger) logger.info("> Computing W1 multi exponentiation"); - let commitW1 = await polynomials.F.multiExponentiation(PTau, "W1"); - proof.addPolynomial("W1", commitW1); - - return 0; - - function computeR0() { - // COMPUTE R0 - // Compute the coefficients of R0(X) from 8 evaluations using lagrange interpolation. R0(X) ∈ F_{<8}[X] - // We decide to use Lagrange interpolations because the R0 degree is very small (deg(R0)===7), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R0 = Polynomial.lagrangePolynomialInterpolation( - [roots.S0.h0w8[0], roots.S0.h0w8[1], roots.S0.h0w8[2], roots.S0.h0w8[3], - roots.S0.h0w8[4], roots.S0.h0w8[5], roots.S0.h0w8[6], roots.S0.h0w8[7]], - [polynomials.C0.evaluate(roots.S0.h0w8[0]), polynomials.C0.evaluate(roots.S0.h0w8[1]), - polynomials.C0.evaluate(roots.S0.h0w8[2]), polynomials.C0.evaluate(roots.S0.h0w8[3]), - polynomials.C0.evaluate(roots.S0.h0w8[4]), polynomials.C0.evaluate(roots.S0.h0w8[5]), - polynomials.C0.evaluate(roots.S0.h0w8[6]), polynomials.C0.evaluate(roots.S0.h0w8[7])], curve); - - // Check the degree of r0(X) < 8 - if (polynomials.R0.degree() > 7) { - throw new Error("R0 Polynomial is not well calculated"); - } - } - - function computeR1() { - // COMPUTE R1 - // Compute the coefficients of R1(X) from 4 evaluations using lagrange interpolation. R1(X) ∈ F_{<4}[X] - // We decide to use Lagrange interpolations because the R1 degree is very small (deg(R1)===3), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R1 = Polynomial.lagrangePolynomialInterpolation( - [roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3]], - [polynomials.C1.evaluate(roots.S1.h1w4[0]), polynomials.C1.evaluate(roots.S1.h1w4[1]), - polynomials.C1.evaluate(roots.S1.h1w4[2]), polynomials.C1.evaluate(roots.S1.h1w4[3])], curve); - - // Check the degree of r1(X) < 4 - if (polynomials.R1.degree() > 3) { - throw new Error("R1 Polynomial is not well calculated"); - } - } - - function computeR2() { - // COMPUTE R2 - // Compute the coefficients of r2(X) from 6 evaluations using lagrange interpolation. r2(X) ∈ F_{<6}[X] - // We decide to use Lagrange interpolations because the R2.degree is very small (deg(R2)===5), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R2 = Polynomial.lagrangePolynomialInterpolation( - [roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], - [polynomials.C2.evaluate(roots.S2.h2w3[0]), polynomials.C2.evaluate(roots.S2.h2w3[1]), - polynomials.C2.evaluate(roots.S2.h2w3[2]), polynomials.C2.evaluate(roots.S2.h3w3[0]), - polynomials.C2.evaluate(roots.S2.h3w3[1]), polynomials.C2.evaluate(roots.S2.h3w3[2])], curve); - - // Check the degree of r2(X) < 6 - if (polynomials.R2.degree() > 5) { - throw new Error("R2 Polynomial is not well calculated"); - } - } - - async function computeF() { - if (logger) logger.info("··· Computing F polynomial"); - - // COMPUTE F(X) - polynomials.F = Polynomial.fromPolynomial(polynomials.C0, curve, logger); - polynomials.F.sub(polynomials.R0); - polynomials.F.divByZerofier(8, challenges.xi); - - let f2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); - f2.sub(polynomials.R1); - f2.mulScalar(challenges.alpha); - f2.divByZerofier(4, challenges.xi); - - let f3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); - f3.sub(polynomials.R2); - f3.mulScalar(Fr.square(challenges.alpha)); - f3.divByZerofier(3, challenges.xi); - f3.divByZerofier(3, challenges.xiw); - - polynomials.F.add(f2); - polynomials.F.add(f3); - - if (polynomials.F.degree() >= 9 * zkey.domainSize - 6) { - throw new Error("F Polynomial is not well calculated"); - } - } - } - - async function round5() { - if (logger) logger.info("> Computing challenge y"); - - // STEP 5.1 - Compute random evaluation point y ∈ F - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.getPolynomial("W1")); - - challenges.y = transcript.getChallenge(); - if (logger) logger.info("··· challenges.y: " + Fr.toString(challenges.y)); - - // STEP 5.2 - Compute L(X) - if (logger) logger.info("> Computing L polynomial"); - await computeL(); - - if (logger) logger.info("> Computing ZTS2 polynomial"); - await computeZTS2(); - - let ZTS2Y = polynomials.ZTS2.evaluate(challenges.y); - ZTS2Y = Fr.inv(ZTS2Y); - polynomials.L.mulScalar(ZTS2Y); - - const polDividend = Polynomial.fromCoefficientsArray([Fr.neg(challenges.y), Fr.one], curve); - if (logger) logger.info("> Computing W' = L / ZTS2 polynomial"); - const polRemainder = polynomials.L.divBy(polDividend); - - //Check polReminder degree is equal to zero - if (polRemainder.degree() > 0) { - throw new Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${polRemainder.degree()} and should be 0`); - } - - if (polynomials.L.degree() >= 9 * zkey.domainSize - 1) { - throw new Error("Degree of L(X)/(ZTS2(y)(X-y)) is not correct"); - } - - // The fifth output of the prover is ([W2]_1), where W2:=(f/Z_t)(x) - if (logger) logger.info("> Computing W' multi exponentiation"); - let commitW2 = await polynomials.L.multiExponentiation(PTau, "W2"); - proof.addPolynomial("W2", commitW2); - - return 0; - - async function computeL() { - if (logger) logger.info("··· Computing L polynomial"); - - const evalR0Y = polynomials.R0.evaluate(challenges.y); - const evalR1Y = polynomials.R1.evaluate(challenges.y); - const evalR2Y = polynomials.R2.evaluate(challenges.y); - - let mulL0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); - for (let i = 1; i < 8; i++) { - mulL0 = Fr.mul(mulL0, Fr.sub(challenges.y, roots.S0.h0w8[i])); - } - - let mulL1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); - for (let i = 1; i < 4; i++) { - mulL1 = Fr.mul(mulL1, Fr.sub(challenges.y, roots.S1.h1w4[i])); - } - - let mulL2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); - for (let i = 1; i < 3; i++) { - mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h2w3[i])); - } - for (let i = 0; i < 3; i++) { - mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h3w3[i])); - } - - let preL0 = Fr.mul(mulL1, mulL2); - let preL1 = Fr.mul(challenges.alpha, Fr.mul(mulL0, mulL2)); - let preL2 = Fr.mul(Fr.square(challenges.alpha), Fr.mul(mulL0, mulL1)); - - toInverse["denH1"] = mulL1; - toInverse["denH2"] = mulL2; - - // COMPUTE L(X) - polynomials.L = Polynomial.fromPolynomial(polynomials.C0, curve, logger); - polynomials.L.subScalar(evalR0Y); - polynomials.L.mulScalar(preL0); - - let l2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); - l2.subScalar(evalR1Y); - l2.mulScalar(preL1); - - let l3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); - l3.subScalar(evalR2Y); - l3.mulScalar(preL2); - - polynomials.L.add(l2); - polynomials.L.add(l3); - - if (logger) logger.info("> Computing ZT polynomial"); - await computeZT(); - - const evalZTY = polynomials.ZT.evaluate(challenges.y); - polynomials.F.mulScalar(evalZTY); - polynomials.L.sub(polynomials.F); - - // Check degree - if (polynomials.L.degree() >= 9 * zkey.domainSize) { - throw new Error("L Polynomial is not well calculated"); - } - - delete buffers.L; - } - - async function computeZT() { - polynomials.ZT = Polynomial.zerofierPolynomial( - [ - roots.S0.h0w8[0], roots.S0.h0w8[1], roots.S0.h0w8[2], roots.S0.h0w8[3], - roots.S0.h0w8[4], roots.S0.h0w8[5], roots.S0.h0w8[6], roots.S0.h0w8[7], - roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3], - roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], curve); - } - - async function computeZTS2() { - polynomials.ZTS2 = Polynomial.zerofierPolynomial( - [roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3], - roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], curve); - } - } - - function getMontgomeryBatchedInverse() { - // · denominator needed in step 8 and 9 of the verifier to multiply by 1/Z_H(xi) - let xiN = challenges.xi; - for (let i = 0; i < zkey.power; i++) { - xiN = Fr.square(xiN); - } - toInverse["zh"] = Fr.sub(xiN, Fr.one); - - // · denominator needed in step 10 and 11 of the verifier - // toInverse.denH1 & toInverse.denH2 -> Computed in round5, computeL() - - // · denominator needed in the verifier when computing L_i^{S0}(X), L_i^{S1}(X) and L_i^{S2}(X) - computeLiS0(toInverse, roots.S0.h0w8, challenges.y, curve); - - computeLiS1(toInverse, roots.S1.h1w4, challenges.y, curve); - - computeLiS2(toInverse, roots.S2.h2w3, roots.S2.h3w3, challenges.y, challenges.xi, challenges.xiw, curve); - - // · L_i i=1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) - const size = Math.max(1, zkey.nPublic); - - let w = Fr.one; - for (let i = 0; i < size; i++) { - toInverse["Li_" + (i + 1)] = Fr.mul(Fr.e(zkey.domainSize), Fr.sub(challenges.xi, w)); - w = Fr.mul(w, Fr.w[zkey.power]); - } - - let mulAccumulator = Fr.one; - for (const element of Object.values(toInverse)) { - if(Array.isArray(element)) { - for (const subElement of element) { - mulAccumulator = Fr.mul(mulAccumulator, subElement); - } - } else { - mulAccumulator = Fr.mul(mulAccumulator, element); - } - } - return Fr.inv(mulAccumulator); - - - function computeLiS0(toInverse, roots, x, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - toInverse[["LiS0_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); - } - - return Li; - } - - function computeLiS1(toInverse, roots, x, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - toInverse[["LiS1_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); - - } - - return Li; - } - - function computeLiS2(toInverse, S2, S2p, value, xi, xiw, curve) { - const Fr = curve.Fr; - - const Li = []; - - const _3h2 = Fr.mul(Fr.e(3), S2[0]); - const xisubxiw = Fr.sub(xi, xiw); - let den1 = Fr.mul(_3h2, xisubxiw); - for (let i = 0; i < 3; i++) { - const den2 = S2[2 * i % 3]; - const den3 = Fr.sub(value, S2[i]); - - toInverse[["LiS2_" + (i + 1)]] = Fr.mul(den1,Fr.mul(den2, den3)); - - } - - const _3h3 = Fr.mul(Fr.e(3), S2p[0]); - const xiwsubxi = Fr.sub(xiw, xi); - den1 = Fr.mul(_3h3, xiwsubxi); - for (let i = 0; i < 3; i++) { - const den2 = S2p[2 * i % 3]; - const den3 = Fr.sub(value, S2p[i]); - - toInverse[["LiS2_" + (i + 1 + 3)]] = Fr.mul(den1,Fr.mul(den2, den3)); - } - - return Li; - } - } -} - -/* - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const {unstringifyBigInts: unstringifyBigInts$3} = ffjavascript.utils; - + if (logger) logger.info("FFLONK PROVER STARTED"); + if (logger) logger.info("> Reading witness file"); + const { fd: fdWtns, sections: wtnsSections } = await _iden3_binfileutils.readBinFile(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); + const wtns = await readHeader(fdWtns, wtnsSections); + if (logger) logger.info("> Reading zkey file"); + const { fd: fdZKey, sections: zkeySections } = await _iden3_binfileutils.readBinFile(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); + const zkey = await readHeader$1(fdZKey, zkeySections, void 0, options); + if (zkey.protocolId !== 10) throw new Error("zkey file is not fflonk"); + if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) throw new Error("Curve of the witness does not match the curve of the proving key"); + if (wtns.nWitness !== zkey.nVars - zkey.nAdditions) throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); + const curve = zkey.curve; + const Fr = curve.Fr; + const sFr = curve.Fr.n8; + const sG1 = curve.G1.F.n8 * 2; + const sDomain = zkey.domainSize * sFr; + if (logger) { + logger.info("----------------------------"); + logger.info(" FFLONK PROVE SETTINGS"); + logger.info(` Curve: ${curve.name}`); + logger.info(` Circuit power: ${zkey.power}`); + logger.info(` Domain size: ${zkey.domainSize}`); + logger.info(` Vars: ${zkey.nVars}`); + logger.info(` Public vars: ${zkey.nPublic}`); + logger.info(` Constraints: ${zkey.nConstraints}`); + logger.info(` Additions: ${zkey.nAdditions}`); + logger.info("----------------------------"); + } + if (logger) logger.info("> Reading witness file data"); + const buffWitness = await _iden3_binfileutils.readSection(fdWtns, wtnsSections, 2); + await fdWtns.close(); + buffWitness.set(Fr.zero, 0); + const buffInternalWitness = new ffjavascript.BigBuffer(zkey.nAdditions * sFr); + let buffers = {}; + let polynomials = {}; + let evaluations = {}; + let toInverse = {}; + let challenges = {}; + let roots = {}; + let proof = new Proof(curve, logger); + if (logger) logger.info(`> Reading Section 3. Additions`); + await calculateAdditions(); + if (logger) logger.info(`> Reading Sections 12,13,14. Sigma1, Sigma2 & Sigma 3`); + if (logger) logger.info("··· Reading Sigma polynomials "); + polynomials.Sigma1 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.Sigma2 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.Sigma3 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[12][0].p); + await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[13][0].p); + await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[14][0].p); + if (logger) logger.info("··· Reading Sigma evaluations"); + evaluations.Sigma1 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.Sigma2 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.Sigma3 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[12][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[13][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[14][0].p + sDomain); + if (logger) logger.info(`> Reading Section 16. Powers of Tau`); + const PTau = new ffjavascript.BigBuffer(zkey.domainSize * 16 * sG1); + await fdZKey.readToBuffer(PTau, 0, (zkey.domainSize * 9 + 18) * sG1, zkeySections[16][0].p); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(""); + if (logger) logger.info("> ROUND 1"); + await round1(); + delete polynomials.T0; + delete evaluations.QL; + delete evaluations.QR; + delete evaluations.QM; + delete evaluations.QO; + delete evaluations.QC; + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> ROUND 2"); + await round2(); + delete buffers.A; + delete buffers.B; + delete buffers.C; + delete evaluations.A; + delete evaluations.B; + delete evaluations.C; + delete evaluations.Sigma1; + delete evaluations.Sigma2; + delete evaluations.Sigma3; + delete evaluations.lagrange1; + delete evaluations.Z; + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> ROUND 3"); + await round3(); + delete polynomials.A; + delete polynomials.B; + delete polynomials.C; + delete polynomials.Z; + delete polynomials.T1; + delete polynomials.T2; + delete polynomials.Sigma1; + delete polynomials.Sigma2; + delete polynomials.Sigma3; + delete polynomials.QL; + delete polynomials.QR; + delete polynomials.QM; + delete polynomials.QC; + delete polynomials.QO; + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> ROUND 4"); + await round4(); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> ROUND 5"); + await round5(); + delete polynomials.C0; + delete polynomials.C1; + delete polynomials.C2; + delete polynomials.R1; + delete polynomials.R2; + delete polynomials.F; + delete polynomials.L; + delete polynomials.ZT; + delete polynomials.ZTS2; + await fdZKey.close(); + if (globalThis.gc) globalThis.gc(); + proof.addEvaluation("inv", getMontgomeryBatchedInverse()); + let _proof = proof.toObjectProof(); + _proof.protocol = "fflonk"; + _proof.curve = curve.name; + let publicSignals = []; + for (let i = 1; i <= zkey.nPublic; i++) { + const i_sFr = i * sFr; + const pub = buffWitness.slice(i_sFr, i_sFr + sFr); + publicSignals.push(ffjavascript.Scalar.fromRprLE(pub)); + } + if (logger) logger.info("FFLONK PROVER FINISHED"); + return { + proof: stringifyBigInts$1(_proof), + publicSignals: stringifyBigInts$1(publicSignals) + }; + async function calculateAdditions() { + if (logger) logger.info("··· Computing additions"); + const additionsBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 3); + const sSum = 8 + sFr * 2; + for (let i = 0; i < zkey.nAdditions; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` addition ${i}/${zkey.nAdditions}`); + let offset = i * sSum; + const signalId1 = readUInt32(additionsBuff, offset); + offset += 4; + const signalId2 = readUInt32(additionsBuff, offset); + offset += 4; + const factor1 = additionsBuff.slice(offset, offset + sFr); + offset += sFr; + const factor2 = additionsBuff.slice(offset, offset + sFr); + const witness1 = getWitness(signalId1); + const witness2 = getWitness(signalId2); + const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); + buffInternalWitness.set(result, sFr * i); + } + } + function readUInt32(b, o) { + const buff = b.slice(o, o + 4); + return new DataView(buff.buffer, buff.byteOffset, buff.byteLength).getUint32(0, true); + } + function getWitness(idx) { + let diff = zkey.nVars - zkey.nAdditions; + if (idx < diff) return buffWitness.slice(idx * sFr, idx * sFr + sFr); + else if (idx < zkey.nVars) { + const offset = (idx - diff) * sFr; + return buffInternalWitness.slice(offset, offset + sFr); + } + return Fr.zero; + } + async function round1() { + challenges.b = []; + for (let i = 1; i <= 9; i++) challenges.b[i] = Fr.random(); + if (logger) logger.info("> Computing A, B, C wire polynomials"); + await computeWirePolynomials(); + if (logger) logger.info("> Computing T0 polynomial"); + await computeT0(); + if (logger) logger.info("> Computing C1 polynomial"); + await computeC1(); + if (logger) logger.info("> Computing C1 multi exponentiation"); + let commitC1 = await polynomials.C1.multiExponentiation(PTau, "C1"); + proof.addPolynomial("C1", commitC1); + return 0; + async function computeWirePolynomials() { + if (logger) logger.info("··· Reading data from zkey file"); + buffers.A = new ffjavascript.BigBuffer(sDomain); + buffers.B = new ffjavascript.BigBuffer(sDomain); + buffers.C = new ffjavascript.BigBuffer(sDomain); + const aMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 4); + const bMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 5); + const cMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 6); + for (let i = 0; i < zkey.nConstraints; i++) { + const i_sFr = i * sFr; + const offset = i * 4; + const signalIdA = readUInt32(aMapBuff, offset); + buffers.A.set(getWitness(signalIdA), i_sFr); + const signalIdB = readUInt32(bMapBuff, offset); + buffers.B.set(getWitness(signalIdB), i_sFr); + const signalIdC = readUInt32(cMapBuff, offset); + buffers.C.set(getWitness(signalIdC), i_sFr); + } + buffers.A.set(challenges.b[1], sDomain - 64); + buffers.A.set(challenges.b[2], sDomain - 32); + buffers.B.set(challenges.b[3], sDomain - 64); + buffers.B.set(challenges.b[4], sDomain - 32); + buffers.C.set(challenges.b[5], sDomain - 64); + buffers.C.set(challenges.b[6], sDomain - 32); + buffers.A = await Fr.batchToMontgomery(buffers.A); + buffers.B = await Fr.batchToMontgomery(buffers.B); + buffers.C = await Fr.batchToMontgomery(buffers.C); + if (logger) logger.info("··· Computing A ifft"); + polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); + if (logger) logger.info("··· Computing B ifft"); + polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); + if (logger) logger.info("··· Computing C ifft"); + polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); + if (logger) logger.info("··· Computing A fft"); + evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); + if (logger) logger.info("··· Computing B fft"); + evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); + if (logger) logger.info("··· Computing C fft"); + evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); + if (polynomials.A.degree() >= zkey.domainSize) throw new Error("A Polynomial is not well calculated"); + if (polynomials.B.degree() >= zkey.domainSize) throw new Error("B Polynomial is not well calculated"); + if (polynomials.C.degree() >= zkey.domainSize) throw new Error("C Polynomial is not well calculated"); + } + async function computeT0() { + if (logger) logger.info(`··· Reading sections 7, 8, 9, 10, 11. Q selectors`); + evaluations.QL = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QR = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QM = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QO = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QC = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[7][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[8][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[9][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[10][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[11][0].p + sDomain); + evaluations.lagrange1 = new Evaluations(await _iden3_binfileutils.readSection(fdZKey, zkeySections, 15), curve, logger); + buffers.T0 = new ffjavascript.BigBuffer(sDomain * 4); + if (logger) logger.info("··· Computing T0 evaluations"); + for (let i = 0; i < zkey.domainSize * 4; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` T0 evaluation ${i}/${zkey.domainSize * 4}`); + const a = evaluations.A.getEvaluation(i); + const b = evaluations.B.getEvaluation(i); + const c = evaluations.C.getEvaluation(i); + const ql = evaluations.QL.getEvaluation(i); + const qr = evaluations.QR.getEvaluation(i); + const qm = evaluations.QM.getEvaluation(i); + const qo = evaluations.QO.getEvaluation(i); + const qc = evaluations.QC.getEvaluation(i); + let pi = Fr.zero; + for (let j = 0; j < zkey.nPublic; j++) { + const offset = j * 5 * zkey.domainSize + zkey.domainSize + i; + const lPol = evaluations.lagrange1.getEvaluation(offset); + const aVal = buffers.A.slice(j * sFr, (j + 1) * sFr); + pi = Fr.sub(pi, Fr.mul(lPol, aVal)); + } + const e1 = Fr.mul(a, ql); + const e2 = Fr.mul(b, qr); + const e3 = Fr.mul(Fr.mul(a, b), qm); + const e4 = Fr.mul(c, qo); + const t0 = Fr.add(e1, Fr.add(e2, Fr.add(e3, Fr.add(e4, Fr.add(qc, pi))))); + buffers.T0.set(t0, i * sFr); + } + if (logger) logger.info("buffer T0: " + buffers.T0.byteLength / sFr); + if (logger) logger.info("··· Computing T0 ifft"); + polynomials.T0 = await Polynomial.fromEvaluations(buffers.T0, curve, logger); + if (logger) logger.info("T0 length: " + polynomials.T0.length()); + if (logger) logger.info("T0 degree: " + polynomials.T0.degree()); + if (logger) logger.info("··· Computing T0 / ZH"); + polynomials.T0.divByZerofier(zkey.domainSize, Fr.one); + if (polynomials.T0.degree() >= 2 * zkey.domainSize - 2) throw new Error(`T0 Polynomial is not well calculated (degree is ${polynomials.T0.degree()} and must be less than ${2 * zkey.domainSize + 2}`); + delete buffers.T0; + } + async function computeC1() { + let C1 = new CPolynomial(4, curve, logger); + C1.addPolynomial(0, polynomials.A); + C1.addPolynomial(1, polynomials.B); + C1.addPolynomial(2, polynomials.C); + C1.addPolynomial(3, polynomials.T0); + polynomials.C1 = C1.getPolynomial(); + if (polynomials.C1.degree() >= 8 * zkey.domainSize - 8) throw new Error("C1 Polynomial is not well calculated"); + } + } + async function round2() { + if (logger) logger.info("> Computing challenges beta and gamma"); + const transcript = new Keccak256Transcript(curve); + transcript.addPolCommitment(zkey.C0); + for (let i = 0; i < zkey.nPublic; i++) transcript.addScalar(buffers.A.slice(i * sFr, i * sFr + sFr)); + transcript.addPolCommitment(proof.getPolynomial("C1")); + challenges.beta = transcript.getChallenge(); + if (logger) logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); + transcript.reset(); + transcript.addScalar(challenges.beta); + challenges.gamma = transcript.getChallenge(); + if (logger) logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); + if (logger) logger.info("> Computing Z polynomial"); + await computeZ(); + if (logger) logger.info("> Computing T1 polynomial"); + await computeT1(); + if (logger) logger.info("> Computing T2 polynomial"); + await computeT2(); + if (logger) logger.info("> Computing C2 polynomial"); + await computeC2(); + if (logger) logger.info("> Computing C2 multi exponentiation"); + let commitC2 = await polynomials.C2.multiExponentiation(PTau, "C2"); + proof.addPolynomial("C2", commitC2); + return 0; + async function computeZ() { + if (logger) logger.info("··· Computing Z evaluations"); + let numArr = new ffjavascript.BigBuffer(sDomain); + let denArr = new ffjavascript.BigBuffer(sDomain); + numArr.set(Fr.one, 0); + denArr.set(Fr.one, 0); + let w = Fr.one; + for (let i = 0; i < zkey.domainSize; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` Z evaluation ${i}/${zkey.domainSize}`); + const i_sFr = i * sFr; + const betaw = Fr.mul(challenges.beta, w); + let num1 = buffers.A.slice(i_sFr, i_sFr + sFr); + num1 = Fr.add(num1, betaw); + num1 = Fr.add(num1, challenges.gamma); + let num2 = buffers.B.slice(i_sFr, i_sFr + sFr); + num2 = Fr.add(num2, Fr.mul(zkey.k1, betaw)); + num2 = Fr.add(num2, challenges.gamma); + let num3 = buffers.C.slice(i_sFr, i_sFr + sFr); + num3 = Fr.add(num3, Fr.mul(zkey.k2, betaw)); + num3 = Fr.add(num3, challenges.gamma); + let num = Fr.mul(num1, Fr.mul(num2, num3)); + let den1 = buffers.A.slice(i_sFr, i_sFr + sFr); + den1 = Fr.add(den1, Fr.mul(challenges.beta, evaluations.Sigma1.getEvaluation(i * 4))); + den1 = Fr.add(den1, challenges.gamma); + let den2 = buffers.B.slice(i_sFr, i_sFr + sFr); + den2 = Fr.add(den2, Fr.mul(challenges.beta, evaluations.Sigma2.getEvaluation(i * 4))); + den2 = Fr.add(den2, challenges.gamma); + let den3 = buffers.C.slice(i_sFr, i_sFr + sFr); + den3 = Fr.add(den3, Fr.mul(challenges.beta, evaluations.Sigma3.getEvaluation(i * 4))); + den3 = Fr.add(den3, challenges.gamma); + let den = Fr.mul(den1, Fr.mul(den2, den3)); + num = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), num); + numArr.set(num, (i + 1) % zkey.domainSize * sFr); + den = Fr.mul(denArr.slice(i_sFr, i_sFr + sFr), den); + denArr.set(den, (i + 1) % zkey.domainSize * sFr); + w = Fr.mul(w, Fr.w[zkey.power]); + } + denArr = await Fr.batchInverse(denArr); + for (let i = 0; i < zkey.domainSize; i++) { + const i_sFr = i * sFr; + const z = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), denArr.slice(i_sFr, i_sFr + sFr)); + numArr.set(z, i_sFr); + } + buffers.Z = numArr; + if (!Fr.eq(numArr.slice(0, sFr), Fr.one)) throw new Error("Copy constraints does not match"); + if (logger) logger.info("··· Computing Z ifft"); + polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); + if (logger) logger.info("··· Computing Z fft"); + evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); + polynomials.Z.blindCoefficients([ + challenges.b[9], + challenges.b[8], + challenges.b[7] + ]); + if (polynomials.Z.degree() >= zkey.domainSize + 3) throw new Error("Z Polynomial is not well calculated"); + delete buffers.Z; + } + async function computeT1() { + if (logger) logger.info("··· Computing T1 evaluations"); + buffers.T1 = new ffjavascript.BigBuffer(sDomain * 2); + buffers.T1z = new ffjavascript.BigBuffer(sDomain * 2); + let omega = Fr.one; + for (let i = 0; i < zkey.domainSize * 2; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` T1 evaluation ${i}/${zkey.domainSize * 4}`); + const omega2 = Fr.square(omega); + const z = evaluations.Z.getEvaluation(i * 2); + const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); + const lagrange1 = evaluations.lagrange1.getEvaluation(zkey.domainSize + i * 2); + let t1 = Fr.mul(Fr.sub(z, Fr.one), lagrange1); + let t1z = Fr.mul(zp, lagrange1); + buffers.T1.set(t1, i * sFr); + buffers.T1z.set(t1z, i * sFr); + omega = Fr.mul(omega, Fr.w[zkey.power + 1]); + } + if (logger) logger.info("··· Computing T1 ifft"); + polynomials.T1 = await Polynomial.fromEvaluations(buffers.T1, curve, logger); + polynomials.T1.divByZerofier(zkey.domainSize, Fr.one); + if (logger) logger.info("··· Computing T1z ifft"); + polynomials.T1z = await Polynomial.fromEvaluations(buffers.T1z, curve, logger); + polynomials.T1.add(polynomials.T1z); + if (polynomials.T1.degree() >= zkey.domainSize + 2) throw new Error("T1 Polynomial is not well calculated"); + delete buffers.T1; + delete buffers.T1z; + delete polynomials.T1z; + } + async function computeT2() { + if (logger) logger.info("··· Computing T2 evaluations"); + buffers.T2 = new ffjavascript.BigBuffer(sDomain * 4); + buffers.T2z = new ffjavascript.BigBuffer(sDomain * 4); + let omega = Fr.one; + for (let i = 0; i < zkey.domainSize * 4; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` T2 evaluation ${i}/${zkey.domainSize * 4}`); + const omega2 = Fr.square(omega); + const omegaW = Fr.mul(omega, Fr.w[zkey.power]); + const omegaW2 = Fr.square(omegaW); + const a = evaluations.A.getEvaluation(i); + const b = evaluations.B.getEvaluation(i); + const c = evaluations.C.getEvaluation(i); + const z = evaluations.Z.getEvaluation(i); + const zW = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); + const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); + const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omegaW2), Fr.mul(challenges.b[8], omegaW)), challenges.b[9]); + const sigma1 = evaluations.Sigma1.getEvaluation(i); + const sigma2 = evaluations.Sigma2.getEvaluation(i); + const sigma3 = evaluations.Sigma3.getEvaluation(i); + const betaX = Fr.mul(challenges.beta, omega); + let e11 = Fr.add(a, betaX); + e11 = Fr.add(e11, challenges.gamma); + let e12 = Fr.add(b, Fr.mul(betaX, zkey.k1)); + e12 = Fr.add(e12, challenges.gamma); + let e13 = Fr.add(c, Fr.mul(betaX, zkey.k2)); + e13 = Fr.add(e13, challenges.gamma); + let e1 = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), z); + let e1z = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), zp); + let e21 = Fr.add(a, Fr.mul(challenges.beta, sigma1)); + e21 = Fr.add(e21, challenges.gamma); + let e22 = Fr.add(b, Fr.mul(challenges.beta, sigma2)); + e22 = Fr.add(e22, challenges.gamma); + let e23 = Fr.add(c, Fr.mul(challenges.beta, sigma3)); + e23 = Fr.add(e23, challenges.gamma); + let e2 = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zW); + let e2z = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zWp); + let t2 = Fr.sub(e1, e2); + let t2z = Fr.sub(e1z, e2z); + buffers.T2.set(t2, i * sFr); + buffers.T2z.set(t2z, i * sFr); + omega = Fr.mul(omega, Fr.w[zkey.power + 2]); + } + if (logger) logger.info("··· Computing T2 ifft"); + polynomials.T2 = await Polynomial.fromEvaluations(buffers.T2, curve, logger); + if (logger) logger.info("··· Computing T2 / ZH"); + polynomials.T2.divByZerofier(zkey.domainSize, Fr.one); + if (logger) logger.info("··· Computing T2z ifft"); + polynomials.T2z = await Polynomial.fromEvaluations(buffers.T2z, curve, logger); + polynomials.T2.add(polynomials.T2z); + if (polynomials.T2.degree() >= 3 * zkey.domainSize) throw new Error("T2 Polynomial is not well calculated"); + delete buffers.T2; + delete buffers.T2z; + delete polynomials.T2z; + } + async function computeC2() { + let C2 = new CPolynomial(3, curve, logger); + C2.addPolynomial(0, polynomials.Z); + C2.addPolynomial(1, polynomials.T1); + C2.addPolynomial(2, polynomials.T2); + polynomials.C2 = C2.getPolynomial(); + if (polynomials.C2.degree() >= 9 * zkey.domainSize) throw new Error("C2 Polynomial is not well calculated"); + } + } + async function round3() { + if (logger) logger.info("> Computing challenge xi"); + const transcript = new Keccak256Transcript(curve); + transcript.addScalar(challenges.gamma); + transcript.addPolCommitment(proof.getPolynomial("C2")); + challenges.xiSeed = transcript.getChallenge(); + const xiSeed2 = Fr.square(challenges.xiSeed); + roots.w8 = []; + roots.w8[0] = Fr.one; + for (let i = 1; i < 8; i++) roots.w8[i] = Fr.mul(roots.w8[i - 1], zkey.w8); + roots.w4 = []; + roots.w4[0] = Fr.one; + for (let i = 1; i < 4; i++) roots.w4[i] = Fr.mul(roots.w4[i - 1], zkey.w4); + roots.w3 = []; + roots.w3[0] = Fr.one; + roots.w3[1] = zkey.w3; + roots.w3[2] = Fr.square(zkey.w3); + roots.S0 = {}; + roots.S0.h0w8 = []; + roots.S0.h0w8[0] = Fr.mul(xiSeed2, challenges.xiSeed); + for (let i = 1; i < 8; i++) roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], roots.w8[i]); + roots.S1 = {}; + roots.S1.h1w4 = []; + roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); + for (let i = 1; i < 4; i++) roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], roots.w4[i]); + roots.S2 = {}; + roots.S2.h2w3 = []; + roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); + roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], roots.w3[1]); + roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], roots.w3[2]); + roots.S2.h3w3 = []; + roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], zkey.wr); + roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], roots.w3[1]); + roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], roots.w3[2]); + challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); + if (logger) logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); + polynomials.QL = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QR = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QM = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QO = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QC = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[7][0].p); + await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[8][0].p); + await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[9][0].p); + await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[10][0].p); + await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[11][0].p); + if (logger) logger.info("··· Computing evaluations"); + proof.addEvaluation("ql", polynomials.QL.evaluate(challenges.xi)); + proof.addEvaluation("qr", polynomials.QR.evaluate(challenges.xi)); + proof.addEvaluation("qm", polynomials.QM.evaluate(challenges.xi)); + proof.addEvaluation("qo", polynomials.QO.evaluate(challenges.xi)); + proof.addEvaluation("qc", polynomials.QC.evaluate(challenges.xi)); + proof.addEvaluation("s1", polynomials.Sigma1.evaluate(challenges.xi)); + proof.addEvaluation("s2", polynomials.Sigma2.evaluate(challenges.xi)); + proof.addEvaluation("s3", polynomials.Sigma3.evaluate(challenges.xi)); + proof.addEvaluation("a", polynomials.A.evaluate(challenges.xi)); + proof.addEvaluation("b", polynomials.B.evaluate(challenges.xi)); + proof.addEvaluation("c", polynomials.C.evaluate(challenges.xi)); + proof.addEvaluation("z", polynomials.Z.evaluate(challenges.xi)); + challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); + proof.addEvaluation("zw", polynomials.Z.evaluate(challenges.xiw)); + proof.addEvaluation("t1w", polynomials.T1.evaluate(challenges.xiw)); + proof.addEvaluation("t2w", polynomials.T2.evaluate(challenges.xiw)); + } + async function round4() { + if (logger) logger.info("> Computing challenge alpha"); + const transcript = new Keccak256Transcript(curve); + transcript.addScalar(challenges.xiSeed); + transcript.addScalar(proof.getEvaluation("ql")); + transcript.addScalar(proof.getEvaluation("qr")); + transcript.addScalar(proof.getEvaluation("qm")); + transcript.addScalar(proof.getEvaluation("qo")); + transcript.addScalar(proof.getEvaluation("qc")); + transcript.addScalar(proof.getEvaluation("s1")); + transcript.addScalar(proof.getEvaluation("s2")); + transcript.addScalar(proof.getEvaluation("s3")); + transcript.addScalar(proof.getEvaluation("a")); + transcript.addScalar(proof.getEvaluation("b")); + transcript.addScalar(proof.getEvaluation("c")); + transcript.addScalar(proof.getEvaluation("z")); + transcript.addScalar(proof.getEvaluation("zw")); + transcript.addScalar(proof.getEvaluation("t1w")); + transcript.addScalar(proof.getEvaluation("t2w")); + challenges.alpha = transcript.getChallenge(); + if (logger) logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); + if (logger) logger.info("> Reading C0 polynomial"); + polynomials.C0 = new Polynomial(new ffjavascript.BigBuffer(sDomain * 8), curve, logger); + await fdZKey.readToBuffer(polynomials.C0.coef, 0, sDomain * 8, zkeySections[17][0].p); + if (logger) logger.info("> Computing R0 polynomial"); + computeR0(); + if (logger) logger.info("> Computing R1 polynomial"); + computeR1(); + if (logger) logger.info("> Computing R2 polynomial"); + computeR2(); + if (logger) logger.info("> Computing F polynomial"); + await computeF(); + if (logger) logger.info("> Computing W1 multi exponentiation"); + let commitW1 = await polynomials.F.multiExponentiation(PTau, "W1"); + proof.addPolynomial("W1", commitW1); + return 0; + function computeR0() { + polynomials.R0 = Polynomial.lagrangePolynomialInterpolation([ + roots.S0.h0w8[0], + roots.S0.h0w8[1], + roots.S0.h0w8[2], + roots.S0.h0w8[3], + roots.S0.h0w8[4], + roots.S0.h0w8[5], + roots.S0.h0w8[6], + roots.S0.h0w8[7] + ], [ + polynomials.C0.evaluate(roots.S0.h0w8[0]), + polynomials.C0.evaluate(roots.S0.h0w8[1]), + polynomials.C0.evaluate(roots.S0.h0w8[2]), + polynomials.C0.evaluate(roots.S0.h0w8[3]), + polynomials.C0.evaluate(roots.S0.h0w8[4]), + polynomials.C0.evaluate(roots.S0.h0w8[5]), + polynomials.C0.evaluate(roots.S0.h0w8[6]), + polynomials.C0.evaluate(roots.S0.h0w8[7]) + ], curve); + if (polynomials.R0.degree() > 7) throw new Error("R0 Polynomial is not well calculated"); + } + function computeR1() { + polynomials.R1 = Polynomial.lagrangePolynomialInterpolation([ + roots.S1.h1w4[0], + roots.S1.h1w4[1], + roots.S1.h1w4[2], + roots.S1.h1w4[3] + ], [ + polynomials.C1.evaluate(roots.S1.h1w4[0]), + polynomials.C1.evaluate(roots.S1.h1w4[1]), + polynomials.C1.evaluate(roots.S1.h1w4[2]), + polynomials.C1.evaluate(roots.S1.h1w4[3]) + ], curve); + if (polynomials.R1.degree() > 3) throw new Error("R1 Polynomial is not well calculated"); + } + function computeR2() { + polynomials.R2 = Polynomial.lagrangePolynomialInterpolation([ + roots.S2.h2w3[0], + roots.S2.h2w3[1], + roots.S2.h2w3[2], + roots.S2.h3w3[0], + roots.S2.h3w3[1], + roots.S2.h3w3[2] + ], [ + polynomials.C2.evaluate(roots.S2.h2w3[0]), + polynomials.C2.evaluate(roots.S2.h2w3[1]), + polynomials.C2.evaluate(roots.S2.h2w3[2]), + polynomials.C2.evaluate(roots.S2.h3w3[0]), + polynomials.C2.evaluate(roots.S2.h3w3[1]), + polynomials.C2.evaluate(roots.S2.h3w3[2]) + ], curve); + if (polynomials.R2.degree() > 5) throw new Error("R2 Polynomial is not well calculated"); + } + async function computeF() { + if (logger) logger.info("··· Computing F polynomial"); + polynomials.F = Polynomial.fromPolynomial(polynomials.C0, curve, logger); + polynomials.F.sub(polynomials.R0); + polynomials.F.divByZerofier(8, challenges.xi); + let f2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); + f2.sub(polynomials.R1); + f2.mulScalar(challenges.alpha); + f2.divByZerofier(4, challenges.xi); + let f3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); + f3.sub(polynomials.R2); + f3.mulScalar(Fr.square(challenges.alpha)); + f3.divByZerofier(3, challenges.xi); + f3.divByZerofier(3, challenges.xiw); + polynomials.F.add(f2); + polynomials.F.add(f3); + if (polynomials.F.degree() >= 9 * zkey.domainSize - 6) throw new Error("F Polynomial is not well calculated"); + } + } + async function round5() { + if (logger) logger.info("> Computing challenge y"); + const transcript = new Keccak256Transcript(curve); + transcript.addScalar(challenges.alpha); + transcript.addPolCommitment(proof.getPolynomial("W1")); + challenges.y = transcript.getChallenge(); + if (logger) logger.info("··· challenges.y: " + Fr.toString(challenges.y)); + if (logger) logger.info("> Computing L polynomial"); + await computeL(); + if (logger) logger.info("> Computing ZTS2 polynomial"); + await computeZTS2(); + let ZTS2Y = polynomials.ZTS2.evaluate(challenges.y); + ZTS2Y = Fr.inv(ZTS2Y); + polynomials.L.mulScalar(ZTS2Y); + const polDividend = Polynomial.fromCoefficientsArray([Fr.neg(challenges.y), Fr.one], curve); + if (logger) logger.info("> Computing W' = L / ZTS2 polynomial"); + const polRemainder = polynomials.L.divBy(polDividend); + if (polRemainder.degree() > 0) throw new Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${polRemainder.degree()} and should be 0`); + if (polynomials.L.degree() >= 9 * zkey.domainSize - 1) throw new Error("Degree of L(X)/(ZTS2(y)(X-y)) is not correct"); + if (logger) logger.info("> Computing W' multi exponentiation"); + let commitW2 = await polynomials.L.multiExponentiation(PTau, "W2"); + proof.addPolynomial("W2", commitW2); + return 0; + async function computeL() { + if (logger) logger.info("··· Computing L polynomial"); + const evalR0Y = polynomials.R0.evaluate(challenges.y); + const evalR1Y = polynomials.R1.evaluate(challenges.y); + const evalR2Y = polynomials.R2.evaluate(challenges.y); + let mulL0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); + for (let i = 1; i < 8; i++) mulL0 = Fr.mul(mulL0, Fr.sub(challenges.y, roots.S0.h0w8[i])); + let mulL1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); + for (let i = 1; i < 4; i++) mulL1 = Fr.mul(mulL1, Fr.sub(challenges.y, roots.S1.h1w4[i])); + let mulL2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); + for (let i = 1; i < 3; i++) mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h2w3[i])); + for (let i = 0; i < 3; i++) mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h3w3[i])); + let preL0 = Fr.mul(mulL1, mulL2); + let preL1 = Fr.mul(challenges.alpha, Fr.mul(mulL0, mulL2)); + let preL2 = Fr.mul(Fr.square(challenges.alpha), Fr.mul(mulL0, mulL1)); + toInverse["denH1"] = mulL1; + toInverse["denH2"] = mulL2; + polynomials.L = Polynomial.fromPolynomial(polynomials.C0, curve, logger); + polynomials.L.subScalar(evalR0Y); + polynomials.L.mulScalar(preL0); + let l2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); + l2.subScalar(evalR1Y); + l2.mulScalar(preL1); + let l3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); + l3.subScalar(evalR2Y); + l3.mulScalar(preL2); + polynomials.L.add(l2); + polynomials.L.add(l3); + if (logger) logger.info("> Computing ZT polynomial"); + await computeZT(); + const evalZTY = polynomials.ZT.evaluate(challenges.y); + polynomials.F.mulScalar(evalZTY); + polynomials.L.sub(polynomials.F); + if (polynomials.L.degree() >= 9 * zkey.domainSize) throw new Error("L Polynomial is not well calculated"); + delete buffers.L; + } + async function computeZT() { + polynomials.ZT = Polynomial.zerofierPolynomial([ + roots.S0.h0w8[0], + roots.S0.h0w8[1], + roots.S0.h0w8[2], + roots.S0.h0w8[3], + roots.S0.h0w8[4], + roots.S0.h0w8[5], + roots.S0.h0w8[6], + roots.S0.h0w8[7], + roots.S1.h1w4[0], + roots.S1.h1w4[1], + roots.S1.h1w4[2], + roots.S1.h1w4[3], + roots.S2.h2w3[0], + roots.S2.h2w3[1], + roots.S2.h2w3[2], + roots.S2.h3w3[0], + roots.S2.h3w3[1], + roots.S2.h3w3[2] + ], curve); + } + async function computeZTS2() { + polynomials.ZTS2 = Polynomial.zerofierPolynomial([ + roots.S1.h1w4[0], + roots.S1.h1w4[1], + roots.S1.h1w4[2], + roots.S1.h1w4[3], + roots.S2.h2w3[0], + roots.S2.h2w3[1], + roots.S2.h2w3[2], + roots.S2.h3w3[0], + roots.S2.h3w3[1], + roots.S2.h3w3[2] + ], curve); + } + } + function getMontgomeryBatchedInverse() { + let xiN = challenges.xi; + for (let i = 0; i < zkey.power; i++) xiN = Fr.square(xiN); + toInverse["zh"] = Fr.sub(xiN, Fr.one); + computeLiS0(toInverse, roots.S0.h0w8, challenges.y, curve); + computeLiS1(toInverse, roots.S1.h1w4, challenges.y, curve); + computeLiS2(toInverse, roots.S2.h2w3, roots.S2.h3w3, challenges.y, challenges.xi, challenges.xiw, curve); + const size = Math.max(1, zkey.nPublic); + let w = Fr.one; + for (let i = 0; i < size; i++) { + toInverse["Li_" + (i + 1)] = Fr.mul(Fr.e(zkey.domainSize), Fr.sub(challenges.xi, w)); + w = Fr.mul(w, Fr.w[zkey.power]); + } + let mulAccumulator = Fr.one; + for (const element of Object.values(toInverse)) if (Array.isArray(element)) for (const subElement of element) mulAccumulator = Fr.mul(mulAccumulator, subElement); + else mulAccumulator = Fr.mul(mulAccumulator, element); + return Fr.inv(mulAccumulator); + function computeLiS0(toInverse, roots, x, curve) { + const Fr = curve.Fr; + const len = roots.length; + const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); + const Li = []; + for (let i = 0; i < len; i++) { + const den2 = roots[(len - 1) * i % len]; + const den3 = Fr.sub(x, roots[i]); + toInverse[["LiS0_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); + } + return Li; + } + function computeLiS1(toInverse, roots, x, curve) { + const Fr = curve.Fr; + const len = roots.length; + const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); + const Li = []; + for (let i = 0; i < len; i++) { + const den2 = roots[(len - 1) * i % len]; + const den3 = Fr.sub(x, roots[i]); + toInverse[["LiS1_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); + } + return Li; + } + function computeLiS2(toInverse, S2, S2p, value, xi, xiw, curve) { + const Fr = curve.Fr; + const Li = []; + const _3h2 = Fr.mul(Fr.e(3), S2[0]); + const xisubxiw = Fr.sub(xi, xiw); + let den1 = Fr.mul(_3h2, xisubxiw); + for (let i = 0; i < 3; i++) { + const den2 = S2[2 * i % 3]; + const den3 = Fr.sub(value, S2[i]); + toInverse[["LiS2_" + (i + 1)]] = Fr.mul(den1, Fr.mul(den2, den3)); + } + const _3h3 = Fr.mul(Fr.e(3), S2p[0]); + const xiwsubxi = Fr.sub(xiw, xi); + den1 = Fr.mul(_3h3, xiwsubxi); + for (let i = 0; i < 3; i++) { + const den2 = S2p[2 * i % 3]; + const den3 = Fr.sub(value, S2p[i]); + toInverse[["LiS2_" + (i + 1 + 3)]] = Fr.mul(den1, Fr.mul(den2, den3)); + } + return Li; + } + } +} +//#endregion +//#region src/fflonk_full_prove.js +var { unstringifyBigInts: unstringifyBigInts$3 } = ffjavascript.utils; async function fflonkFullProve$1(_input, wasmFilename, zkeyFilename, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$3(_input); - - const wtns= {type: "mem"}; - - // Compute the witness - await wtnsCalculate$1(input, wasmFilename, wtns, wtnsCalcOptions); - - // Compute the proof - return await fflonkProve$1(zkeyFilename, wtns, logger, proverOptions); -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const { unstringifyBigInts: unstringifyBigInts$2 } = ffjavascript.utils; - + const input = unstringifyBigInts$3(_input); + const wtns = { type: "mem" }; + await wtnsCalculate$1(input, wasmFilename, wtns, wtnsCalcOptions); + return await fflonkProve$1(zkeyFilename, wtns, logger, proverOptions); +} +//#endregion +//#region src/fflonk_verify.js +var { unstringifyBigInts: unstringifyBigInts$2 } = ffjavascript.utils; async function fflonkVerify$1(_vk_verifier, _publicSignals, _proof, logger) { - if (logger) logger.info("FFLONK VERIFIER STARTED"); - - _vk_verifier = unstringifyBigInts$2(_vk_verifier); - _proof = unstringifyBigInts$2(_proof); - - const curve = await getCurveFromName(_vk_verifier.curve); - - const vk = fromObjectVk(curve, _vk_verifier); - - // TODO ??? Compute wr^3 and check if it matches with w - - const proof = new Proof(curve, logger); - proof.fromObjectProof(_proof); - - const publicSignals = unstringifyBigInts$2(_publicSignals); - - if (publicSignals.length !== vk.nPublic) { - logger.error("Number of public signals does not match with vk"); - return false; - } - - const Fr = curve.Fr; - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK VERIFY SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${vk.power}`); - logger.info(` Domain size: ${2 ** vk.power}`); - logger.info(` Public vars: ${vk.nPublic}`); - logger.info("----------------------------"); - } - - // STEP 1 - Validate that all polynomial commitments ∈ G_1 - if (logger) logger.info("> Checking commitments belong to G1"); - if (!commitmentsBelongToG1(curve, proof, vk)) { - if (logger) logger.error("Proof commitments are not valid"); - return false; - } - - // STEP 2 - Validate that all evaluations ∈ F - if (logger) logger.info("> Checking evaluations belong to F"); - if (!evaluationsAreValid(curve, proof)) { - if (logger) logger.error("Proof evaluations are not valid."); - return false; - } - - // STEP 3 - Validate that w_i ∈ F for i ∈ [l] - if (logger) logger.info("> Checking public inputs belong to F"); - if (!publicInputsAreValid(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - // STEP 4 - Compute the challenges: beta, gamma, xi, alpha and y ∈ F - // as in prover description, from the common preprocessed inputs, public inputs and elements of π_SNARK - if (logger) logger.info("> Computing challenges"); - const { challenges, roots } = computeChallenges(curve, proof, vk, publicSignals, logger); - - // STEP 5 - Compute the zero polynomial evaluation Z_H(xi) = xi^n - 1 - if (logger) logger.info("> Computing Zero polynomial evaluation Z_H(xi)"); - challenges.zh = Fr.sub(challenges.xiN, Fr.one); - challenges.invzh = Fr.inv(challenges.zh); - - // STEP 6 - Compute the lagrange polynomial evaluation L_1(xi) - if (logger) logger.info("> Computing Lagrange evaluations"); - const lagrangeEvals = await computeLagrangeEvaluations(curve, challenges, vk); - - // STEP 7 - Compute public input evaluation PI(xi) - if (logger) logger.info("> Computing polynomial identities PI(X)"); - const pi = calculatePI(curve, publicSignals, lagrangeEvals); - - // STEP 8 - Compute polynomial r0 ∈ F_{<4}[X] - if (logger) logger.info("> Computing r0(y)"); - const r0 = computeR0(proof, challenges, roots, curve, logger); - - // STEP 9 - Compute polynomial r1 ∈ F_{<4}[X] - if (logger) logger.info("> Computing r1(y)"); - const r1 = computeR1(proof, challenges, roots, pi, curve, logger); - - // STEP 9 - Compute polynomial r2 ∈ F_{<6}[X] - if (logger) logger.info("> Computing r2(y)"); - const r2 = computeR2(proof, challenges, roots, lagrangeEvals[1], vk, curve, logger); - - if (logger) logger.info("> Computing F"); - const F = computeF(curve, proof, vk, challenges, roots); - - if (logger) logger.info("> Computing E"); - const E = computeE(curve, proof, challenges, vk, r0, r1, r2); - - if (logger) logger.info("> Computing J"); - const J = computeJ(curve, proof, challenges); - - if (logger) logger.info("> Validate all evaluations with a pairing"); - const res = await isValidPairing(curve, proof, challenges, vk, F, E, J); - - if (logger) { - if (res) { - logger.info("PROOF VERIFIED SUCCESSFULLY"); - } else { - logger.warn("Invalid Proof"); - } - } - - if (logger) logger.info("FFLONK VERIFIER FINISHED"); - - return res; - -} - + if (logger) logger.info("FFLONK VERIFIER STARTED"); + _vk_verifier = unstringifyBigInts$2(_vk_verifier); + _proof = unstringifyBigInts$2(_proof); + const curve = await getCurveFromName(_vk_verifier.curve); + const vk = fromObjectVk(curve, _vk_verifier); + const proof = new Proof(curve, logger); + proof.fromObjectProof(_proof); + const publicSignals = unstringifyBigInts$2(_publicSignals); + if (publicSignals.length !== vk.nPublic) { + logger.error("Number of public signals does not match with vk"); + return false; + } + const Fr = curve.Fr; + if (logger) { + logger.info("----------------------------"); + logger.info(" FFLONK VERIFY SETTINGS"); + logger.info(` Curve: ${curve.name}`); + logger.info(` Circuit power: ${vk.power}`); + logger.info(` Domain size: ${2 ** vk.power}`); + logger.info(` Public vars: ${vk.nPublic}`); + logger.info("----------------------------"); + } + if (logger) logger.info("> Checking commitments belong to G1"); + if (!commitmentsBelongToG1(curve, proof, vk)) { + if (logger) logger.error("Proof commitments are not valid"); + return false; + } + if (logger) logger.info("> Checking evaluations belong to F"); + if (!evaluationsAreValid(curve, proof)) { + if (logger) logger.error("Proof evaluations are not valid."); + return false; + } + if (logger) logger.info("> Checking public inputs belong to F"); + if (!publicInputsAreValid(curve, publicSignals)) { + if (logger) logger.error("Public inputs are not valid."); + return false; + } + if (logger) logger.info("> Computing challenges"); + const { challenges, roots } = computeChallenges(curve, proof, vk, publicSignals, logger); + if (logger) logger.info("> Computing Zero polynomial evaluation Z_H(xi)"); + challenges.zh = Fr.sub(challenges.xiN, Fr.one); + challenges.invzh = Fr.inv(challenges.zh); + if (logger) logger.info("> Computing Lagrange evaluations"); + const lagrangeEvals = await computeLagrangeEvaluations(curve, challenges, vk); + if (logger) logger.info("> Computing polynomial identities PI(X)"); + const pi = calculatePI(curve, publicSignals, lagrangeEvals); + if (logger) logger.info("> Computing r0(y)"); + const r0 = computeR0(proof, challenges, roots, curve, logger); + if (logger) logger.info("> Computing r1(y)"); + const r1 = computeR1(proof, challenges, roots, pi, curve, logger); + if (logger) logger.info("> Computing r2(y)"); + const r2 = computeR2(proof, challenges, roots, lagrangeEvals[1], vk, curve, logger); + if (logger) logger.info("> Computing F"); + const F = computeF(curve, proof, vk, challenges, roots); + if (logger) logger.info("> Computing E"); + const E = computeE(curve, proof, challenges, vk, r0, r1, r2); + if (logger) logger.info("> Computing J"); + const J = computeJ(curve, proof, challenges); + if (logger) logger.info("> Validate all evaluations with a pairing"); + const res = await isValidPairing(curve, proof, challenges, vk, F, E, J); + if (logger) if (res) logger.info("PROOF VERIFIED SUCCESSFULLY"); + else logger.warn("Invalid Proof"); + if (logger) logger.info("FFLONK VERIFIER FINISHED"); + return res; +} function fromObjectVk(curve, vk) { - const res = vk; - res.k1 = curve.Fr.fromObject(vk.k1); - res.k2 = curve.Fr.fromObject(vk.k2); - res.w = curve.Fr.fromObject(vk.w); - // res.wW = curve.Fr.fromObject(vk.wW); - res.w3 = curve.Fr.fromObject(vk.w3); - res.w4 = curve.Fr.fromObject(vk.w4); - res.w8 = curve.Fr.fromObject(vk.w8); - res.wr = curve.Fr.fromObject(vk.wr); - res.X_2 = curve.G2.fromObject(vk.X_2); - res.C0 = curve.G1.fromObject(vk.C0); - return res; -} - + const res = vk; + res.k1 = curve.Fr.fromObject(vk.k1); + res.k2 = curve.Fr.fromObject(vk.k2); + res.w = curve.Fr.fromObject(vk.w); + res.w3 = curve.Fr.fromObject(vk.w3); + res.w4 = curve.Fr.fromObject(vk.w4); + res.w8 = curve.Fr.fromObject(vk.w8); + res.wr = curve.Fr.fromObject(vk.wr); + res.X_2 = curve.G2.fromObject(vk.X_2); + res.C0 = curve.G1.fromObject(vk.C0); + return res; +} function commitmentsBelongToG1(curve, proof, vk) { - const G1 = curve.G1; - return G1.isValid(proof.polynomials.C1) - && G1.isValid(proof.polynomials.C2) - && G1.isValid(proof.polynomials.W1) - && G1.isValid(proof.polynomials.W2) - && G1.isValid(vk.C0); -} - + const G1 = curve.G1; + return G1.isValid(proof.polynomials.C1) && G1.isValid(proof.polynomials.C2) && G1.isValid(proof.polynomials.W1) && G1.isValid(proof.polynomials.W2) && G1.isValid(vk.C0); +} function checkValueBelongToField(curve, value) { - return ffjavascript.Scalar.geq(value, 0) && ffjavascript.Scalar.lt(value, curve.r); + return ffjavascript.Scalar.geq(value, 0) && ffjavascript.Scalar.lt(value, curve.r); } - function checkEvaluationIsValid(curve, evaluation) { - return checkValueBelongToField(curve, ffjavascript.Scalar.fromRprLE(evaluation)); + return checkValueBelongToField(curve, ffjavascript.Scalar.fromRprLE(evaluation)); } - function evaluationsAreValid(curve, proof) { - return checkEvaluationIsValid(curve, proof.evaluations.ql) - && checkEvaluationIsValid(curve, proof.evaluations.qr) - && checkEvaluationIsValid(curve, proof.evaluations.qm) - && checkEvaluationIsValid(curve, proof.evaluations.qo) - && checkEvaluationIsValid(curve, proof.evaluations.qc) - && checkEvaluationIsValid(curve, proof.evaluations.s1) - && checkEvaluationIsValid(curve, proof.evaluations.s2) - && checkEvaluationIsValid(curve, proof.evaluations.s3) - && checkEvaluationIsValid(curve, proof.evaluations.a) - && checkEvaluationIsValid(curve, proof.evaluations.b) - && checkEvaluationIsValid(curve, proof.evaluations.c) - && checkEvaluationIsValid(curve, proof.evaluations.z) - && checkEvaluationIsValid(curve, proof.evaluations.zw) - && checkEvaluationIsValid(curve, proof.evaluations.t1w) - && checkEvaluationIsValid(curve, proof.evaluations.t2w); -} - + return checkEvaluationIsValid(curve, proof.evaluations.ql) && checkEvaluationIsValid(curve, proof.evaluations.qr) && checkEvaluationIsValid(curve, proof.evaluations.qm) && checkEvaluationIsValid(curve, proof.evaluations.qo) && checkEvaluationIsValid(curve, proof.evaluations.qc) && checkEvaluationIsValid(curve, proof.evaluations.s1) && checkEvaluationIsValid(curve, proof.evaluations.s2) && checkEvaluationIsValid(curve, proof.evaluations.s3) && checkEvaluationIsValid(curve, proof.evaluations.a) && checkEvaluationIsValid(curve, proof.evaluations.b) && checkEvaluationIsValid(curve, proof.evaluations.c) && checkEvaluationIsValid(curve, proof.evaluations.z) && checkEvaluationIsValid(curve, proof.evaluations.zw) && checkEvaluationIsValid(curve, proof.evaluations.t1w) && checkEvaluationIsValid(curve, proof.evaluations.t2w); +} function publicInputsAreValid(curve, publicInputs) { - for(let i = 0; i < publicInputs.length; i++) { - if(!checkValueBelongToField(curve, publicInputs[i])) { - return false; - } - } - return true; -} - + for (let i = 0; i < publicInputs.length; i++) if (!checkValueBelongToField(curve, publicInputs[i])) return false; + return true; +} function computeChallenges(curve, proof, vk, publicSignals, logger) { - const Fr = curve.Fr; - - const challenges = {}; - const roots = {}; - const transcript = new Keccak256Transcript(curve); - - // Add C0 to the transcript - transcript.addPolCommitment(vk.C0); - - for (let i = 0; i < publicSignals.length; i++) { - transcript.addScalar(Fr.e(publicSignals[i])); - } - - transcript.addPolCommitment(proof.polynomials.C1); - challenges.beta = transcript.getChallenge(); - transcript.reset(); - - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - - transcript.reset(); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.polynomials.C2); - const xiSeed = transcript.getChallenge(); - const xiSeed2 = Fr.square(xiSeed); - - let w8 = []; - w8[1] = vk.w8; - w8[2] = Fr.square(vk.w8); - w8[3] = Fr.mul(w8[2], vk.w8); - w8[4] = Fr.mul(w8[3], vk.w8); - w8[5] = Fr.mul(w8[4], vk.w8); - w8[6] = Fr.mul(w8[5], vk.w8); - w8[7] = Fr.mul(w8[6], vk.w8); - let w4 = []; - w4[1] = vk.w4; - w4[2] = Fr.square(vk.w4); - w4[3] = Fr.mul(w4[2], vk.w4); - let w3 = []; - w3[1] = vk.w3; - w3[2] = Fr.square(vk.w3); - - // const w4_2 = Fr.square(vk.w4); - // const w4_3 = Fr.mul(w4_2, vk.w4); - // const w3_2 = Fr.square(vk.w3); - - // Compute h0 = xiSeeder^3 - roots.S0 = {}; - roots.S0.h0w8 = []; - roots.S0.h0w8[0] = Fr.mul(xiSeed2, xiSeed); - for (let i = 1; i < 8; i++) { - roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], w8[i]); - } - - // Compute h1 = xi_seeder^6 - roots.S1 = {}; - roots.S1.h1w4 = []; - roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); - for (let i = 1; i < 4; i++) { - roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], w4[i]); - } - - // Compute h2 = xi_seeder^8 - roots.S2 = {}; - roots.S2.h2w3 = []; - roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); - roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], w3[1]); - roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], w3[2]); - - roots.S2.h3w3 = []; - // Multiply h3 by third-root-omega to obtain h_3^3 = xiω - // So, h3 = xi_seeder^8 ω^{1/3} - roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], vk.wr); - roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], w3[1]); - roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], w3[2]); - - // Compute xi = xi_seeder^12 - challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); - challenges.xiw = Fr.mul(challenges.xi, Fr.w[vk.power]); - - challenges.xiN = challenges.xi; - vk.domainSize = 1; - for (let i = 0; i < vk.power; i++) { - challenges.xiN = Fr.square(challenges.xiN); - vk.domainSize *= 2; - } - - transcript.reset(); - transcript.addScalar(xiSeed); - transcript.addScalar(proof.evaluations.ql); - transcript.addScalar(proof.evaluations.qr); - transcript.addScalar(proof.evaluations.qm); - transcript.addScalar(proof.evaluations.qo); - transcript.addScalar(proof.evaluations.qc); - transcript.addScalar(proof.evaluations.s1); - transcript.addScalar(proof.evaluations.s2); - transcript.addScalar(proof.evaluations.s3); - transcript.addScalar(proof.evaluations.a); - transcript.addScalar(proof.evaluations.b); - transcript.addScalar(proof.evaluations.c); - transcript.addScalar(proof.evaluations.z); - transcript.addScalar(proof.evaluations.zw); - transcript.addScalar(proof.evaluations.t1w); - transcript.addScalar(proof.evaluations.t2w); - challenges.alpha = transcript.getChallenge(); - - transcript.reset(); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.polynomials.W1); - challenges.y = transcript.getChallenge(); - - if (logger) { - logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); - logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); - logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); - logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); - logger.info("··· challenges.y: " + Fr.toString(challenges.y)); - } - - return { challenges: challenges, roots: roots }; -} - + const Fr = curve.Fr; + const challenges = {}; + const roots = {}; + const transcript = new Keccak256Transcript(curve); + transcript.addPolCommitment(vk.C0); + for (let i = 0; i < publicSignals.length; i++) transcript.addScalar(Fr.e(publicSignals[i])); + transcript.addPolCommitment(proof.polynomials.C1); + challenges.beta = transcript.getChallenge(); + transcript.reset(); + transcript.addScalar(challenges.beta); + challenges.gamma = transcript.getChallenge(); + transcript.reset(); + transcript.addScalar(challenges.gamma); + transcript.addPolCommitment(proof.polynomials.C2); + const xiSeed = transcript.getChallenge(); + const xiSeed2 = Fr.square(xiSeed); + let w8 = []; + w8[1] = vk.w8; + w8[2] = Fr.square(vk.w8); + w8[3] = Fr.mul(w8[2], vk.w8); + w8[4] = Fr.mul(w8[3], vk.w8); + w8[5] = Fr.mul(w8[4], vk.w8); + w8[6] = Fr.mul(w8[5], vk.w8); + w8[7] = Fr.mul(w8[6], vk.w8); + let w4 = []; + w4[1] = vk.w4; + w4[2] = Fr.square(vk.w4); + w4[3] = Fr.mul(w4[2], vk.w4); + let w3 = []; + w3[1] = vk.w3; + w3[2] = Fr.square(vk.w3); + roots.S0 = {}; + roots.S0.h0w8 = []; + roots.S0.h0w8[0] = Fr.mul(xiSeed2, xiSeed); + for (let i = 1; i < 8; i++) roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], w8[i]); + roots.S1 = {}; + roots.S1.h1w4 = []; + roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); + for (let i = 1; i < 4; i++) roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], w4[i]); + roots.S2 = {}; + roots.S2.h2w3 = []; + roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); + roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], w3[1]); + roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], w3[2]); + roots.S2.h3w3 = []; + roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], vk.wr); + roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], w3[1]); + roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], w3[2]); + challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); + challenges.xiw = Fr.mul(challenges.xi, Fr.w[vk.power]); + challenges.xiN = challenges.xi; + vk.domainSize = 1; + for (let i = 0; i < vk.power; i++) { + challenges.xiN = Fr.square(challenges.xiN); + vk.domainSize *= 2; + } + transcript.reset(); + transcript.addScalar(xiSeed); + transcript.addScalar(proof.evaluations.ql); + transcript.addScalar(proof.evaluations.qr); + transcript.addScalar(proof.evaluations.qm); + transcript.addScalar(proof.evaluations.qo); + transcript.addScalar(proof.evaluations.qc); + transcript.addScalar(proof.evaluations.s1); + transcript.addScalar(proof.evaluations.s2); + transcript.addScalar(proof.evaluations.s3); + transcript.addScalar(proof.evaluations.a); + transcript.addScalar(proof.evaluations.b); + transcript.addScalar(proof.evaluations.c); + transcript.addScalar(proof.evaluations.z); + transcript.addScalar(proof.evaluations.zw); + transcript.addScalar(proof.evaluations.t1w); + transcript.addScalar(proof.evaluations.t2w); + challenges.alpha = transcript.getChallenge(); + transcript.reset(); + transcript.addScalar(challenges.alpha); + transcript.addPolCommitment(proof.polynomials.W1); + challenges.y = transcript.getChallenge(); + if (logger) { + logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); + logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); + logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); + logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); + logger.info("··· challenges.y: " + Fr.toString(challenges.y)); + } + return { + challenges, + roots + }; +} async function computeLagrangeEvaluations(curve, challenges, vk) { - const Fr = curve.Fr; - - const size = Math.max(1, vk.nPublic); - const numArr = new ffjavascript.BigBuffer(size * Fr.n8); - let denArr = new ffjavascript.BigBuffer(size * Fr.n8); - - let w = Fr.one; - for (let i = 0; i < size; i++) { - const i_sFr = i * Fr.n8; - numArr.set(Fr.mul(w, challenges.zh), i_sFr); - denArr.set(Fr.mul(Fr.e(vk.domainSize), Fr.sub(challenges.xi, w)), i_sFr); - w = Fr.mul(w, vk.w); - } - - denArr = await Fr.batchInverse(denArr); - - let L = []; - for (let i = 0; i < size; i++) { - const i_sFr = i * Fr.n8; - L[i + 1] = Fr.mul(numArr.slice(i_sFr, i_sFr + Fr.n8), denArr.slice(i_sFr, i_sFr + Fr.n8)); - } - return L; -} - + const Fr = curve.Fr; + const size = Math.max(1, vk.nPublic); + const numArr = new ffjavascript.BigBuffer(size * Fr.n8); + let denArr = new ffjavascript.BigBuffer(size * Fr.n8); + let w = Fr.one; + for (let i = 0; i < size; i++) { + const i_sFr = i * Fr.n8; + numArr.set(Fr.mul(w, challenges.zh), i_sFr); + denArr.set(Fr.mul(Fr.e(vk.domainSize), Fr.sub(challenges.xi, w)), i_sFr); + w = Fr.mul(w, vk.w); + } + denArr = await Fr.batchInverse(denArr); + let L = []; + for (let i = 0; i < size; i++) { + const i_sFr = i * Fr.n8; + L[i + 1] = Fr.mul(numArr.slice(i_sFr, i_sFr + Fr.n8), denArr.slice(i_sFr, i_sFr + Fr.n8)); + } + return L; +} function calculatePI(curve, publicSignals, lagrangeEvals) { - const Fr = curve.Fr; - - let pi = Fr.zero; - for (let i = 0; i < publicSignals.length; i++) { - const w = Fr.e(publicSignals[i]); - pi = Fr.sub(pi, Fr.mul(w, lagrangeEvals[i + 1])); - } - return pi; -} - + const Fr = curve.Fr; + let pi = Fr.zero; + for (let i = 0; i < publicSignals.length; i++) { + const w = Fr.e(publicSignals[i]); + pi = Fr.sub(pi, Fr.mul(w, lagrangeEvals[i + 1])); + } + return pi; +} function computeR0(proof, challenges, roots, curve, logger) { - const Fr = curve.Fr; - - const Li = computeLagrangeLiSi(roots.S0.h0w8, challenges.y, challenges.xi, curve); - - // r0(y) = ∑_1^8 C_0(h_0 ω_8^{i-1}) L_i(y). To this end we need to compute - - // Compute the 8 C0 values - if (logger) logger.info("··· Computing r0(y)"); - - let res = Fr.zero; - for (let i = 0; i < 8; i++) { - let coefValues = []; - coefValues[1] = roots.S0.h0w8[i]; - for (let j = 2; j < 8; j++) { - coefValues[j] = Fr.mul(coefValues[j - 1], roots.S0.h0w8[i]); - } - - let c0 = Fr.add(proof.evaluations.ql, Fr.mul(proof.evaluations.qr, coefValues[1])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qo, coefValues[2])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qm, coefValues[3])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qc, coefValues[4])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s1, coefValues[5])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s2, coefValues[6])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s3, coefValues[7])); - - res = Fr.add(res, Fr.mul(c0, Li[i])); - } - - return res; -} - + const Fr = curve.Fr; + const Li = computeLagrangeLiSi(roots.S0.h0w8, challenges.y, challenges.xi, curve); + if (logger) logger.info("··· Computing r0(y)"); + let res = Fr.zero; + for (let i = 0; i < 8; i++) { + let coefValues = []; + coefValues[1] = roots.S0.h0w8[i]; + for (let j = 2; j < 8; j++) coefValues[j] = Fr.mul(coefValues[j - 1], roots.S0.h0w8[i]); + let c0 = Fr.add(proof.evaluations.ql, Fr.mul(proof.evaluations.qr, coefValues[1])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.qo, coefValues[2])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.qm, coefValues[3])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.qc, coefValues[4])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.s1, coefValues[5])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.s2, coefValues[6])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.s3, coefValues[7])); + res = Fr.add(res, Fr.mul(c0, Li[i])); + } + return res; +} function computeR1(proof, challenges, roots, pi, curve, logger) { - const Fr = curve.Fr; - - const Li = computeLagrangeLiSi(roots.S1.h1w4, challenges.y, challenges.xi, curve); - - // r1(y) = ∑_1^4 C_1(h_1 ω_4^{i-1}) L_i(y). To this end we need to compute - // Z1 = {C1(h_1}, C1(h_1 ω_4), C1(h_1 ω_4^2), C1(h_1 ω_4^3)} - // where C_1(h_1 ω_4^{i-1}) = eval.a + h_1 ω_4^i eval.b + (h_1 ω_4^i)^2 eval.c + (h_1 ω_4^i)^3 T0(xi), - // where T0(xi) = [ qL·a + qR·b + qM·a·b + qO·c + qC + PI(xi) ] / Z_H(xi) - - // Compute T0(xi) - if (logger) logger.info("··· Computing T0(xi)"); - let t0 = Fr.mul(proof.evaluations.ql, proof.evaluations.a); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qr, proof.evaluations.b)); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qm, Fr.mul(proof.evaluations.a, proof.evaluations.b))); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qo, proof.evaluations.c)); - t0 = Fr.add(t0, proof.evaluations.qc); - t0 = Fr.add(t0, pi); - t0 = Fr.mul(t0, challenges.invzh); - - // Compute the 4 C1 values - if (logger) logger.info("··· Computing C1(h_1ω_4^i) values"); - - let res = Fr.zero; - for (let i = 0; i < 4; i++) { - let c1 = proof.evaluations.a; - c1 = Fr.add(c1, Fr.mul(roots.S1.h1w4[i], proof.evaluations.b)); - const h1w4Squared = Fr.square(roots.S1.h1w4[i]); - c1 = Fr.add(c1, Fr.mul(h1w4Squared, proof.evaluations.c)); - c1 = Fr.add(c1, Fr.mul(Fr.mul(h1w4Squared, roots.S1.h1w4[i]), t0)); - - res = Fr.add(res, Fr.mul(c1, Li[i])); - } - - return res; -} - + const Fr = curve.Fr; + const Li = computeLagrangeLiSi(roots.S1.h1w4, challenges.y, challenges.xi, curve); + if (logger) logger.info("··· Computing T0(xi)"); + let t0 = Fr.mul(proof.evaluations.ql, proof.evaluations.a); + t0 = Fr.add(t0, Fr.mul(proof.evaluations.qr, proof.evaluations.b)); + t0 = Fr.add(t0, Fr.mul(proof.evaluations.qm, Fr.mul(proof.evaluations.a, proof.evaluations.b))); + t0 = Fr.add(t0, Fr.mul(proof.evaluations.qo, proof.evaluations.c)); + t0 = Fr.add(t0, proof.evaluations.qc); + t0 = Fr.add(t0, pi); + t0 = Fr.mul(t0, challenges.invzh); + if (logger) logger.info("··· Computing C1(h_1ω_4^i) values"); + let res = Fr.zero; + for (let i = 0; i < 4; i++) { + let c1 = proof.evaluations.a; + c1 = Fr.add(c1, Fr.mul(roots.S1.h1w4[i], proof.evaluations.b)); + const h1w4Squared = Fr.square(roots.S1.h1w4[i]); + c1 = Fr.add(c1, Fr.mul(h1w4Squared, proof.evaluations.c)); + c1 = Fr.add(c1, Fr.mul(Fr.mul(h1w4Squared, roots.S1.h1w4[i]), t0)); + res = Fr.add(res, Fr.mul(c1, Li[i])); + } + return res; +} function computeR2(proof, challenges, roots, lagrange1, vk, curve, logger) { - const Fr = curve.Fr; - - const LiS2 = computeLagrangeLiS2([roots.S2.h2w3, roots.S2.h3w3], challenges.y, challenges.xi, challenges.xiw, curve); - - // r2(y) = ∑_1^3 C_2(h_2 ω_3^{i-1}) L_i(y) + ∑_1^3 C_2(h_3 ω_3^{i-1}) L_{i+3}(y). To this end we need to compute - // Z2 = {[C2(h_2}, C2(h_2 ω_3), C2(h_2 ω_3^2)], [C2(h_3}, C2(h_3 ω_3), C2(h_3 ω_3^2)]} - // where C_2(h_2 ω_3^{i-1}) = eval.z + h_2 ω_2^i T1(xi) + (h_2 ω_3^i)^2 T2(xi), - // where C_2(h_3 ω_3^{i-1}) = eval.z + h_3 ω_2^i T1(xi) + (h_3 ω_3^i)^2 T2(xi), - // where T1(xi) = [ L_1(xi)(z-1)] / Z_H(xi) - // and T2(xi) = [ (a + beta·xi + gamma)(b + beta·xi·k1 + gamma)(c + beta·xi·k2 + gamma)z - // - (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma)zω ] / Z_H(xi) - - // Compute T1(xi) - if (logger) logger.info("··· Computing T1(xi)"); - let t1 = Fr.sub(proof.evaluations.z, Fr.one); - t1 = Fr.mul(t1, lagrange1); - t1 = Fr.mul(t1, challenges.invzh); - - // Compute T2(xi) - if (logger) logger.info("··· Computing T2(xi)"); - const betaxi = Fr.mul(challenges.beta, challenges.xi); - const t211 = Fr.add(proof.evaluations.a, Fr.add(betaxi, challenges.gamma)); - const t212 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(betaxi, vk.k1), challenges.gamma)); - const t213 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(betaxi, vk.k2), challenges.gamma)); - const t21 = Fr.mul(t211, Fr.mul(t212, Fr.mul(t213, proof.evaluations.z))); - - const t221 = Fr.add(proof.evaluations.a, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s1), challenges.gamma)); - const t222 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s2), challenges.gamma)); - const t223 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s3), challenges.gamma)); - const t22 = Fr.mul(t221, Fr.mul(t222, Fr.mul(t223, proof.evaluations.zw))); - - let t2 = Fr.sub(t21, t22); - t2 = Fr.mul(t2, challenges.invzh); - - // Compute the 6 C2 values - if (logger) logger.info("··· Computing C2(h_2ω_3^i) values"); - let res = Fr.zero; - for (let i = 0; i < 3; i++) { - let c2 = Fr.add(proof.evaluations.z, Fr.mul(roots.S2.h2w3[i], t1)); - c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h2w3[i]), t2)); - - res = Fr.add(res, Fr.mul(c2, LiS2[i])); - } - - if (logger) logger.info("··· Computing C2(h_3ω_3^i) values"); - for (let i = 0; i < 3; i++) { - let c2 = Fr.add(proof.evaluations.zw, Fr.mul(roots.S2.h3w3[i], proof.evaluations.t1w)); - c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h3w3[i]), proof.evaluations.t2w)); - - res = Fr.add(res, Fr.mul(c2, LiS2[i + 3])); - } - - return res; -} - + const Fr = curve.Fr; + const LiS2 = computeLagrangeLiS2([roots.S2.h2w3, roots.S2.h3w3], challenges.y, challenges.xi, challenges.xiw, curve); + if (logger) logger.info("··· Computing T1(xi)"); + let t1 = Fr.sub(proof.evaluations.z, Fr.one); + t1 = Fr.mul(t1, lagrange1); + t1 = Fr.mul(t1, challenges.invzh); + if (logger) logger.info("··· Computing T2(xi)"); + const betaxi = Fr.mul(challenges.beta, challenges.xi); + const t211 = Fr.add(proof.evaluations.a, Fr.add(betaxi, challenges.gamma)); + const t212 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(betaxi, vk.k1), challenges.gamma)); + const t213 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(betaxi, vk.k2), challenges.gamma)); + const t21 = Fr.mul(t211, Fr.mul(t212, Fr.mul(t213, proof.evaluations.z))); + const t221 = Fr.add(proof.evaluations.a, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s1), challenges.gamma)); + const t222 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s2), challenges.gamma)); + const t223 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s3), challenges.gamma)); + const t22 = Fr.mul(t221, Fr.mul(t222, Fr.mul(t223, proof.evaluations.zw))); + let t2 = Fr.sub(t21, t22); + t2 = Fr.mul(t2, challenges.invzh); + if (logger) logger.info("··· Computing C2(h_2ω_3^i) values"); + let res = Fr.zero; + for (let i = 0; i < 3; i++) { + let c2 = Fr.add(proof.evaluations.z, Fr.mul(roots.S2.h2w3[i], t1)); + c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h2w3[i]), t2)); + res = Fr.add(res, Fr.mul(c2, LiS2[i])); + } + if (logger) logger.info("··· Computing C2(h_3ω_3^i) values"); + for (let i = 0; i < 3; i++) { + let c2 = Fr.add(proof.evaluations.zw, Fr.mul(roots.S2.h3w3[i], proof.evaluations.t1w)); + c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h3w3[i]), proof.evaluations.t2w)); + res = Fr.add(res, Fr.mul(c2, LiS2[i + 3])); + } + return res; +} function computeF(curve, proof, vk, challenges, roots) { - const G1 = curve.G1; - const Fr = curve.Fr; - - let mulH0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); - for (let i = 1; i < 8; i++) { - mulH0 = Fr.mul(mulH0, Fr.sub(challenges.y, roots.S0.h0w8[i])); - } - - challenges.temp = mulH0; - - let mulH1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); - for (let i = 1; i < 4; i++) { - mulH1 = Fr.mul(mulH1, Fr.sub(challenges.y, roots.S1.h1w4[i])); - } - - let mulH2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); - for (let i = 1; i < 3; i++) { - mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h2w3[i])); - } - for (let i = 0; i < 3; i++) { - mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h3w3[i])); - } - - challenges.quotient1 = Fr.mul(challenges.alpha, Fr.div(mulH0, mulH1)); - challenges.quotient2 = Fr.mul(Fr.square(challenges.alpha), Fr.div(mulH0, mulH2)); - - let F2 = G1.timesFr(proof.polynomials.C1, challenges.quotient1); - let F3 = G1.timesFr(proof.polynomials.C2, challenges.quotient2); - - return G1.add(vk.C0, G1.add(F2, F3)); -} - + const G1 = curve.G1; + const Fr = curve.Fr; + let mulH0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); + for (let i = 1; i < 8; i++) mulH0 = Fr.mul(mulH0, Fr.sub(challenges.y, roots.S0.h0w8[i])); + challenges.temp = mulH0; + let mulH1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); + for (let i = 1; i < 4; i++) mulH1 = Fr.mul(mulH1, Fr.sub(challenges.y, roots.S1.h1w4[i])); + let mulH2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); + for (let i = 1; i < 3; i++) mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h2w3[i])); + for (let i = 0; i < 3; i++) mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h3w3[i])); + challenges.quotient1 = Fr.mul(challenges.alpha, Fr.div(mulH0, mulH1)); + challenges.quotient2 = Fr.mul(Fr.square(challenges.alpha), Fr.div(mulH0, mulH2)); + let F2 = G1.timesFr(proof.polynomials.C1, challenges.quotient1); + let F3 = G1.timesFr(proof.polynomials.C2, challenges.quotient2); + return G1.add(vk.C0, G1.add(F2, F3)); +} function computeE(curve, proof, challenges, vk, r0, r1, r2) { - const G1 = curve.G1; - const Fr = curve.Fr; - - let E2 = Fr.mul(r1, challenges.quotient1); - let E3 = Fr.mul(r2, challenges.quotient2); - - return G1.timesFr(G1.one, Fr.add(r0, Fr.add(E2, E3))); -} - + const G1 = curve.G1; + const Fr = curve.Fr; + let E2 = Fr.mul(r1, challenges.quotient1); + let E3 = Fr.mul(r2, challenges.quotient2); + return G1.timesFr(G1.one, Fr.add(r0, Fr.add(E2, E3))); +} function computeJ(curve, proof, challenges) { - const G1 = curve.G1; - - return G1.timesFr(proof.polynomials.W1, challenges.temp); + return curve.G1.timesFr(proof.polynomials.W1, challenges.temp); } - async function isValidPairing(curve, proof, challenges, vk, F, E, J) { - const G1 = curve.G1; - - let A1 = G1.timesFr(proof.polynomials.W2, challenges.y); - A1 = G1.add(G1.sub(G1.sub(F, E), J), A1); - const A2 = curve.G2.one; - - const B1 = proof.polynomials.W2; - const B2 = vk.X_2; - - return await curve.pairingEq(G1.neg(A1), A2, B1, B2); -} - - + const G1 = curve.G1; + let A1 = G1.timesFr(proof.polynomials.W2, challenges.y); + A1 = G1.add(G1.sub(G1.sub(F, E), J), A1); + const A2 = curve.G2.one; + const B1 = proof.polynomials.W2; + const B2 = vk.X_2; + return await curve.pairingEq(G1.neg(A1), A2, B1, B2); +} function computeLagrangeLiSi(roots, x, xi, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const num = Fr.sub(Fr.exp(x, len), xi); - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - Li[i] = Fr.div(num, Fr.mul(Fr.mul(den1, den2), den3)); - } - - return Li; -} - + const Fr = curve.Fr; + const len = roots.length; + const num = Fr.sub(Fr.exp(x, len), xi); + const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); + const Li = []; + for (let i = 0; i < len; i++) { + const den2 = roots[(len - 1) * i % len]; + const den3 = Fr.sub(x, roots[i]); + Li[i] = Fr.div(num, Fr.mul(Fr.mul(den1, den2), den3)); + } + return Li; +} function computeLagrangeLiS2(roots, value, xi0, xi1, curve) { - const Fr = curve.Fr; - - const Li = []; - - const len = roots[0].length; - const n = len * roots.length; - - const num1 = Fr.exp(value, n); - const num2 = Fr.mul(Fr.add(xi0, xi1), Fr.exp(value, len)); - const num3 = Fr.mul(xi0, xi1); - const num = Fr.add(Fr.sub(num1, num2), num3); - - let den1 = Fr.mul(Fr.mul(Fr.e(len), roots[0][0]), Fr.sub(xi0, xi1)); - for (let i = 0; i < len; i++) { - const den2 = roots[0][(len - 1) * i % len]; - const den3 = Fr.sub(value, roots[0][i]); - - const den = Fr.mul(den1,Fr.mul(den2, den3)); - - Li[i] = Fr.div(num, den); - } - - den1 = Fr.mul(Fr.mul(Fr.e(len), roots[1][0]), Fr.sub(xi1, xi0)); - for (let i = 0; i < len; i++) { - const den2 = roots[1][(len - 1) * i % len]; - const den3 = Fr.sub(value, roots[1][i]); - - const den = Fr.mul(den1,Fr.mul(den2, den3)); - - Li[i + len] = Fr.div(num, den); - } - - return Li; -} - -/* - Copyright 2021 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const {unstringifyBigInts: unstringifyBigInts$1} = ffjavascript.utils; - + const Fr = curve.Fr; + const Li = []; + const len = roots[0].length; + const n = len * roots.length; + const num1 = Fr.exp(value, n); + const num2 = Fr.mul(Fr.add(xi0, xi1), Fr.exp(value, len)); + const num3 = Fr.mul(xi0, xi1); + const num = Fr.add(Fr.sub(num1, num2), num3); + let den1 = Fr.mul(Fr.mul(Fr.e(len), roots[0][0]), Fr.sub(xi0, xi1)); + for (let i = 0; i < len; i++) { + const den2 = roots[0][(len - 1) * i % len]; + const den3 = Fr.sub(value, roots[0][i]); + const den = Fr.mul(den1, Fr.mul(den2, den3)); + Li[i] = Fr.div(num, den); + } + den1 = Fr.mul(Fr.mul(Fr.e(len), roots[1][0]), Fr.sub(xi1, xi0)); + for (let i = 0; i < len; i++) { + const den2 = roots[1][(len - 1) * i % len]; + const den3 = Fr.sub(value, roots[1][i]); + const den = Fr.mul(den1, Fr.mul(den2, den3)); + Li[i + len] = Fr.div(num, den); + } + return Li; +} +//#endregion +//#region src/fflonk_export_calldata.js +var { unstringifyBigInts: unstringifyBigInts$1 } = ffjavascript.utils; function p256(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0" + nstr; - nstr = `0x${nstr}`; - return nstr; + let nstr = n.toString(16); + while (nstr.length < 64) nstr = "0" + nstr; + nstr = `0x${nstr}`; + return nstr; } - async function fflonkExportCallData(_pub, _proof) { - const proof = unstringifyBigInts$1(_proof); - const pub = unstringifyBigInts$1(_pub); - - await getCurveFromName(proof.curve); - - let inputs = ""; - for (let i = 0; i < pub.length; i++) { - if (inputs !== "") inputs = inputs + ","; - inputs = inputs + p256(pub[i]); - } - - return `[${p256(proof.polynomials.C1[0])}, ${p256(proof.polynomials.C1[1])},` + - `${p256(proof.polynomials.C2[0])},${p256(proof.polynomials.C2[1])},` + - `${p256(proof.polynomials.W1[0])},${p256(proof.polynomials.W1[1])},` + - `${p256(proof.polynomials.W2[0])},${p256(proof.polynomials.W2[1])},` + - `${p256(proof.evaluations.ql)},${p256(proof.evaluations.qr)},${p256(proof.evaluations.qm)},` + - `${p256(proof.evaluations.qo)},${p256(proof.evaluations.qc)},${p256(proof.evaluations.s1)},` + - `${p256(proof.evaluations.s2)},${p256(proof.evaluations.s3)},${p256(proof.evaluations.a)},` + - `${p256(proof.evaluations.b)},${p256(proof.evaluations.c)},${p256(proof.evaluations.z)},` + - `${p256(proof.evaluations.zw)},${p256(proof.evaluations.t1w)},${p256(proof.evaluations.t2w)},` + - `${p256(proof.evaluations.inv)}],` + - `[${inputs}]`; -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const {unstringifyBigInts} = ffjavascript.utils; - - + const proof = unstringifyBigInts$1(_proof); + const pub = unstringifyBigInts$1(_pub); + await getCurveFromName(proof.curve); + let inputs = ""; + for (let i = 0; i < pub.length; i++) { + if (inputs !== "") inputs = inputs + ","; + inputs = inputs + p256(pub[i]); + } + return `[${p256(proof.polynomials.C1[0])}, ${p256(proof.polynomials.C1[1])},${p256(proof.polynomials.C2[0])},${p256(proof.polynomials.C2[1])},${p256(proof.polynomials.W1[0])},${p256(proof.polynomials.W1[1])},${p256(proof.polynomials.W2[0])},${p256(proof.polynomials.W2[1])},${p256(proof.evaluations.ql)},${p256(proof.evaluations.qr)},${p256(proof.evaluations.qm)},${p256(proof.evaluations.qo)},${p256(proof.evaluations.qc)},${p256(proof.evaluations.s1)},${p256(proof.evaluations.s2)},${p256(proof.evaluations.s3)},${p256(proof.evaluations.a)},${p256(proof.evaluations.b)},${p256(proof.evaluations.c)},${p256(proof.evaluations.z)},${p256(proof.evaluations.zw)},${p256(proof.evaluations.t1w)},${p256(proof.evaluations.t2w)},${p256(proof.evaluations.inv)}],[${inputs}]`; +} +//#endregion +//#region src/wtns_debug.js +var { unstringifyBigInts } = ffjavascript.utils; async function wtnsDebug$1(_input, wasmFileName, wtnsFileName, symName, options, logger) { - - const input = unstringifyBigInts(_input); - - const fdWasm = await fastFile__namespace.readExisting(wasmFileName); - const wasm = await fdWasm.read(fdWasm.totalSize); - await fdWasm.close(); - - const wcOps = {...options, sanityCheck: true}; - let sym = await loadSymbols(symName); - if (options.set) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logSetSignal= function(labelIdx, value) { - // The line below splits the arrow log into 2 strings to avoid some Secure ECMAScript issues - if (logger) logger.info("SET " + sym.labelIdx2Name[labelIdx] + " <" + "-- " + value.toString()); - }; - } - if (options.get) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logGetSignal= function(varIdx, value) { - // The line below splits the arrow log into 2 strings to avoid some Secure ECMAScript issues - if (logger) logger.info("GET " + sym.labelIdx2Name[varIdx] + " --" + "> " + value.toString()); - }; - } - if (options.trigger) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logStartComponent= function(cIdx) { - if (logger) logger.info("START: " + sym.componentIdx2Name[cIdx]); - }; - wcOps.logFinishComponent= function(cIdx) { - if (logger) logger.info("FINISH: " + sym.componentIdx2Name[cIdx]); - }; - } - wcOps.sym = sym; - - const wc = await circom_runtime.WitnessCalculatorBuilder(wasm, wcOps); - const w = await wc.calculateWitness(input, true); - - const fdWtns = await binFileUtils__namespace.createBinFile(wtnsFileName, "wtns", 2, 2); - - await write(fdWtns, w, wc.prime); - - await fdWtns.close(); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const input = unstringifyBigInts(_input); + const fdWasm = await fastfile.readExisting(wasmFileName); + const wasm = await fdWasm.read(fdWasm.totalSize); + await fdWasm.close(); + const wcOps = { + ...options, + sanityCheck: true + }; + let sym = await loadSymbols(symName); + if (options.set) { + if (!sym) sym = await loadSymbols(symName); + wcOps.logSetSignal = function(labelIdx, value) { + if (logger) logger.info("SET " + sym.labelIdx2Name[labelIdx] + " <-- " + value.toString()); + }; + } + if (options.get) { + if (!sym) sym = await loadSymbols(symName); + wcOps.logGetSignal = function(varIdx, value) { + if (logger) logger.info("GET " + sym.labelIdx2Name[varIdx] + " --> " + value.toString()); + }; + } + if (options.trigger) { + if (!sym) sym = await loadSymbols(symName); + wcOps.logStartComponent = function(cIdx) { + if (logger) logger.info("START: " + sym.componentIdx2Name[cIdx]); + }; + wcOps.logFinishComponent = function(cIdx) { + if (logger) logger.info("FINISH: " + sym.componentIdx2Name[cIdx]); + }; + } + wcOps.sym = sym; + const wc = await (0, circom_runtime.WitnessCalculatorBuilder)(wasm, wcOps); + const w = await wc.calculateWitness(input, true); + const fdWtns = await _iden3_binfileutils.createBinFile(wtnsFileName, "wtns", 2, 2); + await write(fdWtns, w, wc.prime); + await fdWtns.close(); +} +//#endregion +//#region src/wtns_export_json.js async function wtnsExportJson$1(wtnsFileName) { - - const w = await read(wtnsFileName); - - return w; -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + return await read(wtnsFileName); +} +//#endregion +//#region src/wtns_check.js async function wtnsCheck$1(r1csFilename, wtnsFilename, logger) { - - if (logger) logger.info("WITNESS CHECKING STARTED"); - - // Read r1cs file - if (logger) logger.info("> Reading r1cs file"); - const { - fd: fdR1cs, - sections: sectionsR1cs - } = await binFileUtils__namespace.readBinFile(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); - const r1cs = await r1csfile.readR1csFd(fdR1cs, sectionsR1cs, { loadConstraints: false, loadCustomGates: false }); - - // Read witness file - if (logger) logger.info("> Reading witness file"); - const { - fd: fdWtns, - sections: wtnsSections - } = await binFileUtils__namespace.readBinFile(wtnsFilename, "wtns", 2, 1 << 22, 1 << 24); - const wtnsHeader = await readHeader(fdWtns, wtnsSections); - - if (!ffjavascript.Scalar.eq(r1cs.prime, wtnsHeader.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - const buffWitness = await binFileUtils__namespace.readSection(fdWtns, wtnsSections, 2); - await fdWtns.close(); - - const curve = await getCurveFromR(r1cs.prime); - const Fr = curve.Fr; - const sFr = Fr.n8; - - const bR1cs = await binFileUtils__namespace.readSection(fdR1cs, sectionsR1cs, 2); - - if (logger) { - logger.info("----------------------------"); - logger.info(" WITNESS CHECK"); - logger.info(` Curve: ${r1cs.curve.name}`); - logger.info(` Vars (wires): ${r1cs.nVars}`); - logger.info(` Outputs: ${r1cs.nOutputs}`); - logger.info(` Public Inputs: ${r1cs.nPubInputs}`); - logger.info(` Private Inputs: ${r1cs.nPrvInputs}`); - logger.info(` Labels: ${r1cs.nLabels}`); - logger.info(` Constraints: ${r1cs.nConstraints}`); - logger.info(` Custom Gates: ${r1cs.useCustomGates}`); - logger.info("----------------------------"); - } - - if (logger) logger.info("> Checking witness correctness"); - - let bR1csPos = 0; - let res = true; - for (let i = 0; i < r1cs.nConstraints; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(`··· processing r1cs constraints ${i}/${r1cs.nConstraints}`); - } - - //Read the three linear combinations of the constraint where A * B - C = 0 - const lcA = readLC(); - const lcB = readLC(); - const lcC = readLC(); - - // Evaluate the linear combinations - const evalA = EvaluateLinearCombination(lcA); - const evalB = EvaluateLinearCombination(lcB); - const evalC = EvaluateLinearCombination(lcC); - - // Check that A * B - C == 0 - if (!Fr.eq(Fr.sub(Fr.mul(evalA, evalB), evalC), Fr.zero)) { - logger.warn("··· aborting checking process at constraint " + i); - res = false; - break; - } - } - - fdR1cs.close(); - - if (logger) { - if (res) { - logger.info("WITNESS IS CORRECT"); - logger.info("WITNESS CHECKING FINISHED SUCCESSFULLY"); - } else { - logger.warn("WITNESS IS NOT CORRECT"); - logger.warn("WITNESS CHECKING FINISHED UNSUCCESSFULLY"); - } - } - - return res; - - function EvaluateLinearCombination(lc) { - let res = Fr.zero; - - const keys = Object.keys(lc); - keys.forEach((signalId) => { - const signalValue = getWitnessValue(signalId); - const signalFactor = lc[signalId]; - - res = Fr.add(res, Fr.mul(signalValue, signalFactor)); - }); - - return res; - } - - function readLC() { - const lc = {}; - - const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); - bR1csPos += 4; - const buffUL32V = new DataView(buffUL32.buffer); - const nIdx = buffUL32V.getUint32(0, true); - - const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); - bR1csPos += (4 + r1cs.n8) * nIdx; - const buffV = new DataView(buff.buffer); - for (let i = 0; i < nIdx; i++) { - const idx = buffV.getUint32(i * (4 + r1cs.n8), true); - const val = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); - lc[idx] = val; - } - return lc; - } - - function getWitnessValue(signalId) { - return Fr.fromRprLE(buffWitness.slice(signalId * sFr, signalId * sFr + sFr)); - } -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const {stringifyBigInts} = ffjavascript.utils; - -const logger = Logger.create("snarkJS", {showTimestamp: false}); -Logger.setLogLevel("INFO"); -// const logger = console; -// const Logger = { -// setLogLevel: function (x) {} -// }; - -const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)))); - -const commands = [ - { - cmd: "powersoftau new [powersoftau_0000.ptau]", - description: "Starts a powers of tau ceremony", - alias: ["ptn"], - options: "-verbose|v", - action: powersOfTauNew - }, - { - cmd: "powersoftau contribute ", - description: "creates a ptau file with a new contribution", - alias: ["ptc"], - options: "-verbose|v -name|n -entropy|e", - action: powersOfTauContribute - }, - { - cmd: "powersoftau export challenge [challenge]", - description: "Creates a challenge", - alias: ["ptec"], - options: "-verbose|v", - action: powersOfTauExportChallenge - }, - { - cmd: "powersoftau challenge contribute [response]", - description: "Contribute to a challenge", - alias: ["ptcc"], - options: "-verbose|v -entropy|e", - action: powersOfTauChallengeContribute - }, - { - cmd: "powersoftau import response <", - description: "import a response to a ptau file", - alias: ["ptir"], - options: "-verbose|v -nopoints -nocheck -name|n", - action: powersOfTauImport - }, - { - cmd: "powersoftau beacon ", - description: "adds a beacon", - alias: ["ptb"], - options: "-verbose|v -name|n", - action: powersOfTauBeacon - }, - { - cmd: "powersoftau prepare phase2 ", - description: "Prepares phase 2. ", - longDescription: " This process calculates the evaluation of the Lagrange polinomials at tau for alpha*tau and beta tau", - alias: ["pt2"], - options: "-verbose|v", - action: powersOfTauPreparePhase2 - }, - { - cmd: "powersoftau convert ", - description: "Convert ptau", - longDescription: " This process calculates the evaluation of the Lagrange polinomials at tau for alpha*tau and beta tau", - alias: ["ptcv"], - options: "-verbose|v", - action: powersOfTauConvert - }, - { - cmd: "powersoftau truncate ", - description: "Generate different powers of tau with smaller sizes ", - longDescription: " This process generates smaller ptau files from a bigger power ptau", - alias: ["ptt"], - options: "-verbose|v", - action: powersOfTauTruncate - }, - { - cmd: "powersoftau verify ", - description: "verifies a powers of tau file", - alias: ["ptv"], - options: "-verbose|v", - action: powersOfTauVerify - }, - { - cmd: "powersoftau export json ", - description: "Exports a power of tau file to a JSON", - alias: ["ptej"], - options: "-verbose|v", - action: powersOfTauExportJson - }, - { - cmd: "r1cs info [circuit.r1cs]", - description: "Print statistiscs of a circuit", - alias: ["ri", "info -r|r1cs:circuit.r1cs"], - action: r1csInfo - }, - { - cmd: "r1cs print [circuit.r1cs] [circuit.sym]", - description: "Print the constraints of a circuit", - alias: ["rp", "print -r|r1cs:circuit.r1cs -s|sym"], - action: r1csPrint - }, - { - cmd: "r1cs export json [circuit.r1cs] [circuit.json]", - description: "Export r1cs to JSON file", - alias: ["rej"], - action: r1csExportJSON - }, - { - cmd: "wtns calculate [circuit.wasm] [input.json] [witness.wtns]", - description: "Caclculate specific witness of a circuit given an input", - alias: ["wc", "calculatewitness -ws|wasm:circuit.wasm -i|input:input.json -wt|witness:witness.wtns"], - action: wtnsCalculate - }, - { - cmd: "wtns debug [circuit.wasm] [input.json] [witness.wtns] [circuit.sym]", - description: "Calculate the witness with debug info.", - longDescription: "Calculate the witness with debug info. \nOptions:\n-g or --g : Log signal gets\n-s or --s : Log signal sets\n-t or --trigger : Log triggers ", - options: "-get|g -set|s -trigger|t", - alias: ["wd"], - action: wtnsDebug - }, - { - cmd: "wtns export json [witness.wtns] [witnes.json]", - description: "Calculate the witness with debug info.", - longDescription: "Calculate the witness with debug info. \nOptions:\n-g or --g : Log signal gets\n-s or --s : Log signal sets\n-t or --trigger : Log triggers ", - options: "-verbose|v", - alias: ["wej"], - action: wtnsExportJson - }, - { - cmd: "wtns check [circuit.r1cs] [[witness.wtns]", - description: "Check if a specific witness of a circuit fulfills the r1cs constraints", - alias: ["wchk"], - action: wtnsCheck - }, - { - cmd: "zkey contribute ", - description: "creates a zkey file with a new contribution", - alias: ["zkc"], - options: "-verbose|v -entropy|e -name|n", - action: zkeyContribute - }, - { - cmd: "zkey export bellman [circuit.mpcparams]", - description: "Export a zKey to a MPCParameters file compatible with kobi/phase2 (Bellman)", - alias: ["zkeb"], - options: "-verbose|v", - action: zkeyExportBellman - }, - { - cmd: "zkey bellman contribute ", - description: "contributes to a challenge file in bellman format", - alias: ["zkbc"], - options: "-verbose|v -entropy|e", - action: zkeyBellmanContribute - }, - { - cmd: "zkey import bellman ", - description: "Export a zKey to a MPCParameters file compatible with kobi/phase2 (Bellman) ", - alias: ["zkib"], - options: "-verbose|v -name|n", - action: zkeyImportBellman - }, - { - cmd: "zkey beacon ", - description: "adds a beacon", - alias: ["zkb"], - options: "-verbose|v -name|n", - action: zkeyBeacon - }, - { - cmd: "zkey verify r1cs [circuit.r1cs] [powersoftau.ptau] [circuit_final.zkey]", - description: "Verify zkey file contributions and verify that matches with the original circuit.r1cs and ptau", - alias: ["zkv", "zkvr", "zkey verify"], - options: "-verbose|v", - action: zkeyVerifyFromR1cs - }, - { - cmd: "zkey verify init [circuit_0000.zkey] [powersoftau.ptau] [circuit_final.zkey]", - description: "Verify zkey file contributions and verify that matches with the original circuit.r1cs and ptau", - alias: ["zkvi"], - options: "-verbose|v", - action: zkeyVerifyFromInit - }, - { - cmd: "zkey export verificationkey [circuit_final.zkey] [verification_key.json]", - description: "Exports a verification key", - alias: ["zkev"], - action: zkeyExportVKey - }, - { - cmd: "zkey export json [circuit_final.zkey] [circuit_final.zkey.json]", - description: "Exports a circuit key to a JSON file", - alias: ["zkej"], - options: "-verbose|v", - action: zkeyExportJson - }, - { - cmd: "zkey export solidityverifier [circuit_final.zkey] [verifier.sol]", - description: "Creates a verifier in solidity", - alias: ["zkesv", "generateverifier -vk|verificationkey -v|verifier"], - action: zkeyExportSolidityVerifier - }, - { - cmd: "zkey export soliditycalldata [public.json] [proof.json]", - description: "Generates call parameters ready to be called.", - alias: ["zkesc", "generatecall -pub|public -p|proof"], - action: zkeyExportSolidityCalldata - }, - { - cmd: "groth16 setup [circuit.r1cs] [powersoftau.ptau] [circuit_0000.zkey]", - description: "Creates an initial groth16 pkey file with zero contributions", - alias: ["g16s", "zkn", "zkey new"], - options: "-verbose|v", - action: zkeyNew - }, - { - cmd: "groth16 prove [circuit_final.zkey] [witness.wtns] [proof.json] [public.json]", - description: "Generates a zk Proof from witness", - alias: ["g16p", "zpw", "zksnark proof", "proof -pk|provingkey -wt|witness -p|proof -pub|public"], - options: "-verbose|v -protocol -buildabc -memlog", - action: groth16Prove - }, - { - cmd: "groth16 fullprove [input.json] [circuit_final.wasm] [circuit_final.zkey] [proof.json] [public.json]", - description: "Generates a zk Proof from input", - alias: ["g16f", "g16i"], - options: "-verbose|v -protocol -buildabc -memlog", - action: groth16FullProve - }, - { - cmd: "groth16 verify [verification_key.json] [public.json] [proof.json]", - description: "Verify a zk Proof", - alias: ["g16v", "verify -vk|verificationkey -pub|public -p|proof"], - action: groth16Verify - }, - { - cmd: "plonk setup [circuit.r1cs] [powersoftau.ptau] [circuit.zkey]", - description: "Creates an initial PLONK pkey ", - alias: ["pks"], - options: "-verbose|v", - action: plonkSetup - }, - { - cmd: "plonk prove [circuit.zkey] [witness.wtns] [proof.json] [public.json]", - description: "Generates a PLONK Proof from witness", - alias: ["pkp"], - options: "-verbose|v -protocol", - action: plonkProve - }, - { - cmd: "plonk fullprove [input.json] [circuit.wasm] [circuit.zkey] [proof.json] [public.json]", - description: "Generates a PLONK Proof from input", - alias: ["pkf"], - options: "-verbose|v -protocol", - action: plonkFullProve - }, - { - cmd: "plonk verify [verification_key.json] [public.json] [proof.json]", - description: "Verify a PLONK Proof", - alias: ["pkv"], - options: "-verbose|v", - action: plonkVerify - }, - { - cmd: "fflonk setup [circuit.r1cs] [powersoftau.ptau] [circuit.zkey]", - description: "BETA version. Creates a FFLONK zkey from a circuit", - alias: ["ffs"], - options: "-verbose|v", - action: fflonkSetup - }, - { - cmd: "fflonk prove [circuit.zkey] [witness.wtns] [proof.json] [public.json]", - description: "BETA version. Generates a FFLONK Proof from witness", - alias: ["ffp"], - options: "-verbose|v -protocol", - action: fflonkProve - }, - { - cmd: "fflonk fullprove [witness.json] [circuit.wasm] [circuit.zkey] [proof.json] [public.json]", - description: "BETA version. Generates a witness and the FFLONK Proof in the same command", - alias: ["fff"], - options: "-verbose|v -protocol", - action: fflonkFullProve - }, - { - cmd: "fflonk verify [verification_key.json] [public.json] [proof.json]", - description: "BETA version. Verify a FFLONK Proof", - alias: ["ffv"], - options: "-verbose|v", - action: fflonkVerify - }, - { - cmd: "file info [binary.file]", - description: "Check info of a binary file", - alias: ["fi"], - action: fileInfo - } -]; - - -clProcessor(commands).then((res) => { - process.exit(res); + if (logger) logger.info("WITNESS CHECKING STARTED"); + if (logger) logger.info("> Reading r1cs file"); + const { fd: fdR1cs, sections: sectionsR1cs } = await _iden3_binfileutils.readBinFile(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); + const r1cs = await (0, r1csfile.readR1csFd)(fdR1cs, sectionsR1cs, { + loadConstraints: false, + loadCustomGates: false + }); + if (logger) logger.info("> Reading witness file"); + const { fd: fdWtns, sections: wtnsSections } = await _iden3_binfileutils.readBinFile(wtnsFilename, "wtns", 2, 1 << 22, 1 << 24); + const wtnsHeader = await readHeader(fdWtns, wtnsSections); + if (!ffjavascript.Scalar.eq(r1cs.prime, wtnsHeader.q)) throw new Error("Curve of the witness does not match the curve of the proving key"); + const buffWitness = await _iden3_binfileutils.readSection(fdWtns, wtnsSections, 2); + await fdWtns.close(); + const Fr = (await getCurveFromR(r1cs.prime)).Fr; + const sFr = Fr.n8; + const bR1cs = await _iden3_binfileutils.readSection(fdR1cs, sectionsR1cs, 2); + if (logger) { + logger.info("----------------------------"); + logger.info(" WITNESS CHECK"); + logger.info(` Curve: ${r1cs.curve.name}`); + logger.info(` Vars (wires): ${r1cs.nVars}`); + logger.info(` Outputs: ${r1cs.nOutputs}`); + logger.info(` Public Inputs: ${r1cs.nPubInputs}`); + logger.info(` Private Inputs: ${r1cs.nPrvInputs}`); + logger.info(` Labels: ${r1cs.nLabels}`); + logger.info(` Constraints: ${r1cs.nConstraints}`); + logger.info(` Custom Gates: ${r1cs.useCustomGates}`); + logger.info("----------------------------"); + } + if (logger) logger.info("> Checking witness correctness"); + let bR1csPos = 0; + let res = true; + for (let i = 0; i < r1cs.nConstraints; i++) { + if (logger && i !== 0 && i % 5e5 === 0) logger.info(`··· processing r1cs constraints ${i}/${r1cs.nConstraints}`); + const lcA = readLC(); + const lcB = readLC(); + const lcC = readLC(); + const evalA = EvaluateLinearCombination(lcA); + const evalB = EvaluateLinearCombination(lcB); + const evalC = EvaluateLinearCombination(lcC); + if (!Fr.eq(Fr.sub(Fr.mul(evalA, evalB), evalC), Fr.zero)) { + logger.warn("··· aborting checking process at constraint " + i); + res = false; + break; + } + } + fdR1cs.close(); + if (logger) if (res) { + logger.info("WITNESS IS CORRECT"); + logger.info("WITNESS CHECKING FINISHED SUCCESSFULLY"); + } else { + logger.warn("WITNESS IS NOT CORRECT"); + logger.warn("WITNESS CHECKING FINISHED UNSUCCESSFULLY"); + } + return res; + function EvaluateLinearCombination(lc) { + let res = Fr.zero; + Object.keys(lc).forEach((signalId) => { + const signalValue = getWitnessValue(signalId); + const signalFactor = lc[signalId]; + res = Fr.add(res, Fr.mul(signalValue, signalFactor)); + }); + return res; + } + function readLC() { + const lc = {}; + const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); + bR1csPos += 4; + const nIdx = new DataView(buffUL32.buffer).getUint32(0, true); + const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); + bR1csPos += (4 + r1cs.n8) * nIdx; + const buffV = new DataView(buff.buffer); + for (let i = 0; i < nIdx; i++) { + const idx = buffV.getUint32(i * (4 + r1cs.n8), true); + lc[idx] = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); + } + return lc; + } + function getWitnessValue(signalId) { + return Fr.fromRprLE(buffWitness.slice(signalId * sFr, signalId * sFr + sFr)); + } +} +//#endregion +//#region cli.js +var { stringifyBigInts } = ffjavascript.utils; +var logger = logplease.default.create("snarkJS", { showTimestamp: false }); +logplease.default.setLogLevel("INFO"); +var __dirname$1 = path.default.dirname(url.default.fileURLToPath(require("url").pathToFileURL(__filename).href)); +clProcessor([ + { + cmd: "powersoftau new [powersoftau_0000.ptau]", + description: "Starts a powers of tau ceremony", + alias: ["ptn"], + options: "-verbose|v", + action: powersOfTauNew + }, + { + cmd: "powersoftau contribute ", + description: "creates a ptau file with a new contribution", + alias: ["ptc"], + options: "-verbose|v -name|n -entropy|e", + action: powersOfTauContribute + }, + { + cmd: "powersoftau export challenge [challenge]", + description: "Creates a challenge", + alias: ["ptec"], + options: "-verbose|v", + action: powersOfTauExportChallenge + }, + { + cmd: "powersoftau challenge contribute [response]", + description: "Contribute to a challenge", + alias: ["ptcc"], + options: "-verbose|v -entropy|e", + action: powersOfTauChallengeContribute + }, + { + cmd: "powersoftau import response <", + description: "import a response to a ptau file", + alias: ["ptir"], + options: "-verbose|v -nopoints -nocheck -name|n", + action: powersOfTauImport + }, + { + cmd: "powersoftau beacon ", + description: "adds a beacon", + alias: ["ptb"], + options: "-verbose|v -name|n", + action: powersOfTauBeacon + }, + { + cmd: "powersoftau prepare phase2 ", + description: "Prepares phase 2. ", + longDescription: " This process calculates the evaluation of the Lagrange polinomials at tau for alpha*tau and beta tau", + alias: ["pt2"], + options: "-verbose|v", + action: powersOfTauPreparePhase2 + }, + { + cmd: "powersoftau convert ", + description: "Convert ptau", + longDescription: " This process calculates the evaluation of the Lagrange polinomials at tau for alpha*tau and beta tau", + alias: ["ptcv"], + options: "-verbose|v", + action: powersOfTauConvert + }, + { + cmd: "powersoftau truncate ", + description: "Generate different powers of tau with smaller sizes ", + longDescription: " This process generates smaller ptau files from a bigger power ptau", + alias: ["ptt"], + options: "-verbose|v", + action: powersOfTauTruncate + }, + { + cmd: "powersoftau verify ", + description: "verifies a powers of tau file", + alias: ["ptv"], + options: "-verbose|v", + action: powersOfTauVerify + }, + { + cmd: "powersoftau export json ", + description: "Exports a power of tau file to a JSON", + alias: ["ptej"], + options: "-verbose|v", + action: powersOfTauExportJson + }, + { + cmd: "r1cs info [circuit.r1cs]", + description: "Print statistiscs of a circuit", + alias: ["ri", "info -r|r1cs:circuit.r1cs"], + action: r1csInfo + }, + { + cmd: "r1cs print [circuit.r1cs] [circuit.sym]", + description: "Print the constraints of a circuit", + alias: ["rp", "print -r|r1cs:circuit.r1cs -s|sym"], + action: r1csPrint + }, + { + cmd: "r1cs export json [circuit.r1cs] [circuit.json]", + description: "Export r1cs to JSON file", + alias: ["rej"], + action: r1csExportJSON + }, + { + cmd: "wtns calculate [circuit.wasm] [input.json] [witness.wtns]", + description: "Caclculate specific witness of a circuit given an input", + alias: ["wc", "calculatewitness -ws|wasm:circuit.wasm -i|input:input.json -wt|witness:witness.wtns"], + action: wtnsCalculate + }, + { + cmd: "wtns debug [circuit.wasm] [input.json] [witness.wtns] [circuit.sym]", + description: "Calculate the witness with debug info.", + longDescription: "Calculate the witness with debug info. \nOptions:\n-g or --g : Log signal gets\n-s or --s : Log signal sets\n-t or --trigger : Log triggers ", + options: "-get|g -set|s -trigger|t", + alias: ["wd"], + action: wtnsDebug + }, + { + cmd: "wtns export json [witness.wtns] [witnes.json]", + description: "Calculate the witness with debug info.", + longDescription: "Calculate the witness with debug info. \nOptions:\n-g or --g : Log signal gets\n-s or --s : Log signal sets\n-t or --trigger : Log triggers ", + options: "-verbose|v", + alias: ["wej"], + action: wtnsExportJson + }, + { + cmd: "wtns check [circuit.r1cs] [[witness.wtns]", + description: "Check if a specific witness of a circuit fulfills the r1cs constraints", + alias: ["wchk"], + action: wtnsCheck + }, + { + cmd: "zkey contribute ", + description: "creates a zkey file with a new contribution", + alias: ["zkc"], + options: "-verbose|v -entropy|e -name|n", + action: zkeyContribute + }, + { + cmd: "zkey export bellman [circuit.mpcparams]", + description: "Export a zKey to a MPCParameters file compatible with kobi/phase2 (Bellman)", + alias: ["zkeb"], + options: "-verbose|v", + action: zkeyExportBellman + }, + { + cmd: "zkey bellman contribute ", + description: "contributes to a challenge file in bellman format", + alias: ["zkbc"], + options: "-verbose|v -entropy|e", + action: zkeyBellmanContribute + }, + { + cmd: "zkey import bellman ", + description: "Export a zKey to a MPCParameters file compatible with kobi/phase2 (Bellman) ", + alias: ["zkib"], + options: "-verbose|v -name|n", + action: zkeyImportBellman + }, + { + cmd: "zkey beacon ", + description: "adds a beacon", + alias: ["zkb"], + options: "-verbose|v -name|n", + action: zkeyBeacon + }, + { + cmd: "zkey verify r1cs [circuit.r1cs] [powersoftau.ptau] [circuit_final.zkey]", + description: "Verify zkey file contributions and verify that matches with the original circuit.r1cs and ptau", + alias: [ + "zkv", + "zkvr", + "zkey verify" + ], + options: "-verbose|v", + action: zkeyVerifyFromR1cs + }, + { + cmd: "zkey verify init [circuit_0000.zkey] [powersoftau.ptau] [circuit_final.zkey]", + description: "Verify zkey file contributions and verify that matches with the original circuit.r1cs and ptau", + alias: ["zkvi"], + options: "-verbose|v", + action: zkeyVerifyFromInit + }, + { + cmd: "zkey export verificationkey [circuit_final.zkey] [verification_key.json]", + description: "Exports a verification key", + alias: ["zkev"], + action: zkeyExportVKey + }, + { + cmd: "zkey export json [circuit_final.zkey] [circuit_final.zkey.json]", + description: "Exports a circuit key to a JSON file", + alias: ["zkej"], + options: "-verbose|v", + action: zkeyExportJson + }, + { + cmd: "zkey export solidityverifier [circuit_final.zkey] [verifier.sol]", + description: "Creates a verifier in solidity", + alias: ["zkesv", "generateverifier -vk|verificationkey -v|verifier"], + action: zkeyExportSolidityVerifier + }, + { + cmd: "zkey export soliditycalldata [public.json] [proof.json]", + description: "Generates call parameters ready to be called.", + alias: ["zkesc", "generatecall -pub|public -p|proof"], + action: zkeyExportSolidityCalldata + }, + { + cmd: "groth16 setup [circuit.r1cs] [powersoftau.ptau] [circuit_0000.zkey]", + description: "Creates an initial groth16 pkey file with zero contributions", + alias: [ + "g16s", + "zkn", + "zkey new" + ], + options: "-verbose|v", + action: zkeyNew + }, + { + cmd: "groth16 prove [circuit_final.zkey] [witness.wtns] [proof.json] [public.json]", + description: "Generates a zk Proof from witness", + alias: [ + "g16p", + "zpw", + "zksnark proof", + "proof -pk|provingkey -wt|witness -p|proof -pub|public" + ], + options: "-verbose|v -protocol -buildabc -memlog", + action: groth16Prove + }, + { + cmd: "groth16 fullprove [input.json] [circuit_final.wasm] [circuit_final.zkey] [proof.json] [public.json]", + description: "Generates a zk Proof from input", + alias: ["g16f", "g16i"], + options: "-verbose|v -protocol -buildabc -memlog", + action: groth16FullProve + }, + { + cmd: "groth16 verify [verification_key.json] [public.json] [proof.json]", + description: "Verify a zk Proof", + alias: ["g16v", "verify -vk|verificationkey -pub|public -p|proof"], + action: groth16Verify + }, + { + cmd: "plonk setup [circuit.r1cs] [powersoftau.ptau] [circuit.zkey]", + description: "Creates an initial PLONK pkey ", + alias: ["pks"], + options: "-verbose|v", + action: plonkSetup + }, + { + cmd: "plonk prove [circuit.zkey] [witness.wtns] [proof.json] [public.json]", + description: "Generates a PLONK Proof from witness", + alias: ["pkp"], + options: "-verbose|v -protocol", + action: plonkProve + }, + { + cmd: "plonk fullprove [input.json] [circuit.wasm] [circuit.zkey] [proof.json] [public.json]", + description: "Generates a PLONK Proof from input", + alias: ["pkf"], + options: "-verbose|v -protocol", + action: plonkFullProve + }, + { + cmd: "plonk verify [verification_key.json] [public.json] [proof.json]", + description: "Verify a PLONK Proof", + alias: ["pkv"], + options: "-verbose|v", + action: plonkVerify + }, + { + cmd: "fflonk setup [circuit.r1cs] [powersoftau.ptau] [circuit.zkey]", + description: "BETA version. Creates a FFLONK zkey from a circuit", + alias: ["ffs"], + options: "-verbose|v", + action: fflonkSetup + }, + { + cmd: "fflonk prove [circuit.zkey] [witness.wtns] [proof.json] [public.json]", + description: "BETA version. Generates a FFLONK Proof from witness", + alias: ["ffp"], + options: "-verbose|v -protocol", + action: fflonkProve + }, + { + cmd: "fflonk fullprove [witness.json] [circuit.wasm] [circuit.zkey] [proof.json] [public.json]", + description: "BETA version. Generates a witness and the FFLONK Proof in the same command", + alias: ["fff"], + options: "-verbose|v -protocol", + action: fflonkFullProve + }, + { + cmd: "fflonk verify [verification_key.json] [public.json] [proof.json]", + description: "BETA version. Verify a FFLONK Proof", + alias: ["ffv"], + options: "-verbose|v", + action: fflonkVerify + }, + { + cmd: "file info [binary.file]", + description: "Check info of a binary file", + alias: ["fi"], + action: fileInfo + } +]).then((res) => { + process.exit(res); }, (err) => { - logger.error(err); - process.exit(1); + logger.error(err); + process.exit(1); }); - -/* - -TODO COMMANDS -============= - - { - cmd: "zksnark setup [circuit.r1cs] [circuit.zkey] [verification_key.json]", - description: "Run a simple setup for a circuit generating the proving key.", - alias: ["zs", "setup -r1cs|r -provingkey|pk -verificationkey|vk"], - options: "-verbose|v -protocol", - action: zksnarkSetup - }, - { - cmd: "witness verify ", - description: "Verify a witness against a r1cs", - alias: ["wv"], - action: witnessVerify - }, - { - cmd: "powersOfTau export response" - } -*/ - -// BFJ(Big-Friendly JSON) is pretty heavy module, so we are doing lazy loading for faster startup -let _bfj; +var _bfj; async function getBFJ() { - if (_bfj) return _bfj; - const {default: bfj} = await import('bfj'); - _bfj = bfj; - return _bfj; + if (_bfj) return _bfj; + const { default: bfj } = await import("bfj"); + _bfj = bfj; + return _bfj; } - function changeExt(fileName, newExt) { - let S = fileName; - while ((S.length > 0) && (S[S.length - 1] != ".")) S = S.slice(0, S.length - 1); - if (S.length > 0) { - return S + newExt; - } else { - return fileName + "." + newExt; - } -} - -// r1cs export circomJSON [circuit.r1cs] [circuit.json] + let S = fileName; + while (S.length > 0 && S[S.length - 1] != ".") S = S.slice(0, S.length - 1); + if (S.length > 0) return S + newExt; + else return fileName + "." + newExt; +} async function r1csInfo(params, options) { - const r1csName = params[0] || "circuit.r1cs"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - await r1csInfo$1(r1csName, logger); - - - return 0; -} - -// r1cs print [circuit.r1cs] [circuit.sym] + const r1csName = params[0] || "circuit.r1cs"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await r1csInfo$1(r1csName, logger); + return 0; +} async function r1csPrint(params, options) { - const r1csName = params[0] || "circuit.r1cs"; - const symName = params[1] || changeExt(r1csName, "sym"); - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const cir = await r1csfile.readR1cs(r1csName, true, true, false); - - const sym = await loadSymbols(symName); - - await r1csPrint$1(cir, sym, logger); - - return 0; -} - - -// r1cs export json [circuit.r1cs] [circuit.json] + const r1csName = params[0] || "circuit.r1cs"; + const symName = params[1] || changeExt(r1csName, "sym"); + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await r1csPrint$1(await (0, r1csfile.readR1cs)(r1csName, true, true, false), await loadSymbols(symName), logger); + return 0; +} async function r1csExportJSON(params, options) { - const r1csName = params[0] || "circuit.r1cs"; - const jsonName = params[1] || changeExt(r1csName, "json"); - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const r1csObj = await r1csExportJson(r1csName, logger); - - const bfj = await getBFJ(); - await bfj.write(jsonName, r1csObj, {space: 1}); - - return 0; -} - -// wtns calculate + const r1csName = params[0] || "circuit.r1cs"; + const jsonName = params[1] || changeExt(r1csName, "json"); + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const r1csObj = await r1csExportJson(r1csName, logger); + await (await getBFJ()).write(jsonName, r1csObj, { space: 1 }); + return 0; +} async function wtnsCalculate(params, options) { - const wasmName = params[0] || "circuit.wasm"; - const inputName = params[1] || "input.json"; - const witnessName = params[2] || "witness.wtns"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const input = JSON.parse(await fs.promises.readFile(inputName, "utf8")); - - await wtnsCalculate$1(input, wasmName, witnessName, {}); - - return 0; -} - - -// wtns debug -// -get|g -set|s -trigger|t + const wasmName = params[0] || "circuit.wasm"; + const inputName = params[1] || "input.json"; + const witnessName = params[2] || "witness.wtns"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await wtnsCalculate$1(JSON.parse(await fs.default.promises.readFile(inputName, "utf8")), wasmName, witnessName, {}); + return 0; +} async function wtnsDebug(params, options) { - const wasmName = params[0] || "circuit.wasm"; - const inputName = params[1] || "input.json"; - const witnessName = params[2] || "witness.wtns"; - const symName = params[3] || changeExt(wasmName, "sym"); - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const input = JSON.parse(await fs.promises.readFile(inputName, "utf8")); - - await wtnsDebug$1(input, wasmName, witnessName, symName, options, logger); - - return 0; -} - - -// wtns export json [witness.wtns] [witness.json] -// -get|g -set|s -trigger|t + const wasmName = params[0] || "circuit.wasm"; + const inputName = params[1] || "input.json"; + const witnessName = params[2] || "witness.wtns"; + const symName = params[3] || changeExt(wasmName, "sym"); + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await wtnsDebug$1(JSON.parse(await fs.default.promises.readFile(inputName, "utf8")), wasmName, witnessName, symName, options, logger); + return 0; +} async function wtnsExportJson(params, options) { - const wtnsName = params[0] || "witness.wtns"; - const jsonName = params[1] || "witness.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const w = await wtnsExportJson$1(wtnsName); - - const bfj = await getBFJ(); - await bfj.write(jsonName, stringifyBigInts(w), {space: 1}); - - return 0; -} - -// wtns export json [witness.wtns] [witness.json] -// -get|g -set|s -trigger|t + const wtnsName = params[0] || "witness.wtns"; + const jsonName = params[1] || "witness.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const w = await wtnsExportJson$1(wtnsName); + await (await getBFJ()).write(jsonName, stringifyBigInts(w), { space: 1 }); + return 0; +} async function wtnsCheck(params, options) { - const r1csFilename = params[0] || "circuit.r1cs"; - const wtnsFilename = params[1] || "witness.wtns"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const isValid = await wtnsCheck$1(r1csFilename, wtnsFilename, logger); - - if (isValid) { - return 0; - } else { - return 1; - } -} - - -/* -// zksnark setup [circuit.r1cs] [circuit.zkey] [verification_key.json] -async function zksnarkSetup(params, options) { - - const r1csName = params[0] || "circuit.r1cs"; - const zkeyName = params[1] || changeExt(r1csName, "zkey"); - const verificationKeyName = params[2] || "verification_key.json"; - - const protocol = options.protocol || "groth16"; - - const cir = await readR1cs(r1csName, true); - - if (!zkSnark[protocol]) throw new Error("Invalid protocol"); - const setup = zkSnark[protocol].setup(cir, options.verbose); - - await zkey.utils.write(zkeyName, setup.vk_proof); - await bfj.write(provingKeyName, stringifyBigInts(setup.vk_proof), { space: 1 }); - - await bfj.write(verificationKeyName, stringifyBigInts(setup.vk_verifier), { space: 1 }); - - return 0; + const r1csFilename = params[0] || "circuit.r1cs"; + const wtnsFilename = params[1] || "witness.wtns"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + if (await wtnsCheck$1(r1csFilename, wtnsFilename, logger)) return 0; + else return 1; } -*/ - -// groth16 prove [circuit.zkey] [witness.wtns] [proof.json] [public.json] async function groth16Prove(params, options) { - - const zkeyName = params[0] || "circuit_final.zkey"; - const witnessName = params[1] || "witness.wtns"; - const proofName = params[2] || "proof.json"; - const publicName = params[3] || "public.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const proveOptions = {}; - if (options.buildabc) proveOptions.buildABC = options.buildabc; - if (options.memlog) proveOptions.memoryLogging = options.memlog; - const {proof, publicSignals} = await groth16Prove$1(zkeyName, witnessName, logger, proveOptions); - - fs.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1)); - fs.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1)); - - return 0; -} - -// groth16 fullprove [input.json] [circuit.wasm] [circuit.zkey] [proof.json] [public.json] + const zkeyName = params[0] || "circuit_final.zkey"; + const witnessName = params[1] || "witness.wtns"; + const proofName = params[2] || "proof.json"; + const publicName = params[3] || "public.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const proveOptions = {}; + if (options.buildabc) proveOptions.buildABC = options.buildabc; + if (options.memlog) proveOptions.memoryLogging = options.memlog; + const { proof, publicSignals } = await groth16Prove$1(zkeyName, witnessName, logger, proveOptions); + fs.default.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1)); + fs.default.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1)); + return 0; +} async function groth16FullProve(params, options) { - - const inputName = params[0] || "input.json"; - const wasmName = params[1] || "circuit.wasm"; - const zkeyName = params[2] || "circuit_final.zkey"; - const proofName = params[3] || "proof.json"; - const publicName = params[4] || "public.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const input = JSON.parse(await fs.promises.readFile(inputName, "utf8")); - - const proveOptions = {}; - if (options.buildabc) proveOptions.buildABC = options.buildabc; - if (options.memlog) proveOptions.memoryLogging = options.memlog; - const {proof, publicSignals} = await groth16FullProve$1(input, wasmName, zkeyName, logger, undefined, proveOptions); - - fs.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1)); - fs.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1)); - - return 0; -} - -// groth16 verify [verification_key.json] [public.json] [proof.json] + const inputName = params[0] || "input.json"; + const wasmName = params[1] || "circuit.wasm"; + const zkeyName = params[2] || "circuit_final.zkey"; + const proofName = params[3] || "proof.json"; + const publicName = params[4] || "public.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const input = JSON.parse(await fs.default.promises.readFile(inputName, "utf8")); + const proveOptions = {}; + if (options.buildabc) proveOptions.buildABC = options.buildabc; + if (options.memlog) proveOptions.memoryLogging = options.memlog; + const { proof, publicSignals } = await groth16FullProve$1(input, wasmName, zkeyName, logger, void 0, proveOptions); + fs.default.writeFileSync(proofName, JSON.stringify(stringifyBigInts(proof), null, 1)); + fs.default.writeFileSync(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1)); + return 0; +} async function groth16Verify(params, options) { - - const verificationKeyName = params[0] || "verification_key.json"; - const publicName = params[1] || "public.json"; - const proofName = params[2] || "proof.json"; - - const verificationKey = JSON.parse(fs.readFileSync(verificationKeyName, "utf8")); - const pub = JSON.parse(fs.readFileSync(publicName, "utf8")); - const proof = JSON.parse(fs.readFileSync(proofName, "utf8")); - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const isValid = await groth16Verify$1(verificationKey, pub, proof, logger); - - if (isValid) { - return 0; - } else { - return 1; - } -} - -// zkey export vkey [circuit_final.zkey] [verification_key.json]", + const verificationKeyName = params[0] || "verification_key.json"; + const publicName = params[1] || "public.json"; + const proofName = params[2] || "proof.json"; + const verificationKey = JSON.parse(fs.default.readFileSync(verificationKeyName, "utf8")); + const pub = JSON.parse(fs.default.readFileSync(publicName, "utf8")); + const proof = JSON.parse(fs.default.readFileSync(proofName, "utf8")); + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + if (await groth16Verify$1(verificationKey, pub, proof, logger)) return 0; + else return 1; +} async function zkeyExportVKey(params, options) { - const zKeyFileName = params[0] || "circuit_final.zkey"; - const vKeyFilename = params[1] || "circuit_vk.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const vKey = await zkeyExportVerificationKey(zKeyFileName, logger); - - const bfj = await getBFJ(); - await bfj.write(vKeyFilename, stringifyBigInts(vKey), {space: 1}); - - return 0; -} - -// zkey export json [circuit_final.zkey] [circuit.zkey.json]", + const zKeyFileName = params[0] || "circuit_final.zkey"; + const vKeyFilename = params[1] || "circuit_vk.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const vKey = await zkeyExportVerificationKey(zKeyFileName, logger); + await (await getBFJ()).write(vKeyFilename, stringifyBigInts(vKey), { space: 1 }); + return 0; +} async function zkeyExportJson(params, options) { - const zkeyName = params[0] || "circuit_final.zkey"; - const zkeyJsonName = params[1] || "circuit_final.zkey.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const zKeyJson = await zkeyExportJson$1(zkeyName); - - const bfj = await getBFJ(); - await bfj.write(zkeyJsonName, zKeyJson, {space: 1}); -} - + const zkeyName = params[0] || "circuit_final.zkey"; + const zkeyJsonName = params[1] || "circuit_final.zkey.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const zKeyJson = await zkeyExportJson$1(zkeyName, logger); + await (await getBFJ()).write(zkeyJsonName, zKeyJson, { space: 1 }); +} async function fileExists(file) { - return fs.promises.access(file, fs.constants.F_OK) - .then(() => true) - .catch(() => false); + return fs.default.promises.access(file, fs.default.constants.F_OK).then(() => true).catch(() => false); } - -// solidity genverifier [circuit_final.zkey] [verifier.sol] async function zkeyExportSolidityVerifier(params, options) { - let zkeyName; - let verifierName; - - if (params.length < 1) { - zkeyName = "circuit_final.zkey"; - } else { - zkeyName = params[0]; - } - - if (params.length < 2) { - verifierName = "verifier.sol"; - } else { - verifierName = params[1]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const templates = {}; - - if (await fileExists(path.join(__dirname$1, "templates"))) { - templates.groth16 = await fs.promises.readFile(path.join(__dirname$1, "templates", "verifier_groth16.sol.ejs"), "utf8"); - templates.plonk = await fs.promises.readFile(path.join(__dirname$1, "templates", "verifier_plonk.sol.ejs"), "utf8"); - templates.fflonk = await fs.promises.readFile(path.join(__dirname$1, "templates", "verifier_fflonk.sol.ejs"), "utf8"); - } else { - templates.groth16 = await fs.promises.readFile(path.join(__dirname$1, "..", "templates", "verifier_groth16.sol.ejs"), "utf8"); - templates.plonk = await fs.promises.readFile(path.join(__dirname$1, "..", "templates", "verifier_plonk.sol.ejs"), "utf8"); - templates.fflonk = await fs.promises.readFile(path.join(__dirname$1, "..", "templates", "verifier_fflonk.sol.ejs"), "utf8"); - } - - const verifierCode = await exportSolidityVerifier(zkeyName, templates, logger); - - fs.writeFileSync(verifierName, verifierCode, "utf-8"); - - return 0; -} - - -// solidity gencall + let zkeyName; + let verifierName; + if (params.length < 1) zkeyName = "circuit_final.zkey"; + else zkeyName = params[0]; + if (params.length < 2) verifierName = "verifier.sol"; + else verifierName = params[1]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const templates = {}; + if (await fileExists(path.default.join(__dirname$1, "templates"))) { + templates.groth16 = await fs.default.promises.readFile(path.default.join(__dirname$1, "templates", "verifier_groth16.sol.ejs"), "utf8"); + templates.plonk = await fs.default.promises.readFile(path.default.join(__dirname$1, "templates", "verifier_plonk.sol.ejs"), "utf8"); + templates.fflonk = await fs.default.promises.readFile(path.default.join(__dirname$1, "templates", "verifier_fflonk.sol.ejs"), "utf8"); + } else { + templates.groth16 = await fs.default.promises.readFile(path.default.join(__dirname$1, "..", "templates", "verifier_groth16.sol.ejs"), "utf8"); + templates.plonk = await fs.default.promises.readFile(path.default.join(__dirname$1, "..", "templates", "verifier_plonk.sol.ejs"), "utf8"); + templates.fflonk = await fs.default.promises.readFile(path.default.join(__dirname$1, "..", "templates", "verifier_fflonk.sol.ejs"), "utf8"); + } + const verifierCode = await exportSolidityVerifier(zkeyName, templates, logger); + fs.default.writeFileSync(verifierName, verifierCode, "utf-8"); + return 0; +} async function zkeyExportSolidityCalldata(params, options) { - let publicName; - let proofName; - - if (params.length < 1) { - publicName = "public.json"; - } else { - publicName = params[0]; - } - - if (params.length < 2) { - proofName = "proof.json"; - } else { - proofName = params[1]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const pub = JSON.parse(fs.readFileSync(publicName, "utf8")); - const proof = JSON.parse(fs.readFileSync(proofName, "utf8")); - - let res; - if (proof.protocol == "groth16") { - res = await groth16ExportSolidityCallData(proof, pub); - } else if (proof.protocol == "plonk") { - res = await plonkExportSolidityCallData(proof, pub); - } else if (proof.protocol === "fflonk") { - res = await fflonkExportCallData(pub, proof); - } else { - throw new Error("Invalid Protocol"); - } - console.log(res); - - return 0; -} - -// powersoftau new [powersoftau_0000.ptau]", + let publicName; + let proofName; + if (params.length < 1) publicName = "public.json"; + else publicName = params[0]; + if (params.length < 2) proofName = "proof.json"; + else proofName = params[1]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const pub = JSON.parse(fs.default.readFileSync(publicName, "utf8")); + const proof = JSON.parse(fs.default.readFileSync(proofName, "utf8")); + let res; + if (proof.protocol == "groth16") res = await groth16ExportSolidityCallData(proof, pub); + else if (proof.protocol == "plonk") res = await plonkExportSolidityCallData(proof, pub); + else if (proof.protocol === "fflonk") res = await fflonkExportCallData(pub, proof); + else throw new Error("Invalid Protocol"); + console.log(res); + return 0; +} async function powersOfTauNew(params, options) { - let curveName; - let power; - let ptauName; - - curveName = params[0]; - - power = parseInt(params[1]); - if ((power<1) || (power>28) || isNaN(power)) { - throw new Error("Power must be between 1 and 28"); - } - - if (params.length < 3) { - ptauName = "powersOfTau" + power + "_0000.ptau"; - } else { - ptauName = params[2]; - } - - const curve = await getCurveFromName(curveName); - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // Discard firstChallengeHash - await newAccumulator(curve, power, ptauName, logger); - - return 0; -} - + let curveName; + let power; + let ptauName; + curveName = params[0]; + power = parseInt(params[1]); + if (power < 1 || power > 28 || isNaN(power)) throw new Error("Power must be between 1 and 28"); + if (params.length < 3) ptauName = "powersOfTau" + power + "_0000.ptau"; + else ptauName = params[2]; + const curve = await getCurveFromName(curveName); + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await newAccumulator(curve, power, ptauName, logger); + return 0; +} async function powersOfTauExportChallenge(params, options) { - let ptauName; - let challengeName; - - ptauName = params[0]; - - if (params.length < 2) { - challengeName = "challenge"; - } else { - challengeName = params[1]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // Discard curChallengeHash - await exportChallenge(ptauName, challengeName, logger); - - return 0; -} - -// powersoftau challenge contribute [response] + let ptauName; + let challengeName; + ptauName = params[0]; + if (params.length < 2) challengeName = "challenge"; + else challengeName = params[1]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await exportChallenge(ptauName, challengeName, logger); + return 0; +} async function powersOfTauChallengeContribute(params, options) { - let challengeName; - let responseName; - - const curve = await getCurveFromName(params[0]); - - challengeName = params[1]; - - if (params.length < 3) { - responseName = changeExt(challengeName, "response"); - } else { - responseName = params[2]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - await challengeContribute(curve, challengeName, responseName, options.entropy, logger); - - return 0; -} - - + let challengeName; + let responseName; + const curve = await getCurveFromName(params[0]); + challengeName = params[1]; + if (params.length < 3) responseName = changeExt(challengeName, "response"); + else responseName = params[2]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await challengeContribute(curve, challengeName, responseName, options.entropy, logger); + return 0; +} async function powersOfTauImport(params, options) { - let oldPtauName; - let response; - let newPtauName; - let importPoints = true; - let doCheck = true; - - oldPtauName = params[0]; - response = params[1]; - newPtauName = params[2]; - - if (options.nopoints) importPoints = false; - if (options.nocheck) doCheck = false; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const nextChallenge = await importResponse(oldPtauName, response, newPtauName, options.name, importPoints, logger); - - if (nextChallenge) return 0; - if (!doCheck) return 0; - - // TODO Verify -} - + let oldPtauName; + let response; + let newPtauName; + let importPoints = true; + let doCheck = true; + oldPtauName = params[0]; + response = params[1]; + newPtauName = params[2]; + if (options.nopoints) importPoints = false; + if (options.nocheck) doCheck = false; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + if (await importResponse(oldPtauName, response, newPtauName, options.name, importPoints, logger)) return 0; + if (!doCheck) return 0; +} async function powersOfTauVerify(params, options) { - let ptauName; - - ptauName = params[0]; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const res = await verify(ptauName, logger); - if (res === true) { - return 0; - } else { - return 1; - } -} - + let ptauName; + ptauName = params[0]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + if (await verify(ptauName, logger) === true) return 0; + else return 1; +} async function powersOfTauBeacon(params, options) { - let oldPtauName; - let newPtauName; - let beaconHashStr; - let numIterationsExp; - - oldPtauName = params[0]; - newPtauName = params[1]; - beaconHashStr = params[2]; - numIterationsExp = params[3]; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // Discard hashResponse - await beacon$1(oldPtauName, newPtauName, options.name, beaconHashStr, numIterationsExp, logger); - - return 0; -} - + let oldPtauName; + let newPtauName; + let beaconHashStr; + let numIterationsExp; + oldPtauName = params[0]; + newPtauName = params[1]; + beaconHashStr = params[2]; + numIterationsExp = params[3]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await beacon$1(oldPtauName, newPtauName, options.name, beaconHashStr, numIterationsExp, logger); + return 0; +} async function powersOfTauContribute(params, options) { - let oldPtauName; - let newPtauName; - - oldPtauName = params[0]; - newPtauName = params[1]; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // Discard hashResponse - await contribute(oldPtauName, newPtauName, options.name, options.entropy, logger); - - return 0; -} - + let oldPtauName; + let newPtauName; + oldPtauName = params[0]; + newPtauName = params[1]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await contribute(oldPtauName, newPtauName, options.name, options.entropy, logger); + return 0; +} async function powersOfTauPreparePhase2(params, options) { - let oldPtauName; - let newPtauName; - - oldPtauName = params[0]; - newPtauName = params[1]; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - await preparePhase2(oldPtauName, newPtauName, logger); - - return 0; -} - + let oldPtauName; + let newPtauName; + oldPtauName = params[0]; + newPtauName = params[1]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await preparePhase2(oldPtauName, newPtauName, logger); + return 0; +} async function powersOfTauConvert(params, options) { - let oldPtauName; - let newPtauName; - - oldPtauName = params[0]; - newPtauName = params[1]; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - await convert(oldPtauName, newPtauName, logger); - - return 0; -} - - + let oldPtauName; + let newPtauName; + oldPtauName = params[0]; + newPtauName = params[1]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await convert(oldPtauName, newPtauName, logger); + return 0; +} async function powersOfTauTruncate(params, options) { - let ptauName; - - ptauName = params[0]; - - let template = ptauName; - while ((template.length > 0) && (template[template.length - 1] != ".")) template = template.slice(0, template.length - 1); - template = template.slice(0, template.length - 1); - template = template + "_"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // Discard `true` - await truncate(ptauName, template, logger); - - return 0; -} - -// powersoftau export json ", + let ptauName; + ptauName = params[0]; + let template = ptauName; + while (template.length > 0 && template[template.length - 1] != ".") template = template.slice(0, template.length - 1); + template = template.slice(0, template.length - 1); + template = template + "_"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await truncate(ptauName, template, logger); + return 0; +} async function powersOfTauExportJson(params, options) { - let ptauName; - let jsonName; - - ptauName = params[0]; - jsonName = params[1]; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const pTauJson = await exportJson(ptauName, logger); - - const bfj = await getBFJ(); - await bfj.write(jsonName, pTauJson, {space: 1}); -} - - -// phase2 new + let ptauName; + let jsonName; + ptauName = params[0]; + jsonName = params[1]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const pTauJson = await exportJson(ptauName, logger); + await (await getBFJ()).write(jsonName, pTauJson, { space: 1 }); +} async function zkeyNew(params, options) { - let r1csName; - let ptauName; - let zkeyName; - - if (params.length < 1) { - r1csName = "circuit.r1cs"; - } else { - r1csName = params[0]; - } - - if (params.length < 2) { - ptauName = "powersoftau.ptau"; - } else { - ptauName = params[1]; - } - - if (params.length < 3) { - zkeyName = "circuit_0000.zkey"; - } else { - zkeyName = params[2]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // Discard csHash - await newZKey(r1csName, ptauName, zkeyName, logger); - - return 0; -} - -// zkey export bellman [circuit_0000.zkey] [circuit.mpcparams] + let r1csName; + let ptauName; + let zkeyName; + if (params.length < 1) r1csName = "circuit.r1cs"; + else r1csName = params[0]; + if (params.length < 2) ptauName = "powersoftau.ptau"; + else ptauName = params[1]; + if (params.length < 3) zkeyName = "circuit_0000.zkey"; + else zkeyName = params[2]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await newZKey(r1csName, ptauName, zkeyName, logger); + return 0; +} async function zkeyExportBellman(params, options) { - let zkeyName; - let mpcparamsName; - - zkeyName = params[0]; - - if (params.length < 2) { - mpcparamsName = "circuit.mpcparams"; - } else { - mpcparamsName = params[1]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - await phase2exportMPCParams(zkeyName, mpcparamsName, logger); - - return 0; -} - - -// zkey import bellman + let zkeyName; + let mpcparamsName; + zkeyName = params[0]; + if (params.length < 2) mpcparamsName = "circuit.mpcparams"; + else mpcparamsName = params[1]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await phase2exportMPCParams(zkeyName, mpcparamsName, logger); + return 0; +} async function zkeyImportBellman(params, options) { - let zkeyNameOld; - let mpcParamsName; - let zkeyNameNew; - - zkeyNameOld = params[0]; - mpcParamsName = params[1]; - zkeyNameNew = params[2]; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const isValid = await phase2importMPCParams(zkeyNameOld, mpcParamsName, zkeyNameNew, options.name, logger); - if (isValid) { - return 0; - } else { - return 1; - } -} - -// phase2 verify r1cs [circuit.r1cs] [powersoftau.ptau] [circuit_final.zkey] + let zkeyNameOld; + let mpcParamsName; + let zkeyNameNew; + zkeyNameOld = params[0]; + mpcParamsName = params[1]; + zkeyNameNew = params[2]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + if (await phase2importMPCParams(zkeyNameOld, mpcParamsName, zkeyNameNew, options.name, logger)) return 0; + else return 1; +} async function zkeyVerifyFromR1cs(params, options) { - let r1csName; - let ptauName; - let zkeyName; - - if (params.length < 1) { - r1csName = "circuit.r1cs"; - } else { - r1csName = params[0]; - } - - if (params.length < 2) { - ptauName = "powersoftau.ptau"; - } else { - ptauName = params[1]; - } - - if (params.length < 3) { - zkeyName = "circuit_final.zkey"; - } else { - zkeyName = params[2]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const res = await phase2verifyFromR1cs(r1csName, ptauName, zkeyName, logger); - if (res === true) { - return 0; - } else { - return 1; - } - -} - -// phase2 verify [circuit_0000] [powersoftau.ptau] [circuit_final.zkey] + let r1csName; + let ptauName; + let zkeyName; + if (params.length < 1) r1csName = "circuit.r1cs"; + else r1csName = params[0]; + if (params.length < 2) ptauName = "powersoftau.ptau"; + else ptauName = params[1]; + if (params.length < 3) zkeyName = "circuit_final.zkey"; + else zkeyName = params[2]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + if (await phase2verifyFromR1cs(r1csName, ptauName, zkeyName, logger) === true) return 0; + else return 1; +} async function zkeyVerifyFromInit(params, options) { - let initZKeyName; - let ptauName; - let zkeyName; - - if (params.length < 1) { - initZKeyName = "circuit_0000.zkey"; - } else { - initZKeyName = params[0]; - } - - if (params.length < 2) { - ptauName = "powersoftau.ptau"; - } else { - ptauName = params[1]; - } - - if (params.length < 3) { - zkeyName = "circuit_final.zkey"; - } else { - zkeyName = params[2]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const res = await phase2verifyFromInit(initZKeyName, ptauName, zkeyName, logger); - if (res === true) { - return 0; - } else { - return 1; - } -} - -// zkey contribute + let initZKeyName; + let ptauName; + let zkeyName; + if (params.length < 1) initZKeyName = "circuit_0000.zkey"; + else initZKeyName = params[0]; + if (params.length < 2) ptauName = "powersoftau.ptau"; + else ptauName = params[1]; + if (params.length < 3) zkeyName = "circuit_final.zkey"; + else zkeyName = params[2]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + if (await phase2verifyFromInit(initZKeyName, ptauName, zkeyName, logger) === true) return 0; + else return 1; +} async function zkeyContribute(params, options) { - let zkeyOldName; - let zkeyNewName; - - zkeyOldName = params[0]; - zkeyNewName = params[1]; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // Discard contribuionHash - await phase2contribute(zkeyOldName, zkeyNewName, options.name, options.entropy, logger); - - return 0; -} - -// zkey beacon + let zkeyOldName; + let zkeyNewName; + zkeyOldName = params[0]; + zkeyNewName = params[1]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await phase2contribute(zkeyOldName, zkeyNewName, options.name, options.entropy, logger); + return 0; +} async function zkeyBeacon(params, options) { - let zkeyOldName; - let zkeyNewName; - let beaconHashStr; - let numIterationsExp; - - zkeyOldName = params[0]; - zkeyNewName = params[1]; - beaconHashStr = params[2]; - numIterationsExp = params[3]; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // Discard contribuionHash - await beacon(zkeyOldName, zkeyNewName, options.name, beaconHashStr, numIterationsExp, logger); - - return 0; -} - - -// zkey challenge contribute [response]", + let zkeyOldName; + let zkeyNewName; + let beaconHashStr; + let numIterationsExp; + zkeyOldName = params[0]; + zkeyNewName = params[1]; + beaconHashStr = params[2]; + numIterationsExp = params[3]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await beacon(zkeyOldName, zkeyNewName, options.name, beaconHashStr, numIterationsExp, logger); + return 0; +} async function zkeyBellmanContribute(params, options) { - let challengeName; - let responseName; - - const curve = await getCurveFromName(params[0]); - - challengeName = params[1]; - - if (params.length < 3) { - responseName = changeExt(challengeName, "response"); - } else { - responseName = params[2]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // Discard contributionHash - await bellmanContribute(curve, challengeName, responseName, options.entropy, logger); - - return 0; -} - - -// plonk setup + let challengeName; + let responseName; + const curve = await getCurveFromName(params[0]); + challengeName = params[1]; + if (params.length < 3) responseName = changeExt(challengeName, "response"); + else responseName = params[2]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + await bellmanContribute(curve, challengeName, responseName, options.entropy, logger); + return 0; +} async function plonkSetup(params, options) { - let r1csName; - let ptauName; - let zkeyName; - - if (params.length < 1) { - r1csName = "circuit.r1cs"; - } else { - r1csName = params[0]; - } - - if (params.length < 2) { - ptauName = "powersoftau.ptau"; - } else { - ptauName = params[1]; - } - - if (params.length < 3) { - zkeyName = "circuit.zkey"; - } else { - zkeyName = params[2]; - } - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // TODO: Make plonk.setup reject instead of returning -1 or null - return plonkSetup$1(r1csName, ptauName, zkeyName, logger); -} - - -// plonk prove [circuit.zkey] [witness.wtns] [proof.json] [public.json] + let r1csName; + let ptauName; + let zkeyName; + if (params.length < 1) r1csName = "circuit.r1cs"; + else r1csName = params[0]; + if (params.length < 2) ptauName = "powersoftau.ptau"; + else ptauName = params[1]; + if (params.length < 3) zkeyName = "circuit.zkey"; + else zkeyName = params[2]; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + return plonkSetup$1(r1csName, ptauName, zkeyName, logger); +} async function plonkProve(params, options) { - - const zkeyName = params[0] || "circuit.zkey"; - const witnessName = params[1] || "witness.wtns"; - const proofName = params[2] || "proof.json"; - const publicName = params[3] || "public.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const {proof, publicSignals} = await plonk16Prove(zkeyName, witnessName, logger); - - const bfj = await getBFJ(); - await bfj.write(proofName, stringifyBigInts(proof), {space: 1}); - await bfj.write(publicName, stringifyBigInts(publicSignals), {space: 1}); - - return 0; -} - - -// plonk fullprove [input.json] [circuit.wasm] [circuit.zkey] [proof.json] [public.json] + const zkeyName = params[0] || "circuit.zkey"; + const witnessName = params[1] || "witness.wtns"; + const proofName = params[2] || "proof.json"; + const publicName = params[3] || "public.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const { proof, publicSignals } = await plonk16Prove(zkeyName, witnessName, logger); + const bfj = await getBFJ(); + await bfj.write(proofName, stringifyBigInts(proof), { space: 1 }); + await bfj.write(publicName, stringifyBigInts(publicSignals), { space: 1 }); + return 0; +} async function plonkFullProve(params, options) { - - const inputName = params[0] || "input.json"; - const wasmName = params[1] || "circuit.wasm"; - const zkeyName = params[2] || "circuit.zkey"; - const proofName = params[3] || "proof.json"; - const publicName = params[4] || "public.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const input = JSON.parse(await fs.promises.readFile(inputName, "utf8")); - - const {proof, publicSignals} = await plonkFullProve$1(input, wasmName, zkeyName, logger); - - const bfj = await getBFJ(); - await bfj.write(proofName, stringifyBigInts(proof), {space: 1}); - await bfj.write(publicName, stringifyBigInts(publicSignals), {space: 1}); - - return 0; -} - - -// plonk verify [verification_key.json] [public.json] [proof.json] + const inputName = params[0] || "input.json"; + const wasmName = params[1] || "circuit.wasm"; + const zkeyName = params[2] || "circuit.zkey"; + const proofName = params[3] || "proof.json"; + const publicName = params[4] || "public.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const { proof, publicSignals } = await plonkFullProve$1(JSON.parse(await fs.default.promises.readFile(inputName, "utf8")), wasmName, zkeyName, logger); + const bfj = await getBFJ(); + await bfj.write(proofName, stringifyBigInts(proof), { space: 1 }); + await bfj.write(publicName, stringifyBigInts(publicSignals), { space: 1 }); + return 0; +} async function plonkVerify(params, options) { - - const verificationKeyName = params[0] || "verification_key.json"; - const publicName = params[1] || "public.json"; - const proofName = params[2] || "proof.json"; - - const verificationKey = JSON.parse(fs.readFileSync(verificationKeyName, "utf8")); - const pub = JSON.parse(fs.readFileSync(publicName, "utf8")); - const proof = JSON.parse(fs.readFileSync(proofName, "utf8")); - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const isValid = await plonkVerify$1(verificationKey, pub, proof, logger); - - if (isValid) { - return 0; - } else { - return 1; - } -} - + const verificationKeyName = params[0] || "verification_key.json"; + const publicName = params[1] || "public.json"; + const proofName = params[2] || "proof.json"; + const verificationKey = JSON.parse(fs.default.readFileSync(verificationKeyName, "utf8")); + const pub = JSON.parse(fs.default.readFileSync(publicName, "utf8")); + const proof = JSON.parse(fs.default.readFileSync(proofName, "utf8")); + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + if (await plonkVerify$1(verificationKey, pub, proof, logger)) return 0; + else return 1; +} async function fflonkSetup(params, options) { - const r1csFilename = params[0] || "circuit.r1cs"; - const ptauFilename = params[1] || "powersoftau.ptau"; - const zkeyFilename = params[2] || "circuit.zkey"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - // TODO: Make fflonk.setup return valuable information or nothing at all - return await fflonkSetup$1(r1csFilename, ptauFilename, zkeyFilename, logger); -} - - + const r1csFilename = params[0] || "circuit.r1cs"; + const ptauFilename = params[1] || "powersoftau.ptau"; + const zkeyFilename = params[2] || "circuit.zkey"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + return await fflonkSetup$1(r1csFilename, ptauFilename, zkeyFilename, logger); +} async function fflonkProve(params, options) { - const zkeyFilename = params[0] || "circuit.zkey"; - const witnessFilename = params[1] || "witness.wtns"; - const proofFilename = params[2] || "proof.json"; - const publicInputsFilename = params[3] || "public.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const {proof, publicSignals} = await fflonkProve$1(zkeyFilename, witnessFilename, logger); - - if(undefined !== proofFilename && undefined !== publicInputsFilename) { - const bfj = await getBFJ(); - // Write the proof and the public signals in each file - await bfj.write(proofFilename, stringifyBigInts(proof), {space: 1}); - await bfj.write(publicInputsFilename, stringifyBigInts(publicSignals), {space: 1}); - } - - return 0; -} - + const zkeyFilename = params[0] || "circuit.zkey"; + const witnessFilename = params[1] || "witness.wtns"; + const proofFilename = params[2] || "proof.json"; + const publicInputsFilename = params[3] || "public.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const { proof, publicSignals } = await fflonkProve$1(zkeyFilename, witnessFilename, logger); + if (void 0 !== proofFilename && void 0 !== publicInputsFilename) { + const bfj = await getBFJ(); + await bfj.write(proofFilename, stringifyBigInts(proof), { space: 1 }); + await bfj.write(publicInputsFilename, stringifyBigInts(publicSignals), { space: 1 }); + } + return 0; +} async function fflonkFullProve(params, options) { - - const witnessInputsFilename = params[0] || "witness.json"; - const wasmFilename = params[1] || "circuit.wasm"; - const zkeyFilename = params[2] || "circuit.zkey"; - const proofFilename = params[3] || "proof.json"; - const publicInputsFilename = params[4] || "public.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const input = JSON.parse(await fs.promises.readFile(witnessInputsFilename, "utf8")); - - const {proof, publicSignals} = await fflonkFullProve$1(input, wasmFilename, zkeyFilename, logger); - - const bfj = await getBFJ(); - // Write the proof and the public signals in each file - await bfj.write(proofFilename, stringifyBigInts(proof), {space: 1}); - await bfj.write(publicInputsFilename, stringifyBigInts(publicSignals), {space: 1}); - - return 0; -} - + const witnessInputsFilename = params[0] || "witness.json"; + const wasmFilename = params[1] || "circuit.wasm"; + const zkeyFilename = params[2] || "circuit.zkey"; + const proofFilename = params[3] || "proof.json"; + const publicInputsFilename = params[4] || "public.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + const { proof, publicSignals } = await fflonkFullProve$1(JSON.parse(await fs.default.promises.readFile(witnessInputsFilename, "utf8")), wasmFilename, zkeyFilename, logger); + const bfj = await getBFJ(); + await bfj.write(proofFilename, stringifyBigInts(proof), { space: 1 }); + await bfj.write(publicInputsFilename, stringifyBigInts(publicSignals), { space: 1 }); + return 0; +} async function fflonkVerify(params, options) { - const vkeyFilename = params[0] || "circuit.vkey"; - const publicInputsFilename = params[1] || "public.json"; - const proofFilename = params[2] || "proof.json"; - - if (options.verbose) Logger.setLogLevel("DEBUG"); - - const vkey = JSON.parse(fs.readFileSync(vkeyFilename, "utf8")); - const publicInputs = JSON.parse(fs.readFileSync(publicInputsFilename, "utf8")); - const proof = JSON.parse(fs.readFileSync(proofFilename, "utf8")); - - const isValid = await fflonkVerify$1(vkey, publicInputs, proof, logger); - - return isValid ? 0 : 1; -} - -async function fileInfo(params) { - const filename = params[0]; - const extension = filename.split(".").pop(); - - if (!["zkey", "r1cs", "ptau", "wtns"].includes(extension)) { - console.error(`Extension ${extension} is not allowed.`); - return; - } - - try { - const { - fd: fd, - sections: sections - } = await binFileUtils__namespace.readBinFile(filename, extension, 2, 1 << 25, 1 << 23); - - console.log(`File info for ${filename}`); - console.log(); - console.log(`File size: ${fd.totalSize} bytes`); - console.log(`File type: ${extension}`); - console.log(`Version: ${fd.version}`); - console.log(`Bin version: ${fd.binVersion}`); - console.log(""); - - sections.forEach((section, index) => { - let errors = []; - if (section.length > 1) errors.push(`Section ${index} has more than one section definition`); - else { - if (section[0].size === 0) { - errors.push(`Section ${index} size is zero. This could cause false errors in other sections.`); - } - } - if (section[0].p + section[0].size > fd.totalSize) { - errors.push(`Section ${index} is out of bounds of the file.`); - } - - const color = errors.length === 0 ? "%s%s%s" : "%s\x1b[31m%s\x1b[0m%s"; - const text0 = "section " + ("#" + index).padStart(5, " "); - const text1 = errors.length === 0 ? " " : " !!"; - const text2 = ` size: ${section[0].size}\toffset: 0x${(section[0].p - 12).toString(16)}`; - console.log(color, text0, text1, text2); - errors.forEach((error) => { - console.error("\x1b[31m%s\x1b[0m", " > " + error); - }); - }); - } catch (error) { - console.error(error.message); - } + const vkeyFilename = params[0] || "circuit.vkey"; + const publicInputsFilename = params[1] || "public.json"; + const proofFilename = params[2] || "proof.json"; + if (options.verbose) logplease.default.setLogLevel("DEBUG"); + return await fflonkVerify$1(JSON.parse(fs.default.readFileSync(vkeyFilename, "utf8")), JSON.parse(fs.default.readFileSync(publicInputsFilename, "utf8")), JSON.parse(fs.default.readFileSync(proofFilename, "utf8")), logger) ? 0 : 1; } +async function fileInfo(params) { + const filename = params[0]; + const extension = filename.split(".").pop(); + if (![ + "zkey", + "r1cs", + "ptau", + "wtns" + ].includes(extension)) { + console.error(`Extension ${extension} is not allowed.`); + return; + } + try { + const { fd, sections } = await _iden3_binfileutils.readBinFile(filename, extension, 2, 1 << 25, 1 << 23); + console.log(`File info for ${filename}`); + console.log(); + console.log(`File size: ${fd.totalSize} bytes`); + console.log(`File type: ${extension}`); + console.log(`Version: ${fd.version}`); + console.log(`Bin version: ${fd.binVersion}`); + console.log(""); + sections.forEach((section, index) => { + let errors = []; + if (section.length > 1) errors.push(`Section ${index} has more than one section definition`); + else if (section[0].size === 0) errors.push(`Section ${index} size is zero. This could cause false errors in other sections.`); + if (section[0].p + section[0].size > fd.totalSize) errors.push(`Section ${index} is out of bounds of the file.`); + const color = errors.length === 0 ? "%s%s%s" : "%s\x1B[31m%s\x1B[0m%s"; + const text0 = "section " + ("#" + index).padStart(5, " "); + const text1 = errors.length === 0 ? " " : " !!"; + const text2 = ` size: ${section[0].size}\toffset: 0x${(section[0].p - 12).toString(16)}`; + console.log(color, text0, text1, text2); + errors.forEach((error) => { + console.error("\x1B[31m%s\x1B[0m", " > " + error); + }); + }); + } catch (error) { + console.error(error.message); + } +} +//#endregion diff --git a/build/main.cjs b/build/main.cjs index ee101467..bca23179 100644 --- a/build/main.cjs +++ b/build/main.cjs @@ -1,12760 +1,8039 @@ -'use strict'; - -var binFileUtils = require('@iden3/binfileutils'); -var ffjavascript = require('ffjavascript'); -var blake2_js = require('@noble/hashes/blake2.js'); -var utils_js = require('@noble/hashes/utils.js'); -var readline = require('readline'); -var crypto = require('crypto'); -var fastFile = require('fastfile'); -var circom_runtime = require('circom_runtime'); -var r1csfile = require('r1csfile'); -var sha3_js = require('@noble/hashes/sha3.js'); - -function _interopNamespaceDefault(e) { - var n = Object.create(null); - if (e) { - Object.keys(e).forEach(function (k) { - if (k !== 'default') { - var d = Object.getOwnPropertyDescriptor(e, k); - Object.defineProperty(n, k, d.get ? d : { - enumerable: true, - get: function () { return e[k]; } - }); - } - }); - } - n.default = e; - return Object.freeze(n); -} - -var binFileUtils__namespace = /*#__PURE__*/_interopNamespaceDefault(binFileUtils); -var fastFile__namespace = /*#__PURE__*/_interopNamespaceDefault(fastFile); - -const bls12381r$1 = ffjavascript.Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); -const bn128r$1 = ffjavascript.Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - -const bls12381q = ffjavascript.Scalar.e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16); -const bn128q = ffjavascript.Scalar.e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); - +Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); +//#region \0rolldown/runtime.js +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __exportAll = (all, no_symbols) => { + let target = {}; + for (var name in all) __defProp(target, name, { + get: all[name], + enumerable: true + }); + if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" }); + return target; +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { + key = keys[i]; + if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { + get: ((k) => from[k]).bind(null, key), + enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable + }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { + value: mod, + enumerable: true +}) : target, mod)); +//#endregion +let _iden3_binfileutils = require("@iden3/binfileutils"); +_iden3_binfileutils = __toESM(_iden3_binfileutils, 1); +let ffjavascript = require("ffjavascript"); +let _noble_hashes_blake2_js = require("@noble/hashes/blake2.js"); +let _noble_hashes_utils_js = require("@noble/hashes/utils.js"); +let readline = require("readline"); +readline = __toESM(readline, 1); +let crypto = require("crypto"); +crypto = __toESM(crypto, 1); +let fastfile = require("fastfile"); +fastfile = __toESM(fastfile, 1); +let circom_runtime = require("circom_runtime"); +let r1csfile = require("r1csfile"); +let _noble_hashes_sha3_js = require("@noble/hashes/sha3.js"); +//#region src/curves.js +var curves_exports = /* @__PURE__ */ __exportAll({ + getCurveFromName: () => getCurveFromName, + getCurveFromQ: () => getCurveFromQ, + getCurveFromR: () => getCurveFromR +}); +var bls12381r$1 = ffjavascript.Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); +var bn128r$1 = ffjavascript.Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); +var bls12381q = ffjavascript.Scalar.e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16); +var bn128q = ffjavascript.Scalar.e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); async function getCurveFromR(r, options) { - let curve; - // check that options param is defined and that options.singleThread is defined - let singleThread = options && options.singleThread; - if (ffjavascript.Scalar.eq(r, bn128r$1)) { - curve = await ffjavascript.buildBn128(singleThread); - } else if (ffjavascript.Scalar.eq(r, bls12381r$1)) { - curve = await ffjavascript.buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${ffjavascript.Scalar.toString(r)}`); - } - return curve; -} - + let curve; + let singleThread = options && options.singleThread; + if (ffjavascript.Scalar.eq(r, bn128r$1)) curve = await (0, ffjavascript.buildBn128)(singleThread); + else if (ffjavascript.Scalar.eq(r, bls12381r$1)) curve = await (0, ffjavascript.buildBls12381)(singleThread); + else throw new Error(`Curve not supported: ${ffjavascript.Scalar.toString(r)}`); + return curve; +} async function getCurveFromQ(q, options) { - let curve; - let singleThread = options && options.singleThread; - if (ffjavascript.Scalar.eq(q, bn128q)) { - curve = await ffjavascript.buildBn128(singleThread); - } else if (ffjavascript.Scalar.eq(q, bls12381q)) { - curve = await ffjavascript.buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${ffjavascript.Scalar.toString(q)}`); - } - return curve; -} - + let curve; + let singleThread = options && options.singleThread; + if (ffjavascript.Scalar.eq(q, bn128q)) curve = await (0, ffjavascript.buildBn128)(singleThread); + else if (ffjavascript.Scalar.eq(q, bls12381q)) curve = await (0, ffjavascript.buildBls12381)(singleThread); + else throw new Error(`Curve not supported: ${ffjavascript.Scalar.toString(q)}`); + return curve; +} async function getCurveFromName(name, options) { - let curve; - let singleThread = options && options.singleThread; - const normName = normalizeName(name); - if (["BN128", "BN254", "ALTBN128"].indexOf(normName) >= 0) { - curve = await ffjavascript.buildBn128(singleThread); - } else if (["BLS12381"].indexOf(normName) >= 0) { - curve = await ffjavascript.buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${name}`); - } - return curve; - - function normalizeName(n) { - return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); - } - -} - -var curves = /*#__PURE__*/Object.freeze({ - __proto__: null, - getCurveFromName: getCurveFromName, - getCurveFromQ: getCurveFromQ, - getCurveFromR: getCurveFromR -}); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - - -function log2( V ) -{ - return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) ); -} - - + let curve; + let singleThread = options && options.singleThread; + const normName = normalizeName(name); + if ([ + "BN128", + "BN254", + "ALTBN128" + ].indexOf(normName) >= 0) curve = await (0, ffjavascript.buildBn128)(singleThread); + else if (["BLS12381"].indexOf(normName) >= 0) curve = await (0, ffjavascript.buildBls12381)(singleThread); + else throw new Error(`Curve not supported: ${name}`); + return curve; + function normalizeName(n) { + return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); + } +} +//#endregion +//#region src/misc.js +var _revTable = []; +for (let i = 0; i < 256; i++) _revTable[i] = _revSlow(i, 8); +function _revSlow(idx, bits) { + let res = 0; + let a = idx; + for (let i = 0; i < bits; i++) { + res <<= 1; + res = res | a & 1; + a >>= 1; + } + return res; +} +function log2(V) { + return ((V & 4294901760) !== 0 ? (V &= 4294901760, 16) : 0) | ((V & 4278255360) !== 0 ? (V &= 4278255360, 8) : 0) | ((V & 4042322160) !== 0 ? (V &= 4042322160, 4) : 0) | ((V & 3435973836) !== 0 ? (V &= 3435973836, 2) : 0) | (V & 2863311530) !== 0; +} function formatHash(b, title) { - const a = new DataView(b.buffer, b.byteOffset, b.byteLength); - let S = ""; - for (let i=0; i<4; i++) { - if (i>0) S += "\n"; - S += "\t\t"; - for (let j=0; j<4; j++) { - if (j>0) S += " "; - S += a.getUint32(i*16+j*4).toString(16).padStart(8, "0"); - } - } - if (title) S = title + "\n" + S; - return S; -} - + const a = new DataView(b.buffer, b.byteOffset, b.byteLength); + let S = ""; + for (let i = 0; i < 4; i++) { + if (i > 0) S += "\n"; + S += " "; + for (let j = 0; j < 4; j++) { + if (j > 0) S += " "; + S += a.getUint32(i * 16 + j * 4).toString(16).padStart(8, "0"); + } + } + if (title) S = title + "\n" + S; + return S; +} function hashIsEqual(h1, h2) { - if (h1.byteLength != h2.byteLength) return false; - var dv1 = new Int8Array(h1); - var dv2 = new Int8Array(h2); - for (var i = 0 ; i != h1.byteLength ; i++) - { - if (dv1[i] != dv2[i]) return false; - } - return true; -} - + if (h1.byteLength != h2.byteLength) return false; + var dv1 = new Int8Array(h1); + var dv2 = new Int8Array(h2); + for (var i = 0; i != h1.byteLength; i++) if (dv1[i] != dv2[i]) return false; + return true; +} function cloneHasher(h) { - return h.clone(); + return h.clone(); } - function fromPartialHash(partial) { - // NOTE: this is unsafe and uses internal API - const buf = partial.subarray(0, 128); - const rest = utils_js.u32(partial.subarray(128)); - const res = blake2_js.blake2b.create({ dkLen: 64 }); - res.buffer.set(buf); - (res.v0l = rest[0] | 0), (res.v0h = rest[1] | 0); - (res.v1l = rest[2] | 0), (res.v1h = rest[3] | 0); - (res.v2l = rest[4] | 0), (res.v2h = rest[5] | 0); - (res.v3l = rest[6] | 0), (res.v3h = rest[7] | 0); - (res.v4l = rest[8] | 0), (res.v4h = rest[9] | 0); - (res.v5l = rest[10] | 0), (res.v5h = rest[11] | 0); - (res.v6l = rest[12] | 0), (res.v6h = rest[13] | 0); - (res.v7l = rest[14] | 0), (res.v7h = rest[15] | 0); - const shift = 2 ** 32; - const len = rest[16] + rest[17] * shift; - const pos = rest[18] + rest[19] * shift; - res.length = len + pos; - res.pos = pos; - return res; -} - -function toPartialHash(hash){ - // NOTE: this is unsafe and uses internal API - const res = new Uint8Array(216); - const res32 = utils_js.u32(res.subarray(128)); - res.set(hash.buffer); - (res32[0] = hash.v0l), (res32[1] = hash.v0h); - (res32[2] = hash.v1l), (res32[3] = hash.v1h); - (res32[4] = hash.v2l), (res32[5] = hash.v2h); - (res32[6] = hash.v3l), (res32[7] = hash.v3h); - (res32[8] = hash.v4l), (res32[9] = hash.v4h); - (res32[10] = hash.v5l), (res32[11] = hash.v5h); - (res32[12] = hash.v6l), (res32[13] = hash.v6h); - (res32[14] = hash.v7l), (res32[15] = hash.v7h); - res32[18] = hash.pos; - res32[16] = hash.length-hash.pos; - return res; -} - + const buf = partial.subarray(0, 128); + const rest = (0, _noble_hashes_utils_js.u32)(partial.subarray(128)); + const res = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + res.buffer.set(buf); + res.v0l = rest[0] | 0, res.v0h = rest[1] | 0; + res.v1l = rest[2] | 0, res.v1h = rest[3] | 0; + res.v2l = rest[4] | 0, res.v2h = rest[5] | 0; + res.v3l = rest[6] | 0, res.v3h = rest[7] | 0; + res.v4l = rest[8] | 0, res.v4h = rest[9] | 0; + res.v5l = rest[10] | 0, res.v5h = rest[11] | 0; + res.v6l = rest[12] | 0, res.v6h = rest[13] | 0; + res.v7l = rest[14] | 0, res.v7h = rest[15] | 0; + const shift = 2 ** 32; + const len = rest[16] + rest[17] * shift; + const pos = rest[18] + rest[19] * shift; + res.length = len + pos; + res.pos = pos; + return res; +} +function toPartialHash(hash) { + const res = /* @__PURE__ */ new Uint8Array(216); + const res32 = (0, _noble_hashes_utils_js.u32)(res.subarray(128)); + res.set(hash.buffer); + res32[0] = hash.v0l, res32[1] = hash.v0h; + res32[2] = hash.v1l, res32[3] = hash.v1h; + res32[4] = hash.v2l, res32[5] = hash.v2h; + res32[6] = hash.v3l, res32[7] = hash.v3h; + res32[8] = hash.v4l, res32[9] = hash.v4h; + res32[10] = hash.v5l, res32[11] = hash.v5h; + res32[12] = hash.v6l, res32[13] = hash.v6h; + res32[14] = hash.v7l, res32[15] = hash.v7h; + res32[18] = hash.pos; + res32[16] = hash.length - hash.pos; + return res; +} async function sameRatio$2(curve, g1s, g1sx, g2s, g2sx) { - if (curve.G1.isZero(g1s)) return false; - if (curve.G1.isZero(g1sx)) return false; - if (curve.G2.isZero(g2s)) return false; - if (curve.G2.isZero(g2sx)) return false; - // return curve.F12.eq(curve.pairing(g1s, g2sx), curve.pairing(g1sx, g2s)); - const res = await curve.pairingEq(g1s, g2sx, curve.G1.neg(g1sx), g2s); - return res; -} - - + if (curve.G1.isZero(g1s)) return false; + if (curve.G1.isZero(g1sx)) return false; + if (curve.G2.isZero(g2s)) return false; + if (curve.G2.isZero(g2sx)) return false; + return await curve.pairingEq(g1s, g2sx, curve.G1.neg(g1sx), g2s); +} function askEntropy() { - // Use the browser prompt only when a real DOM window exists. "not Node" is - // NOT the same as "browser" (Bun/Deno/edge/SES have neither window nor are - // classic Node), so detect the actual API. - if (typeof window !== "undefined" && typeof window.prompt === "function") { - return window.prompt("Enter a random text. (Entropy): ", ""); - } else { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); - - return new Promise((resolve) => { - rl.question("Enter a random text. (Entropy): ", (input) => resolve(input) ); - }); - } -} - + if (typeof window !== "undefined" && typeof window.prompt === "function") return window.prompt("Enter a random text. (Entropy): ", ""); + else { + const rl = readline.default.createInterface({ + input: process.stdin, + output: process.stdout + }); + return new Promise((resolve) => { + rl.question("Enter a random text. (Entropy): ", (input) => resolve(input)); + }); + } +} function getRandomBytes(n) { - let array = new Uint8Array(n); - if (crypto && crypto.randomFillSync) { // Node: no per-call size limit - crypto.randomFillSync(array); - } else if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) { - // Web Crypto caps each call at 65536 bytes; fill in windows. - for (let i = 0; i < n; i += 65536) { - globalThis.crypto.getRandomValues(array.subarray(i, Math.min(i + 65536, n))); - } - } else { - throw new Error("No secure random source available"); - } - return array; -} - + let array = new Uint8Array(n); + if (crypto.default && crypto.default.randomFillSync) crypto.default.randomFillSync(array); + else if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) for (let i = 0; i < n; i += 65536) globalThis.crypto.getRandomValues(array.subarray(i, Math.min(i + 65536, n))); + else throw new Error("No secure random source available"); + return array; +} async function sha256digest(data) { - if (crypto && crypto.createHash) { // Node - return crypto.createHash("sha256").update(data).digest(); - } else { - // Web Crypto: pass the view (data), not data.buffer, so byteOffset and - // byteLength of subarray views are respected. - const buffer = await globalThis.crypto.subtle.digest("SHA-256", data); - return new Uint8Array(buffer); - } -} - + if (crypto.default && crypto.default.createHash) return crypto.default.createHash("sha256").update(data).digest(); + else { + const buffer = await globalThis.crypto.subtle.digest("SHA-256", data); + return new Uint8Array(buffer); + } +} /** - * @param {Uint8Array} data - * @param {number} offset - */ +* @param {Uint8Array} data +* @param {number} offset +*/ function readUInt32BE(data, offset) { - return new DataView(data.buffer).getUint32(offset, false); + return new DataView(data.buffer).getUint32(offset, false); } - async function getRandomRng(entropy) { - // Generate a random Rng - while (!entropy) { - entropy = await askEntropy(); - } - const hasher = blake2_js.blake2b.create(64); - hasher.update(getRandomBytes(64)); - const enc = new TextEncoder(); // always utf-8 - hasher.update(enc.encode(entropy)); - const hash = hasher.digest(); - - const seed = []; - for (let i=0;i<8;i++) { - seed[i] = readUInt32BE(hash, i*4); - } - const rng = new ffjavascript.ChaCha(seed); - return rng; -} - + while (!entropy) entropy = await askEntropy(); + const hasher = _noble_hashes_blake2_js.blake2b.create(64); + hasher.update(getRandomBytes(64)); + const enc = new TextEncoder(); + hasher.update(enc.encode(entropy)); + const hash = hasher.digest(); + const seed = []; + for (let i = 0; i < 8; i++) seed[i] = readUInt32BE(hash, i * 4); + return new ffjavascript.ChaCha(seed); +} async function rngFromBeaconParams(beaconHash, numIterationsExp) { - let nIterationsInner; - let nIterationsOuter; - if (numIterationsExp<32) { - nIterationsInner = (1 << numIterationsExp) >>> 0; - nIterationsOuter = 1; - } else { - nIterationsInner = 0x100000000; - nIterationsOuter = (1 << (numIterationsExp-32)) >>> 0; - } - - let curHash = beaconHash; - for (let i=0; i>> 0; + nIterationsOuter = 1; + } else { + nIterationsInner = 4294967296; + nIterationsOuter = 1 << numIterationsExp - 32 >>> 0; + } + let curHash = beaconHash; + for (let i = 0; i < nIterationsOuter; i++) for (let j = 0; j < nIterationsInner; j++) curHash = await sha256digest(curHash); + const curHashV = new DataView(curHash.buffer, curHash.byteOffset, curHash.byteLength); + const seed = []; + for (let i = 0; i < 8; i++) seed[i] = curHashV.getUint32(i * 4, false); + return new ffjavascript.ChaCha(seed); +} function hex2ByteArray(s) { - if (s instanceof Uint8Array) return s; - if (s.slice(0,2) == "0x") s= s.slice(2); - return new Uint8Array(s.match(/[\da-f]{2}/gi).map(function (h) { - return parseInt(h, 16); - })); + if (s instanceof Uint8Array) return s; + if (s.slice(0, 2) == "0x") s = s.slice(2); + return new Uint8Array(s.match(/[\da-f]{2}/gi).map(function(h) { + return parseInt(h, 16); + })); } - function byteArray2hex(byteArray) { - return Array.prototype.map.call(byteArray, function(byte) { - return ("0" + (byte & 0xFF).toString(16)).slice(-2); - }).join(""); + return Array.prototype.map.call(byteArray, function(byte) { + return ("0" + (byte & 255).toString(16)).slice(-2); + }).join(""); } - function stringifyBigIntsWithField(Fr, o) { - if (o instanceof Uint8Array) { - return Fr.toString(o); - } else if (Array.isArray(o)) { - return o.map(stringifyBigIntsWithField.bind(null, Fr)); - } else if (typeof o == "object") { - const res = {}; - const keys = Object.keys(o); - keys.forEach( (k) => { - res[k] = stringifyBigIntsWithField(Fr, o[k]); - }); - return res; - } else if ((typeof(o) == "bigint") || o.eq !== undefined) { - return o.toString(10); - } else { - return o; - } -} - -const HEADER_ZKEY_SECTION = 1; - -const GROTH16_PROTOCOL_ID = 1; -const PLONK_PROTOCOL_ID = 2; -const FFLONK_PROTOCOL_ID = 10; - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -// FFlonk constants -const FF_T_POL_DEG_MIN = 3; - -// ZKEY constants -const ZKEY_FF_NSECTIONS = 17; - -const ZKEY_FF_HEADER_SECTION = 2; -const ZKEY_FF_ADDITIONS_SECTION = 3; -const ZKEY_FF_A_MAP_SECTION = 4; -const ZKEY_FF_B_MAP_SECTION = 5; -const ZKEY_FF_C_MAP_SECTION = 6; -const ZKEY_FF_QL_SECTION = 7; -const ZKEY_FF_QR_SECTION = 8; -const ZKEY_FF_QM_SECTION = 9; -const ZKEY_FF_QO_SECTION = 10; -const ZKEY_FF_QC_SECTION = 11; -const ZKEY_FF_SIGMA1_SECTION = 12; -const ZKEY_FF_SIGMA2_SECTION = 13; -const ZKEY_FF_SIGMA3_SECTION = 14; -const ZKEY_FF_LAGRANGE_SECTION = 15; -const ZKEY_FF_PTAU_SECTION = 16; -const ZKEY_FF_C0_SECTION = 17; - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + if (o instanceof Uint8Array) return Fr.toString(o); + else if (Array.isArray(o)) return o.map(stringifyBigIntsWithField.bind(null, Fr)); + else if (typeof o == "object") { + const res = {}; + Object.keys(o).forEach((k) => { + res[k] = stringifyBigIntsWithField(Fr, o[k]); + }); + return res; + } else if (typeof o == "bigint" || o.eq !== void 0) return o.toString(10); + else return o; +} +//#endregion +//#region src/zkey_utils.js async function writeHeader(fd, zkey) { - - // Write the header - /////////// - await binFileUtils__namespace.startWriteSection(fd, 1); - await fd.writeULE32(1); // Groth - await binFileUtils__namespace.endWriteSection(fd); - - // Write the Groth header section - /////////// - - const curve = await getCurveFromQ(zkey.q); - - await binFileUtils__namespace.startWriteSection(fd, 2); - const primeQ = curve.q; - const n8q = (Math.floor( (ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) +1)*8; - - const primeR = curve.r; - const n8r = (Math.floor( (ffjavascript.Scalar.bitLength(primeR) - 1) / 64) +1)*8; - - await fd.writeULE32(n8q); - await binFileUtils__namespace.writeBigInt(fd, primeQ, n8q); - await fd.writeULE32(n8r); - await binFileUtils__namespace.writeBigInt(fd, primeR, n8r); - await fd.writeULE32(zkey.nVars); // Total number of bars - await fd.writeULE32(zkey.nPublic); // Total number of public vars (not including ONE) - await fd.writeULE32(zkey.domainSize); // domainSize - await writeG1(fd, curve, zkey.vk_alpha_1); - await writeG1(fd, curve, zkey.vk_beta_1); - await writeG2(fd, curve, zkey.vk_beta_2); - await writeG2(fd, curve, zkey.vk_gamma_2); - await writeG1(fd, curve, zkey.vk_delta_1); - await writeG2(fd, curve, zkey.vk_delta_2); - - await binFileUtils__namespace.endWriteSection(fd); - - -} - + await _iden3_binfileutils.startWriteSection(fd, 1); + await fd.writeULE32(1); + await _iden3_binfileutils.endWriteSection(fd); + const curve = await getCurveFromQ(zkey.q); + await _iden3_binfileutils.startWriteSection(fd, 2); + const primeQ = curve.q; + const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; + const primeR = curve.r; + const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; + await fd.writeULE32(n8q); + await _iden3_binfileutils.writeBigInt(fd, primeQ, n8q); + await fd.writeULE32(n8r); + await _iden3_binfileutils.writeBigInt(fd, primeR, n8r); + await fd.writeULE32(zkey.nVars); + await fd.writeULE32(zkey.nPublic); + await fd.writeULE32(zkey.domainSize); + await writeG1(fd, curve, zkey.vk_alpha_1); + await writeG1(fd, curve, zkey.vk_beta_1); + await writeG2(fd, curve, zkey.vk_beta_2); + await writeG2(fd, curve, zkey.vk_gamma_2); + await writeG1(fd, curve, zkey.vk_delta_1); + await writeG2(fd, curve, zkey.vk_delta_2); + await _iden3_binfileutils.endWriteSection(fd); +} async function writeG1(fd, curve, p) { - const buff = new Uint8Array(curve.G1.F.n8*2); - curve.G1.toRprLEM(buff, 0, p); - await fd.write(buff); + const buff = new Uint8Array(curve.G1.F.n8 * 2); + curve.G1.toRprLEM(buff, 0, p); + await fd.write(buff); } - async function writeG2(fd, curve, p) { - const buff = new Uint8Array(curve.G2.F.n8*2); - curve.G2.toRprLEM(buff, 0, p); - await fd.write(buff); + const buff = new Uint8Array(curve.G2.F.n8 * 2); + curve.G2.toRprLEM(buff, 0, p); + await fd.write(buff); } - async function readG1(fd, curve, toObject) { - const buff = await fd.read(curve.G1.F.n8*2); - const res = curve.G1.fromRprLEM(buff, 0); - return toObject ? curve.G1.toObject(res) : res; + const buff = await fd.read(curve.G1.F.n8 * 2); + const res = curve.G1.fromRprLEM(buff, 0); + return toObject ? curve.G1.toObject(res) : res; } - async function readG2(fd, curve, toObject) { - const buff = await fd.read(curve.G2.F.n8*2); - const res = curve.G2.fromRprLEM(buff, 0); - return toObject ? curve.G2.toObject(res) : res; + const buff = await fd.read(curve.G2.F.n8 * 2); + const res = curve.G2.fromRprLEM(buff, 0); + return toObject ? curve.G2.toObject(res) : res; } - - async function readHeader$1(fd, sections, toObject, options) { - // Read Header - ///////////////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 1); - const protocolId = await fd.readULE32(); - await binFileUtils__namespace.endReadSection(fd); - - if (protocolId === GROTH16_PROTOCOL_ID) { - return await readHeaderGroth16(fd, sections, toObject, options); - } else if (protocolId === PLONK_PROTOCOL_ID) { - return await readHeaderPlonk(fd, sections, toObject, options); - } else if (protocolId === FFLONK_PROTOCOL_ID) { - return await readHeaderFFlonk(fd, sections, toObject, options); - } else { - throw new Error("Protocol not supported: "); - } -} - - - - + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 1); + const protocolId = await fd.readULE32(); + await _iden3_binfileutils.endReadSection(fd); + if (protocolId === 1) return await readHeaderGroth16(fd, sections, toObject, options); + else if (protocolId === 2) return await readHeaderPlonk(fd, sections, toObject, options); + else if (protocolId === 10) return await readHeaderFFlonk(fd, sections, toObject, options); + else throw new Error("Protocol not supported: "); +} async function readHeaderGroth16(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "groth16"; - - // Read Groth Header - ///////////////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 2); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await binFileUtils__namespace.readBigInt(fd, n8q); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await binFileUtils__namespace.readBigInt(fd, n8r); - zkey.curve = await getCurveFromQ(zkey.q, options); - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.vk_alpha_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_beta_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_beta_2 = await readG2(fd, zkey.curve, toObject); - zkey.vk_gamma_2 = await readG2(fd, zkey.curve, toObject); - zkey.vk_delta_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_delta_2 = await readG2(fd, zkey.curve, toObject); - await binFileUtils__namespace.endReadSection(fd); - - return zkey; - -} - + const zkey = {}; + zkey.protocol = "groth16"; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 2); + const n8q = await fd.readULE32(); + zkey.n8q = n8q; + zkey.q = await _iden3_binfileutils.readBigInt(fd, n8q); + const n8r = await fd.readULE32(); + zkey.n8r = n8r; + zkey.r = await _iden3_binfileutils.readBigInt(fd, n8r); + zkey.curve = await getCurveFromQ(zkey.q, options); + zkey.nVars = await fd.readULE32(); + zkey.nPublic = await fd.readULE32(); + zkey.domainSize = await fd.readULE32(); + zkey.power = log2(zkey.domainSize); + zkey.vk_alpha_1 = await readG1(fd, zkey.curve, toObject); + zkey.vk_beta_1 = await readG1(fd, zkey.curve, toObject); + zkey.vk_beta_2 = await readG2(fd, zkey.curve, toObject); + zkey.vk_gamma_2 = await readG2(fd, zkey.curve, toObject); + zkey.vk_delta_1 = await readG1(fd, zkey.curve, toObject); + zkey.vk_delta_2 = await readG2(fd, zkey.curve, toObject); + await _iden3_binfileutils.endReadSection(fd); + return zkey; +} async function readHeaderPlonk(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "plonk"; - - // Read Plonk Header - ///////////////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 2); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await binFileUtils__namespace.readBigInt(fd, n8q); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await binFileUtils__namespace.readBigInt(fd, n8r); - zkey.curve = await getCurveFromQ(zkey.q, options); - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.nAdditions = await fd.readULE32(); - zkey.nConstraints = await fd.readULE32(); - zkey.k1 = await fd.read(n8r); - zkey.k2 = await fd.read(n8r); - - zkey.Qm = await readG1(fd, zkey.curve, toObject); - zkey.Ql = await readG1(fd, zkey.curve, toObject); - zkey.Qr = await readG1(fd, zkey.curve, toObject); - zkey.Qo = await readG1(fd, zkey.curve, toObject); - zkey.Qc = await readG1(fd, zkey.curve, toObject); - zkey.S1 = await readG1(fd, zkey.curve, toObject); - zkey.S2 = await readG1(fd, zkey.curve, toObject); - zkey.S3 = await readG1(fd, zkey.curve, toObject); - zkey.X_2 = await readG2(fd, zkey.curve, toObject); - - await binFileUtils__namespace.endReadSection(fd); - - return zkey; -} - + const zkey = {}; + zkey.protocol = "plonk"; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 2); + const n8q = await fd.readULE32(); + zkey.n8q = n8q; + zkey.q = await _iden3_binfileutils.readBigInt(fd, n8q); + const n8r = await fd.readULE32(); + zkey.n8r = n8r; + zkey.r = await _iden3_binfileutils.readBigInt(fd, n8r); + zkey.curve = await getCurveFromQ(zkey.q, options); + zkey.nVars = await fd.readULE32(); + zkey.nPublic = await fd.readULE32(); + zkey.domainSize = await fd.readULE32(); + zkey.power = log2(zkey.domainSize); + zkey.nAdditions = await fd.readULE32(); + zkey.nConstraints = await fd.readULE32(); + zkey.k1 = await fd.read(n8r); + zkey.k2 = await fd.read(n8r); + zkey.Qm = await readG1(fd, zkey.curve, toObject); + zkey.Ql = await readG1(fd, zkey.curve, toObject); + zkey.Qr = await readG1(fd, zkey.curve, toObject); + zkey.Qo = await readG1(fd, zkey.curve, toObject); + zkey.Qc = await readG1(fd, zkey.curve, toObject); + zkey.S1 = await readG1(fd, zkey.curve, toObject); + zkey.S2 = await readG1(fd, zkey.curve, toObject); + zkey.S3 = await readG1(fd, zkey.curve, toObject); + zkey.X_2 = await readG2(fd, zkey.curve, toObject); + await _iden3_binfileutils.endReadSection(fd); + return zkey; +} async function readHeaderFFlonk(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "fflonk"; - zkey.protocolId = FFLONK_PROTOCOL_ID; - - await binFileUtils__namespace.startReadUniqueSection(fd, sections, ZKEY_FF_HEADER_SECTION); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await binFileUtils__namespace.readBigInt(fd, n8q); - zkey.curve = await getCurveFromQ(zkey.q, options); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await binFileUtils__namespace.readBigInt(fd, n8r); - - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.nAdditions = await fd.readULE32(); - zkey.nConstraints = await fd.readULE32(); - - zkey.k1 = await fd.read(n8r); - zkey.k2 = await fd.read(n8r); - - zkey.w3 = await fd.read(n8r); - zkey.w4 = await fd.read(n8r); - zkey.w8 = await fd.read(n8r); - zkey.wr = await fd.read(n8r); - - zkey.X_2 = await readG2(fd, zkey.curve, toObject); - - zkey.C0 = await readG1(fd, zkey.curve, toObject); - - await binFileUtils__namespace.endReadSection(fd); - - return zkey; -} - + const zkey = {}; + zkey.protocol = "fflonk"; + zkey.protocolId = 10; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 2); + const n8q = await fd.readULE32(); + zkey.n8q = n8q; + zkey.q = await _iden3_binfileutils.readBigInt(fd, n8q); + zkey.curve = await getCurveFromQ(zkey.q, options); + const n8r = await fd.readULE32(); + zkey.n8r = n8r; + zkey.r = await _iden3_binfileutils.readBigInt(fd, n8r); + zkey.nVars = await fd.readULE32(); + zkey.nPublic = await fd.readULE32(); + zkey.domainSize = await fd.readULE32(); + zkey.power = log2(zkey.domainSize); + zkey.nAdditions = await fd.readULE32(); + zkey.nConstraints = await fd.readULE32(); + zkey.k1 = await fd.read(n8r); + zkey.k2 = await fd.read(n8r); + zkey.w3 = await fd.read(n8r); + zkey.w4 = await fd.read(n8r); + zkey.w8 = await fd.read(n8r); + zkey.wr = await fd.read(n8r); + zkey.X_2 = await readG2(fd, zkey.curve, toObject); + zkey.C0 = await readG1(fd, zkey.curve, toObject); + await _iden3_binfileutils.endReadSection(fd); + return zkey; +} async function readZKey(fileName, toObject) { - const {fd, sections} = await binFileUtils__namespace.readBinFile(fileName, "zkey", 1); - - const zkey = await readHeader$1(fd, sections, toObject); - - const Fr = new ffjavascript.F1Field(zkey.r); - const Rr = ffjavascript.Scalar.mod(ffjavascript.Scalar.shl(1, zkey.n8r*8), zkey.r); - const Rri = Fr.inv(Rr); - const Rri2 = Fr.mul(Rri, Rri); - - let curve = await getCurveFromQ(zkey.q); - - // Read IC Section - /////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 3); - zkey.IC = []; - for (let i=0; i<= zkey.nPublic; i++) { - const P = await readG1(fd, curve, toObject); - zkey.IC.push(P); - } - await binFileUtils__namespace.endReadSection(fd); - - - // Read Coefs - /////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 4); - const nCCoefs = await fd.readULE32(); - zkey.ccoefs = []; - for (let i=0; i0) { - const paramsBuff = new Uint8Array(params); - await fd.writeULE32(paramsBuff.byteLength); - await fd.write(paramsBuff); - } else { - await fd.writeULE32(0); - } - -} - + await writeG1(fd, curve, c.deltaAfter); + await writeG1(fd, curve, c.delta.g1_s); + await writeG1(fd, curve, c.delta.g1_sx); + await writeG2(fd, curve, c.delta.g2_spx); + await fd.write(c.transcript); + await fd.writeULE32(c.type || 0); + const params = []; + if (c.name) { + params.push(1); + const nameData = new TextEncoder("utf-8").encode(c.name.substring(0, 64)); + params.push(nameData.byteLength); + for (let i = 0; i < nameData.byteLength; i++) params.push(nameData[i]); + } + if (c.type == 1) { + params.push(2); + params.push(c.numIterationsExp); + params.push(3); + params.push(c.beaconHash.byteLength); + for (let i = 0; i < c.beaconHash.byteLength; i++) params.push(c.beaconHash[i]); + } + if (params.length > 0) { + const paramsBuff = new Uint8Array(params); + await fd.writeULE32(paramsBuff.byteLength); + await fd.write(paramsBuff); + } else await fd.writeULE32(0); +} async function writeMPCParams(fd, curve, mpcParams) { - await binFileUtils__namespace.startWriteSection(fd, 10); - await fd.write(mpcParams.csHash); - await fd.writeULE32(mpcParams.contributions.length); - for (let i=0; i. -*/ - - - + hashG1(hasher, curve, c.deltaAfter); + hashG1(hasher, curve, c.delta.g1_s); + hashG1(hasher, curve, c.delta.g1_sx); + hashG2(hasher, curve, c.delta.g2_spx); + hasher.update(c.transcript); +} +//#endregion +//#region src/wtns_utils.js async function write(fd, witness, prime) { - - await binFileUtils__namespace.startWriteSection(fd, 1); - const n8 = (Math.floor( (ffjavascript.Scalar.bitLength(prime) - 1) / 64) +1)*8; - await fd.writeULE32(n8); - await binFileUtils__namespace.writeBigInt(fd, prime, n8); - await fd.writeULE32(witness.length); - await binFileUtils__namespace.endWriteSection(fd); - - await binFileUtils__namespace.startWriteSection(fd, 2); - for (let i=0; i. -*/ - -const {stringifyBigInts: stringifyBigInts$4} = ffjavascript.utils; - + const { fd, sections } = await _iden3_binfileutils.readBinFile(fileName, "wtns", 2); + const { n8, nWitness } = await readHeader(fd, sections); + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 2); + const res = []; + for (let i = 0; i < nWitness; i++) { + const v = await _iden3_binfileutils.readBigInt(fd, n8); + res.push(v); + } + await _iden3_binfileutils.endReadSection(fd); + await fd.close(); + return res; +} +//#endregion +//#region src/groth16_prove.js +var { stringifyBigInts: stringifyBigInts$4 } = ffjavascript.utils; async function groth16Prove(zkeyFileName, witnessFileName, logger, options) { - // Opt-in periodic memory-usage logging (heap/RSS/external/ArrayBuffers). - // options.memoryLogging: true (1s interval) or an interval in ms. - // Node-only: process.memoryUsage does not exist in browsers. - let memTimer = null; - if (logger && options && options.memoryLogging - && typeof process !== "undefined" && typeof process.memoryUsage === "function") { - const interval = Number(options.memoryLogging) > 1 ? Number(options.memoryLogging) : 1000; - memTimer = monitorMemoryUsage(logger, interval); - } - try { - return await _groth16Prove(zkeyFileName, witnessFileName, logger, options); - } finally { - if (memTimer) { - clearInterval(memTimer); - memUsage(logger); - } - } -} - + let memTimer = null; + if (logger && options && options.memoryLogging && typeof process !== "undefined" && typeof process.memoryUsage === "function") memTimer = monitorMemoryUsage(logger, Number(options.memoryLogging) > 1 ? Number(options.memoryLogging) : 1e3); + try { + return await _groth16Prove(zkeyFileName, witnessFileName, logger, options); + } finally { + if (memTimer) { + clearInterval(memTimer); + memUsage(logger); + } + } +} async function _groth16Prove(zkeyFileName, witnessFileName, logger, options) { - - const {fd: fdWtns, sections: sectionsWtns} = await binFileUtils__namespace.readBinFile(witnessFileName, "wtns", 2, 1<<25, 1<<23); - - const wtns = await readHeader(fdWtns, sectionsWtns); - - const {fd: fdZKey, sections: sectionsZKey} = await binFileUtils__namespace.readBinFile(zkeyFileName, "zkey", 2, 1<<25, 1<<23); - - const zkey = await readHeader$1(fdZKey, sectionsZKey, undefined, options); - - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness != zkey.nVars) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}`); - } - - const curve = zkey.curve; - const Fr = curve.Fr; - const G1 = curve.G1; - const G2 = curve.G2; - - options = options || {}; - - // MSM batching mode, threaded to every multiexp below: - // "auto" (default) use the batch-affine MSM module only for - // cache-friendly chunk sizes (where it is measurably faster); - // "enabled" always use it (best for small/medium circuits); - // "disabled" never use it (plain in-module multiexp; lowest memory). - const msmBatching = options.msmBatching || "auto"; - if (msmBatching !== "auto" && msmBatching !== "enabled" && msmBatching !== "disabled") { - throw new Error(`groth16Prove: invalid msmBatching "${msmBatching}" (expected "auto", "enabled" or "disabled")`); - } - // msmGlv / msmGls: "auto" (default -- use the G1/G2 endomorphism MSM paths - // where the curve supports them; the wasm still gates internally on chunk - // sizes) or "disabled" (generic batch accumulation). A/B and debugging - // aids, like msmBatching. - const msmGlv = options.msmGlv || "auto"; - const msmGls = options.msmGls || "auto"; - for (const [name, v] of [["msmGlv", msmGlv], ["msmGls", msmGls]]) { - if (v !== "auto" && v !== "disabled") { - throw new Error(`groth16Prove: invalid ${name} "${v}" (expected "auto" or "disabled")`); - } - } - const msmOpts = { batch: msmBatching, glv: msmGlv, gls: msmGls }; - - const power = log2(zkey.domainSize); - - if (logger) logger.debug("Reading Wtns"); - const buffWitness = await binFileUtils__namespace.readSection(fdWtns, sectionsWtns, 2); - - // Reader for a zkey section that returns an arbitrary sub-range directly from - // disk, used to feed multiExp bases to the workers in chunks instead of - // reading the whole (potentially hundreds of MB) section into one buffer and - // slicing it. Bounds the bases resident in RAM to a few in-flight chunks. - const mkSectionReader = (idSection) => { - const start = sectionsZKey[idSection][0].p; - const size = sectionsZKey[idSection][0].size; - return async (off, len) => { - if (off + len > size) throw new Error(`groth16Prove: read out of range of section ${idSection}`); - const buff = new Uint8Array(len); - await fdZKey.readToBuffer(buff, 0, len, start + off); - return buff; - }; - }; - - let resH; - let resHPromise; - let buffPodd_T; - - let abcPromise = (async function (){ - let buffA_T, buffB_T, buffC_T; - - await (async function (){ - if (logger) logger.debug("Reading Coeffs"); - const buffCoeffs = await binFileUtils__namespace.readSection(fdZKey, sectionsZKey, 4); - - if (logger) logger.debug("Building ABC"); - - if (options.buildABC === "js") { - [buffA_T, buffB_T, buffC_T] = await buildABC1(curve, zkey, buffWitness, buffCoeffs, logger); - } else if (options.buildABC === "stream") { - const p = pickStreamParams(curve, zkey, buffCoeffs, options); - [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); - } else { - // Default: streaming build (bounded worker memory, tunable - // parallelism). The per-chunk witness gather keeps the witness - // out of WASM entirely, so there is no witness size limit. - const p = pickStreamParams(curve, zkey, buffCoeffs, options); - if (logger) logger.debug(`buildABC: stream nChunks=${p.nChunks} maxInFlight=${p.maxInFlight}`); - [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); - } - })(); - - - // Do not call gc() here. gc() is a stop-the-world pause that blocks the - // Node.js event loop. If the pause exceeds the worker idle-termination - // timeout (1s), a worker closes its port while the main thread is blocked, - // and the next task dispatched to it is silently dropped → hang. The - // coefficients buffer goes out of scope at the end of the inner IIFE above - // and is reclaimed by V8's incremental GC automatically. - - const inc = power === Fr.s ? curve.Fr.shift : curve.Fr.w[power+1]; - - let buffAodd_T, buffBodd_T, buffCodd_T; - // The IFFT input (buffX_T) is dropped immediately, and the FFT input - // (buffXodd) goes out of scope right after -- so both can be consumed - // (consume=true), skipping ffjavascript's defensive full-input copy. - await Promise.all([ - (async function () { - let buffA = await Fr.ifft(buffA_T, "", "", logger, "IFFT_A", true); - buffA_T = null; - const buffAodd = await Fr.batchApplyKey(buffA, Fr.e(1), inc); - buffAodd_T = await Fr.fft(buffAodd, "", "", logger, "FFT_A", true); - })(), - (async function () { - let buffB = await Fr.ifft(buffB_T, "", "", logger, "IFFT_B", true); - buffB_T = null; - const buffBodd = await Fr.batchApplyKey(buffB, Fr.e(1), inc); - buffBodd_T = await Fr.fft(buffBodd, "", "", logger, "FFT_B", true); - })(), - (async function () { - let buffC = await Fr.ifft(buffC_T, "", "", logger, "IFFT_C", true); - buffC_T = null; - const buffCodd = await Fr.batchApplyKey(buffC, Fr.e(1), inc); - buffCodd_T = await Fr.fft(buffCodd, "", "", logger, "FFT_C", true); - })(), - ]); - - if (logger) logger.debug("Join ABC"); - buffPodd_T = await joinABC(curve, zkey, buffAodd_T, buffBodd_T, buffCodd_T, logger); - if (logger) logger.debug("Join ABC finished"); - buffAodd_T = null; - buffBodd_T = null; - buffCodd_T = null; - - if (globalThis.gc) {globalThis.gc();} - })(); - //await abcPromise; - - let proof = {}; - - async function calcPiA(){ - if (logger) logger.debug("Reading A Points"); - proof.pi_a = await curve.G1.multiExpAffineChunked(mkSectionReader(5), sectionsZKey[5][0].size, buffWitness, logger, "multiexp A", msmOpts); - } - - let piaPromise = calcPiA(); - //await piaPromise; - - let pib1; - - async function calcPiB1() { - if (logger) logger.debug("Reading B1 Points"); - pib1 = await curve.G1.multiExpAffineChunked(mkSectionReader(6), sectionsZKey[6][0].size, buffWitness, logger, "multiexp B1", msmOpts); - } - - let pib1Promise = calcPiB1(); - //await pib1Promise; - - async function calcPiB() { - if (logger) logger.debug("Reading B2 Points"); - proof.pi_b = await curve.G2.multiExpAffineChunked(mkSectionReader(7), sectionsZKey[7][0].size, buffWitness, logger, "multiexp B2", msmOpts); - } - - let pibPromise = calcPiB(); - //await pibPromise; - - let picPromise = (async function (){ - if (logger) logger.debug("Reading C Points"); - proof.pi_c = await curve.G1.multiExpAffineChunked(mkSectionReader(8), sectionsZKey[8][0].size, buffWitness.slice((zkey.nPublic+1)*curve.Fr.n8), logger, "multiexp C", msmOpts); - })(); - //await picPromise; - - resHPromise = (async function (){ - if (logger) logger.debug("Reading H Points"); - await abcPromise; - resH = await curve.G1.multiExpAffineChunked(mkSectionReader(9), sectionsZKey[9][0].size, buffPodd_T, logger, "multiexp H", msmOpts); - })(); - //await resHPromise; - - - const r = curve.Fr.random(); - const s = curve.Fr.random(); - - await piaPromise; - proof.pi_a = G1.add( proof.pi_a, zkey.vk_alpha_1 ); - proof.pi_a = G1.add( proof.pi_a, G1.timesFr( zkey.vk_delta_1, r )); - - await pibPromise; - proof.pi_b = G2.add( proof.pi_b, zkey.vk_beta_2 ); - proof.pi_b = G2.add( proof.pi_b, G2.timesFr( zkey.vk_delta_2, s )); - - await pib1Promise; - pib1 = G1.add( pib1, zkey.vk_beta_1 ); - pib1 = G1.add( pib1, G1.timesFr( zkey.vk_delta_1, s )); - - await Promise.all([picPromise, resHPromise]); - proof.pi_c = G1.add(proof.pi_c, resH); - - - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( proof.pi_a, s )); - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( pib1, r )); - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( zkey.vk_delta_1, Fr.neg(Fr.mul(r,s) ))); - - - let publicSignals = []; - - for (let i=1; i<= zkey.nPublic; i++) { - const b = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8); - publicSignals.push(ffjavascript.Scalar.fromRprLE(b)); - } - - proof.pi_a = G1.toObject(G1.toAffine(proof.pi_a)); - proof.pi_b = G2.toObject(G2.toAffine(proof.pi_b)); - proof.pi_c = G1.toObject(G1.toAffine(proof.pi_c)); - - proof.protocol = "groth16"; - proof.curve = curve.name; - - await fdZKey.close(); - await fdWtns.close(); - - proof = stringifyBigInts$4(proof); - publicSignals = stringifyBigInts$4(publicSignals); - - return {proof, publicSignals}; -} - - + const { fd: fdWtns, sections: sectionsWtns } = await _iden3_binfileutils.readBinFile(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); + const wtns = await readHeader(fdWtns, sectionsWtns); + const { fd: fdZKey, sections: sectionsZKey } = await _iden3_binfileutils.readBinFile(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); + const zkey = await readHeader$1(fdZKey, sectionsZKey, void 0, options); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) throw new Error("Curve of the witness does not match the curve of the proving key"); + if (wtns.nWitness != zkey.nVars) throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}`); + const curve = zkey.curve; + const Fr = curve.Fr; + const G1 = curve.G1; + const G2 = curve.G2; + options = options || {}; + const msmBatching = options.msmBatching || "auto"; + if (msmBatching !== "auto" && msmBatching !== "enabled" && msmBatching !== "disabled") throw new Error(`groth16Prove: invalid msmBatching "${msmBatching}" (expected "auto", "enabled" or "disabled")`); + const msmGlv = options.msmGlv || "auto"; + const msmGls = options.msmGls || "auto"; + for (const [name, v] of [["msmGlv", msmGlv], ["msmGls", msmGls]]) if (v !== "auto" && v !== "disabled") throw new Error(`groth16Prove: invalid ${name} "${v}" (expected "auto" or "disabled")`); + const msmOpts = { + batch: msmBatching, + glv: msmGlv, + gls: msmGls + }; + const power = log2(zkey.domainSize); + if (logger) logger.debug("Reading Wtns"); + const buffWitness = await _iden3_binfileutils.readSection(fdWtns, sectionsWtns, 2); + const mkSectionReader = (idSection) => { + const start = sectionsZKey[idSection][0].p; + const size = sectionsZKey[idSection][0].size; + return async (off, len) => { + if (off + len > size) throw new Error(`groth16Prove: read out of range of section ${idSection}`); + const buff = new Uint8Array(len); + await fdZKey.readToBuffer(buff, 0, len, start + off); + return buff; + }; + }; + let resH; + let resHPromise; + let buffPodd_T; + let abcPromise = (async function() { + let buffA_T, buffB_T, buffC_T; + await (async function() { + if (logger) logger.debug("Reading Coeffs"); + const buffCoeffs = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 4); + if (logger) logger.debug("Building ABC"); + if (options.buildABC === "js") [buffA_T, buffB_T, buffC_T] = await buildABC1(curve, zkey, buffWitness, buffCoeffs, logger); + else if (options.buildABC === "stream") { + const p = pickStreamParams(curve, zkey, buffCoeffs, options); + [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); + } else { + const p = pickStreamParams(curve, zkey, buffCoeffs, options); + if (logger) logger.debug(`buildABC: stream nChunks=${p.nChunks} maxInFlight=${p.maxInFlight}`); + [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); + } + })(); + const inc = power === Fr.s ? curve.Fr.shift : curve.Fr.w[power + 1]; + let buffAodd_T, buffBodd_T, buffCodd_T; + await Promise.all([ + (async function() { + let buffA = await Fr.ifft(buffA_T, "", "", logger, "IFFT_A", true); + buffA_T = null; + const buffAodd = await Fr.batchApplyKey(buffA, Fr.e(1), inc); + buffAodd_T = await Fr.fft(buffAodd, "", "", logger, "FFT_A", true); + })(), + (async function() { + let buffB = await Fr.ifft(buffB_T, "", "", logger, "IFFT_B", true); + buffB_T = null; + const buffBodd = await Fr.batchApplyKey(buffB, Fr.e(1), inc); + buffBodd_T = await Fr.fft(buffBodd, "", "", logger, "FFT_B", true); + })(), + (async function() { + let buffC = await Fr.ifft(buffC_T, "", "", logger, "IFFT_C", true); + buffC_T = null; + const buffCodd = await Fr.batchApplyKey(buffC, Fr.e(1), inc); + buffCodd_T = await Fr.fft(buffCodd, "", "", logger, "FFT_C", true); + })() + ]); + if (logger) logger.debug("Join ABC"); + buffPodd_T = await joinABC(curve, zkey, buffAodd_T, buffBodd_T, buffCodd_T, logger); + if (logger) logger.debug("Join ABC finished"); + buffAodd_T = null; + buffBodd_T = null; + buffCodd_T = null; + if (globalThis.gc) globalThis.gc(); + })(); + let proof = {}; + async function calcPiA() { + if (logger) logger.debug("Reading A Points"); + proof.pi_a = await curve.G1.multiExpAffineChunked(mkSectionReader(5), sectionsZKey[5][0].size, buffWitness, logger, "multiexp A", msmOpts); + } + let piaPromise = calcPiA(); + let pib1; + async function calcPiB1() { + if (logger) logger.debug("Reading B1 Points"); + pib1 = await curve.G1.multiExpAffineChunked(mkSectionReader(6), sectionsZKey[6][0].size, buffWitness, logger, "multiexp B1", msmOpts); + } + let pib1Promise = calcPiB1(); + async function calcPiB() { + if (logger) logger.debug("Reading B2 Points"); + proof.pi_b = await curve.G2.multiExpAffineChunked(mkSectionReader(7), sectionsZKey[7][0].size, buffWitness, logger, "multiexp B2", msmOpts); + } + let pibPromise = calcPiB(); + let picPromise = (async function() { + if (logger) logger.debug("Reading C Points"); + proof.pi_c = await curve.G1.multiExpAffineChunked(mkSectionReader(8), sectionsZKey[8][0].size, buffWitness.slice((zkey.nPublic + 1) * curve.Fr.n8), logger, "multiexp C", msmOpts); + })(); + resHPromise = (async function() { + if (logger) logger.debug("Reading H Points"); + await abcPromise; + resH = await curve.G1.multiExpAffineChunked(mkSectionReader(9), sectionsZKey[9][0].size, buffPodd_T, logger, "multiexp H", msmOpts); + })(); + const r = curve.Fr.random(); + const s = curve.Fr.random(); + await piaPromise; + proof.pi_a = G1.add(proof.pi_a, zkey.vk_alpha_1); + proof.pi_a = G1.add(proof.pi_a, G1.timesFr(zkey.vk_delta_1, r)); + await pibPromise; + proof.pi_b = G2.add(proof.pi_b, zkey.vk_beta_2); + proof.pi_b = G2.add(proof.pi_b, G2.timesFr(zkey.vk_delta_2, s)); + await pib1Promise; + pib1 = G1.add(pib1, zkey.vk_beta_1); + pib1 = G1.add(pib1, G1.timesFr(zkey.vk_delta_1, s)); + await Promise.all([picPromise, resHPromise]); + proof.pi_c = G1.add(proof.pi_c, resH); + proof.pi_c = G1.add(proof.pi_c, G1.timesFr(proof.pi_a, s)); + proof.pi_c = G1.add(proof.pi_c, G1.timesFr(pib1, r)); + proof.pi_c = G1.add(proof.pi_c, G1.timesFr(zkey.vk_delta_1, Fr.neg(Fr.mul(r, s)))); + let publicSignals = []; + for (let i = 1; i <= zkey.nPublic; i++) { + const b = buffWitness.slice(i * Fr.n8, i * Fr.n8 + Fr.n8); + publicSignals.push(ffjavascript.Scalar.fromRprLE(b)); + } + proof.pi_a = G1.toObject(G1.toAffine(proof.pi_a)); + proof.pi_b = G2.toObject(G2.toAffine(proof.pi_b)); + proof.pi_c = G1.toObject(G1.toAffine(proof.pi_c)); + proof.protocol = "groth16"; + proof.curve = curve.name; + await fdZKey.close(); + await fdWtns.close(); + proof = stringifyBigInts$4(proof); + publicSignals = stringifyBigInts$4(publicSignals); + return { + proof, + publicSignals + }; +} async function buildABC1(curve, zkey, witness, coeffs, logger) { - const n8 = curve.Fr.n8; - const sCoef = 4*3 + zkey.n8r; - const nCoef = (coeffs.byteLength-4) / sCoef; - - const outBuffA = new ffjavascript.BigBuffer(zkey.domainSize * n8); - const outBuffB = new ffjavascript.BigBuffer(zkey.domainSize * n8); - const outBuffC = new ffjavascript.BigBuffer(zkey.domainSize * n8); - - const outBuf = [ outBuffA, outBuffB ]; - for (let i=0; i coeffsDV[Math.floor(pos / PAGE_LEN)].getUint32(pos % PAGE_LEN, true); - } else { - const coeffsDV = new DataView(coeffs.buffer, coeffs.byteOffset, coeffs.byteLength); - getUint32 = (pos) => coeffsDV.getUint32(pos, true); - } - function getCutPoint(v) { - let m = 0, n = getUint32(0); - while (m < n) { - const k = Math.floor((n + m) / 2); - const va = getUint32(4 + k * sCoef + 4); - if (va > v) n = k - 1; else if (va < v) m = k + 1; else n = k; - } - return 4 + m * sCoef; - } - - const elementsPerChunk = Math.floor((domainSize - 1) / nChunks) + 1; - const cutPoints = []; - for (let i = 0; i < nChunks; i++) cutPoints.push(getCutPoint(i * elementsPerChunk)); - cutPoints.push(coeffs.byteLength); - - // Return a flat Uint8Array when the domain fits under BigBuffer's 1 GiB page, - // so the downstream IFFT can consume it in place (skip its defensive copy). - // Larger domains stay paged BigBuffers (the IFFT flattens those as before). - const outBytes = domainSize * n8; - const mkOut = () => (outBytes < (1 << 30)) ? new Uint8Array(outBytes) : new ffjavascript.BigBuffer(outBytes); - const outBuffA = mkOut(); - const outBuffB = mkOut(); - const outBuffC = mkOut(); - - const inFlight = new Set(); - const tasks = []; - for (let i = 0; i < nChunks; i++) { - const outOffset = i * elementsPerChunk; - const n = Math.min(elementsPerChunk, domainSize - outOffset); - if (n <= 0) break; - const cpA = cutPoints[i], cpB = cutPoints[i + 1]; - while (inFlight.size >= maxInFlight) await Promise.race(inFlight); - if (logger) logger.debug(`buildABCStream: ${i}/${nChunks}`); - const op = (async () => { - // Gather the witness values this chunk references into a compact - // buffer (one entry per coefficient, in coefficient order) and - // rewrite each coefficient's s-index to its sequential position. - // The witness itself never enters WASM, so its size is unbounded - // (it can stay a BigBuffer) and each task ships only what it uses - // -- typically much less than a full witness copy per task. - const coeffChunk = coeffs.slice(cpA, cpB); - const nCoefChunk = (cpB - cpA) / sCoef; - const gathered = new Uint8Array(nCoefChunk * n8); - // Hot loop (one iteration per coefficient): use typed-array lane - // copies instead of set(subarray) -- per-element memcpy dispatch - // dominated the profile otherwise. Uint32 lanes on purpose: the - // data is integer bit patterns, and Float64Array stores may - // legally canonicalize NaN-patterned lanes (SetValueInBuffer is - // implementation-defined for NaN encodings). The s-field offsets - // are 4-byte aligned (sCoef and the +8 offset are multiples of 4). - const chunkU32 = new Uint32Array(coeffChunk.buffer, coeffChunk.byteOffset, coeffChunk.byteLength >> 2); - const sStep = sCoef >> 2; - const laneFast = !!witness.buffer && ((witness.byteOffset & 3) === 0) && (n8 === 32); - if (laneFast) { - const wU32 = new Uint32Array(witness.buffer, witness.byteOffset, witness.byteLength >> 2); - const gU32 = new Uint32Array(gathered.buffer); - for (let j = 0; j < nCoefChunk; j++) { - const si = chunkU32[j * sStep + 2]; - const so = si << 3, go = j << 3; - gU32[go] = wU32[so]; gU32[go + 1] = wU32[so + 1]; - gU32[go + 2] = wU32[so + 2]; gU32[go + 3] = wU32[so + 3]; - gU32[go + 4] = wU32[so + 4]; gU32[go + 5] = wU32[so + 5]; - gU32[go + 6] = wU32[so + 6]; gU32[go + 7] = wU32[so + 7]; - chunkU32[j * sStep + 2] = j; - } - } else { - const witnessIsView = !!witness.buffer; - for (let j = 0; j < nCoefChunk; j++) { - const s = chunkU32[j * sStep + 2]; - if (witnessIsView) gathered.set(witness.subarray(s * n8, (s + 1) * n8), j * n8); - else gathered.set(witness.slice(s * n8, (s + 1) * n8), j * n8); - chunkU32[j * sStep + 2] = j; - } - } - const task = [ - {cmd: "ALLOCSET", var: 0, buff: coeffChunk}, - {cmd: "ALLOCSET", var: 1, buff: gathered}, - {cmd: "ALLOC", var: 2, len: n * n8}, - {cmd: "ALLOC", var: 3, len: n * n8}, - {cmd: "ALLOC", var: 4, len: n * n8}, - {cmd: "CALL", fnName: "qap_buildABC", params: [ - {var: 0}, {val: nCoefChunk}, {var: 1}, - {var: 2}, {var: 3}, {var: 4}, - {val: outOffset}, {val: n}, {val: 0}, {val: nCoefChunk}, - ]}, - {cmd: "GET", out: 0, var: 2, len: n * n8}, - {cmd: "GET", out: 1, var: 3, len: n * n8}, - {cmd: "GET", out: 2, var: 4, len: n * n8}, - ]; - const r = await curve.tm.queueAction(task, [coeffChunk.buffer, gathered.buffer]); - outBuffA.set(r[0], outOffset * n8); - outBuffB.set(r[1], outOffset * n8); - outBuffC.set(r[2], outOffset * n8); - })(); - const slot = op.finally(() => inFlight.delete(slot)); - inFlight.add(slot); - tasks.push(slot); - } - await Promise.all(tasks); - return [outBuffA, outBuffB, outBuffC]; -} - + const n8 = curve.Fr.n8; + const sCoef = 12 + zkey.n8r; + const domainSize = zkey.domainSize; + let getUint32; + if (coeffs instanceof ffjavascript.BigBuffer) { + const coeffsDV = []; + const PAGE_LEN = coeffs.buffers[0].length; + for (let i = 0; i < coeffs.buffers.length; i++) coeffsDV.push(new DataView(coeffs.buffers[i].buffer)); + getUint32 = (pos) => coeffsDV[Math.floor(pos / PAGE_LEN)].getUint32(pos % PAGE_LEN, true); + } else { + const coeffsDV = new DataView(coeffs.buffer, coeffs.byteOffset, coeffs.byteLength); + getUint32 = (pos) => coeffsDV.getUint32(pos, true); + } + function getCutPoint(v) { + let m = 0, n = getUint32(0); + while (m < n) { + const k = Math.floor((n + m) / 2); + const va = getUint32(4 + k * sCoef + 4); + if (va > v) n = k - 1; + else if (va < v) m = k + 1; + else n = k; + } + return 4 + m * sCoef; + } + const elementsPerChunk = Math.floor((domainSize - 1) / nChunks) + 1; + const cutPoints = []; + for (let i = 0; i < nChunks; i++) cutPoints.push(getCutPoint(i * elementsPerChunk)); + cutPoints.push(coeffs.byteLength); + const outBytes = domainSize * n8; + const mkOut = () => outBytes < 1 << 30 ? new Uint8Array(outBytes) : new ffjavascript.BigBuffer(outBytes); + const outBuffA = mkOut(); + const outBuffB = mkOut(); + const outBuffC = mkOut(); + const inFlight = /* @__PURE__ */ new Set(); + const tasks = []; + for (let i = 0; i < nChunks; i++) { + const outOffset = i * elementsPerChunk; + const n = Math.min(elementsPerChunk, domainSize - outOffset); + if (n <= 0) break; + const cpA = cutPoints[i], cpB = cutPoints[i + 1]; + while (inFlight.size >= maxInFlight) await Promise.race(inFlight); + if (logger) logger.debug(`buildABCStream: ${i}/${nChunks}`); + const slot = (async () => { + const coeffChunk = coeffs.slice(cpA, cpB); + const nCoefChunk = (cpB - cpA) / sCoef; + const gathered = new Uint8Array(nCoefChunk * n8); + const chunkU32 = new Uint32Array(coeffChunk.buffer, coeffChunk.byteOffset, coeffChunk.byteLength >> 2); + const sStep = sCoef >> 2; + if (!!witness.buffer && (witness.byteOffset & 3) === 0 && n8 === 32) { + const wU32 = new Uint32Array(witness.buffer, witness.byteOffset, witness.byteLength >> 2); + const gU32 = new Uint32Array(gathered.buffer); + for (let j = 0; j < nCoefChunk; j++) { + const so = chunkU32[j * sStep + 2] << 3, go = j << 3; + gU32[go] = wU32[so]; + gU32[go + 1] = wU32[so + 1]; + gU32[go + 2] = wU32[so + 2]; + gU32[go + 3] = wU32[so + 3]; + gU32[go + 4] = wU32[so + 4]; + gU32[go + 5] = wU32[so + 5]; + gU32[go + 6] = wU32[so + 6]; + gU32[go + 7] = wU32[so + 7]; + chunkU32[j * sStep + 2] = j; + } + } else { + const witnessIsView = !!witness.buffer; + for (let j = 0; j < nCoefChunk; j++) { + const s = chunkU32[j * sStep + 2]; + if (witnessIsView) gathered.set(witness.subarray(s * n8, (s + 1) * n8), j * n8); + else gathered.set(witness.slice(s * n8, (s + 1) * n8), j * n8); + chunkU32[j * sStep + 2] = j; + } + } + const task = [ + { + cmd: "ALLOCSET", + var: 0, + buff: coeffChunk + }, + { + cmd: "ALLOCSET", + var: 1, + buff: gathered + }, + { + cmd: "ALLOC", + var: 2, + len: n * n8 + }, + { + cmd: "ALLOC", + var: 3, + len: n * n8 + }, + { + cmd: "ALLOC", + var: 4, + len: n * n8 + }, + { + cmd: "CALL", + fnName: "qap_buildABC", + params: [ + { var: 0 }, + { val: nCoefChunk }, + { var: 1 }, + { var: 2 }, + { var: 3 }, + { var: 4 }, + { val: outOffset }, + { val: n }, + { val: 0 }, + { val: nCoefChunk } + ] + }, + { + cmd: "GET", + out: 0, + var: 2, + len: n * n8 + }, + { + cmd: "GET", + out: 1, + var: 3, + len: n * n8 + }, + { + cmd: "GET", + out: 2, + var: 4, + len: n * n8 + } + ]; + const r = await curve.tm.queueAction(task, [coeffChunk.buffer, gathered.buffer]); + outBuffA.set(r[0], outOffset * n8); + outBuffB.set(r[1], outOffset * n8); + outBuffC.set(r[2], outOffset * n8); + })().finally(() => inFlight.delete(slot)); + inFlight.add(slot); + tasks.push(slot); + } + await Promise.all(tasks); + return [ + outBuffA, + outBuffB, + outBuffC + ]; +} async function joinABC(curve, zkey, a, b, c, logger) { - const MAX_CHUNK_SIZE = 1 << 16; - - const n8 = curve.Fr.n8; - const nElements = Math.floor(a.byteLength / curve.Fr.n8); - - const promises = []; - - for (let i=0; i { - memUsage(logger); - }, interval); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const { unstringifyBigInts: unstringifyBigInts$b} = ffjavascript.utils; - + if (!logger) return; + const used = process.memoryUsage(); + logger.info(" ", "\x1B[0m Heap:\x1B[32m", `${Math.round(used.heapUsed / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m / \x1B[32m", `${Math.round(used.heapTotal / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m RSS:\x1B[32m", `${Math.round(used.rss / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m External:\x1B[32m", `${Math.round(used.external / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m ArrBuffers:\x1B[32m", `${Math.round(used.arrayBuffers / 1024 / 1024 * 100) / 100} MB`.padEnd(12), "\x1B[0m"); +} +function monitorMemoryUsage(logger, interval = 5e3) { + return setInterval(() => { + memUsage(logger); + }, interval); +} +//#endregion +//#region src/wtns_calculate.js +var { unstringifyBigInts: unstringifyBigInts$11 } = ffjavascript.utils; async function wtnsCalculate(_input, wasmFileName, wtnsFileName, options) { - const input = unstringifyBigInts$b(_input); - - const fdWasm = await fastFile__namespace.readExisting(wasmFileName); - const wasm = await fdWasm.read(fdWasm.totalSize); - await fdWasm.close(); - - const wc = await circom_runtime.WitnessCalculatorBuilder(wasm, options); - if (wc.circom_version() === 1) { - const w = await wc.calculateBinWitness(input); - - const fdWtns = await binFileUtils__namespace.createBinFile(wtnsFileName, "wtns", 2, 2); - - await writeBin(fdWtns, w, wc.prime); - await fdWtns.close(); - } else { - const fdWtns = await fastFile__namespace.createOverride(wtnsFileName); - - const w = await wc.calculateWTNSBin(input); - - await fdWtns.write(w); - await fdWtns.close(); - } -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const {unstringifyBigInts: unstringifyBigInts$a} = ffjavascript.utils; - + const input = unstringifyBigInts$11(_input); + const fdWasm = await fastfile.readExisting(wasmFileName); + const wasm = await fdWasm.read(fdWasm.totalSize); + await fdWasm.close(); + const wc = await (0, circom_runtime.WitnessCalculatorBuilder)(wasm, options); + if (wc.circom_version() === 1) { + const w = await wc.calculateBinWitness(input); + const fdWtns = await _iden3_binfileutils.createBinFile(wtnsFileName, "wtns", 2, 2); + await writeBin(fdWtns, w, wc.prime); + await fdWtns.close(); + } else { + const fdWtns = await fastfile.createOverride(wtnsFileName); + const w = await wc.calculateWTNSBin(input); + await fdWtns.write(w); + await fdWtns.close(); + } +} +//#endregion +//#region src/groth16_fullprove.js +var { unstringifyBigInts: unstringifyBigInts$10 } = ffjavascript.utils; async function groth16FullProve(_input, wasmFile, zkeyFileName, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$a(_input); - - const wtns= { - type: "mem" - }; - await wtnsCalculate(input, wasmFile, wtns, wtnsCalcOptions); - return await groth16Prove(zkeyFileName, wtns, logger, proverOptions); -} - -/* - Copyright 2018 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const {unstringifyBigInts: unstringifyBigInts$9} = ffjavascript.utils; - + const input = unstringifyBigInts$10(_input); + const wtns = { type: "mem" }; + await wtnsCalculate(input, wasmFile, wtns, wtnsCalcOptions); + return await groth16Prove(zkeyFileName, wtns, logger, proverOptions); +} +//#endregion +//#region src/groth16_verify.js +var { unstringifyBigInts: unstringifyBigInts$9 } = ffjavascript.utils; async function groth16Verify(_vk_verifier, _publicSignals, _proof, logger) { -/* - let cpub = vk_verifier.IC[0]; - for (let s= 0; s< vk_verifier.nPublic; s++) { - cpub = G1.add( cpub, G1.timesScalar( vk_verifier.IC[s+1], publicSignals[s])); - } -*/ - - const vk_verifier = unstringifyBigInts$9(_vk_verifier); - const proof = unstringifyBigInts$9(_proof); - const publicSignals = unstringifyBigInts$9(_publicSignals); - - const curve = await getCurveFromName(vk_verifier.curve); - - const IC0 = curve.G1.fromObject(vk_verifier.IC[0]); - const IC = new Uint8Array(curve.G1.F.n8*2 * publicSignals.length); - const w = new Uint8Array(curve.Fr.n8 * publicSignals.length); - - if (!publicInputsAreValid$2(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - for (let i=0; i. -*/ -const { unstringifyBigInts: unstringifyBigInts$8} = ffjavascript.utils; - + for (let i = 0; i < publicInputs.length; i++) if (!checkValueBelongToField$2(curve, publicInputs[i])) return false; + return true; +} +//#endregion +//#region src/groth16_exportsoliditycalldata.js +var { unstringifyBigInts: unstringifyBigInts$8 } = ffjavascript.utils; function p256$2(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0"+nstr; - nstr = `"0x${nstr}"`; - return nstr; + let nstr = n.toString(16); + while (nstr.length < 64) nstr = "0" + nstr; + nstr = `"0x${nstr}"`; + return nstr; } - async function groth16ExportSolidityCallData(_proof, _pub) { - const proof = unstringifyBigInts$8(_proof); - const pub = unstringifyBigInts$8(_pub); - - let inputs = ""; - for (let i=0; i. -*/ - -var groth16 = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportSolidityCallData: groth16ExportSolidityCallData, - fullProve: groth16FullProve, - prove: groth16Prove, - verify: groth16Verify + const proof = unstringifyBigInts$8(_proof); + const pub = unstringifyBigInts$8(_pub); + let inputs = ""; + for (let i = 0; i < pub.length; i++) { + if (inputs != "") inputs = inputs + ","; + inputs = inputs + p256$2(pub[i]); + } + let S; + S = `[${p256$2(proof.pi_a[0])}, ${p256$2(proof.pi_a[1])}],[[${p256$2(proof.pi_b[0][1])}, ${p256$2(proof.pi_b[0][0])}],[${p256$2(proof.pi_b[1][1])}, ${p256$2(proof.pi_b[1][0])}]],[${p256$2(proof.pi_c[0])}, ${p256$2(proof.pi_c[1])}],[${inputs}]`; + return S; +} +//#endregion +//#region src/groth16.js +var groth16_exports = /* @__PURE__ */ __exportAll({ + exportSolidityCallData: () => groth16ExportSolidityCallData, + fullProve: () => groth16FullProve, + prove: () => groth16Prove, + verify: () => groth16Verify }); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - +//#endregion +//#region src/keypair.js function hashToG2(curve, hash) { - const hashV = new DataView(hash.buffer, hash.byteOffset, hash.byteLength); - const seed = []; - for (let i=0; i<8; i++) { - seed[i] = hashV.getUint32(i*4); - } - - const rng = new ffjavascript.ChaCha(seed); - - const g2_sp = curve.G2.fromRng(rng); - - return g2_sp; -} - + const hashV = new DataView(hash.buffer, hash.byteOffset, hash.byteLength); + const seed = []; + for (let i = 0; i < 8; i++) seed[i] = hashV.getUint32(i * 4); + const rng = new ffjavascript.ChaCha(seed); + return curve.G2.fromRng(rng); +} function getG2sp(curve, persinalization, challenge, g1s, g1sx) { - - const h = blake2_js.blake2b.create({ dkLen: 64 }); - const b1 = new Uint8Array([persinalization]); - h.update(b1); - h.update(challenge); - const b3 = curve.G1.toUncompressed(g1s); - h.update( b3); - const b4 = curve.G1.toUncompressed(g1sx); - h.update( b4); - const hash =h.digest(); - - return hashToG2(curve, hash); -} - -function calculatePubKey(k, curve, personalization, challengeHash, rng ) { - k.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); - k.g1_sx = curve.G1.toAffine(curve.G1.timesFr(k.g1_s, k.prvKey)); - k.g2_sp = curve.G2.toAffine(getG2sp(curve, personalization, challengeHash, k.g1_s, k.g1_sx)); - k.g2_spx = curve.G2.toAffine(curve.G2.timesFr(k.g2_sp, k.prvKey)); - return k; -} - + const h = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + const b1 = new Uint8Array([persinalization]); + h.update(b1); + h.update(challenge); + const b3 = curve.G1.toUncompressed(g1s); + h.update(b3); + const b4 = curve.G1.toUncompressed(g1sx); + h.update(b4); + return hashToG2(curve, h.digest()); +} +function calculatePubKey(k, curve, personalization, challengeHash, rng) { + k.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + k.g1_sx = curve.G1.toAffine(curve.G1.timesFr(k.g1_s, k.prvKey)); + k.g2_sp = curve.G2.toAffine(getG2sp(curve, personalization, challengeHash, k.g1_s, k.g1_sx)); + k.g2_spx = curve.G2.toAffine(curve.G2.timesFr(k.g2_sp, k.prvKey)); + return k; +} function createPTauKey(curve, challengeHash, rng) { - const key = { - tau: {}, - alpha: {}, - beta: {} - }; - key.tau.prvKey = curve.Fr.fromRng(rng); - key.alpha.prvKey = curve.Fr.fromRng(rng); - key.beta.prvKey = curve.Fr.fromRng(rng); - calculatePubKey(key.tau, curve, 0, challengeHash, rng); - calculatePubKey(key.alpha, curve, 1, challengeHash, rng); - calculatePubKey(key.beta, curve, 2, challengeHash, rng); - return key; -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const key = { + tau: {}, + alpha: {}, + beta: {} + }; + key.tau.prvKey = curve.Fr.fromRng(rng); + key.alpha.prvKey = curve.Fr.fromRng(rng); + key.beta.prvKey = curve.Fr.fromRng(rng); + calculatePubKey(key.tau, curve, 0, challengeHash, rng); + calculatePubKey(key.alpha, curve, 1, challengeHash, rng); + calculatePubKey(key.beta, curve, 2, challengeHash, rng); + return key; +} +//#endregion +//#region src/powersoftau_utils.js async function writePTauHeader(fd, curve, power, ceremonyPower) { - // Write the header - /////////// - - if (! ceremonyPower) ceremonyPower = power; - await fd.writeULE32(1); // Header type - const pHeaderSize = fd.pos; - await fd.writeULE64(0); // Temporally set to 0 length - - await fd.writeULE32(curve.F1.n64*8); - - const buff = new Uint8Array(curve.F1.n8); - ffjavascript.Scalar.toRprLE(buff, 0, curve.q, curve.F1.n8); - await fd.write(buff); - await fd.writeULE32(power); // power - await fd.writeULE32(ceremonyPower); // power - - const headerSize = fd.pos - pHeaderSize - 8; - - const oldPos = fd.pos; - - await fd.writeULE64(headerSize, pHeaderSize); - - fd.pos = oldPos; -} - + if (!ceremonyPower) ceremonyPower = power; + await fd.writeULE32(1); + const pHeaderSize = fd.pos; + await fd.writeULE64(0); + await fd.writeULE32(curve.F1.n64 * 8); + const buff = new Uint8Array(curve.F1.n8); + ffjavascript.Scalar.toRprLE(buff, 0, curve.q, curve.F1.n8); + await fd.write(buff); + await fd.writeULE32(power); + await fd.writeULE32(ceremonyPower); + const headerSize = fd.pos - pHeaderSize - 8; + const oldPos = fd.pos; + await fd.writeULE64(headerSize, pHeaderSize); + fd.pos = oldPos; +} async function readPTauHeader(fd, sections) { - if (!sections[1]) throw new Error(fd.fileName + ": File has no header"); - if (sections[1].length>1) throw new Error(fd.fileName +": File has more than one header"); - - fd.pos = sections[1][0].p; - const n8 = await fd.readULE32(); - const buff = await fd.read(n8); - const q = ffjavascript.Scalar.fromRprLE(buff); - - const curve = await getCurveFromQ(q); - - if (curve.F1.n64*8 != n8) throw new Error(fd.fileName +": Invalid size"); - - const power = await fd.readULE32(); - const ceremonyPower = await fd.readULE32(); - - if (fd.pos-sections[1][0].p != sections[1][0].size) throw new Error("Invalid PTau header size"); - - return {curve, power, ceremonyPower}; -} - - + if (!sections[1]) throw new Error(fd.fileName + ": File has no header"); + if (sections[1].length > 1) throw new Error(fd.fileName + ": File has more than one header"); + fd.pos = sections[1][0].p; + const n8 = await fd.readULE32(); + const buff = await fd.read(n8); + const curve = await getCurveFromQ(ffjavascript.Scalar.fromRprLE(buff)); + if (curve.F1.n64 * 8 != n8) throw new Error(fd.fileName + ": Invalid size"); + const power = await fd.readULE32(); + const ceremonyPower = await fd.readULE32(); + if (fd.pos - sections[1][0].p != sections[1][0].size) throw new Error("Invalid PTau header size"); + return { + curve, + power, + ceremonyPower + }; +} async function readPtauPubKey(fd, curve, montgomery) { - - const buff = await fd.read(curve.F1.n8*2*6 + curve.F2.n8*2*3); - - return fromPtauPubKeyRpr(buff, 0, curve, montgomery); + return fromPtauPubKeyRpr(await fd.read(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3), 0, curve, montgomery); } - function fromPtauPubKeyRpr(buff, pos, curve, montgomery) { - - const key = { - tau: {}, - alpha: {}, - beta: {} - }; - - key.tau.g1_s = readG1(); - key.tau.g1_sx = readG1(); - key.alpha.g1_s = readG1(); - key.alpha.g1_sx = readG1(); - key.beta.g1_s = readG1(); - key.beta.g1_sx = readG1(); - key.tau.g2_spx = readG2(); - key.alpha.g2_spx = readG2(); - key.beta.g2_spx = readG2(); - - return key; - - function readG1() { - let p; - if (montgomery) { - p = curve.G1.fromRprLEM( buff, pos ); - } else { - p = curve.G1.fromRprUncompressed( buff, pos ); - } - pos += curve.G1.F.n8*2; - return p; - } - - function readG2() { - let p; - if (montgomery) { - p = curve.G2.fromRprLEM( buff, pos ); - } else { - p = curve.G2.fromRprUncompressed( buff, pos ); - } - pos += curve.G2.F.n8*2; - return p; - } -} - + const key = { + tau: {}, + alpha: {}, + beta: {} + }; + key.tau.g1_s = readG1(); + key.tau.g1_sx = readG1(); + key.alpha.g1_s = readG1(); + key.alpha.g1_sx = readG1(); + key.beta.g1_s = readG1(); + key.beta.g1_sx = readG1(); + key.tau.g2_spx = readG2(); + key.alpha.g2_spx = readG2(); + key.beta.g2_spx = readG2(); + return key; + function readG1() { + let p; + if (montgomery) p = curve.G1.fromRprLEM(buff, pos); + else p = curve.G1.fromRprUncompressed(buff, pos); + pos += curve.G1.F.n8 * 2; + return p; + } + function readG2() { + let p; + if (montgomery) p = curve.G2.fromRprLEM(buff, pos); + else p = curve.G2.fromRprUncompressed(buff, pos); + pos += curve.G2.F.n8 * 2; + return p; + } +} function toPtauPubKeyRpr(buff, pos, curve, key, montgomery) { - - writeG1(key.tau.g1_s); - writeG1(key.tau.g1_sx); - writeG1(key.alpha.g1_s); - writeG1(key.alpha.g1_sx); - writeG1(key.beta.g1_s); - writeG1(key.beta.g1_sx); - writeG2(key.tau.g2_spx); - writeG2(key.alpha.g2_spx); - writeG2(key.beta.g2_spx); - - async function writeG1(p) { - if (montgomery) { - curve.G1.toRprLEM(buff, pos, p); - } else { - curve.G1.toRprUncompressed(buff, pos, p); - } - pos += curve.F1.n8*2; - } - - async function writeG2(p) { - if (montgomery) { - curve.G2.toRprLEM(buff, pos, p); - } else { - curve.G2.toRprUncompressed(buff, pos, p); - } - pos += curve.F2.n8*2; - } - - return buff; -} - + writeG1(key.tau.g1_s); + writeG1(key.tau.g1_sx); + writeG1(key.alpha.g1_s); + writeG1(key.alpha.g1_sx); + writeG1(key.beta.g1_s); + writeG1(key.beta.g1_sx); + writeG2(key.tau.g2_spx); + writeG2(key.alpha.g2_spx); + writeG2(key.beta.g2_spx); + async function writeG1(p) { + if (montgomery) curve.G1.toRprLEM(buff, pos, p); + else curve.G1.toRprUncompressed(buff, pos, p); + pos += curve.F1.n8 * 2; + } + async function writeG2(p) { + if (montgomery) curve.G2.toRprLEM(buff, pos, p); + else curve.G2.toRprUncompressed(buff, pos, p); + pos += curve.F2.n8 * 2; + } + return buff; +} async function writePtauPubKey(fd, curve, key, montgomery) { - const buff = new Uint8Array(curve.F1.n8*2*6 + curve.F2.n8*2*3); - toPtauPubKeyRpr(buff, 0, curve, key, montgomery); - await fd.write(buff); + const buff = new Uint8Array(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + toPtauPubKeyRpr(buff, 0, curve, key, montgomery); + await fd.write(buff); } - async function readContribution(fd, curve) { - const c = {}; - - c.tauG1 = await readG1(); - c.tauG2 = await readG2(); - c.alphaG1 = await readG1(); - c.betaG1 = await readG1(); - c.betaG2 = await readG2(); - c.key = await readPtauPubKey(fd, curve, true); - c.partialHash = await fd.read(216); - c.nextChallenge = await fd.read(64); - c.type = await fd.readULE32(); - - const buffV = new Uint8Array(curve.G1.F.n8*2*6+curve.G2.F.n8*2*3); - toPtauPubKeyRpr(buffV, 0, curve, c.key, false); - - const responseHasher = fromPartialHash(c.partialHash); - responseHasher.update(buffV); - c.responseHash = responseHasher.digest(); - - const paramLength = await fd.readULE32(); - const curPos = fd.pos; - let lastType =0; - while (fd.pos-curPos < paramLength) { - const buffType = await readDV(1); - if (buffType[0]<= lastType) throw new Error("Parameters in the contribution must be sorted"); - lastType = buffType[0]; - if (buffType[0]==1) { // Name - const buffLen = await readDV(1); - const buffStr = await readDV(buffLen[0]); - c.name = new TextDecoder().decode(buffStr); - } else if (buffType[0]==2) { - const buffExp = await readDV(1); - c.numIterationsExp = buffExp[0]; - } else if (buffType[0]==3) { - const buffLen = await readDV(1); - c.beaconHash = await readDV(buffLen[0]); - } else { - throw new Error("Parameter not recognized"); - } - } - if (fd.pos != curPos + paramLength) { - throw new Error("Parameters do not match"); - } - - return c; - - async function readG1() { - const pBuff = await fd.read(curve.G1.F.n8*2); - return curve.G1.fromRprLEM( pBuff ); - } - - async function readG2() { - const pBuff = await fd.read(curve.G2.F.n8*2); - return curve.G2.fromRprLEM( pBuff ); - } - - async function readDV(n) { - const b = await fd.read(n); - return new Uint8Array(b); - } -} - + const c = {}; + c.tauG1 = await readG1(); + c.tauG2 = await readG2(); + c.alphaG1 = await readG1(); + c.betaG1 = await readG1(); + c.betaG2 = await readG2(); + c.key = await readPtauPubKey(fd, curve, true); + c.partialHash = await fd.read(216); + c.nextChallenge = await fd.read(64); + c.type = await fd.readULE32(); + const buffV = new Uint8Array(curve.G1.F.n8 * 2 * 6 + curve.G2.F.n8 * 2 * 3); + toPtauPubKeyRpr(buffV, 0, curve, c.key, false); + const responseHasher = fromPartialHash(c.partialHash); + responseHasher.update(buffV); + c.responseHash = responseHasher.digest(); + const paramLength = await fd.readULE32(); + const curPos = fd.pos; + let lastType = 0; + while (fd.pos - curPos < paramLength) { + const buffType = await readDV(1); + if (buffType[0] <= lastType) throw new Error("Parameters in the contribution must be sorted"); + lastType = buffType[0]; + if (buffType[0] == 1) { + const buffStr = await readDV((await readDV(1))[0]); + c.name = new TextDecoder().decode(buffStr); + } else if (buffType[0] == 2) c.numIterationsExp = (await readDV(1))[0]; + else if (buffType[0] == 3) c.beaconHash = await readDV((await readDV(1))[0]); + else throw new Error("Parameter not recognized"); + } + if (fd.pos != curPos + paramLength) throw new Error("Parameters do not match"); + return c; + async function readG1() { + const pBuff = await fd.read(curve.G1.F.n8 * 2); + return curve.G1.fromRprLEM(pBuff); + } + async function readG2() { + const pBuff = await fd.read(curve.G2.F.n8 * 2); + return curve.G2.fromRprLEM(pBuff); + } + async function readDV(n) { + const b = await fd.read(n); + return new Uint8Array(b); + } +} async function readContributions(fd, curve, sections) { - if (!sections[7]) throw new Error(fd.fileName + ": File has no contributions"); - if (sections[7][0].length>1) throw new Error(fd.fileName +": File has more than one contributions section"); - - fd.pos = sections[7][0].p; - const nContributions = await fd.readULE32(); - const contributions = []; - for (let i=0; i 1) throw new Error(fd.fileName + ": File has more than one contributions section"); + fd.pos = sections[7][0].p; + const nContributions = await fd.readULE32(); + const contributions = []; + for (let i = 0; i < nContributions; i++) { + const c = await readContribution(fd, curve); + c.id = i + 1; + contributions.push(c); + } + if (fd.pos - sections[7][0].p != sections[7][0].size) throw new Error("Invalid contribution section size"); + return contributions; +} async function writeContribution(fd, curve, contribution) { - - const buffG1 = new Uint8Array(curve.F1.n8*2); - const buffG2 = new Uint8Array(curve.F2.n8*2); - await writeG1(contribution.tauG1); - await writeG2(contribution.tauG2); - await writeG1(contribution.alphaG1); - await writeG1(contribution.betaG1); - await writeG2(contribution.betaG2); - await writePtauPubKey(fd, curve, contribution.key, true); - await fd.write(contribution.partialHash); - await fd.write(contribution.nextChallenge); - await fd.writeULE32(contribution.type || 0); - - const params = []; - if (contribution.name) { - params.push(1); // Param Name - const nameData = new TextEncoder("utf-8").encode(contribution.name.substring(0,64)); - params.push(nameData.byteLength); - for (let i=0; i0) { - const paramsBuff = new Uint8Array(params); - await fd.writeULE32(paramsBuff.byteLength); - await fd.write(paramsBuff); - } else { - await fd.writeULE32(0); - } - - - async function writeG1(p) { - curve.G1.toRprLEM(buffG1, 0, p); - await fd.write(buffG1); - } - - async function writeG2(p) { - curve.G2.toRprLEM(buffG2, 0, p); - await fd.write(buffG2); - } - -} - + const buffG1 = new Uint8Array(curve.F1.n8 * 2); + const buffG2 = new Uint8Array(curve.F2.n8 * 2); + await writeG1(contribution.tauG1); + await writeG2(contribution.tauG2); + await writeG1(contribution.alphaG1); + await writeG1(contribution.betaG1); + await writeG2(contribution.betaG2); + await writePtauPubKey(fd, curve, contribution.key, true); + await fd.write(contribution.partialHash); + await fd.write(contribution.nextChallenge); + await fd.writeULE32(contribution.type || 0); + const params = []; + if (contribution.name) { + params.push(1); + const nameData = new TextEncoder("utf-8").encode(contribution.name.substring(0, 64)); + params.push(nameData.byteLength); + for (let i = 0; i < nameData.byteLength; i++) params.push(nameData[i]); + } + if (contribution.type == 1) { + params.push(2); + params.push(contribution.numIterationsExp); + params.push(3); + params.push(contribution.beaconHash.byteLength); + for (let i = 0; i < contribution.beaconHash.byteLength; i++) params.push(contribution.beaconHash[i]); + } + if (params.length > 0) { + const paramsBuff = new Uint8Array(params); + await fd.writeULE32(paramsBuff.byteLength); + await fd.write(paramsBuff); + } else await fd.writeULE32(0); + async function writeG1(p) { + curve.G1.toRprLEM(buffG1, 0, p); + await fd.write(buffG1); + } + async function writeG2(p) { + curve.G2.toRprLEM(buffG2, 0, p); + await fd.write(buffG2); + } +} async function writeContributions(fd, curve, contributions) { - - await fd.writeULE32(7); // Header type - const pContributionsSize = fd.pos; - await fd.writeULE64(0); // Temporally set to 0 length - - await fd.writeULE32(contributions.length); - for (let i=0; i< contributions.length; i++) { - await writeContribution(fd, curve, contributions[i]); - } - const contributionsSize = fd.pos - pContributionsSize - 8; - - const oldPos = fd.pos; - - await fd.writeULE64(contributionsSize, pContributionsSize); - fd.pos = oldPos; -} - + await fd.writeULE32(7); + const pContributionsSize = fd.pos; + await fd.writeULE64(0); + await fd.writeULE32(contributions.length); + for (let i = 0; i < contributions.length; i++) await writeContribution(fd, curve, contributions[i]); + const contributionsSize = fd.pos - pContributionsSize - 8; + const oldPos = fd.pos; + await fd.writeULE64(contributionsSize, pContributionsSize); + fd.pos = oldPos; +} function calculateFirstChallengeHash(curve, power, logger) { - if (logger) logger.debug("Calculating First Challenge Hash"); - - const hasher = blake2_js.blake2b.create({ dkLen: 64 }); - - const vG1 = new Uint8Array(curve.G1.F.n8*2); - const vG2 = new Uint8Array(curve.G2.F.n8*2); - curve.G1.toRprUncompressed(vG1, 0, curve.G1.g); - curve.G2.toRprUncompressed(vG2, 0, curve.G2.g); - - hasher.update(blake2_js.blake2b.create({ dkLen: 64 }).digest()); - - let n; - - n=(2 ** power)*2 -1; - if (logger) logger.debug("Calculate Initial Hash: tauG1"); - hashBlock(vG1, n); - n= 2 ** power; - if (logger) logger.debug("Calculate Initial Hash: tauG2"); - hashBlock(vG2, n); - if (logger) logger.debug("Calculate Initial Hash: alphaTauG1"); - hashBlock(vG1, n); - if (logger) logger.debug("Calculate Initial Hash: betaTauG1"); - hashBlock(vG1, n); - hasher.update(vG2); - - return hasher.digest(); - - function hashBlock(buff, n) { - // this block size is a good compromise between speed and the maximum - // input size of the Blake2b update method (65,535,720 bytes). - const blockSize = 341000; - const nBlocks = Math.floor(n / blockSize); - const rem = n % blockSize; - const bigBuff = new Uint8Array(blockSize * buff.byteLength); - for (let i=0; i. -*/ - - + return createPTauKey(curve, challengeHash, await rngFromBeaconParams(beaconHash, numIterationsExp)); +} +//#endregion +//#region src/powersoftau_new.js async function newAccumulator(curve, power, fileName, logger) { - - const fd = await binFileUtils__namespace.createBinFile(fileName, "ptau", 1, 7); - - await writePTauHeader(fd, curve, power, 0); - - const buffG1 = curve.G1.oneAffine; - const buffG2 = curve.G2.oneAffine; - - // Write tauG1 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 2); - const nTauG1 = (2 ** power) * 2 -1; - for (let i=0; i< nTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("tauG1: " + i); - } - await binFileUtils__namespace.endWriteSection(fd); - - // Write tauG2 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 3); - const nTauG2 = (2 ** power); - for (let i=0; i< nTauG2; i++) { - await fd.write(buffG2); - if ((logger)&&((i%100000) == 0)&&i) logger.log("tauG2: " + i); - } - await binFileUtils__namespace.endWriteSection(fd); - - // Write alphaTauG1 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 4); - const nAlfaTauG1 = (2 ** power); - for (let i=0; i< nAlfaTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("alphaTauG1: " + i); - } - await binFileUtils__namespace.endWriteSection(fd); - - // Write betaTauG1 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 5); - const nBetaTauG1 = (2 ** power); - for (let i=0; i< nBetaTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("betaTauG1: " + i); - } - await binFileUtils__namespace.endWriteSection(fd); - - // Write betaG2 - /////////// - await binFileUtils__namespace.startWriteSection(fd, 6); - await fd.write(buffG2); - await binFileUtils__namespace.endWriteSection(fd); - - // Contributions - /////////// - await binFileUtils__namespace.startWriteSection(fd, 7); - await fd.writeULE32(0); // 0 Contributions - await binFileUtils__namespace.endWriteSection(fd); - - await fd.close(); - - const firstChallengeHash = calculateFirstChallengeHash(curve, power, logger); - - if (logger) logger.debug(formatHash(blake2_js.blake2b.create({ dkLen: 64 }).digest(), "Blank Contribution Hash:")); - - if (logger) logger.info(formatHash(firstChallengeHash, "First Contribution Hash:")); - - return firstChallengeHash; - -} - -// Format of the outpu -// Hash of the last contribution 64Bytes -// 2^N * 2 -1 TauG1 points (uncompressed) -// 2^N TauG2 Points (uncompressed) -// 2^N AlphaTauG1 Points (uncompressed) -// 2^N BetaTauG1 Points (uncompressed) -// BetaG2 (uncompressed) - - + const fd = await _iden3_binfileutils.createBinFile(fileName, "ptau", 1, 7); + await writePTauHeader(fd, curve, power, 0); + const buffG1 = curve.G1.oneAffine; + const buffG2 = curve.G2.oneAffine; + await _iden3_binfileutils.startWriteSection(fd, 2); + const nTauG1 = 2 ** power * 2 - 1; + for (let i = 0; i < nTauG1; i++) { + await fd.write(buffG1); + if (logger && i % 1e5 == 0 && i) logger.log("tauG1: " + i); + } + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 3); + const nTauG2 = 2 ** power; + for (let i = 0; i < nTauG2; i++) { + await fd.write(buffG2); + if (logger && i % 1e5 == 0 && i) logger.log("tauG2: " + i); + } + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 4); + const nAlfaTauG1 = 2 ** power; + for (let i = 0; i < nAlfaTauG1; i++) { + await fd.write(buffG1); + if (logger && i % 1e5 == 0 && i) logger.log("alphaTauG1: " + i); + } + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 5); + const nBetaTauG1 = 2 ** power; + for (let i = 0; i < nBetaTauG1; i++) { + await fd.write(buffG1); + if (logger && i % 1e5 == 0 && i) logger.log("betaTauG1: " + i); + } + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 6); + await fd.write(buffG2); + await _iden3_binfileutils.endWriteSection(fd); + await _iden3_binfileutils.startWriteSection(fd, 7); + await fd.writeULE32(0); + await _iden3_binfileutils.endWriteSection(fd); + await fd.close(); + const firstChallengeHash = calculateFirstChallengeHash(curve, power, logger); + if (logger) logger.debug(formatHash(_noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }).digest(), "Blank Contribution Hash:")); + if (logger) logger.info(formatHash(firstChallengeHash, "First Contribution Hash:")); + return firstChallengeHash; +} +//#endregion +//#region src/powersoftau_export_challenge.js async function exportChallenge(pTauFilename, challengeFilename, logger) { - const {fd: fdFrom, sections} = await binFileUtils__namespace.readBinFile(pTauFilename, "ptau", 1); - - const {curve, power} = await readPTauHeader(fdFrom, sections); - - const contributions = await readContributions(fdFrom, curve, sections); - let lastResponseHash, curChallengeHash; - if (contributions.length == 0) { - lastResponseHash = blake2_js.blake2b.create({ dkLen: 64 }).digest(); - curChallengeHash = calculateFirstChallengeHash(curve, power); - } else { - lastResponseHash = contributions[contributions.length-1].responseHash; - curChallengeHash = contributions[contributions.length-1].nextChallenge; - } - - if (logger) logger.info(formatHash(lastResponseHash, "Last Response Hash: ")); - - if (logger) logger.info(formatHash(curChallengeHash, "New Challenge Hash: ")); - - - const fdTo = await fastFile__namespace.createOverride(challengeFilename); - - const toHash = blake2_js.blake2b.create({ dkLen: 64 }); - await fdTo.write(lastResponseHash); - toHash.update(lastResponseHash); - - await exportSection(2, "G1", (2 ** power) * 2 -1, "tauG1"); - await exportSection(3, "G2", (2 ** power) , "tauG2"); - await exportSection(4, "G1", (2 ** power) , "alphaTauG1"); - await exportSection(5, "G1", (2 ** power) , "betaTauG1"); - await exportSection(6, "G2", 1 , "betaG2"); - - await fdFrom.close(); - await fdTo.close(); - - const calcCurChallengeHash = toHash.digest(); - - if (!hashIsEqual (curChallengeHash, calcCurChallengeHash)) { - if (logger) logger.info(formatHash(calcCurChallengeHash, "Calc Curret Challenge Hash: ")); - - if (logger) logger.error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); - throw new Error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); - } - - return curChallengeHash; - - async function exportSection(sectionId, groupName, nPoints, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPointsChunk = Math.floor((1<<24)/sG); - - await binFileUtils__namespace.startReadUniqueSection(fdFrom, sections, sectionId); - for (let i=0; i< nPoints; i+= nPointsChunk) { - if (logger) logger.debug(`Exporting ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - let buff; - buff = await fdFrom.read(n*sG); - buff = await G.batchLEMtoU(buff); - await fdTo.write(buff); - toHash.update(buff); - } - await binFileUtils__namespace.endReadSection(fdFrom); - } - - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const { fd: fdFrom, sections } = await _iden3_binfileutils.readBinFile(pTauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fdFrom, sections); + const contributions = await readContributions(fdFrom, curve, sections); + let lastResponseHash, curChallengeHash; + if (contributions.length == 0) { + lastResponseHash = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }).digest(); + curChallengeHash = calculateFirstChallengeHash(curve, power); + } else { + lastResponseHash = contributions[contributions.length - 1].responseHash; + curChallengeHash = contributions[contributions.length - 1].nextChallenge; + } + if (logger) logger.info(formatHash(lastResponseHash, "Last Response Hash: ")); + if (logger) logger.info(formatHash(curChallengeHash, "New Challenge Hash: ")); + const fdTo = await fastfile.createOverride(challengeFilename); + const toHash = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + await fdTo.write(lastResponseHash); + toHash.update(lastResponseHash); + await exportSection(2, "G1", 2 ** power * 2 - 1, "tauG1"); + await exportSection(3, "G2", 2 ** power, "tauG2"); + await exportSection(4, "G1", 2 ** power, "alphaTauG1"); + await exportSection(5, "G1", 2 ** power, "betaTauG1"); + await exportSection(6, "G2", 1, "betaG2"); + await fdFrom.close(); + await fdTo.close(); + const calcCurChallengeHash = toHash.digest(); + if (!hashIsEqual(curChallengeHash, calcCurChallengeHash)) { + if (logger) logger.info(formatHash(calcCurChallengeHash, "Calc Curret Challenge Hash: ")); + if (logger) logger.error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); + throw new Error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); + } + return curChallengeHash; + async function exportSection(sectionId, groupName, nPoints, sectionName) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const nPointsChunk = Math.floor((1 << 24) / sG); + await _iden3_binfileutils.startReadUniqueSection(fdFrom, sections, sectionId); + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Exporting ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + let buff; + buff = await fdFrom.read(n * sG); + buff = await G.batchLEMtoU(buff); + await fdTo.write(buff); + toHash.update(buff); + } + await _iden3_binfileutils.endReadSection(fdFrom); + } +} +//#endregion +//#region src/powersoftau_import.js async function importResponse(oldPtauFilename, contributionFilename, newPTauFilename, name, importPoints, logger) { - - const noHash = new Uint8Array(64); - for (let i=0; i<64; i++) noHash[i] = 0xFF; - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - const contributions = await readContributions(fdOld, curve, sections); - const currentContribution = {}; - - if (name) currentContribution.name = name; - - const sG1 = curve.F1.n8*2; - const scG1 = curve.F1.n8; // Compressed size - const sG2 = curve.F2.n8*2; - const scG2 = curve.F2.n8; // Compressed size - - const fdResponse = await fastFile__namespace.readExisting(contributionFilename); - - if (fdResponse.totalSize != - 64 + // Old Hash - ((2 ** power)*2-1)*scG1 + - (2 ** power)*scG2 + - (2 ** power)*scG1 + - (2 ** power)*scG1 + - scG2 + - sG1*6 + sG2*3) - throw new Error("Size of the contribution is invalid"); - - let lastChallengeHash; - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, importPoints ? 7: 2); - await writePTauHeader(fdNew, curve, power); - - const contributionPreviousHash = await fdResponse.read(64); - - if (hashIsEqual(noHash,lastChallengeHash)) { - lastChallengeHash = contributionPreviousHash; - contributions[contributions.length-1].nextChallenge = lastChallengeHash; - } - - if(!hashIsEqual(contributionPreviousHash,lastChallengeHash)) - throw new Error("Wrong contribution. This contribution is not based on the previous hash"); - - const hasherResponse = blake2_js.blake2b.create({ dkLen: 64 }); - hasherResponse.update(contributionPreviousHash); - - const startSections = []; - let res; - res = await processSection(fdResponse, fdNew, "G1", 2, (2 ** power) * 2 -1, [1], "tauG1"); - currentContribution.tauG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G2", 3, (2 ** power) , [1], "tauG2"); - currentContribution.tauG2 = res[0]; - res = await processSection(fdResponse, fdNew, "G1", 4, (2 ** power) , [0], "alphaG1"); - currentContribution.alphaG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G1", 5, (2 ** power) , [0], "betaG1"); - currentContribution.betaG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G2", 6, 1 , [0], "betaG2"); - currentContribution.betaG2 = res[0]; - - currentContribution.partialHash = toPartialHash(hasherResponse); - - - const buffKey = await fdResponse.read(curve.F1.n8*2*6+curve.F2.n8*2*3); - - currentContribution.key = fromPtauPubKeyRpr(buffKey, 0, curve, false); - - hasherResponse.update(new Uint8Array(buffKey)); - const hashResponse = hasherResponse.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - if (importPoints) { - const nextChallengeHasher = blake2_js.blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(nextChallengeHasher, fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G2", 3, (2 ** power) , "tauG2", logger); - await hashSection(nextChallengeHasher, fdNew, "G1", 4, (2 ** power) , "alphaTauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G1", 5, (2 ** power) , "betaTauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G2", 6, 1 , "betaG2", logger); - - currentContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(currentContribution.nextChallenge, "Next Challenge Hash: ")); - } else { - currentContribution.nextChallenge = noHash; - } - - contributions.push(currentContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdResponse.close(); - await fdNew.close(); - await fdOld.close(); - - return currentContribution.nextChallenge; - - async function processSection(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - if (importPoints) { - return await processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); - } else { - return await processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); - } - } - - async function processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - - const G = curve[groupName]; - const scG = G.F.n8; - const sG = G.F.n8*2; - - const singularPoints = []; - - await binFileUtils__namespace.startWriteSection(fdTo, sectionId); - const nPointsChunk = Math.floor((1<<24)/sG); - - startSections[sectionId] = fdTo.pos; - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffC = await fdFrom.read(n * scG); - hasherResponse.update(buffC); - - const buffLEM = await G.batchCtoLEM(buffC); - - await fdTo.write(buffLEM); - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprLEM(buffLEM, (sp-i)*sG); - singularPoints.push(P); - } - } - } - - await binFileUtils__namespace.endWriteSection(fdTo); - - return singularPoints; - } - - - async function processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - - const G = curve[groupName]; - const scG = G.F.n8; - - const singularPoints = []; - - const nPointsChunk = Math.floor((1<<24)/scG); - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffC = await fdFrom.read(n * scG); - hasherResponse.update(buffC); - - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprCompressed(buffC, (sp-i)*scG); - singularPoints.push(P); - } - } - } - - return singularPoints; - } - - - async function hashSection(nextChallengeHasher, fdTo, groupName, sectionId, nPoints, sectionName, logger) { - - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPointsChunk = Math.floor((1<<24)/sG); - - const oldPos = fdTo.pos; - fdTo.pos = startSections[sectionId]; - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Hashing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffLEM = await fdTo.read(n * sG); - - const buffU = await G.batchLEMtoU(buffLEM); - - nextChallengeHasher.update(buffU); - } - - fdTo.pos = oldPos; - } - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const sameRatio$1 = sameRatio$2; - + const noHash = /* @__PURE__ */ new Uint8Array(64); + for (let i = 0; i < 64; i++) noHash[i] = 255; + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fdOld, sections); + const contributions = await readContributions(fdOld, curve, sections); + const currentContribution = {}; + if (name) currentContribution.name = name; + const sG1 = curve.F1.n8 * 2; + const scG1 = curve.F1.n8; + const sG2 = curve.F2.n8 * 2; + const scG2 = curve.F2.n8; + const fdResponse = await fastfile.readExisting(contributionFilename); + if (fdResponse.totalSize != 64 + (2 ** power * 2 - 1) * scG1 + 2 ** power * scG2 + 2 ** power * scG1 + 2 ** power * scG1 + scG2 + sG1 * 6 + sG2 * 3) throw new Error("Size of the contribution is invalid"); + let lastChallengeHash; + if (contributions.length > 0) lastChallengeHash = contributions[contributions.length - 1].nextChallenge; + else lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, importPoints ? 7 : 2); + await writePTauHeader(fdNew, curve, power); + const contributionPreviousHash = await fdResponse.read(64); + if (hashIsEqual(noHash, lastChallengeHash)) { + lastChallengeHash = contributionPreviousHash; + contributions[contributions.length - 1].nextChallenge = lastChallengeHash; + } + if (!hashIsEqual(contributionPreviousHash, lastChallengeHash)) throw new Error("Wrong contribution. This contribution is not based on the previous hash"); + const hasherResponse = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hasherResponse.update(contributionPreviousHash); + const startSections = []; + let res; + res = await processSection(fdResponse, fdNew, "G1", 2, 2 ** power * 2 - 1, [1], "tauG1"); + currentContribution.tauG1 = res[0]; + res = await processSection(fdResponse, fdNew, "G2", 3, 2 ** power, [1], "tauG2"); + currentContribution.tauG2 = res[0]; + res = await processSection(fdResponse, fdNew, "G1", 4, 2 ** power, [0], "alphaG1"); + currentContribution.alphaG1 = res[0]; + res = await processSection(fdResponse, fdNew, "G1", 5, 2 ** power, [0], "betaG1"); + currentContribution.betaG1 = res[0]; + res = await processSection(fdResponse, fdNew, "G2", 6, 1, [0], "betaG2"); + currentContribution.betaG2 = res[0]; + currentContribution.partialHash = toPartialHash(hasherResponse); + const buffKey = await fdResponse.read(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + currentContribution.key = fromPtauPubKeyRpr(buffKey, 0, curve, false); + hasherResponse.update(new Uint8Array(buffKey)); + const hashResponse = hasherResponse.digest(); + if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); + if (importPoints) { + const nextChallengeHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + nextChallengeHasher.update(hashResponse); + await hashSection(nextChallengeHasher, fdNew, "G1", 2, 2 ** power * 2 - 1, "tauG1", logger); + await hashSection(nextChallengeHasher, fdNew, "G2", 3, 2 ** power, "tauG2", logger); + await hashSection(nextChallengeHasher, fdNew, "G1", 4, 2 ** power, "alphaTauG1", logger); + await hashSection(nextChallengeHasher, fdNew, "G1", 5, 2 ** power, "betaTauG1", logger); + await hashSection(nextChallengeHasher, fdNew, "G2", 6, 1, "betaG2", logger); + currentContribution.nextChallenge = nextChallengeHasher.digest(); + if (logger) logger.info(formatHash(currentContribution.nextChallenge, "Next Challenge Hash: ")); + } else currentContribution.nextChallenge = noHash; + contributions.push(currentContribution); + await writeContributions(fdNew, curve, contributions); + await fdResponse.close(); + await fdNew.close(); + await fdOld.close(); + return currentContribution.nextChallenge; + async function processSection(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { + if (importPoints) return await processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); + else return await processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); + } + async function processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { + const G = curve[groupName]; + const scG = G.F.n8; + const sG = G.F.n8 * 2; + const singularPoints = []; + await _iden3_binfileutils.startWriteSection(fdTo, sectionId); + const nPointsChunk = Math.floor((1 << 24) / sG); + startSections[sectionId] = fdTo.pos; + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + const buffC = await fdFrom.read(n * scG); + hasherResponse.update(buffC); + const buffLEM = await G.batchCtoLEM(buffC); + await fdTo.write(buffLEM); + for (let j = 0; j < singularPointIndexes.length; j++) { + const sp = singularPointIndexes[j]; + if (sp >= i && sp < i + n) { + const P = G.fromRprLEM(buffLEM, (sp - i) * sG); + singularPoints.push(P); + } + } + } + await _iden3_binfileutils.endWriteSection(fdTo); + return singularPoints; + } + async function processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { + const G = curve[groupName]; + const scG = G.F.n8; + const singularPoints = []; + const nPointsChunk = Math.floor((1 << 24) / scG); + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + const buffC = await fdFrom.read(n * scG); + hasherResponse.update(buffC); + for (let j = 0; j < singularPointIndexes.length; j++) { + const sp = singularPointIndexes[j]; + if (sp >= i && sp < i + n) { + const P = G.fromRprCompressed(buffC, (sp - i) * scG); + singularPoints.push(P); + } + } + } + return singularPoints; + } + async function hashSection(nextChallengeHasher, fdTo, groupName, sectionId, nPoints, sectionName, logger) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const nPointsChunk = Math.floor((1 << 24) / sG); + const oldPos = fdTo.pos; + fdTo.pos = startSections[sectionId]; + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Hashing ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + const buffLEM = await fdTo.read(n * sG); + const buffU = await G.batchLEMtoU(buffLEM); + nextChallengeHasher.update(buffU); + } + fdTo.pos = oldPos; + } +} +//#endregion +//#region src/powersoftau_verify.js +var sameRatio$1 = sameRatio$2; async function verifyContribution(curve, cur, prev, logger) { - let sr; - if (cur.type == 1) { // Verify the beacon. - const beaconKey = await keyFromBeacon(curve, prev.nextChallenge, cur.beaconHash, cur.numIterationsExp); - - if (!curve.G1.eq(cur.key.tau.g1_s, beaconKey.tau.g1_s)) { - if (logger) logger.error(`BEACON key (tauG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.tau.g1_sx, beaconKey.tau.g1_sx)) { - if (logger) logger.error(`BEACON key (tauG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.tau.g2_spx, beaconKey.tau.g2_spx)) { - if (logger) logger.error(`BEACON key (tauG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - - if (!curve.G1.eq(cur.key.alpha.g1_s, beaconKey.alpha.g1_s)) { - if (logger) logger.error(`BEACON key (alphaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.alpha.g1_sx, beaconKey.alpha.g1_sx)) { - if (logger) logger.error(`BEACON key (alphaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.alpha.g2_spx, beaconKey.alpha.g2_spx)) { - if (logger) logger.error(`BEACON key (alphaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - - if (!curve.G1.eq(cur.key.beta.g1_s, beaconKey.beta.g1_s)) { - if (logger) logger.error(`BEACON key (betaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.beta.g1_sx, beaconKey.beta.g1_sx)) { - if (logger) logger.error(`BEACON key (betaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.beta.g2_spx, beaconKey.beta.g2_spx)) { - if (logger) logger.error(`BEACON key (betaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - } - - cur.key.tau.g2_sp = curve.G2.toAffine(getG2sp(curve, 0, prev.nextChallenge, cur.key.tau.g1_s, cur.key.tau.g1_sx)); - cur.key.alpha.g2_sp = curve.G2.toAffine(getG2sp(curve, 1, prev.nextChallenge, cur.key.alpha.g1_s, cur.key.alpha.g1_sx)); - cur.key.beta.g2_sp = curve.G2.toAffine(getG2sp(curve, 2, prev.nextChallenge, cur.key.beta.g1_s, cur.key.beta.g1_sx)); - - sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, cur.key.tau.g2_sp, cur.key.tau.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (tau) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, cur.key.alpha.g1_s, cur.key.alpha.g1_sx, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (alpha) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, cur.key.beta.g2_sp, cur.key.beta.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (beta) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, prev.tauG1, cur.tauG1, cur.key.tau.g2_sp, cur.key.tau.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID tau*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, prev.tauG2, cur.tauG2); - if (sr !== true) { - if (logger) logger.error("INVALID tau*G2. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, prev.alphaG1, cur.alphaG1, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID alpha*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, prev.betaG1, cur.betaG1, cur.key.beta.g2_sp, cur.key.beta.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID beta*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, prev.betaG2, cur.betaG2); - if (sr !== true) { - if (logger) logger.error("INVALID beta*G2. challenge #"+cur.id+"It does not follow the previous contribution"); - return false; - } - - if (logger) logger.info("Powers Of tau file OK!"); - return true; -} - + let sr; + if (cur.type == 1) { + const beaconKey = await keyFromBeacon(curve, prev.nextChallenge, cur.beaconHash, cur.numIterationsExp); + if (!curve.G1.eq(cur.key.tau.g1_s, beaconKey.tau.g1_s)) { + if (logger) logger.error(`BEACON key (tauG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.tau.g1_sx, beaconKey.tau.g1_sx)) { + if (logger) logger.error(`BEACON key (tauG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G2.eq(cur.key.tau.g2_spx, beaconKey.tau.g2_spx)) { + if (logger) logger.error(`BEACON key (tauG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.alpha.g1_s, beaconKey.alpha.g1_s)) { + if (logger) logger.error(`BEACON key (alphaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.alpha.g1_sx, beaconKey.alpha.g1_sx)) { + if (logger) logger.error(`BEACON key (alphaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G2.eq(cur.key.alpha.g2_spx, beaconKey.alpha.g2_spx)) { + if (logger) logger.error(`BEACON key (alphaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.beta.g1_s, beaconKey.beta.g1_s)) { + if (logger) logger.error(`BEACON key (betaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G1.eq(cur.key.beta.g1_sx, beaconKey.beta.g1_sx)) { + if (logger) logger.error(`BEACON key (betaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + if (!curve.G2.eq(cur.key.beta.g2_spx, beaconKey.beta.g2_spx)) { + if (logger) logger.error(`BEACON key (betaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}`); + return false; + } + } + cur.key.tau.g2_sp = curve.G2.toAffine(getG2sp(curve, 0, prev.nextChallenge, cur.key.tau.g1_s, cur.key.tau.g1_sx)); + cur.key.alpha.g2_sp = curve.G2.toAffine(getG2sp(curve, 1, prev.nextChallenge, cur.key.alpha.g1_s, cur.key.alpha.g1_sx)); + cur.key.beta.g2_sp = curve.G2.toAffine(getG2sp(curve, 2, prev.nextChallenge, cur.key.beta.g1_s, cur.key.beta.g1_sx)); + sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, cur.key.tau.g2_sp, cur.key.tau.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID key (tau) in challenge #" + cur.id); + return false; + } + sr = await sameRatio$1(curve, cur.key.alpha.g1_s, cur.key.alpha.g1_sx, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID key (alpha) in challenge #" + cur.id); + return false; + } + sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, cur.key.beta.g2_sp, cur.key.beta.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID key (beta) in challenge #" + cur.id); + return false; + } + sr = await sameRatio$1(curve, prev.tauG1, cur.tauG1, cur.key.tau.g2_sp, cur.key.tau.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID tau*G1. challenge #" + cur.id + " It does not follow the previous contribution"); + return false; + } + sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, prev.tauG2, cur.tauG2); + if (sr !== true) { + if (logger) logger.error("INVALID tau*G2. challenge #" + cur.id + " It does not follow the previous contribution"); + return false; + } + sr = await sameRatio$1(curve, prev.alphaG1, cur.alphaG1, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID alpha*G1. challenge #" + cur.id + " It does not follow the previous contribution"); + return false; + } + sr = await sameRatio$1(curve, prev.betaG1, cur.betaG1, cur.key.beta.g2_sp, cur.key.beta.g2_spx); + if (sr !== true) { + if (logger) logger.error("INVALID beta*G1. challenge #" + cur.id + " It does not follow the previous contribution"); + return false; + } + sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, prev.betaG2, cur.betaG2); + if (sr !== true) { + if (logger) logger.error("INVALID beta*G2. challenge #" + cur.id + "It does not follow the previous contribution"); + return false; + } + if (logger) logger.info("Powers Of tau file OK!"); + return true; +} async function verify(tauFilename, logger) { - let sr; - - const {fd, sections} = await binFileUtils__namespace.readBinFile(tauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fd, sections); - const contrs = await readContributions(fd, curve, sections); - - if (logger) logger.debug("power: 2**" + power); - // Verify Last contribution - - if (logger) logger.debug("Computing initial contribution hash"); - const initialContribution = { - tauG1: curve.G1.g, - tauG2: curve.G2.g, - alphaG1: curve.G1.g, - betaG1: curve.G1.g, - betaG2: curve.G2.g, - nextChallenge: calculateFirstChallengeHash(curve, ceremonyPower, logger), - responseHash: blake2_js.blake2b.create({ dkLen: 64 }).digest() - }; - - if (contrs.length == 0) { - if (logger) logger.error("This file has no contribution! It cannot be used in production"); - return false; - } - - let prevContr; - if (contrs.length>1) { - prevContr = contrs[contrs.length-2]; - } else { - prevContr = initialContribution; - } - const curContr = contrs[contrs.length-1]; - if (logger) logger.debug("Validating contribution #"+contrs[contrs.length-1].id); - const res = await verifyContribution(curve, curContr, prevContr, logger); - if (!res) return false; - - - const nextContributionHasher = blake2_js.blake2b.create({ dkLen: 64 }); - nextContributionHasher.update(curContr.responseHash); - - // Verify powers and compute nextChallengeHash - - // await test(); - - // Verify Section tau*G1 - if (logger) logger.debug("Verifying powers in tau*G1 section"); - const rTau1 = await processSection(2, "G1", "tauG1", (2 ** power)*2-1, [0, 1], logger); - sr = await sameRatio$1(curve, rTau1.R1, rTau1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("tauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curve.G1.g, rTau1.singularPoints[0])) { - if (logger) logger.error("First element of tau*G1 section must be the generator"); - return false; - } - if (!curve.G1.eq(curContr.tauG1, rTau1.singularPoints[1])) { - if (logger) logger.error("Second element of tau*G1 section does not match the one in the contribution section"); - return false; - } - - // await test(); - - // Verify Section tau*G2 - if (logger) logger.debug("Verifying powers in tau*G2 section"); - const rTau2 = await processSection(3, "G2", "tauG2", 2 ** power, [0, 1], logger); - sr = await sameRatio$1(curve, curve.G1.g, curContr.tauG1, rTau2.R1, rTau2.R2); - if (sr !== true) { - if (logger) logger.error("tauG2 section. Powers do not match"); - return false; - } - if (!curve.G2.eq(curve.G2.g, rTau2.singularPoints[0])) { - if (logger) logger.error("First element of tau*G2 section must be the generator"); - return false; - } - if (!curve.G2.eq(curContr.tauG2, rTau2.singularPoints[1])) { - if (logger) logger.error("Second element of tau*G2 section does not match the one in the contribution section"); - return false; - } - - // Verify Section alpha*tau*G1 - if (logger) logger.debug("Verifying powers in alpha*tau*G1 section"); - const rAlphaTauG1 = await processSection(4, "G1", "alphatauG1", 2 ** power, [0], logger); - sr = await sameRatio$1(curve, rAlphaTauG1.R1, rAlphaTauG1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("alphaTauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curContr.alphaG1, rAlphaTauG1.singularPoints[0])) { - if (logger) logger.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"); - return false; - } - - // Verify Section beta*tau*G1 - if (logger) logger.debug("Verifying powers in beta*tau*G1 section"); - const rBetaTauG1 = await processSection(5, "G1", "betatauG1", 2 ** power, [0], logger); - sr = await sameRatio$1(curve, rBetaTauG1.R1, rBetaTauG1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("betaTauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curContr.betaG1, rBetaTauG1.singularPoints[0])) { - if (logger) logger.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"); - return false; - } - - //Verify Beta G2 - const betaG2 = await processSectionBetaG2(logger); - if (!curve.G2.eq(curContr.betaG2, betaG2)) { - if (logger) logger.error("betaG2 element in betaG2 section does not match the one in the contribution section"); - return false; - } - - - const nextContributionHash = nextContributionHasher.digest(); - - // Check the nextChallengeHash - if (power == ceremonyPower) { - if (!hashIsEqual(nextContributionHash,curContr.nextChallenge)) { - if (logger) logger.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"); - return false; - } - } - - if (logger) logger.info(formatHash(nextContributionHash, "Next challenge hash: ")); - - // Verify Previous contributions - - printContribution(curContr, prevContr); - for (let i = contrs.length-2; i>=0; i--) { - const curContr = contrs[i]; - const prevContr = (i>0) ? contrs[i-1] : initialContribution; - const res = await verifyContribution(curve, curContr, prevContr, logger); - if (!res) return false; - printContribution(curContr, prevContr); - } - if (logger) logger.info("-----------------------------------------------------"); - - if ((!sections[12]) || (!sections[13]) || (!sections[14]) || (!sections[15])) { - if (logger) logger.warn( - "this file does not contain phase2 precalculated values. Please run: \n" + - " snarkjs \"powersoftau preparephase2\" to prepare this file to be used in the phase2 ceremony." - ); - } else { - let res; - res = await verifyLagrangeEvaluations("G1", 2, 12, "tauG1", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G2", 3, 13, "tauG2", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G1", 4, 14, "alphaTauG1", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G1", 5, 15, "betaTauG1", logger); - if (!res) return false; - } - - await fd.close(); - - if (logger) logger.info("Powers of Tau Ok!"); - - return true; - - function printContribution(curContr, prevContr) { - if (!logger) return; - logger.info("-----------------------------------------------------"); - logger.info(`Contribution #${curContr.id}: ${curContr.name ||""}`); - - logger.info(formatHash(curContr.nextChallenge, "Next Challenge: ")); - - const buffV = new Uint8Array(curve.G1.F.n8*2*6+curve.G2.F.n8*2*3); - toPtauPubKeyRpr(buffV, 0, curve, curContr.key, false); - - const responseHasher = fromPartialHash(curContr.partialHash); - responseHasher.update(buffV); - const responseHash = responseHasher.digest(); - - logger.info(formatHash(responseHash, "Response Hash:")); - - logger.info(formatHash(prevContr.nextChallenge, "Response Hash:")); - - if (curContr.type == 1) { - logger.info(`Beacon generator: ${byteArray2hex(curContr.beaconHash)}`); - logger.info(`Beacon iterations Exp: ${curContr.numIterationsExp}`); - } - - } - - async function processSectionBetaG2(logger) { - const G = curve.G2; - const sG = G.F.n8*2; - const buffUv = new Uint8Array(sG); - - if (!sections[6]) { - logger.error("File has no BetaG2 section"); - throw new Error("File has no BetaG2 section"); - } - if (sections[6].length>1) { - logger.error("File has no BetaG2 section"); - throw new Error("File has more than one GetaG2 section"); - } - fd.pos = sections[6][0].p; - - const buff = await fd.read(sG); - const P = G.fromRprLEM(buff); - - G.toRprUncompressed(buffUv, 0, P); - nextContributionHasher.update(buffUv); - - return P; - } - - async function processSection(idSection, groupName, sectionName, nPoints, singularPointIndexes, logger) { - const MAX_CHUNK_SIZE = 1<<16; - const G = curve[groupName]; - const sG = G.F.n8*2; - await binFileUtils__namespace.startReadUniqueSection(fd, sections, idSection); - - const singularPoints = []; - - let R1 = G.zero; - let R2 = G.zero; - - let lastBase = G.zero; - - for (let i=0; i0) { - const firstBase = G.fromRprLEM(bases, 0); - const r = readUInt32BE(getRandomBytes(4), 0); - - R1 = G.add(R1, G.timesScalar(lastBase, r)); - R2 = G.add(R2, G.timesScalar(firstBase, r)); - } - - const r1 = await G.multiExpAffine(bases.slice(0, (n-1)*sG), scalars); - const r2 = await G.multiExpAffine(bases.slice(sG), scalars); - - R1 = G.add(R1, r1); - R2 = G.add(R2, r2); - - lastBase = G.fromRprLEM( bases, (n-1)*sG); - - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprLEM(bases, (sp-i)*sG); - singularPoints.push(P); - } - } - - } - await binFileUtils__namespace.endReadSection(fd); - - return { - R1: R1, - R2: R2, - singularPoints: singularPoints - }; - - } - - async function verifyLagrangeEvaluations(gName, tauSection, lagrangeSection, sectionName, logger) { - - if (logger) logger.debug(`Verifying phase2 calculated values ${sectionName}...`); - const G = curve[gName]; - const sG = G.F.n8*2; - - const seed= new Array(8); - for (let i=0; i<8; i++) { - seed[i] = readUInt32BE(getRandomBytes(4), 0); - } - - for (let p=0; p<= power; p ++) { - const res = await verifyPower(p); - if (!res) return false; - } - - if (tauSection == 2) { - const res = await verifyPower(power+1); - if (!res) return false; - } - - return true; - - async function verifyPower(p) { - if (logger) logger.debug(`Power ${p}...`); - const n8r = curve.Fr.n8; - const nPoints = 2 ** p; - let buff_r = new Uint32Array(nPoints); - let buffG; - - let rng = new ffjavascript.ChaCha(seed); - - if (logger) logger.debug(`Creating random numbers Powers${p}...`); - for (let i=0; i. -*/ - - -/* - This function creates a new section in the fdTo file with id idSection. - It multiplies the points in fdFrom by first, first*inc, first*inc^2, .... - nPoint Times. - It also updates the newChallengeHasher with the new points -*/ - + let sr; + const { fd, sections } = await _iden3_binfileutils.readBinFile(tauFilename, "ptau", 1); + const { curve, power, ceremonyPower } = await readPTauHeader(fd, sections); + const contrs = await readContributions(fd, curve, sections); + if (logger) logger.debug("power: 2**" + power); + if (logger) logger.debug("Computing initial contribution hash"); + const initialContribution = { + tauG1: curve.G1.g, + tauG2: curve.G2.g, + alphaG1: curve.G1.g, + betaG1: curve.G1.g, + betaG2: curve.G2.g, + nextChallenge: calculateFirstChallengeHash(curve, ceremonyPower, logger), + responseHash: _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }).digest() + }; + if (contrs.length == 0) { + if (logger) logger.error("This file has no contribution! It cannot be used in production"); + return false; + } + let prevContr; + if (contrs.length > 1) prevContr = contrs[contrs.length - 2]; + else prevContr = initialContribution; + const curContr = contrs[contrs.length - 1]; + if (logger) logger.debug("Validating contribution #" + contrs[contrs.length - 1].id); + if (!await verifyContribution(curve, curContr, prevContr, logger)) return false; + const nextContributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + nextContributionHasher.update(curContr.responseHash); + if (logger) logger.debug("Verifying powers in tau*G1 section"); + const rTau1 = await processSection(2, "G1", "tauG1", 2 ** power * 2 - 1, [0, 1], logger); + sr = await sameRatio$1(curve, rTau1.R1, rTau1.R2, curve.G2.g, curContr.tauG2); + if (sr !== true) { + if (logger) logger.error("tauG1 section. Powers do not match"); + return false; + } + if (!curve.G1.eq(curve.G1.g, rTau1.singularPoints[0])) { + if (logger) logger.error("First element of tau*G1 section must be the generator"); + return false; + } + if (!curve.G1.eq(curContr.tauG1, rTau1.singularPoints[1])) { + if (logger) logger.error("Second element of tau*G1 section does not match the one in the contribution section"); + return false; + } + if (logger) logger.debug("Verifying powers in tau*G2 section"); + const rTau2 = await processSection(3, "G2", "tauG2", 2 ** power, [0, 1], logger); + sr = await sameRatio$1(curve, curve.G1.g, curContr.tauG1, rTau2.R1, rTau2.R2); + if (sr !== true) { + if (logger) logger.error("tauG2 section. Powers do not match"); + return false; + } + if (!curve.G2.eq(curve.G2.g, rTau2.singularPoints[0])) { + if (logger) logger.error("First element of tau*G2 section must be the generator"); + return false; + } + if (!curve.G2.eq(curContr.tauG2, rTau2.singularPoints[1])) { + if (logger) logger.error("Second element of tau*G2 section does not match the one in the contribution section"); + return false; + } + if (logger) logger.debug("Verifying powers in alpha*tau*G1 section"); + const rAlphaTauG1 = await processSection(4, "G1", "alphatauG1", 2 ** power, [0], logger); + sr = await sameRatio$1(curve, rAlphaTauG1.R1, rAlphaTauG1.R2, curve.G2.g, curContr.tauG2); + if (sr !== true) { + if (logger) logger.error("alphaTauG1 section. Powers do not match"); + return false; + } + if (!curve.G1.eq(curContr.alphaG1, rAlphaTauG1.singularPoints[0])) { + if (logger) logger.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"); + return false; + } + if (logger) logger.debug("Verifying powers in beta*tau*G1 section"); + const rBetaTauG1 = await processSection(5, "G1", "betatauG1", 2 ** power, [0], logger); + sr = await sameRatio$1(curve, rBetaTauG1.R1, rBetaTauG1.R2, curve.G2.g, curContr.tauG2); + if (sr !== true) { + if (logger) logger.error("betaTauG1 section. Powers do not match"); + return false; + } + if (!curve.G1.eq(curContr.betaG1, rBetaTauG1.singularPoints[0])) { + if (logger) logger.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"); + return false; + } + const betaG2 = await processSectionBetaG2(logger); + if (!curve.G2.eq(curContr.betaG2, betaG2)) { + if (logger) logger.error("betaG2 element in betaG2 section does not match the one in the contribution section"); + return false; + } + const nextContributionHash = nextContributionHasher.digest(); + if (power == ceremonyPower) { + if (!hashIsEqual(nextContributionHash, curContr.nextChallenge)) { + if (logger) logger.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"); + return false; + } + } + if (logger) logger.info(formatHash(nextContributionHash, "Next challenge hash: ")); + printContribution(curContr, prevContr); + for (let i = contrs.length - 2; i >= 0; i--) { + const curContr = contrs[i]; + const prevContr = i > 0 ? contrs[i - 1] : initialContribution; + if (!await verifyContribution(curve, curContr, prevContr, logger)) return false; + printContribution(curContr, prevContr, logger); + } + if (logger) logger.info("-----------------------------------------------------"); + if (!sections[12] || !sections[13] || !sections[14] || !sections[15]) { + if (logger) logger.warn("this file does not contain phase2 precalculated values. Please run: \n snarkjs \"powersoftau preparephase2\" to prepare this file to be used in the phase2 ceremony."); + } else { + let res; + res = await verifyLagrangeEvaluations("G1", 2, 12, "tauG1", logger); + if (!res) return false; + res = await verifyLagrangeEvaluations("G2", 3, 13, "tauG2", logger); + if (!res) return false; + res = await verifyLagrangeEvaluations("G1", 4, 14, "alphaTauG1", logger); + if (!res) return false; + res = await verifyLagrangeEvaluations("G1", 5, 15, "betaTauG1", logger); + if (!res) return false; + } + await fd.close(); + if (logger) logger.info("Powers of Tau Ok!"); + return true; + function printContribution(curContr, prevContr) { + if (!logger) return; + logger.info("-----------------------------------------------------"); + logger.info(`Contribution #${curContr.id}: ${curContr.name || ""}`); + logger.info(formatHash(curContr.nextChallenge, "Next Challenge: ")); + const buffV = new Uint8Array(curve.G1.F.n8 * 2 * 6 + curve.G2.F.n8 * 2 * 3); + toPtauPubKeyRpr(buffV, 0, curve, curContr.key, false); + const responseHasher = fromPartialHash(curContr.partialHash); + responseHasher.update(buffV); + const responseHash = responseHasher.digest(); + logger.info(formatHash(responseHash, "Response Hash:")); + logger.info(formatHash(prevContr.nextChallenge, "Response Hash:")); + if (curContr.type == 1) { + logger.info(`Beacon generator: ${byteArray2hex(curContr.beaconHash)}`); + logger.info(`Beacon iterations Exp: ${curContr.numIterationsExp}`); + } + } + async function processSectionBetaG2(logger) { + const G = curve.G2; + const sG = G.F.n8 * 2; + const buffUv = new Uint8Array(sG); + if (!sections[6]) { + logger.error("File has no BetaG2 section"); + throw new Error("File has no BetaG2 section"); + } + if (sections[6].length > 1) { + logger.error("File has no BetaG2 section"); + throw new Error("File has more than one GetaG2 section"); + } + fd.pos = sections[6][0].p; + const buff = await fd.read(sG); + const P = G.fromRprLEM(buff); + G.toRprUncompressed(buffUv, 0, P); + nextContributionHasher.update(buffUv); + return P; + } + async function processSection(idSection, groupName, sectionName, nPoints, singularPointIndexes, logger) { + const MAX_CHUNK_SIZE = 65536; + const G = curve[groupName]; + const sG = G.F.n8 * 2; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, idSection); + const singularPoints = []; + let R1 = G.zero; + let R2 = G.zero; + let lastBase = G.zero; + for (let i = 0; i < nPoints; i += MAX_CHUNK_SIZE) { + if (logger) logger.debug(`points relations: ${sectionName}: ${i}/${nPoints} `); + const n = Math.min(nPoints - i, MAX_CHUNK_SIZE); + const bases = await fd.read(n * sG); + const basesU = await G.batchLEMtoU(bases); + nextContributionHasher.update(basesU); + const scalars = getRandomBytes(4 * (n - 1)); + if (i > 0) { + const firstBase = G.fromRprLEM(bases, 0); + const r = readUInt32BE(getRandomBytes(4), 0); + R1 = G.add(R1, G.timesScalar(lastBase, r)); + R2 = G.add(R2, G.timesScalar(firstBase, r)); + } + const r1 = await G.multiExpAffine(bases.slice(0, (n - 1) * sG), scalars); + const r2 = await G.multiExpAffine(bases.slice(sG), scalars); + R1 = G.add(R1, r1); + R2 = G.add(R2, r2); + lastBase = G.fromRprLEM(bases, (n - 1) * sG); + for (let j = 0; j < singularPointIndexes.length; j++) { + const sp = singularPointIndexes[j]; + if (sp >= i && sp < i + n) { + const P = G.fromRprLEM(bases, (sp - i) * sG); + singularPoints.push(P); + } + } + } + await _iden3_binfileutils.endReadSection(fd); + return { + R1, + R2, + singularPoints + }; + } + async function verifyLagrangeEvaluations(gName, tauSection, lagrangeSection, sectionName, logger) { + if (logger) logger.debug(`Verifying phase2 calculated values ${sectionName}...`); + const G = curve[gName]; + const sG = G.F.n8 * 2; + const seed = new Array(8); + for (let i = 0; i < 8; i++) seed[i] = readUInt32BE(getRandomBytes(4), 0); + for (let p = 0; p <= power; p++) if (!await verifyPower(p)) return false; + if (tauSection == 2) { + if (!await verifyPower(power + 1)) return false; + } + return true; + async function verifyPower(p) { + if (logger) logger.debug(`Power ${p}...`); + const n8r = curve.Fr.n8; + const nPoints = 2 ** p; + let buff_r = new Uint32Array(nPoints); + let buffG; + let rng = new ffjavascript.ChaCha(seed); + if (logger) logger.debug(`Creating random numbers Powers${p}...`); + for (let i = 0; i < nPoints; i++) if (p == power + 1 && i == nPoints - 1) buff_r[i] = 0; + else buff_r[i] = rng.nextU32(); + buff_r = new Uint8Array(buff_r.buffer, buff_r.byteOffset, buff_r.byteLength); + if (logger) logger.debug(`reading points Powers${p}...`); + await _iden3_binfileutils.startReadUniqueSection(fd, sections, tauSection); + buffG = new ffjavascript.BigBuffer(nPoints * sG); + if (p == power + 1) { + await fd.readToBuffer(buffG, 0, (nPoints - 1) * sG); + buffG.set(curve.G1.zeroAffine, (nPoints - 1) * sG); + } else await fd.readToBuffer(buffG, 0, nPoints * sG); + await _iden3_binfileutils.endReadSection(fd, true); + const resTau = await G.multiExpAffine(buffG, buff_r, logger, sectionName + "_" + p); + buff_r = new ffjavascript.BigBuffer(nPoints * n8r); + rng = new ffjavascript.ChaCha(seed); + const buff4 = /* @__PURE__ */ new Uint8Array(4); + const buff4V = new DataView(buff4.buffer); + if (logger) logger.debug(`Creating random numbers Powers${p}...`); + for (let i = 0; i < nPoints; i++) if (i != nPoints - 1 || p != power + 1) { + buff4V.setUint32(0, rng.nextU32(), true); + buff_r.set(buff4, i * n8r); + } + if (logger) logger.debug(`batchToMontgomery ${p}...`); + buff_r = await curve.Fr.batchToMontgomery(buff_r); + if (logger) logger.debug(`fft ${p}...`); + buff_r = await curve.Fr.fft(buff_r); + if (logger) logger.debug(`batchFromMontgomery ${p}...`); + buff_r = await curve.Fr.batchFromMontgomery(buff_r); + if (logger) logger.debug(`reading points Lagrange${p}...`); + await _iden3_binfileutils.startReadUniqueSection(fd, sections, lagrangeSection); + fd.pos += sG * (2 ** p - 1); + await fd.readToBuffer(buffG, 0, nPoints * sG); + await _iden3_binfileutils.endReadSection(fd, true); + const resLagrange = await G.multiExpAffine(buffG, buff_r, logger, sectionName + "_" + p + "_transformed"); + if (!G.eq(resTau, resLagrange)) { + if (logger) logger.error("Phase2 caclutation does not match with powers of tau"); + return false; + } + return true; + } + } +} +//#endregion +//#region src/mpc_applykey.js async function applyKeyToSection(fdOld, sections, fdNew, idSection, curve, groupName, first, inc, sectionName, logger) { - const MAX_CHUNK_SIZE = 1 << 16; - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPoints = sections[idSection][0].size / sG; - - await binFileUtils__namespace.startReadUniqueSection(fdOld, sections,idSection ); - await binFileUtils__namespace.startWriteSection(fdNew, idSection); - - let t = first; - for (let i=0; i. -*/ - - + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const chunkSize = Math.floor((1 << 20) / sG); + let t = first; + for (let i = 0; i < nPoints; i += chunkSize) { + if (logger) logger.debug(`Applying key ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, chunkSize); + const buffInU = await fdOld.read(n * sG); + const buffInLEM = await G.batchUtoLEM(buffInU); + const buffOutLEM = await G.batchApplyKey(buffInLEM, t, inc); + let buffOut; + if (formatOut == "COMPRESSED") buffOut = await G.batchLEMtoC(buffOutLEM); + else buffOut = await G.batchLEMtoU(buffOutLEM); + if (responseHasher) responseHasher.update(buffOut); + await fdNew.write(buffOut); + t = curve.Fr.mul(t, curve.Fr.exp(inc, n)); + } +} +//#endregion +//#region src/powersoftau_challenge_contribute.js async function challengeContribute(curve, challengeFilename, responseFileName, entropy, logger) { - const fdFrom = await fastFile__namespace.readExisting(challengeFilename); - - - const sG1 = curve.F1.n64*8*2; - const sG2 = curve.F2.n64*8*2; - const domainSize = (fdFrom.totalSize + sG1 - 64 - sG2) / (4*sG1 + sG2); - let e = domainSize; - let power = 0; - while (e>1) { - e = e /2; - power += 1; - } - - if (2 ** power != domainSize) throw new Error("Invalid file size"); - if (logger) logger.debug("Power to tau size: "+power); - - const rng = await getRandomRng(entropy); - - const fdTo = await fastFile__namespace.createOverride(responseFileName); - - // Calculate the hash - const challengeHasher = blake2_js.blake2b.create({ dkLen: 64 }); - for (let i=0; i { - logger.debug(k + ".g1_s: " + curve.G1.toString(key[k].g1_s, 16)); - logger.debug(k + ".g1_sx: " + curve.G1.toString(key[k].g1_sx, 16)); - logger.debug(k + ".g2_sp: " + curve.G2.toString(key[k].g2_sp, 16)); - logger.debug(k + ".g2_spx: " + curve.G2.toString(key[k].g2_spx, 16)); - logger.debug(""); - }); - } - - const responseHasher = blake2_js.blake2b.create({ dkLen: 64 }); - - await fdTo.write(challengeHash); - responseHasher.update(challengeHash); - - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power)*2-1, curve.Fr.one , key.tau.prvKey, "COMPRESSED", "tauG1" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", (2 ** power) , curve.Fr.one , key.tau.prvKey, "COMPRESSED", "tauG2" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power) , key.alpha.prvKey, key.tau.prvKey, "COMPRESSED", "alphaTauG1", logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power) , key.beta.prvKey , key.tau.prvKey, "COMPRESSED", "betaTauG1" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", 1 , key.beta.prvKey , key.tau.prvKey, "COMPRESSED", "betaTauG2" , logger ); - - // Write and hash key - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - toPtauPubKeyRpr(buffKey, 0, curve, key, false); - await fdTo.write(buffKey); - responseHasher.update(buffKey); - const responseHash = responseHasher.digest(); - if (logger) logger.info(formatHash(responseHash, "Contribution Response Hash: ")); - - await fdTo.close(); - await fdFrom.close(); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -async function beacon$1(oldPtauFilename, newPTauFilename, name, beaconHashStr,numIterationsExp, logger) { - const beaconHash = hex2ByteArray(beaconHashStr); - if ( (beaconHash.byteLength == 0) - || (beaconHash.byteLength*2 !=beaconHashStr.length)) - { - if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); - return false; - } - if (beaconHash.length>=256) { - if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); - return false; - } - - numIterationsExp = parseInt(numIterationsExp); - if ((numIterationsExp<10)||(numIterationsExp>63)) { - if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); - return false; - } - - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - if (power != ceremonyPower) { - if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); - return false; - } - if (sections[12]) { - if (logger) logger.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); - } - const contributions = await readContributions(fdOld, curve, sections); - const curContribution = { - name: name, - type: 1, // Beacon - numIterationsExp: numIterationsExp, - beaconHash: beaconHash - }; - - let lastChallengeHash; - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - curContribution.key = await keyFromBeacon(curve, lastChallengeHash, beaconHash, numIterationsExp); - - const responseHasher = blake2_js.blake2b.create({ dkLen: 64 }); - responseHasher.update(lastChallengeHash); - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, 7); - await writePTauHeader(fdNew, curve, power); - - const startSections = []; - - let firstPoints; - firstPoints = await processSection(2, "G1", (2 ** power) * 2 -1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1", logger ); - curContribution.tauG1 = firstPoints[1]; - firstPoints = await processSection(3, "G2", (2 ** power) , curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2", logger ); - curContribution.tauG2 = firstPoints[1]; - firstPoints = await processSection(4, "G1", (2 ** power) , curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1", logger ); - curContribution.alphaG1 = firstPoints[0]; - firstPoints = await processSection(5, "G1", (2 ** power) , curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1", logger ); - curContribution.betaG1 = firstPoints[0]; - firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2", logger ); - curContribution.betaG2 = firstPoints[0]; - - curContribution.partialHash = toPartialHash(responseHasher); - - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - - toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); - - responseHasher.update(new Uint8Array(buffKey)); - const hashResponse = responseHasher.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - const nextChallengeHasher = blake2_js.blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1", logger); - await hashSection(fdNew, "G2", 3, (2 ** power) , "tauG2", logger); - await hashSection(fdNew, "G1", 4, (2 ** power) , "alphaTauG1", logger); - await hashSection(fdNew, "G1", 5, (2 ** power) , "betaTauG1", logger); - await hashSection(fdNew, "G2", 6, 1 , "betaG2", logger); - - curContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); - - contributions.push(curContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdOld.close(); - await fdNew.close(); - - return hashResponse; - - async function processSection(sectionId, groupName, NPoints, first, inc, sectionName, logger) { - const res = []; - fdOld.pos = sections[sectionId][0].p; - - await binFileUtils__namespace.startWriteSection(fdNew, sectionId); - - startSections[sectionId] = fdNew.pos; - - const G = curve[groupName]; - const sG = G.F.n8*2; - const chunkSize = Math.floor((1<<20) / sG); // 128Mb chunks - let t = first; - for (let i=0 ; i. -*/ - - + const fdFrom = await fastfile.readExisting(challengeFilename); + const sG1 = curve.F1.n64 * 8 * 2; + const sG2 = curve.F2.n64 * 8 * 2; + const domainSize = (fdFrom.totalSize + sG1 - 64 - sG2) / (4 * sG1 + sG2); + let e = domainSize; + let power = 0; + while (e > 1) { + e = e / 2; + power += 1; + } + if (2 ** power != domainSize) throw new Error("Invalid file size"); + if (logger) logger.debug("Power to tau size: " + power); + const rng = await getRandomRng(entropy); + const fdTo = await fastfile.createOverride(responseFileName); + const challengeHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + for (let i = 0; i < fdFrom.totalSize; i += fdFrom.pageSize) { + if (logger) logger.debug(`Hashing challenge ${i}/${fdFrom.totalSize}`); + const s = Math.min(fdFrom.totalSize - i, fdFrom.pageSize); + const buff = await fdFrom.read(s); + challengeHasher.update(buff); + } + const claimedHash = await fdFrom.read(64, 0); + if (logger) logger.info(formatHash(claimedHash, "Claimed Previous Response Hash: ")); + const challengeHash = challengeHasher.digest(); + if (logger) logger.info(formatHash(challengeHash, "Current Challenge Hash: ")); + const key = createPTauKey(curve, challengeHash, rng); + if (logger) [ + "tau", + "alpha", + "beta" + ].forEach((k) => { + logger.debug(k + ".g1_s: " + curve.G1.toString(key[k].g1_s, 16)); + logger.debug(k + ".g1_sx: " + curve.G1.toString(key[k].g1_sx, 16)); + logger.debug(k + ".g2_sp: " + curve.G2.toString(key[k].g2_sp, 16)); + logger.debug(k + ".g2_spx: " + curve.G2.toString(key[k].g2_spx, 16)); + logger.debug(""); + }); + const responseHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + await fdTo.write(challengeHash); + responseHasher.update(challengeHash); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", 2 ** power * 2 - 1, curve.Fr.one, key.tau.prvKey, "COMPRESSED", "tauG1", logger); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", 2 ** power, curve.Fr.one, key.tau.prvKey, "COMPRESSED", "tauG2", logger); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", 2 ** power, key.alpha.prvKey, key.tau.prvKey, "COMPRESSED", "alphaTauG1", logger); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", 2 ** power, key.beta.prvKey, key.tau.prvKey, "COMPRESSED", "betaTauG1", logger); + await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", 1, key.beta.prvKey, key.tau.prvKey, "COMPRESSED", "betaTauG2", logger); + const buffKey = new Uint8Array(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + toPtauPubKeyRpr(buffKey, 0, curve, key, false); + await fdTo.write(buffKey); + responseHasher.update(buffKey); + const responseHash = responseHasher.digest(); + if (logger) logger.info(formatHash(responseHash, "Contribution Response Hash: ")); + await fdTo.close(); + await fdFrom.close(); +} +//#endregion +//#region src/powersoftau_beacon.js +async function beacon$1(oldPtauFilename, newPTauFilename, name, beaconHashStr, numIterationsExp, logger) { + const beaconHash = hex2ByteArray(beaconHashStr); + if (beaconHash.byteLength == 0 || beaconHash.byteLength * 2 != beaconHashStr.length) { + if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); + return false; + } + if (beaconHash.length >= 256) { + if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); + return false; + } + numIterationsExp = parseInt(numIterationsExp); + if (numIterationsExp < 10 || numIterationsExp > 63) { + if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); + return false; + } + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power, ceremonyPower } = await readPTauHeader(fdOld, sections); + if (power != ceremonyPower) { + if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); + return false; + } + if (sections[12]) { + if (logger) logger.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); + } + const contributions = await readContributions(fdOld, curve, sections); + const curContribution = { + name, + type: 1, + numIterationsExp, + beaconHash + }; + let lastChallengeHash; + if (contributions.length > 0) lastChallengeHash = contributions[contributions.length - 1].nextChallenge; + else lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); + curContribution.key = await keyFromBeacon(curve, lastChallengeHash, beaconHash, numIterationsExp); + const responseHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + responseHasher.update(lastChallengeHash); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, 7); + await writePTauHeader(fdNew, curve, power); + const startSections = []; + let firstPoints; + firstPoints = await processSection(2, "G1", 2 ** power * 2 - 1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1", logger); + curContribution.tauG1 = firstPoints[1]; + firstPoints = await processSection(3, "G2", 2 ** power, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2", logger); + curContribution.tauG2 = firstPoints[1]; + firstPoints = await processSection(4, "G1", 2 ** power, curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1", logger); + curContribution.alphaG1 = firstPoints[0]; + firstPoints = await processSection(5, "G1", 2 ** power, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1", logger); + curContribution.betaG1 = firstPoints[0]; + firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2", logger); + curContribution.betaG2 = firstPoints[0]; + curContribution.partialHash = toPartialHash(responseHasher); + const buffKey = new Uint8Array(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); + responseHasher.update(new Uint8Array(buffKey)); + const hashResponse = responseHasher.digest(); + if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); + const nextChallengeHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + nextChallengeHasher.update(hashResponse); + await hashSection(fdNew, "G1", 2, 2 ** power * 2 - 1, "tauG1", logger); + await hashSection(fdNew, "G2", 3, 2 ** power, "tauG2", logger); + await hashSection(fdNew, "G1", 4, 2 ** power, "alphaTauG1", logger); + await hashSection(fdNew, "G1", 5, 2 ** power, "betaTauG1", logger); + await hashSection(fdNew, "G2", 6, 1, "betaG2", logger); + curContribution.nextChallenge = nextChallengeHasher.digest(); + if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); + contributions.push(curContribution); + await writeContributions(fdNew, curve, contributions); + await fdOld.close(); + await fdNew.close(); + return hashResponse; + async function processSection(sectionId, groupName, NPoints, first, inc, sectionName, logger) { + const res = []; + fdOld.pos = sections[sectionId][0].p; + await _iden3_binfileutils.startWriteSection(fdNew, sectionId); + startSections[sectionId] = fdNew.pos; + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const chunkSize = Math.floor((1 << 20) / sG); + let t = first; + for (let i = 0; i < NPoints; i += chunkSize) { + if (logger) logger.debug(`applying key${sectionName}: ${i}/${NPoints}`); + const n = Math.min(NPoints - i, chunkSize); + const buffIn = await fdOld.read(n * sG); + const buffOutLEM = await G.batchApplyKey(buffIn, t, inc); + const promiseWrite = fdNew.write(buffOutLEM); + const buffOutC = await G.batchLEMtoC(buffOutLEM); + responseHasher.update(buffOutC); + await promiseWrite; + if (i == 0) for (let j = 0; j < Math.min(2, NPoints); j++) res.push(G.fromRprLEM(buffOutLEM, j * sG)); + t = curve.Fr.mul(t, curve.Fr.exp(inc, n)); + } + await _iden3_binfileutils.endWriteSection(fdNew); + return res; + } + async function hashSection(fdTo, groupName, sectionId, nPoints, sectionName, logger) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const nPointsChunk = Math.floor((1 << 24) / sG); + const oldPos = fdTo.pos; + fdTo.pos = startSections[sectionId]; + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger) logger.debug(`Hashing ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, nPointsChunk); + const buffLEM = await fdTo.read(n * sG); + const buffU = await G.batchLEMtoU(buffLEM); + nextChallengeHasher.update(buffU); + } + fdTo.pos = oldPos; + } +} +//#endregion +//#region src/powersoftau_contribute.js async function contribute(oldPtauFilename, newPTauFilename, name, entropy, logger) { - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - if (power != ceremonyPower) { - if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); - throw new Error("This file has been reduced. You cannot contribute into a reduced file."); - } - if (sections[12]) { - if (logger) logger.warn("WARNING: Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); - } - const contributions = await readContributions(fdOld, curve, sections); - const curContribution = { - name: name, - type: 0, // Beacon - }; - - let lastChallengeHash; - - const rng = await getRandomRng(entropy); - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - // Generate a random key - - - curContribution.key = createPTauKey(curve, lastChallengeHash, rng); - - - const responseHasher = blake2_js.blake2b.create({ dkLen: 64 }); - responseHasher.update(lastChallengeHash); - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, 7); - await writePTauHeader(fdNew, curve, power); - - const startSections = []; - - let firstPoints; - firstPoints = await processSection(2, "G1", (2 ** power) * 2 -1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1" ); - curContribution.tauG1 = firstPoints[1]; - firstPoints = await processSection(3, "G2", (2 ** power) , curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2" ); - curContribution.tauG2 = firstPoints[1]; - firstPoints = await processSection(4, "G1", (2 ** power) , curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1" ); - curContribution.alphaG1 = firstPoints[0]; - firstPoints = await processSection(5, "G1", (2 ** power) , curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1" ); - curContribution.betaG1 = firstPoints[0]; - firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2" ); - curContribution.betaG2 = firstPoints[0]; - - curContribution.partialHash = toPartialHash(responseHasher); - - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - - toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); - - responseHasher.update(new Uint8Array(buffKey)); - const hashResponse = responseHasher.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - const nextChallengeHasher = blake2_js.blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1"); - await hashSection(fdNew, "G2", 3, (2 ** power) , "tauG2"); - await hashSection(fdNew, "G1", 4, (2 ** power) , "alphaTauG1"); - await hashSection(fdNew, "G1", 5, (2 ** power) , "betaTauG1"); - await hashSection(fdNew, "G2", 6, 1 , "betaG2"); - - curContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); - - contributions.push(curContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdOld.close(); - await fdNew.close(); - - return hashResponse; - - async function processSection(sectionId, groupName, NPoints, first, inc, sectionName) { - const res = []; - fdOld.pos = sections[sectionId][0].p; - - await binFileUtils__namespace.startWriteSection(fdNew, sectionId); - - startSections[sectionId] = fdNew.pos; - - const G = curve[groupName]; - const sG = G.F.n8*2; - const chunkSize = Math.floor((1<<20) / sG); // 128Mb chunks - let t = first; - for (let i=0 ; i. -*/ - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power, ceremonyPower } = await readPTauHeader(fdOld, sections); + if (power != ceremonyPower) { + if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); + throw new Error("This file has been reduced. You cannot contribute into a reduced file."); + } + if (sections[12]) { + if (logger) logger.warn("WARNING: Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); + } + const contributions = await readContributions(fdOld, curve, sections); + const curContribution = { + name, + type: 0 + }; + let lastChallengeHash; + const rng = await getRandomRng(entropy); + if (contributions.length > 0) lastChallengeHash = contributions[contributions.length - 1].nextChallenge; + else lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); + curContribution.key = createPTauKey(curve, lastChallengeHash, rng); + const responseHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + responseHasher.update(lastChallengeHash); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, 7); + await writePTauHeader(fdNew, curve, power); + const startSections = []; + let firstPoints; + firstPoints = await processSection(2, "G1", 2 ** power * 2 - 1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1"); + curContribution.tauG1 = firstPoints[1]; + firstPoints = await processSection(3, "G2", 2 ** power, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2"); + curContribution.tauG2 = firstPoints[1]; + firstPoints = await processSection(4, "G1", 2 ** power, curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1"); + curContribution.alphaG1 = firstPoints[0]; + firstPoints = await processSection(5, "G1", 2 ** power, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1"); + curContribution.betaG1 = firstPoints[0]; + firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2"); + curContribution.betaG2 = firstPoints[0]; + curContribution.partialHash = toPartialHash(responseHasher); + const buffKey = new Uint8Array(curve.F1.n8 * 2 * 6 + curve.F2.n8 * 2 * 3); + toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); + responseHasher.update(new Uint8Array(buffKey)); + const hashResponse = responseHasher.digest(); + if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); + const nextChallengeHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + nextChallengeHasher.update(hashResponse); + await hashSection(fdNew, "G1", 2, 2 ** power * 2 - 1, "tauG1"); + await hashSection(fdNew, "G2", 3, 2 ** power, "tauG2"); + await hashSection(fdNew, "G1", 4, 2 ** power, "alphaTauG1"); + await hashSection(fdNew, "G1", 5, 2 ** power, "betaTauG1"); + await hashSection(fdNew, "G2", 6, 1, "betaG2"); + curContribution.nextChallenge = nextChallengeHasher.digest(); + if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); + contributions.push(curContribution); + await writeContributions(fdNew, curve, contributions); + await fdOld.close(); + await fdNew.close(); + return hashResponse; + async function processSection(sectionId, groupName, NPoints, first, inc, sectionName) { + const res = []; + fdOld.pos = sections[sectionId][0].p; + await _iden3_binfileutils.startWriteSection(fdNew, sectionId); + startSections[sectionId] = fdNew.pos; + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const chunkSize = Math.floor((1 << 20) / sG); + let t = first; + for (let i = 0; i < NPoints; i += chunkSize) { + if (logger) logger.debug(`processing: ${sectionName}: ${i}/${NPoints}`); + const n = Math.min(NPoints - i, chunkSize); + const buffIn = await fdOld.read(n * sG); + const buffOutLEM = await G.batchApplyKey(buffIn, t, inc); + const promiseWrite = fdNew.write(buffOutLEM); + const buffOutC = await G.batchLEMtoC(buffOutLEM); + responseHasher.update(buffOutC); + await promiseWrite; + if (i == 0) for (let j = 0; j < Math.min(2, NPoints); j++) res.push(G.fromRprLEM(buffOutLEM, j * sG)); + t = curve.Fr.mul(t, curve.Fr.exp(inc, n)); + } + await _iden3_binfileutils.endWriteSection(fdNew); + return res; + } + async function hashSection(fdTo, groupName, sectionId, nPoints, sectionName) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const nPointsChunk = Math.floor((1 << 24) / sG); + const oldPos = fdTo.pos; + fdTo.pos = startSections[sectionId]; + for (let i = 0; i < nPoints; i += nPointsChunk) { + if (logger && i) logger.debug(`Hashing ${sectionName}: ` + i); + const n = Math.min(nPoints - i, nPointsChunk); + const buffLEM = await fdTo.read(n * sG); + const buffU = await G.batchLEMtoU(buffLEM); + nextChallengeHasher.update(buffU); + } + fdTo.pos = oldPos; + } +} +//#endregion +//#region src/powersoftau_preparephase2.js async function preparePhase2(oldPtauFilename, newPTauFilename, logger) { - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, 11); - await writePTauHeader(fdNew, curve, power); - - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 2); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 3); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 4); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 5); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 6); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 7); - - await processSection(2, 12, "G1", "tauG1" ); - await processSection(3, 13, "G2", "tauG2" ); - await processSection(4, 14, "G1", "alphaTauG1" ); - await processSection(5, 15, "G1", "betaTauG1" ); - - await fdOld.close(); - await fdNew.close(); - - // await fs.promises.unlink(newPTauFilename+ ".tmp"); - - return; - - async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { - if (logger) logger.debug("Starting section: "+sectionName); - - await binFileUtils__namespace.startWriteSection(fdNew, newSectionId); - - for (let p=0; p<=power; p++) { - await processSectionPower(p); - } - - if (oldSectionId == 2) { - await processSectionPower(power+1); - } - - await binFileUtils__namespace.endWriteSection(fdNew); - - - async function processSectionPower(p) { - const nPoints = 2 ** p; - const G = curve[Gstr]; - const sGin = G.F.n8*2; - - let buff; - buff = new ffjavascript.BigBuffer(nPoints*sGin); - - await binFileUtils__namespace.startReadUniqueSection(fdOld, sections, oldSectionId); - if ((oldSectionId == 2)&&(p==power+1)) { - await fdOld.readToBuffer(buff, 0,(nPoints-1)*sGin ); - buff.set(curve.G1.zeroAffine, (nPoints-1)*sGin ); - } else { - await fdOld.readToBuffer(buff, 0,nPoints*sGin ); - } - await binFileUtils__namespace.endReadSection(fdOld, true); - - - buff = await G.lagrangeEvaluations(buff, "affine", "affine", logger, sectionName); - await fdNew.write(buff); - - /* - if (p <= curve.Fr.s) { - buff = await G.ifft(buff, "affine", "affine", logger, sectionName); - await fdNew.write(buff); - } else if (p == curve.Fr.s+1) { - const smallM = 1<. -*/ - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fdOld, sections); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, 11); + await writePTauHeader(fdNew, curve, power); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + await processSection(2, 12, "G1", "tauG1"); + await processSection(3, 13, "G2", "tauG2"); + await processSection(4, 14, "G1", "alphaTauG1"); + await processSection(5, 15, "G1", "betaTauG1"); + await fdOld.close(); + await fdNew.close(); + return; + async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { + if (logger) logger.debug("Starting section: " + sectionName); + await _iden3_binfileutils.startWriteSection(fdNew, newSectionId); + for (let p = 0; p <= power; p++) await processSectionPower(p); + if (oldSectionId == 2) await processSectionPower(power + 1); + await _iden3_binfileutils.endWriteSection(fdNew); + async function processSectionPower(p) { + const nPoints = 2 ** p; + const G = curve[Gstr]; + const sGin = G.F.n8 * 2; + let buff; + buff = new ffjavascript.BigBuffer(nPoints * sGin); + await _iden3_binfileutils.startReadUniqueSection(fdOld, sections, oldSectionId); + if (oldSectionId == 2 && p == power + 1) { + await fdOld.readToBuffer(buff, 0, (nPoints - 1) * sGin); + buff.set(curve.G1.zeroAffine, (nPoints - 1) * sGin); + } else await fdOld.readToBuffer(buff, 0, nPoints * sGin); + await _iden3_binfileutils.endReadSection(fdOld, true); + buff = await G.lagrangeEvaluations(buff, "affine", "affine", logger, sectionName); + await fdNew.write(buff); + } + } +} +//#endregion +//#region src/powersoftau_truncate.js async function truncate(ptauFilename, template, logger) { - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(ptauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - for (let p=1; p. -*/ - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(ptauFilename, "ptau", 1); + const { curve, power, ceremonyPower } = await readPTauHeader(fdOld, sections); + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + for (let p = 1; p < power; p++) await generateTruncate(p); + await fdOld.close(); + return true; + async function generateTruncate(p) { + let sP = p.toString(); + while (sP.length < 2) sP = "0" + sP; + if (logger) logger.debug("Writing Power: " + sP); + const fdNew = await _iden3_binfileutils.createBinFile(template + sP + ".ptau", "ptau", 1, 11); + await writePTauHeader(fdNew, curve, p, ceremonyPower); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 2, (2 ** p * 2 - 1) * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3, 2 ** p * sG2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4, 2 ** p * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5, 2 ** p * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6, sG2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 12, (2 ** (p + 1) * 2 - 1) * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 13, (2 ** p * 2 - 1) * sG2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 14, (2 ** p * 2 - 1) * sG1); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 15, (2 ** p * 2 - 1) * sG1); + await fdNew.close(); + } +} +//#endregion +//#region src/powersoftau_convert.js async function convert(oldPtauFilename, newPTauFilename, logger) { - - const {fd: fdOld, sections} = await binFileUtils__namespace.readBinFile(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - - const fdNew = await binFileUtils__namespace.createBinFile(newPTauFilename, "ptau", 1, 11); - await writePTauHeader(fdNew, curve, power); - - // const fdTmp = await fastFile.createOverride(newPTauFilename+ ".tmp"); - - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 2); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 3); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 4); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 5); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 6); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 7); - - await processSection(2, 12, "G1", "tauG1" ); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 13); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 14); - await binFileUtils__namespace.copySection(fdOld, sections, fdNew, 15); - - await fdOld.close(); - await fdNew.close(); - - // await fs.promises.unlink(newPTauFilename+ ".tmp"); - - return; - - async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { - if (logger) logger.debug("Starting section: "+sectionName); - - await binFileUtils__namespace.startWriteSection(fdNew, newSectionId); - - const size = sections[newSectionId][0].size; - const chunkSize = fdOld.pageSize; - await binFileUtils__namespace.startReadUniqueSection(fdOld, sections, newSectionId); - for (let p=0; p. -*/ - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(oldPtauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fdOld, sections); + const fdNew = await _iden3_binfileutils.createBinFile(newPTauFilename, "ptau", 1, 11); + await writePTauHeader(fdNew, curve, power); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 2); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + await processSection(2, 12, "G1", "tauG1"); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 13); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 14); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 15); + await fdOld.close(); + await fdNew.close(); + return; + async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { + if (logger) logger.debug("Starting section: " + sectionName); + await _iden3_binfileutils.startWriteSection(fdNew, newSectionId); + const size = sections[newSectionId][0].size; + const chunkSize = fdOld.pageSize; + await _iden3_binfileutils.startReadUniqueSection(fdOld, sections, newSectionId); + for (let p = 0; p < size; p += chunkSize) { + const l = Math.min(size - p, chunkSize); + const buff = await fdOld.read(l); + await fdNew.write(buff); + } + await _iden3_binfileutils.endReadSection(fdOld); + if (oldSectionId == 2) await processSectionPower(power + 1); + await _iden3_binfileutils.endWriteSection(fdNew); + async function processSectionPower(p) { + const nPoints = 2 ** p; + const G = curve[Gstr]; + const sGin = G.F.n8 * 2; + let buff; + buff = new ffjavascript.BigBuffer(nPoints * sGin); + await _iden3_binfileutils.startReadUniqueSection(fdOld, sections, oldSectionId); + if (oldSectionId == 2 && p == power + 1) { + await fdOld.readToBuffer(buff, 0, (nPoints - 1) * sGin); + buff.set(curve.G1.zeroAffine, (nPoints - 1) * sGin); + } else await fdOld.readToBuffer(buff, 0, nPoints * sGin); + await _iden3_binfileutils.endReadSection(fdOld, true); + buff = await G.lagrangeEvaluations(buff, "affine", "affine", logger, sectionName); + await fdNew.write(buff); + } + } +} +//#endregion +//#region src/powersoftau_export_json.js async function exportJson(pTauFilename, verbose) { - const {fd, sections} = await binFileUtils__namespace.readBinFile(pTauFilename, "ptau", 1); - - const {curve, power} = await readPTauHeader(fd, sections); - - const pTau = {}; - pTau.q = curve.q; - pTau.power = power; - pTau.contributions = await readContributions(fd, curve, sections); - - pTau.tauG1 = await exportSection(2, "G1", (2 ** power)*2 -1, "tauG1"); - pTau.tauG2 = await exportSection(3, "G2", (2 ** power), "tauG2"); - pTau.alphaTauG1 = await exportSection(4, "G1", (2 ** power), "alphaTauG1"); - pTau.betaTauG1 = await exportSection(5, "G1", (2 ** power), "betaTauG1"); - pTau.betaG2 = await exportSection(6, "G2", 1, "betaG2"); - - pTau.lTauG1 = await exportLagrange(12, "G1", "lTauG1"); - pTau.lTauG2 = await exportLagrange(13, "G2", "lTauG2"); - pTau.lAlphaTauG1 = await exportLagrange(14, "G1", "lAlphaTauG2"); - pTau.lBetaTauG1 = await exportLagrange(15, "G1", "lBetaTauG2"); - - await fd.close(); - - return stringifyBigIntsWithField(curve.Fr, pTau); - - - - async function exportSection(sectionId, groupName, nPoints, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - - const res = []; - await binFileUtils__namespace.startReadUniqueSection(fd, sections, sectionId); - for (let i=0; i< nPoints; i++) { - if ((verbose)&&i&&(i%10000 == 0)) console.log(`${sectionName}: ` + i); - const buff = await fd.read(sG); - res.push(G.fromRprLEM(buff, 0)); - } - await binFileUtils__namespace.endReadSection(fd); - - return res; - } - - async function exportLagrange(sectionId, groupName, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - - const res = []; - await binFileUtils__namespace.startReadUniqueSection(fd, sections, sectionId); - for (let p=0; p<=power; p++) { - if (verbose) console.log(`${sectionName}: Power: ${p}`); - res[p] = []; - const nPoints = (2 ** p); - for (let i=0; i. -*/ - -var powersoftau = /*#__PURE__*/Object.freeze({ - __proto__: null, - beacon: beacon$1, - challengeContribute: challengeContribute, - contribute: contribute, - convert: convert, - exportChallenge: exportChallenge, - exportJson: exportJson, - importResponse: importResponse, - newAccumulator: newAccumulator, - preparePhase2: preparePhase2, - truncate: truncate, - verify: verify + const { fd, sections } = await _iden3_binfileutils.readBinFile(pTauFilename, "ptau", 1); + const { curve, power } = await readPTauHeader(fd, sections); + const pTau = {}; + pTau.q = curve.q; + pTau.power = power; + pTau.contributions = await readContributions(fd, curve, sections); + pTau.tauG1 = await exportSection(2, "G1", 2 ** power * 2 - 1, "tauG1"); + pTau.tauG2 = await exportSection(3, "G2", 2 ** power, "tauG2"); + pTau.alphaTauG1 = await exportSection(4, "G1", 2 ** power, "alphaTauG1"); + pTau.betaTauG1 = await exportSection(5, "G1", 2 ** power, "betaTauG1"); + pTau.betaG2 = await exportSection(6, "G2", 1, "betaG2"); + pTau.lTauG1 = await exportLagrange(12, "G1", "lTauG1"); + pTau.lTauG2 = await exportLagrange(13, "G2", "lTauG2"); + pTau.lAlphaTauG1 = await exportLagrange(14, "G1", "lAlphaTauG2"); + pTau.lBetaTauG1 = await exportLagrange(15, "G1", "lBetaTauG2"); + await fd.close(); + return stringifyBigIntsWithField(curve.Fr, pTau); + async function exportSection(sectionId, groupName, nPoints, sectionName) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const res = []; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, sectionId); + for (let i = 0; i < nPoints; i++) { + if (verbose && i && i % 1e4 == 0) console.log(`${sectionName}: ` + i); + const buff = await fd.read(sG); + res.push(G.fromRprLEM(buff, 0)); + } + await _iden3_binfileutils.endReadSection(fd); + return res; + } + async function exportLagrange(sectionId, groupName, sectionName) { + const G = curve[groupName]; + const sG = G.F.n8 * 2; + const res = []; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, sectionId); + for (let p = 0; p <= power; p++) { + if (verbose) console.log(`${sectionName}: Power: ${p}`); + res[p] = []; + const nPoints = 2 ** p; + for (let i = 0; i < nPoints; i++) { + if (verbose && i && i % 1e4 == 0) console.log(`${sectionName}: ${i}/${nPoints}`); + const buff = await fd.read(sG); + res[p].push(G.fromRprLEM(buff, 0)); + } + } + await _iden3_binfileutils.endReadSection(fd, true); + return res; + } +} +//#endregion +//#region src/powersoftau.js +var powersoftau_exports = /* @__PURE__ */ __exportAll({ + beacon: () => beacon$1, + challengeContribute: () => challengeContribute, + contribute: () => contribute, + convert: () => convert, + exportChallenge: () => exportChallenge, + exportJson: () => exportJson, + importResponse: () => importResponse, + newAccumulator: () => newAccumulator, + preparePhase2: () => preparePhase2, + truncate: () => truncate, + verify: () => verify }); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - +//#endregion +//#region src/r1cs_print.js function r1csPrint(r1cs, syms, logger) { - for (let i=0; i { - let S = ""; - const keys = Object.keys(lc); - keys.forEach( (k) => { - let name = syms.varIdx2Name[k]; - if (name == "one") name = "1"; - - let vs = r1cs.curve.Fr.toString(lc[k]); - if (vs == "1") vs = ""; // Do not show ones - if (vs == "-1") vs = "-"; // Do not show ones - if ((S!="")&&(vs[0]!="-")) vs = "+"+vs; - if (S!="") vs = " "+vs; - S= S + vs + name; - }); - return S; - }; - const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`; - if (logger) logger.info(S); - } - -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const bls12381r = ffjavascript.Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); -const bn128r = ffjavascript.Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - + for (let i = 0; i < r1cs.constraints.length; i++) printCostraint(r1cs.constraints[i]); + function printCostraint(c) { + const lc2str = (lc) => { + let S = ""; + Object.keys(lc).forEach((k) => { + let name = syms.varIdx2Name[k]; + if (name == "one") name = "1"; + let vs = r1cs.curve.Fr.toString(lc[k]); + if (vs == "1") vs = ""; + if (vs == "-1") vs = "-"; + if (S != "" && vs[0] != "-") vs = "+" + vs; + if (S != "") vs = " " + vs; + S = S + vs + name; + }); + return S; + }; + const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`; + if (logger) logger.info(S); + } +} +//#endregion +//#region src/r1cs_info.js +var bls12381r = ffjavascript.Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); +var bn128r = ffjavascript.Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); async function r1csInfo(r1csName, logger) { - - // Only the header (section 1) is needed for these counts; loading the - // constraints + wire-to-label map would read the whole (potentially many-GB) - // file for nothing. - const cir = await r1csfile.readR1cs(r1csName, {loadConstraints: false, loadMap: false}); - - if (ffjavascript.Scalar.eq(cir.prime, bn128r)) { - if (logger) logger.info("Curve: bn-128"); - } else if (ffjavascript.Scalar.eq(cir.prime, bls12381r)) { - if (logger) logger.info("Curve: bls12-381"); - } else { - if (logger) logger.info(`Unknown Curve. Prime: ${ffjavascript.Scalar.toString(cir.prime)}`); - } - if (logger) logger.info(`# of Wires: ${cir.nVars}`); - if (logger) logger.info(`# of Constraints: ${cir.nConstraints}`); - if (logger) logger.info(`# of Private Inputs: ${cir.nPrvInputs}`); - if (logger) logger.info(`# of Public Inputs: ${cir.nPubInputs}`); - if (logger) logger.info(`# of Labels: ${cir.nLabels}`); - if (logger) logger.info(`# of Outputs: ${cir.nOutputs}`); - - return cir; -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - - + const cir = await (0, r1csfile.readR1cs)(r1csName, { + loadConstraints: false, + loadMap: false + }); + if (ffjavascript.Scalar.eq(cir.prime, bn128r)) { + if (logger) logger.info("Curve: bn-128"); + } else if (ffjavascript.Scalar.eq(cir.prime, bls12381r)) { + if (logger) logger.info("Curve: bls12-381"); + } else if (logger) logger.info(`Unknown Curve. Prime: ${ffjavascript.Scalar.toString(cir.prime)}`); + if (logger) logger.info(`# of Wires: ${cir.nVars}`); + if (logger) logger.info(`# of Constraints: ${cir.nConstraints}`); + if (logger) logger.info(`# of Private Inputs: ${cir.nPrvInputs}`); + if (logger) logger.info(`# of Public Inputs: ${cir.nPubInputs}`); + if (logger) logger.info(`# of Labels: ${cir.nLabels}`); + if (logger) logger.info(`# of Outputs: ${cir.nOutputs}`); + return cir; +} +//#endregion +//#region src/r1cs_export_json.js async function r1csExportJson(r1csFileName, logger) { - - const cir = await r1csfile.readR1cs(r1csFileName, true, true, true, logger); - const Fr=cir.curve.Fr; - delete cir.curve; - delete cir.F; - - return stringifyBigIntsWithField(Fr, cir); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -var r1cs = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportJson: r1csExportJson, - info: r1csInfo, - print: r1csPrint + const cir = await (0, r1csfile.readR1cs)(r1csFileName, true, true, true, logger); + const Fr = cir.curve.Fr; + delete cir.curve; + delete cir.F; + return stringifyBigIntsWithField(Fr, cir); +} +//#endregion +//#region src/r1cs.js +var r1cs_exports = /* @__PURE__ */ __exportAll({ + exportJson: () => r1csExportJson, + info: () => r1csInfo, + print: () => r1csPrint }); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - +//#endregion +//#region src/loadsyms.js async function loadSymbols(symFileName) { - const sym = { - labelIdx2Name: [ "one" ], - varIdx2Name: [ "one" ], - componentIdx2Name: [] - }; - const fd = await fastFile__namespace.readExisting(symFileName); - const buff = await fd.read(fd.totalSize); - const symsStr = new TextDecoder("utf-8").decode(buff); - const lines = symsStr.split("\n"); - for (let i=0; i. -*/ - -const {unstringifyBigInts: unstringifyBigInts$7} = ffjavascript.utils; - - + const sym = { + labelIdx2Name: ["one"], + varIdx2Name: ["one"], + componentIdx2Name: [] + }; + const fd = await fastfile.readExisting(symFileName); + const buff = await fd.read(fd.totalSize); + const lines = new TextDecoder("utf-8").decode(buff).split("\n"); + for (let i = 0; i < lines.length; i++) { + const arr = lines[i].split(","); + if (arr.length != 4) continue; + if (sym.varIdx2Name[arr[1]]) sym.varIdx2Name[arr[1]] += "|" + arr[3]; + else sym.varIdx2Name[arr[1]] = arr[3]; + sym.labelIdx2Name[arr[0]] = arr[3]; + if (!sym.componentIdx2Name[arr[2]]) sym.componentIdx2Name[arr[2]] = extractComponent(arr[3]); + } + await fd.close(); + return sym; + function extractComponent(name) { + const arr = name.split("."); + arr.pop(); + return arr.join("."); + } +} +//#endregion +//#region src/wtns_debug.js +var { unstringifyBigInts: unstringifyBigInts$7 } = ffjavascript.utils; async function wtnsDebug(_input, wasmFileName, wtnsFileName, symName, options, logger) { - - const input = unstringifyBigInts$7(_input); - - const fdWasm = await fastFile__namespace.readExisting(wasmFileName); - const wasm = await fdWasm.read(fdWasm.totalSize); - await fdWasm.close(); - - const wcOps = {...options, sanityCheck: true}; - let sym = await loadSymbols(symName); - if (options.set) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logSetSignal= function(labelIdx, value) { - // The line below splits the arrow log into 2 strings to avoid some Secure ECMAScript issues - if (logger) logger.info("SET " + sym.labelIdx2Name[labelIdx] + " <" + "-- " + value.toString()); - }; - } - if (options.get) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logGetSignal= function(varIdx, value) { - // The line below splits the arrow log into 2 strings to avoid some Secure ECMAScript issues - if (logger) logger.info("GET " + sym.labelIdx2Name[varIdx] + " --" + "> " + value.toString()); - }; - } - if (options.trigger) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logStartComponent= function(cIdx) { - if (logger) logger.info("START: " + sym.componentIdx2Name[cIdx]); - }; - wcOps.logFinishComponent= function(cIdx) { - if (logger) logger.info("FINISH: " + sym.componentIdx2Name[cIdx]); - }; - } - wcOps.sym = sym; - - const wc = await circom_runtime.WitnessCalculatorBuilder(wasm, wcOps); - const w = await wc.calculateWitness(input, true); - - const fdWtns = await binFileUtils__namespace.createBinFile(wtnsFileName, "wtns", 2, 2); - - await write(fdWtns, w, wc.prime); - - await fdWtns.close(); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const input = unstringifyBigInts$7(_input); + const fdWasm = await fastfile.readExisting(wasmFileName); + const wasm = await fdWasm.read(fdWasm.totalSize); + await fdWasm.close(); + const wcOps = { + ...options, + sanityCheck: true + }; + let sym = await loadSymbols(symName); + if (options.set) { + if (!sym) sym = await loadSymbols(symName); + wcOps.logSetSignal = function(labelIdx, value) { + if (logger) logger.info("SET " + sym.labelIdx2Name[labelIdx] + " <-- " + value.toString()); + }; + } + if (options.get) { + if (!sym) sym = await loadSymbols(symName); + wcOps.logGetSignal = function(varIdx, value) { + if (logger) logger.info("GET " + sym.labelIdx2Name[varIdx] + " --> " + value.toString()); + }; + } + if (options.trigger) { + if (!sym) sym = await loadSymbols(symName); + wcOps.logStartComponent = function(cIdx) { + if (logger) logger.info("START: " + sym.componentIdx2Name[cIdx]); + }; + wcOps.logFinishComponent = function(cIdx) { + if (logger) logger.info("FINISH: " + sym.componentIdx2Name[cIdx]); + }; + } + wcOps.sym = sym; + const wc = await (0, circom_runtime.WitnessCalculatorBuilder)(wasm, wcOps); + const w = await wc.calculateWitness(input, true); + const fdWtns = await _iden3_binfileutils.createBinFile(wtnsFileName, "wtns", 2, 2); + await write(fdWtns, w, wc.prime); + await fdWtns.close(); +} +//#endregion +//#region src/wtns_export_json.js async function wtnsExportJson(wtnsFileName) { - - const w = await read(wtnsFileName); - - return w; -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + return await read(wtnsFileName); +} +//#endregion +//#region src/wtns_check.js async function wtnsCheck(r1csFilename, wtnsFilename, logger) { - - if (logger) logger.info("WITNESS CHECKING STARTED"); - - // Read r1cs file - if (logger) logger.info("> Reading r1cs file"); - const { - fd: fdR1cs, - sections: sectionsR1cs - } = await binFileUtils__namespace.readBinFile(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); - const r1cs = await r1csfile.readR1csFd(fdR1cs, sectionsR1cs, { loadConstraints: false, loadCustomGates: false }); - - // Read witness file - if (logger) logger.info("> Reading witness file"); - const { - fd: fdWtns, - sections: wtnsSections - } = await binFileUtils__namespace.readBinFile(wtnsFilename, "wtns", 2, 1 << 22, 1 << 24); - const wtnsHeader = await readHeader(fdWtns, wtnsSections); - - if (!ffjavascript.Scalar.eq(r1cs.prime, wtnsHeader.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - const buffWitness = await binFileUtils__namespace.readSection(fdWtns, wtnsSections, 2); - await fdWtns.close(); - - const curve = await getCurveFromR(r1cs.prime); - const Fr = curve.Fr; - const sFr = Fr.n8; - - const bR1cs = await binFileUtils__namespace.readSection(fdR1cs, sectionsR1cs, 2); - - if (logger) { - logger.info("----------------------------"); - logger.info(" WITNESS CHECK"); - logger.info(` Curve: ${r1cs.curve.name}`); - logger.info(` Vars (wires): ${r1cs.nVars}`); - logger.info(` Outputs: ${r1cs.nOutputs}`); - logger.info(` Public Inputs: ${r1cs.nPubInputs}`); - logger.info(` Private Inputs: ${r1cs.nPrvInputs}`); - logger.info(` Labels: ${r1cs.nLabels}`); - logger.info(` Constraints: ${r1cs.nConstraints}`); - logger.info(` Custom Gates: ${r1cs.useCustomGates}`); - logger.info("----------------------------"); - } - - if (logger) logger.info("> Checking witness correctness"); - - let bR1csPos = 0; - let res = true; - for (let i = 0; i < r1cs.nConstraints; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(`··· processing r1cs constraints ${i}/${r1cs.nConstraints}`); - } - - //Read the three linear combinations of the constraint where A * B - C = 0 - const lcA = readLC(); - const lcB = readLC(); - const lcC = readLC(); - - // Evaluate the linear combinations - const evalA = EvaluateLinearCombination(lcA); - const evalB = EvaluateLinearCombination(lcB); - const evalC = EvaluateLinearCombination(lcC); - - // Check that A * B - C == 0 - if (!Fr.eq(Fr.sub(Fr.mul(evalA, evalB), evalC), Fr.zero)) { - logger.warn("··· aborting checking process at constraint " + i); - res = false; - break; - } - } - - fdR1cs.close(); - - if (logger) { - if (res) { - logger.info("WITNESS IS CORRECT"); - logger.info("WITNESS CHECKING FINISHED SUCCESSFULLY"); - } else { - logger.warn("WITNESS IS NOT CORRECT"); - logger.warn("WITNESS CHECKING FINISHED UNSUCCESSFULLY"); - } - } - - return res; - - function EvaluateLinearCombination(lc) { - let res = Fr.zero; - - const keys = Object.keys(lc); - keys.forEach((signalId) => { - const signalValue = getWitnessValue(signalId); - const signalFactor = lc[signalId]; - - res = Fr.add(res, Fr.mul(signalValue, signalFactor)); - }); - - return res; - } - - function readLC() { - const lc = {}; - - const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); - bR1csPos += 4; - const buffUL32V = new DataView(buffUL32.buffer); - const nIdx = buffUL32V.getUint32(0, true); - - const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); - bR1csPos += (4 + r1cs.n8) * nIdx; - const buffV = new DataView(buff.buffer); - for (let i = 0; i < nIdx; i++) { - const idx = buffV.getUint32(i * (4 + r1cs.n8), true); - const val = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); - lc[idx] = val; - } - return lc; - } - - function getWitnessValue(signalId) { - return Fr.fromRprLE(buffWitness.slice(signalId * sFr, signalId * sFr + sFr)); - } -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -var wtns = /*#__PURE__*/Object.freeze({ - __proto__: null, - calculate: wtnsCalculate, - check: wtnsCheck, - debug: wtnsDebug, - exportJson: wtnsExportJson + if (logger) logger.info("WITNESS CHECKING STARTED"); + if (logger) logger.info("> Reading r1cs file"); + const { fd: fdR1cs, sections: sectionsR1cs } = await _iden3_binfileutils.readBinFile(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); + const r1cs = await (0, r1csfile.readR1csFd)(fdR1cs, sectionsR1cs, { + loadConstraints: false, + loadCustomGates: false + }); + if (logger) logger.info("> Reading witness file"); + const { fd: fdWtns, sections: wtnsSections } = await _iden3_binfileutils.readBinFile(wtnsFilename, "wtns", 2, 1 << 22, 1 << 24); + const wtnsHeader = await readHeader(fdWtns, wtnsSections); + if (!ffjavascript.Scalar.eq(r1cs.prime, wtnsHeader.q)) throw new Error("Curve of the witness does not match the curve of the proving key"); + const buffWitness = await _iden3_binfileutils.readSection(fdWtns, wtnsSections, 2); + await fdWtns.close(); + const Fr = (await getCurveFromR(r1cs.prime)).Fr; + const sFr = Fr.n8; + const bR1cs = await _iden3_binfileutils.readSection(fdR1cs, sectionsR1cs, 2); + if (logger) { + logger.info("----------------------------"); + logger.info(" WITNESS CHECK"); + logger.info(` Curve: ${r1cs.curve.name}`); + logger.info(` Vars (wires): ${r1cs.nVars}`); + logger.info(` Outputs: ${r1cs.nOutputs}`); + logger.info(` Public Inputs: ${r1cs.nPubInputs}`); + logger.info(` Private Inputs: ${r1cs.nPrvInputs}`); + logger.info(` Labels: ${r1cs.nLabels}`); + logger.info(` Constraints: ${r1cs.nConstraints}`); + logger.info(` Custom Gates: ${r1cs.useCustomGates}`); + logger.info("----------------------------"); + } + if (logger) logger.info("> Checking witness correctness"); + let bR1csPos = 0; + let res = true; + for (let i = 0; i < r1cs.nConstraints; i++) { + if (logger && i !== 0 && i % 5e5 === 0) logger.info(`··· processing r1cs constraints ${i}/${r1cs.nConstraints}`); + const lcA = readLC(); + const lcB = readLC(); + const lcC = readLC(); + const evalA = EvaluateLinearCombination(lcA); + const evalB = EvaluateLinearCombination(lcB); + const evalC = EvaluateLinearCombination(lcC); + if (!Fr.eq(Fr.sub(Fr.mul(evalA, evalB), evalC), Fr.zero)) { + logger.warn("··· aborting checking process at constraint " + i); + res = false; + break; + } + } + fdR1cs.close(); + if (logger) if (res) { + logger.info("WITNESS IS CORRECT"); + logger.info("WITNESS CHECKING FINISHED SUCCESSFULLY"); + } else { + logger.warn("WITNESS IS NOT CORRECT"); + logger.warn("WITNESS CHECKING FINISHED UNSUCCESSFULLY"); + } + return res; + function EvaluateLinearCombination(lc) { + let res = Fr.zero; + Object.keys(lc).forEach((signalId) => { + const signalValue = getWitnessValue(signalId); + const signalFactor = lc[signalId]; + res = Fr.add(res, Fr.mul(signalValue, signalFactor)); + }); + return res; + } + function readLC() { + const lc = {}; + const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); + bR1csPos += 4; + const nIdx = new DataView(buffUL32.buffer).getUint32(0, true); + const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); + bR1csPos += (4 + r1cs.n8) * nIdx; + const buffV = new DataView(buff.buffer); + for (let i = 0; i < nIdx; i++) { + const idx = buffV.getUint32(i * (4 + r1cs.n8), true); + lc[idx] = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); + } + return lc; + } + function getWitnessValue(signalId) { + return Fr.fromRprLE(buffWitness.slice(signalId * sFr, signalId * sFr + sFr)); + } +} +//#endregion +//#region src/wtns.js +var wtns_exports = /* @__PURE__ */ __exportAll({ + calculate: () => wtnsCalculate, + check: () => wtnsCheck, + debug: () => wtnsDebug, + exportJson: () => wtnsExportJson }); - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -const SUBARRAY_SIZE = 0x40000; - -const BigArrayHandler = { - get: function(obj, prop) { - if (!isNaN(prop)) { - return obj.getElement(prop); - } else return obj[prop]; - }, - set: function(obj, prop, value) { - if (!isNaN(prop)) { - return obj.setElement(prop, value); - } else { - obj[prop] = value; - return true; - } - } +//#endregion +//#region src/bigarray.js +var SUBARRAY_SIZE = 262144; +var BigArrayHandler = { + get: function(obj, prop) { + if (!isNaN(prop)) return obj.getElement(prop); + else return obj[prop]; + }, + set: function(obj, prop, value) { + if (!isNaN(prop)) return obj.setElement(prop, value); + else { + obj[prop] = value; + return true; + } + } }; - -class _BigArray { - constructor (initSize) { - this.length = initSize || 0; - this.arr = new Array(SUBARRAY_SIZE); - - for (let i=0; i= this.length) this.length = idx+1; - return true; - } - getKeys() { - const newA = new BigArray(); - for (let i=0; i. -*/ - - +var _BigArray = class { + constructor(initSize) { + this.length = initSize || 0; + this.arr = new Array(SUBARRAY_SIZE); + for (let i = 0; i < initSize; i += SUBARRAY_SIZE) this.arr[i / SUBARRAY_SIZE] = new Array(Math.min(SUBARRAY_SIZE, initSize - i)); + return this; + } + push() { + for (let i = 0; i < arguments.length; i++) this.setElement(this.length, arguments[i]); + } + slice(f, t) { + const arr = new Array(t - f); + for (let i = f; i < t; i++) arr[i - f] = this.getElement(i); + return arr; + } + getElement(idx) { + idx = parseInt(idx); + const idx1 = Math.floor(idx / SUBARRAY_SIZE); + const idx2 = idx % SUBARRAY_SIZE; + return this.arr[idx1] ? this.arr[idx1][idx2] : void 0; + } + setElement(idx, value) { + idx = parseInt(idx); + const idx1 = Math.floor(idx / SUBARRAY_SIZE); + if (!this.arr[idx1]) this.arr[idx1] = new Array(SUBARRAY_SIZE); + const idx2 = idx % SUBARRAY_SIZE; + this.arr[idx1][idx2] = value; + if (idx >= this.length) this.length = idx + 1; + return true; + } + getKeys() { + const newA = new BigArray(); + for (let i = 0; i < this.arr.length; i++) if (this.arr[i]) { + for (let j = 0; j < this.arr[i].length; j++) if (typeof this.arr[i][j] !== "undefined") newA.push(i * SUBARRAY_SIZE + j); + } + return newA; + } +}; +var BigArray = class { + constructor(initSize) { + const obj = new _BigArray(initSize); + return new Proxy(obj, BigArrayHandler); + } +}; +//#endregion +//#region src/zkey_new.js async function newZKey(r1csName, ptauName, zkeyName, logger) { - - const TAU_G1 = 0; - const TAU_G2 = 1; - const ALPHATAU_G1 = 2; - const BETATAU_G1 = 3; - const csHasher = blake2_js.blake2b.create({ dkLen: 64 }); - - const {fd: fdPTau, sections: sectionsPTau} = await binFileUtils.readBinFile(ptauName, "ptau", 1, 1<<22, 1<<24); - const {curve, power} = await readPTauHeader(fdPTau, sectionsPTau); - const {fd: fdR1cs, sections: sectionsR1cs} = await binFileUtils.readBinFile(r1csName, "r1cs", 1, 1<<22, 1<<24); - const r1cs = await r1csfile.readR1csHeader(fdR1cs, sectionsR1cs, false); - - const fdZKey = await binFileUtils.createBinFile(zkeyName, "zkey", 1, 10, 1<<22, 1<<24); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - if (r1cs.prime != curve.r) { - if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); - return -1; - } - - const cirPower = log2(r1cs.nConstraints + r1cs.nPubInputs + r1cs.nOutputs +1 -1) +1; - - if (cirPower > power) { - if (logger) logger.error(`circuit too big for this power of tau ceremony. ${r1cs.nConstraints}*2 > 2**${power}`); - return -1; - } - - if (!sectionsPTau[12]) { - if (logger) logger.error("Powers of tau is not prepared."); - return -1; - } - - const nPublic = r1cs.nOutputs + r1cs.nPubInputs; - const domainSize = 2 ** cirPower; - - // Write the header - /////////// - await binFileUtils.startWriteSection(fdZKey, 1); - await fdZKey.writeULE32(1); // Groth - await binFileUtils.endWriteSection(fdZKey); - - // Write the Groth header section - /////////// - - await binFileUtils.startWriteSection(fdZKey, 2); - const primeQ = curve.q; - const n8q = (Math.floor( (ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) +1)*8; - - const primeR = curve.r; - const n8r = (Math.floor( (ffjavascript.Scalar.bitLength(primeR) - 1) / 64) +1)*8; - const Rr = ffjavascript.Scalar.mod(ffjavascript.Scalar.shl(1, n8r*8), primeR); - const R2r = curve.Fr.e(ffjavascript.Scalar.mod(ffjavascript.Scalar.mul(Rr,Rr), primeR)); - - await fdZKey.writeULE32(n8q); - await binFileUtils.writeBigInt(fdZKey, primeQ, n8q); - await fdZKey.writeULE32(n8r); - await binFileUtils.writeBigInt(fdZKey, primeR, n8r); - await fdZKey.writeULE32(r1cs.nVars); // Total number of bars - await fdZKey.writeULE32(nPublic); // Total number of public vars (not including ONE) - await fdZKey.writeULE32(domainSize); // domainSize - - let bAlpha1; - bAlpha1 = await fdPTau.read(sG1, sectionsPTau[4][0].p); - await fdZKey.write(bAlpha1); - bAlpha1 = await curve.G1.batchLEMtoU(bAlpha1); - csHasher.update(bAlpha1); - - let bBeta1; - bBeta1 = await fdPTau.read(sG1, sectionsPTau[5][0].p); - await fdZKey.write(bBeta1); - bBeta1 = await curve.G1.batchLEMtoU(bBeta1); - csHasher.update(bBeta1); - - let bBeta2; - bBeta2 = await fdPTau.read(sG2, sectionsPTau[6][0].p); - await fdZKey.write(bBeta2); - bBeta2 = await curve.G2.batchLEMtoU(bBeta2); - csHasher.update(bBeta2); - - const bg1 = new Uint8Array(sG1); - curve.G1.toRprLEM(bg1, 0, curve.G1.g); - const bg2 = new Uint8Array(sG2); - curve.G2.toRprLEM(bg2, 0, curve.G2.g); - const bg1U = new Uint8Array(sG1); - curve.G1.toRprUncompressed(bg1U, 0, curve.G1.g); - const bg2U = new Uint8Array(sG2); - curve.G2.toRprUncompressed(bg2U, 0, curve.G2.g); - - await fdZKey.write(bg2); // gamma2 - await fdZKey.write(bg1); // delta1 - await fdZKey.write(bg2); // delta2 - csHasher.update(bg2U); // gamma2 - csHasher.update(bg1U); // delta1 - csHasher.update(bg2U); // delta2 - await binFileUtils.endWriteSection(fdZKey); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Reading r1cs"); - let sR1cs = await binFileUtils.readSection(fdR1cs, sectionsR1cs, 2); - await fdR1cs.close(); - - let A = new BigArray(r1cs.nVars); - let B1 = new BigArray(r1cs.nVars); - let B2 = new BigArray(r1cs.nVars); - let C = new BigArray(r1cs.nVars- nPublic -1); - let IC = new Array(nPublic+1); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Reading tauG1"); - let sTauG1 = await binFileUtils.readSection(fdPTau, sectionsPTau, 12, (domainSize -1)*sG1, domainSize*sG1); - if (logger) logger.info("Reading tauG2"); - let sTauG2 = await binFileUtils.readSection(fdPTau, sectionsPTau, 13, (domainSize -1)*sG2, domainSize*sG2); - if (logger) logger.info("Reading alphatauG1"); - let sAlphaTauG1 = await binFileUtils.readSection(fdPTau, sectionsPTau, 14, (domainSize -1)*sG1, domainSize*sG1); - if (logger) logger.info("Reading betatauG1"); - let sBetaTauG1 = await binFileUtils.readSection(fdPTau, sectionsPTau, 15, (domainSize -1)*sG1, domainSize*sG1); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("processConstraints"); - await processConstraints(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints"); - await composeAndWritePoints(3, "G1", IC, "IC"); - - IC = null; - // const gc = runInNewContext("gc"); // nocommit - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("writeHs"); - await writeHs(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("hashHPoints"); - await hashHPoints(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 8 G1 C"); - await composeAndWritePoints(8, "G1", C, "C"); - - C = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 5 G1 A"); - await composeAndWritePoints(5, "G1", A, "A"); - - A = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 6 G1 B1"); - await composeAndWritePoints(6, "G1", B1, "B1"); - - B1 = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 7 G2 B2"); - await composeAndWritePoints(7, "G2", B2, "B2"); - - B2 = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Contributions section"); - const csHash = csHasher.digest(); - // Contributions section - await binFileUtils.startWriteSection(fdZKey, 10); - await fdZKey.write(csHash); - await fdZKey.writeULE32(0); - await binFileUtils.endWriteSection(fdZKey); - - if (logger) logger.info(formatHash(csHash, "Circuit hash: ")); - - - await fdZKey.close(); - await fdPTau.close(); - - return csHash; - - async function writeHs() { - await binFileUtils.startWriteSection(fdZKey, 9); - const buffOut = new ffjavascript.BigBuffer(domainSize*sG1); - if (cirPower < curve.Fr.s) { - let sTauG1 = await binFileUtils.readSection(fdPTau, sectionsPTau, 12, (domainSize*2-1)*sG1, domainSize*2*sG1); - for (let i=0; i< domainSize; i++) { - if ((logger)&&(i%10000 == 0)) logger.debug(`splitting buffer: ${i}/${domainSize}`); - const buff = sTauG1.slice( (i*2+1)*sG1, (i*2+1)*sG1 + sG1 ); - buffOut.set(buff, i*sG1); - } - } else if (cirPower == curve.Fr.s) { - const o = sectionsPTau[12][0].p + ((2 ** (cirPower+1)) -1)*sG1; - await fdPTau.readToBuffer(buffOut, 0, domainSize*sG1, o + domainSize*sG1); - } else { - if (logger) logger.error("Circuit too big"); - throw new Error("Circuit too big for this curve"); - } - await fdZKey.write(buffOut); - await binFileUtils.endWriteSection(fdZKey); - } - - async function processConstraints() { - const buffCoeff = new Uint8Array(12 + curve.Fr.n8); - const buffCoeffV = new DataView(buffCoeff.buffer); - const bOne = new Uint8Array(curve.Fr.n8); - curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); - - let r1csPos = 0; - - function r1cs_readULE32() { - const buff = sR1cs.slice(r1csPos, r1csPos+4); - r1csPos += 4; - const buffV = new DataView(buff.buffer); - return buffV.getUint32(0, true); - } - - const coefs = new BigArray(); - for (let c=0; c=0) { - n = curve.Fr.fromRprLE(sR1cs.slice(c[3], c[3] + curve.Fr.n8), 0); - } else { - n = curve.Fr.fromRprLE(bOne, 0); - } - const nR2 = curve.Fr.mul(n, R2r); - curve.Fr.toRprLE(buffCoeff, 12, nR2); - buffSection.set(buffCoeff, coefsPos); - coefsPos += buffCoeff.length; - } - - } - - async function composeAndWritePoints(idSection, groupName, arr, sectionName) { - const CHUNK_SIZE= 1<<15; - const G = curve[groupName]; - - hashU32(arr.length); - await binFileUtils.startWriteSection(fdZKey, idSection); - - let opPromises = []; - - let i=0; - while (i { - if (logger) logger.debug(`Writing points end ${sectionName}: ${_i}/${arr.length}`); - return r; - })); - i += n; - t++; - } - - const result = await Promise.all(opPromises); - - for (let k=0; k 2<<14) { - bBases = new ffjavascript.BigBuffer(acc*sGin); - bScalars = new ffjavascript.BigBuffer(acc*curve.Fr.n8); - } else { - bBases = new Uint8Array(acc*sGin); - bScalars = new Uint8Array(acc*curve.Fr.n8); - } - let pB =0; - let pS =0; - - const sBuffs = [ - sTauG1, - sTauG2, - sAlphaTauG1, - sBetaTauG1 - ]; - - const bOne = new Uint8Array(curve.Fr.n8); - curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); - - let offset = 0; - for (let i=0; i=0) { - bScalars.set( - sR1cs.slice( - arr[i][j][2], - arr[i][j][2] + curve.Fr.n8 - ), - offset*curve.Fr.n8 - ); - } else { - bScalars.set(bOne, offset*curve.Fr.n8); - } - offset ++; - } - } - - if (arr.length>1) { - const task = []; - task.push({cmd: "ALLOCSET", var: 0, buff: bBases}); - task.push({cmd: "ALLOCSET", var: 1, buff: bScalars}); - task.push({cmd: "ALLOC", var: 2, len: arr.length*sGmid}); - pB = 0; - pS = 0; - let pD =0; - for (let i=0; i power) { + if (logger) logger.error(`circuit too big for this power of tau ceremony. ${r1cs.nConstraints}*2 > 2**${power}`); + return -1; + } + if (!sectionsPTau[12]) { + if (logger) logger.error("Powers of tau is not prepared."); + return -1; + } + const nPublic = r1cs.nOutputs + r1cs.nPubInputs; + const domainSize = 2 ** cirPower; + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 1); + await fdZKey.writeULE32(1); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 2); + const primeQ = curve.q; + const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; + const primeR = curve.r; + const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; + const Rr = ffjavascript.Scalar.mod(ffjavascript.Scalar.shl(1, n8r * 8), primeR); + const R2r = curve.Fr.e(ffjavascript.Scalar.mod(ffjavascript.Scalar.mul(Rr, Rr), primeR)); + await fdZKey.writeULE32(n8q); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeQ, n8q); + await fdZKey.writeULE32(n8r); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeR, n8r); + await fdZKey.writeULE32(r1cs.nVars); + await fdZKey.writeULE32(nPublic); + await fdZKey.writeULE32(domainSize); + let bAlpha1; + bAlpha1 = await fdPTau.read(sG1, sectionsPTau[4][0].p); + await fdZKey.write(bAlpha1); + bAlpha1 = await curve.G1.batchLEMtoU(bAlpha1); + csHasher.update(bAlpha1); + let bBeta1; + bBeta1 = await fdPTau.read(sG1, sectionsPTau[5][0].p); + await fdZKey.write(bBeta1); + bBeta1 = await curve.G1.batchLEMtoU(bBeta1); + csHasher.update(bBeta1); + let bBeta2; + bBeta2 = await fdPTau.read(sG2, sectionsPTau[6][0].p); + await fdZKey.write(bBeta2); + bBeta2 = await curve.G2.batchLEMtoU(bBeta2); + csHasher.update(bBeta2); + const bg1 = new Uint8Array(sG1); + curve.G1.toRprLEM(bg1, 0, curve.G1.g); + const bg2 = new Uint8Array(sG2); + curve.G2.toRprLEM(bg2, 0, curve.G2.g); + const bg1U = new Uint8Array(sG1); + curve.G1.toRprUncompressed(bg1U, 0, curve.G1.g); + const bg2U = new Uint8Array(sG2); + curve.G2.toRprUncompressed(bg2U, 0, curve.G2.g); + await fdZKey.write(bg2); + await fdZKey.write(bg1); + await fdZKey.write(bg2); + csHasher.update(bg2U); + csHasher.update(bg1U); + csHasher.update(bg2U); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + if (logger) logger.info(memUsage()); + if (logger) logger.info("Reading r1cs"); + let sR1cs = await (0, _iden3_binfileutils.readSection)(fdR1cs, sectionsR1cs, 2); + await fdR1cs.close(); + let A = new BigArray(r1cs.nVars); + let B1 = new BigArray(r1cs.nVars); + let B2 = new BigArray(r1cs.nVars); + let C = new BigArray(r1cs.nVars - nPublic - 1); + let IC = new Array(nPublic + 1); + if (logger) logger.info(memUsage()); + if (logger) logger.info("Reading tauG1"); + let sTauG1 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 12, (domainSize - 1) * sG1, domainSize * sG1); + if (logger) logger.info("Reading tauG2"); + let sTauG2 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 13, (domainSize - 1) * sG2, domainSize * sG2); + if (logger) logger.info("Reading alphatauG1"); + let sAlphaTauG1 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 14, (domainSize - 1) * sG1, domainSize * sG1); + if (logger) logger.info("Reading betatauG1"); + let sBetaTauG1 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 15, (domainSize - 1) * sG1, domainSize * sG1); + if (logger) logger.info(memUsage()); + if (logger) logger.info("processConstraints"); + await processConstraints(); + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints"); + await composeAndWritePoints(3, "G1", IC, "IC"); + IC = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("writeHs"); + await writeHs(); + if (logger) logger.info(memUsage()); + if (logger) logger.info("hashHPoints"); + await hashHPoints(); + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints 8 G1 C"); + await composeAndWritePoints(8, "G1", C, "C"); + C = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints 5 G1 A"); + await composeAndWritePoints(5, "G1", A, "A"); + A = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints 6 G1 B1"); + await composeAndWritePoints(6, "G1", B1, "B1"); + B1 = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("composeAndWritePoints 7 G2 B2"); + await composeAndWritePoints(7, "G2", B2, "B2"); + B2 = null; + if (logger) logger.info(memUsage()); + if (logger) logger.info("Contributions section"); + const csHash = csHasher.digest(); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 10); + await fdZKey.write(csHash); + await fdZKey.writeULE32(0); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + if (logger) logger.info(formatHash(csHash, "Circuit hash: ")); + await fdZKey.close(); + await fdPTau.close(); + return csHash; + async function writeHs() { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 9); + const buffOut = new ffjavascript.BigBuffer(domainSize * sG1); + if (cirPower < curve.Fr.s) { + let sTauG1 = await (0, _iden3_binfileutils.readSection)(fdPTau, sectionsPTau, 12, (domainSize * 2 - 1) * sG1, domainSize * 2 * sG1); + for (let i = 0; i < domainSize; i++) { + if (logger && i % 1e4 == 0) logger.debug(`splitting buffer: ${i}/${domainSize}`); + const buff = sTauG1.slice((i * 2 + 1) * sG1, (i * 2 + 1) * sG1 + sG1); + buffOut.set(buff, i * sG1); + } + } else if (cirPower == curve.Fr.s) { + const o = sectionsPTau[12][0].p + (2 ** (cirPower + 1) - 1) * sG1; + await fdPTau.readToBuffer(buffOut, 0, domainSize * sG1, o + domainSize * sG1); + } else { + if (logger) logger.error("Circuit too big"); + throw new Error("Circuit too big for this curve"); + } + await fdZKey.write(buffOut); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function processConstraints() { + const buffCoeff = new Uint8Array(12 + curve.Fr.n8); + const buffCoeffV = new DataView(buffCoeff.buffer); + const bOne = new Uint8Array(curve.Fr.n8); + curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); + let r1csPos = 0; + function r1cs_readULE32() { + const buff = sR1cs.slice(r1csPos, r1csPos + 4); + r1csPos += 4; + return new DataView(buff.buffer).getUint32(0, true); + } + const coefs = new BigArray(); + for (let c = 0; c < r1cs.nConstraints; c++) { + if (logger && c % 1e4 == 0) logger.debug(`processing constraints: ${c}/${r1cs.nConstraints}`); + const nA = r1cs_readULE32(); + for (let i = 0; i < nA; i++) { + const s = r1cs_readULE32(); + const coefp = r1csPos; + r1csPos += curve.Fr.n8; + const l1t = TAU_G1; + const l1 = sG1 * c; + const l2t = BETATAU_G1; + const l2 = sG1 * c; + if (typeof A[s] === "undefined") A[s] = []; + A[s].push([ + l1t, + l1, + coefp + ]); + if (s <= nPublic) { + if (typeof IC[s] === "undefined") IC[s] = []; + IC[s].push([ + l2t, + l2, + coefp + ]); + } else { + if (typeof C[s - nPublic - 1] === "undefined") C[s - nPublic - 1] = []; + C[s - nPublic - 1].push([ + l2t, + l2, + coefp + ]); + } + coefs.push([ + 0, + c, + s, + coefp + ]); + } + const nB = r1cs_readULE32(); + for (let i = 0; i < nB; i++) { + const s = r1cs_readULE32(); + const coefp = r1csPos; + r1csPos += curve.Fr.n8; + const l1t = TAU_G1; + const l1 = sG1 * c; + const l2t = TAU_G2; + const l2 = sG2 * c; + const l3t = ALPHATAU_G1; + const l3 = sG1 * c; + if (typeof B1[s] === "undefined") B1[s] = []; + B1[s].push([ + l1t, + l1, + coefp + ]); + if (typeof B2[s] === "undefined") B2[s] = []; + B2[s].push([ + l2t, + l2, + coefp + ]); + if (s <= nPublic) { + if (typeof IC[s] === "undefined") IC[s] = []; + IC[s].push([ + l3t, + l3, + coefp + ]); + } else { + if (typeof C[s - nPublic - 1] === "undefined") C[s - nPublic - 1] = []; + C[s - nPublic - 1].push([ + l3t, + l3, + coefp + ]); + } + coefs.push([ + 1, + c, + s, + coefp + ]); + } + const nC = r1cs_readULE32(); + for (let i = 0; i < nC; i++) { + const s = r1cs_readULE32(); + const coefp = r1csPos; + r1csPos += curve.Fr.n8; + const l1t = TAU_G1; + const l1 = sG1 * c; + if (s <= nPublic) { + if (typeof IC[s] === "undefined") IC[s] = []; + IC[s].push([ + l1t, + l1, + coefp + ]); + } else { + if (typeof C[s - nPublic - 1] === "undefined") C[s - nPublic - 1] = []; + C[s - nPublic - 1].push([ + l1t, + l1, + coefp + ]); + } + } + } + for (let s = 0; s <= nPublic; s++) { + const l1t = TAU_G1; + const l1 = sG1 * (r1cs.nConstraints + s); + const l2t = BETATAU_G1; + const l2 = sG1 * (r1cs.nConstraints + s); + if (typeof A[s] === "undefined") A[s] = []; + A[s].push([ + l1t, + l1, + -1 + ]); + if (typeof IC[s] === "undefined") IC[s] = []; + IC[s].push([ + l2t, + l2, + -1 + ]); + coefs.push([ + 0, + r1cs.nConstraints + s, + s, + -1 + ]); + } + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 4); + const buffSection = new ffjavascript.BigBuffer(coefs.length * (12 + curve.Fr.n8) + 4); + const buff4 = /* @__PURE__ */ new Uint8Array(4); + new DataView(buff4.buffer).setUint32(0, coefs.length, true); + buffSection.set(buff4); + let coefsPos = 4; + for (let i = 0; i < coefs.length; i++) { + if (logger && i % 1e5 == 0) logger.debug(`writing coeffs: ${i}/${coefs.length}`); + writeCoef(coefs[i]); + } + await fdZKey.write(buffSection); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + function writeCoef(c) { + buffCoeffV.setUint32(0, c[0], true); + buffCoeffV.setUint32(4, c[1], true); + buffCoeffV.setUint32(8, c[2], true); + let n; + if (c[3] >= 0) n = curve.Fr.fromRprLE(sR1cs.slice(c[3], c[3] + curve.Fr.n8), 0); + else n = curve.Fr.fromRprLE(bOne, 0); + const nR2 = curve.Fr.mul(n, R2r); + curve.Fr.toRprLE(buffCoeff, 12, nR2); + buffSection.set(buffCoeff, coefsPos); + coefsPos += buffCoeff.length; + } + } + async function composeAndWritePoints(idSection, groupName, arr, sectionName) { + const CHUNK_SIZE = 32768; + const G = curve[groupName]; + hashU32(arr.length); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, idSection); + let opPromises = []; + let i = 0; + while (i < arr.length) { + let t = 0; + while (i < arr.length && t < curve.tm.concurrency) { + if (logger) logger.debug(`Writing points start ${sectionName}: ${i}/${arr.length}`); + let n = 1; + let nP = arr[i] ? arr[i].length : 0; + while (i + n < arr.length && nP + (arr[i + n] ? arr[i + n].length : 0) < CHUNK_SIZE && n < CHUNK_SIZE) { + nP += arr[i + n] ? arr[i + n].length : 0; + n++; + } + if (logger) logger.info("before slice:"); + if (logger) logger.info(memUsage()); + const subArr = arr.slice(i, i + n); + if (logger) logger.info("after slice:"); + if (logger) logger.info(memUsage()); + const _i = i; + opPromises.push(composeAndWritePointsThread(groupName, subArr, logger, sectionName).then((r) => { + if (logger) logger.debug(`Writing points end ${sectionName}: ${_i}/${arr.length}`); + return r; + })); + i += n; + t++; + } + const result = await Promise.all(opPromises); + for (let k = 0; k < result.length; k++) { + await fdZKey.write(result[k][0]); + const buff = await G.batchLEMtoU(result[k][0]); + csHasher.update(buff); + } + opPromises = []; + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function composeAndWritePointsThread(groupName, arr, logger, sectionName) { + const G = curve[groupName]; + const sGin = G.F.n8 * 2; + const sGmid = G.F.n8 * 3; + const sGout = G.F.n8 * 2; + let fnExp, fnMultiExp, fnBatchToAffine, fnZero; + if (groupName == "G1") { + fnExp = "g1m_timesScalarAffine"; + fnMultiExp = "g1m_multiexpAffine"; + fnBatchToAffine = "g1m_batchToAffine"; + fnZero = "g1m_zero"; + } else if (groupName == "G2") { + fnExp = "g2m_timesScalarAffine"; + fnMultiExp = "g2m_multiexpAffine"; + fnBatchToAffine = "g2m_batchToAffine"; + fnZero = "g2m_zero"; + } else throw new Error("Invalid group"); + let acc = 0; + for (let i = 0; i < arr.length; i++) acc += arr[i] ? arr[i].length : 0; + let bBases, bScalars; + if (acc > 32768) { + bBases = new ffjavascript.BigBuffer(acc * sGin); + bScalars = new ffjavascript.BigBuffer(acc * curve.Fr.n8); + } else { + bBases = new Uint8Array(acc * sGin); + bScalars = new Uint8Array(acc * curve.Fr.n8); + } + let pB = 0; + let pS = 0; + const sBuffs = [ + sTauG1, + sTauG2, + sAlphaTauG1, + sBetaTauG1 + ]; + const bOne = new Uint8Array(curve.Fr.n8); + curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); + let offset = 0; + for (let i = 0; i < arr.length; i++) { + if (!arr[i]) continue; + for (let j = 0; j < arr[i].length; j++) { + if (logger && j && j % 1e4 == 0) logger.debug(`Configuring big array ${sectionName}: ${j}/${arr[i].length}`); + bBases.set(sBuffs[arr[i][j][0]].slice(arr[i][j][1], arr[i][j][1] + sGin), offset * sGin); + if (arr[i][j][2] >= 0) bScalars.set(sR1cs.slice(arr[i][j][2], arr[i][j][2] + curve.Fr.n8), offset * curve.Fr.n8); + else bScalars.set(bOne, offset * curve.Fr.n8); + offset++; + } + } + if (arr.length > 1) { + const task = []; + task.push({ + cmd: "ALLOCSET", + var: 0, + buff: bBases + }); + task.push({ + cmd: "ALLOCSET", + var: 1, + buff: bScalars + }); + task.push({ + cmd: "ALLOC", + var: 2, + len: arr.length * sGmid + }); + pB = 0; + pS = 0; + let pD = 0; + for (let i = 0; i < arr.length; i++) { + if (!arr[i]) { + task.push({ + cmd: "CALL", + fnName: fnZero, + params: [{ + var: 2, + offset: pD + }] + }); + pD += sGmid; + continue; + } + if (arr[i].length == 1) task.push({ + cmd: "CALL", + fnName: fnExp, + params: [ + { + var: 0, + offset: pB + }, + { + var: 1, + offset: pS + }, + { val: curve.Fr.n8 }, + { + var: 2, + offset: pD + } + ] + }); + else task.push({ + cmd: "CALL", + fnName: fnMultiExp, + params: [ + { + var: 0, + offset: pB + }, + { + var: 1, + offset: pS + }, + { val: curve.Fr.n8 }, + { val: arr[i].length }, + { + var: 2, + offset: pD + } + ] + }); + pB += sGin * arr[i].length; + pS += curve.Fr.n8 * arr[i].length; + pD += sGmid; + } + task.push({ + cmd: "CALL", + fnName: fnBatchToAffine, + params: [ + { var: 2 }, + { val: arr.length }, + { var: 2 } + ] + }); + task.push({ + cmd: "GET", + out: 0, + var: 2, + len: arr.length * sGout + }); + return await curve.tm.queueAction(task); + } else { + let res = await G.multiExpAffine(bBases, bScalars, logger, sectionName); + res = [G.toAffine(res)]; + return res; + } + } + async function hashHPoints() { + const CHUNK_SIZE = 16384; + hashU32(domainSize - 1); + for (let i = 0; i < domainSize - 1; i += CHUNK_SIZE) { + if (logger) logger.debug(`HashingHPoints: ${i}/${domainSize}`); + const n = Math.min(domainSize - 1, CHUNK_SIZE); + await hashHPointsChunk(i, n); + } + } + async function hashHPointsChunk(offset, nPoints) { + const buff1 = await fdPTau.read(nPoints * sG1, sectionsPTau[2][0].p + (offset + domainSize) * sG1); + const buff2 = await fdPTau.read(nPoints * sG1, sectionsPTau[2][0].p + offset * sG1); + const concurrency = curve.tm.concurrency; + const nPointsPerThread = Math.floor(nPoints / concurrency); + const opPromises = []; + for (let i = 0; i < concurrency; i++) { + let n; + if (i < concurrency - 1) n = nPointsPerThread; + else n = nPoints - i * nPointsPerThread; + if (n == 0) continue; + const subBuff1 = buff1.slice(i * nPointsPerThread * sG1, (i * nPointsPerThread + n) * sG1); + const subBuff2 = buff2.slice(i * nPointsPerThread * sG1, (i * nPointsPerThread + n) * sG1); + opPromises.push(hashHPointsThread(subBuff1, subBuff2)); + } + const result = await Promise.all(opPromises); + for (let i = 0; i < result.length; i++) csHasher.update(result[i][0]); + } + async function hashHPointsThread(buff1, buff2) { + const nPoints = buff1.byteLength / sG1; + const sGmid = curve.G1.F.n8 * 3; + const task = []; + task.push({ + cmd: "ALLOCSET", + var: 0, + buff: buff1 + }); + task.push({ + cmd: "ALLOCSET", + var: 1, + buff: buff2 + }); + task.push({ + cmd: "ALLOC", + var: 2, + len: nPoints * sGmid + }); + for (let i = 0; i < nPoints; i++) task.push({ + cmd: "CALL", + fnName: "g1m_subAffine", + params: [ + { + var: 0, + offset: i * sG1 + }, + { + var: 1, + offset: i * sG1 + }, + { + var: 2, + offset: i * sGmid + } + ] + }); + task.push({ + cmd: "CALL", + fnName: "g1m_batchToAffine", + params: [ + { var: 2 }, + { val: nPoints }, + { var: 2 } + ] + }); + task.push({ + cmd: "CALL", + fnName: "g1m_batchLEMtoU", + params: [ + { var: 2 }, + { val: nPoints }, + { var: 2 } + ] + }); + task.push({ + cmd: "GET", + out: 0, + var: 2, + len: nPoints * sG1 + }); + return await curve.tm.queueAction(task); + } + function hashU32(n) { + const buff = /* @__PURE__ */ new Uint8Array(4); + new DataView(buff.buffer, buff.byteOffset, buff.byteLength).setUint32(0, n, false); + csHasher.update(buff); + } + function memUsage() { + let m = process.memoryUsage(); + for (const i in m) m[i] = Math.round(m[i] / (1024 * 1024)); + return m; + } +} +//#endregion +//#region src/zkey_export_bellman.js async function phase2exportMPCParams(zkeyName, mpcparamsName, logger) { - - const {fd: fdZKey, sections: sectionsZKey} = await binFileUtils__namespace.readBinFile(zkeyName, "zkey", 2); - const zkey = await readHeader$1(fdZKey, sectionsZKey); - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkey.q); - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - const mpcParams = await readMPCParams(fdZKey, curve, sectionsZKey); - - const fdMPCParams = await fastFile__namespace.createOverride(mpcparamsName); - - ///////////////////// - // Verification Key Section - ///////////////////// - await writeG1(zkey.vk_alpha_1); - await writeG1(zkey.vk_beta_1); - await writeG2(zkey.vk_beta_2); - await writeG2(zkey.vk_gamma_2); - await writeG1(zkey.vk_delta_1); - await writeG2(zkey.vk_delta_2); - - // IC - let buffBasesIC; - buffBasesIC = await binFileUtils__namespace.readSection(fdZKey, sectionsZKey, 3); - buffBasesIC = await curve.G1.batchLEMtoU(buffBasesIC); - - await writePointArray("G1", buffBasesIC); - - ///////////////////// - // h Section - ///////////////////// - const buffBasesH_Lodd = await binFileUtils__namespace.readSection(fdZKey, sectionsZKey, 9); - - let buffBasesH_Tau; - buffBasesH_Tau = await curve.G1.fft(buffBasesH_Lodd, "affine", "jacobian", logger); - buffBasesH_Tau = await curve.G1.batchApplyKey(buffBasesH_Tau, curve.Fr.neg(curve.Fr.e(2)), curve.Fr.w[zkey.power+1], "jacobian", "affine", logger); - - // Remove last element. (The degree of H will be always m-2) - buffBasesH_Tau = buffBasesH_Tau.slice(0, buffBasesH_Tau.byteLength - sG1); - buffBasesH_Tau = await curve.G1.batchLEMtoU(buffBasesH_Tau); - await writePointArray("G1", buffBasesH_Tau); - - ///////////////////// - // L section - ///////////////////// - let buffBasesC; - buffBasesC = await binFileUtils__namespace.readSection(fdZKey, sectionsZKey, 8); - buffBasesC = await curve.G1.batchLEMtoU(buffBasesC); - await writePointArray("G1", buffBasesC); - - ///////////////////// - // A Section (C section) - ///////////////////// - let buffBasesA; - buffBasesA = await binFileUtils__namespace.readSection(fdZKey, sectionsZKey, 5); - buffBasesA = await curve.G1.batchLEMtoU(buffBasesA); - await writePointArray("G1", buffBasesA); - - ///////////////////// - // B1 Section - ///////////////////// - let buffBasesB1; - buffBasesB1 = await binFileUtils__namespace.readSection(fdZKey, sectionsZKey, 6); - buffBasesB1 = await curve.G1.batchLEMtoU(buffBasesB1); - await writePointArray("G1", buffBasesB1); - - ///////////////////// - // B2 Section - ///////////////////// - let buffBasesB2; - buffBasesB2 = await binFileUtils__namespace.readSection(fdZKey, sectionsZKey, 7); - buffBasesB2 = await curve.G2.batchLEMtoU(buffBasesB2); - await writePointArray("G2", buffBasesB2); - - await fdMPCParams.write(mpcParams.csHash); - await writeU32(mpcParams.contributions.length); - - for (let i=0; i. -*/ - - + const { fd: fdZKey, sections: sectionsZKey } = await _iden3_binfileutils.readBinFile(zkeyName, "zkey", 2); + const zkey = await readHeader$1(fdZKey, sectionsZKey); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkey.q); + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + const mpcParams = await readMPCParams(fdZKey, curve, sectionsZKey); + const fdMPCParams = await fastfile.createOverride(mpcparamsName); + await writeG1(zkey.vk_alpha_1); + await writeG1(zkey.vk_beta_1); + await writeG2(zkey.vk_beta_2); + await writeG2(zkey.vk_gamma_2); + await writeG1(zkey.vk_delta_1); + await writeG2(zkey.vk_delta_2); + let buffBasesIC; + buffBasesIC = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 3); + buffBasesIC = await curve.G1.batchLEMtoU(buffBasesIC); + await writePointArray("G1", buffBasesIC); + const buffBasesH_Lodd = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 9); + let buffBasesH_Tau; + buffBasesH_Tau = await curve.G1.fft(buffBasesH_Lodd, "affine", "jacobian", logger); + buffBasesH_Tau = await curve.G1.batchApplyKey(buffBasesH_Tau, curve.Fr.neg(curve.Fr.e(2)), curve.Fr.w[zkey.power + 1], "jacobian", "affine", logger); + buffBasesH_Tau = buffBasesH_Tau.slice(0, buffBasesH_Tau.byteLength - sG1); + buffBasesH_Tau = await curve.G1.batchLEMtoU(buffBasesH_Tau); + await writePointArray("G1", buffBasesH_Tau); + let buffBasesC; + buffBasesC = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 8); + buffBasesC = await curve.G1.batchLEMtoU(buffBasesC); + await writePointArray("G1", buffBasesC); + let buffBasesA; + buffBasesA = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 5); + buffBasesA = await curve.G1.batchLEMtoU(buffBasesA); + await writePointArray("G1", buffBasesA); + let buffBasesB1; + buffBasesB1 = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 6); + buffBasesB1 = await curve.G1.batchLEMtoU(buffBasesB1); + await writePointArray("G1", buffBasesB1); + let buffBasesB2; + buffBasesB2 = await _iden3_binfileutils.readSection(fdZKey, sectionsZKey, 7); + buffBasesB2 = await curve.G2.batchLEMtoU(buffBasesB2); + await writePointArray("G2", buffBasesB2); + await fdMPCParams.write(mpcParams.csHash); + await writeU32(mpcParams.contributions.length); + for (let i = 0; i < mpcParams.contributions.length; i++) { + const c = mpcParams.contributions[i]; + await writeG1(c.deltaAfter); + await writeG1(c.delta.g1_s); + await writeG1(c.delta.g1_sx); + await writeG2(c.delta.g2_spx); + await fdMPCParams.write(c.transcript); + } + await fdZKey.close(); + await fdMPCParams.close(); + async function writeG1(P) { + const buff = new Uint8Array(sG1); + curve.G1.toRprUncompressed(buff, 0, P); + await fdMPCParams.write(buff); + } + async function writeG2(P) { + const buff = new Uint8Array(sG2); + curve.G2.toRprUncompressed(buff, 0, P); + await fdMPCParams.write(buff); + } + async function writePointArray(groupName, buff) { + let sG; + if (groupName == "G1") sG = sG1; + else sG = sG2; + const buffSize = /* @__PURE__ */ new Uint8Array(4); + new DataView(buffSize.buffer, buffSize.byteOffset, buffSize.byteLength).setUint32(0, buff.byteLength / sG, false); + await fdMPCParams.write(buffSize); + await fdMPCParams.write(buff); + } + async function writeU32(n) { + const buffSize = /* @__PURE__ */ new Uint8Array(4); + new DataView(buffSize.buffer, buffSize.byteOffset, buffSize.byteLength).setUint32(0, n, false); + await fdMPCParams.write(buffSize); + } +} +//#endregion +//#region src/zkey_import_bellman.js async function phase2importMPCParams(zkeyNameOld, mpcparamsName, zkeyNameNew, name, logger) { - - const {fd: fdZKeyOld, sections: sectionsZKeyOld} = await binFileUtils__namespace.readBinFile(zkeyNameOld, "zkey", 2); - const zkeyHeader = await readHeader$1(fdZKeyOld, sectionsZKeyOld, false); - if (zkeyHeader.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkeyHeader.q); - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - const oldMPCParams = await readMPCParams(fdZKeyOld, curve, sectionsZKeyOld); - const newMPCParams = {}; - - const fdMPCParams = await fastFile__namespace.readExisting(mpcparamsName); - - fdMPCParams.pos = - sG1*3 + sG2*3 + // vKey - 8 + sG1*zkeyHeader.nVars + // IC + C - 4 + sG1*(zkeyHeader.domainSize-1) + // H - 4 + sG1*zkeyHeader.nVars + // A - 4 + sG1*zkeyHeader.nVars + // B1 - 4 + sG2*zkeyHeader.nVars; // B2 - - // csHash - newMPCParams.csHash = await fdMPCParams.read(64); - - const nContributions = await fdMPCParams.readUBE32(); - newMPCParams.contributions = []; - for (let i=0; i newMPCParams.contributions.length) { - if (logger) logger.error("The impoerted file does not include new contributions"); - return false; - } - - for (let i=0; i. -*/ - -const sameRatio = sameRatio$2; - - - + const { fd: fdZKeyOld, sections: sectionsZKeyOld } = await _iden3_binfileutils.readBinFile(zkeyNameOld, "zkey", 2); + const zkeyHeader = await readHeader$1(fdZKeyOld, sectionsZKeyOld, false); + if (zkeyHeader.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkeyHeader.q); + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + const oldMPCParams = await readMPCParams(fdZKeyOld, curve, sectionsZKeyOld); + const newMPCParams = {}; + const fdMPCParams = await fastfile.readExisting(mpcparamsName); + fdMPCParams.pos = sG1 * 3 + sG2 * 3 + 8 + sG1 * zkeyHeader.nVars + 4 + sG1 * (zkeyHeader.domainSize - 1) + 4 + sG1 * zkeyHeader.nVars + 4 + sG1 * zkeyHeader.nVars + 4 + sG2 * zkeyHeader.nVars; + newMPCParams.csHash = await fdMPCParams.read(64); + const nContributions = await fdMPCParams.readUBE32(); + newMPCParams.contributions = []; + for (let i = 0; i < nContributions; i++) { + const c = { delta: {} }; + c.deltaAfter = await readG1(fdMPCParams); + c.delta.g1_s = await readG1(fdMPCParams); + c.delta.g1_sx = await readG1(fdMPCParams); + c.delta.g2_spx = await readG2(fdMPCParams); + c.transcript = await fdMPCParams.read(64); + if (i < oldMPCParams.contributions.length) { + c.type = oldMPCParams.contributions[i].type; + if (c.type == 1) { + c.beaconHash = oldMPCParams.contributions[i].beaconHash; + c.numIterationsExp = oldMPCParams.contributions[i].numIterationsExp; + } + if (oldMPCParams.contributions[i].name) c.name = oldMPCParams.contributions[i].name; + } + newMPCParams.contributions.push(c); + } + if (!hashIsEqual(newMPCParams.csHash, oldMPCParams.csHash)) { + if (logger) logger.error("Hash of the original circuit does not match with the MPC one"); + return false; + } + if (oldMPCParams.contributions.length > newMPCParams.contributions.length) { + if (logger) logger.error("The impoerted file does not include new contributions"); + return false; + } + for (let i = 0; i < oldMPCParams.contributions.length; i++) if (!contributionIsEqual(oldMPCParams.contributions[i], newMPCParams.contributions[i])) { + if (logger) logger.error(`Previous contribution ${i} does not match`); + return false; + } + if (name) for (let i = oldMPCParams.contributions.length; i < newMPCParams.contributions.length; i++) newMPCParams.contributions[i].name = name; + const fdZKeyNew = await _iden3_binfileutils.createBinFile(zkeyNameNew, "zkey", 1, 10); + fdMPCParams.pos = 0; + fdMPCParams.pos += sG1; + fdMPCParams.pos += sG1; + fdMPCParams.pos += sG2; + fdMPCParams.pos += sG2; + zkeyHeader.vk_delta_1 = await readG1(fdMPCParams); + zkeyHeader.vk_delta_2 = await readG2(fdMPCParams); + await writeHeader(fdZKeyNew, zkeyHeader); + if (await fdMPCParams.readUBE32() != zkeyHeader.nPublic + 1) { + if (logger) logger.error("Invalid number of points in IC"); + await fdZKeyNew.discard(); + return false; + } + fdMPCParams.pos += sG1 * (zkeyHeader.nPublic + 1); + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 3); + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 4); + if (await fdMPCParams.readUBE32() != zkeyHeader.domainSize - 1) { + if (logger) logger.error("Invalid number of points in H"); + await fdZKeyNew.discard(); + return false; + } + let buffH; + const buffTauU = await fdMPCParams.read(sG1 * (zkeyHeader.domainSize - 1)); + const buffTauLEM = await curve.G1.batchUtoLEM(buffTauU); + buffH = new Uint8Array(zkeyHeader.domainSize * sG1); + buffH.set(buffTauLEM); + curve.G1.toRprLEM(buffH, sG1 * (zkeyHeader.domainSize - 1), curve.G1.zeroAffine); + const n2Inv = curve.Fr.neg(curve.Fr.inv(curve.Fr.e(2))); + const wInv = curve.Fr.inv(curve.Fr.w[zkeyHeader.power + 1]); + buffH = await curve.G1.batchApplyKey(buffH, n2Inv, wInv, "affine", "jacobian", logger); + buffH = await curve.G1.ifft(buffH, "jacobian", "affine", logger); + await _iden3_binfileutils.startWriteSection(fdZKeyNew, 9); + await fdZKeyNew.write(buffH); + await _iden3_binfileutils.endWriteSection(fdZKeyNew); + if (await fdMPCParams.readUBE32() != zkeyHeader.nVars - zkeyHeader.nPublic - 1) { + if (logger) logger.error("Invalid number of points in L"); + await fdZKeyNew.discard(); + return false; + } + let buffL; + buffL = await fdMPCParams.read(sG1 * (zkeyHeader.nVars - zkeyHeader.nPublic - 1)); + buffL = await curve.G1.batchUtoLEM(buffL); + await _iden3_binfileutils.startWriteSection(fdZKeyNew, 8); + await fdZKeyNew.write(buffL); + await _iden3_binfileutils.endWriteSection(fdZKeyNew); + if (await fdMPCParams.readUBE32() != zkeyHeader.nVars) { + if (logger) logger.error("Invalid number of points in A"); + await fdZKeyNew.discard(); + return false; + } + fdMPCParams.pos += sG1 * zkeyHeader.nVars; + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 5); + if (await fdMPCParams.readUBE32() != zkeyHeader.nVars) { + if (logger) logger.error("Invalid number of points in B1"); + await fdZKeyNew.discard(); + return false; + } + fdMPCParams.pos += sG1 * zkeyHeader.nVars; + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 6); + if (await fdMPCParams.readUBE32() != zkeyHeader.nVars) { + if (logger) logger.error("Invalid number of points in B2"); + await fdZKeyNew.discard(); + return false; + } + fdMPCParams.pos += sG2 * zkeyHeader.nVars; + await _iden3_binfileutils.copySection(fdZKeyOld, sectionsZKeyOld, fdZKeyNew, 7); + await writeMPCParams(fdZKeyNew, curve, newMPCParams); + await fdMPCParams.close(); + await fdZKeyNew.close(); + await fdZKeyOld.close(); + return true; + async function readG1(fd) { + const buff = await fd.read(curve.G1.F.n8 * 2); + return curve.G1.fromRprUncompressed(buff, 0); + } + async function readG2(fd) { + const buff = await fd.read(curve.G2.F.n8 * 2); + return curve.G2.fromRprUncompressed(buff, 0); + } + function contributionIsEqual(c1, c2) { + if (!curve.G1.eq(c1.deltaAfter, c2.deltaAfter)) return false; + if (!curve.G1.eq(c1.delta.g1_s, c2.delta.g1_s)) return false; + if (!curve.G1.eq(c1.delta.g1_sx, c2.delta.g1_sx)) return false; + if (!curve.G2.eq(c1.delta.g2_spx, c2.delta.g2_spx)) return false; + if (!hashIsEqual(c1.transcript, c2.transcript)) return false; + return true; + } +} +//#endregion +//#region src/zkey_verify_frominit.js +var sameRatio = sameRatio$2; async function phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger) { - - let sr; - const {fd, sections} = await binFileUtils__namespace.readBinFile(zkeyFileName, "zkey", 2); - const zkey = await readHeader$1(fd, sections, false); - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkey.q); - const sG1 = curve.G1.F.n8*2; - - const mpcParams = await readMPCParams(fd, curve, sections); - - const accumulatedHasher = blake2_js.blake2b.create({ dkLen: 64 }); - accumulatedHasher.update(mpcParams.csHash); - let curDelta = curve.G1.g; - for (let i=0; i=0; i--) { - const c = mpcParams.contributions[i]; - if (logger) logger.info("-------------------------"); - if (logger) logger.info(formatHash(c.contributionHash, `contribution #${i+1} ${c.name ? c.name : ""}:`)); - if (c.type == 1) { - if (logger) logger.info(`Beacon generator: ${byteArray2hex(c.beaconHash)}`); - if (logger) logger.info(`Beacon iterations Exp: ${c.numIterationsExp}`); - } - } - if (logger) logger.info("-------------------------"); - - if (logger) logger.info("ZKey Ok!"); - - return true; - - - async function sectionHasSameRatio(groupName, fd1, sections1, fd2, sections2, idSection, g2sp, g2spx, sectionName) { - const MAX_CHUNK_SIZE = 1<<20; - const G = curve[groupName]; - const sG = G.F.n8*2; - await binFileUtils__namespace.startReadUniqueSection(fd1, sections1, idSection); - await binFileUtils__namespace.startReadUniqueSection(fd2, sections2, idSection); - - let R1 = G.zero; - let R2 = G.zero; - - const nPoints = sections1[idSection][0].size / sG; - - for (let i=0; i. -*/ - - + let sr; + const { fd, sections } = await _iden3_binfileutils.readBinFile(zkeyFileName, "zkey", 2); + const zkey = await readHeader$1(fd, sections, false); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkey.q); + const sG1 = curve.G1.F.n8 * 2; + const mpcParams = await readMPCParams(fd, curve, sections); + const accumulatedHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + accumulatedHasher.update(mpcParams.csHash); + let curDelta = curve.G1.g; + for (let i = 0; i < mpcParams.contributions.length; i++) { + const c = mpcParams.contributions[i]; + const ourHasher = cloneHasher(accumulatedHasher); + hashG1(ourHasher, curve, c.delta.g1_s); + hashG1(ourHasher, curve, c.delta.g1_sx); + if (!hashIsEqual(ourHasher.digest(), c.transcript)) { + console.log(`INVALID(${i}): Inconsistent transcript `); + return false; + } + const delta_g2_sp = hashToG2(curve, c.transcript); + sr = await sameRatio(curve, c.delta.g1_s, c.delta.g1_sx, delta_g2_sp, c.delta.g2_spx); + if (sr !== true) { + console.log(`INVALID(${i}): public key G1 and G2 do not have the same ration `); + return false; + } + sr = await sameRatio(curve, curDelta, c.deltaAfter, delta_g2_sp, c.delta.g2_spx); + if (sr !== true) { + console.log(`INVALID(${i}): deltaAfter does not fillow the public key `); + return false; + } + if (c.type == 1) { + const rng = await rngFromBeaconParams(c.beaconHash, c.numIterationsExp); + const expected_prvKey = curve.Fr.fromRng(rng); + const expected_g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + const expected_g1_sx = curve.G1.toAffine(curve.G1.timesFr(expected_g1_s, expected_prvKey)); + if (curve.G1.eq(expected_g1_s, c.delta.g1_s) !== true) { + console.log(`INVALID(${i}): Key of the beacon does not match. g1_s `); + return false; + } + if (curve.G1.eq(expected_g1_sx, c.delta.g1_sx) !== true) { + console.log(`INVALID(${i}): Key of the beacon does not match. g1_sx `); + return false; + } + } + hashPubKey(accumulatedHasher, curve, c); + const contributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hashPubKey(contributionHasher, curve, c); + c.contributionHash = contributionHasher.digest(); + curDelta = c.deltaAfter; + } + const { fd: fdInit, sections: sectionsInit } = await _iden3_binfileutils.readBinFile(initFileName, "zkey", 2); + const zkeyInit = await readHeader$1(fdInit, sectionsInit, false); + if (zkeyInit.protocol != "groth16") throw new Error("zkeyinit file is not groth16"); + if (!ffjavascript.Scalar.eq(zkeyInit.q, zkey.q) || !ffjavascript.Scalar.eq(zkeyInit.r, zkey.r) || zkeyInit.n8q != zkey.n8q || zkeyInit.n8r != zkey.n8r) { + if (logger) logger.error("INVALID: Different curves"); + return false; + } + if (zkeyInit.nVars != zkey.nVars || zkeyInit.nPublic != zkey.nPublic || zkeyInit.domainSize != zkey.domainSize) { + if (logger) logger.error("INVALID: Different circuit parameters"); + return false; + } + if (!curve.G1.eq(zkey.vk_alpha_1, zkeyInit.vk_alpha_1)) { + if (logger) logger.error("INVALID: Invalid alpha1"); + return false; + } + if (!curve.G1.eq(zkey.vk_beta_1, zkeyInit.vk_beta_1)) { + if (logger) logger.error("INVALID: Invalid beta1"); + return false; + } + if (!curve.G2.eq(zkey.vk_beta_2, zkeyInit.vk_beta_2)) { + if (logger) logger.error("INVALID: Invalid beta2"); + return false; + } + if (!curve.G2.eq(zkey.vk_gamma_2, zkeyInit.vk_gamma_2)) { + if (logger) logger.error("INVALID: Invalid gamma2"); + return false; + } + if (!curve.G1.eq(zkey.vk_delta_1, curDelta)) { + if (logger) logger.error("INVALID: Invalid delta1"); + return false; + } + sr = await sameRatio(curve, curve.G1.g, curDelta, curve.G2.g, zkey.vk_delta_2); + if (sr !== true) { + if (logger) logger.error("INVALID: Invalid delta2"); + return false; + } + const mpcParamsInit = await readMPCParams(fdInit, curve, sectionsInit); + if (!hashIsEqual(mpcParams.csHash, mpcParamsInit.csHash)) { + if (logger) logger.error("INVALID: Circuit does not match"); + return false; + } + if (sections[8][0].size != sG1 * (zkey.nVars - zkey.nPublic - 1)) { + if (logger) logger.error("INVALID: Invalid L section size"); + return false; + } + if (sections[9][0].size != sG1 * zkey.domainSize) { + if (logger) logger.error("INVALID: Invalid H section size"); + return false; + } + let ss; + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 3); + if (!ss) { + if (logger) logger.error("INVALID: IC section is not identical"); + return false; + } + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 4); + if (!ss) { + if (logger) logger.error("Coeffs section is not identical"); + return false; + } + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 5); + if (!ss) { + if (logger) logger.error("A section is not identical"); + return false; + } + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 6); + if (!ss) { + if (logger) logger.error("B1 section is not identical"); + return false; + } + ss = await _iden3_binfileutils.sectionIsEqual(fd, sections, fdInit, sectionsInit, 7); + if (!ss) { + if (logger) logger.error("B2 section is not identical"); + return false; + } + sr = await sectionHasSameRatio("G1", fdInit, sectionsInit, fd, sections, 8, zkey.vk_delta_2, zkeyInit.vk_delta_2, "L section"); + if (sr !== true) { + if (logger) logger.error("L section does not match"); + return false; + } + sr = await sameRatioH(); + if (sr !== true) { + if (logger) logger.error("H section does not match"); + return false; + } + if (logger) logger.info(formatHash(mpcParams.csHash, "Circuit Hash: ")); + await fd.close(); + await fdInit.close(); + for (let i = mpcParams.contributions.length - 1; i >= 0; i--) { + const c = mpcParams.contributions[i]; + if (logger) logger.info("-------------------------"); + if (logger) logger.info(formatHash(c.contributionHash, `contribution #${i + 1} ${c.name ? c.name : ""}:`)); + if (c.type == 1) { + if (logger) logger.info(`Beacon generator: ${byteArray2hex(c.beaconHash)}`); + if (logger) logger.info(`Beacon iterations Exp: ${c.numIterationsExp}`); + } + } + if (logger) logger.info("-------------------------"); + if (logger) logger.info("ZKey Ok!"); + return true; + async function sectionHasSameRatio(groupName, fd1, sections1, fd2, sections2, idSection, g2sp, g2spx, sectionName) { + const MAX_CHUNK_SIZE = 1 << 20; + const G = curve[groupName]; + const sG = G.F.n8 * 2; + await _iden3_binfileutils.startReadUniqueSection(fd1, sections1, idSection); + await _iden3_binfileutils.startReadUniqueSection(fd2, sections2, idSection); + let R1 = G.zero; + let R2 = G.zero; + const nPoints = sections1[idSection][0].size / sG; + for (let i = 0; i < nPoints; i += MAX_CHUNK_SIZE) { + if (logger) logger.debug(`Same ratio check ${sectionName}: ${i}/${nPoints}`); + const n = Math.min(nPoints - i, MAX_CHUNK_SIZE); + const bases1 = await fd1.read(n * sG); + const bases2 = await fd2.read(n * sG); + const scalars = getRandomBytes(4 * n); + const r1 = await G.multiExpAffine(bases1, scalars); + const r2 = await G.multiExpAffine(bases2, scalars); + R1 = G.add(R1, r1); + R2 = G.add(R2, r2); + } + await _iden3_binfileutils.endReadSection(fd1); + await _iden3_binfileutils.endReadSection(fd2); + if (nPoints == 0) return true; + sr = await sameRatio(curve, R1, R2, g2sp, g2spx); + if (sr !== true) return false; + return true; + } + async function sameRatioH() { + const MAX_CHUNK_SIZE = 1 << 20; + const G = curve.G1; + const Fr = curve.Fr; + const sG = G.F.n8 * 2; + const { fd: fdPTau, sections: sectionsPTau } = await _iden3_binfileutils.readBinFile(pTauFileName, "ptau", 1); + let buff_r = new ffjavascript.BigBuffer(zkey.domainSize * zkey.n8r); + const seed = new Array(8); + for (let i = 0; i < 8; i++) seed[i] = readUInt32BE(getRandomBytes(4), 0); + const rng = new ffjavascript.ChaCha(seed); + for (let i = 0; i < zkey.domainSize - 1; i++) { + const e = Fr.fromRng(rng); + Fr.toRprLE(buff_r, i * zkey.n8r, e); + } + Fr.toRprLE(buff_r, (zkey.domainSize - 1) * zkey.n8r, Fr.zero); + let R1 = G.zero; + for (let i = 0; i < zkey.domainSize; i += MAX_CHUNK_SIZE) { + if (logger) logger.debug(`H Verification(tau): ${i}/${zkey.domainSize}`); + const n = Math.min(zkey.domainSize - i, MAX_CHUNK_SIZE); + const buffB = await batchSubtract(await fdPTau.read(sG * n, sectionsPTau[2][0].p + zkey.domainSize * sG + i * sG), await fdPTau.read(sG * n, sectionsPTau[2][0].p + i * sG)); + const buffS = buff_r.slice(i * zkey.n8r, (i + n) * zkey.n8r); + const r = await G.multiExpAffine(buffB, buffS); + R1 = G.add(R1, r); + } + buff_r = await Fr.batchToMontgomery(buff_r); + let first; + if (zkey.power < Fr.s) first = Fr.neg(Fr.e(2)); + else { + const small_m = 2 ** Fr.s; + const shift_to_small_m = Fr.exp(Fr.shift, small_m); + first = Fr.sub(shift_to_small_m, Fr.one); + } + const inc = zkey.power < Fr.s ? Fr.w[zkey.power + 1] : Fr.shift; + buff_r = await Fr.batchApplyKey(buff_r, first, inc); + buff_r = await Fr.fft(buff_r); + buff_r = await Fr.batchFromMontgomery(buff_r); + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 9); + let R2 = G.zero; + for (let i = 0; i < zkey.domainSize; i += MAX_CHUNK_SIZE) { + if (logger) logger.debug(`H Verification(lagrange): ${i}/${zkey.domainSize}`); + const n = Math.min(zkey.domainSize - i, MAX_CHUNK_SIZE); + const buff = await fd.read(sG * n); + const buffS = buff_r.slice(i * zkey.n8r, (i + n) * zkey.n8r); + const r = await G.multiExpAffine(buff, buffS); + R2 = G.add(R2, r); + } + await _iden3_binfileutils.endReadSection(fd); + sr = await sameRatio(curve, R1, R2, zkey.vk_delta_2, zkeyInit.vk_delta_2); + if (sr !== true) return false; + return true; + } + async function batchSubtract(buff1, buff2) { + const sG = curve.G1.F.n8 * 2; + const nPoints = buff1.byteLength / sG; + const concurrency = curve.tm.concurrency; + const nPointsPerThread = Math.floor(nPoints / concurrency); + const opPromises = []; + for (let i = 0; i < concurrency; i++) { + let n; + if (i < concurrency - 1) n = nPointsPerThread; + else n = nPoints - i * nPointsPerThread; + if (n == 0) continue; + const subBuff1 = buff1.slice(i * nPointsPerThread * sG1, (i * nPointsPerThread + n) * sG1); + const subBuff2 = buff2.slice(i * nPointsPerThread * sG1, (i * nPointsPerThread + n) * sG1); + opPromises.push(batchSubtractThread(subBuff1, subBuff2)); + } + const result = await Promise.all(opPromises); + const fullBuffOut = new Uint8Array(nPoints * sG); + let p = 0; + for (let i = 0; i < result.length; i++) { + fullBuffOut.set(result[i][0], p); + p += result[i][0].byteLength; + } + return fullBuffOut; + } + async function batchSubtractThread(buff1, buff2) { + const sG1 = curve.G1.F.n8 * 2; + const sGmid = curve.G1.F.n8 * 3; + const nPoints = buff1.byteLength / sG1; + const task = []; + task.push({ + cmd: "ALLOCSET", + var: 0, + buff: buff1 + }); + task.push({ + cmd: "ALLOCSET", + var: 1, + buff: buff2 + }); + task.push({ + cmd: "ALLOC", + var: 2, + len: nPoints * sGmid + }); + for (let i = 0; i < nPoints; i++) task.push({ + cmd: "CALL", + fnName: "g1m_subAffine", + params: [ + { + var: 0, + offset: i * sG1 + }, + { + var: 1, + offset: i * sG1 + }, + { + var: 2, + offset: i * sGmid + } + ] + }); + task.push({ + cmd: "CALL", + fnName: "g1m_batchToAffine", + params: [ + { var: 2 }, + { val: nPoints }, + { var: 2 } + ] + }); + task.push({ + cmd: "GET", + out: 0, + var: 2, + len: nPoints * sG1 + }); + return await curve.tm.queueAction(task); + } +} +//#endregion +//#region src/zkey_verify_fromr1cs.js async function phase2verifyFromR1cs(r1csFileName, pTauFileName, zkeyFileName, logger) { - - // const initFileName = "~" + zkeyFileName + ".init"; - const initFileName = {type: "bigMem"}; - await newZKey(r1csFileName, pTauFileName, initFileName, logger); - - return await phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const initFileName = { type: "bigMem" }; + await newZKey(r1csFileName, pTauFileName, initFileName, logger); + return await phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger); +} +//#endregion +//#region src/zkey_contribute.js async function phase2contribute(zkeyNameOld, zkeyNameNew, name, entropy, logger) { - - const {fd: fdOld, sections: sections} = await binFileUtils__namespace.readBinFile(zkeyNameOld, "zkey", 2); - const zkey = await readHeader$1(fdOld, sections); - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkey.q); - - const mpcParams = await readMPCParams(fdOld, curve, sections); - - const fdNew = await binFileUtils__namespace.createBinFile(zkeyNameNew, "zkey", 1, 10); - - - const rng = await getRandomRng(entropy); - - const transcriptHasher = blake2_js.blake2b.create({ dkLen: 64 }); - transcriptHasher.update(mpcParams.csHash); - for (let i=0; i. -*/ - - - + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(zkeyNameOld, "zkey", 2); + const zkey = await readHeader$1(fdOld, sections); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkey.q); + const mpcParams = await readMPCParams(fdOld, curve, sections); + const fdNew = await _iden3_binfileutils.createBinFile(zkeyNameNew, "zkey", 1, 10); + const rng = await getRandomRng(entropy); + const transcriptHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + transcriptHasher.update(mpcParams.csHash); + for (let i = 0; i < mpcParams.contributions.length; i++) hashPubKey(transcriptHasher, curve, mpcParams.contributions[i]); + const curContribution = {}; + curContribution.delta = {}; + curContribution.delta.prvKey = curve.Fr.fromRng(rng); + curContribution.delta.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + curContribution.delta.g1_sx = curve.G1.toAffine(curve.G1.timesFr(curContribution.delta.g1_s, curContribution.delta.prvKey)); + hashG1(transcriptHasher, curve, curContribution.delta.g1_s); + hashG1(transcriptHasher, curve, curContribution.delta.g1_sx); + curContribution.transcript = transcriptHasher.digest(); + curContribution.delta.g2_sp = hashToG2(curve, curContribution.transcript); + curContribution.delta.g2_spx = curve.G2.toAffine(curve.G2.timesFr(curContribution.delta.g2_sp, curContribution.delta.prvKey)); + zkey.vk_delta_1 = curve.G1.timesFr(zkey.vk_delta_1, curContribution.delta.prvKey); + zkey.vk_delta_2 = curve.G2.timesFr(zkey.vk_delta_2, curContribution.delta.prvKey); + curContribution.deltaAfter = zkey.vk_delta_1; + curContribution.type = 0; + if (name) curContribution.name = name; + mpcParams.contributions.push(curContribution); + await writeHeader(fdNew, zkey); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + const invDelta = curve.Fr.inv(curContribution.delta.prvKey); + await applyKeyToSection(fdOld, sections, fdNew, 8, curve, "G1", invDelta, curve.Fr.e(1), "L Section", logger); + await applyKeyToSection(fdOld, sections, fdNew, 9, curve, "G1", invDelta, curve.Fr.e(1), "H Section", logger); + await writeMPCParams(fdNew, curve, mpcParams); + await fdOld.close(); + await fdNew.close(); + const contributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hashPubKey(contributionHasher, curve, curContribution); + const contributionHash = contributionHasher.digest(); + if (logger) logger.info(formatHash(mpcParams.csHash, "Circuit Hash: ")); + if (logger) logger.info(formatHash(contributionHash, "Contribution Hash: ")); + return contributionHash; +} +//#endregion +//#region src/zkey_beacon.js async function beacon(zkeyNameOld, zkeyNameNew, name, beaconHashStr, numIterationsExp, logger) { - const beaconHash = hex2ByteArray(beaconHashStr); - if ( (beaconHash.byteLength == 0) - || (beaconHash.byteLength*2 !=beaconHashStr.length)) - { - if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); - return false; - } - if (beaconHash.length>=256) { - if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); - return false; - } - - numIterationsExp = parseInt(numIterationsExp); - if ((numIterationsExp<10)||(numIterationsExp>63)) { - if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); - return false; - } - - - const {fd: fdOld, sections: sections} = await binFileUtils__namespace.readBinFile(zkeyNameOld, "zkey", 2); - const zkey = await readHeader$1(fdOld, sections); - - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - - const curve = await getCurveFromQ(zkey.q); - - const mpcParams = await readMPCParams(fdOld, curve, sections); - - const fdNew = await binFileUtils__namespace.createBinFile(zkeyNameNew, "zkey", 1, 10); - - const rng = await rngFromBeaconParams(beaconHash, numIterationsExp); - - const transcriptHasher = blake2_js.blake2b.create({ dkLen: 64 }); transcriptHasher.update(mpcParams.csHash); - for (let i=0; i= 256) { + if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); + return false; + } + numIterationsExp = parseInt(numIterationsExp); + if (numIterationsExp < 10 || numIterationsExp > 63) { + if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); + return false; + } + const { fd: fdOld, sections } = await _iden3_binfileutils.readBinFile(zkeyNameOld, "zkey", 2); + const zkey = await readHeader$1(fdOld, sections); + if (zkey.protocol != "groth16") throw new Error("zkey file is not groth16"); + const curve = await getCurveFromQ(zkey.q); + const mpcParams = await readMPCParams(fdOld, curve, sections); + const fdNew = await _iden3_binfileutils.createBinFile(zkeyNameNew, "zkey", 1, 10); + const rng = await rngFromBeaconParams(beaconHash, numIterationsExp); + const transcriptHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + transcriptHasher.update(mpcParams.csHash); + for (let i = 0; i < mpcParams.contributions.length; i++) hashPubKey(transcriptHasher, curve, mpcParams.contributions[i]); + const curContribution = {}; + curContribution.delta = {}; + curContribution.delta.prvKey = curve.Fr.fromRng(rng); + curContribution.delta.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + curContribution.delta.g1_sx = curve.G1.toAffine(curve.G1.timesFr(curContribution.delta.g1_s, curContribution.delta.prvKey)); + hashG1(transcriptHasher, curve, curContribution.delta.g1_s); + hashG1(transcriptHasher, curve, curContribution.delta.g1_sx); + curContribution.transcript = transcriptHasher.digest(); + curContribution.delta.g2_sp = hashToG2(curve, curContribution.transcript); + curContribution.delta.g2_spx = curve.G2.toAffine(curve.G2.timesFr(curContribution.delta.g2_sp, curContribution.delta.prvKey)); + zkey.vk_delta_1 = curve.G1.timesFr(zkey.vk_delta_1, curContribution.delta.prvKey); + zkey.vk_delta_2 = curve.G2.timesFr(zkey.vk_delta_2, curContribution.delta.prvKey); + curContribution.deltaAfter = zkey.vk_delta_1; + curContribution.type = 1; + curContribution.numIterationsExp = numIterationsExp; + curContribution.beaconHash = beaconHash; + if (name) curContribution.name = name; + mpcParams.contributions.push(curContribution); + await writeHeader(fdNew, zkey); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 3); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 4); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 5); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 6); + await _iden3_binfileutils.copySection(fdOld, sections, fdNew, 7); + const invDelta = curve.Fr.inv(curContribution.delta.prvKey); + await applyKeyToSection(fdOld, sections, fdNew, 8, curve, "G1", invDelta, curve.Fr.e(1), "L Section", logger); + await applyKeyToSection(fdOld, sections, fdNew, 9, curve, "G1", invDelta, curve.Fr.e(1), "H Section", logger); + await writeMPCParams(fdNew, curve, mpcParams); + await fdOld.close(); + await fdNew.close(); + const contributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hashPubKey(contributionHasher, curve, curContribution); + const contributionHash = contributionHasher.digest(); + if (logger) logger.info(formatHash(contributionHash, "Contribution Hash: ")); + return contributionHash; +} +//#endregion +//#region src/zkey_export_json.js async function zkeyExportJson(zkeyFileName) { - - const zKey = await readZKey(zkeyFileName, true); - delete zKey.curve; - delete zKey.F; - - return ffjavascript.utils.stringifyBigInts(zKey); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - + const zKey = await readZKey(zkeyFileName, true); + delete zKey.curve; + delete zKey.F; + return ffjavascript.utils.stringifyBigInts(zKey); +} +//#endregion +//#region src/zkey_bellman_contribute.js async function bellmanContribute(curve, challengeFilename, responseFileName, entropy, logger) { - const rng = await getRandomRng(entropy); - - const delta = curve.Fr.fromRng(rng); - const invDelta = curve.Fr.inv(delta); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - const fdFrom = await fastFile__namespace.readExisting(challengeFilename); - const fdTo = await fastFile__namespace.createOverride(responseFileName); - - - await copy(sG1); // alpha1 - await copy(sG1); // beta1 - await copy(sG2); // beta2 - await copy(sG2); // gamma2 - const oldDelta1 = await readG1(); - const delta1 = curve.G1.timesFr(oldDelta1, delta); - await writeG1(delta1); - const oldDelta2 = await readG2(); - const delta2 = curve.G2.timesFr(oldDelta2, delta); - await writeG2(delta2); - - // IC - const nIC = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nIC); - await copy(nIC*sG1); - - // H - const nH = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nH); - await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nH, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "H", logger); - - // L - const nL = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nL); - await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nL, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "L", logger); - - // A - const nA = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nA); - await copy(nA*sG1); - - // B1 - const nB1 = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nB1); - await copy(nB1*sG1); - - // B2 - const nB2 = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nB2); - await copy(nB2*sG2); - - - ////////// - /// Read contributions - ////////// - const transcriptHasher = blake2_js.blake2b.create({ dkLen: 64 }); - const mpcParams = {}; - // csHash - mpcParams.csHash = await fdFrom.read(64); - transcriptHasher.update(mpcParams.csHash); - - const nContributions = await fdFrom.readUBE32(); - mpcParams.contributions = []; - for (let i=0; i. -*/ - - -const {stringifyBigInts: stringifyBigInts$3} = ffjavascript.utils; - + const rng = await getRandomRng(entropy); + const delta = curve.Fr.fromRng(rng); + const invDelta = curve.Fr.inv(delta); + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + const fdFrom = await fastfile.readExisting(challengeFilename); + const fdTo = await fastfile.createOverride(responseFileName); + await copy(sG1); + await copy(sG1); + await copy(sG2); + await copy(sG2); + const oldDelta1 = await readG1(); + const delta1 = curve.G1.timesFr(oldDelta1, delta); + await writeG1(delta1); + const oldDelta2 = await readG2(); + await writeG2(curve.G2.timesFr(oldDelta2, delta)); + const nIC = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nIC); + await copy(nIC * sG1); + const nH = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nH); + await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nH, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "H", logger); + const nL = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nL); + await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nL, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "L", logger); + const nA = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nA); + await copy(nA * sG1); + const nB1 = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nB1); + await copy(nB1 * sG1); + const nB2 = await fdFrom.readUBE32(); + await fdTo.writeUBE32(nB2); + await copy(nB2 * sG2); + const transcriptHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + const mpcParams = {}; + mpcParams.csHash = await fdFrom.read(64); + transcriptHasher.update(mpcParams.csHash); + const nContributions = await fdFrom.readUBE32(); + mpcParams.contributions = []; + for (let i = 0; i < nContributions; i++) { + const c = { delta: {} }; + c.deltaAfter = await readG1(); + c.delta.g1_s = await readG1(); + c.delta.g1_sx = await readG1(); + c.delta.g2_spx = await readG2(); + c.transcript = await fdFrom.read(64); + mpcParams.contributions.push(c); + hashPubKey(transcriptHasher, curve, c); + } + const curContribution = {}; + curContribution.delta = {}; + curContribution.delta.prvKey = delta; + curContribution.delta.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); + curContribution.delta.g1_sx = curve.G1.toAffine(curve.G1.timesFr(curContribution.delta.g1_s, delta)); + hashG1(transcriptHasher, curve, curContribution.delta.g1_s); + hashG1(transcriptHasher, curve, curContribution.delta.g1_sx); + curContribution.transcript = transcriptHasher.digest(); + curContribution.delta.g2_sp = hashToG2(curve, curContribution.transcript); + curContribution.delta.g2_spx = curve.G2.toAffine(curve.G2.timesFr(curContribution.delta.g2_sp, delta)); + curContribution.deltaAfter = delta1; + curContribution.type = 0; + mpcParams.contributions.push(curContribution); + await fdTo.write(mpcParams.csHash); + await fdTo.writeUBE32(mpcParams.contributions.length); + for (let i = 0; i < mpcParams.contributions.length; i++) { + const c = mpcParams.contributions[i]; + await writeG1(c.deltaAfter); + await writeG1(c.delta.g1_s); + await writeG1(c.delta.g1_sx); + await writeG2(c.delta.g2_spx); + await fdTo.write(c.transcript); + } + const contributionHasher = _noble_hashes_blake2_js.blake2b.create({ dkLen: 64 }); + hashPubKey(contributionHasher, curve, curContribution); + const contributionHash = contributionHasher.digest(); + if (logger) logger.info(formatHash(contributionHash, "Contribution Hash: ")); + await fdTo.close(); + await fdFrom.close(); + return contributionHash; + async function copy(nBytes) { + const CHUNK_SIZE = fdFrom.pageSize * 2; + for (let i = 0; i < nBytes; i += CHUNK_SIZE) { + const n = Math.min(nBytes - i, CHUNK_SIZE); + const buff = await fdFrom.read(n); + await fdTo.write(buff); + } + } + async function readG1() { + const buff = await fdFrom.read(curve.G1.F.n8 * 2); + return curve.G1.fromRprUncompressed(buff, 0); + } + async function readG2() { + const buff = await fdFrom.read(curve.G2.F.n8 * 2); + return curve.G2.fromRprUncompressed(buff, 0); + } + async function writeG1(P) { + const buff = new Uint8Array(sG1); + curve.G1.toRprUncompressed(buff, 0, P); + await fdTo.write(buff); + } + async function writeG2(P) { + const buff = new Uint8Array(sG2); + curve.G2.toRprUncompressed(buff, 0, P); + await fdTo.write(buff); + } +} +//#endregion +//#region src/zkey_export_verificationkey.js +var { stringifyBigInts: stringifyBigInts$3 } = ffjavascript.utils; async function zkeyExportVerificationKey(zkeyName, logger) { - if (logger) logger.info("EXPORT VERIFICATION KEY STARTED"); - - const {fd, sections} = await binFileUtils__namespace.readBinFile(zkeyName, "zkey", 2); - const zkey = await readHeader$1(fd, sections); - - if (logger) logger.info("> Detected protocol: " + zkey.protocol); - - let res; - if (zkey.protocol === "groth16") { - res = await groth16Vk(zkey, fd, sections); - } else if (zkey.protocol === "plonk") { - res = await plonkVk(zkey); - } else if (zkey.protocolId && zkey.protocolId === FFLONK_PROTOCOL_ID) { - res = await exportFFlonkVk(zkey); - } else { - throw new Error("zkey file protocol unrecognized"); - } - - await fd.close(); - - if (logger) logger.info("EXPORT VERIFICATION KEY FINISHED"); - - return res; -} - - + if (logger) logger.info("EXPORT VERIFICATION KEY STARTED"); + const { fd, sections } = await _iden3_binfileutils.readBinFile(zkeyName, "zkey", 2); + const zkey = await readHeader$1(fd, sections); + if (logger) logger.info("> Detected protocol: " + zkey.protocol); + let res; + if (zkey.protocol === "groth16") res = await groth16Vk(zkey, fd, sections); + else if (zkey.protocol === "plonk") res = await plonkVk(zkey); + else if (zkey.protocolId && zkey.protocolId === 10) res = await exportFFlonkVk(zkey, logger); + else throw new Error("zkey file protocol unrecognized"); + await fd.close(); + if (logger) logger.info("EXPORT VERIFICATION KEY FINISHED"); + return res; +} async function groth16Vk(zkey, fd, sections) { - const curve = await getCurveFromQ(zkey.q); - const sG1 = curve.G1.F.n8 * 2; - - const alphaBeta = await curve.pairing(zkey.vk_alpha_1, zkey.vk_beta_2); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - - vk_alpha_1: curve.G1.toObject(zkey.vk_alpha_1), - - vk_beta_2: curve.G2.toObject(zkey.vk_beta_2), - vk_gamma_2: curve.G2.toObject(zkey.vk_gamma_2), - vk_delta_2: curve.G2.toObject(zkey.vk_delta_2), - - vk_alphabeta_12: curve.Gt.toObject(alphaBeta) - }; - - // Read IC Section - /////////// - await binFileUtils__namespace.startReadUniqueSection(fd, sections, 3); - vKey.IC = []; - for (let i = 0; i <= zkey.nPublic; i++) { - const buff = await fd.read(sG1); - const P = curve.G1.toObject(buff); - vKey.IC.push(P); - } - await binFileUtils__namespace.endReadSection(fd); - - vKey = stringifyBigInts$3(vKey); - - return vKey; -} - - + const curve = await getCurveFromQ(zkey.q); + const sG1 = curve.G1.F.n8 * 2; + const alphaBeta = await curve.pairing(zkey.vk_alpha_1, zkey.vk_beta_2); + let vKey = { + protocol: zkey.protocol, + curve: curve.name, + nPublic: zkey.nPublic, + vk_alpha_1: curve.G1.toObject(zkey.vk_alpha_1), + vk_beta_2: curve.G2.toObject(zkey.vk_beta_2), + vk_gamma_2: curve.G2.toObject(zkey.vk_gamma_2), + vk_delta_2: curve.G2.toObject(zkey.vk_delta_2), + vk_alphabeta_12: curve.Gt.toObject(alphaBeta) + }; + await _iden3_binfileutils.startReadUniqueSection(fd, sections, 3); + vKey.IC = []; + for (let i = 0; i <= zkey.nPublic; i++) { + const buff = await fd.read(sG1); + const P = curve.G1.toObject(buff); + vKey.IC.push(P); + } + await _iden3_binfileutils.endReadSection(fd); + vKey = stringifyBigInts$3(vKey); + return vKey; +} async function plonkVk(zkey) { - const curve = await getCurveFromQ(zkey.q); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - power: zkey.power, - - k1: curve.Fr.toObject(zkey.k1), - k2: curve.Fr.toObject(zkey.k2), - - Qm: curve.G1.toObject(zkey.Qm), - Ql: curve.G1.toObject(zkey.Ql), - Qr: curve.G1.toObject(zkey.Qr), - Qo: curve.G1.toObject(zkey.Qo), - Qc: curve.G1.toObject(zkey.Qc), - S1: curve.G1.toObject(zkey.S1), - S2: curve.G1.toObject(zkey.S2), - S3: curve.G1.toObject(zkey.S3), - - X_2: curve.G2.toObject(zkey.X_2), - - w: curve.Fr.toObject(curve.Fr.w[zkey.power]) - }; - - vKey = stringifyBigInts$3(vKey); - - return vKey; -} - + const curve = await getCurveFromQ(zkey.q); + let vKey = { + protocol: zkey.protocol, + curve: curve.name, + nPublic: zkey.nPublic, + power: zkey.power, + k1: curve.Fr.toObject(zkey.k1), + k2: curve.Fr.toObject(zkey.k2), + Qm: curve.G1.toObject(zkey.Qm), + Ql: curve.G1.toObject(zkey.Ql), + Qr: curve.G1.toObject(zkey.Qr), + Qo: curve.G1.toObject(zkey.Qo), + Qc: curve.G1.toObject(zkey.Qc), + S1: curve.G1.toObject(zkey.S1), + S2: curve.G1.toObject(zkey.S2), + S3: curve.G1.toObject(zkey.S3), + X_2: curve.G2.toObject(zkey.X_2), + w: curve.Fr.toObject(curve.Fr.w[zkey.power]) + }; + vKey = stringifyBigInts$3(vKey); + return vKey; +} async function exportFFlonkVk(zkey, logger) { - const curve = await getCurveFromQ(zkey.q); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - power: zkey.power, - - k1: curve.Fr.toObject(zkey.k1), - k2: curve.Fr.toObject(zkey.k2), - - w: curve.Fr.toObject(curve.Fr.w[zkey.power]), - //wW: curve.Fr.toObject(curve.Fr.w[zkey.power + 1]), - w3: curve.Fr.toObject(zkey.w3), - w4: curve.Fr.toObject(zkey.w4), - w8: curve.Fr.toObject(zkey.w8), - wr: curve.Fr.toObject(zkey.wr), - - X_2: curve.G2.toObject(zkey.X_2), - - C0: curve.G1.toObject(zkey.C0), - }; - - return stringifyBigInts$3(vKey); -} - -/* - Copyright 2021 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const {unstringifyBigInts: unstringifyBigInts$6, stringifyBigInts: stringifyBigInts$2} = ffjavascript.utils; - + const curve = await getCurveFromQ(zkey.q); + return stringifyBigInts$3({ + protocol: zkey.protocol, + curve: curve.name, + nPublic: zkey.nPublic, + power: zkey.power, + k1: curve.Fr.toObject(zkey.k1), + k2: curve.Fr.toObject(zkey.k2), + w: curve.Fr.toObject(curve.Fr.w[zkey.power]), + w3: curve.Fr.toObject(zkey.w3), + w4: curve.Fr.toObject(zkey.w4), + w8: curve.Fr.toObject(zkey.w8), + wr: curve.Fr.toObject(zkey.wr), + X_2: curve.G2.toObject(zkey.X_2), + C0: curve.G1.toObject(zkey.C0) + }); +} +//#endregion +//#region src/fflonk_export_solidity_verifier.js +var { unstringifyBigInts: unstringifyBigInts$6, stringifyBigInts: stringifyBigInts$2 } = ffjavascript.utils; async function fflonkExportSolidityVerifier(vk, templates, logger) { - if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER STARTED"); - - const curve = await getCurveFromName(vk.curve); - - // Precompute w3_2, w4_2 and w4_3 - let w3 = fromVkey(vk.w3); - vk.w3_2 = toVkey(curve.Fr.square(w3)); - - let w4 = fromVkey(vk.w4); - vk.w4_2 = toVkey(curve.Fr.square(w4)); - vk.w4_3 = toVkey(curve.Fr.mul(curve.Fr.square(w4), w4)); - - let w8 = fromVkey(vk.w8); - let acc = curve.Fr.one; - - for (let i = 1; i < 8; i++) { - acc = curve.Fr.mul(acc, w8); - vk["w8_" + i] = toVkey(acc); - } - - let template = templates[vk.protocol]; - - if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER FINISHED"); - - const {default: ejs} = await import('ejs'); - return ejs.render(template, vk); - - function fromVkey(str) { - const val = unstringifyBigInts$6(str); - return curve.Fr.fromObject(val); - } - - function toVkey(val) { - const str = curve.Fr.toObject(val); - return stringifyBigInts$2(str); - } -} - -// Not ready yet -// module.exports.generateVerifier_kimleeoh = generateVerifier_kimleeoh; - + if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER STARTED"); + const curve = await getCurveFromName(vk.curve); + let w3 = fromVkey(vk.w3); + vk.w3_2 = toVkey(curve.Fr.square(w3)); + let w4 = fromVkey(vk.w4); + vk.w4_2 = toVkey(curve.Fr.square(w4)); + vk.w4_3 = toVkey(curve.Fr.mul(curve.Fr.square(w4), w4)); + let w8 = fromVkey(vk.w8); + let acc = curve.Fr.one; + for (let i = 1; i < 8; i++) { + acc = curve.Fr.mul(acc, w8); + vk["w8_" + i] = toVkey(acc); + } + let template = templates[vk.protocol]; + if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER FINISHED"); + const { default: ejs } = await import("ejs"); + return ejs.render(template, vk); + function fromVkey(str) { + const val = unstringifyBigInts$6(str); + return curve.Fr.fromObject(val); + } + function toVkey(val) { + return stringifyBigInts$2(curve.Fr.toObject(val)); + } +} +//#endregion +//#region src/zkey_export_solidityverifier.js async function exportSolidityVerifier(zKeyName, templates, logger) { - - const verificationKey = await zkeyExportVerificationKey(zKeyName, logger); - - if ("fflonk" === verificationKey.protocol) { - return fflonkExportSolidityVerifier(verificationKey, templates, logger); - } - - let template = templates[verificationKey.protocol]; - - const {default: ejs} = await import('ejs'); - - return ejs.render(template, verificationKey); -} - -/* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - -var zkey = /*#__PURE__*/Object.freeze({ - __proto__: null, - beacon: beacon, - bellmanContribute: bellmanContribute, - contribute: phase2contribute, - exportBellman: phase2exportMPCParams, - exportJson: zkeyExportJson, - exportSolidityVerifier: exportSolidityVerifier, - exportVerificationKey: zkeyExportVerificationKey, - importBellman: phase2importMPCParams, - newZKey: newZKey, - verifyFromInit: phase2verifyFromInit, - verifyFromR1cs: phase2verifyFromR1cs + const verificationKey = await zkeyExportVerificationKey(zKeyName, logger); + if ("fflonk" === verificationKey.protocol) return fflonkExportSolidityVerifier(verificationKey, templates, logger); + let template = templates[verificationKey.protocol]; + const { default: ejs } = await import("ejs"); + return ejs.render(template, verificationKey); +} +//#endregion +//#region src/zkey.js +var zkey_exports = /* @__PURE__ */ __exportAll({ + beacon: () => beacon, + bellmanContribute: () => bellmanContribute, + contribute: () => phase2contribute, + exportBellman: () => phase2exportMPCParams, + exportJson: () => zkeyExportJson, + exportSolidityVerifier: () => exportSolidityVerifier, + exportVerificationKey: () => zkeyExportVerificationKey, + importBellman: () => phase2importMPCParams, + newZKey: () => newZKey, + verifyFromInit: () => phase2verifyFromInit, + verifyFromR1cs: () => phase2verifyFromR1cs }); - -/* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - - +//#endregion +//#region src/plonk_setup.js async function plonkSetup(r1csName, ptauName, zkeyName, logger) { - - if (globalThis.gc) {globalThis.gc();} - - const {fd: fdPTau, sections: sectionsPTau} = await binFileUtils.readBinFile(ptauName, "ptau", 1, 1<<22, 1<<24); - const {curve, power} = await readPTauHeader(fdPTau, sectionsPTau); - const {fd: fdR1cs, sections: sectionsR1cs} = await binFileUtils.readBinFile(r1csName, "r1cs", 1, 1<<22, 1<<24); - - const r1cs = await r1csfile.readR1csFd(fdR1cs, sectionsR1cs, {loadConstraints: true, loadCustomGates: true}); - - const sG1 = curve.G1.F.n8*2; - const G1 = curve.G1; - const sG2 = curve.G2.F.n8*2; - const Fr = curve.Fr; - const n8r = curve.Fr.n8; - - if (logger) logger.info("Reading r1cs"); - - const plonkConstraints = new BigArray(); - const plonkAdditions = new BigArray(); - let plonkNVars = r1cs.nVars; - - const nPublic = r1cs.nOutputs + r1cs.nPubInputs; - - await processConstraints(curve.Fr, r1cs, logger); - - if (globalThis.gc) {globalThis.gc();} - - const fdZKey = await binFileUtils.createBinFile(zkeyName, "zkey", 1, 14, 1<<22, 1<<24); - - - if (r1cs.prime != curve.r) { - if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); - return -1; - } - - let cirPower = log2(plonkConstraints.length -1) +1; - if (cirPower < 3) cirPower = 3; // As the t polynomial is n+5 we need at least a power of 4 - const domainSize = 2 ** cirPower; - - if (logger) logger.info("Plonk constraints: " + plonkConstraints.length); - if (cirPower > power) { - if (logger) logger.error(`circuit too big for this power of tau ceremony. ${plonkConstraints.length} > 2**${power}`); - return -1; - } - - if (!sectionsPTau[12]) { - if (logger) logger.error("Powers of tau is not prepared."); - return -1; - } - - - const LPoints = new ffjavascript.BigBuffer(domainSize*sG1); - const o = sectionsPTau[12][0].p + ((2 ** (cirPower)) -1)*sG1; - await fdPTau.readToBuffer(LPoints, 0, domainSize*sG1, o); - - const [k1, k2] = getK1K2(); - - const vk = {}; - - - await writeAdditions(3, "Additions"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(4, 0, "Amap"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(5, 1, "Bmap"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(6, 2, "Cmap"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(7, 3, "Qm"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(8, 4, "Ql"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(9, 5, "Qr"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(10, 6, "Qo"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(11, 7, "Qc"); - if (globalThis.gc) {globalThis.gc();} - await writeSigma(12, "sigma"); - if (globalThis.gc) {globalThis.gc();} - await writeLs(13, "lagrange polynomials"); - if (globalThis.gc) {globalThis.gc();} - - // Write PTau points - //////////// - - await binFileUtils.startWriteSection(fdZKey, 14); - const buffOut = new ffjavascript.BigBuffer((domainSize+6)*sG1); - await fdPTau.readToBuffer(buffOut, 0, (domainSize+6)*sG1, sectionsPTau[2][0].p); - await fdZKey.write(buffOut); - await binFileUtils.endWriteSection(fdZKey); - if (globalThis.gc) {globalThis.gc();} - - - await writeHeaders(); - - await fdZKey.close(); - await fdR1cs.close(); - await fdPTau.close(); - - if (logger) logger.info("Setup Finished"); - - return ; - - async function processConstraints(Fr, r1cs, logger) { - - function normalize(linearComb) { - const ss = Object.keys(linearComb); - for (let i = 0; i < ss.length; i++) { - if (linearComb[ss[i]] == 0n) delete linearComb[ss[i]]; - } - } - - function join(linearComb1, k, linearComb2) { - const res = {}; - - for (let s in linearComb1) { - if (typeof res[s] == "undefined") { - res[s] = Fr.mul(k, linearComb1[s]); - } else { - res[s] = Fr.add(res[s], Fr.mul(k, linearComb1[s])); - } - } - - for (let s in linearComb2) { - if (typeof res[s] == "undefined") { - res[s] = linearComb2[s]; - } else { - res[s] = Fr.add(res[s], linearComb2[s]); - } - } - normalize(res); - return res; - } - - function reduceCoefs(linearComb, maxC) { - const res = { - k: Fr.zero, - s: [], - coefs: [] - }; - const cs = []; - - for (let s in linearComb) { - if (s == 0) { - res.k = Fr.add(res.k, linearComb[s]); - } else if (linearComb[s] != 0n) { - cs.push([Number(s), linearComb[s]]); - } - } - while (cs.length > maxC) { - const c1 = cs.shift(); - const c2 = cs.shift(); - - const sl = c1[0]; - const sr = c2[0]; - const so = plonkNVars++; - const qm = Fr.zero; - const ql = Fr.neg(c1[1]); - const qr = Fr.neg(c2[1]); - const qo = Fr.one; - const qc = Fr.zero; - - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - - plonkAdditions.push([sl, sr, c1[1], c2[1]]); - - cs.push([so, Fr.one]); - } - for (let i = 0; i < cs.length; i++) { - res.s[i] = cs[i][0]; - res.coefs[i] = cs[i][1]; - } - while (res.coefs.length < maxC) { - res.s.push(0); - res.coefs.push(Fr.zero); - } - return res; - } - - function addConstraintSum(lc) { - const C = reduceCoefs(lc, 3); - const sl = C.s[0]; - const sr = C.s[1]; - const so = C.s[2]; - const qm = Fr.zero; - const ql = C.coefs[0]; - const qr = C.coefs[1]; - const qo = C.coefs[2]; - const qc = C.k; - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - function addConstraintMul(lcA, lcB, lcC) { - const A = reduceCoefs(lcA, 1); - const B = reduceCoefs(lcB, 1); - const C = reduceCoefs(lcC, 1); - - - const sl = A.s[0]; - const sr = B.s[0]; - const so = C.s[0]; - const qm = Fr.mul(A.coefs[0], B.coefs[0]); - const ql = Fr.mul(A.coefs[0], B.k); - const qr = Fr.mul(A.k, B.coefs[0]); - const qo = Fr.neg(C.coefs[0]); - const qc = Fr.sub(Fr.mul(A.k, B.k), C.k); - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - function getLinearCombinationType(lc) { - let k = Fr.zero; - let n = 0; - const ss = Object.keys(lc); - for (let i = 0; i < ss.length; i++) { - if (lc[ss[i]] == 0n) { - delete lc[ss[i]]; - } else if (ss[i] == 0) { - k = Fr.add(k, lc[ss[i]]); - } else { - n++; - } - } - if (n > 0) return n.toString(); - if (k != Fr.zero) return "k"; - return "0"; - } - - function process(lcA, lcB, lcC) { - const lctA = getLinearCombinationType(lcA); - const lctB = getLinearCombinationType(lcB); - if ((lctA === "0") || (lctB === "0")) { - normalize(lcC); - addConstraintSum(lcC); - } else if (lctA === "k") { - const lcCC = join(lcB, lcA[0], lcC); - addConstraintSum(lcCC); - } else if (lctB === "k") { - const lcCC = join(lcA, lcB[0], lcC); - addConstraintSum(lcCC); - } else { - addConstraintMul(lcA, lcB, lcC); - } - } - - for (let s = 1; s <= nPublic; s++) { - const sl = s; - const sr = 0; - const so = 0; - const qm = Fr.zero; - const ql = Fr.one; - const qr = Fr.zero; - const qo = Fr.zero; - const qc = Fr.zero; - - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - for (let c = 0; c < r1cs.constraints.length; c++) { - if ((logger) && (c % 10000 === 0)) logger.debug(`processing constraints: ${c}/${r1cs.nConstraints}`); - process(...r1cs.constraints[c]); - } - } - - async function writeWitnessMap(sectionNum, posConstraint, name) { - await binFileUtils.startWriteSection(fdZKey, sectionNum); - for (let i=0; i. -*/ - -class Proof { - constructor(curve, logger) { - this.curve = curve; - this.logger = logger; - - this.resetProof(); - } - - resetProof() { - this.polynomials = {}; - this.evaluations = {}; - } - - addPolynomial(key, polynomial) { - if (key in this.polynomials) { - this.logger.warn(`proof: polynomial.${key} already exist in proof`); - } - this.polynomials[key] = polynomial; - } - - getPolynomial(key) { - if (!(key in this.polynomials)) { - this.logger.warn(`proof: polynomial ${key} does not exist in proof`); - } - return this.polynomials[key]; - } - - addEvaluation(key, evaluation) { - if (key in this.evaluations) { - this.logger.warn(`proof: evaluations.${key} already exist in proof`); - } - this.evaluations[key] = evaluation; - } - - getEvaluation(key) { - if (!(key in this.evaluations)) { - this.logger.warn(`proof: evaluation ${key} does not exist in proof`); - } - return this.evaluations[key]; - } - - toObjectProof(splitFields = true) { - let res = splitFields ? {polynomials: {}, evaluations: {}} : {}; - - Object.keys(this.polynomials).forEach(key => { - const value = this.curve.G1.toObject(this.polynomials[key]); - if(splitFields) { - res.polynomials[key] = value; - } else { - res[key] = value; - } - }); - - Object.keys(this.evaluations).forEach(key => { - const value = this.curve.Fr.toObject(this.evaluations[key]); - if(splitFields) { - res.evaluations[key] = value; - } else { - res[key] = value; - } - }); - - return res; - } - - fromObjectProof(objectProof) { - this.resetProof(); - - Object.keys(objectProof.polynomials).forEach(key => { - this.polynomials[key] = this.curve.G1.fromObject(objectProof.polynomials[key]); - }); - - Object.keys(objectProof.evaluations).forEach(key => { - this.evaluations[key] = this.curve.Fr.fromObject(objectProof.evaluations[key]); - }); - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const POLYNOMIAL = 0; -const SCALAR = 1; - -class Keccak256Transcript { - constructor(curve) { - this.G1 = curve.G1; - this.Fr = curve.Fr; - - this.reset(); - } - - reset() { - this.data = []; - } - - addPolCommitment(polynomialCommitment) { - this.data.push({type: POLYNOMIAL, data: polynomialCommitment}); - } - - addScalar(scalar) { - this.data.push({type: SCALAR, data: scalar}); - } - - getChallenge() { - if(0 === this.data.length) { - throw new Error("Keccak256Transcript: No data to generate a transcript"); - } - - let nPolynomials = 0; - let nScalars = 0; - - this.data.forEach(element => POLYNOMIAL === element.type ? nPolynomials++ : nScalars++); - - let buffer = new Uint8Array(nScalars * this.Fr.n8 + nPolynomials * this.G1.F.n8 * 2); - let offset = 0; - - for (let i = 0; i < this.data.length; i++) { - if (POLYNOMIAL === this.data[i].type) { - this.G1.toRprUncompressed(buffer, offset, this.data[i].data); - offset += this.G1.F.n8 * 2; - } else { - this.Fr.toRprBE(buffer, offset, this.data[i].data); - offset += this.Fr.n8; - } - } - - const value = ffjavascript.Scalar.fromRprBE(sha3_js.keccak_256(buffer)); - return this.Fr.e(value); - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -class MulZ { - static getZ1(Fr) { - return [ - Fr.zero, - Fr.add(Fr.e(-1), Fr.w[2]), - Fr.e(-2), - Fr.sub(Fr.e(-1), Fr.w[2]), - ]; - } - - static getZ2(Fr) { - return [ - Fr.zero, - Fr.add(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), - Fr.e(4), - Fr.sub(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), - ]; - } - - static getZ3(Fr) { - return [ - Fr.zero, - Fr.add(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), - Fr.e(-8), - Fr.sub(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), - ]; - - } - - static mul2(a, b, ap, bp, p, Fr) { - const Z1 = this.getZ1(Fr); - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - r = a_b; - - let a0 = Fr.add(a_bp, ap_b); - - let a1 = ap_bp; - - rz = a0; - if (p) { - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - } - - return [r, rz]; - } - - static mul3(a, b, c, ap, bp, cp, p, Fr) { - const Z1 = this.getZ1(Fr); - const Z2 = this.getZ2(Fr); - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - r = Fr.mul(a_b, c); - - let a0 = Fr.mul(ap_b, c); - a0 = Fr.add(a0, Fr.mul(a_bp, c)); - a0 = Fr.add(a0, Fr.mul(a_b, cp)); - - let a1 = Fr.mul(ap_bp, c); - a1 = Fr.add(a1, Fr.mul(a_bp, cp)); - a1 = Fr.add(a1, Fr.mul(ap_b, cp)); - - rz = a0; - if (p) { - const a2 = Fr.mul(ap_bp, cp); - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - rz = Fr.add(rz, Fr.mul(Z2[p], a2)); - } - - return [r, rz]; - } - - static mul4(a, b, c, d, ap, bp, cp, dp, p, Fr) { - const Z1 = this.getZ1(Fr); - const Z2 = this.getZ2(Fr); - const Z3 = this.getZ3(Fr); - - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - const c_d = Fr.mul(c, d); - const c_dp = Fr.mul(c, dp); - const cp_d = Fr.mul(cp, d); - const cp_dp = Fr.mul(cp, dp); - - r = Fr.mul(a_b, c_d); - - let a0 = Fr.mul(ap_b, c_d); - a0 = Fr.add(a0, Fr.mul(a_bp, c_d)); - a0 = Fr.add(a0, Fr.mul(a_b, cp_d)); - a0 = Fr.add(a0, Fr.mul(a_b, c_dp)); - - let a1 = Fr.mul(ap_bp, c_d); - a1 = Fr.add(a1, Fr.mul(ap_b, cp_d)); - a1 = Fr.add(a1, Fr.mul(ap_b, c_dp)); - a1 = Fr.add(a1, Fr.mul(a_bp, cp_d)); - a1 = Fr.add(a1, Fr.mul(a_bp, c_dp)); - a1 = Fr.add(a1, Fr.mul(a_b, cp_dp)); - - let a2 = Fr.mul(a_bp, cp_dp); - a2 = Fr.add(a2, Fr.mul(ap_b, cp_dp)); - a2 = Fr.add(a2, Fr.mul(ap_bp, c_dp)); - a2 = Fr.add(a2, Fr.mul(ap_bp, cp_d)); - - let a3 = Fr.mul(ap_bp, cp_dp); - - rz = a0; - if (p) { - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - rz = Fr.add(rz, Fr.mul(Z2[p], a2)); - rz = Fr.add(rz, Fr.mul(Z3[p], a3)); - } - - return [r, rz]; - } -} - -const ZKEY_PL_ADDITIONS_SECTION = 3; -const ZKEY_PL_A_MAP_SECTION = 4; -const ZKEY_PL_B_MAP_SECTION = 5; -const ZKEY_PL_C_MAP_SECTION = 6; -const ZKEY_PL_QM_SECTION = 7; -const ZKEY_PL_QL_SECTION = 8; -const ZKEY_PL_QR_SECTION = 9; -const ZKEY_PL_QO_SECTION = 10; -const ZKEY_PL_QC_SECTION = 11; -const ZKEY_PL_SIGMA_SECTION = 12; -const ZKEY_PL_LAGRANGE_SECTION = 13; -const ZKEY_PL_PTAU_SECTION = 14; - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -class Polynomial { - constructor(coefficients, curve, logger) { - this.coef = coefficients; - this.curve = curve; - this.Fr = curve.Fr; - this.G1 = curve.G1; - this.logger = logger; - } - - static async fromEvaluations(buffer, curve, logger) { - let coefficients = await curve.Fr.ifft(buffer); - - return new Polynomial(coefficients, curve, logger); - } - - static fromCoefficientsArray(array, curve, logger) { - const Fr = curve.Fr; - let buff = array.length > 2 << 14 ? - new ffjavascript.BigBuffer(array.length * Fr.n8) : new Uint8Array(array.length * Fr.n8); - for (let i = 0; i < array.length; i++) buff.set(array[i], i * Fr.n8); - - return new Polynomial(buff, curve, logger); - } - - static fromPolynomial(polynomial, curve, logger) { - let length = polynomial.length(); - let Fr = curve.Fr; - - let buff = length > 2 << 14 ? - new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - buff.set(polynomial.coef.slice(), 0); - - return new Polynomial(buff, curve, logger); - } - - isEqual(polynomial) { - const degree = this.degree(); - if (degree !== polynomial.degree()) return false; - - for (let i = 0; i < degree + 1; i++) { - if (!this.Fr.eq(this.getCoef(i), polynomial.getCoef(i))) return false; - } - - return true; - } - - blindCoefficients(blindingFactors) { - blindingFactors = blindingFactors || []; - - const blindedCoefficients = (this.length() + blindingFactors.length) > 2 << 14 ? - new ffjavascript.BigBuffer((this.length() + blindingFactors.length) * this.Fr.n8) : - new Uint8Array((this.length() + blindingFactors.length) * this.Fr.n8); - - blindedCoefficients.set(this.coef, 0); - for (let i = 0; i < blindingFactors.length; i++) { - blindedCoefficients.set( - this.Fr.add( - blindedCoefficients.slice((this.length() + i) * this.Fr.n8, (this.length() + i + 1) * this.Fr.n8), - blindingFactors[i] - ), - (this.length() + i) * this.Fr.n8 - ); - blindedCoefficients.set( - this.Fr.sub( - blindedCoefficients.slice(i * this.Fr.n8, (i + 1) * this.Fr.n8), - blindingFactors[i] - ), - i * this.Fr.n8 - ); - } - this.coef = blindedCoefficients; - } - - getCoef(index) { - const i_n8 = index * this.Fr.n8; - - if (i_n8 + this.Fr.n8 > this.coef.byteLength) return this.Fr.zero; - - return this.coef.slice(i_n8, i_n8 + this.Fr.n8); - } - - setCoef(index, value) { - if (index > (this.length() - 1)) { - throw new Error("Coef index is not available"); - } - - this.coef.set(value, index * this.Fr.n8); - } - - static async to4T(buffer, domainSize, blindingFactors, Fr) { - blindingFactors = blindingFactors || []; - let a = await Fr.ifft(buffer); - - const a4 = (domainSize * 4) > 2 << 14 ? - new ffjavascript.BigBuffer(domainSize * 4 * Fr.n8) : new Uint8Array(domainSize * 4 * Fr.n8); - a4.set(a, 0); - - const A4 = await Fr.fft(a4); - - if (blindingFactors.length === 0) { - return [a, A4]; - } - - const a1 = domainSize + blindingFactors.length > 2 << 14 ? - new ffjavascript.BigBuffer((domainSize + blindingFactors.length) * Fr.n8) : - new Uint8Array((domainSize + blindingFactors.length) * Fr.n8); - - a1.set(a, 0); - for (let i = 0; i < blindingFactors.length; i++) { - a1.set( - Fr.add( - a1.slice((domainSize + i) * Fr.n8, (domainSize + i + 1) * Fr.n8), - blindingFactors[i] - ), - (domainSize + i) * Fr.n8 - ); - a1.set( - Fr.sub( - a1.slice(i * Fr.n8, (i + 1) * Fr.n8), - blindingFactors[i] - ), - i * Fr.n8 - ); - } - - return [a1, A4]; - } - - length() { - let length = this.coef.byteLength / this.Fr.n8; - if (length !== Math.floor(this.coef.byteLength / this.Fr.n8)) { - throw new Error("Polynomial coefficients buffer has incorrect size"); - } - if (0 === length) { - if (this.logger) { - this.logger.warn("Polynomial has length zero"); - } - } - return length; - } - - degree() { - for (let i = this.length() - 1; i > 0; i--) { - const i_n8 = i * this.Fr.n8; - if (!this.Fr.eq(this.Fr.zero, this.coef.slice(i_n8, i_n8 + this.Fr.n8))) { - return i; - } - } - - return 0; - } - - evaluate(point) { - let res = this.Fr.zero; - - for (let i = this.degree() + 1; i > 0; i--) { - let i_n8 = i * this.Fr.n8; - const currentCoefficient = this.coef.slice(i_n8 - this.Fr.n8, i_n8); - res = this.Fr.add(currentCoefficient, this.Fr.mul(res, point)); - } - - return res; - } - - fastEvaluate(point) { - const Fr = this.Fr; - let nThreads = 3; - - let nCoefs = this.degree() + 1; - let coefsThread = parseInt(nCoefs / nThreads); - let residualCoefs = nCoefs - coefsThread * nThreads; - - let res = []; - let xN = []; - - xN[0] = Fr.one; - - for (let i = 0; i < nThreads; i++) { - res[i] = Fr.zero; - - let nCoefs = i === (nThreads - 1) ? coefsThread + residualCoefs : coefsThread; - for (let j = nCoefs; j > 0; j--) { - res[i] = Fr.add(this.getCoef((i * coefsThread) + j - 1), Fr.mul(res[i], point)); - - if (i === 0) xN[0] = Fr.mul(xN[0], point); - } - } - - for (let i = 1; i < nThreads; i++) { - res[0] = Fr.add(res[0], Fr.mul(xN[i - 1], res[i])); - xN[i] = Fr.mul(xN[i - 1], xN[0]); - } - - return res[0]; - } - - add(polynomial, blindingValue) { - let other = false; - - if (polynomial.length() > this.length()) { - other = true; - } - - const thisLength = this.length(); - const polyLength = polynomial.length(); - for (let i = 0; i < Math.max(thisLength, polyLength); i++) { - const i_n8 = i * this.Fr.n8; - - const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - - if (blindingValue !== undefined) { - b = this.Fr.mul(b, blindingValue); - } - if (other) { - polynomial.coef.set(this.Fr.add(a, b), i_n8); - } else { - this.coef.set(this.Fr.add(a, b), i_n8); - } - } - if (other) { - delete this.coef; - this.coef = polynomial.coef; - } - } - - sub(polynomial, blindingValue) { - let other = false; - - if (polynomial.length() > this.length()) { - other = true; - } - - const thisLength = this.length(); - const polyLength = polynomial.length(); - for (let i = 0; i < Math.max(thisLength, polyLength); i++) { - const i_n8 = i * this.Fr.n8; - - const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - - if (blindingValue !== undefined) { - b = this.Fr.mul(b, blindingValue); - } - if (other) { - polynomial.coef.set(this.Fr.sub(a, b), i_n8); - } else { - this.coef.set(this.Fr.sub(a, b), i_n8); - } - } - if (other) { - delete this.coef; - this.coef = polynomial.coef; - } - } - - mulScalar(value) { - for (let i = 0; i < this.length(); i++) { - const i_n8 = i * this.Fr.n8; - - this.coef.set(this.Fr.mul(this.coef.slice(i_n8, i_n8 + this.Fr.n8), value), i_n8); - } - } - - addScalar(value) { - const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); - this.coef.set(this.Fr.add(currentValue, value), 0); - } - - subScalar(value) { - const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); - this.coef.set(this.Fr.sub(currentValue, value), 0); - } - - // Multiply current polynomial by the polynomial (X - value) - byXSubValue(value) { - const Fr = this.Fr; - const resize = !Fr.eq(Fr.zero, this.getCoef(this.length() - 1)); - - const length = resize ? this.length() + 1 : this.length(); - const buff = length > 2 << 14 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - let pol = new Polynomial(buff, this.curve, this.logger); - - // Step 0: Set current coefficients to the new buffer shifted one position - pol.coef.set(this.coef.slice(0, (length - 1) * Fr.n8), 32); - - // Step 1: multiply each coefficient by (-value) - this.mulScalar(Fr.neg(value)); - - // Step 2: Add current polynomial to destination polynomial - pol.add(this); - - // Swap buffers - this.coef = pol.coef; - } - - // Multiply current polynomial by the polynomial (X^n + value) - byXNSubValue(n, value) { - const Fr = this.Fr; - const resize = !(this.length() - n - 1 >= this.degree()); - - const length = resize ? this.length() + n : this.length(); - const buff = length > 2 << 14 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - let pol = new Polynomial(buff, this.curve, this.logger); - - // Step 0: Set current coefficients to the new buffer shifted one position - pol.coef.set(this.coef.slice(0, (this.degree() + 1) * 32, ), n * 32); - - // Step 1: multiply each coefficient by (- value) - this.mulScalar(value); - - // Step 2: Add current polynomial to destination polynomial - pol.add(this); - - // Swap buffers - this.coef = pol.coef; - } - - // Euclidean division - divBy(polynomial) { - const Fr = this.Fr; - const degreeA = this.degree(); - const degreeB = polynomial.degree(); - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - for (let i = degreeA - degreeB; i >= 0; i--) { - this.setCoef(i, Fr.div(polR.getCoef(i + degreeB), polynomial.getCoef(degreeB))); - for (let j = 0; j <= degreeB; j++) { - polR.setCoef(i + j, Fr.sub(polR.getCoef(i + j), Fr.mul(this.getCoef(i), polynomial.getCoef(j)))); - } - } - - return polR; - } - - // Division by a Polynomial of the form (x^m - beta) - divByMonic(m, beta) { - const Fr = this.Fr; - - let d = this.degree(); - - let buffer = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - let quotient = new Polynomial(buffer, this.curve, this.logger); - - let bArr = []; - - // Add the m leading coefficients of this to quotient - for (let i = 0; i < m; i++) { - quotient.setCoef((d - i) - m, this.getCoef(d - i)); - bArr[i] = this.getCoef(d - i); - } - - let nThreads = m; - for (let k = 0; k < nThreads; k++) { - for (let i = d - 2 * m - k; i >= 0; i = i - nThreads) { - if (i < 0) break; - let idx = k; - bArr[idx] = Fr.add(this.getCoef(i + m), Fr.mul(bArr[idx], beta)); - - quotient.setCoef(i, bArr[idx]); - } - } - - this.coef = quotient.coef; - } - - divByVanishing(n, beta) { - if (this.degree() < n) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - const Fr = this.Fr; - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - for (let i = this.length() - 1; i >= n; i--) { - let leadingCoef = polR.getCoef(i); - if (Fr.eq(Fr.zero, leadingCoef)) continue; - - polR.setCoef(i, Fr.zero); - polR.setCoef(i - n, Fr.add(polR.getCoef(i - n), Fr.mul(beta, leadingCoef))); - this.setCoef(i - n, Fr.add(this.getCoef(i - n), leadingCoef)); - } - - return polR; - } - - divByVanishing2(m, beta) { - if (this.degree() < m) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - const Fr = this.Fr; - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - let nThreads = 3; - let nTotal = this.length() - m; - let nElementsChunk = Math.floor(nTotal / nThreads); - let nElementsLast = nTotal - (nThreads - 1) * nElementsChunk; - - console.log(nTotal); - console.log(nElementsChunk + " " + nElementsLast); - for (let k = 0; k < nThreads; k++) { - console.log("> Thread " + k); - for (let i = (k === 0 ? nElementsLast : nElementsChunk); i > 0; i--) { - let idxDst = i - 1; - if (k !== 0) idxDst += (k - 1) * nElementsChunk + nElementsLast; - let idxSrc = idxDst + m; - - let leadingCoef = polR.getCoef(idxSrc); - if (Fr.eq(Fr.zero, leadingCoef)) continue; - - polR.setCoef(idxSrc, Fr.zero); - polR.setCoef(idxDst, Fr.add(polR.getCoef(idxDst), Fr.mul(beta, leadingCoef))); - this.setCoef(idxDst, Fr.add(this.getCoef(idxDst), leadingCoef)); - console.log(idxDst + " <-- " + idxSrc); - } - } - - this.print(); - return polR; - } - - fastDivByVanishing(data) { - const Fr = this.Fr; - - for (let i = 0; i < data.length; i++) { - - let m = data[i][0]; - let beta = data[i][1]; - - if (this.degree() < m) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - let nThreads = 5; - let nElements = this.length() - m; - let nElementsBucket = Math.floor(nElements / nThreads / m); - let nElementsChunk = nElementsBucket * m; - let nElementsLast = nElements - nThreads * nElementsChunk; - - //In C++ implementation this buffer will be allocated only once outside the loop - let polTmp = new Polynomial(this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8), this.curve, this.logger); - - let ptr = this.coef; - this.coef = polTmp.coef; - polTmp.coef = ptr; - - // STEP 1: Setejar els m valors del següent bucket al chunk actual, PARALEL·LITZAR - for (let k = 0; k < nThreads; k++) { - let idx0 = (k + 1) * nElementsChunk + nElementsLast; - for (let i = 0; i < m; i++) { - this.setCoef(idx0 + i - m, polTmp.getCoef(idx0 + i)); - } - - for (let i = 0; i < nElementsChunk - m; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); - this.setCoef(offset - m, val); - } - } - - //STEP 2: Setejar els valors del elements last NO PARAL·LELITZAR - let idx0 = nElementsLast; - let pending = nElementsLast; - for (let i = 0; i < m && pending; i++) { - this.setCoef(idx0 - i - 1, polTmp.getCoef(idx0 + m - i - 1)); - pending--; - } - - for (let i = 0; i < pending; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); - this.setCoef(offset - m, val); - } - - //Step 3: calcular acumulats NO PARALEL·LITZAR - - let acc = []; - let betaPow = Fr.one; - for (let i = 0; i < nElementsBucket; i++) { - betaPow = Fr.mul(betaPow, beta); - } - let currentBeta = Fr.one; - - for (let k = nThreads; k > 0; k--) { - let idThread = k - 1; - let idx0 = idThread * nElementsChunk + nElementsLast; - acc[idThread] = []; - - for (let i = 0; i < m; i++) { - acc[idThread][i] = this.getCoef(idx0 + i); - - if (k !== nThreads) { - acc[idThread][i] = Fr.add(acc[idThread][i], Fr.mul(betaPow, acc[idThread + 1][i])); - } - } - currentBeta = Fr.mul(currentBeta, betaPow); - } - - //STEP 4 recalcular PARALEL·LITZAR - for (let k = 0; k < nThreads; k++) { - - let idx0 = k * nElementsChunk + nElementsLast; - let currentBeta = beta; //Quan hopassem a C++ i ho paralelitzem aquesta variable ha de ser privada - let currentM = m - 1; - - let limit = k === 0 ? nElementsLast : nElementsChunk; - for (let i = 0; i < limit; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(this.getCoef(offset), Fr.mul(currentBeta, acc[k][currentM])); - - this.setCoef(offset, val); - - // To avoid modular operations in each loop... - if (currentM === 0) { - currentM = m - 1; - currentBeta = Fr.mul(currentBeta, beta); - } else { - currentM--; - } - } - } - } - } - - - // Divide polynomial by X - value - divByXSubValue(value) { - const coefs = this.length() > 2 << 14 ? - new ffjavascript.BigBuffer(this.length() * this.Fr.n8) : new Uint8Array(this.length() * this.Fr.n8); - - coefs.set(this.Fr.zero, (this.length() - 1) * this.Fr.n8); - coefs.set(this.coef.slice((this.length() - 1) * this.Fr.n8, this.length() * this.Fr.n8), (this.length() - 2) * this.Fr.n8); - for (let i = this.length() - 3; i >= 0; i--) { - let i_n8 = i * this.Fr.n8; - coefs.set( - this.Fr.add( - this.coef.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8), - this.Fr.mul(value, coefs.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8)) - ), - i * this.Fr.n8 - ); - } - if (!this.Fr.eq( - this.coef.slice(0, this.Fr.n8), - this.Fr.mul(this.Fr.neg(value), coefs.slice(0, this.Fr.n8)) - )) { - throw new Error("Polynomial does not divide"); - } - - this.coef = coefs; - } - - divZh(domainSize, extensions = 4) { - for (let i = 0; i < domainSize; i++) { - const i_n8 = i * this.Fr.n8; - this.coef.set(this.Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)), i_n8); - } - - const upperBound = this.coef.byteLength / this.Fr.n8; - for (let i = domainSize; i < upperBound; i++) { - const i_n8 = i * this.Fr.n8; - - const a = this.Fr.sub( - this.coef.slice((i - domainSize) * this.Fr.n8, (i - domainSize) * this.Fr.n8 + this.Fr.n8), - this.coef.slice(i_n8, i_n8 + this.Fr.n8) - ); - this.coef.set(a, i_n8); - if (i > (domainSize * (extensions-1) - extensions)) { - if (!this.Fr.isZero(a)) { - throw new Error("Polynomial is not divisible"); - } - } - } - - return this; - } - - divByZerofier(n, beta) { - let Fr = this.Fr; - const invBeta = Fr.inv(beta); - const invBetaNeg = Fr.neg(invBeta); - - let isOne = Fr.eq(Fr.one, invBetaNeg); - let isNegOne = Fr.eq(Fr.negone, invBetaNeg); - - if (!isOne) { - for (let i = 0; i < n; i++) { - const i_n8 = i * this.Fr.n8; - let element; - - // If invBetaNeg === -1 we'll save a multiplication changing it by a neg function call - if (isNegOne) { - element = Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)); - } else { - element = Fr.mul(invBetaNeg, this.coef.slice(i_n8, i_n8 + this.Fr.n8)); - } - - this.coef.set(element, i_n8); - } - } - - isOne = Fr.eq(Fr.one, invBeta); - isNegOne = Fr.eq(Fr.negone, invBeta); - - for (let i = n; i < this.length(); i++) { - const i_n8 = i * this.Fr.n8; - const i_prev_n8 = (i - n) * this.Fr.n8; - - let element = this.Fr.sub( - this.coef.slice(i_prev_n8, i_prev_n8 + this.Fr.n8), - this.coef.slice(i_n8, i_n8 + this.Fr.n8) - ); - - // If invBeta === 1 we'll not do anything - if(!isOne) { - // If invBeta === -1 we'll save a multiplication changing it by a neg function call - if(isNegOne) { - element = Fr.neg(element); - } else { - element = Fr.mul(invBeta, element); - } - } - - this.coef.set(element, i_n8); - - // Check if polynomial is divisible by checking if n high coefficients are zero - if (i > this.length() - n - 1) { - if (!this.Fr.isZero(element)) { - throw new Error("Polynomial is not divisible"); - } - } - } - - return this; - } - - // function divideByVanishing(f, n, p) { - // // polynomial division f(X) / (X^n - 1) with remainder - // // very cheap, 0 multiplications - // // strategy: - // // start with q(X) = 0, r(X) = f(X) - // // then start changing q, r while preserving the identity: - // // f(X) = q(X) * (X^n - 1) + r(X) - // // in every step, move highest-degree term of r into the product - // // => r eventually has degree < n and we're done - // let q = Array(f.length).fill(0n); - // let r = [...f]; - // for (let i = f.length - 1; i >= n; i--) { - // let leadingCoeff = r[i]; - // if (leadingCoeff === 0n) continue; - // r[i] = 0n; - // r[i - n] = mod(r[i - n] + leadingCoeff, p); - // q[i - n] = mod(q[i - n] + leadingCoeff, p); - // } - // return [q, r]; - // } - - byX() { - const coefs = (this.length() + 1) > 2 << 14 ? - new ffjavascript.BigBuffer(this.coef.byteLength + this.Fr.n8) : new Uint8Array(this.coef.byteLength + this.Fr.n8); - coefs.set(this.Fr.zero, 0); - coefs.set(this.coef, this.Fr.n8); - - this.coef = coefs; - } - - // Compute a new polynomial f(x^n) from f(x) - // f(x) = a_0 + a_1·x + a_2·x^2 + ... + a_j·x^j - // f(x^n) = a_0 + a_1·x^n + a_2·x^2n + ... + a_j·x^jn - static - async expX(polynomial, n, truncate = false) { - const Fr = polynomial.Fr; - - if (n < 1) { - // n == 0 not allowed because it has no sense, but if it's necessary we have to return - // a zero degree polynomial with a constant coefficient equals to the sum of all the original coefficients - throw new Error("Compute a new polynomial to a zero or negative number is not allowed"); - } else if (1 === n) { - return await Polynomial.fromEvaluations(polynomial.coef, polynomial.curve, polynomial.logger); - } - - // length is the length of non-constant coefficients - // if truncate === true, the highest zero coefficients (if exist) will be removed - const length = truncate ? polynomial.degree() : (polynomial.length() - 1); - const bufferDst = (length * n + 1) > 2 << 14 ? - new ffjavascript.BigBuffer((length * n + 1) * Fr.n8) : new Uint8Array((length * n + 1) * Fr.n8); - - // Copy constant coefficient as is because is not related to x - bufferDst.set(polynomial.getCoef(0), 0); - - for (let i = 1; i <= length; i++) { - const i_sFr = i * Fr.n8; - - const coef = polynomial.getCoef(i); - bufferDst.set(coef, i_sFr * n); - } - - return new Polynomial(bufferDst, polynomial.curve, polynomial.logger); - } - - split(numPols, degPols, blindingFactors) { - if (numPols < 1) { - throw new Error(`Polynomials can't be split in ${numPols} parts`); - } else if (1 === numPols) { - return [this]; - } - - //blinding factors can be void or must have a length of numPols - 1 - if (0 !== blindingFactors.length && blindingFactors.length < numPols - 1) { - throw new Error(`Blinding factors length must be ${numPols - 1}`); - } - - const chunkByteLength = (degPols + 1) * this.Fr.n8; - let res = []; - - // Check polynomial can be split in numChunks parts of chunkSize bytes... - const numRealPols = Math.ceil((this.degree() + 1) * this.Fr.n8 / chunkByteLength); - if (numRealPols < numPols) { - //throw new Error(`Polynomial is short to be split in ${numPols} parts of ${degPols} coefficients each.`); - for (let i = numRealPols; i < numPols; i++) { - res[i] = new Polynomial(new Uint8Array(this.Fr.n8), this.curve, this.logger); - } - } - - numPols = Math.min(numPols, numRealPols); - for (let i = 0; i < numPols; i++) { - const isLast = (numPols - 1) === i; - const byteLength = isLast ? this.coef.byteLength - ((numPols - 1) * chunkByteLength) : chunkByteLength + this.Fr.n8; - - let buff = (byteLength / this.Fr.n8) > 2 << 14 ? new ffjavascript.BigBuffer(byteLength) : new Uint8Array(byteLength); - res[i] = new Polynomial(buff, this.curve, this.logger); - - const fr = i * chunkByteLength; - const to = isLast ? this.coef.byteLength : (i + 1) * chunkByteLength; - res[i].coef.set(this.coef.slice(fr, to), 0); - - // Add a blinding factor as higher degree - if (!isLast) { - res[i].coef.set(blindingFactors[i], chunkByteLength); - } - - // Sub blinding factor to the lowest degree - if (0 !== i) { - const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); - res[i].coef.set(lowestDegree, 0); - } - - if (isLast) { - res[i].truncate(); - } - } - - return res; - - // // compute t_low(X) - // let polTLow = new BigBuffer((chunkSize + 1) * n8r); - // polTLow.set(t.slice(0, zkey.domainSize * n8r), 0); - // // Add blinding scalar b_10 as a new coefficient n - // polTLow.set(ch.b[10], zkey.domainSize * n8r); - // - // // compute t_mid(X) - // let polTMid = new BigBuffer((zkey.domainSize + 1) * n8r); - // polTMid.set(t.slice(zkey.domainSize * n8r, zkey.domainSize * 2 * n8r), 0); - // // Subtract blinding scalar b_10 to the lowest coefficient of t_mid - // const lowestMid = Fr.sub(polTMid.slice(0, n8r), ch.b[10]); - // polTMid.set(lowestMid, 0); - // // Add blinding scalar b_11 as a new coefficient n - // polTMid.set(ch.b[11], zkey.domainSize * n8r); - // - // // compute t_high(X) - // let polTHigh = new BigBuffer((zkey.domainSize + 6) * n8r); - // polTHigh.set(t.slice(zkey.domainSize * 2 * n8r, (zkey.domainSize * 3 + 6) * n8r), 0); - // //Subtract blinding scalar b_11 to the lowest coefficient of t_high - // const lowestHigh = Fr.sub(polTHigh.slice(0, n8r), ch.b[11]); - // polTHigh.set(lowestHigh, 0); - // - // proof.T1 = await expTau(polTLow, "multiexp T1"); - // proof.T2 = await expTau(polTMid, "multiexp T2"); - // proof.T3 = await expTau(polTHigh, "multiexp T3"); - } - - // split2(degPols, blindingFactors) { - // let currentDegree = this.degree(); - // const numFilledPols = Math.ceil((currentDegree + 1) / (degPols + 1)); - // - // //blinding factors can be void or must have a length of numPols - 1 - // if (0 !== blindingFactors.length && blindingFactors.length < numFilledPols - 1) { - // throw new Error(`Blinding factors length must be ${numFilledPols - 1}`); - // } - // - // const chunkByteLength = (degPols + 1) * this.Fr.n8; - // - // // Check polynomial can be split in numChunks parts of chunkSize bytes... - // if (this.coef.byteLength / chunkByteLength <= numFilledPols - 1) { - // throw new Error(`Polynomial is short to be split in ${numFilledPols} parts of ${degPols} coefficients each.`); - // } - // - // let res = []; - // for (let i = 0; i < numFilledPols; i++) { - // const isLast = (numFilledPols - 1) === i; - // const byteLength = isLast ? (currentDegree + 1) * this.Fr.n8 - ((numFilledPols - 1) * chunkByteLength) : chunkByteLength + this.Fr.n8; - // - // res[i] = new Polynomial(new BigBuffer(byteLength), this.Fr, this.logger); - // const fr = i * chunkByteLength; - // const to = isLast ? (currentDegree + 1) * this.Fr.n8 : (i + 1) * chunkByteLength; - // res[i].coef.set(this.coef.slice(fr, to), 0); - // - // // Add a blinding factor as higher degree - // if (!isLast) { - // res[i].coef.set(blindingFactors[i], chunkByteLength); - // } - // - // // Sub blinding factor to the lowest degree - // if (0 !== i) { - // const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); - // res[i].coef.set(lowestDegree, 0); - // } - // } - // - // return res; - // } - - // merge(pols, overlap = true) { - // let length = 0; - // for (let i = 0; i < pols.length; i++) { - // length += pols[i].length(); - // } - // - // if (overlap) { - // length -= pols.length - 1; - // } - // - // let res = new Polynomial(new BigBuffer(length * this.Fr.n8)); - // for (let i = 0; i < pols.length; i++) { - // const byteLength = pols[i].coef.byteLength; - // if (0 === i) { - // res.coef.set(pols[i].coef, 0); - // } else { - // - // } - // } - // - // return res; - // } - - truncate() { - const deg = this.degree(); - if (deg + 1 < this.coef.byteLength / this.Fr.n8) { - const newCoefs = (deg + 1) > 2 << 14 ? - new ffjavascript.BigBuffer((deg + 1) * this.Fr.n8) : new Uint8Array((deg + 1) * this.Fr.n8); - - newCoefs.set(this.coef.slice(0, (deg + 1) * this.Fr.n8), 0); - this.coef = newCoefs; - } - } - - static lagrangePolynomialInterpolation(xArr, yArr, curve) { - const Fr = curve.Fr; - let polynomial = computeLagrangePolynomial(0); - for (let i = 1; i < xArr.length; i++) { - polynomial.add(computeLagrangePolynomial(i)); - } - - return polynomial; - - function computeLagrangePolynomial(i) { - let polynomial; - - for (let j = 0; j < xArr.length; j++) { - if (j === i) continue; - - if (polynomial === undefined) { - let buff = (xArr.length) > 2 << 14 ? - new ffjavascript.BigBuffer((xArr.length) * Fr.n8) : new Uint8Array((xArr.length) * Fr.n8); - polynomial = new Polynomial(buff, curve); - polynomial.setCoef(0, Fr.neg(xArr[j])); - polynomial.setCoef(1, Fr.one); - } else { - polynomial.byXSubValue(xArr[j]); - } - } - - let denominator = polynomial.evaluate(xArr[i]); - denominator = Fr.inv(denominator); - const mulFactor = Fr.mul(yArr[i], denominator); - - polynomial.mulScalar(mulFactor); - - return polynomial; - } - } - - static zerofierPolynomial(xArr, curve) { - const Fr = curve.Fr; - let buff = (xArr.length + 1) > 2 << 14 ? - new ffjavascript.BigBuffer((xArr.length + 1) * Fr.n8) : new Uint8Array((xArr.length + 1) * Fr.n8); - let polynomial = new Polynomial(buff, curve); - - // Build a zerofier polynomial with the following form: - // zerofier(X) = (X-xArr[0])(X-xArr[1])...(X-xArr[n]) - polynomial.setCoef(0, Fr.neg(xArr[0])); - polynomial.setCoef(1, Fr.one); - - for (let i = 1; i < xArr.length; i++) { - polynomial.byXSubValue(xArr[i]); - } - - return polynomial; - } - - print() { - const Fr = this.Fr; - let res = ""; - for (let i = this.degree(); i >= 0; i--) { - const coef = this.getCoef(i); - if (!Fr.eq(Fr.zero, coef)) { - if (Fr.isNegative(coef)) { - res += " - "; - } else if (i !== this.degree()) { - res += " + "; - } - res += Fr.toString(coef); - if (i > 0) { - res += i > 1 ? "x^" + i : "x"; - } - } - } - console.log(res); - } - - async multiExponentiation(PTau, name) { - const n = this.coef.byteLength / this.Fr.n8; - const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); - const bm = await this.Fr.batchFromMontgomery(this.coef); - let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); - res = this.G1.toAffine(res); - return res; - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -class Evaluations { - constructor(evaluations, curve, logger) { - this.eval = evaluations; - this.curve = curve; - this.Fr = curve.Fr; - this.logger = logger; - } - - static async fromPolynomial(polynomial, extension, curve, logger) { - const coefficientsN = new ffjavascript.BigBuffer(polynomial.length() * extension * curve.Fr.n8); - coefficientsN.set(polynomial.coef, 0); - - const evaluations = await curve.Fr.fft(coefficientsN); - - return new Evaluations(evaluations, curve, logger); - } - - getEvaluation(index) { - const i_n8 = index * this.Fr.n8; - - if (i_n8 + this.Fr.n8 > this.eval.byteLength) { - throw new Error("Evaluations.getEvaluation() out of bounds"); - } - - return this.eval.slice(i_n8, i_n8 + this.Fr.n8); - } - - length() { - let length = this.eval.byteLength / this.Fr.n8; - if (length !== Math.floor(this.eval.byteLength / this.Fr.n8)) { - throw new Error("Polynomial evaluations buffer has incorrect size"); - } - if (0 === length) { - this.logger.warn("Polynomial has length zero"); - } - return length; - } -} - -/* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const {stringifyBigInts: stringifyBigInts$1} = ffjavascript.utils; - + if (globalThis.gc) globalThis.gc(); + const { fd: fdPTau, sections: sectionsPTau } = await (0, _iden3_binfileutils.readBinFile)(ptauName, "ptau", 1, 1 << 22, 1 << 24); + const { curve, power } = await readPTauHeader(fdPTau, sectionsPTau); + const { fd: fdR1cs, sections: sectionsR1cs } = await (0, _iden3_binfileutils.readBinFile)(r1csName, "r1cs", 1, 1 << 22, 1 << 24); + const r1cs = await (0, r1csfile.readR1csFd)(fdR1cs, sectionsR1cs, { + loadConstraints: true, + loadCustomGates: true + }); + const sG1 = curve.G1.F.n8 * 2; + const G1 = curve.G1; + const sG2 = curve.G2.F.n8 * 2; + const Fr = curve.Fr; + const n8r = curve.Fr.n8; + if (logger) logger.info("Reading r1cs"); + const plonkConstraints = new BigArray(); + const plonkAdditions = new BigArray(); + let plonkNVars = r1cs.nVars; + const nPublic = r1cs.nOutputs + r1cs.nPubInputs; + await processConstraints(curve.Fr, r1cs, logger); + if (globalThis.gc) globalThis.gc(); + const fdZKey = await (0, _iden3_binfileutils.createBinFile)(zkeyName, "zkey", 1, 14, 1 << 22, 1 << 24); + if (r1cs.prime != curve.r) { + if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); + return -1; + } + let cirPower = log2(plonkConstraints.length - 1) + 1; + if (cirPower < 3) cirPower = 3; + const domainSize = 2 ** cirPower; + if (logger) logger.info("Plonk constraints: " + plonkConstraints.length); + if (cirPower > power) { + if (logger) logger.error(`circuit too big for this power of tau ceremony. ${plonkConstraints.length} > 2**${power}`); + return -1; + } + if (!sectionsPTau[12]) { + if (logger) logger.error("Powers of tau is not prepared."); + return -1; + } + const LPoints = new ffjavascript.BigBuffer(domainSize * sG1); + const o = sectionsPTau[12][0].p + (2 ** cirPower - 1) * sG1; + await fdPTau.readToBuffer(LPoints, 0, domainSize * sG1, o); + const [k1, k2] = getK1K2(); + const vk = {}; + await writeAdditions(3, "Additions"); + if (globalThis.gc) globalThis.gc(); + await writeWitnessMap(4, 0, "Amap"); + if (globalThis.gc) globalThis.gc(); + await writeWitnessMap(5, 1, "Bmap"); + if (globalThis.gc) globalThis.gc(); + await writeWitnessMap(6, 2, "Cmap"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(7, 3, "Qm"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(8, 4, "Ql"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(9, 5, "Qr"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(10, 6, "Qo"); + if (globalThis.gc) globalThis.gc(); + await writeQMap(11, 7, "Qc"); + if (globalThis.gc) globalThis.gc(); + await writeSigma(12, "sigma"); + if (globalThis.gc) globalThis.gc(); + await writeLs(13, "lagrange polynomials"); + if (globalThis.gc) globalThis.gc(); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 14); + const buffOut = new ffjavascript.BigBuffer((domainSize + 6) * sG1); + await fdPTau.readToBuffer(buffOut, 0, (domainSize + 6) * sG1, sectionsPTau[2][0].p); + await fdZKey.write(buffOut); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + if (globalThis.gc) globalThis.gc(); + await writeHeaders(); + await fdZKey.close(); + await fdR1cs.close(); + await fdPTau.close(); + if (logger) logger.info("Setup Finished"); + return; + async function processConstraints(Fr, r1cs, logger) { + function normalize(linearComb) { + const ss = Object.keys(linearComb); + for (let i = 0; i < ss.length; i++) if (linearComb[ss[i]] == 0n) delete linearComb[ss[i]]; + } + function join(linearComb1, k, linearComb2) { + const res = {}; + for (let s in linearComb1) if (typeof res[s] == "undefined") res[s] = Fr.mul(k, linearComb1[s]); + else res[s] = Fr.add(res[s], Fr.mul(k, linearComb1[s])); + for (let s in linearComb2) if (typeof res[s] == "undefined") res[s] = linearComb2[s]; + else res[s] = Fr.add(res[s], linearComb2[s]); + normalize(res); + return res; + } + function reduceCoefs(linearComb, maxC) { + const res = { + k: Fr.zero, + s: [], + coefs: [] + }; + const cs = []; + for (let s in linearComb) if (s == 0) res.k = Fr.add(res.k, linearComb[s]); + else if (linearComb[s] != 0n) cs.push([Number(s), linearComb[s]]); + while (cs.length > maxC) { + const c1 = cs.shift(); + const c2 = cs.shift(); + const sl = c1[0]; + const sr = c2[0]; + const so = plonkNVars++; + const qm = Fr.zero; + const ql = Fr.neg(c1[1]); + const qr = Fr.neg(c2[1]); + const qo = Fr.one; + const qc = Fr.zero; + plonkConstraints.push([ + sl, + sr, + so, + qm, + ql, + qr, + qo, + qc + ]); + plonkAdditions.push([ + sl, + sr, + c1[1], + c2[1] + ]); + cs.push([so, Fr.one]); + } + for (let i = 0; i < cs.length; i++) { + res.s[i] = cs[i][0]; + res.coefs[i] = cs[i][1]; + } + while (res.coefs.length < maxC) { + res.s.push(0); + res.coefs.push(Fr.zero); + } + return res; + } + function addConstraintSum(lc) { + const C = reduceCoefs(lc, 3); + const sl = C.s[0]; + const sr = C.s[1]; + const so = C.s[2]; + const qm = Fr.zero; + const ql = C.coefs[0]; + const qr = C.coefs[1]; + const qo = C.coefs[2]; + const qc = C.k; + plonkConstraints.push([ + sl, + sr, + so, + qm, + ql, + qr, + qo, + qc + ]); + } + function addConstraintMul(lcA, lcB, lcC) { + const A = reduceCoefs(lcA, 1); + const B = reduceCoefs(lcB, 1); + const C = reduceCoefs(lcC, 1); + const sl = A.s[0]; + const sr = B.s[0]; + const so = C.s[0]; + const qm = Fr.mul(A.coefs[0], B.coefs[0]); + const ql = Fr.mul(A.coefs[0], B.k); + const qr = Fr.mul(A.k, B.coefs[0]); + const qo = Fr.neg(C.coefs[0]); + const qc = Fr.sub(Fr.mul(A.k, B.k), C.k); + plonkConstraints.push([ + sl, + sr, + so, + qm, + ql, + qr, + qo, + qc + ]); + } + function getLinearCombinationType(lc) { + let k = Fr.zero; + let n = 0; + const ss = Object.keys(lc); + for (let i = 0; i < ss.length; i++) if (lc[ss[i]] == 0n) delete lc[ss[i]]; + else if (ss[i] == 0) k = Fr.add(k, lc[ss[i]]); + else n++; + if (n > 0) return n.toString(); + if (k != Fr.zero) return "k"; + return "0"; + } + function process(lcA, lcB, lcC) { + const lctA = getLinearCombinationType(lcA); + const lctB = getLinearCombinationType(lcB); + if (lctA === "0" || lctB === "0") { + normalize(lcC); + addConstraintSum(lcC); + } else if (lctA === "k") addConstraintSum(join(lcB, lcA[0], lcC)); + else if (lctB === "k") addConstraintSum(join(lcA, lcB[0], lcC)); + else addConstraintMul(lcA, lcB, lcC); + } + for (let s = 1; s <= nPublic; s++) { + const sl = s; + const sr = 0; + const so = 0; + const qm = Fr.zero; + const ql = Fr.one; + const qr = Fr.zero; + const qo = Fr.zero; + const qc = Fr.zero; + plonkConstraints.push([ + sl, + sr, + so, + qm, + ql, + qr, + qo, + qc + ]); + } + for (let c = 0; c < r1cs.constraints.length; c++) { + if (logger && c % 1e4 === 0) logger.debug(`processing constraints: ${c}/${r1cs.nConstraints}`); + process(...r1cs.constraints[c]); + } + } + async function writeWitnessMap(sectionNum, posConstraint, name) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + for (let i = 0; i < plonkConstraints.length; i++) { + await fdZKey.writeULE32(plonkConstraints[i][posConstraint]); + if (logger && i % 1e6 == 0) logger.debug(`writing ${name}: ${i}/${plonkConstraints.length}`); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeQMap(sectionNum, posConstraint, name) { + let Q = new ffjavascript.BigBuffer(domainSize * n8r); + for (let i = 0; i < plonkConstraints.length; i++) { + Q.set(plonkConstraints[i][posConstraint], i * n8r); + if (logger && i % 1e6 == 0) logger.debug(`writing ${name}: ${i}/${plonkConstraints.length}`); + } + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + await writeP4(Q); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + Q = await Fr.batchFromMontgomery(Q); + vk[name] = await curve.G1.multiExpAffine(LPoints, Q, logger, "multiexp " + name); + } + async function writeP4(buff) { + const q = await Fr.ifft(buff); + const q4 = new ffjavascript.BigBuffer(domainSize * n8r * 4); + q4.set(q, 0); + const Q4 = await Fr.fft(q4); + await fdZKey.write(q); + await fdZKey.write(Q4); + } + async function writeAdditions(sectionNum, name) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + const buffOut = new Uint8Array(8 + 2 * n8r); + const buffOutV = new DataView(buffOut.buffer); + for (let i = 0; i < plonkAdditions.length; i++) { + const addition = plonkAdditions[i]; + let o = 0; + buffOutV.setUint32(o, addition[0], true); + o += 4; + buffOutV.setUint32(o, addition[1], true); + o += 4; + buffOut.set(addition[2], o); + o += n8r; + buffOut.set(addition[3], o); + o += n8r; + await fdZKey.write(buffOut); + if (logger && i % 1e6 == 0) logger.debug(`writing ${name}: ${i}/${plonkAdditions.length}`); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeSigma(sectionNum, name) { + const sigma = new ffjavascript.BigBuffer(n8r * domainSize * 3); + const lastAparence = new BigArray(plonkNVars); + const firstPos = new BigArray(plonkNVars); + let w = Fr.one; + for (let i = 0; i < domainSize; i++) { + if (i < plonkConstraints.length) { + buildSigma(plonkConstraints[i][0], i); + buildSigma(plonkConstraints[i][1], domainSize + i); + buildSigma(plonkConstraints[i][2], domainSize * 2 + i); + } else { + buildSigma(0, i); + buildSigma(0, domainSize + i); + buildSigma(0, domainSize * 2 + i); + } + w = Fr.mul(w, Fr.w[cirPower]); + if (logger && i % 1e6 == 0) logger.debug(`writing ${name} phase1: ${i}/${plonkConstraints.length}`); + } + for (let s = 0; s < plonkNVars; s++) { + if (typeof firstPos[s] !== "undefined") sigma.set(lastAparence[s], firstPos[s] * n8r); + else console.log("Variable not used"); + if (logger && s % 1e6 == 0) logger.debug(`writing ${name} phase2: ${s}/${plonkNVars}`); + } + if (globalThis.gc) globalThis.gc(); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + let S1 = sigma.slice(0, domainSize * n8r); + await writeP4(S1); + if (globalThis.gc) globalThis.gc(); + let S2 = sigma.slice(domainSize * n8r, domainSize * n8r * 2); + await writeP4(S2); + if (globalThis.gc) globalThis.gc(); + let S3 = sigma.slice(domainSize * n8r * 2, domainSize * n8r * 3); + await writeP4(S3); + if (globalThis.gc) globalThis.gc(); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + S1 = await Fr.batchFromMontgomery(S1); + S2 = await Fr.batchFromMontgomery(S2); + S3 = await Fr.batchFromMontgomery(S3); + vk.S1 = await curve.G1.multiExpAffine(LPoints, S1, logger, "multiexp S1"); + if (globalThis.gc) globalThis.gc(); + vk.S2 = await curve.G1.multiExpAffine(LPoints, S2, logger, "multiexp S2"); + if (globalThis.gc) globalThis.gc(); + vk.S3 = await curve.G1.multiExpAffine(LPoints, S3, logger, "multiexp S3"); + if (globalThis.gc) globalThis.gc(); + function buildSigma(s, p) { + if (typeof lastAparence[s] === "undefined") firstPos[s] = p; + else sigma.set(lastAparence[s], p * n8r); + let v; + if (p < domainSize) v = w; + else if (p < 2 * domainSize) v = Fr.mul(w, k1); + else v = Fr.mul(w, k2); + lastAparence[s] = v; + } + } + async function writeLs(sectionNum, name) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + const l = Math.max(nPublic, 1); + for (let i = 0; i < l; i++) { + let buff = new ffjavascript.BigBuffer(domainSize * n8r); + buff.set(Fr.one, i * n8r); + await writeP4(buff); + if (logger) logger.debug(`writing ${name} ${i}/${l}`); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeHeaders() { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 1); + await fdZKey.writeULE32(2); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 2); + const primeQ = curve.q; + const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; + const primeR = curve.r; + const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; + await fdZKey.writeULE32(n8q); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeQ, n8q); + await fdZKey.writeULE32(n8r); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeR, n8r); + await fdZKey.writeULE32(plonkNVars); + await fdZKey.writeULE32(nPublic); + await fdZKey.writeULE32(domainSize); + await fdZKey.writeULE32(plonkAdditions.length); + await fdZKey.writeULE32(plonkConstraints.length); + await fdZKey.write(k1); + await fdZKey.write(k2); + await fdZKey.write(G1.toAffine(vk.Qm)); + await fdZKey.write(G1.toAffine(vk.Ql)); + await fdZKey.write(G1.toAffine(vk.Qr)); + await fdZKey.write(G1.toAffine(vk.Qo)); + await fdZKey.write(G1.toAffine(vk.Qc)); + await fdZKey.write(G1.toAffine(vk.S1)); + await fdZKey.write(G1.toAffine(vk.S2)); + await fdZKey.write(G1.toAffine(vk.S3)); + let bX_2; + bX_2 = await fdPTau.read(sG2, sectionsPTau[3][0].p + sG2); + await fdZKey.write(bX_2); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + function getK1K2() { + let k1 = Fr.two; + while (isIncluded(k1, [], cirPower)) Fr.add(k1, Fr.one); + let k2 = Fr.add(k1, Fr.one); + while (isIncluded(k2, [k1], cirPower)) Fr.add(k2, Fr.one); + return [k1, k2]; + function isIncluded(k, kArr, pow) { + const domainSize = 2 ** pow; + let w = Fr.one; + for (let i = 0; i < domainSize; i++) { + if (Fr.eq(k, w)) return true; + for (let j = 0; j < kArr.length; j++) if (Fr.eq(k, Fr.mul(kArr[j], w))) return true; + w = Fr.mul(w, Fr.w[pow]); + } + return false; + } + } +} +//#endregion +//#region src/proof.js +var Proof = class { + constructor(curve, logger) { + this.curve = curve; + this.logger = logger; + this.resetProof(); + } + resetProof() { + this.polynomials = {}; + this.evaluations = {}; + } + addPolynomial(key, polynomial) { + if (key in this.polynomials) this.logger.warn(`proof: polynomial.${key} already exist in proof`); + this.polynomials[key] = polynomial; + } + getPolynomial(key) { + if (!(key in this.polynomials)) this.logger.warn(`proof: polynomial ${key} does not exist in proof`); + return this.polynomials[key]; + } + addEvaluation(key, evaluation) { + if (key in this.evaluations) this.logger.warn(`proof: evaluations.${key} already exist in proof`); + this.evaluations[key] = evaluation; + } + getEvaluation(key) { + if (!(key in this.evaluations)) this.logger.warn(`proof: evaluation ${key} does not exist in proof`); + return this.evaluations[key]; + } + toObjectProof(splitFields = true) { + let res = splitFields ? { + polynomials: {}, + evaluations: {} + } : {}; + Object.keys(this.polynomials).forEach((key) => { + const value = this.curve.G1.toObject(this.polynomials[key]); + if (splitFields) res.polynomials[key] = value; + else res[key] = value; + }); + Object.keys(this.evaluations).forEach((key) => { + const value = this.curve.Fr.toObject(this.evaluations[key]); + if (splitFields) res.evaluations[key] = value; + else res[key] = value; + }); + return res; + } + fromObjectProof(objectProof) { + this.resetProof(); + Object.keys(objectProof.polynomials).forEach((key) => { + this.polynomials[key] = this.curve.G1.fromObject(objectProof.polynomials[key]); + }); + Object.keys(objectProof.evaluations).forEach((key) => { + this.evaluations[key] = this.curve.Fr.fromObject(objectProof.evaluations[key]); + }); + } +}; +//#endregion +//#region src/Keccak256Transcript.js +var POLYNOMIAL = 0; +var SCALAR = 1; +var Keccak256Transcript = class { + constructor(curve) { + this.G1 = curve.G1; + this.Fr = curve.Fr; + this.reset(); + } + reset() { + this.data = []; + } + addPolCommitment(polynomialCommitment) { + this.data.push({ + type: POLYNOMIAL, + data: polynomialCommitment + }); + } + addScalar(scalar) { + this.data.push({ + type: SCALAR, + data: scalar + }); + } + getChallenge() { + if (0 === this.data.length) throw new Error("Keccak256Transcript: No data to generate a transcript"); + let nPolynomials = 0; + let nScalars = 0; + this.data.forEach((element) => POLYNOMIAL === element.type ? nPolynomials++ : nScalars++); + let buffer = new Uint8Array(nScalars * this.Fr.n8 + nPolynomials * this.G1.F.n8 * 2); + let offset = 0; + for (let i = 0; i < this.data.length; i++) if (POLYNOMIAL === this.data[i].type) { + this.G1.toRprUncompressed(buffer, offset, this.data[i].data); + offset += this.G1.F.n8 * 2; + } else { + this.Fr.toRprBE(buffer, offset, this.data[i].data); + offset += this.Fr.n8; + } + const value = ffjavascript.Scalar.fromRprBE((0, _noble_hashes_sha3_js.keccak_256)(buffer)); + return this.Fr.e(value); + } +}; +//#endregion +//#region src/mul_z.js +var MulZ = class { + static getZ1(Fr) { + return [ + Fr.zero, + Fr.add(Fr.e(-1), Fr.w[2]), + Fr.e(-2), + Fr.sub(Fr.e(-1), Fr.w[2]) + ]; + } + static getZ2(Fr) { + return [ + Fr.zero, + Fr.add(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), + Fr.e(4), + Fr.sub(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])) + ]; + } + static getZ3(Fr) { + return [ + Fr.zero, + Fr.add(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), + Fr.e(-8), + Fr.sub(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])) + ]; + } + static mul2(a, b, ap, bp, p, Fr) { + const Z1 = this.getZ1(Fr); + let r, rz; + const a_b = Fr.mul(a, b); + const a_bp = Fr.mul(a, bp); + const ap_b = Fr.mul(ap, b); + const ap_bp = Fr.mul(ap, bp); + r = a_b; + let a0 = Fr.add(a_bp, ap_b); + let a1 = ap_bp; + rz = a0; + if (p) rz = Fr.add(rz, Fr.mul(Z1[p], a1)); + return [r, rz]; + } + static mul3(a, b, c, ap, bp, cp, p, Fr) { + const Z1 = this.getZ1(Fr); + const Z2 = this.getZ2(Fr); + let r, rz; + const a_b = Fr.mul(a, b); + const a_bp = Fr.mul(a, bp); + const ap_b = Fr.mul(ap, b); + const ap_bp = Fr.mul(ap, bp); + r = Fr.mul(a_b, c); + let a0 = Fr.mul(ap_b, c); + a0 = Fr.add(a0, Fr.mul(a_bp, c)); + a0 = Fr.add(a0, Fr.mul(a_b, cp)); + let a1 = Fr.mul(ap_bp, c); + a1 = Fr.add(a1, Fr.mul(a_bp, cp)); + a1 = Fr.add(a1, Fr.mul(ap_b, cp)); + rz = a0; + if (p) { + const a2 = Fr.mul(ap_bp, cp); + rz = Fr.add(rz, Fr.mul(Z1[p], a1)); + rz = Fr.add(rz, Fr.mul(Z2[p], a2)); + } + return [r, rz]; + } + static mul4(a, b, c, d, ap, bp, cp, dp, p, Fr) { + const Z1 = this.getZ1(Fr); + const Z2 = this.getZ2(Fr); + const Z3 = this.getZ3(Fr); + let r, rz; + const a_b = Fr.mul(a, b); + const a_bp = Fr.mul(a, bp); + const ap_b = Fr.mul(ap, b); + const ap_bp = Fr.mul(ap, bp); + const c_d = Fr.mul(c, d); + const c_dp = Fr.mul(c, dp); + const cp_d = Fr.mul(cp, d); + const cp_dp = Fr.mul(cp, dp); + r = Fr.mul(a_b, c_d); + let a0 = Fr.mul(ap_b, c_d); + a0 = Fr.add(a0, Fr.mul(a_bp, c_d)); + a0 = Fr.add(a0, Fr.mul(a_b, cp_d)); + a0 = Fr.add(a0, Fr.mul(a_b, c_dp)); + let a1 = Fr.mul(ap_bp, c_d); + a1 = Fr.add(a1, Fr.mul(ap_b, cp_d)); + a1 = Fr.add(a1, Fr.mul(ap_b, c_dp)); + a1 = Fr.add(a1, Fr.mul(a_bp, cp_d)); + a1 = Fr.add(a1, Fr.mul(a_bp, c_dp)); + a1 = Fr.add(a1, Fr.mul(a_b, cp_dp)); + let a2 = Fr.mul(a_bp, cp_dp); + a2 = Fr.add(a2, Fr.mul(ap_b, cp_dp)); + a2 = Fr.add(a2, Fr.mul(ap_bp, c_dp)); + a2 = Fr.add(a2, Fr.mul(ap_bp, cp_d)); + let a3 = Fr.mul(ap_bp, cp_dp); + rz = a0; + if (p) { + rz = Fr.add(rz, Fr.mul(Z1[p], a1)); + rz = Fr.add(rz, Fr.mul(Z2[p], a2)); + rz = Fr.add(rz, Fr.mul(Z3[p], a3)); + } + return [r, rz]; + } +}; +//#endregion +//#region src/polynomial/polynomial.js +var Polynomial = class Polynomial { + constructor(coefficients, curve, logger) { + this.coef = coefficients; + this.curve = curve; + this.Fr = curve.Fr; + this.G1 = curve.G1; + this.logger = logger; + } + static async fromEvaluations(buffer, curve, logger) { + return new Polynomial(await curve.Fr.ifft(buffer), curve, logger); + } + static fromCoefficientsArray(array, curve, logger) { + const Fr = curve.Fr; + let buff = array.length > 32768 ? new ffjavascript.BigBuffer(array.length * Fr.n8) : new Uint8Array(array.length * Fr.n8); + for (let i = 0; i < array.length; i++) buff.set(array[i], i * Fr.n8); + return new Polynomial(buff, curve, logger); + } + static fromPolynomial(polynomial, curve, logger) { + let length = polynomial.length(); + let Fr = curve.Fr; + let buff = length > 32768 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); + buff.set(polynomial.coef.slice(), 0); + return new Polynomial(buff, curve, logger); + } + isEqual(polynomial) { + const degree = this.degree(); + if (degree !== polynomial.degree()) return false; + for (let i = 0; i < degree + 1; i++) if (!this.Fr.eq(this.getCoef(i), polynomial.getCoef(i))) return false; + return true; + } + blindCoefficients(blindingFactors) { + blindingFactors = blindingFactors || []; + const blindedCoefficients = this.length() + blindingFactors.length > 32768 ? new ffjavascript.BigBuffer((this.length() + blindingFactors.length) * this.Fr.n8) : new Uint8Array((this.length() + blindingFactors.length) * this.Fr.n8); + blindedCoefficients.set(this.coef, 0); + for (let i = 0; i < blindingFactors.length; i++) { + blindedCoefficients.set(this.Fr.add(blindedCoefficients.slice((this.length() + i) * this.Fr.n8, (this.length() + i + 1) * this.Fr.n8), blindingFactors[i]), (this.length() + i) * this.Fr.n8); + blindedCoefficients.set(this.Fr.sub(blindedCoefficients.slice(i * this.Fr.n8, (i + 1) * this.Fr.n8), blindingFactors[i]), i * this.Fr.n8); + } + this.coef = blindedCoefficients; + } + getCoef(index) { + const i_n8 = index * this.Fr.n8; + if (i_n8 + this.Fr.n8 > this.coef.byteLength) return this.Fr.zero; + return this.coef.slice(i_n8, i_n8 + this.Fr.n8); + } + setCoef(index, value) { + if (index > this.length() - 1) throw new Error("Coef index is not available"); + this.coef.set(value, index * this.Fr.n8); + } + static async to4T(buffer, domainSize, blindingFactors, Fr) { + blindingFactors = blindingFactors || []; + let a = await Fr.ifft(buffer); + const a4 = domainSize * 4 > 32768 ? new ffjavascript.BigBuffer(domainSize * 4 * Fr.n8) : new Uint8Array(domainSize * 4 * Fr.n8); + a4.set(a, 0); + const A4 = await Fr.fft(a4); + if (blindingFactors.length === 0) return [a, A4]; + const a1 = domainSize + blindingFactors.length > 32768 ? new ffjavascript.BigBuffer((domainSize + blindingFactors.length) * Fr.n8) : new Uint8Array((domainSize + blindingFactors.length) * Fr.n8); + a1.set(a, 0); + for (let i = 0; i < blindingFactors.length; i++) { + a1.set(Fr.add(a1.slice((domainSize + i) * Fr.n8, (domainSize + i + 1) * Fr.n8), blindingFactors[i]), (domainSize + i) * Fr.n8); + a1.set(Fr.sub(a1.slice(i * Fr.n8, (i + 1) * Fr.n8), blindingFactors[i]), i * Fr.n8); + } + return [a1, A4]; + } + length() { + let length = this.coef.byteLength / this.Fr.n8; + if (length !== Math.floor(this.coef.byteLength / this.Fr.n8)) throw new Error("Polynomial coefficients buffer has incorrect size"); + if (0 === length) { + if (this.logger) this.logger.warn("Polynomial has length zero"); + } + return length; + } + degree() { + for (let i = this.length() - 1; i > 0; i--) { + const i_n8 = i * this.Fr.n8; + if (!this.Fr.eq(this.Fr.zero, this.coef.slice(i_n8, i_n8 + this.Fr.n8))) return i; + } + return 0; + } + evaluate(point) { + let res = this.Fr.zero; + for (let i = this.degree() + 1; i > 0; i--) { + let i_n8 = i * this.Fr.n8; + const currentCoefficient = this.coef.slice(i_n8 - this.Fr.n8, i_n8); + res = this.Fr.add(currentCoefficient, this.Fr.mul(res, point)); + } + return res; + } + fastEvaluate(point) { + const Fr = this.Fr; + let nThreads = 3; + let nCoefs = this.degree() + 1; + let coefsThread = parseInt(nCoefs / nThreads); + let residualCoefs = nCoefs - coefsThread * nThreads; + let res = []; + let xN = []; + xN[0] = Fr.one; + for (let i = 0; i < nThreads; i++) { + res[i] = Fr.zero; + let nCoefs = i === nThreads - 1 ? coefsThread + residualCoefs : coefsThread; + for (let j = nCoefs; j > 0; j--) { + res[i] = Fr.add(this.getCoef(i * coefsThread + j - 1), Fr.mul(res[i], point)); + if (i === 0) xN[0] = Fr.mul(xN[0], point); + } + } + for (let i = 1; i < nThreads; i++) { + res[0] = Fr.add(res[0], Fr.mul(xN[i - 1], res[i])); + xN[i] = Fr.mul(xN[i - 1], xN[0]); + } + return res[0]; + } + add(polynomial, blindingValue) { + let other = false; + if (polynomial.length() > this.length()) other = true; + const thisLength = this.length(); + const polyLength = polynomial.length(); + for (let i = 0; i < Math.max(thisLength, polyLength); i++) { + const i_n8 = i * this.Fr.n8; + const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; + let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; + if (blindingValue !== void 0) b = this.Fr.mul(b, blindingValue); + if (other) polynomial.coef.set(this.Fr.add(a, b), i_n8); + else this.coef.set(this.Fr.add(a, b), i_n8); + } + if (other) { + delete this.coef; + this.coef = polynomial.coef; + } + } + sub(polynomial, blindingValue) { + let other = false; + if (polynomial.length() > this.length()) other = true; + const thisLength = this.length(); + const polyLength = polynomial.length(); + for (let i = 0; i < Math.max(thisLength, polyLength); i++) { + const i_n8 = i * this.Fr.n8; + const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; + let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; + if (blindingValue !== void 0) b = this.Fr.mul(b, blindingValue); + if (other) polynomial.coef.set(this.Fr.sub(a, b), i_n8); + else this.coef.set(this.Fr.sub(a, b), i_n8); + } + if (other) { + delete this.coef; + this.coef = polynomial.coef; + } + } + mulScalar(value) { + for (let i = 0; i < this.length(); i++) { + const i_n8 = i * this.Fr.n8; + this.coef.set(this.Fr.mul(this.coef.slice(i_n8, i_n8 + this.Fr.n8), value), i_n8); + } + } + addScalar(value) { + const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); + this.coef.set(this.Fr.add(currentValue, value), 0); + } + subScalar(value) { + const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); + this.coef.set(this.Fr.sub(currentValue, value), 0); + } + byXSubValue(value) { + const Fr = this.Fr; + const length = !Fr.eq(Fr.zero, this.getCoef(this.length() - 1)) ? this.length() + 1 : this.length(); + let pol = new Polynomial(length > 32768 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8), this.curve, this.logger); + pol.coef.set(this.coef.slice(0, (length - 1) * Fr.n8), 32); + this.mulScalar(Fr.neg(value)); + pol.add(this); + this.coef = pol.coef; + } + byXNSubValue(n, value) { + const Fr = this.Fr; + const length = !(this.length() - n - 1 >= this.degree()) ? this.length() + n : this.length(); + let pol = new Polynomial(length > 32768 ? new ffjavascript.BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8), this.curve, this.logger); + pol.coef.set(this.coef.slice(0, (this.degree() + 1) * 32), n * 32); + this.mulScalar(value); + pol.add(this); + this.coef = pol.coef; + } + divBy(polynomial) { + const Fr = this.Fr; + const degreeA = this.degree(); + const degreeB = polynomial.degree(); + let polR = new Polynomial(this.coef, this.curve, this.logger); + this.coef = this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); + for (let i = degreeA - degreeB; i >= 0; i--) { + this.setCoef(i, Fr.div(polR.getCoef(i + degreeB), polynomial.getCoef(degreeB))); + for (let j = 0; j <= degreeB; j++) polR.setCoef(i + j, Fr.sub(polR.getCoef(i + j), Fr.mul(this.getCoef(i), polynomial.getCoef(j)))); + } + return polR; + } + divByMonic(m, beta) { + const Fr = this.Fr; + let d = this.degree(); + let quotient = new Polynomial(this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8), this.curve, this.logger); + let bArr = []; + for (let i = 0; i < m; i++) { + quotient.setCoef(d - i - m, this.getCoef(d - i)); + bArr[i] = this.getCoef(d - i); + } + let nThreads = m; + let j = 0; + for (let k = 0; k < nThreads; k++) for (let i = d - 2 * m - k; i >= 0; i = i - nThreads) { + if (i < 0) break; + let idx = k; + bArr[idx] = Fr.add(this.getCoef(i + m), Fr.mul(bArr[idx], beta)); + quotient.setCoef(i, bArr[idx]); + j = (j + 1) % m; + } + this.coef = quotient.coef; + } + divByVanishing(n, beta) { + if (this.degree() < n) throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); + const Fr = this.Fr; + let polR = new Polynomial(this.coef, this.curve, this.logger); + this.coef = this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); + for (let i = this.length() - 1; i >= n; i--) { + let leadingCoef = polR.getCoef(i); + if (Fr.eq(Fr.zero, leadingCoef)) continue; + polR.setCoef(i, Fr.zero); + polR.setCoef(i - n, Fr.add(polR.getCoef(i - n), Fr.mul(beta, leadingCoef))); + this.setCoef(i - n, Fr.add(this.getCoef(i - n), leadingCoef)); + } + return polR; + } + divByVanishing2(m, beta) { + if (this.degree() < m) throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); + const Fr = this.Fr; + let polR = new Polynomial(this.coef, this.curve, this.logger); + this.coef = this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); + let nThreads = 3; + let nTotal = this.length() - m; + let nElementsChunk = Math.floor(nTotal / nThreads); + let nElementsLast = nTotal - (nThreads - 1) * nElementsChunk; + console.log(nTotal); + console.log(nElementsChunk + " " + nElementsLast); + for (let k = 0; k < nThreads; k++) { + console.log("> Thread " + k); + for (let i = k === 0 ? nElementsLast : nElementsChunk; i > 0; i--) { + let idxDst = i - 1; + if (k !== 0) idxDst += (k - 1) * nElementsChunk + nElementsLast; + let idxSrc = idxDst + m; + let leadingCoef = polR.getCoef(idxSrc); + if (Fr.eq(Fr.zero, leadingCoef)) continue; + polR.setCoef(idxSrc, Fr.zero); + polR.setCoef(idxDst, Fr.add(polR.getCoef(idxDst), Fr.mul(beta, leadingCoef))); + this.setCoef(idxDst, Fr.add(this.getCoef(idxDst), leadingCoef)); + console.log(idxDst + " <-- " + idxSrc); + } + } + this.print(); + return polR; + } + fastDivByVanishing(data) { + const Fr = this.Fr; + for (let i = 0; i < data.length; i++) { + let m = data[i][0]; + let beta = data[i][1]; + if (this.degree() < m) throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); + let nThreads = 5; + let nElements = this.length() - m; + let nElementsBucket = Math.floor(nElements / nThreads / m); + let nElementsChunk = nElementsBucket * m; + let nElementsLast = nElements - nThreads * nElementsChunk; + let polTmp = new Polynomial(this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8), this.curve, this.logger); + let ptr = this.coef; + this.coef = polTmp.coef; + polTmp.coef = ptr; + for (let k = 0; k < nThreads; k++) { + let idx0 = (k + 1) * nElementsChunk + nElementsLast; + for (let i = 0; i < m; i++) this.setCoef(idx0 + i - m, polTmp.getCoef(idx0 + i)); + for (let i = 0; i < nElementsChunk - m; i++) { + let offset = idx0 - i - 1; + let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); + this.setCoef(offset - m, val); + } + } + let idx0 = nElementsLast; + let pending = nElementsLast; + for (let i = 0; i < m && pending; i++) { + this.setCoef(idx0 - i - 1, polTmp.getCoef(idx0 + m - i - 1)); + pending--; + } + for (let i = 0; i < pending; i++) { + let offset = idx0 - i - 1; + let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); + this.setCoef(offset - m, val); + } + let acc = []; + let betaPow = Fr.one; + for (let i = 0; i < nElementsBucket; i++) betaPow = Fr.mul(betaPow, beta); + let currentBeta = Fr.one; + for (let k = nThreads; k > 0; k--) { + let idThread = k - 1; + let idx0 = idThread * nElementsChunk + nElementsLast; + acc[idThread] = []; + for (let i = 0; i < m; i++) { + acc[idThread][i] = this.getCoef(idx0 + i); + if (k !== nThreads) acc[idThread][i] = Fr.add(acc[idThread][i], Fr.mul(betaPow, acc[idThread + 1][i])); + } + currentBeta = Fr.mul(currentBeta, betaPow); + } + for (let k = 0; k < nThreads; k++) { + let idx0 = k * nElementsChunk + nElementsLast; + let currentBeta = beta; + let currentM = m - 1; + let limit = k === 0 ? nElementsLast : nElementsChunk; + for (let i = 0; i < limit; i++) { + let offset = idx0 - i - 1; + let val = Fr.add(this.getCoef(offset), Fr.mul(currentBeta, acc[k][currentM])); + this.setCoef(offset, val); + if (currentM === 0) { + currentM = m - 1; + currentBeta = Fr.mul(currentBeta, beta); + } else currentM--; + } + } + } + } + divByXSubValue(value) { + const coefs = this.length() > 32768 ? new ffjavascript.BigBuffer(this.length() * this.Fr.n8) : new Uint8Array(this.length() * this.Fr.n8); + coefs.set(this.Fr.zero, (this.length() - 1) * this.Fr.n8); + coefs.set(this.coef.slice((this.length() - 1) * this.Fr.n8, this.length() * this.Fr.n8), (this.length() - 2) * this.Fr.n8); + for (let i = this.length() - 3; i >= 0; i--) { + let i_n8 = i * this.Fr.n8; + coefs.set(this.Fr.add(this.coef.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8), this.Fr.mul(value, coefs.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8))), i * this.Fr.n8); + } + if (!this.Fr.eq(this.coef.slice(0, this.Fr.n8), this.Fr.mul(this.Fr.neg(value), coefs.slice(0, this.Fr.n8)))) throw new Error("Polynomial does not divide"); + this.coef = coefs; + } + divZh(domainSize, extensions = 4) { + for (let i = 0; i < domainSize; i++) { + const i_n8 = i * this.Fr.n8; + this.coef.set(this.Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)), i_n8); + } + const upperBound = this.coef.byteLength / this.Fr.n8; + for (let i = domainSize; i < upperBound; i++) { + const i_n8 = i * this.Fr.n8; + const a = this.Fr.sub(this.coef.slice((i - domainSize) * this.Fr.n8, (i - domainSize) * this.Fr.n8 + this.Fr.n8), this.coef.slice(i_n8, i_n8 + this.Fr.n8)); + this.coef.set(a, i_n8); + if (i > domainSize * (extensions - 1) - extensions) { + if (!this.Fr.isZero(a)) throw new Error("Polynomial is not divisible"); + } + } + return this; + } + divByZerofier(n, beta) { + let Fr = this.Fr; + const invBeta = Fr.inv(beta); + const invBetaNeg = Fr.neg(invBeta); + let isOne = Fr.eq(Fr.one, invBetaNeg); + let isNegOne = Fr.eq(Fr.negone, invBetaNeg); + if (!isOne) for (let i = 0; i < n; i++) { + const i_n8 = i * this.Fr.n8; + let element; + if (isNegOne) element = Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)); + else element = Fr.mul(invBetaNeg, this.coef.slice(i_n8, i_n8 + this.Fr.n8)); + this.coef.set(element, i_n8); + } + isOne = Fr.eq(Fr.one, invBeta); + isNegOne = Fr.eq(Fr.negone, invBeta); + for (let i = n; i < this.length(); i++) { + const i_n8 = i * this.Fr.n8; + const i_prev_n8 = (i - n) * this.Fr.n8; + let element = this.Fr.sub(this.coef.slice(i_prev_n8, i_prev_n8 + this.Fr.n8), this.coef.slice(i_n8, i_n8 + this.Fr.n8)); + if (!isOne) if (isNegOne) element = Fr.neg(element); + else element = Fr.mul(invBeta, element); + this.coef.set(element, i_n8); + if (i > this.length() - n - 1) { + if (!this.Fr.isZero(element)) throw new Error("Polynomial is not divisible"); + } + } + return this; + } + byX() { + const coefs = this.length() + 1 > 32768 ? new ffjavascript.BigBuffer(this.coef.byteLength + this.Fr.n8) : new Uint8Array(this.coef.byteLength + this.Fr.n8); + coefs.set(this.Fr.zero, 0); + coefs.set(this.coef, this.Fr.n8); + this.coef = coefs; + } + static async expX(polynomial, n, truncate = false) { + const Fr = polynomial.Fr; + if (n < 1) throw new Error("Compute a new polynomial to a zero or negative number is not allowed"); + else if (1 === n) return await Polynomial.fromEvaluations(polynomial.coef, polynomial.curve, polynomial.logger); + const length = truncate ? polynomial.degree() : polynomial.length() - 1; + const bufferDst = length * n + 1 > 32768 ? new ffjavascript.BigBuffer((length * n + 1) * Fr.n8) : new Uint8Array((length * n + 1) * Fr.n8); + bufferDst.set(polynomial.getCoef(0), 0); + for (let i = 1; i <= length; i++) { + const i_sFr = i * Fr.n8; + const coef = polynomial.getCoef(i); + bufferDst.set(coef, i_sFr * n); + } + return new Polynomial(bufferDst, polynomial.curve, polynomial.logger); + } + split(numPols, degPols, blindingFactors) { + if (numPols < 1) throw new Error(`Polynomials can't be split in ${numPols} parts`); + else if (1 === numPols) return [this]; + if (0 !== blindingFactors.length && blindingFactors.length < numPols - 1) throw new Error(`Blinding factors length must be ${numPols - 1}`); + const chunkByteLength = (degPols + 1) * this.Fr.n8; + let res = []; + const numRealPols = Math.ceil((this.degree() + 1) * this.Fr.n8 / chunkByteLength); + if (numRealPols < numPols) for (let i = numRealPols; i < numPols; i++) res[i] = new Polynomial(new Uint8Array(this.Fr.n8), this.curve, this.logger); + numPols = Math.min(numPols, numRealPols); + for (let i = 0; i < numPols; i++) { + const isLast = numPols - 1 === i; + const byteLength = isLast ? this.coef.byteLength - (numPols - 1) * chunkByteLength : chunkByteLength + this.Fr.n8; + res[i] = new Polynomial(byteLength / this.Fr.n8 > 32768 ? new ffjavascript.BigBuffer(byteLength) : new Uint8Array(byteLength), this.curve, this.logger); + const fr = i * chunkByteLength; + const to = isLast ? this.coef.byteLength : (i + 1) * chunkByteLength; + res[i].coef.set(this.coef.slice(fr, to), 0); + if (!isLast) res[i].coef.set(blindingFactors[i], chunkByteLength); + if (0 !== i) { + const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); + res[i].coef.set(lowestDegree, 0); + } + if (isLast) res[i].truncate(); + } + return res; + } + truncate() { + const deg = this.degree(); + if (deg + 1 < this.coef.byteLength / this.Fr.n8) { + const newCoefs = deg + 1 > 32768 ? new ffjavascript.BigBuffer((deg + 1) * this.Fr.n8) : new Uint8Array((deg + 1) * this.Fr.n8); + newCoefs.set(this.coef.slice(0, (deg + 1) * this.Fr.n8), 0); + this.coef = newCoefs; + } + } + static lagrangePolynomialInterpolation(xArr, yArr, curve) { + const Fr = curve.Fr; + let polynomial = computeLagrangePolynomial(0); + for (let i = 1; i < xArr.length; i++) polynomial.add(computeLagrangePolynomial(i)); + return polynomial; + function computeLagrangePolynomial(i) { + let polynomial; + for (let j = 0; j < xArr.length; j++) { + if (j === i) continue; + if (polynomial === void 0) { + polynomial = new Polynomial(xArr.length > 32768 ? new ffjavascript.BigBuffer(xArr.length * Fr.n8) : new Uint8Array(xArr.length * Fr.n8), curve); + polynomial.setCoef(0, Fr.neg(xArr[j])); + polynomial.setCoef(1, Fr.one); + } else polynomial.byXSubValue(xArr[j]); + } + let denominator = polynomial.evaluate(xArr[i]); + denominator = Fr.inv(denominator); + const mulFactor = Fr.mul(yArr[i], denominator); + polynomial.mulScalar(mulFactor); + return polynomial; + } + } + static zerofierPolynomial(xArr, curve) { + const Fr = curve.Fr; + let polynomial = new Polynomial(xArr.length + 1 > 32768 ? new ffjavascript.BigBuffer((xArr.length + 1) * Fr.n8) : new Uint8Array((xArr.length + 1) * Fr.n8), curve); + polynomial.setCoef(0, Fr.neg(xArr[0])); + polynomial.setCoef(1, Fr.one); + for (let i = 1; i < xArr.length; i++) polynomial.byXSubValue(xArr[i]); + return polynomial; + } + print() { + const Fr = this.Fr; + let res = ""; + for (let i = this.degree(); i >= 0; i--) { + const coef = this.getCoef(i); + if (!Fr.eq(Fr.zero, coef)) { + if (Fr.isNegative(coef)) res += " - "; + else if (i !== this.degree()) res += " + "; + res += Fr.toString(coef); + if (i > 0) res += i > 1 ? "x^" + i : "x"; + } + } + console.log(res); + } + async multiExponentiation(PTau, name) { + const n = this.coef.byteLength / this.Fr.n8; + const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); + const bm = await this.Fr.batchFromMontgomery(this.coef); + let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); + res = this.G1.toAffine(res); + return res; + } +}; +//#endregion +//#region src/polynomial/evaluations.js +var Evaluations = class Evaluations { + constructor(evaluations, curve, logger) { + this.eval = evaluations; + this.curve = curve; + this.Fr = curve.Fr; + this.logger = logger; + } + static async fromPolynomial(polynomial, extension, curve, logger) { + const coefficientsN = new ffjavascript.BigBuffer(polynomial.length() * extension * curve.Fr.n8); + coefficientsN.set(polynomial.coef, 0); + return new Evaluations(await curve.Fr.fft(coefficientsN), curve, logger); + } + getEvaluation(index) { + const i_n8 = index * this.Fr.n8; + if (i_n8 + this.Fr.n8 > this.eval.byteLength) throw new Error("Evaluations.getEvaluation() out of bounds"); + return this.eval.slice(i_n8, i_n8 + this.Fr.n8); + } + length() { + let length = this.eval.byteLength / this.Fr.n8; + if (length !== Math.floor(this.eval.byteLength / this.Fr.n8)) throw new Error("Polynomial evaluations buffer has incorrect size"); + if (0 === length) this.logger.warn("Polynomial has length zero"); + return length; + } +}; +//#endregion +//#region src/plonk_prove.js +var { stringifyBigInts: stringifyBigInts$1 } = ffjavascript.utils; async function plonk16Prove(zkeyFileName, witnessFileName, logger, options) { - const {fd: fdWtns, sections: sectionsWtns} = await binFileUtils__namespace.readBinFile(witnessFileName, "wtns", 2, 1<<25, 1<<23); - - // Read witness file - if (logger) logger.debug("> Reading witness file"); - const wtns = await readHeader(fdWtns, sectionsWtns); - - // Read zkey file - if (logger) logger.debug("> Reading zkey file"); - const {fd: fdZKey, sections: zkeySections} = await binFileUtils__namespace.readBinFile(zkeyFileName, "zkey", 2, 1<<25, 1<<23); - - const zkey = await readHeader$1(fdZKey, zkeySections, undefined, options); - if (zkey.protocol != "plonk") { - throw new Error("zkey file is not plonk"); - } - - if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness != zkey.nVars -zkey.nAdditions) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); - } - - const curve = zkey.curve; - - const Fr = curve.Fr; - const n8r = curve.Fr.n8; - const sDomain = zkey.domainSize * n8r; - - if (logger) { - logger.debug("----------------------------"); - logger.debug(" PLONK PROVE SETTINGS"); - logger.debug(` Curve: ${curve.name}`); - logger.debug(` Circuit power: ${zkey.power}`); - logger.debug(` Domain size: ${zkey.domainSize}`); - logger.debug(` Vars: ${zkey.nVars}`); - logger.debug(` Public vars: ${zkey.nPublic}`); - logger.debug(` Constraints: ${zkey.nConstraints}`); - logger.debug(` Additions: ${zkey.nAdditions}`); - logger.debug("----------------------------"); - } - - //Read witness data - if (logger) logger.debug("> Reading witness file data"); - const buffWitness = await binFileUtils__namespace.readSection(fdWtns, sectionsWtns, 2); - - // First element in plonk is not used and can be any value. (But always the same). - // We set it to zero to go faster in the exponentiations. - buffWitness.set(Fr.zero, 0); - const buffInternalWitness = new ffjavascript.BigBuffer(n8r*zkey.nAdditions); - - let buffers = {}; - let polynomials = {}; - let evaluations = {}; - - let challenges = {}; - let proof = new Proof(curve, logger); - const transcript = new Keccak256Transcript(curve); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_ADDITIONS_SECTION}. Additions`); - await calculateAdditions(); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_SIGMA_SECTION}. Sigma1, Sigma2 & Sigma 3`); - if (logger) logger.debug("··· Reading Sigma polynomials "); - polynomials.Sigma1 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.Sigma2 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.Sigma3 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - - await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 5 * sDomain); - await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 10 * sDomain); - - if (logger) logger.debug("··· Reading Sigma evaluations"); - evaluations.Sigma1 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma2 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma3 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - - await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 6 * sDomain); - await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 11 * sDomain); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_PTAU_SECTION}. Powers of Tau`); - const PTau = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_PTAU_SECTION); - - let publicSignals = []; - - for (let i=1; i<= zkey.nPublic; i++) { - const pub = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8); - publicSignals.push(ffjavascript.Scalar.fromRprLE(pub)); - } - - if (logger) logger.debug(""); - if (logger) logger.debug("> ROUND 1"); - await round1(); - - if (logger) logger.debug("> ROUND 2"); - await round2(); - - if (logger) logger.debug("> ROUND 3"); - await round3(); - - if (logger) logger.debug("> ROUND 4"); - await round4(); - - if (logger) logger.debug("> ROUND 5"); - await round5(); - - /////////////////////// - // Final adjustments // - /////////////////////// - - await fdZKey.close(); - await fdWtns.close(); - - // Prepare proof - let _proof = proof.toObjectProof(false); - _proof.protocol = "plonk"; - _proof.curve = curve.name; - - if (logger) logger.debug("PLONK PROVER FINISHED"); - - return { - proof: stringifyBigInts$1(_proof), - publicSignals: stringifyBigInts$1(publicSignals) - }; - - async function calculateAdditions() { - if (logger) logger.debug("··· Computing additions"); - const additionsBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_ADDITIONS_SECTION); - - // sizes: wireId_x = 4 bytes (32 bits), factor_x = field size bits - // Addition form: wireId_a wireId_b factor_a factor_b (size is 4 + 4 + sFr + sFr) - const sSum = 8 + n8r * 2; - - for (let i = 0; i < zkey.nAdditions; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.debug(` addition ${i}/${zkey.nAdditions}`); - - // Read addition values - let offset = i * sSum; - const signalId1 = readUInt32(additionsBuff, offset); - offset += 4; - const signalId2 = readUInt32(additionsBuff, offset); - offset += 4; - const factor1 = additionsBuff.slice(offset, offset + n8r); - offset += n8r; - const factor2 = additionsBuff.slice(offset, offset + n8r); - - // Get witness value - const witness1 = getWitness(signalId1); - const witness2 = getWitness(signalId2); - - //Calculate final result - const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); - - buffInternalWitness.set(result, n8r * i); - } - } - - function readUInt32(b, o) { - const buff = b.slice(o, o+4); - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - return buffV.getUint32(0, true); - } - - function getWitness(idx) { - if (idx < zkey.nVars-zkey.nAdditions) { - return buffWitness.slice(idx*n8r, idx*n8r+n8r); - } else if (idx < zkey.nVars) { - return buffInternalWitness.slice((idx - (zkey.nVars-zkey.nAdditions))*n8r, (idx-(zkey.nVars-zkey.nAdditions))*n8r + n8r); - } else { - return curve.Fr.zero; - } - } - - async function round1() { - // STEP 1.1 - Generate random blinding scalars (b1, ..., b11) ∈ F - challenges.b = []; - for (let i=1; i<=11; i++) { - challenges.b[i] = curve.Fr.random(); - } - - // STEP 1.2 - Compute wire polynomials a(X), b(X) and c(X) - if (logger) logger.debug("> Computing A, B, C wire polynomials"); - await computeWirePolynomials(); - - // STEP 1.3 - Compute [a]_1, [b]_1, [c]_1 - if (logger) logger.debug("> Computing A, B, C MSM"); - let commitA = await polynomials.A.multiExponentiation(PTau, "A"); - let commitB = await polynomials.B.multiExponentiation(PTau, "B"); - let commitC = await polynomials.C.multiExponentiation(PTau, "C"); - - // First output of the prover is ([A]_1, [B]_1, [C]_1) - proof.addPolynomial("A", commitA); - proof.addPolynomial("B", commitB); - proof.addPolynomial("C", commitC); - - return 0; - } - - async function computeWirePolynomials() { - if (logger) logger.debug("··· Reading data from zkey file"); - - // Build A, B and C evaluations buffer from zkey and witness files - buffers.A = new ffjavascript.BigBuffer(sDomain); - buffers.B = new ffjavascript.BigBuffer(sDomain); - buffers.C = new ffjavascript.BigBuffer(sDomain); - - // Read zkey file to the buffers - const aMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_A_MAP_SECTION); - const bMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_B_MAP_SECTION); - const cMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_PL_C_MAP_SECTION); - - // Compute all witness from signal ids and set them to A,B & C buffers - for (let i = 0; i < zkey.nConstraints; i++) { - const i_sFr = i * n8r; - const offset = i * 4; - - // Compute A value from a signal id - const signalIdA = readUInt32(aMapBuff, offset); - buffers.A.set(getWitness(signalIdA), i_sFr); - - // Compute B value from a signal id - const signalIdB = readUInt32(bMapBuff, offset); - buffers.B.set(getWitness(signalIdB), i_sFr); - - // Compute C value from a signal id - const signalIdC = readUInt32(cMapBuff, offset); - buffers.C.set(getWitness(signalIdC), i_sFr); - } - - buffers.A = await Fr.batchToMontgomery(buffers.A); - buffers.B = await Fr.batchToMontgomery(buffers.B); - buffers.C = await Fr.batchToMontgomery(buffers.C); - - // Compute the coefficients of the wire polynomials a(X), b(X) and c(X) from A,B & C buffers - if (logger) logger.debug("··· Computing A ifft"); - polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); - if (logger) logger.debug("··· Computing B ifft"); - polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); - if (logger) logger.debug("··· Computing C ifft"); - polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); - - // Compute extended evaluations of a(X), b(X) and c(X) polynomials - if (logger) logger.debug("··· Computing A fft"); - evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); - if (logger) logger.debug("··· Computing B fft"); - evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); - if (logger) logger.debug("··· Computing C fft"); - evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); - - // Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b - polynomials.A.blindCoefficients([challenges.b[2], challenges.b[1]]); - polynomials.B.blindCoefficients([challenges.b[4], challenges.b[3]]); - polynomials.C.blindCoefficients([challenges.b[6], challenges.b[5]]); - - // Check degrees - if (polynomials.A.degree() >= zkey.domainSize + 2) { - throw new Error("A Polynomial is not well calculated"); - } - if (polynomials.B.degree() >= zkey.domainSize + 2) { - throw new Error("B Polynomial is not well calculated"); - } - if (polynomials.C.degree() >= zkey.domainSize + 2) { - throw new Error("C Polynomial is not well calculated"); - } - } - - async function round2() { - // STEP 2.1 - Compute permutation challenge beta and gamma ∈ F - // Compute permutation challenge beta - if (logger) logger.debug("> Computing challenges beta and gamma"); - transcript.reset(); - - transcript.addPolCommitment(zkey.Qm); - transcript.addPolCommitment(zkey.Ql); - transcript.addPolCommitment(zkey.Qr); - transcript.addPolCommitment(zkey.Qo); - transcript.addPolCommitment(zkey.Qc); - transcript.addPolCommitment(zkey.S1); - transcript.addPolCommitment(zkey.S2); - transcript.addPolCommitment(zkey.S3); - - // Add A to the transcript - for (let i = 0; i < zkey.nPublic; i++) { - transcript.addScalar(buffers.A.slice(i * n8r, i * n8r + n8r)); - } - - // Add A, B, C to the transcript - transcript.addPolCommitment(proof.getPolynomial("A")); - transcript.addPolCommitment(proof.getPolynomial("B")); - transcript.addPolCommitment(proof.getPolynomial("C")); - - challenges.beta = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.beta: " + Fr.toString(challenges.beta, 16)); - - // Compute permutation challenge gamma - transcript.reset(); - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.gamma: " + Fr.toString(challenges.gamma, 16)); - - // STEP 2.2 - Compute permutation polynomial z(X) - if (logger) logger.debug("> Computing Z polynomial"); - await computeZ(); - - // STEP 2.3 - Compute permutation [z]_1 - if (logger) logger.debug("> Computing Z MSM"); - let commitZ = await polynomials.Z.multiExponentiation(PTau, "Z"); - - // Second output of the prover is ([Z]_1) - proof.addPolynomial("Z", commitZ); - } - - async function computeZ() { - if (logger) logger.debug("··· Computing Z evaluations"); - - let numArr = new ffjavascript.BigBuffer(sDomain); - let denArr = new ffjavascript.BigBuffer(sDomain); - - // Set the first values to 1 - numArr.set(Fr.one, 0); - denArr.set(Fr.one, 0); - - // Set initial omega - let w = Fr.one; - for (let i = 0; i < zkey.domainSize; i++) { - const i_n8r = i * n8r; - - const a = buffers.A.slice(i_n8r, i_n8r + n8r); - const b = buffers.B.slice(i_n8r, i_n8r + n8r); - const c = buffers.C.slice(i_n8r, i_n8r + n8r); - - // Z(X) := numArr / denArr - // numArr := (a + beta·ω + gamma)(b + beta·ω·k1 + gamma)(c + beta·ω·k2 + gamma) - const betaw = Fr.mul(challenges.beta, w); - - let n1 = Fr.add(a, betaw); - n1 = Fr.add(n1, challenges.gamma); - - let n2 = Fr.add(b, Fr.mul(zkey.k1, betaw)); - n2 = Fr.add(n2, challenges.gamma); - - let n3 = Fr.add(c, Fr.mul(zkey.k2, betaw)); - n3 = Fr.add(n3, challenges.gamma); - - let num = Fr.mul(n1, Fr.mul(n2, n3)); - - // denArr := (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma) - let d1 = Fr.add(a, Fr.mul(evaluations.Sigma1.getEvaluation(i * 4), challenges.beta)); - d1 = Fr.add(d1, challenges.gamma); - - let d2 = Fr.add(b, Fr.mul(evaluations.Sigma2.getEvaluation(i * 4), challenges.beta)); - d2 = Fr.add(d2, challenges.gamma); - - let d3 = Fr.add(c, Fr.mul(evaluations.Sigma3.getEvaluation(i * 4), challenges.beta)); - d3 = Fr.add(d3, challenges.gamma); - - let den = Fr.mul(d1, Fr.mul(d2, d3)); - - // Multiply current num value with the previous one saved in numArr - num = Fr.mul(numArr.slice(i_n8r, i_n8r + n8r), num); - numArr.set(num, ((i + 1) % zkey.domainSize) * n8r); - - // Multiply current den value with the previous one saved in denArr - den = Fr.mul(denArr.slice(i_n8r, i_n8r + n8r), den); - denArr.set(den, ((i + 1) % zkey.domainSize) * n8r); - - w = Fr.mul(w, Fr.w[zkey.power]); - } - - // Compute the inverse of denArr to compute in the next command the - // division numArr/denArr by multiplying num · 1/denArr - denArr = await Fr.batchInverse(denArr); - - // TODO: Do it in assembly and in parallel - // Multiply numArr · denArr where denArr was inverted in the previous command - for (let i = 0; i < zkey.domainSize; i++) { - const i_sFr = i * n8r; - - const z = Fr.mul(numArr.slice(i_sFr, i_sFr + n8r), denArr.slice(i_sFr, i_sFr + n8r)); - numArr.set(z, i_sFr); - } - - // From now on the values saved on numArr will be Z(X) buffer - buffers.Z = numArr; - - if (!Fr.eq(numArr.slice(0, n8r), Fr.one)) { - throw new Error("Copy constraints does not match"); - } - - // Compute polynomial coefficients z(X) from buffers.Z - if (logger) logger.debug("··· Computing Z ifft"); - polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); - - // Compute extended evaluations of z(X) polynomial - if (logger) logger.debug("··· Computing Z fft"); - evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); - - // Blind z(X) polynomial coefficients with blinding scalars b - polynomials.Z.blindCoefficients([challenges.b[9], challenges.b[8], challenges.b[7]]); - - // Check degree - if (polynomials.Z.degree() >= zkey.domainSize + 3) { - throw new Error("Z Polynomial is not well calculated"); - } - - delete buffers.Z; - } - - async function round3() { - if (logger) logger.debug("> Computing challenge alpha"); - - // STEP 3.1 - Compute evaluation challenge alpha ∈ F - transcript.reset(); - transcript.addScalar(challenges.beta); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.getPolynomial("Z")); - - challenges.alpha = transcript.getChallenge(); - challenges.alpha2 = Fr.square(challenges.alpha); - if (logger) logger.debug("··· challenges.alpha: " + Fr.toString(challenges.alpha, 16)); - - // Compute quotient polynomial T(X) - if (logger) logger.debug("> Computing T polynomial"); - await computeT(); - - // Compute [T1]_1, [T2]_1, [T3]_1 - if (logger) logger.debug("> Computing T MSM"); - let commitT1 = await polynomials.T1.multiExponentiation(PTau, "T1"); - let commitT2 = await polynomials.T2.multiExponentiation(PTau, "T2"); - let commitT3 = await polynomials.T3.multiExponentiation(PTau, "T3"); - - // Third output of the prover is ([T1]_1, [T2]_1, [T3]_1) - proof.addPolynomial("T1", commitT1); - proof.addPolynomial("T2", commitT2); - proof.addPolynomial("T3", commitT3); - } - - async function computeT() { - if (logger) - logger.debug(`··· Reading sections ${ZKEY_PL_QL_SECTION}, ${ZKEY_PL_QR_SECTION}` + - `, ${ZKEY_PL_QM_SECTION}, ${ZKEY_PL_QO_SECTION}, ${ZKEY_PL_QC_SECTION}. Q selectors`); - // Reserve memory for Q's evaluations - evaluations.QL = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QR = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QM = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QO = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QC = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QL_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QR_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QM_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QO_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QC_SECTION][0].p + sDomain); - - // Read Lagrange polynomials & evaluations from zkey file - evaluations.Lagrange = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4 * zkey.nPublic), curve, logger); - - for (let i = 0; i < zkey.nPublic; i++) { - await fdZKey.readToBuffer(evaluations.Lagrange.eval, i * sDomain * 4, sDomain * 4, zkeySections[ZKEY_PL_LAGRANGE_SECTION][0].p + i * 5 * sDomain + sDomain); - } - - buffers.T = new ffjavascript.BigBuffer(sDomain * 4); - buffers.Tz = new ffjavascript.BigBuffer(sDomain * 4); - - if (logger) logger.debug("··· Computing T evaluations"); - - let w = Fr.one; - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) - logger.debug(` T evaluation ${i}/${zkey.domainSize * 4}`); - - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - const z = evaluations.Z.getEvaluation(i); - const zw = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); - - const qm = evaluations.QM.getEvaluation(i); - const ql = evaluations.QL.getEvaluation(i); - const qr = evaluations.QR.getEvaluation(i); - const qo = evaluations.QO.getEvaluation(i); - const qc = evaluations.QC.getEvaluation(i); - const s1 = evaluations.Sigma1.getEvaluation(i); - const s2 = evaluations.Sigma2.getEvaluation(i); - const s3 = evaluations.Sigma3.getEvaluation(i); - - const ap = Fr.add(challenges.b[2], Fr.mul(challenges.b[1], w)); - const bp = Fr.add(challenges.b[4], Fr.mul(challenges.b[3], w)); - const cp = Fr.add(challenges.b[6], Fr.mul(challenges.b[5], w)); - - const w2 = Fr.square(w); - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], w2), Fr.mul(challenges.b[8], w)), challenges.b[9]); - const wW = Fr.mul(w, Fr.w[zkey.power]); - const wW2 = Fr.square(wW); - const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], wW2), Fr.mul(challenges.b[8], wW)), challenges.b[9]); - - let pi = Fr.zero; - for (let j = 0; j < zkey.nPublic; j++) { - const offset = (j * 4 * zkey.domainSize) + i; - - const lPol = evaluations.Lagrange.getEvaluation(offset); - const aVal = buffers.A.slice(j * n8r, (j + 1) * n8r); - - pi = Fr.sub(pi, Fr.mul(lPol, aVal)); - } - - // e1 := a(X)b(X)qM(X) + a(X)qL(X) + b(X)qR(X) + c(X)qO(X) + PI(X) + qC(X) - let [e1, e1z] = MulZ.mul2(a, b, ap, bp, i % 4, Fr); - e1 = Fr.mul(e1, qm); - e1z = Fr.mul(e1z, qm); - - e1 = Fr.add(e1, Fr.mul(a, ql)); - e1z = Fr.add(e1z, Fr.mul(ap, ql)); - - e1 = Fr.add(e1, Fr.mul(b, qr)); - e1z = Fr.add(e1z, Fr.mul(bp, qr)); - - e1 = Fr.add(e1, Fr.mul(c, qo)); - e1z = Fr.add(e1z, Fr.mul(cp, qo)); - - e1 = Fr.add(e1, pi); - e1 = Fr.add(e1, qc); - - // e2 := α[(a(X) + βX + γ)(b(X) + βk1X + γ)(c(X) + βk2X + γ)z(X)] - const betaw = Fr.mul(challenges.beta, w); - let e2a = a; - e2a = Fr.add(e2a, betaw); - e2a = Fr.add(e2a, challenges.gamma); - - let e2b = b; - e2b = Fr.add(e2b, Fr.mul(betaw, zkey.k1)); - e2b = Fr.add(e2b, challenges.gamma); - - let e2c = c; - e2c = Fr.add(e2c, Fr.mul(betaw, zkey.k2)); - e2c = Fr.add(e2c, challenges.gamma); - - let e2d = z; - - let [e2, e2z] = MulZ.mul4(e2a, e2b, e2c, e2d, ap, bp, cp, zp, i % 4, Fr); - e2 = Fr.mul(e2, challenges.alpha); - e2z = Fr.mul(e2z, challenges.alpha); - - // e3 := α[(a(X) + βSσ1(X) + γ)(b(X) + βSσ2(X) + γ)(c(X) + βSσ3(X) + γ)z(Xω)] - let e3a = a; - e3a = Fr.add(e3a, Fr.mul(challenges.beta, s1)); - e3a = Fr.add(e3a, challenges.gamma); - - let e3b = b; - e3b = Fr.add(e3b, Fr.mul(challenges.beta, s2)); - e3b = Fr.add(e3b, challenges.gamma); - - let e3c = c; - e3c = Fr.add(e3c, Fr.mul(challenges.beta, s3)); - e3c = Fr.add(e3c, challenges.gamma); - - let e3d = zw; - let [e3, e3z] = MulZ.mul4(e3a, e3b, e3c, e3d, ap, bp, cp, zWp, i % 4, Fr); - - e3 = Fr.mul(e3, challenges.alpha); - e3z = Fr.mul(e3z, challenges.alpha); - - // e4 := α^2(z(X)−1)L1(X) - let e4 = Fr.sub(z, Fr.one); - e4 = Fr.mul(e4, evaluations.Lagrange.getEvaluation(i)); - e4 = Fr.mul(e4, challenges.alpha2); - - let e4z = Fr.mul(zp, evaluations.Lagrange.getEvaluation(i)); - e4z = Fr.mul(e4z, challenges.alpha2); - - - let t = Fr.add(Fr.sub(Fr.add(e1, e2), e3), e4); - let tz = Fr.add(Fr.sub(Fr.add(e1z, e2z), e3z), e4z); - - buffers.T.set(t, i * n8r); - buffers.Tz.set(tz, i * n8r); - - w = Fr.mul(w, Fr.w[zkey.power + 2]); - } - - // Compute the coefficients of the polynomial T0(X) from buffers.T0 - if (logger) - logger.debug("··· Computing T ifft"); - polynomials.T = await Polynomial.fromEvaluations(buffers.T, curve, logger); - - // Divide the polynomial T0 by Z_H(X) - if (logger) - logger.debug("··· Computing T / ZH"); - polynomials.T.divZh(zkey.domainSize, 4); - - // Compute the coefficients of the polynomial Tz(X) from buffers.Tz - if (logger) - logger.debug("··· Computing Tz ifft"); - polynomials.Tz = await Polynomial.fromEvaluations(buffers.Tz, curve, logger); - - // Add the polynomial T1z to T1 to get the final polynomial T1 - polynomials.T.add(polynomials.Tz); - - // Check degree - if (polynomials.T.degree() >= zkey.domainSize * 3 + 6) { - throw new Error("T Polynomial is not well calculated"); - } - - // t(x) has degree 3n + 5, we are going to split t(x) into three smaller polynomials: - // T1' and T2' with a degree < n and T3' with a degree n+5 - // such that t(x) = T1'(X) + X^n T2'(X) + X^{2n} T3'(X) - // To randomize the parts we use blinding scalars b_10 and b_11 in a way that doesn't change t(X): - // T1(X) = T1'(X) + b_10 X^n - // T2(X) = T2'(X) - b_10 + b_11 X^n - // T3(X) = T3'(X) - b_11 - // such that - // t(X) = T1(X) + X^n T2(X) + X^2n T3(X) - if (logger) logger.debug("··· Computing T1, T2, T3 polynomials"); - polynomials.T1 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); - polynomials.T2 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); - polynomials.T3 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 6) * n8r), curve, logger); - - polynomials.T1.coef.set(polynomials.T.coef.slice(0, sDomain), 0); - polynomials.T2.coef.set(polynomials.T.coef.slice(sDomain, sDomain * 2), 0); - polynomials.T3.coef.set(polynomials.T.coef.slice(sDomain * 2, sDomain * 3 + 6 * n8r), 0); - - // Add blinding scalar b_10 as a new coefficient n - polynomials.T1.setCoef(zkey.domainSize, challenges.b[10]); - - // compute t_mid(X) - // Subtract blinding scalar b_10 to the lowest coefficient of t_mid - const lowestMid = Fr.sub(polynomials.T2.getCoef(0), challenges.b[10]); - polynomials.T2.setCoef(0, lowestMid); - polynomials.T2.setCoef(zkey.domainSize, challenges.b[11]); - - // compute t_high(X) - //Subtract blinding scalar b_11 to the lowest coefficient of t_high - const lowestHigh = Fr.sub(polynomials.T3.getCoef(0), challenges.b[11]); - polynomials.T3.setCoef(0, lowestHigh); - } - - async function round4() { - if (logger) logger.debug("> Computing challenge xi"); - - // STEP 4.1 - Compute evaluation challenge xi ∈ F - transcript.reset(); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.getPolynomial("T1")); - transcript.addPolCommitment(proof.getPolynomial("T2")); - transcript.addPolCommitment(proof.getPolynomial("T3")); - - challenges.xi = transcript.getChallenge(); - challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); - - if (logger) logger.debug("··· challenges.xi: " + Fr.toString(challenges.xi, 16)); - - // Fourth output of the prover is ( a(xi), b(xi), c(xi), s1(xi), s2(xi), z(xiw) ) - proof.addEvaluation("eval_a", polynomials.A.evaluate(challenges.xi)); - proof.addEvaluation("eval_b", polynomials.B.evaluate(challenges.xi)); - proof.addEvaluation("eval_c", polynomials.C.evaluate(challenges.xi)); - proof.addEvaluation("eval_s1", polynomials.Sigma1.evaluate(challenges.xi)); - proof.addEvaluation("eval_s2", polynomials.Sigma2.evaluate(challenges.xi)); - proof.addEvaluation("eval_zw", polynomials.Z.evaluate(challenges.xiw)); - } - - async function round5() { - if (logger) logger.debug("> Computing challenge v"); - - // STEP 5.1 - Compute evaluation challenge v ∈ F - transcript.reset(); - transcript.addScalar(challenges.xi); - transcript.addScalar(proof.getEvaluation("eval_a")); - transcript.addScalar(proof.getEvaluation("eval_b")); - transcript.addScalar(proof.getEvaluation("eval_c")); - transcript.addScalar(proof.getEvaluation("eval_s1")); - transcript.addScalar(proof.getEvaluation("eval_s2")); - transcript.addScalar(proof.getEvaluation("eval_zw")); - - challenges.v = []; - challenges.v[1] = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.v: " + Fr.toString(challenges.v[1], 16)); - - for (let i = 2; i < 6; i++) { - challenges.v[i] = Fr.mul(challenges.v[i - 1], challenges.v[1]); - } - - // STEP 5.2 Compute linearisation polynomial r(X) - if (logger) logger.debug("> Computing linearisation polynomial R(X)"); - await computeR(); - - //STEP 5.3 Compute opening proof polynomial Wxi(X) - if (logger) logger.debug("> Computing opening proof polynomial Wxi(X) polynomial"); - computeWxi(); - - //STEP 5.4 Compute opening proof polynomial Wxiw(X) - if (logger) logger.debug("> Computing opening proof polynomial Wxiw(X) polynomial"); - computeWxiw(); - - if (logger) logger.debug("> Computing Wxi, Wxiw MSM"); - let commitWxi = await polynomials.Wxi.multiExponentiation(PTau, "Wxi"); - let commitWxiw = await polynomials.Wxiw.multiExponentiation(PTau, "Wxiw"); - - // Fifth output of the prover is ([Wxi]_1, [Wxiw]_1) - proof.addPolynomial("Wxi", commitWxi); - proof.addPolynomial("Wxiw", commitWxiw); - } - - async function computeR() { - const Fr = curve.Fr; - - // Reserve memory for Q's polynomials - polynomials.QL = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QR = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QM = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QO = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QC = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[ZKEY_PL_QL_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[ZKEY_PL_QR_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[ZKEY_PL_QM_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[ZKEY_PL_QO_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[ZKEY_PL_QC_SECTION][0].p); - - challenges.xin = challenges.xi; - for (let i = 0; i < zkey.power; i++) { - challenges.xin = Fr.square(challenges.xin); - } - - challenges.zh = Fr.sub(challenges.xin, Fr.one); - - const L = []; - - const n = Fr.e(zkey.domainSize); - let w = Fr.one; - for (let i = 1; i <= Math.max(1, zkey.nPublic); i++) { - L[i] = Fr.div(Fr.mul(w, challenges.zh), Fr.mul(n, Fr.sub(challenges.xi, w))); - w = Fr.mul(w, Fr.w[zkey.power]); - } - - const eval_l1 = Fr.div( - Fr.sub(challenges.xin, Fr.one), - Fr.mul(n, Fr.sub(challenges.xi, Fr.one)) - ); - - if (logger) { - logger.debug("Lagrange Evaluations: "); - for (let i=1; i. -*/ - -const {unstringifyBigInts: unstringifyBigInts$5} = ffjavascript.utils; - + const { fd: fdWtns, sections: sectionsWtns } = await _iden3_binfileutils.readBinFile(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); + if (logger) logger.debug("> Reading witness file"); + const wtns = await readHeader(fdWtns, sectionsWtns); + if (logger) logger.debug("> Reading zkey file"); + const { fd: fdZKey, sections: zkeySections } = await _iden3_binfileutils.readBinFile(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); + const zkey = await readHeader$1(fdZKey, zkeySections, void 0, options); + if (zkey.protocol != "plonk") throw new Error("zkey file is not plonk"); + if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) throw new Error("Curve of the witness does not match the curve of the proving key"); + if (wtns.nWitness != zkey.nVars - zkey.nAdditions) throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); + const curve = zkey.curve; + const Fr = curve.Fr; + const n8r = curve.Fr.n8; + const sDomain = zkey.domainSize * n8r; + if (logger) { + logger.debug("----------------------------"); + logger.debug(" PLONK PROVE SETTINGS"); + logger.debug(` Curve: ${curve.name}`); + logger.debug(` Circuit power: ${zkey.power}`); + logger.debug(` Domain size: ${zkey.domainSize}`); + logger.debug(` Vars: ${zkey.nVars}`); + logger.debug(` Public vars: ${zkey.nPublic}`); + logger.debug(` Constraints: ${zkey.nConstraints}`); + logger.debug(` Additions: ${zkey.nAdditions}`); + logger.debug("----------------------------"); + } + if (logger) logger.debug("> Reading witness file data"); + const buffWitness = await _iden3_binfileutils.readSection(fdWtns, sectionsWtns, 2); + buffWitness.set(Fr.zero, 0); + const buffInternalWitness = new ffjavascript.BigBuffer(n8r * zkey.nAdditions); + let buffers = {}; + let polynomials = {}; + let evaluations = {}; + let challenges = {}; + let proof = new Proof(curve, logger); + const transcript = new Keccak256Transcript(curve); + if (logger) logger.debug(`> Reading Section 3. Additions`); + await calculateAdditions(); + if (logger) logger.debug(`> Reading Section 12. Sigma1, Sigma2 & Sigma 3`); + if (logger) logger.debug("··· Reading Sigma polynomials "); + polynomials.Sigma1 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.Sigma2 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.Sigma3 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[12][0].p); + await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[12][0].p + 5 * sDomain); + await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[12][0].p + 10 * sDomain); + if (logger) logger.debug("··· Reading Sigma evaluations"); + evaluations.Sigma1 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.Sigma2 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.Sigma3 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[12][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[12][0].p + 6 * sDomain); + await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[12][0].p + 11 * sDomain); + if (logger) logger.debug(`> Reading Section 14. Powers of Tau`); + const PTau = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 14); + let publicSignals = []; + for (let i = 1; i <= zkey.nPublic; i++) { + const pub = buffWitness.slice(i * Fr.n8, i * Fr.n8 + Fr.n8); + publicSignals.push(ffjavascript.Scalar.fromRprLE(pub)); + } + if (logger) logger.debug(""); + if (logger) logger.debug("> ROUND 1"); + await round1(); + if (logger) logger.debug("> ROUND 2"); + await round2(); + if (logger) logger.debug("> ROUND 3"); + await round3(); + if (logger) logger.debug("> ROUND 4"); + await round4(); + if (logger) logger.debug("> ROUND 5"); + await round5(); + await fdZKey.close(); + await fdWtns.close(); + let _proof = proof.toObjectProof(false); + _proof.protocol = "plonk"; + _proof.curve = curve.name; + if (logger) logger.debug("PLONK PROVER FINISHED"); + return { + proof: stringifyBigInts$1(_proof), + publicSignals: stringifyBigInts$1(publicSignals) + }; + async function calculateAdditions() { + if (logger) logger.debug("··· Computing additions"); + const additionsBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 3); + const sSum = 8 + n8r * 2; + for (let i = 0; i < zkey.nAdditions; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.debug(` addition ${i}/${zkey.nAdditions}`); + let offset = i * sSum; + const signalId1 = readUInt32(additionsBuff, offset); + offset += 4; + const signalId2 = readUInt32(additionsBuff, offset); + offset += 4; + const factor1 = additionsBuff.slice(offset, offset + n8r); + offset += n8r; + const factor2 = additionsBuff.slice(offset, offset + n8r); + const witness1 = getWitness(signalId1); + const witness2 = getWitness(signalId2); + const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); + buffInternalWitness.set(result, n8r * i); + } + } + function readUInt32(b, o) { + const buff = b.slice(o, o + 4); + return new DataView(buff.buffer, buff.byteOffset, buff.byteLength).getUint32(0, true); + } + function getWitness(idx) { + if (idx < zkey.nVars - zkey.nAdditions) return buffWitness.slice(idx * n8r, idx * n8r + n8r); + else if (idx < zkey.nVars) return buffInternalWitness.slice((idx - (zkey.nVars - zkey.nAdditions)) * n8r, (idx - (zkey.nVars - zkey.nAdditions)) * n8r + n8r); + else return curve.Fr.zero; + } + async function round1() { + challenges.b = []; + for (let i = 1; i <= 11; i++) challenges.b[i] = curve.Fr.random(); + if (logger) logger.debug("> Computing A, B, C wire polynomials"); + await computeWirePolynomials(); + if (logger) logger.debug("> Computing A, B, C MSM"); + let commitA = await polynomials.A.multiExponentiation(PTau, "A"); + let commitB = await polynomials.B.multiExponentiation(PTau, "B"); + let commitC = await polynomials.C.multiExponentiation(PTau, "C"); + proof.addPolynomial("A", commitA); + proof.addPolynomial("B", commitB); + proof.addPolynomial("C", commitC); + return 0; + } + async function computeWirePolynomials() { + if (logger) logger.debug("··· Reading data from zkey file"); + buffers.A = new ffjavascript.BigBuffer(sDomain); + buffers.B = new ffjavascript.BigBuffer(sDomain); + buffers.C = new ffjavascript.BigBuffer(sDomain); + const aMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 4); + const bMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 5); + const cMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 6); + for (let i = 0; i < zkey.nConstraints; i++) { + const i_sFr = i * n8r; + const offset = i * 4; + const signalIdA = readUInt32(aMapBuff, offset); + buffers.A.set(getWitness(signalIdA), i_sFr); + const signalIdB = readUInt32(bMapBuff, offset); + buffers.B.set(getWitness(signalIdB), i_sFr); + const signalIdC = readUInt32(cMapBuff, offset); + buffers.C.set(getWitness(signalIdC), i_sFr); + } + buffers.A = await Fr.batchToMontgomery(buffers.A); + buffers.B = await Fr.batchToMontgomery(buffers.B); + buffers.C = await Fr.batchToMontgomery(buffers.C); + if (logger) logger.debug("··· Computing A ifft"); + polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); + if (logger) logger.debug("··· Computing B ifft"); + polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); + if (logger) logger.debug("··· Computing C ifft"); + polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); + if (logger) logger.debug("··· Computing A fft"); + evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); + if (logger) logger.debug("··· Computing B fft"); + evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); + if (logger) logger.debug("··· Computing C fft"); + evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); + polynomials.A.blindCoefficients([challenges.b[2], challenges.b[1]]); + polynomials.B.blindCoefficients([challenges.b[4], challenges.b[3]]); + polynomials.C.blindCoefficients([challenges.b[6], challenges.b[5]]); + if (polynomials.A.degree() >= zkey.domainSize + 2) throw new Error("A Polynomial is not well calculated"); + if (polynomials.B.degree() >= zkey.domainSize + 2) throw new Error("B Polynomial is not well calculated"); + if (polynomials.C.degree() >= zkey.domainSize + 2) throw new Error("C Polynomial is not well calculated"); + } + async function round2() { + if (logger) logger.debug("> Computing challenges beta and gamma"); + transcript.reset(); + transcript.addPolCommitment(zkey.Qm); + transcript.addPolCommitment(zkey.Ql); + transcript.addPolCommitment(zkey.Qr); + transcript.addPolCommitment(zkey.Qo); + transcript.addPolCommitment(zkey.Qc); + transcript.addPolCommitment(zkey.S1); + transcript.addPolCommitment(zkey.S2); + transcript.addPolCommitment(zkey.S3); + for (let i = 0; i < zkey.nPublic; i++) transcript.addScalar(buffers.A.slice(i * n8r, i * n8r + n8r)); + transcript.addPolCommitment(proof.getPolynomial("A")); + transcript.addPolCommitment(proof.getPolynomial("B")); + transcript.addPolCommitment(proof.getPolynomial("C")); + challenges.beta = transcript.getChallenge(); + if (logger) logger.debug("··· challenges.beta: " + Fr.toString(challenges.beta, 16)); + transcript.reset(); + transcript.addScalar(challenges.beta); + challenges.gamma = transcript.getChallenge(); + if (logger) logger.debug("··· challenges.gamma: " + Fr.toString(challenges.gamma, 16)); + if (logger) logger.debug("> Computing Z polynomial"); + await computeZ(); + if (logger) logger.debug("> Computing Z MSM"); + let commitZ = await polynomials.Z.multiExponentiation(PTau, "Z"); + proof.addPolynomial("Z", commitZ); + } + async function computeZ() { + if (logger) logger.debug("··· Computing Z evaluations"); + let numArr = new ffjavascript.BigBuffer(sDomain); + let denArr = new ffjavascript.BigBuffer(sDomain); + numArr.set(Fr.one, 0); + denArr.set(Fr.one, 0); + let w = Fr.one; + for (let i = 0; i < zkey.domainSize; i++) { + const i_n8r = i * n8r; + const a = buffers.A.slice(i_n8r, i_n8r + n8r); + const b = buffers.B.slice(i_n8r, i_n8r + n8r); + const c = buffers.C.slice(i_n8r, i_n8r + n8r); + const betaw = Fr.mul(challenges.beta, w); + let n1 = Fr.add(a, betaw); + n1 = Fr.add(n1, challenges.gamma); + let n2 = Fr.add(b, Fr.mul(zkey.k1, betaw)); + n2 = Fr.add(n2, challenges.gamma); + let n3 = Fr.add(c, Fr.mul(zkey.k2, betaw)); + n3 = Fr.add(n3, challenges.gamma); + let num = Fr.mul(n1, Fr.mul(n2, n3)); + let d1 = Fr.add(a, Fr.mul(evaluations.Sigma1.getEvaluation(i * 4), challenges.beta)); + d1 = Fr.add(d1, challenges.gamma); + let d2 = Fr.add(b, Fr.mul(evaluations.Sigma2.getEvaluation(i * 4), challenges.beta)); + d2 = Fr.add(d2, challenges.gamma); + let d3 = Fr.add(c, Fr.mul(evaluations.Sigma3.getEvaluation(i * 4), challenges.beta)); + d3 = Fr.add(d3, challenges.gamma); + let den = Fr.mul(d1, Fr.mul(d2, d3)); + num = Fr.mul(numArr.slice(i_n8r, i_n8r + n8r), num); + numArr.set(num, (i + 1) % zkey.domainSize * n8r); + den = Fr.mul(denArr.slice(i_n8r, i_n8r + n8r), den); + denArr.set(den, (i + 1) % zkey.domainSize * n8r); + w = Fr.mul(w, Fr.w[zkey.power]); + } + denArr = await Fr.batchInverse(denArr); + for (let i = 0; i < zkey.domainSize; i++) { + const i_sFr = i * n8r; + const z = Fr.mul(numArr.slice(i_sFr, i_sFr + n8r), denArr.slice(i_sFr, i_sFr + n8r)); + numArr.set(z, i_sFr); + } + buffers.Z = numArr; + if (!Fr.eq(numArr.slice(0, n8r), Fr.one)) throw new Error("Copy constraints does not match"); + if (logger) logger.debug("··· Computing Z ifft"); + polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); + if (logger) logger.debug("··· Computing Z fft"); + evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); + polynomials.Z.blindCoefficients([ + challenges.b[9], + challenges.b[8], + challenges.b[7] + ]); + if (polynomials.Z.degree() >= zkey.domainSize + 3) throw new Error("Z Polynomial is not well calculated"); + delete buffers.Z; + } + async function round3() { + if (logger) logger.debug("> Computing challenge alpha"); + transcript.reset(); + transcript.addScalar(challenges.beta); + transcript.addScalar(challenges.gamma); + transcript.addPolCommitment(proof.getPolynomial("Z")); + challenges.alpha = transcript.getChallenge(); + challenges.alpha2 = Fr.square(challenges.alpha); + if (logger) logger.debug("··· challenges.alpha: " + Fr.toString(challenges.alpha, 16)); + if (logger) logger.debug("> Computing T polynomial"); + await computeT(); + if (logger) logger.debug("> Computing T MSM"); + let commitT1 = await polynomials.T1.multiExponentiation(PTau, "T1"); + let commitT2 = await polynomials.T2.multiExponentiation(PTau, "T2"); + let commitT3 = await polynomials.T3.multiExponentiation(PTau, "T3"); + proof.addPolynomial("T1", commitT1); + proof.addPolynomial("T2", commitT2); + proof.addPolynomial("T3", commitT3); + } + async function computeT() { + if (logger) logger.debug(`··· Reading sections 8, 9, 7, 10, 11. Q selectors`); + evaluations.QL = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QR = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QM = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QO = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QC = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[8][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[9][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[7][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[10][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[11][0].p + sDomain); + evaluations.Lagrange = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4 * zkey.nPublic), curve, logger); + for (let i = 0; i < zkey.nPublic; i++) await fdZKey.readToBuffer(evaluations.Lagrange.eval, i * sDomain * 4, sDomain * 4, zkeySections[13][0].p + i * 5 * sDomain + sDomain); + buffers.T = new ffjavascript.BigBuffer(sDomain * 4); + buffers.Tz = new ffjavascript.BigBuffer(sDomain * 4); + if (logger) logger.debug("··· Computing T evaluations"); + let w = Fr.one; + for (let i = 0; i < zkey.domainSize * 4; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.debug(` T evaluation ${i}/${zkey.domainSize * 4}`); + const a = evaluations.A.getEvaluation(i); + const b = evaluations.B.getEvaluation(i); + const c = evaluations.C.getEvaluation(i); + const z = evaluations.Z.getEvaluation(i); + const zw = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); + const qm = evaluations.QM.getEvaluation(i); + const ql = evaluations.QL.getEvaluation(i); + const qr = evaluations.QR.getEvaluation(i); + const qo = evaluations.QO.getEvaluation(i); + const qc = evaluations.QC.getEvaluation(i); + const s1 = evaluations.Sigma1.getEvaluation(i); + const s2 = evaluations.Sigma2.getEvaluation(i); + const s3 = evaluations.Sigma3.getEvaluation(i); + const ap = Fr.add(challenges.b[2], Fr.mul(challenges.b[1], w)); + const bp = Fr.add(challenges.b[4], Fr.mul(challenges.b[3], w)); + const cp = Fr.add(challenges.b[6], Fr.mul(challenges.b[5], w)); + const w2 = Fr.square(w); + const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], w2), Fr.mul(challenges.b[8], w)), challenges.b[9]); + const wW = Fr.mul(w, Fr.w[zkey.power]); + const wW2 = Fr.square(wW); + const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], wW2), Fr.mul(challenges.b[8], wW)), challenges.b[9]); + let pi = Fr.zero; + for (let j = 0; j < zkey.nPublic; j++) { + const offset = j * 4 * zkey.domainSize + i; + const lPol = evaluations.Lagrange.getEvaluation(offset); + const aVal = buffers.A.slice(j * n8r, (j + 1) * n8r); + pi = Fr.sub(pi, Fr.mul(lPol, aVal)); + } + let [e1, e1z] = MulZ.mul2(a, b, ap, bp, i % 4, Fr); + e1 = Fr.mul(e1, qm); + e1z = Fr.mul(e1z, qm); + e1 = Fr.add(e1, Fr.mul(a, ql)); + e1z = Fr.add(e1z, Fr.mul(ap, ql)); + e1 = Fr.add(e1, Fr.mul(b, qr)); + e1z = Fr.add(e1z, Fr.mul(bp, qr)); + e1 = Fr.add(e1, Fr.mul(c, qo)); + e1z = Fr.add(e1z, Fr.mul(cp, qo)); + e1 = Fr.add(e1, pi); + e1 = Fr.add(e1, qc); + const betaw = Fr.mul(challenges.beta, w); + let e2a = a; + e2a = Fr.add(e2a, betaw); + e2a = Fr.add(e2a, challenges.gamma); + let e2b = b; + e2b = Fr.add(e2b, Fr.mul(betaw, zkey.k1)); + e2b = Fr.add(e2b, challenges.gamma); + let e2c = c; + e2c = Fr.add(e2c, Fr.mul(betaw, zkey.k2)); + e2c = Fr.add(e2c, challenges.gamma); + let e2d = z; + let [e2, e2z] = MulZ.mul4(e2a, e2b, e2c, e2d, ap, bp, cp, zp, i % 4, Fr); + e2 = Fr.mul(e2, challenges.alpha); + e2z = Fr.mul(e2z, challenges.alpha); + let e3a = a; + e3a = Fr.add(e3a, Fr.mul(challenges.beta, s1)); + e3a = Fr.add(e3a, challenges.gamma); + let e3b = b; + e3b = Fr.add(e3b, Fr.mul(challenges.beta, s2)); + e3b = Fr.add(e3b, challenges.gamma); + let e3c = c; + e3c = Fr.add(e3c, Fr.mul(challenges.beta, s3)); + e3c = Fr.add(e3c, challenges.gamma); + let e3d = zw; + let [e3, e3z] = MulZ.mul4(e3a, e3b, e3c, e3d, ap, bp, cp, zWp, i % 4, Fr); + e3 = Fr.mul(e3, challenges.alpha); + e3z = Fr.mul(e3z, challenges.alpha); + let e4 = Fr.sub(z, Fr.one); + e4 = Fr.mul(e4, evaluations.Lagrange.getEvaluation(i)); + e4 = Fr.mul(e4, challenges.alpha2); + let e4z = Fr.mul(zp, evaluations.Lagrange.getEvaluation(i)); + e4z = Fr.mul(e4z, challenges.alpha2); + let t = Fr.add(Fr.sub(Fr.add(e1, e2), e3), e4); + let tz = Fr.add(Fr.sub(Fr.add(e1z, e2z), e3z), e4z); + buffers.T.set(t, i * n8r); + buffers.Tz.set(tz, i * n8r); + w = Fr.mul(w, Fr.w[zkey.power + 2]); + } + if (logger) logger.debug("··· Computing T ifft"); + polynomials.T = await Polynomial.fromEvaluations(buffers.T, curve, logger); + if (logger) logger.debug("··· Computing T / ZH"); + polynomials.T.divZh(zkey.domainSize, 4); + if (logger) logger.debug("··· Computing Tz ifft"); + polynomials.Tz = await Polynomial.fromEvaluations(buffers.Tz, curve, logger); + polynomials.T.add(polynomials.Tz); + if (polynomials.T.degree() >= zkey.domainSize * 3 + 6) throw new Error("T Polynomial is not well calculated"); + if (logger) logger.debug("··· Computing T1, T2, T3 polynomials"); + polynomials.T1 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); + polynomials.T2 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); + polynomials.T3 = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 6) * n8r), curve, logger); + polynomials.T1.coef.set(polynomials.T.coef.slice(0, sDomain), 0); + polynomials.T2.coef.set(polynomials.T.coef.slice(sDomain, sDomain * 2), 0); + polynomials.T3.coef.set(polynomials.T.coef.slice(sDomain * 2, sDomain * 3 + 6 * n8r), 0); + polynomials.T1.setCoef(zkey.domainSize, challenges.b[10]); + const lowestMid = Fr.sub(polynomials.T2.getCoef(0), challenges.b[10]); + polynomials.T2.setCoef(0, lowestMid); + polynomials.T2.setCoef(zkey.domainSize, challenges.b[11]); + const lowestHigh = Fr.sub(polynomials.T3.getCoef(0), challenges.b[11]); + polynomials.T3.setCoef(0, lowestHigh); + } + async function round4() { + if (logger) logger.debug("> Computing challenge xi"); + transcript.reset(); + transcript.addScalar(challenges.alpha); + transcript.addPolCommitment(proof.getPolynomial("T1")); + transcript.addPolCommitment(proof.getPolynomial("T2")); + transcript.addPolCommitment(proof.getPolynomial("T3")); + challenges.xi = transcript.getChallenge(); + challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); + if (logger) logger.debug("··· challenges.xi: " + Fr.toString(challenges.xi, 16)); + proof.addEvaluation("eval_a", polynomials.A.evaluate(challenges.xi)); + proof.addEvaluation("eval_b", polynomials.B.evaluate(challenges.xi)); + proof.addEvaluation("eval_c", polynomials.C.evaluate(challenges.xi)); + proof.addEvaluation("eval_s1", polynomials.Sigma1.evaluate(challenges.xi)); + proof.addEvaluation("eval_s2", polynomials.Sigma2.evaluate(challenges.xi)); + proof.addEvaluation("eval_zw", polynomials.Z.evaluate(challenges.xiw)); + } + async function round5() { + if (logger) logger.debug("> Computing challenge v"); + transcript.reset(); + transcript.addScalar(challenges.xi); + transcript.addScalar(proof.getEvaluation("eval_a")); + transcript.addScalar(proof.getEvaluation("eval_b")); + transcript.addScalar(proof.getEvaluation("eval_c")); + transcript.addScalar(proof.getEvaluation("eval_s1")); + transcript.addScalar(proof.getEvaluation("eval_s2")); + transcript.addScalar(proof.getEvaluation("eval_zw")); + challenges.v = []; + challenges.v[1] = transcript.getChallenge(); + if (logger) logger.debug("··· challenges.v: " + Fr.toString(challenges.v[1], 16)); + for (let i = 2; i < 6; i++) challenges.v[i] = Fr.mul(challenges.v[i - 1], challenges.v[1]); + if (logger) logger.debug("> Computing linearisation polynomial R(X)"); + await computeR(); + if (logger) logger.debug("> Computing opening proof polynomial Wxi(X) polynomial"); + computeWxi(); + if (logger) logger.debug("> Computing opening proof polynomial Wxiw(X) polynomial"); + computeWxiw(); + if (logger) logger.debug("> Computing Wxi, Wxiw MSM"); + let commitWxi = await polynomials.Wxi.multiExponentiation(PTau, "Wxi"); + let commitWxiw = await polynomials.Wxiw.multiExponentiation(PTau, "Wxiw"); + proof.addPolynomial("Wxi", commitWxi); + proof.addPolynomial("Wxiw", commitWxiw); + } + async function computeR() { + const Fr = curve.Fr; + polynomials.QL = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QR = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QM = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QO = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QC = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[8][0].p); + await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[9][0].p); + await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[7][0].p); + await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[10][0].p); + await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[11][0].p); + challenges.xin = challenges.xi; + for (let i = 0; i < zkey.power; i++) challenges.xin = Fr.square(challenges.xin); + challenges.zh = Fr.sub(challenges.xin, Fr.one); + const L = []; + const n = Fr.e(zkey.domainSize); + let w = Fr.one; + for (let i = 1; i <= Math.max(1, zkey.nPublic); i++) { + L[i] = Fr.div(Fr.mul(w, challenges.zh), Fr.mul(n, Fr.sub(challenges.xi, w))); + w = Fr.mul(w, Fr.w[zkey.power]); + } + const eval_l1 = Fr.div(Fr.sub(challenges.xin, Fr.one), Fr.mul(n, Fr.sub(challenges.xi, Fr.one))); + if (logger) { + logger.debug("Lagrange Evaluations: "); + for (let i = 1; i < L.length; i++) logger.debug(`L${i}(xi)=` + Fr.toString(L[i], 16)); + } + let eval_pi = Fr.zero; + for (let i = 0; i < publicSignals.length; i++) { + const w = Fr.e(publicSignals[i]); + eval_pi = Fr.sub(eval_pi, Fr.mul(w, L[i + 1])); + } + if (logger) logger.debug("PI: " + Fr.toString(eval_pi, 16)); + const coef_ab = Fr.mul(proof.evaluations.eval_a, proof.evaluations.eval_b); + let e2a = proof.evaluations.eval_a; + const betaxi = Fr.mul(challenges.beta, challenges.xi); + e2a = Fr.add(e2a, betaxi); + e2a = Fr.add(e2a, challenges.gamma); + let e2b = proof.evaluations.eval_b; + e2b = Fr.add(e2b, Fr.mul(betaxi, zkey.k1)); + e2b = Fr.add(e2b, challenges.gamma); + let e2c = proof.evaluations.eval_c; + e2c = Fr.add(e2c, Fr.mul(betaxi, zkey.k2)); + e2c = Fr.add(e2c, challenges.gamma); + const e2 = Fr.mul(Fr.mul(Fr.mul(e2a, e2b), e2c), challenges.alpha); + let e3a = proof.evaluations.eval_a; + e3a = Fr.add(e3a, Fr.mul(challenges.beta, proof.evaluations.eval_s1)); + e3a = Fr.add(e3a, challenges.gamma); + let e3b = proof.evaluations.eval_b; + e3b = Fr.add(e3b, Fr.mul(challenges.beta, proof.evaluations.eval_s2)); + e3b = Fr.add(e3b, challenges.gamma); + let e3 = Fr.mul(e3a, e3b); + e3 = Fr.mul(e3, proof.evaluations.eval_zw); + e3 = Fr.mul(e3, challenges.alpha); + const e4 = Fr.mul(eval_l1, challenges.alpha2); + polynomials.R = new Polynomial(new ffjavascript.BigBuffer((zkey.domainSize + 6) * n8r), curve, logger); + polynomials.R.add(polynomials.QM, coef_ab); + polynomials.R.add(polynomials.QL, proof.evaluations.eval_a); + polynomials.R.add(polynomials.QR, proof.evaluations.eval_b); + polynomials.R.add(polynomials.QO, proof.evaluations.eval_c); + polynomials.R.add(polynomials.QC); + polynomials.R.add(polynomials.Z, e2); + polynomials.R.sub(polynomials.Sigma3, Fr.mul(e3, challenges.beta)); + polynomials.R.add(polynomials.Z, e4); + let tmp = Polynomial.fromPolynomial(polynomials.T3, curve, logger); + tmp.mulScalar(Fr.square(challenges.xin)); + tmp.add(polynomials.T2, challenges.xin); + tmp.add(polynomials.T1); + tmp.mulScalar(challenges.zh); + polynomials.R.sub(tmp); + let r0 = Fr.sub(eval_pi, Fr.mul(e3, Fr.add(proof.evaluations.eval_c, challenges.gamma))); + r0 = Fr.sub(r0, e4); + if (logger) logger.debug("r0: " + Fr.toString(r0, 16)); + polynomials.R.addScalar(r0); + } + function computeWxi() { + polynomials.Wxi = new Polynomial(new ffjavascript.BigBuffer(sDomain + 6 * n8r), curve, logger); + polynomials.Wxi.add(polynomials.R); + polynomials.Wxi.add(polynomials.A, challenges.v[1]); + polynomials.Wxi.add(polynomials.B, challenges.v[2]); + polynomials.Wxi.add(polynomials.C, challenges.v[3]); + polynomials.Wxi.add(polynomials.Sigma1, challenges.v[4]); + polynomials.Wxi.add(polynomials.Sigma2, challenges.v[5]); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[1], proof.evaluations.eval_a)); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[2], proof.evaluations.eval_b)); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[3], proof.evaluations.eval_c)); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[4], proof.evaluations.eval_s1)); + polynomials.Wxi.subScalar(Fr.mul(challenges.v[5], proof.evaluations.eval_s2)); + polynomials.Wxi.divByZerofier(1, challenges.xi); + } + async function computeWxiw() { + polynomials.Wxiw = Polynomial.fromPolynomial(polynomials.Z, curve, logger); + polynomials.Wxiw.subScalar(proof.evaluations.eval_zw); + polynomials.Wxiw.divByZerofier(1, challenges.xiw); + } +} +//#endregion +//#region src/plonk_fullprove.js +var { unstringifyBigInts: unstringifyBigInts$5 } = ffjavascript.utils; async function plonkFullProve(_input, wasmFile, zkeyFileName, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$5(_input); - - const wtns= { - type: "mem" - }; - await wtnsCalculate(input, wasmFile, wtns, wtnsCalcOptions); - return await plonk16Prove(zkeyFileName, wtns, logger, proverOptions); -} - -/* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const { unstringifyBigInts: unstringifyBigInts$4 } = ffjavascript.utils; - + const input = unstringifyBigInts$5(_input); + const wtns = { type: "mem" }; + await wtnsCalculate(input, wasmFile, wtns, wtnsCalcOptions); + return await plonk16Prove(zkeyFileName, wtns, logger, proverOptions); +} +//#endregion +//#region src/plonk_verify.js +var { unstringifyBigInts: unstringifyBigInts$4 } = ffjavascript.utils; async function plonkVerify(_vk_verifier, _publicSignals, _proof, logger) { - let vk_verifier = unstringifyBigInts$4(_vk_verifier); - _proof = unstringifyBigInts$4(_proof); - let publicSignals = unstringifyBigInts$4(_publicSignals); - - const curve = await getCurveFromName(vk_verifier.curve); - - const Fr = curve.Fr; - const G1 = curve.G1; - - if (logger) logger.info("PLONK VERIFIER STARTED"); - - let proof = fromObjectProof(curve,_proof); - vk_verifier = fromObjectVk$1(curve, vk_verifier); - - if (!isWellConstructed(curve, proof)) { - logger.error("Proof commitments are not valid."); - return false; - } - - if (publicSignals.length != vk_verifier.nPublic) { - if (logger) logger.error("Invalid number of public inputs"); - return false; - } - - if (!evaluationsAreValid$1(curve, proof)) { - if (logger) logger.error("Proof evaluations are not valid"); - return false; - } - - if (!publicInputsAreValid$1(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - const challenges = calculatechallenges(curve, proof, publicSignals, vk_verifier); - if (logger) { - logger.debug("beta: " + Fr.toString(challenges.beta, 16)); - logger.debug("gamma: " + Fr.toString(challenges.gamma, 16)); - logger.debug("alpha: " + Fr.toString(challenges.alpha, 16)); - logger.debug("xi: " + Fr.toString(challenges.xi, 16)); - for(let i=1;i<6;i++) { - if (logger) logger.debug("v: " + Fr.toString(challenges.v[i], 16)); - } - logger.debug("u: " + Fr.toString(challenges.u, 16)); - } - const L = calculateLagrangeEvaluations(curve, challenges, vk_verifier); - if (logger) { - for (let i=1; i. -*/ - -const { unstringifyBigInts: unstringifyBigInts$3} = ffjavascript.utils; - + const G1 = curve.G1; + const Fr = curve.Fr; + let A1 = proof.Wxi; + A1 = G1.add(A1, G1.timesFr(proof.Wxiw, challenges.u)); + let B1 = G1.timesFr(proof.Wxi, challenges.xi); + const s = Fr.mul(Fr.mul(challenges.u, challenges.xi), Fr.w[vk.power]); + B1 = G1.add(B1, G1.timesFr(proof.Wxiw, s)); + B1 = G1.add(B1, F); + B1 = G1.sub(B1, E); + return await curve.pairingEq(G1.neg(A1), vk.X_2, B1, curve.G2.one); +} +//#endregion +//#region src/plonk_exportsoliditycalldata.js +var { unstringifyBigInts: unstringifyBigInts$3 } = ffjavascript.utils; function p256$1(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0"+nstr; - nstr = `"0x${nstr}"`; - return nstr; + let nstr = n.toString(16); + while (nstr.length < 64) nstr = "0" + nstr; + nstr = `"0x${nstr}"`; + return nstr; } - async function plonkExportSolidityCallData(_proof, _pub) { - const proof = unstringifyBigInts$3(_proof); - const pub = unstringifyBigInts$3(_pub); - - await getCurveFromName(proof.curve); - - let inputs = ""; - for (let i=0; i. -*/ - -var plonk = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportSolidityCallData: plonkExportSolidityCallData, - fullProve: plonkFullProve, - prove: plonk16Prove, - setup: plonkSetup, - verify: plonkVerify + const proof = unstringifyBigInts$3(_proof); + const pub = unstringifyBigInts$3(_pub); + await getCurveFromName(proof.curve); + let inputs = ""; + for (let i = 0; i < pub.length; i++) { + if (inputs != "") inputs = inputs + ","; + inputs = inputs + p256$1(pub[i]); + } + return `[${p256$1(proof.A[0])}, ${p256$1(proof.A[1])},${p256$1(proof.B[0])},${p256$1(proof.B[1])},${p256$1(proof.C[0])},${p256$1(proof.C[1])},${p256$1(proof.Z[0])},${p256$1(proof.Z[1])},${p256$1(proof.T1[0])},${p256$1(proof.T1[1])},${p256$1(proof.T2[0])},${p256$1(proof.T2[1])},${p256$1(proof.T3[0])},${p256$1(proof.T3[1])},${p256$1(proof.Wxi[0])},${p256$1(proof.Wxi[1])},${p256$1(proof.Wxiw[0])},${p256$1(proof.Wxiw[1])},${p256$1(proof.eval_a)},${p256$1(proof.eval_b)},${p256$1(proof.eval_c)},${p256$1(proof.eval_s1)},${p256$1(proof.eval_s2)},${p256$1(proof.eval_zw)}][${inputs}]`; +} +//#endregion +//#region src/plonk.js +var plonk_exports = /* @__PURE__ */ __exportAll({ + exportSolidityCallData: () => plonkExportSolidityCallData, + fullProve: () => plonkFullProve, + prove: () => plonk16Prove, + setup: () => plonkSetup, + verify: () => plonkVerify }); - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -// We export to zkey the signals and values of the a, b, c, ql, qr, qm, qo and qc - -// a, b and c are signals id (32-bit integers) -// ql, qr, qm, qo and qc are field values - +//#endregion +//#region src/plonk_equation.js function getFFlonkConstantConstraint(signal1, Fr) { - return [signal1, 0, 0, Fr.one, Fr.zero, Fr.zero, Fr.zero, Fr.zero]; + return [ + signal1, + 0, + 0, + Fr.one, + Fr.zero, + Fr.zero, + Fr.zero, + Fr.zero + ]; } - function getFFlonkAdditionConstraint(signal1, signal2, signalOut, ql, qr, qm, qo, qc) { - return [signal1, signal2, signalOut, ql, qr, qm, qo, qc]; + return [ + signal1, + signal2, + signalOut, + ql, + qr, + qm, + qo, + qc + ]; } - function getFFlonkMultiplicationConstraint(signal1, signal2, signalOut, ql, qr, qm, qo, qc, Fr) { - return [signal1, signal2, signalOut, ql, qr, qm, qo, qc]; -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const LINEAR_COMBINATION_NULLABLE = 0; -const LINEAR_COMBINATION_CONSTANT = 1; -const LINEAR_COMBINATION_VARIABLE = 2; - -class r1csConstraintProcessor { - constructor(Fr, fnGetConstantConstraint, fnGetAdditionConstraint, fnGetMultiplicationConstraint, logger) { - this.Fr = Fr; - this.logger = logger; - this.fnGetAdditionConstraint = fnGetAdditionConstraint; - this.fnGetMultiplicationConstraint = fnGetMultiplicationConstraint; - } - - processR1csConstraint(settings, lcA, lcB, lcC) { - this.normalizeLinearCombination(lcA); - this.normalizeLinearCombination(lcB); - this.normalizeLinearCombination(lcC); - - const lctA = this.getLinearCombinationType(lcA); - const lctB = this.getLinearCombinationType(lcB); - - if ((lctA === LINEAR_COMBINATION_NULLABLE) || (lctB === LINEAR_COMBINATION_NULLABLE)) { - return this.processR1csAdditionConstraint(settings, lcC); - } else if (lctA === LINEAR_COMBINATION_CONSTANT) { - const lcCC = this.joinLinearCombinations(lcB, lcC, lcA[0]); - return this.processR1csAdditionConstraint(settings, lcCC); - } else if (lctB === LINEAR_COMBINATION_CONSTANT) { - const lcCC = this.joinLinearCombinations(lcA, lcC, lcB[0]); - return this.processR1csAdditionConstraint(settings, lcCC); - } else { - return this.processR1csMultiplicationConstraint(settings, lcA, lcB, lcC); - } - } - - getLinearCombinationType(linCom) { - // let k = this.Fr.zero; - // - // const signalIds = Object.keys(linCom); - // for (let i = 0; i < signalIds.length; i++) { - // if (signalIds[i] === "0") { - // k = this.Fr.add(k, linCom[signalIds[i]]); - // } else { - // return LINEAR_COMBINATION_VARIABLE; - // } - // } - // - // if (!this.Fr.eq(k, this.Fr.zero)) return LINEAR_COMBINATION_CONSTANT; - // - // return LINEAR_COMBINATION_NULLABLE; - - let k = this.Fr.zero; - let n = 0; - const ss = Object.keys(linCom); - for (let i = 0; i < ss.length; i++) { - if (linCom[ss[i]] == 0n) { - delete linCom[ss[i]]; - } else if (ss[i] == 0) { - k = this.Fr.add(k, linCom[ss[i]]); - } else { - n++; - } - } - if (n > 0) return LINEAR_COMBINATION_VARIABLE; - if (!this.Fr.isZero(k)) return LINEAR_COMBINATION_CONSTANT; - return LINEAR_COMBINATION_NULLABLE; - } - - normalizeLinearCombination(linCom) { - const signalIds = Object.keys(linCom); - for (let i = 0; i < signalIds.length; i++) { - if (this.Fr.isZero(linCom[signalIds[i]])) delete linCom[signalIds[i]]; - } - - return linCom; - } - - joinLinearCombinations(linCom1, linCom2, k) { - const res = {}; - - // for (let s in linCom1) { - // const val = this.Fr.mul(k, linCom1[s]); - // res[s] = !(s in res) ? val : this.Fr.add(val, res[s]); - // } - // - // for (let s in linCom2) { - // const val = this.Fr.mul(k, linCom2[s]); - // res[s] = !(s in res) ? val : this.Fr.add(val, res[s]); - // } - - for (let s in linCom1) { - if (typeof res[s] == "undefined") { - res[s] = this.Fr.mul(k, linCom1[s]); - } else { - res[s] = this.Fr.add(res[s], this.Fr.mul(k, linCom1[s])); - } - } - - for (let s in linCom2) { - if (typeof res[s] == "undefined") { - res[s] = linCom2[s]; - } else { - res[s] = this.Fr.add(res[s], linCom2[s]); - } - } - - return this.normalizeLinearCombination(res); - } - - reduceCoefs(settings, constraintsArr, additionsArr, linCom, maxC) { - const res = { - k: this.Fr.zero, - signals: [], - coefs: [] - }; - const cs = []; - - for (let signalId in linCom) { - if (signalId == 0) { - res.k = this.Fr.add(res.k, linCom[signalId]); - } else if (linCom[signalId] != 0n) { - cs.push([Number(signalId), linCom[signalId]]); - } - } - - while (cs.length > maxC) { - const c1 = cs.shift(); - const c2 = cs.shift(); - const so = settings.nVars++; - - const constraints = this.fnGetAdditionConstraint( - c1[0], c2[0], so, - this.Fr.neg(c1[1]), this.Fr.neg(c2[1]), this.Fr.zero, this.Fr.one, this.Fr.zero); - - constraintsArr.push(constraints); - additionsArr.push([c1[0], c2[0], c1[1], c2[1]]); - - cs.push([so, this.Fr.one]); - } - - for (let i = 0; i < cs.length; i++) { - res.signals[i] = cs[i][0]; - res.coefs[i] = cs[i][1]; - } - - while (res.coefs.length < maxC) { - res.signals.push(0); - res.coefs.push(this.Fr.zero); - } - - return res; - } - - processR1csAdditionConstraint(settings, linCom) { - const constraintsArr = []; - const additionsArr = []; - - const C = this.reduceCoefs(settings, constraintsArr, additionsArr, linCom, 3); - - const constraints = this.fnGetAdditionConstraint( - C.signals[0], C.signals[1], C.signals[2], - C.coefs[0], C.coefs[1], this.Fr.zero, C.coefs[2], C.k); - - constraintsArr.push(constraints); - - return [constraintsArr, additionsArr]; - } - - processR1csMultiplicationConstraint(settings, lcA, lcB, lcC) { - const constraintsArr = []; - const additionsArr = []; - - const A = this.reduceCoefs(settings, constraintsArr, additionsArr, lcA, 1); - const B = this.reduceCoefs(settings, constraintsArr, additionsArr, lcB, 1); - const C = this.reduceCoefs(settings, constraintsArr, additionsArr, lcC, 1); - - const constraints = this.fnGetMultiplicationConstraint( - A.signals[0], B.signals[0], C.signals[0], - this.Fr.mul(A.coefs[0], B.k), - this.Fr.mul(A.k, B.coefs[0]), - this.Fr.mul(A.coefs[0], B.coefs[0]), - this.Fr.neg(C.coefs[0]), - this.Fr.sub(this.Fr.mul(A.k, B.k), C.k)); - - constraintsArr.push(constraints); - - return [constraintsArr, additionsArr]; - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -class CPolynomial { - constructor(n, curve, logger) { - this.n = n; - this.polynomials = Array(n).fill(undefined); - this.curve = curve; - this.Fr = curve.Fr; - this.G1 = curve.G1; - this.logger = logger; - } - - addPolynomial(position, polynomial) { - if (position > this.n - 1) { - throw new Error("CPolynomial:addPolynomial, cannot add a polynomial to a position greater than n-1"); - } - - this.polynomials[position] = polynomial; - } - - degree() { - let degrees = this.polynomials.map( - (polynomial, index) => polynomial === undefined ? 0 : polynomial.degree() * this.n + index); - return Math.max(...degrees); - } - - getPolynomial() { - let degrees = this.polynomials.map(polynomial => polynomial === undefined ? 0 : polynomial.degree()); - const maxDegree = this.degree(); - const lengthBuffer = 2 ** (log2(maxDegree - 1) + 1); - const sFr = this.Fr.n8; - - let polynomial = new Polynomial(new ffjavascript.BigBuffer(lengthBuffer * sFr), this.curve, this.logger); - - for (let i = 0; i < maxDegree; i++) { - const i_n8 = i * sFr; - const i_sFr = i_n8 * this.n; - - for (let j = 0; j < this.n; j++) { - if (this.polynomials[j] !== undefined) { - if (i <= degrees[j]) polynomial.coef.set(this.polynomials[j].coef.slice(i_n8, i_n8 + sFr), i_sFr + j * sFr); - } - } - } - - return polynomial; - } - - async multiExponentiation(PTau, name) { - let polynomial = this.getPolynomial(); - const n = polynomial.coef.byteLength / this.Fr.n8; - const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); - const bm = await this.Fr.batchFromMontgomery(polynomial.coef); - let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); - res = this.G1.toAffine(res); - return res; - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - - + return [ + signal1, + signal2, + signalOut, + ql, + qr, + qm, + qo, + qc + ]; +} +//#endregion +//#region src/r1cs_constraint_processor.js +var LINEAR_COMBINATION_NULLABLE = 0; +var LINEAR_COMBINATION_CONSTANT = 1; +var LINEAR_COMBINATION_VARIABLE = 2; +var r1csConstraintProcessor = class { + constructor(Fr, fnGetConstantConstraint, fnGetAdditionConstraint, fnGetMultiplicationConstraint, logger) { + this.Fr = Fr; + this.logger = logger; + this.fnGetAdditionConstraint = fnGetAdditionConstraint; + this.fnGetMultiplicationConstraint = fnGetMultiplicationConstraint; + } + processR1csConstraint(settings, lcA, lcB, lcC) { + this.normalizeLinearCombination(lcA); + this.normalizeLinearCombination(lcB); + this.normalizeLinearCombination(lcC); + const lctA = this.getLinearCombinationType(lcA); + const lctB = this.getLinearCombinationType(lcB); + if (lctA === LINEAR_COMBINATION_NULLABLE || lctB === LINEAR_COMBINATION_NULLABLE) return this.processR1csAdditionConstraint(settings, lcC); + else if (lctA === LINEAR_COMBINATION_CONSTANT) { + const lcCC = this.joinLinearCombinations(lcB, lcC, lcA[0]); + return this.processR1csAdditionConstraint(settings, lcCC); + } else if (lctB === LINEAR_COMBINATION_CONSTANT) { + const lcCC = this.joinLinearCombinations(lcA, lcC, lcB[0]); + return this.processR1csAdditionConstraint(settings, lcCC); + } else return this.processR1csMultiplicationConstraint(settings, lcA, lcB, lcC); + } + getLinearCombinationType(linCom) { + let k = this.Fr.zero; + let n = 0; + const ss = Object.keys(linCom); + for (let i = 0; i < ss.length; i++) if (linCom[ss[i]] == 0n) delete linCom[ss[i]]; + else if (ss[i] == 0) k = this.Fr.add(k, linCom[ss[i]]); + else n++; + if (n > 0) return LINEAR_COMBINATION_VARIABLE; + if (!this.Fr.isZero(k)) return LINEAR_COMBINATION_CONSTANT; + return LINEAR_COMBINATION_NULLABLE; + } + normalizeLinearCombination(linCom) { + const signalIds = Object.keys(linCom); + for (let i = 0; i < signalIds.length; i++) if (this.Fr.isZero(linCom[signalIds[i]])) delete linCom[signalIds[i]]; + return linCom; + } + joinLinearCombinations(linCom1, linCom2, k) { + const res = {}; + for (let s in linCom1) if (typeof res[s] == "undefined") res[s] = this.Fr.mul(k, linCom1[s]); + else res[s] = this.Fr.add(res[s], this.Fr.mul(k, linCom1[s])); + for (let s in linCom2) if (typeof res[s] == "undefined") res[s] = linCom2[s]; + else res[s] = this.Fr.add(res[s], linCom2[s]); + return this.normalizeLinearCombination(res); + } + reduceCoefs(settings, constraintsArr, additionsArr, linCom, maxC) { + const res = { + k: this.Fr.zero, + signals: [], + coefs: [] + }; + const cs = []; + for (let signalId in linCom) if (signalId == 0) res.k = this.Fr.add(res.k, linCom[signalId]); + else if (linCom[signalId] != 0n) cs.push([Number(signalId), linCom[signalId]]); + while (cs.length > maxC) { + const c1 = cs.shift(); + const c2 = cs.shift(); + const so = settings.nVars++; + const constraints = this.fnGetAdditionConstraint(c1[0], c2[0], so, this.Fr.neg(c1[1]), this.Fr.neg(c2[1]), this.Fr.zero, this.Fr.one, this.Fr.zero); + constraintsArr.push(constraints); + additionsArr.push([ + c1[0], + c2[0], + c1[1], + c2[1] + ]); + cs.push([so, this.Fr.one]); + } + for (let i = 0; i < cs.length; i++) { + res.signals[i] = cs[i][0]; + res.coefs[i] = cs[i][1]; + } + while (res.coefs.length < maxC) { + res.signals.push(0); + res.coefs.push(this.Fr.zero); + } + return res; + } + processR1csAdditionConstraint(settings, linCom) { + const constraintsArr = []; + const additionsArr = []; + const C = this.reduceCoefs(settings, constraintsArr, additionsArr, linCom, 3); + const constraints = this.fnGetAdditionConstraint(C.signals[0], C.signals[1], C.signals[2], C.coefs[0], C.coefs[1], this.Fr.zero, C.coefs[2], C.k); + constraintsArr.push(constraints); + return [constraintsArr, additionsArr]; + } + processR1csMultiplicationConstraint(settings, lcA, lcB, lcC) { + const constraintsArr = []; + const additionsArr = []; + const A = this.reduceCoefs(settings, constraintsArr, additionsArr, lcA, 1); + const B = this.reduceCoefs(settings, constraintsArr, additionsArr, lcB, 1); + const C = this.reduceCoefs(settings, constraintsArr, additionsArr, lcC, 1); + const constraints = this.fnGetMultiplicationConstraint(A.signals[0], B.signals[0], C.signals[0], this.Fr.mul(A.coefs[0], B.k), this.Fr.mul(A.k, B.coefs[0]), this.Fr.mul(A.coefs[0], B.coefs[0]), this.Fr.neg(C.coefs[0]), this.Fr.sub(this.Fr.mul(A.k, B.k), C.k)); + constraintsArr.push(constraints); + return [constraintsArr, additionsArr]; + } +}; +//#endregion +//#region src/polynomial/cpolynomial.js +var CPolynomial = class { + constructor(n, curve, logger) { + this.n = n; + this.polynomials = Array(n).fill(void 0); + this.curve = curve; + this.Fr = curve.Fr; + this.G1 = curve.G1; + this.logger = logger; + } + addPolynomial(position, polynomial) { + if (position > this.n - 1) throw new Error("CPolynomial:addPolynomial, cannot add a polynomial to a position greater than n-1"); + this.polynomials[position] = polynomial; + } + degree() { + let degrees = this.polynomials.map((polynomial, index) => polynomial === void 0 ? 0 : polynomial.degree() * this.n + index); + return Math.max(...degrees); + } + getPolynomial() { + let degrees = this.polynomials.map((polynomial) => polynomial === void 0 ? 0 : polynomial.degree()); + const maxDegree = this.degree(); + const lengthBuffer = 2 ** (log2(maxDegree - 1) + 1); + const sFr = this.Fr.n8; + let polynomial = new Polynomial(new ffjavascript.BigBuffer(lengthBuffer * sFr), this.curve, this.logger); + for (let i = 0; i < maxDegree; i++) { + const i_n8 = i * sFr; + const i_sFr = i_n8 * this.n; + for (let j = 0; j < this.n; j++) if (this.polynomials[j] !== void 0) { + if (i <= degrees[j]) polynomial.coef.set(this.polynomials[j].coef.slice(i_n8, i_n8 + sFr), i_sFr + j * sFr); + } + } + return polynomial; + } + async multiExponentiation(PTau, name) { + let polynomial = this.getPolynomial(); + const n = polynomial.coef.byteLength / this.Fr.n8; + const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); + const bm = await this.Fr.batchFromMontgomery(polynomial.coef); + let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); + res = this.G1.toAffine(res); + return res; + } +}; +//#endregion +//#region src/fflonk_setup.js async function fflonkSetup(r1csFilename, ptauFilename, zkeyFilename, logger) { - if (logger) logger.info("FFLONK SETUP STARTED"); - - if (globalThis.gc) globalThis.gc(); - - // Read PTau file - if (logger) logger.info("> Reading PTau file"); - const {fd: fdPTau, sections: pTauSections} = await binFileUtils.readBinFile(ptauFilename, "ptau", 1, 1 << 22, 1 << 24); - if (!pTauSections[12]) { - throw new Error("Powers of Tau is not well prepared. Section 12 missing."); - } - - // Get curve defined in PTau - if (logger) logger.info("> Getting curve from PTau settings"); - const {curve} = await readPTauHeader(fdPTau, pTauSections); - - // Read r1cs file - if (logger) logger.info("> Reading r1cs file"); - const {fd: fdR1cs, sections: sectionsR1cs} = await binFileUtils.readBinFile(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); - const r1cs = await r1csfile.readR1csFd(fdR1cs, sectionsR1cs, {loadConstraints: false, loadCustomGates: true}); - - // Potential error checks - if (r1cs.prime !== curve.r) { - throw new Error("r1cs curve does not match powers of tau ceremony curve"); - } - - // Initializations - const Fr = curve.Fr; - - const sFr = curve.Fr.n8; - const sG1 = curve.G1.F.n8 * 2; - const sG2 = curve.G2.F.n8 * 2; - - let polynomials = {}; - let evaluations = {}; - let PTau; - - let settings = { - nVars: r1cs.nVars, - nPublic: r1cs.nOutputs + r1cs.nPubInputs - }; - - const plonkConstraints = new BigArray(); - let plonkAdditions = new BigArray(); - - // Process constraints inside r1cs - if (logger) logger.info("> Processing FFlonk constraints"); - await computeFFConstraints(curve.Fr, r1cs, logger); - if (globalThis.gc) globalThis.gc(); - - // As the t polynomial is n+5 we need at least a power of 4 - //TODO check!!!! - // NOTE : plonkConstraints + 2 = #constraints + blinding coefficients for each wire polynomial - settings.cirPower = Math.max(FF_T_POL_DEG_MIN, log2((plonkConstraints.length + 2) - 1) + 1); - settings.domainSize = 2 ** settings.cirPower; - - if (pTauSections[2][0].size < (settings.domainSize * 9 + 18) * sG1) { - throw new Error("Powers of Tau is not big enough for this circuit size. Section 2 too small."); - } - if (pTauSections[3][0].size < sG2) { - throw new Error("Powers of Tau is not well prepared. Section 3 too small."); - } - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK SETUP SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${settings.cirPower}`); - logger.info(` Domain size: ${settings.domainSize}`); - logger.info(` Vars: ${settings.nVars}`); - logger.info(` Public vars: ${settings.nPublic}`); - logger.info(` Constraints: ${plonkConstraints.length}`); - logger.info(` Additions: ${plonkAdditions.length}`); - logger.info("----------------------------"); - } - - // Compute k1 and k2 to be used in the permutation checks - if (logger) logger.info("> computing k1 and k2"); - const [k1, k2] = computeK1K2(); - - // Compute omega 3 (w3) and omega 4 (w4) to be used in the prover and the verifier - // w3^3 = 1 and w4^4 = 1 - if (logger) logger.info("> computing w3"); - const w3 = computeW3(); - if (logger) logger.info("> computing w4"); - const w4 = computeW4(); - if (logger) logger.info("> computing w8"); - const w8 = computeW8(); - if (logger) logger.info("> computing wr"); - const wr = getOmegaCubicRoot(settings.cirPower, curve.Fr); - - // Write output zkey file - await writeZkeyFile(); - - await fdR1cs.close(); - await fdPTau.close(); - - if (logger) logger.info("FFLONK SETUP FINISHED"); - - return 0; - - async function computeFFConstraints(Fr, r1cs, logger) { - // Add public inputs and outputs - for (let i = 0; i < settings.nPublic; i++) { - plonkConstraints.push(getFFlonkConstantConstraint(i + 1, Fr)); - } - - // Add all constraints from r1cs file - const r1csProcessor = new r1csConstraintProcessor(Fr, getFFlonkConstantConstraint, getFFlonkAdditionConstraint, getFFlonkMultiplicationConstraint, logger); - - const bR1cs = await binFileUtils__namespace.readSection(fdR1cs, sectionsR1cs, 2); - let bR1csPos = 0; - for (let i = 0; i < r1cs.nConstraints; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` processing r1cs constraints ${i}/${r1cs.nConstraints}`); - } - const [constraints, additions] = r1csProcessor.processR1csConstraint(settings, ...readConstraint()); - - plonkConstraints.push(...constraints); - plonkAdditions.push(...additions); - } - - function readConstraint() { - const c = []; - c[0] = readLC(); - c[1] = readLC(); - c[2] = readLC(); - return c; - } - - function readLC() { - const lc = {}; - - const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); - bR1csPos += 4; - const buffUL32V = new DataView(buffUL32.buffer); - const nIdx = buffUL32V.getUint32(0, true); - - const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); - bR1csPos += (4 + r1cs.n8) * nIdx; - const buffV = new DataView(buff.buffer); - for (let i = 0; i < nIdx; i++) { - const idx = buffV.getUint32(i * (4 + r1cs.n8), true); - const val = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); - lc[idx] = val; - } - return lc; - } - - return 0; - } - - async function writeZkeyFile() { - if (logger) logger.info("> Writing the zkey file"); - const fdZKey = await binFileUtils.createBinFile(zkeyFilename, "zkey", 1, ZKEY_FF_NSECTIONS, 1 << 22, 1 << 24); - - if (logger) logger.info(`··· Writing Section ${HEADER_ZKEY_SECTION}. Zkey Header`); - await writeZkeyHeader(fdZKey); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_ADDITIONS_SECTION}. Additions`); - await writeAdditions(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_A_MAP_SECTION}. A Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_A_MAP_SECTION, 0, "A map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_B_MAP_SECTION}. B Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_B_MAP_SECTION, 1, "B map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_C_MAP_SECTION}. C Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_C_MAP_SECTION, 2, "C map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QL_SECTION}. QL`); - await writeQMap(fdZKey, ZKEY_FF_QL_SECTION, 3, "QL"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QR_SECTION}. QR`); - await writeQMap(fdZKey, ZKEY_FF_QR_SECTION, 4, "QR"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QM_SECTION}. QM`); - await writeQMap(fdZKey, ZKEY_FF_QM_SECTION, 5, "QM"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QO_SECTION}. QO`); - await writeQMap(fdZKey, ZKEY_FF_QO_SECTION, 6, "QO"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QC_SECTION}. QC`); - await writeQMap(fdZKey, ZKEY_FF_QC_SECTION, 7, "QC"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Sections ${ZKEY_FF_SIGMA1_SECTION},${ZKEY_FF_SIGMA2_SECTION},${ZKEY_FF_SIGMA3_SECTION}. Sigma1, Sigma2 & Sigma 3`); - await writeSigma(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_LAGRANGE_SECTION}. Lagrange Polynomials`); - await writeLagrangePolynomials(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_PTAU_SECTION}. Powers of Tau`); - await writePtau(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_C0_SECTION}. C0`); - await writeC0(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_HEADER_SECTION}. FFlonk Header`); - await writeFFlonkHeader(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info("> Writing the zkey file finished"); - - await fdZKey.close(); - } - - async function writeZkeyHeader(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, HEADER_ZKEY_SECTION); - await fdZKey.writeULE32(FFLONK_PROTOCOL_ID); - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeAdditions(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_ADDITIONS_SECTION); - - // Written values are 2 * 32 bit integers (2 * 4 bytes) + 2 field size values ( 2 * sFr bytes) - const buffOut = new Uint8Array(8 + 2 * sFr); - const buffOutV = new DataView(buffOut.buffer); - - for (let i = 0; i < plonkAdditions.length; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) logger.info(` writing Additions: ${i}/${plonkAdditions.length}`); - - const addition = plonkAdditions[i]; - - buffOutV.setUint32(0, addition[0], true); - buffOutV.setUint32(4, addition[1], true); - buffOut.set(addition[2], 8); - buffOut.set(addition[3], 8 + sFr); - - await fdZKey.write(buffOut); - } - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeWitnessMap(fdZKey, sectionNum, posConstraint, name) { - await binFileUtils.startWriteSection(fdZKey, sectionNum); - for (let i = 0; i < plonkConstraints.length; i++) { - if (logger && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing witness ${name}: ${i}/${plonkConstraints.length}`); - } - - await fdZKey.writeULE32(plonkConstraints[i][posConstraint]); - } - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeQMap(fdZKey, sectionNum, posConstraint, name) { - // Compute Q from q evaluations - let Q = new ffjavascript.BigBuffer(settings.domainSize * sFr); - - for (let i = 0; i < plonkConstraints.length; i++) { - Q.set(plonkConstraints[i][posConstraint], i * sFr); - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing ${name}: ${i}/${plonkConstraints.length}`); - } - } - - polynomials[name] = await Polynomial.fromEvaluations(Q, curve, logger); - evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); - - // Write Q coefficients and evaluations - await binFileUtils.startWriteSection(fdZKey, sectionNum); - await fdZKey.write(polynomials[name].coef); - await fdZKey.write(evaluations[name].eval); - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeSigma(fdZKey) { - // Compute sigma - const sigma = new ffjavascript.BigBuffer(sFr * settings.domainSize * 3); - const lastSeen = new BigArray(settings.nVars); - const firstPos = new BigArray(settings.nVars); - - let w = Fr.one; - for (let i = 0; i < settings.domainSize; i++) { - if (i < plonkConstraints.length) { - buildSigma(plonkConstraints[i][0], i); - buildSigma(plonkConstraints[i][1], settings.domainSize + i); - buildSigma(plonkConstraints[i][2], settings.domainSize * 2 + i); - } else if (i < settings.domainSize - 2) { - buildSigma(0, i); - buildSigma(0, settings.domainSize + i); - buildSigma(0, settings.domainSize * 2 + i); - } else { - sigma.set(w, i * sFr); - sigma.set(Fr.mul(w, k1), (settings.domainSize + i) * sFr); - sigma.set(Fr.mul(w, k2), (settings.domainSize * 2 + i) * sFr); - } - - w = Fr.mul(w, Fr.w[settings.cirPower]); - - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing sigma phase1: ${i}/${plonkConstraints.length}`); - } - } - - for (let i = 0; i < settings.nVars; i++) { - if (typeof firstPos[i] !== "undefined") { - sigma.set(lastSeen[i], firstPos[i] * sFr); - } else { - // throw new Error("Variable not used"); - console.log("Variable not used"); - } - if ((logger) && (i !== 0) && (i % 500000 === 0)) logger.info(` writing sigma phase2: ${i}/${settings.nVars}`); - } - - if (globalThis.gc) globalThis.gc(); - - // Write sigma coefficients and evaluations - for (let i = 0; i < 3; i++) { - const sectionId = 0 === i ? ZKEY_FF_SIGMA1_SECTION : 1 === i ? ZKEY_FF_SIGMA2_SECTION : ZKEY_FF_SIGMA3_SECTION; - - let name = "S" + (i + 1); - polynomials[name] = await Polynomial.fromEvaluations(sigma.slice(settings.domainSize * sFr * i, settings.domainSize * sFr * (i + 1)), curve, logger); - evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); - await binFileUtils.startWriteSection(fdZKey, sectionId); - await fdZKey.write(polynomials[name].coef); - await fdZKey.write(evaluations[name].eval); - await binFileUtils.endWriteSection(fdZKey); - - if (globalThis.gc) globalThis.gc(); - } - - return 0; - - function buildSigma(signalId, idx) { - if (typeof lastSeen[signalId] === "undefined") { - firstPos[signalId] = idx; - } else { - sigma.set(lastSeen[signalId], idx * sFr); - } - let v; - if (idx < settings.domainSize) { - v = w; - } else if (idx < 2 * settings.domainSize) { - v = Fr.mul(w, k1); - } else { - v = Fr.mul(w, k2); - } - - lastSeen[signalId] = v; - } - } - - async function writeLagrangePolynomials(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_LAGRANGE_SECTION); - - const l = Math.max(settings.nPublic, 1); - for (let i = 0; i < l; i++) { - let buff = new ffjavascript.BigBuffer(settings.domainSize * sFr); - buff.set(Fr.one, i * sFr); - - await writeP4(fdZKey, buff); - } - await binFileUtils.endWriteSection(fdZKey); - } - - async function writePtau(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_PTAU_SECTION); - - // domainSize * 9 + 18 = maximum SRS length needed, specifically to commit C2 - PTau = new ffjavascript.BigBuffer((settings.domainSize * 9 + 18) * sG1); - await fdPTau.readToBuffer(PTau, 0, (settings.domainSize * 9 + 18) * sG1, pTauSections[2][0].p); - - await fdZKey.write(PTau); - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeC0(fdZKey) { - // C0(X) := QL(X^8) + X · QR(X^8) + X^2 · QO(X^8) + X^3 · QM(X^8) + X^4 · QC(X^8) - // + X^5 · SIGMA1(X^8) + X^6 · SIGMA2(X^8) + X^7 · SIGMA3(X^8) - let C0 = new CPolynomial(8, curve, logger); - C0.addPolynomial(0, polynomials.QL); - C0.addPolynomial(1, polynomials.QR); - C0.addPolynomial(2, polynomials.QO); - C0.addPolynomial(3, polynomials.QM); - C0.addPolynomial(4, polynomials.QC); - C0.addPolynomial(5, polynomials.S1); - C0.addPolynomial(6, polynomials.S2); - C0.addPolynomial(7, polynomials.S3); - - polynomials.C0 = C0.getPolynomial(); - - // Check degree - if (polynomials.C0.degree() >= 8 * settings.domainSize) { - throw new Error("C0 Polynomial is not well calculated"); - } - - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_C0_SECTION); - await fdZKey.write(polynomials.C0.coef); - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeFFlonkHeader(fdZKey) { - await binFileUtils.startWriteSection(fdZKey, ZKEY_FF_HEADER_SECTION); - - const primeQ = curve.q; - const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; - await fdZKey.writeULE32(n8q); - await binFileUtils.writeBigInt(fdZKey, primeQ, n8q); - - const primeR = curve.r; - const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; - await fdZKey.writeULE32(n8r); - await binFileUtils.writeBigInt(fdZKey, primeR, n8r); - - // Total number of r1cs vars - await fdZKey.writeULE32(settings.nVars); - // Total number of r1cs public vars = outputs + public inputs - await fdZKey.writeULE32(settings.nPublic); - await fdZKey.writeULE32(settings.domainSize); - await fdZKey.writeULE32(plonkAdditions.length); - await fdZKey.writeULE32(plonkConstraints.length); - - await fdZKey.write(k1); - await fdZKey.write(k2); - - await fdZKey.write(w3); - await fdZKey.write(w4); - await fdZKey.write(w8); - await fdZKey.write(wr); - - let bX_2; - bX_2 = await fdPTau.read(sG2, pTauSections[3][0].p + sG2); - await fdZKey.write(bX_2); - - let commitC0 = await polynomials.C0.multiExponentiation(PTau, "C0"); - await fdZKey.write(commitC0); - - await binFileUtils.endWriteSection(fdZKey); - } - - async function writeP4(fdZKey, buff) { - const [coefficients, evaluations4] = await Polynomial.to4T(buff, settings.domainSize, [], Fr); - await fdZKey.write(coefficients); - await fdZKey.write(evaluations4); - - return [coefficients, evaluations4]; - } - - function computeK1K2() { - let k1 = Fr.two; - while (isIncluded(k1, [], settings.cirPower)) Fr.add(k1, Fr.one); - let k2 = Fr.add(k1, Fr.one); - while (isIncluded(k2, [k1], settings.cirPower)) Fr.add(k2, Fr.one); - return [k1, k2]; - - function isIncluded(k, kArr, pow) { - const domainSize = 2 ** pow; - let w = Fr.one; - for (let i = 0; i < domainSize; i++) { - if (Fr.eq(k, w)) return true; - for (let j = 0; j < kArr.length; j++) { - if (Fr.eq(k, Fr.mul(kArr[j], w))) return true; - } - w = Fr.mul(w, Fr.w[pow]); - } - return false; - } - } - - function computeW3() { - let generator = Fr.e(31624); - - // Exponent is order(r - 1) / 3 - let orderRsub1 = 3648040478639879203707734290876212514758060733402672390616367364429301415936n; - let exponent = ffjavascript.Scalar.div(orderRsub1, ffjavascript.Scalar.e(3)); - - return Fr.exp(generator, exponent); - } - - function computeW4() { - return Fr.w[2]; - } - - function computeW8() { - return Fr.w[3]; - } - - function getOmegaCubicRoot(power, Fr) { - // Hardcorded 3th-root of Fr.w[28] - const firstRoot = Fr.e(467799165886069610036046866799264026481344299079011762026774533774345988080n); - - return Fr.exp(firstRoot, 2 ** (28 - power)); - } -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const { stringifyBigInts } = ffjavascript.utils; - - + if (logger) logger.info("FFLONK SETUP STARTED"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> Reading PTau file"); + const { fd: fdPTau, sections: pTauSections } = await (0, _iden3_binfileutils.readBinFile)(ptauFilename, "ptau", 1, 1 << 22, 1 << 24); + if (!pTauSections[12]) throw new Error("Powers of Tau is not well prepared. Section 12 missing."); + if (logger) logger.info("> Getting curve from PTau settings"); + const { curve } = await readPTauHeader(fdPTau, pTauSections); + if (logger) logger.info("> Reading r1cs file"); + const { fd: fdR1cs, sections: sectionsR1cs } = await (0, _iden3_binfileutils.readBinFile)(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); + const r1cs = await (0, r1csfile.readR1csFd)(fdR1cs, sectionsR1cs, { + loadConstraints: false, + loadCustomGates: true + }); + if (r1cs.prime !== curve.r) throw new Error("r1cs curve does not match powers of tau ceremony curve"); + const Fr = curve.Fr; + const sFr = curve.Fr.n8; + const sG1 = curve.G1.F.n8 * 2; + const sG2 = curve.G2.F.n8 * 2; + let polynomials = {}; + let evaluations = {}; + let PTau; + let settings = { + nVars: r1cs.nVars, + nPublic: r1cs.nOutputs + r1cs.nPubInputs + }; + const plonkConstraints = new BigArray(); + let plonkAdditions = new BigArray(); + if (logger) logger.info("> Processing FFlonk constraints"); + await computeFFConstraints(curve.Fr, r1cs, logger); + if (globalThis.gc) globalThis.gc(); + settings.cirPower = Math.max(3, log2(plonkConstraints.length + 2 - 1) + 1); + settings.domainSize = 2 ** settings.cirPower; + if (pTauSections[2][0].size < (settings.domainSize * 9 + 18) * sG1) throw new Error("Powers of Tau is not big enough for this circuit size. Section 2 too small."); + if (pTauSections[3][0].size < sG2) throw new Error("Powers of Tau is not well prepared. Section 3 too small."); + if (logger) { + logger.info("----------------------------"); + logger.info(" FFLONK SETUP SETTINGS"); + logger.info(` Curve: ${curve.name}`); + logger.info(` Circuit power: ${settings.cirPower}`); + logger.info(` Domain size: ${settings.domainSize}`); + logger.info(` Vars: ${settings.nVars}`); + logger.info(` Public vars: ${settings.nPublic}`); + logger.info(` Constraints: ${plonkConstraints.length}`); + logger.info(` Additions: ${plonkAdditions.length}`); + logger.info("----------------------------"); + } + if (logger) logger.info("> computing k1 and k2"); + const [k1, k2] = computeK1K2(); + if (logger) logger.info("> computing w3"); + const w3 = computeW3(); + if (logger) logger.info("> computing w4"); + const w4 = computeW4(); + if (logger) logger.info("> computing w8"); + const w8 = computeW8(); + if (logger) logger.info("> computing wr"); + const wr = getOmegaCubicRoot(settings.cirPower, curve.Fr); + await writeZkeyFile(); + await fdR1cs.close(); + await fdPTau.close(); + if (logger) logger.info("FFLONK SETUP FINISHED"); + return 0; + async function computeFFConstraints(Fr, r1cs, logger) { + for (let i = 0; i < settings.nPublic; i++) plonkConstraints.push(getFFlonkConstantConstraint(i + 1, Fr)); + const r1csProcessor = new r1csConstraintProcessor(Fr, getFFlonkConstantConstraint, getFFlonkAdditionConstraint, getFFlonkMultiplicationConstraint, logger); + const bR1cs = await _iden3_binfileutils.readSection(fdR1cs, sectionsR1cs, 2); + let bR1csPos = 0; + for (let i = 0; i < r1cs.nConstraints; i++) { + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` processing r1cs constraints ${i}/${r1cs.nConstraints}`); + const [constraints, additions] = r1csProcessor.processR1csConstraint(settings, ...readConstraint()); + plonkConstraints.push(...constraints); + plonkAdditions.push(...additions); + } + function readConstraint() { + const c = []; + c[0] = readLC(); + c[1] = readLC(); + c[2] = readLC(); + return c; + } + function readLC() { + const lc = {}; + const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); + bR1csPos += 4; + const nIdx = new DataView(buffUL32.buffer).getUint32(0, true); + const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); + bR1csPos += (4 + r1cs.n8) * nIdx; + const buffV = new DataView(buff.buffer); + for (let i = 0; i < nIdx; i++) { + const idx = buffV.getUint32(i * (4 + r1cs.n8), true); + lc[idx] = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); + } + return lc; + } + return 0; + } + async function writeZkeyFile() { + if (logger) logger.info("> Writing the zkey file"); + const fdZKey = await (0, _iden3_binfileutils.createBinFile)(zkeyFilename, "zkey", 1, 17, 1 << 22, 1 << 24); + if (logger) logger.info(`··· Writing Section 1. Zkey Header`); + await writeZkeyHeader(fdZKey); + if (logger) logger.info(`··· Writing Section 3. Additions`); + await writeAdditions(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 4. A Map`); + await writeWitnessMap(fdZKey, 4, 0, "A map"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 5. B Map`); + await writeWitnessMap(fdZKey, 5, 1, "B map"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 6. C Map`); + await writeWitnessMap(fdZKey, 6, 2, "C map"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 7. QL`); + await writeQMap(fdZKey, 7, 3, "QL"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 8. QR`); + await writeQMap(fdZKey, 8, 4, "QR"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 9. QM`); + await writeQMap(fdZKey, 9, 5, "QM"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 10. QO`); + await writeQMap(fdZKey, 10, 6, "QO"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 11. QC`); + await writeQMap(fdZKey, 11, 7, "QC"); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Sections 12,13,14. Sigma1, Sigma2 & Sigma 3`); + await writeSigma(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 15. Lagrange Polynomials`); + await writeLagrangePolynomials(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 16. Powers of Tau`); + await writePtau(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 17. C0`); + await writeC0(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(`··· Writing Section 2. FFlonk Header`); + await writeFFlonkHeader(fdZKey); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> Writing the zkey file finished"); + await fdZKey.close(); + } + async function writeZkeyHeader(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 1); + await fdZKey.writeULE32(10); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeAdditions(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 3); + const buffOut = new Uint8Array(8 + 2 * sFr); + const buffOutV = new DataView(buffOut.buffer); + for (let i = 0; i < plonkAdditions.length; i++) { + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing Additions: ${i}/${plonkAdditions.length}`); + const addition = plonkAdditions[i]; + buffOutV.setUint32(0, addition[0], true); + buffOutV.setUint32(4, addition[1], true); + buffOut.set(addition[2], 8); + buffOut.set(addition[3], 8 + sFr); + await fdZKey.write(buffOut); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeWitnessMap(fdZKey, sectionNum, posConstraint, name) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + for (let i = 0; i < plonkConstraints.length; i++) { + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing witness ${name}: ${i}/${plonkConstraints.length}`); + await fdZKey.writeULE32(plonkConstraints[i][posConstraint]); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeQMap(fdZKey, sectionNum, posConstraint, name) { + let Q = new ffjavascript.BigBuffer(settings.domainSize * sFr); + for (let i = 0; i < plonkConstraints.length; i++) { + Q.set(plonkConstraints[i][posConstraint], i * sFr); + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing ${name}: ${i}/${plonkConstraints.length}`); + } + polynomials[name] = await Polynomial.fromEvaluations(Q, curve, logger); + evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionNum); + await fdZKey.write(polynomials[name].coef); + await fdZKey.write(evaluations[name].eval); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeSigma(fdZKey) { + const sigma = new ffjavascript.BigBuffer(sFr * settings.domainSize * 3); + const lastSeen = new BigArray(settings.nVars); + const firstPos = new BigArray(settings.nVars); + let w = Fr.one; + for (let i = 0; i < settings.domainSize; i++) { + if (i < plonkConstraints.length) { + buildSigma(plonkConstraints[i][0], i); + buildSigma(plonkConstraints[i][1], settings.domainSize + i); + buildSigma(plonkConstraints[i][2], settings.domainSize * 2 + i); + } else if (i < settings.domainSize - 2) { + buildSigma(0, i); + buildSigma(0, settings.domainSize + i); + buildSigma(0, settings.domainSize * 2 + i); + } else { + sigma.set(w, i * sFr); + sigma.set(Fr.mul(w, k1), (settings.domainSize + i) * sFr); + sigma.set(Fr.mul(w, k2), (settings.domainSize * 2 + i) * sFr); + } + w = Fr.mul(w, Fr.w[settings.cirPower]); + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing sigma phase1: ${i}/${plonkConstraints.length}`); + } + for (let i = 0; i < settings.nVars; i++) { + if (typeof firstPos[i] !== "undefined") sigma.set(lastSeen[i], firstPos[i] * sFr); + else console.log("Variable not used"); + if (logger && i !== 0 && i % 5e5 === 0) logger.info(` writing sigma phase2: ${i}/${settings.nVars}`); + } + if (globalThis.gc) globalThis.gc(); + for (let i = 0; i < 3; i++) { + const sectionId = 0 === i ? 12 : 1 === i ? 13 : 14; + let name = "S" + (i + 1); + polynomials[name] = await Polynomial.fromEvaluations(sigma.slice(settings.domainSize * sFr * i, settings.domainSize * sFr * (i + 1)), curve, logger); + evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, sectionId); + await fdZKey.write(polynomials[name].coef); + await fdZKey.write(evaluations[name].eval); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + if (globalThis.gc) globalThis.gc(); + } + return 0; + function buildSigma(signalId, idx) { + if (typeof lastSeen[signalId] === "undefined") firstPos[signalId] = idx; + else sigma.set(lastSeen[signalId], idx * sFr); + let v; + if (idx < settings.domainSize) v = w; + else if (idx < 2 * settings.domainSize) v = Fr.mul(w, k1); + else v = Fr.mul(w, k2); + lastSeen[signalId] = v; + } + } + async function writeLagrangePolynomials(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 15); + const l = Math.max(settings.nPublic, 1); + for (let i = 0; i < l; i++) { + let buff = new ffjavascript.BigBuffer(settings.domainSize * sFr); + buff.set(Fr.one, i * sFr); + await writeP4(fdZKey, buff); + } + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writePtau(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 16); + PTau = new ffjavascript.BigBuffer((settings.domainSize * 9 + 18) * sG1); + await fdPTau.readToBuffer(PTau, 0, (settings.domainSize * 9 + 18) * sG1, pTauSections[2][0].p); + await fdZKey.write(PTau); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeC0(fdZKey) { + let C0 = new CPolynomial(8, curve, logger); + C0.addPolynomial(0, polynomials.QL); + C0.addPolynomial(1, polynomials.QR); + C0.addPolynomial(2, polynomials.QO); + C0.addPolynomial(3, polynomials.QM); + C0.addPolynomial(4, polynomials.QC); + C0.addPolynomial(5, polynomials.S1); + C0.addPolynomial(6, polynomials.S2); + C0.addPolynomial(7, polynomials.S3); + polynomials.C0 = C0.getPolynomial(); + if (polynomials.C0.degree() >= 8 * settings.domainSize) throw new Error("C0 Polynomial is not well calculated"); + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 17); + await fdZKey.write(polynomials.C0.coef); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeFFlonkHeader(fdZKey) { + await (0, _iden3_binfileutils.startWriteSection)(fdZKey, 2); + const primeQ = curve.q; + const n8q = (Math.floor((ffjavascript.Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; + await fdZKey.writeULE32(n8q); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeQ, n8q); + const primeR = curve.r; + const n8r = (Math.floor((ffjavascript.Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; + await fdZKey.writeULE32(n8r); + await (0, _iden3_binfileutils.writeBigInt)(fdZKey, primeR, n8r); + await fdZKey.writeULE32(settings.nVars); + await fdZKey.writeULE32(settings.nPublic); + await fdZKey.writeULE32(settings.domainSize); + await fdZKey.writeULE32(plonkAdditions.length); + await fdZKey.writeULE32(plonkConstraints.length); + await fdZKey.write(k1); + await fdZKey.write(k2); + await fdZKey.write(w3); + await fdZKey.write(w4); + await fdZKey.write(w8); + await fdZKey.write(wr); + let bX_2; + bX_2 = await fdPTau.read(sG2, pTauSections[3][0].p + sG2); + await fdZKey.write(bX_2); + let commitC0 = await polynomials.C0.multiExponentiation(PTau, "C0"); + await fdZKey.write(commitC0); + await (0, _iden3_binfileutils.endWriteSection)(fdZKey); + } + async function writeP4(fdZKey, buff) { + const [coefficients, evaluations4] = await Polynomial.to4T(buff, settings.domainSize, [], Fr); + await fdZKey.write(coefficients); + await fdZKey.write(evaluations4); + return [coefficients, evaluations4]; + } + function computeK1K2() { + let k1 = Fr.two; + while (isIncluded(k1, [], settings.cirPower)) Fr.add(k1, Fr.one); + let k2 = Fr.add(k1, Fr.one); + while (isIncluded(k2, [k1], settings.cirPower)) Fr.add(k2, Fr.one); + return [k1, k2]; + function isIncluded(k, kArr, pow) { + const domainSize = 2 ** pow; + let w = Fr.one; + for (let i = 0; i < domainSize; i++) { + if (Fr.eq(k, w)) return true; + for (let j = 0; j < kArr.length; j++) if (Fr.eq(k, Fr.mul(kArr[j], w))) return true; + w = Fr.mul(w, Fr.w[pow]); + } + return false; + } + } + function computeW3() { + let generator = Fr.e(31624); + let exponent = ffjavascript.Scalar.div(3648040478639879203707734290876212514758060733402672390616367364429301415936n, ffjavascript.Scalar.e(3)); + return Fr.exp(generator, exponent); + } + function computeW4() { + return Fr.w[2]; + } + function computeW8() { + return Fr.w[3]; + } + function getOmegaCubicRoot(power, Fr) { + const firstRoot = Fr.e(467799165886069610036046866799264026481344299079011762026774533774345988080n); + return Fr.exp(firstRoot, 2 ** (28 - power)); + } +} +//#endregion +//#region src/fflonk_prove.js +var { stringifyBigInts } = ffjavascript.utils; async function fflonkProve(zkeyFileName, witnessFileName, logger, options) { - if (logger) logger.info("FFLONK PROVER STARTED"); - - // Read witness file - if (logger) logger.info("> Reading witness file"); - const { - fd: fdWtns, - sections: wtnsSections - } = await binFileUtils__namespace.readBinFile(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); - const wtns = await readHeader(fdWtns, wtnsSections); - - //Read zkey file - if (logger) logger.info("> Reading zkey file"); - const { - fd: fdZKey, - sections: zkeySections - } = await binFileUtils__namespace.readBinFile(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); - - const zkey = await readHeader$1(fdZKey, zkeySections, undefined, options); - - if (zkey.protocolId !== FFLONK_PROTOCOL_ID) { - throw new Error("zkey file is not fflonk"); - } - - if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness !== zkey.nVars - zkey.nAdditions) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); - } - - const curve = zkey.curve; - - const Fr = curve.Fr; - - const sFr = curve.Fr.n8; - const sG1 = curve.G1.F.n8 * 2; - const sDomain = zkey.domainSize * sFr; - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK PROVE SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${zkey.power}`); - logger.info(` Domain size: ${zkey.domainSize}`); - logger.info(` Vars: ${zkey.nVars}`); - logger.info(` Public vars: ${zkey.nPublic}`); - logger.info(` Constraints: ${zkey.nConstraints}`); - logger.info(` Additions: ${zkey.nAdditions}`); - logger.info("----------------------------"); - } - - //Read witness data - if (logger) logger.info("> Reading witness file data"); - const buffWitness = await binFileUtils__namespace.readSection(fdWtns, wtnsSections, 2); - await fdWtns.close(); - - // First element in plonk is not used and can be any value. (But always the same). - // We set it to zero to go faster in the exponentiations. - buffWitness.set(Fr.zero, 0); - const buffInternalWitness = new ffjavascript.BigBuffer(zkey.nAdditions * sFr); - - let buffers = {}; - let polynomials = {}; - let evaluations = {}; - - // To divide prime fields the Extended Euclidean Algorithm for computing modular inverses is needed. - // NOTE: This is the equivalent of compute 1/denominator and then multiply it by the numerator. - // The Extended Euclidean Algorithm is expensive in terms of computation. - // For the special case where we need to do many modular inverses, there's a simple mathematical trick - // that allows us to compute many inverses, called Montgomery batch inversion. - // More info: https://vitalik.ca/general/2018/07/21/starks_part_3.html - // Montgomery batch inversion reduces the n inverse computations to a single one - // To save this (single) inverse computation on-chain, will compute it in proving time and send it to the verifier. - // The verifier will have to check: - // 1) the denominator is correct multiplying by himself non-inverted -> a * 1/a == 1 - // 2) compute the rest of the denominators using the Montgomery batch inversion - // The inversions are: - // · denominator needed in step 8 and 9 of the verifier to multiply by 1/Z_H(xi) - // · denominator needed in step 10 and 11 of the verifier - // · denominator needed in the verifier when computing L_i^{S1}(X) and L_i^{S2}(X) - // · L_i i=1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) - let toInverse = {}; - - let challenges = {}; - let roots = {}; - - let proof = new Proof(curve, logger); - - if (logger) logger.info(`> Reading Section ${ZKEY_FF_ADDITIONS_SECTION}. Additions`); - await calculateAdditions(); - - if (logger) logger.info(`> Reading Sections ${ZKEY_FF_SIGMA1_SECTION},${ZKEY_FF_SIGMA2_SECTION},${ZKEY_FF_SIGMA3_SECTION}. Sigma1, Sigma2 & Sigma 3`); - if (logger) logger.info("··· Reading Sigma polynomials "); - polynomials.Sigma1 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.Sigma2 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.Sigma3 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - - await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA1_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA2_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA3_SECTION][0].p); - - if (logger) logger.info("··· Reading Sigma evaluations"); - evaluations.Sigma1 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma2 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma3 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - - await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA1_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA2_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA3_SECTION][0].p + sDomain); - - if (logger) logger.info(`> Reading Section ${ZKEY_FF_PTAU_SECTION}. Powers of Tau`); - const PTau = new ffjavascript.BigBuffer(zkey.domainSize * 16 * sG1); - // domainSize * 9 + 18 = SRS length in the zkey saved in setup process. - // it corresponds to the maximum SRS length needed, specifically to commit C2 - // notice that the reserved buffers size is zkey.domainSize * 16 * sG1 because a power of two buffer size is needed - // the remaining buffer not filled from SRS are set to 0 - await fdZKey.readToBuffer(PTau, 0, (zkey.domainSize * 9 + 18) * sG1, zkeySections[ZKEY_FF_PTAU_SECTION][0].p); - - // START FFLONK PROVER PROTOCOL - if (globalThis.gc) globalThis.gc(); - - // ROUND 1. Compute C1(X) polynomial - if (logger) logger.info(""); - if (logger) logger.info("> ROUND 1"); - await round1(); - - delete polynomials.T0; - delete evaluations.QL; - delete evaluations.QR; - delete evaluations.QM; - delete evaluations.QO; - delete evaluations.QC; - if (globalThis.gc) globalThis.gc(); - - // ROUND 2. Compute C2(X) polynomial - if (logger) logger.info("> ROUND 2"); - await round2(); - - delete buffers.A; - delete buffers.B; - delete buffers.C; - delete evaluations.A; - delete evaluations.B; - delete evaluations.C; - delete evaluations.Sigma1; - delete evaluations.Sigma2; - delete evaluations.Sigma3; - delete evaluations.lagrange1; - delete evaluations.Z; - if (globalThis.gc) globalThis.gc(); - - // ROUND 3. Compute opening evaluations - if (logger) logger.info("> ROUND 3"); - await round3(); - - delete polynomials.A; - delete polynomials.B; - delete polynomials.C; - delete polynomials.Z; - delete polynomials.T1; - delete polynomials.T2; - delete polynomials.Sigma1; - delete polynomials.Sigma2; - delete polynomials.Sigma3; - delete polynomials.QL; - delete polynomials.QR; - delete polynomials.QM; - delete polynomials.QC; - delete polynomials.QO; - if (globalThis.gc) globalThis.gc(); - - // ROUND 4. Compute W(X) polynomial - if (logger) logger.info("> ROUND 4"); - await round4(); - if (globalThis.gc) globalThis.gc(); - - // ROUND 5. Compute W'(X) polynomial - if (logger) logger.info("> ROUND 5"); - await round5(); - - delete polynomials.C0; - delete polynomials.C1; - delete polynomials.C2; - delete polynomials.R1; - delete polynomials.R2; - delete polynomials.F; - delete polynomials.L; - delete polynomials.ZT; - delete polynomials.ZTS2; - await fdZKey.close(); - if (globalThis.gc) globalThis.gc(); - - proof.addEvaluation("inv", getMontgomeryBatchedInverse()); - - // Prepare proof - let _proof = proof.toObjectProof(); - _proof.protocol = "fflonk"; - _proof.curve = curve.name; - - // Prepare public inputs - let publicSignals = []; - - for (let i = 1; i <= zkey.nPublic; i++) { - const i_sFr = i * sFr; - - const pub = buffWitness.slice(i_sFr, i_sFr + sFr); - publicSignals.push(ffjavascript.Scalar.fromRprLE(pub)); - } - - if (logger) logger.info("FFLONK PROVER FINISHED"); - - return { - proof: stringifyBigInts(_proof), - publicSignals: stringifyBigInts(publicSignals) - }; - - async function calculateAdditions() { - if (logger) logger.info("··· Computing additions"); - const additionsBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_ADDITIONS_SECTION); - - // sizes: wireId_x = 4 bytes (32 bits), factor_x = field size bits - // Addition form: wireId_a wireId_b factor_a factor_b (size is 4 + 4 + sFr + sFr) - const sSum = 8 + sFr * 2; - - for (let i = 0; i < zkey.nAdditions; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` addition ${i}/${zkey.nAdditions}`); - - // Read addition values - let offset = i * sSum; - const signalId1 = readUInt32(additionsBuff, offset); - offset += 4; - const signalId2 = readUInt32(additionsBuff, offset); - offset += 4; - const factor1 = additionsBuff.slice(offset, offset + sFr); - offset += sFr; - const factor2 = additionsBuff.slice(offset, offset + sFr); - - // Get witness value - const witness1 = getWitness(signalId1); - const witness2 = getWitness(signalId2); - - //Calculate final result - const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); - - buffInternalWitness.set(result, sFr * i); - } - } - - function readUInt32(b, o) { - const buff = b.slice(o, o + 4); - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - return buffV.getUint32(0, true); - } - - function getWitness(idx) { - let diff = zkey.nVars - zkey.nAdditions; - if (idx < diff) { - return buffWitness.slice(idx * sFr, idx * sFr + sFr); - } else if (idx < zkey.nVars) { - const offset = (idx - diff) * sFr; - return buffInternalWitness.slice(offset, offset + sFr); - } - - return Fr.zero; - } - - async function round1() { - // STEP 1.1 - Generate random blinding scalars (b_1, ..., b9) ∈ F - challenges.b = []; - for (let i = 1; i <= 9; i++) { - challenges.b[i] = Fr.random(); - } - - // STEP 1.2 - Compute wire polynomials a(X), b(X) and c(X) - if (logger) logger.info("> Computing A, B, C wire polynomials"); - await computeWirePolynomials(); - - // STEP 1.3 - Compute the quotient polynomial T0(X) - if (logger) logger.info("> Computing T0 polynomial"); - await computeT0(); - - // STEP 1.4 - Compute the FFT-style combination polynomial C1(X) - if (logger) logger.info("> Computing C1 polynomial"); - await computeC1(); - - // The first output of the prover is ([C1]_1) - if (logger) logger.info("> Computing C1 multi exponentiation"); - let commitC1 = await polynomials.C1.multiExponentiation(PTau, "C1"); - proof.addPolynomial("C1", commitC1); - - return 0; - - async function computeWirePolynomials() { - if (logger) logger.info("··· Reading data from zkey file"); - // Build A, B and C evaluations buffer from zkey and witness files - buffers.A = new ffjavascript.BigBuffer(sDomain); - buffers.B = new ffjavascript.BigBuffer(sDomain); - buffers.C = new ffjavascript.BigBuffer(sDomain); - - // Read zkey sections and fill the buffers - const aMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_A_MAP_SECTION); - const bMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_B_MAP_SECTION); - const cMapBuff = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_C_MAP_SECTION); - - // Compute all witness from signal ids and set them to A,B & C buffers - for (let i = 0; i < zkey.nConstraints; i++) { - const i_sFr = i * sFr; - const offset = i * 4; - - // Compute A value from a signal id - const signalIdA = readUInt32(aMapBuff, offset); - buffers.A.set(getWitness(signalIdA), i_sFr); - - // Compute B value from a signal id - const signalIdB = readUInt32(bMapBuff, offset); - buffers.B.set(getWitness(signalIdB), i_sFr); - - // Compute C value from a signal id - const signalIdC = readUInt32(cMapBuff, offset); - buffers.C.set(getWitness(signalIdC), i_sFr); - } - - // Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b - buffers.A.set(challenges.b[1], sDomain - 64); - buffers.A.set(challenges.b[2], sDomain - 32); - buffers.B.set(challenges.b[3], sDomain - 64); - buffers.B.set(challenges.b[4], sDomain - 32); - buffers.C.set(challenges.b[5], sDomain - 64); - buffers.C.set(challenges.b[6], sDomain - 32); - - buffers.A = await Fr.batchToMontgomery(buffers.A); - buffers.B = await Fr.batchToMontgomery(buffers.B); - buffers.C = await Fr.batchToMontgomery(buffers.C); - - // Compute the coefficients of the wire polynomials a(X), b(X) and c(X) from A,B & C buffers - if (logger) logger.info("··· Computing A ifft"); - polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); - if (logger) logger.info("··· Computing B ifft"); - polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); - if (logger) logger.info("··· Computing C ifft"); - polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); - - // Compute extended evaluations of a(X), b(X) and c(X) polynomials - if (logger) logger.info("··· Computing A fft"); - evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); - if (logger) logger.info("··· Computing B fft"); - evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); - if (logger) logger.info("··· Computing C fft"); - evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); - - // Check degrees - if (polynomials.A.degree() >= zkey.domainSize) { - throw new Error("A Polynomial is not well calculated"); - } - if (polynomials.B.degree() >= zkey.domainSize) { - throw new Error("B Polynomial is not well calculated"); - } - if (polynomials.C.degree() >= zkey.domainSize) { - throw new Error("C Polynomial is not well calculated"); - } - } - - async function computeT0() { - if (logger) logger.info(`··· Reading sections ${ZKEY_FF_QL_SECTION}, ${ZKEY_FF_QR_SECTION}` + - `, ${ZKEY_FF_QM_SECTION}, ${ZKEY_FF_QO_SECTION}, ${ZKEY_FF_QC_SECTION}. Q selectors`); - // Reserve memory for Q's evaluations - evaluations.QL = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QR = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QM = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QO = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - evaluations.QC = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QL_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QR_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QM_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QO_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QC_SECTION][0].p + sDomain); - - // Read Lagrange polynomials & evaluations from zkey file - const lagrangePolynomials = await binFileUtils__namespace.readSection(fdZKey, zkeySections, ZKEY_FF_LAGRANGE_SECTION); - evaluations.lagrange1 = new Evaluations(lagrangePolynomials, curve, logger); - - // Reserve memory for buffers T0 - buffers.T0 = new ffjavascript.BigBuffer(sDomain * 4); - - if (logger) logger.info("··· Computing T0 evaluations"); - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T0 evaluation ${i}/${zkey.domainSize * 4}`); - - // Get related evaluations to compute current T0 evaluation - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - - const ql = evaluations.QL.getEvaluation(i); - const qr = evaluations.QR.getEvaluation(i); - const qm = evaluations.QM.getEvaluation(i); - const qo = evaluations.QO.getEvaluation(i); - const qc = evaluations.QC.getEvaluation(i); - - // Compute current public input - let pi = Fr.zero; - for (let j = 0; j < zkey.nPublic; j++) { - const offset = (j * 5 * zkey.domainSize) + zkey.domainSize + i; - - const lPol = evaluations.lagrange1.getEvaluation(offset); - const aVal = buffers.A.slice(j * sFr, (j + 1) * sFr); - - pi = Fr.sub(pi, Fr.mul(lPol, aVal)); - } - - //T0(X) = [q_L(X)·a(X) + q_R(X)·b(X) + q_M(X)·a(X)·b(X) + q_O(X)·c(X) + q_C(X) + PI(X)] · 1/Z_H(X) - // Compute first T0(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - // expression 1 -> q_L(X)·a(X) - const e1 = Fr.mul(a, ql); - - // expression 2 -> q_R(X)·b(X) - const e2 = Fr.mul(b, qr); - - // expression 3 -> q_M(X)·a(X)·b(X) - const e3 = Fr.mul(Fr.mul(a, b), qm); - - // expression 4 -> q_O(X)·c(X) - const e4 = Fr.mul(c, qo); - - // t0 = expressions 1 + expression 2 + expression 3 + expression 4 + qc + pi - const t0 = Fr.add(e1, Fr.add(e2, Fr.add(e3, Fr.add(e4, Fr.add(qc, pi))))); - - buffers.T0.set(t0, i * sFr); - } - - if (logger) logger.info("buffer T0: " + buffers.T0.byteLength / sFr); - - // Compute the coefficients of the polynomial T0(X) from buffers.T0 - if (logger) logger.info("··· Computing T0 ifft"); - polynomials.T0 = await Polynomial.fromEvaluations(buffers.T0, curve, logger); - - if (logger) logger.info("T0 length: " + polynomials.T0.length()); - if (logger) logger.info("T0 degree: " + polynomials.T0.degree()); - - // Divide the polynomial T0 by Z_H(X) - if (logger) logger.info("··· Computing T0 / ZH"); - polynomials.T0.divByZerofier(zkey.domainSize, Fr.one); - - // Check degree - if (polynomials.T0.degree() >= 2 * zkey.domainSize - 2) { - throw new Error(`T0 Polynomial is not well calculated (degree is ${polynomials.T0.degree()} and must be less than ${2 * zkey.domainSize + 2}`); - } - - delete buffers.T0; - } - - async function computeC1() { - let C1 = new CPolynomial(4, curve, logger); - C1.addPolynomial(0, polynomials.A); - C1.addPolynomial(1, polynomials.B); - C1.addPolynomial(2, polynomials.C); - C1.addPolynomial(3, polynomials.T0); - - polynomials.C1 = C1.getPolynomial(); - - // Check degree - if (polynomials.C1.degree() >= 8 * zkey.domainSize - 8) { - throw new Error("C1 Polynomial is not well calculated"); - } - } - } - - async function round2() { - // STEP 2.1 - Compute permutation challenge beta and gamma ∈ F - // Compute permutation challenge beta - if (logger) logger.info("> Computing challenges beta and gamma"); - const transcript = new Keccak256Transcript(curve); - - // Add C0 to the transcript - transcript.addPolCommitment(zkey.C0); - - // Add A to the transcript - for (let i = 0; i < zkey.nPublic; i++) { - transcript.addScalar(buffers.A.slice(i * sFr, i * sFr + sFr)); - } - - // Add C1 to the transcript - transcript.addPolCommitment(proof.getPolynomial("C1")); - - challenges.beta = transcript.getChallenge(); - if (logger) logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); - - // Compute permutation challenge gamma - transcript.reset(); - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - if (logger) logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); - - // STEP 2.2 - Compute permutation polynomial z(X) - if (logger) logger.info("> Computing Z polynomial"); - await computeZ(); - - // STEP 2.3 - Compute quotient polynomial T1(X) and T2(X) - if (logger) logger.info("> Computing T1 polynomial"); - await computeT1(); - if (logger) logger.info("> Computing T2 polynomial"); - await computeT2(); - - // STEP 2.4 - Compute the FFT-style combination polynomial C2(X) - if (logger) logger.info("> Computing C2 polynomial"); - await computeC2(); - - // The second output of the prover is ([C2]_1) - if (logger) logger.info("> Computing C2 multi exponentiation"); - let commitC2 = await polynomials.C2.multiExponentiation(PTau, "C2"); - proof.addPolynomial("C2", commitC2); - - return 0; - - async function computeZ() { - if (logger) logger.info("··· Computing Z evaluations"); - - let numArr = new ffjavascript.BigBuffer(sDomain); - let denArr = new ffjavascript.BigBuffer(sDomain); - - // Set the first values to 1 - numArr.set(Fr.one, 0); - denArr.set(Fr.one, 0); - - // Set initial omega - let w = Fr.one; - for (let i = 0; i < zkey.domainSize; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` Z evaluation ${i}/${zkey.domainSize}`); - const i_sFr = i * sFr; - - // Z(X) := numArr / denArr - // numArr := (a + beta·ω + gamma)(b + beta·ω·k1 + gamma)(c + beta·ω·k2 + gamma) - const betaw = Fr.mul(challenges.beta, w); - - let num1 = buffers.A.slice(i_sFr, i_sFr + sFr); - num1 = Fr.add(num1, betaw); - num1 = Fr.add(num1, challenges.gamma); - - let num2 = buffers.B.slice(i_sFr, i_sFr + sFr); - num2 = Fr.add(num2, Fr.mul(zkey.k1, betaw)); - num2 = Fr.add(num2, challenges.gamma); - - let num3 = buffers.C.slice(i_sFr, i_sFr + sFr); - num3 = Fr.add(num3, Fr.mul(zkey.k2, betaw)); - num3 = Fr.add(num3, challenges.gamma); - - let num = Fr.mul(num1, Fr.mul(num2, num3)); - - // denArr := (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma) - let den1 = buffers.A.slice(i_sFr, i_sFr + sFr); - den1 = Fr.add(den1, Fr.mul(challenges.beta, evaluations.Sigma1.getEvaluation(i * 4))); - den1 = Fr.add(den1, challenges.gamma); - - let den2 = buffers.B.slice(i_sFr, i_sFr + sFr); - den2 = Fr.add(den2, Fr.mul(challenges.beta, evaluations.Sigma2.getEvaluation(i * 4))); - den2 = Fr.add(den2, challenges.gamma); - - let den3 = buffers.C.slice(i_sFr, i_sFr + sFr); - den3 = Fr.add(den3, Fr.mul(challenges.beta, evaluations.Sigma3.getEvaluation(i * 4))); - den3 = Fr.add(den3, challenges.gamma); - - let den = Fr.mul(den1, Fr.mul(den2, den3)); - - // Multiply current num value with the previous one saved in numArr - num = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), num); - numArr.set(num, ((i + 1) % zkey.domainSize) * sFr); - - // Multiply current den value with the previous one saved in denArr - den = Fr.mul(denArr.slice(i_sFr, i_sFr + sFr), den); - denArr.set(den, ((i + 1) % zkey.domainSize) * sFr); - - // Next omega - w = Fr.mul(w, Fr.w[zkey.power]); - } - // Compute the inverse of denArr to compute in the next command the - // division numArr/denArr by multiplying num · 1/denArr - denArr = await Fr.batchInverse(denArr); - - // TODO: Do it in assembly and in parallel - // Multiply numArr · denArr where denArr was inverted in the previous command - for (let i = 0; i < zkey.domainSize; i++) { - const i_sFr = i * sFr; - - const z = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), denArr.slice(i_sFr, i_sFr + sFr)); - numArr.set(z, i_sFr); - } - // From now on the values saved on numArr will be Z(X) buffer - buffers.Z = numArr; - - if (!Fr.eq(numArr.slice(0, sFr), Fr.one)) { - throw new Error("Copy constraints does not match"); - } - - // Compute polynomial coefficients z(X) from buffers.Z - if (logger) logger.info("··· Computing Z ifft"); - polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); - - // Compute extended evaluations of z(X) polynomial - if (logger) logger.info("··· Computing Z fft"); - evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); - - // Blind z(X) polynomial coefficients with blinding scalars b - polynomials.Z.blindCoefficients([challenges.b[9], challenges.b[8], challenges.b[7]]); - - // Check degree - if (polynomials.Z.degree() >= zkey.domainSize + 3) { - throw new Error("Z Polynomial is not well calculated"); - } - - delete buffers.Z; - } - - async function computeT1() { - if (logger) logger.info("··· Computing T1 evaluations"); - - buffers.T1 = new ffjavascript.BigBuffer(sDomain * 2); - buffers.T1z = new ffjavascript.BigBuffer(sDomain * 2); - - // Set initial omega - let omega = Fr.one; - for (let i = 0; i < zkey.domainSize * 2; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T1 evaluation ${i}/${zkey.domainSize * 4}`); - - const omega2 = Fr.square(omega); - - const z = evaluations.Z.getEvaluation(i * 2); - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); - - // T1(X) := (z(X) - 1) · L_1(X) - // Compute first T1(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - const lagrange1 = evaluations.lagrange1.getEvaluation(zkey.domainSize + i * 2); - let t1 = Fr.mul(Fr.sub(z, Fr.one), lagrange1); - let t1z = Fr.mul(zp, lagrange1); - - buffers.T1.set(t1, i * sFr); - buffers.T1z.set(t1z, i * sFr); - - // Compute next omega - omega = Fr.mul(omega, Fr.w[zkey.power + 1]); - } - - // Compute the coefficients of the polynomial T1(X) from buffers.T1 - if (logger) logger.info("··· Computing T1 ifft"); - polynomials.T1 = await Polynomial.fromEvaluations(buffers.T1, curve, logger); - - // Divide the polynomial T1 by Z_H(X) - polynomials.T1.divByZerofier(zkey.domainSize, Fr.one); - - // Compute the coefficients of the polynomial T1z(X) from buffers.T1z - if (logger) logger.info("··· Computing T1z ifft"); - polynomials.T1z = await Polynomial.fromEvaluations(buffers.T1z, curve, logger); - - // Add the polynomial T1z to T1 to get the final polynomial T1 - polynomials.T1.add(polynomials.T1z); - - // Check degree - if (polynomials.T1.degree() >= zkey.domainSize + 2) { - throw new Error("T1 Polynomial is not well calculated"); - } - - delete buffers.T1; - delete buffers.T1z; - delete polynomials.T1z; - } - - async function computeT2() { - if (logger) logger.info("··· Computing T2 evaluations"); - - buffers.T2 = new ffjavascript.BigBuffer(sDomain * 4); - buffers.T2z = new ffjavascript.BigBuffer(sDomain * 4); - - // Set initial omega - let omega = Fr.one; - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T2 evaluation ${i}/${zkey.domainSize * 4}`); - - const omega2 = Fr.square(omega); - const omegaW = Fr.mul(omega, Fr.w[zkey.power]); - const omegaW2 = Fr.square(omegaW); - - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - const z = evaluations.Z.getEvaluation(i); - const zW = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); - - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); - const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omegaW2), Fr.mul(challenges.b[8], omegaW)), challenges.b[9]); - - const sigma1 = evaluations.Sigma1.getEvaluation(i); - const sigma2 = evaluations.Sigma2.getEvaluation(i); - const sigma3 = evaluations.Sigma3.getEvaluation(i); - - // T2(X) := [ (a(X) + beta·X + gamma)(b(X) + beta·k1·X + gamma)(c(X) + beta·k2·X + gamma)z(X) - // -(a(X) + beta·sigma1(X) + gamma)(b(X) + beta·sigma2(X) + gamma)(c(X) + beta·sigma3(X) + gamma)z(Xω)] · 1/Z_H(X) - // Compute first T2(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - - // expression 1 -> (a(X) + beta·X + gamma)(b(X) + beta·k1·X + gamma)(c(X) + beta·k2·X + gamma)z(X) - const betaX = Fr.mul(challenges.beta, omega); - - let e11 = Fr.add(a, betaX); - e11 = Fr.add(e11, challenges.gamma); - - let e12 = Fr.add(b, Fr.mul(betaX, zkey.k1)); - e12 = Fr.add(e12, challenges.gamma); - - let e13 = Fr.add(c, Fr.mul(betaX, zkey.k2)); - e13 = Fr.add(e13, challenges.gamma); - - let e1 = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), z); - let e1z = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), zp); - // const [e1, e1z] = MulZ.mul4(e11, e12, e13, z, ap, bp, cp, zp, i % 4, Fr); - - // expression 2 -> (a(X) + beta·sigma1(X) + gamma)(b(X) + beta·sigma2(X) + gamma)(c(X) + beta·sigma3(X) + gamma)z(Xω) - let e21 = Fr.add(a, Fr.mul(challenges.beta, sigma1)); - e21 = Fr.add(e21, challenges.gamma); - - let e22 = Fr.add(b, Fr.mul(challenges.beta, sigma2)); - e22 = Fr.add(e22, challenges.gamma); - - let e23 = Fr.add(c, Fr.mul(challenges.beta, sigma3)); - e23 = Fr.add(e23, challenges.gamma); - - let e2 = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zW); - let e2z = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zWp); - // const [e2, e2z] = MulZ.mul4(e21, e22, e23, zW, ap, bp, cp, zWp, i % 4, Fr); - - let t2 = Fr.sub(e1, e2); - let t2z = Fr.sub(e1z, e2z); - - buffers.T2.set(t2, i * sFr); - buffers.T2z.set(t2z, i * sFr); - - // Compute next omega - omega = Fr.mul(omega, Fr.w[zkey.power + 2]); - } - - // Compute the coefficients of the polynomial T2(X) from buffers.T2 - if (logger) logger.info("··· Computing T2 ifft"); - polynomials.T2 = await Polynomial.fromEvaluations(buffers.T2, curve, logger); - - // Divide the polynomial T2 by Z_H(X) - if (logger) logger.info("··· Computing T2 / ZH"); - polynomials.T2.divByZerofier(zkey.domainSize, Fr.one); - - // Compute the coefficients of the polynomial T2z(X) from buffers.T2z - if (logger) logger.info("··· Computing T2z ifft"); - polynomials.T2z = await Polynomial.fromEvaluations(buffers.T2z, curve, logger); - - // Add the polynomial T2z to T2 to get the final polynomial T2 - polynomials.T2.add(polynomials.T2z); - - // Check degree - if (polynomials.T2.degree() >= 3 * zkey.domainSize) { - throw new Error("T2 Polynomial is not well calculated"); - } - - delete buffers.T2; - delete buffers.T2z; - delete polynomials.T2z; - } - - async function computeC2() { - let C2 = new CPolynomial(3, curve, logger); - C2.addPolynomial(0, polynomials.Z); - C2.addPolynomial(1, polynomials.T1); - C2.addPolynomial(2, polynomials.T2); - - polynomials.C2 = C2.getPolynomial(); - - // Check degree - if (polynomials.C2.degree() >= 9 * zkey.domainSize) { - throw new Error("C2 Polynomial is not well calculated"); - } - } - } - - async function round3() { - if (logger) logger.info("> Computing challenge xi"); - // STEP 3.1 - Compute evaluation challenge xi ∈ S - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.getPolynomial("C2")); - - // Obtain a xi_seeder from the transcript - // To force h1^4 = xi, h2^3 = xi and h_3^2 = xiω - // we compute xi = xi_seeder^12, h1 = xi_seeder^3, h2 = xi_seeder^4 and h3 = xi_seeder^6 - challenges.xiSeed = transcript.getChallenge(); - const xiSeed2 = Fr.square(challenges.xiSeed); - - // Compute omega8, omega4 and omega3 - roots.w8 = []; - roots.w8[0] = Fr.one; - for (let i = 1; i < 8; i++) { - roots.w8[i] = Fr.mul(roots.w8[i - 1], zkey.w8); - } - - roots.w4 = []; - roots.w4[0] = Fr.one; - for (let i = 1; i < 4; i++) { - roots.w4[i] = Fr.mul(roots.w4[i - 1], zkey.w4); - } - - roots.w3 = []; - roots.w3[0] = Fr.one; - roots.w3[1] = zkey.w3; - roots.w3[2] = Fr.square(zkey.w3); - - // Compute h0 = xiSeeder^3 - roots.S0 = {}; - roots.S0.h0w8 = []; - roots.S0.h0w8[0] = Fr.mul(xiSeed2, challenges.xiSeed); - for (let i = 1; i < 8; i++) { - roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], roots.w8[i]); - } - - // Compute h1 = xi_seeder^6 - roots.S1 = {}; - roots.S1.h1w4 = []; - roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); - for (let i = 1; i < 4; i++) { - roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], roots.w4[i]); - } - - // Compute h2 = xi_seeder^8 - roots.S2 = {}; - roots.S2.h2w3 = []; - roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); - roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], roots.w3[1]); - roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], roots.w3[2]); - - roots.S2.h3w3 = []; - // Multiply h3 by third-root-omega to obtain h_3^3 = xiω - // So, h3 = xi_seeder^8 ω^{1/3} - roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], zkey.wr); - roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], roots.w3[1]); - roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], roots.w3[2]); - - // Compute xi = xi_seeder^24 - challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); - - if (logger) logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); - - // Reserve memory for Q's polynomials - polynomials.QL = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QR = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QM = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QO = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - polynomials.QC = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[ZKEY_FF_QL_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[ZKEY_FF_QR_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[ZKEY_FF_QM_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[ZKEY_FF_QO_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[ZKEY_FF_QC_SECTION][0].p); - - // STEP 3.2 - Compute opening evaluations and add them to the proof (third output of the prover) - if (logger) logger.info("··· Computing evaluations"); - proof.addEvaluation("ql", polynomials.QL.evaluate(challenges.xi)); - proof.addEvaluation("qr", polynomials.QR.evaluate(challenges.xi)); - proof.addEvaluation("qm", polynomials.QM.evaluate(challenges.xi)); - proof.addEvaluation("qo", polynomials.QO.evaluate(challenges.xi)); - proof.addEvaluation("qc", polynomials.QC.evaluate(challenges.xi)); - proof.addEvaluation("s1", polynomials.Sigma1.evaluate(challenges.xi)); - proof.addEvaluation("s2", polynomials.Sigma2.evaluate(challenges.xi)); - proof.addEvaluation("s3", polynomials.Sigma3.evaluate(challenges.xi)); - proof.addEvaluation("a", polynomials.A.evaluate(challenges.xi)); - proof.addEvaluation("b", polynomials.B.evaluate(challenges.xi)); - proof.addEvaluation("c", polynomials.C.evaluate(challenges.xi)); - proof.addEvaluation("z", polynomials.Z.evaluate(challenges.xi)); - - challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); - proof.addEvaluation("zw", polynomials.Z.evaluate(challenges.xiw)); - proof.addEvaluation("t1w", polynomials.T1.evaluate(challenges.xiw)); - proof.addEvaluation("t2w", polynomials.T2.evaluate(challenges.xiw)); - } - - async function round4() { - if (logger) logger.info("> Computing challenge alpha"); - // STEP 4.1 - Compute challenge alpha ∈ F - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.xiSeed); - transcript.addScalar(proof.getEvaluation("ql")); - transcript.addScalar(proof.getEvaluation("qr")); - transcript.addScalar(proof.getEvaluation("qm")); - transcript.addScalar(proof.getEvaluation("qo")); - transcript.addScalar(proof.getEvaluation("qc")); - transcript.addScalar(proof.getEvaluation("s1")); - transcript.addScalar(proof.getEvaluation("s2")); - transcript.addScalar(proof.getEvaluation("s3")); - transcript.addScalar(proof.getEvaluation("a")); - transcript.addScalar(proof.getEvaluation("b")); - transcript.addScalar(proof.getEvaluation("c")); - transcript.addScalar(proof.getEvaluation("z")); - transcript.addScalar(proof.getEvaluation("zw")); - transcript.addScalar(proof.getEvaluation("t1w")); - transcript.addScalar(proof.getEvaluation("t2w")); - challenges.alpha = transcript.getChallenge(); - if (logger) logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); - - // STEP 4.2 - Compute F(X) - if (logger) logger.info("> Reading C0 polynomial"); - polynomials.C0 = new Polynomial(new ffjavascript.BigBuffer(sDomain * 8), curve, logger); - await fdZKey.readToBuffer(polynomials.C0.coef, 0, sDomain * 8, zkeySections[ZKEY_FF_C0_SECTION][0].p); - - if (logger) logger.info("> Computing R0 polynomial"); - computeR0(); - if (logger) logger.info("> Computing R1 polynomial"); - computeR1(); - if (logger) logger.info("> Computing R2 polynomial"); - computeR2(); - - if (logger) logger.info("> Computing F polynomial"); - await computeF(); - - // The fourth output of the prover is ([W1]_1), where W1:=(f/Z_t)(x) - if (logger) logger.info("> Computing W1 multi exponentiation"); - let commitW1 = await polynomials.F.multiExponentiation(PTau, "W1"); - proof.addPolynomial("W1", commitW1); - - return 0; - - function computeR0() { - // COMPUTE R0 - // Compute the coefficients of R0(X) from 8 evaluations using lagrange interpolation. R0(X) ∈ F_{<8}[X] - // We decide to use Lagrange interpolations because the R0 degree is very small (deg(R0)===7), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R0 = Polynomial.lagrangePolynomialInterpolation( - [roots.S0.h0w8[0], roots.S0.h0w8[1], roots.S0.h0w8[2], roots.S0.h0w8[3], - roots.S0.h0w8[4], roots.S0.h0w8[5], roots.S0.h0w8[6], roots.S0.h0w8[7]], - [polynomials.C0.evaluate(roots.S0.h0w8[0]), polynomials.C0.evaluate(roots.S0.h0w8[1]), - polynomials.C0.evaluate(roots.S0.h0w8[2]), polynomials.C0.evaluate(roots.S0.h0w8[3]), - polynomials.C0.evaluate(roots.S0.h0w8[4]), polynomials.C0.evaluate(roots.S0.h0w8[5]), - polynomials.C0.evaluate(roots.S0.h0w8[6]), polynomials.C0.evaluate(roots.S0.h0w8[7])], curve); - - // Check the degree of r0(X) < 8 - if (polynomials.R0.degree() > 7) { - throw new Error("R0 Polynomial is not well calculated"); - } - } - - function computeR1() { - // COMPUTE R1 - // Compute the coefficients of R1(X) from 4 evaluations using lagrange interpolation. R1(X) ∈ F_{<4}[X] - // We decide to use Lagrange interpolations because the R1 degree is very small (deg(R1)===3), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R1 = Polynomial.lagrangePolynomialInterpolation( - [roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3]], - [polynomials.C1.evaluate(roots.S1.h1w4[0]), polynomials.C1.evaluate(roots.S1.h1w4[1]), - polynomials.C1.evaluate(roots.S1.h1w4[2]), polynomials.C1.evaluate(roots.S1.h1w4[3])], curve); - - // Check the degree of r1(X) < 4 - if (polynomials.R1.degree() > 3) { - throw new Error("R1 Polynomial is not well calculated"); - } - } - - function computeR2() { - // COMPUTE R2 - // Compute the coefficients of r2(X) from 6 evaluations using lagrange interpolation. r2(X) ∈ F_{<6}[X] - // We decide to use Lagrange interpolations because the R2.degree is very small (deg(R2)===5), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R2 = Polynomial.lagrangePolynomialInterpolation( - [roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], - [polynomials.C2.evaluate(roots.S2.h2w3[0]), polynomials.C2.evaluate(roots.S2.h2w3[1]), - polynomials.C2.evaluate(roots.S2.h2w3[2]), polynomials.C2.evaluate(roots.S2.h3w3[0]), - polynomials.C2.evaluate(roots.S2.h3w3[1]), polynomials.C2.evaluate(roots.S2.h3w3[2])], curve); - - // Check the degree of r2(X) < 6 - if (polynomials.R2.degree() > 5) { - throw new Error("R2 Polynomial is not well calculated"); - } - } - - async function computeF() { - if (logger) logger.info("··· Computing F polynomial"); - - // COMPUTE F(X) - polynomials.F = Polynomial.fromPolynomial(polynomials.C0, curve, logger); - polynomials.F.sub(polynomials.R0); - polynomials.F.divByZerofier(8, challenges.xi); - - let f2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); - f2.sub(polynomials.R1); - f2.mulScalar(challenges.alpha); - f2.divByZerofier(4, challenges.xi); - - let f3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); - f3.sub(polynomials.R2); - f3.mulScalar(Fr.square(challenges.alpha)); - f3.divByZerofier(3, challenges.xi); - f3.divByZerofier(3, challenges.xiw); - - polynomials.F.add(f2); - polynomials.F.add(f3); - - if (polynomials.F.degree() >= 9 * zkey.domainSize - 6) { - throw new Error("F Polynomial is not well calculated"); - } - } - } - - async function round5() { - if (logger) logger.info("> Computing challenge y"); - - // STEP 5.1 - Compute random evaluation point y ∈ F - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.getPolynomial("W1")); - - challenges.y = transcript.getChallenge(); - if (logger) logger.info("··· challenges.y: " + Fr.toString(challenges.y)); - - // STEP 5.2 - Compute L(X) - if (logger) logger.info("> Computing L polynomial"); - await computeL(); - - if (logger) logger.info("> Computing ZTS2 polynomial"); - await computeZTS2(); - - let ZTS2Y = polynomials.ZTS2.evaluate(challenges.y); - ZTS2Y = Fr.inv(ZTS2Y); - polynomials.L.mulScalar(ZTS2Y); - - const polDividend = Polynomial.fromCoefficientsArray([Fr.neg(challenges.y), Fr.one], curve); - if (logger) logger.info("> Computing W' = L / ZTS2 polynomial"); - const polRemainder = polynomials.L.divBy(polDividend); - - //Check polReminder degree is equal to zero - if (polRemainder.degree() > 0) { - throw new Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${polRemainder.degree()} and should be 0`); - } - - if (polynomials.L.degree() >= 9 * zkey.domainSize - 1) { - throw new Error("Degree of L(X)/(ZTS2(y)(X-y)) is not correct"); - } - - // The fifth output of the prover is ([W2]_1), where W2:=(f/Z_t)(x) - if (logger) logger.info("> Computing W' multi exponentiation"); - let commitW2 = await polynomials.L.multiExponentiation(PTau, "W2"); - proof.addPolynomial("W2", commitW2); - - return 0; - - async function computeL() { - if (logger) logger.info("··· Computing L polynomial"); - - const evalR0Y = polynomials.R0.evaluate(challenges.y); - const evalR1Y = polynomials.R1.evaluate(challenges.y); - const evalR2Y = polynomials.R2.evaluate(challenges.y); - - let mulL0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); - for (let i = 1; i < 8; i++) { - mulL0 = Fr.mul(mulL0, Fr.sub(challenges.y, roots.S0.h0w8[i])); - } - - let mulL1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); - for (let i = 1; i < 4; i++) { - mulL1 = Fr.mul(mulL1, Fr.sub(challenges.y, roots.S1.h1w4[i])); - } - - let mulL2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); - for (let i = 1; i < 3; i++) { - mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h2w3[i])); - } - for (let i = 0; i < 3; i++) { - mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h3w3[i])); - } - - let preL0 = Fr.mul(mulL1, mulL2); - let preL1 = Fr.mul(challenges.alpha, Fr.mul(mulL0, mulL2)); - let preL2 = Fr.mul(Fr.square(challenges.alpha), Fr.mul(mulL0, mulL1)); - - toInverse["denH1"] = mulL1; - toInverse["denH2"] = mulL2; - - // COMPUTE L(X) - polynomials.L = Polynomial.fromPolynomial(polynomials.C0, curve, logger); - polynomials.L.subScalar(evalR0Y); - polynomials.L.mulScalar(preL0); - - let l2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); - l2.subScalar(evalR1Y); - l2.mulScalar(preL1); - - let l3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); - l3.subScalar(evalR2Y); - l3.mulScalar(preL2); - - polynomials.L.add(l2); - polynomials.L.add(l3); - - if (logger) logger.info("> Computing ZT polynomial"); - await computeZT(); - - const evalZTY = polynomials.ZT.evaluate(challenges.y); - polynomials.F.mulScalar(evalZTY); - polynomials.L.sub(polynomials.F); - - // Check degree - if (polynomials.L.degree() >= 9 * zkey.domainSize) { - throw new Error("L Polynomial is not well calculated"); - } - - delete buffers.L; - } - - async function computeZT() { - polynomials.ZT = Polynomial.zerofierPolynomial( - [ - roots.S0.h0w8[0], roots.S0.h0w8[1], roots.S0.h0w8[2], roots.S0.h0w8[3], - roots.S0.h0w8[4], roots.S0.h0w8[5], roots.S0.h0w8[6], roots.S0.h0w8[7], - roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3], - roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], curve); - } - - async function computeZTS2() { - polynomials.ZTS2 = Polynomial.zerofierPolynomial( - [roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3], - roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], curve); - } - } - - function getMontgomeryBatchedInverse() { - // · denominator needed in step 8 and 9 of the verifier to multiply by 1/Z_H(xi) - let xiN = challenges.xi; - for (let i = 0; i < zkey.power; i++) { - xiN = Fr.square(xiN); - } - toInverse["zh"] = Fr.sub(xiN, Fr.one); - - // · denominator needed in step 10 and 11 of the verifier - // toInverse.denH1 & toInverse.denH2 -> Computed in round5, computeL() - - // · denominator needed in the verifier when computing L_i^{S0}(X), L_i^{S1}(X) and L_i^{S2}(X) - computeLiS0(toInverse, roots.S0.h0w8, challenges.y, curve); - - computeLiS1(toInverse, roots.S1.h1w4, challenges.y, curve); - - computeLiS2(toInverse, roots.S2.h2w3, roots.S2.h3w3, challenges.y, challenges.xi, challenges.xiw, curve); - - // · L_i i=1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) - const size = Math.max(1, zkey.nPublic); - - let w = Fr.one; - for (let i = 0; i < size; i++) { - toInverse["Li_" + (i + 1)] = Fr.mul(Fr.e(zkey.domainSize), Fr.sub(challenges.xi, w)); - w = Fr.mul(w, Fr.w[zkey.power]); - } - - let mulAccumulator = Fr.one; - for (const element of Object.values(toInverse)) { - if(Array.isArray(element)) { - for (const subElement of element) { - mulAccumulator = Fr.mul(mulAccumulator, subElement); - } - } else { - mulAccumulator = Fr.mul(mulAccumulator, element); - } - } - return Fr.inv(mulAccumulator); - - - function computeLiS0(toInverse, roots, x, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - toInverse[["LiS0_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); - } - - return Li; - } - - function computeLiS1(toInverse, roots, x, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - toInverse[["LiS1_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); - - } - - return Li; - } - - function computeLiS2(toInverse, S2, S2p, value, xi, xiw, curve) { - const Fr = curve.Fr; - - const Li = []; - - const _3h2 = Fr.mul(Fr.e(3), S2[0]); - const xisubxiw = Fr.sub(xi, xiw); - let den1 = Fr.mul(_3h2, xisubxiw); - for (let i = 0; i < 3; i++) { - const den2 = S2[2 * i % 3]; - const den3 = Fr.sub(value, S2[i]); - - toInverse[["LiS2_" + (i + 1)]] = Fr.mul(den1,Fr.mul(den2, den3)); - - } - - const _3h3 = Fr.mul(Fr.e(3), S2p[0]); - const xiwsubxi = Fr.sub(xiw, xi); - den1 = Fr.mul(_3h3, xiwsubxi); - for (let i = 0; i < 3; i++) { - const den2 = S2p[2 * i % 3]; - const den3 = Fr.sub(value, S2p[i]); - - toInverse[["LiS2_" + (i + 1 + 3)]] = Fr.mul(den1,Fr.mul(den2, den3)); - } - - return Li; - } - } -} - -/* - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -const {unstringifyBigInts: unstringifyBigInts$2} = ffjavascript.utils; - + if (logger) logger.info("FFLONK PROVER STARTED"); + if (logger) logger.info("> Reading witness file"); + const { fd: fdWtns, sections: wtnsSections } = await _iden3_binfileutils.readBinFile(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); + const wtns = await readHeader(fdWtns, wtnsSections); + if (logger) logger.info("> Reading zkey file"); + const { fd: fdZKey, sections: zkeySections } = await _iden3_binfileutils.readBinFile(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); + const zkey = await readHeader$1(fdZKey, zkeySections, void 0, options); + if (zkey.protocolId !== 10) throw new Error("zkey file is not fflonk"); + if (!ffjavascript.Scalar.eq(zkey.r, wtns.q)) throw new Error("Curve of the witness does not match the curve of the proving key"); + if (wtns.nWitness !== zkey.nVars - zkey.nAdditions) throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); + const curve = zkey.curve; + const Fr = curve.Fr; + const sFr = curve.Fr.n8; + const sG1 = curve.G1.F.n8 * 2; + const sDomain = zkey.domainSize * sFr; + if (logger) { + logger.info("----------------------------"); + logger.info(" FFLONK PROVE SETTINGS"); + logger.info(` Curve: ${curve.name}`); + logger.info(` Circuit power: ${zkey.power}`); + logger.info(` Domain size: ${zkey.domainSize}`); + logger.info(` Vars: ${zkey.nVars}`); + logger.info(` Public vars: ${zkey.nPublic}`); + logger.info(` Constraints: ${zkey.nConstraints}`); + logger.info(` Additions: ${zkey.nAdditions}`); + logger.info("----------------------------"); + } + if (logger) logger.info("> Reading witness file data"); + const buffWitness = await _iden3_binfileutils.readSection(fdWtns, wtnsSections, 2); + await fdWtns.close(); + buffWitness.set(Fr.zero, 0); + const buffInternalWitness = new ffjavascript.BigBuffer(zkey.nAdditions * sFr); + let buffers = {}; + let polynomials = {}; + let evaluations = {}; + let toInverse = {}; + let challenges = {}; + let roots = {}; + let proof = new Proof(curve, logger); + if (logger) logger.info(`> Reading Section 3. Additions`); + await calculateAdditions(); + if (logger) logger.info(`> Reading Sections 12,13,14. Sigma1, Sigma2 & Sigma 3`); + if (logger) logger.info("··· Reading Sigma polynomials "); + polynomials.Sigma1 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.Sigma2 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.Sigma3 = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[12][0].p); + await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[13][0].p); + await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[14][0].p); + if (logger) logger.info("··· Reading Sigma evaluations"); + evaluations.Sigma1 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.Sigma2 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.Sigma3 = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[12][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[13][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[14][0].p + sDomain); + if (logger) logger.info(`> Reading Section 16. Powers of Tau`); + const PTau = new ffjavascript.BigBuffer(zkey.domainSize * 16 * sG1); + await fdZKey.readToBuffer(PTau, 0, (zkey.domainSize * 9 + 18) * sG1, zkeySections[16][0].p); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info(""); + if (logger) logger.info("> ROUND 1"); + await round1(); + delete polynomials.T0; + delete evaluations.QL; + delete evaluations.QR; + delete evaluations.QM; + delete evaluations.QO; + delete evaluations.QC; + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> ROUND 2"); + await round2(); + delete buffers.A; + delete buffers.B; + delete buffers.C; + delete evaluations.A; + delete evaluations.B; + delete evaluations.C; + delete evaluations.Sigma1; + delete evaluations.Sigma2; + delete evaluations.Sigma3; + delete evaluations.lagrange1; + delete evaluations.Z; + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> ROUND 3"); + await round3(); + delete polynomials.A; + delete polynomials.B; + delete polynomials.C; + delete polynomials.Z; + delete polynomials.T1; + delete polynomials.T2; + delete polynomials.Sigma1; + delete polynomials.Sigma2; + delete polynomials.Sigma3; + delete polynomials.QL; + delete polynomials.QR; + delete polynomials.QM; + delete polynomials.QC; + delete polynomials.QO; + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> ROUND 4"); + await round4(); + if (globalThis.gc) globalThis.gc(); + if (logger) logger.info("> ROUND 5"); + await round5(); + delete polynomials.C0; + delete polynomials.C1; + delete polynomials.C2; + delete polynomials.R1; + delete polynomials.R2; + delete polynomials.F; + delete polynomials.L; + delete polynomials.ZT; + delete polynomials.ZTS2; + await fdZKey.close(); + if (globalThis.gc) globalThis.gc(); + proof.addEvaluation("inv", getMontgomeryBatchedInverse()); + let _proof = proof.toObjectProof(); + _proof.protocol = "fflonk"; + _proof.curve = curve.name; + let publicSignals = []; + for (let i = 1; i <= zkey.nPublic; i++) { + const i_sFr = i * sFr; + const pub = buffWitness.slice(i_sFr, i_sFr + sFr); + publicSignals.push(ffjavascript.Scalar.fromRprLE(pub)); + } + if (logger) logger.info("FFLONK PROVER FINISHED"); + return { + proof: stringifyBigInts(_proof), + publicSignals: stringifyBigInts(publicSignals) + }; + async function calculateAdditions() { + if (logger) logger.info("··· Computing additions"); + const additionsBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 3); + const sSum = 8 + sFr * 2; + for (let i = 0; i < zkey.nAdditions; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` addition ${i}/${zkey.nAdditions}`); + let offset = i * sSum; + const signalId1 = readUInt32(additionsBuff, offset); + offset += 4; + const signalId2 = readUInt32(additionsBuff, offset); + offset += 4; + const factor1 = additionsBuff.slice(offset, offset + sFr); + offset += sFr; + const factor2 = additionsBuff.slice(offset, offset + sFr); + const witness1 = getWitness(signalId1); + const witness2 = getWitness(signalId2); + const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); + buffInternalWitness.set(result, sFr * i); + } + } + function readUInt32(b, o) { + const buff = b.slice(o, o + 4); + return new DataView(buff.buffer, buff.byteOffset, buff.byteLength).getUint32(0, true); + } + function getWitness(idx) { + let diff = zkey.nVars - zkey.nAdditions; + if (idx < diff) return buffWitness.slice(idx * sFr, idx * sFr + sFr); + else if (idx < zkey.nVars) { + const offset = (idx - diff) * sFr; + return buffInternalWitness.slice(offset, offset + sFr); + } + return Fr.zero; + } + async function round1() { + challenges.b = []; + for (let i = 1; i <= 9; i++) challenges.b[i] = Fr.random(); + if (logger) logger.info("> Computing A, B, C wire polynomials"); + await computeWirePolynomials(); + if (logger) logger.info("> Computing T0 polynomial"); + await computeT0(); + if (logger) logger.info("> Computing C1 polynomial"); + await computeC1(); + if (logger) logger.info("> Computing C1 multi exponentiation"); + let commitC1 = await polynomials.C1.multiExponentiation(PTau, "C1"); + proof.addPolynomial("C1", commitC1); + return 0; + async function computeWirePolynomials() { + if (logger) logger.info("··· Reading data from zkey file"); + buffers.A = new ffjavascript.BigBuffer(sDomain); + buffers.B = new ffjavascript.BigBuffer(sDomain); + buffers.C = new ffjavascript.BigBuffer(sDomain); + const aMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 4); + const bMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 5); + const cMapBuff = await _iden3_binfileutils.readSection(fdZKey, zkeySections, 6); + for (let i = 0; i < zkey.nConstraints; i++) { + const i_sFr = i * sFr; + const offset = i * 4; + const signalIdA = readUInt32(aMapBuff, offset); + buffers.A.set(getWitness(signalIdA), i_sFr); + const signalIdB = readUInt32(bMapBuff, offset); + buffers.B.set(getWitness(signalIdB), i_sFr); + const signalIdC = readUInt32(cMapBuff, offset); + buffers.C.set(getWitness(signalIdC), i_sFr); + } + buffers.A.set(challenges.b[1], sDomain - 64); + buffers.A.set(challenges.b[2], sDomain - 32); + buffers.B.set(challenges.b[3], sDomain - 64); + buffers.B.set(challenges.b[4], sDomain - 32); + buffers.C.set(challenges.b[5], sDomain - 64); + buffers.C.set(challenges.b[6], sDomain - 32); + buffers.A = await Fr.batchToMontgomery(buffers.A); + buffers.B = await Fr.batchToMontgomery(buffers.B); + buffers.C = await Fr.batchToMontgomery(buffers.C); + if (logger) logger.info("··· Computing A ifft"); + polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); + if (logger) logger.info("··· Computing B ifft"); + polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); + if (logger) logger.info("··· Computing C ifft"); + polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); + if (logger) logger.info("··· Computing A fft"); + evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); + if (logger) logger.info("··· Computing B fft"); + evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); + if (logger) logger.info("··· Computing C fft"); + evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); + if (polynomials.A.degree() >= zkey.domainSize) throw new Error("A Polynomial is not well calculated"); + if (polynomials.B.degree() >= zkey.domainSize) throw new Error("B Polynomial is not well calculated"); + if (polynomials.C.degree() >= zkey.domainSize) throw new Error("C Polynomial is not well calculated"); + } + async function computeT0() { + if (logger) logger.info(`··· Reading sections 7, 8, 9, 10, 11. Q selectors`); + evaluations.QL = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QR = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QM = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QO = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + evaluations.QC = new Evaluations(new ffjavascript.BigBuffer(sDomain * 4), curve, logger); + await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[7][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[8][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[9][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[10][0].p + sDomain); + await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[11][0].p + sDomain); + evaluations.lagrange1 = new Evaluations(await _iden3_binfileutils.readSection(fdZKey, zkeySections, 15), curve, logger); + buffers.T0 = new ffjavascript.BigBuffer(sDomain * 4); + if (logger) logger.info("··· Computing T0 evaluations"); + for (let i = 0; i < zkey.domainSize * 4; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` T0 evaluation ${i}/${zkey.domainSize * 4}`); + const a = evaluations.A.getEvaluation(i); + const b = evaluations.B.getEvaluation(i); + const c = evaluations.C.getEvaluation(i); + const ql = evaluations.QL.getEvaluation(i); + const qr = evaluations.QR.getEvaluation(i); + const qm = evaluations.QM.getEvaluation(i); + const qo = evaluations.QO.getEvaluation(i); + const qc = evaluations.QC.getEvaluation(i); + let pi = Fr.zero; + for (let j = 0; j < zkey.nPublic; j++) { + const offset = j * 5 * zkey.domainSize + zkey.domainSize + i; + const lPol = evaluations.lagrange1.getEvaluation(offset); + const aVal = buffers.A.slice(j * sFr, (j + 1) * sFr); + pi = Fr.sub(pi, Fr.mul(lPol, aVal)); + } + const e1 = Fr.mul(a, ql); + const e2 = Fr.mul(b, qr); + const e3 = Fr.mul(Fr.mul(a, b), qm); + const e4 = Fr.mul(c, qo); + const t0 = Fr.add(e1, Fr.add(e2, Fr.add(e3, Fr.add(e4, Fr.add(qc, pi))))); + buffers.T0.set(t0, i * sFr); + } + if (logger) logger.info("buffer T0: " + buffers.T0.byteLength / sFr); + if (logger) logger.info("··· Computing T0 ifft"); + polynomials.T0 = await Polynomial.fromEvaluations(buffers.T0, curve, logger); + if (logger) logger.info("T0 length: " + polynomials.T0.length()); + if (logger) logger.info("T0 degree: " + polynomials.T0.degree()); + if (logger) logger.info("··· Computing T0 / ZH"); + polynomials.T0.divByZerofier(zkey.domainSize, Fr.one); + if (polynomials.T0.degree() >= 2 * zkey.domainSize - 2) throw new Error(`T0 Polynomial is not well calculated (degree is ${polynomials.T0.degree()} and must be less than ${2 * zkey.domainSize + 2}`); + delete buffers.T0; + } + async function computeC1() { + let C1 = new CPolynomial(4, curve, logger); + C1.addPolynomial(0, polynomials.A); + C1.addPolynomial(1, polynomials.B); + C1.addPolynomial(2, polynomials.C); + C1.addPolynomial(3, polynomials.T0); + polynomials.C1 = C1.getPolynomial(); + if (polynomials.C1.degree() >= 8 * zkey.domainSize - 8) throw new Error("C1 Polynomial is not well calculated"); + } + } + async function round2() { + if (logger) logger.info("> Computing challenges beta and gamma"); + const transcript = new Keccak256Transcript(curve); + transcript.addPolCommitment(zkey.C0); + for (let i = 0; i < zkey.nPublic; i++) transcript.addScalar(buffers.A.slice(i * sFr, i * sFr + sFr)); + transcript.addPolCommitment(proof.getPolynomial("C1")); + challenges.beta = transcript.getChallenge(); + if (logger) logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); + transcript.reset(); + transcript.addScalar(challenges.beta); + challenges.gamma = transcript.getChallenge(); + if (logger) logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); + if (logger) logger.info("> Computing Z polynomial"); + await computeZ(); + if (logger) logger.info("> Computing T1 polynomial"); + await computeT1(); + if (logger) logger.info("> Computing T2 polynomial"); + await computeT2(); + if (logger) logger.info("> Computing C2 polynomial"); + await computeC2(); + if (logger) logger.info("> Computing C2 multi exponentiation"); + let commitC2 = await polynomials.C2.multiExponentiation(PTau, "C2"); + proof.addPolynomial("C2", commitC2); + return 0; + async function computeZ() { + if (logger) logger.info("··· Computing Z evaluations"); + let numArr = new ffjavascript.BigBuffer(sDomain); + let denArr = new ffjavascript.BigBuffer(sDomain); + numArr.set(Fr.one, 0); + denArr.set(Fr.one, 0); + let w = Fr.one; + for (let i = 0; i < zkey.domainSize; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` Z evaluation ${i}/${zkey.domainSize}`); + const i_sFr = i * sFr; + const betaw = Fr.mul(challenges.beta, w); + let num1 = buffers.A.slice(i_sFr, i_sFr + sFr); + num1 = Fr.add(num1, betaw); + num1 = Fr.add(num1, challenges.gamma); + let num2 = buffers.B.slice(i_sFr, i_sFr + sFr); + num2 = Fr.add(num2, Fr.mul(zkey.k1, betaw)); + num2 = Fr.add(num2, challenges.gamma); + let num3 = buffers.C.slice(i_sFr, i_sFr + sFr); + num3 = Fr.add(num3, Fr.mul(zkey.k2, betaw)); + num3 = Fr.add(num3, challenges.gamma); + let num = Fr.mul(num1, Fr.mul(num2, num3)); + let den1 = buffers.A.slice(i_sFr, i_sFr + sFr); + den1 = Fr.add(den1, Fr.mul(challenges.beta, evaluations.Sigma1.getEvaluation(i * 4))); + den1 = Fr.add(den1, challenges.gamma); + let den2 = buffers.B.slice(i_sFr, i_sFr + sFr); + den2 = Fr.add(den2, Fr.mul(challenges.beta, evaluations.Sigma2.getEvaluation(i * 4))); + den2 = Fr.add(den2, challenges.gamma); + let den3 = buffers.C.slice(i_sFr, i_sFr + sFr); + den3 = Fr.add(den3, Fr.mul(challenges.beta, evaluations.Sigma3.getEvaluation(i * 4))); + den3 = Fr.add(den3, challenges.gamma); + let den = Fr.mul(den1, Fr.mul(den2, den3)); + num = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), num); + numArr.set(num, (i + 1) % zkey.domainSize * sFr); + den = Fr.mul(denArr.slice(i_sFr, i_sFr + sFr), den); + denArr.set(den, (i + 1) % zkey.domainSize * sFr); + w = Fr.mul(w, Fr.w[zkey.power]); + } + denArr = await Fr.batchInverse(denArr); + for (let i = 0; i < zkey.domainSize; i++) { + const i_sFr = i * sFr; + const z = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), denArr.slice(i_sFr, i_sFr + sFr)); + numArr.set(z, i_sFr); + } + buffers.Z = numArr; + if (!Fr.eq(numArr.slice(0, sFr), Fr.one)) throw new Error("Copy constraints does not match"); + if (logger) logger.info("··· Computing Z ifft"); + polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); + if (logger) logger.info("··· Computing Z fft"); + evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); + polynomials.Z.blindCoefficients([ + challenges.b[9], + challenges.b[8], + challenges.b[7] + ]); + if (polynomials.Z.degree() >= zkey.domainSize + 3) throw new Error("Z Polynomial is not well calculated"); + delete buffers.Z; + } + async function computeT1() { + if (logger) logger.info("··· Computing T1 evaluations"); + buffers.T1 = new ffjavascript.BigBuffer(sDomain * 2); + buffers.T1z = new ffjavascript.BigBuffer(sDomain * 2); + let omega = Fr.one; + for (let i = 0; i < zkey.domainSize * 2; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` T1 evaluation ${i}/${zkey.domainSize * 4}`); + const omega2 = Fr.square(omega); + const z = evaluations.Z.getEvaluation(i * 2); + const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); + const lagrange1 = evaluations.lagrange1.getEvaluation(zkey.domainSize + i * 2); + let t1 = Fr.mul(Fr.sub(z, Fr.one), lagrange1); + let t1z = Fr.mul(zp, lagrange1); + buffers.T1.set(t1, i * sFr); + buffers.T1z.set(t1z, i * sFr); + omega = Fr.mul(omega, Fr.w[zkey.power + 1]); + } + if (logger) logger.info("··· Computing T1 ifft"); + polynomials.T1 = await Polynomial.fromEvaluations(buffers.T1, curve, logger); + polynomials.T1.divByZerofier(zkey.domainSize, Fr.one); + if (logger) logger.info("··· Computing T1z ifft"); + polynomials.T1z = await Polynomial.fromEvaluations(buffers.T1z, curve, logger); + polynomials.T1.add(polynomials.T1z); + if (polynomials.T1.degree() >= zkey.domainSize + 2) throw new Error("T1 Polynomial is not well calculated"); + delete buffers.T1; + delete buffers.T1z; + delete polynomials.T1z; + } + async function computeT2() { + if (logger) logger.info("··· Computing T2 evaluations"); + buffers.T2 = new ffjavascript.BigBuffer(sDomain * 4); + buffers.T2z = new ffjavascript.BigBuffer(sDomain * 4); + let omega = Fr.one; + for (let i = 0; i < zkey.domainSize * 4; i++) { + if (logger && 0 !== i && i % 1e5 === 0) logger.info(` T2 evaluation ${i}/${zkey.domainSize * 4}`); + const omega2 = Fr.square(omega); + const omegaW = Fr.mul(omega, Fr.w[zkey.power]); + const omegaW2 = Fr.square(omegaW); + const a = evaluations.A.getEvaluation(i); + const b = evaluations.B.getEvaluation(i); + const c = evaluations.C.getEvaluation(i); + const z = evaluations.Z.getEvaluation(i); + const zW = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); + const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); + const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omegaW2), Fr.mul(challenges.b[8], omegaW)), challenges.b[9]); + const sigma1 = evaluations.Sigma1.getEvaluation(i); + const sigma2 = evaluations.Sigma2.getEvaluation(i); + const sigma3 = evaluations.Sigma3.getEvaluation(i); + const betaX = Fr.mul(challenges.beta, omega); + let e11 = Fr.add(a, betaX); + e11 = Fr.add(e11, challenges.gamma); + let e12 = Fr.add(b, Fr.mul(betaX, zkey.k1)); + e12 = Fr.add(e12, challenges.gamma); + let e13 = Fr.add(c, Fr.mul(betaX, zkey.k2)); + e13 = Fr.add(e13, challenges.gamma); + let e1 = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), z); + let e1z = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), zp); + let e21 = Fr.add(a, Fr.mul(challenges.beta, sigma1)); + e21 = Fr.add(e21, challenges.gamma); + let e22 = Fr.add(b, Fr.mul(challenges.beta, sigma2)); + e22 = Fr.add(e22, challenges.gamma); + let e23 = Fr.add(c, Fr.mul(challenges.beta, sigma3)); + e23 = Fr.add(e23, challenges.gamma); + let e2 = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zW); + let e2z = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zWp); + let t2 = Fr.sub(e1, e2); + let t2z = Fr.sub(e1z, e2z); + buffers.T2.set(t2, i * sFr); + buffers.T2z.set(t2z, i * sFr); + omega = Fr.mul(omega, Fr.w[zkey.power + 2]); + } + if (logger) logger.info("··· Computing T2 ifft"); + polynomials.T2 = await Polynomial.fromEvaluations(buffers.T2, curve, logger); + if (logger) logger.info("··· Computing T2 / ZH"); + polynomials.T2.divByZerofier(zkey.domainSize, Fr.one); + if (logger) logger.info("··· Computing T2z ifft"); + polynomials.T2z = await Polynomial.fromEvaluations(buffers.T2z, curve, logger); + polynomials.T2.add(polynomials.T2z); + if (polynomials.T2.degree() >= 3 * zkey.domainSize) throw new Error("T2 Polynomial is not well calculated"); + delete buffers.T2; + delete buffers.T2z; + delete polynomials.T2z; + } + async function computeC2() { + let C2 = new CPolynomial(3, curve, logger); + C2.addPolynomial(0, polynomials.Z); + C2.addPolynomial(1, polynomials.T1); + C2.addPolynomial(2, polynomials.T2); + polynomials.C2 = C2.getPolynomial(); + if (polynomials.C2.degree() >= 9 * zkey.domainSize) throw new Error("C2 Polynomial is not well calculated"); + } + } + async function round3() { + if (logger) logger.info("> Computing challenge xi"); + const transcript = new Keccak256Transcript(curve); + transcript.addScalar(challenges.gamma); + transcript.addPolCommitment(proof.getPolynomial("C2")); + challenges.xiSeed = transcript.getChallenge(); + const xiSeed2 = Fr.square(challenges.xiSeed); + roots.w8 = []; + roots.w8[0] = Fr.one; + for (let i = 1; i < 8; i++) roots.w8[i] = Fr.mul(roots.w8[i - 1], zkey.w8); + roots.w4 = []; + roots.w4[0] = Fr.one; + for (let i = 1; i < 4; i++) roots.w4[i] = Fr.mul(roots.w4[i - 1], zkey.w4); + roots.w3 = []; + roots.w3[0] = Fr.one; + roots.w3[1] = zkey.w3; + roots.w3[2] = Fr.square(zkey.w3); + roots.S0 = {}; + roots.S0.h0w8 = []; + roots.S0.h0w8[0] = Fr.mul(xiSeed2, challenges.xiSeed); + for (let i = 1; i < 8; i++) roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], roots.w8[i]); + roots.S1 = {}; + roots.S1.h1w4 = []; + roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); + for (let i = 1; i < 4; i++) roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], roots.w4[i]); + roots.S2 = {}; + roots.S2.h2w3 = []; + roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); + roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], roots.w3[1]); + roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], roots.w3[2]); + roots.S2.h3w3 = []; + roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], zkey.wr); + roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], roots.w3[1]); + roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], roots.w3[2]); + challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); + if (logger) logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); + polynomials.QL = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QR = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QM = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QO = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + polynomials.QC = new Polynomial(new ffjavascript.BigBuffer(sDomain), curve, logger); + await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[7][0].p); + await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[8][0].p); + await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[9][0].p); + await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[10][0].p); + await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[11][0].p); + if (logger) logger.info("··· Computing evaluations"); + proof.addEvaluation("ql", polynomials.QL.evaluate(challenges.xi)); + proof.addEvaluation("qr", polynomials.QR.evaluate(challenges.xi)); + proof.addEvaluation("qm", polynomials.QM.evaluate(challenges.xi)); + proof.addEvaluation("qo", polynomials.QO.evaluate(challenges.xi)); + proof.addEvaluation("qc", polynomials.QC.evaluate(challenges.xi)); + proof.addEvaluation("s1", polynomials.Sigma1.evaluate(challenges.xi)); + proof.addEvaluation("s2", polynomials.Sigma2.evaluate(challenges.xi)); + proof.addEvaluation("s3", polynomials.Sigma3.evaluate(challenges.xi)); + proof.addEvaluation("a", polynomials.A.evaluate(challenges.xi)); + proof.addEvaluation("b", polynomials.B.evaluate(challenges.xi)); + proof.addEvaluation("c", polynomials.C.evaluate(challenges.xi)); + proof.addEvaluation("z", polynomials.Z.evaluate(challenges.xi)); + challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); + proof.addEvaluation("zw", polynomials.Z.evaluate(challenges.xiw)); + proof.addEvaluation("t1w", polynomials.T1.evaluate(challenges.xiw)); + proof.addEvaluation("t2w", polynomials.T2.evaluate(challenges.xiw)); + } + async function round4() { + if (logger) logger.info("> Computing challenge alpha"); + const transcript = new Keccak256Transcript(curve); + transcript.addScalar(challenges.xiSeed); + transcript.addScalar(proof.getEvaluation("ql")); + transcript.addScalar(proof.getEvaluation("qr")); + transcript.addScalar(proof.getEvaluation("qm")); + transcript.addScalar(proof.getEvaluation("qo")); + transcript.addScalar(proof.getEvaluation("qc")); + transcript.addScalar(proof.getEvaluation("s1")); + transcript.addScalar(proof.getEvaluation("s2")); + transcript.addScalar(proof.getEvaluation("s3")); + transcript.addScalar(proof.getEvaluation("a")); + transcript.addScalar(proof.getEvaluation("b")); + transcript.addScalar(proof.getEvaluation("c")); + transcript.addScalar(proof.getEvaluation("z")); + transcript.addScalar(proof.getEvaluation("zw")); + transcript.addScalar(proof.getEvaluation("t1w")); + transcript.addScalar(proof.getEvaluation("t2w")); + challenges.alpha = transcript.getChallenge(); + if (logger) logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); + if (logger) logger.info("> Reading C0 polynomial"); + polynomials.C0 = new Polynomial(new ffjavascript.BigBuffer(sDomain * 8), curve, logger); + await fdZKey.readToBuffer(polynomials.C0.coef, 0, sDomain * 8, zkeySections[17][0].p); + if (logger) logger.info("> Computing R0 polynomial"); + computeR0(); + if (logger) logger.info("> Computing R1 polynomial"); + computeR1(); + if (logger) logger.info("> Computing R2 polynomial"); + computeR2(); + if (logger) logger.info("> Computing F polynomial"); + await computeF(); + if (logger) logger.info("> Computing W1 multi exponentiation"); + let commitW1 = await polynomials.F.multiExponentiation(PTau, "W1"); + proof.addPolynomial("W1", commitW1); + return 0; + function computeR0() { + polynomials.R0 = Polynomial.lagrangePolynomialInterpolation([ + roots.S0.h0w8[0], + roots.S0.h0w8[1], + roots.S0.h0w8[2], + roots.S0.h0w8[3], + roots.S0.h0w8[4], + roots.S0.h0w8[5], + roots.S0.h0w8[6], + roots.S0.h0w8[7] + ], [ + polynomials.C0.evaluate(roots.S0.h0w8[0]), + polynomials.C0.evaluate(roots.S0.h0w8[1]), + polynomials.C0.evaluate(roots.S0.h0w8[2]), + polynomials.C0.evaluate(roots.S0.h0w8[3]), + polynomials.C0.evaluate(roots.S0.h0w8[4]), + polynomials.C0.evaluate(roots.S0.h0w8[5]), + polynomials.C0.evaluate(roots.S0.h0w8[6]), + polynomials.C0.evaluate(roots.S0.h0w8[7]) + ], curve); + if (polynomials.R0.degree() > 7) throw new Error("R0 Polynomial is not well calculated"); + } + function computeR1() { + polynomials.R1 = Polynomial.lagrangePolynomialInterpolation([ + roots.S1.h1w4[0], + roots.S1.h1w4[1], + roots.S1.h1w4[2], + roots.S1.h1w4[3] + ], [ + polynomials.C1.evaluate(roots.S1.h1w4[0]), + polynomials.C1.evaluate(roots.S1.h1w4[1]), + polynomials.C1.evaluate(roots.S1.h1w4[2]), + polynomials.C1.evaluate(roots.S1.h1w4[3]) + ], curve); + if (polynomials.R1.degree() > 3) throw new Error("R1 Polynomial is not well calculated"); + } + function computeR2() { + polynomials.R2 = Polynomial.lagrangePolynomialInterpolation([ + roots.S2.h2w3[0], + roots.S2.h2w3[1], + roots.S2.h2w3[2], + roots.S2.h3w3[0], + roots.S2.h3w3[1], + roots.S2.h3w3[2] + ], [ + polynomials.C2.evaluate(roots.S2.h2w3[0]), + polynomials.C2.evaluate(roots.S2.h2w3[1]), + polynomials.C2.evaluate(roots.S2.h2w3[2]), + polynomials.C2.evaluate(roots.S2.h3w3[0]), + polynomials.C2.evaluate(roots.S2.h3w3[1]), + polynomials.C2.evaluate(roots.S2.h3w3[2]) + ], curve); + if (polynomials.R2.degree() > 5) throw new Error("R2 Polynomial is not well calculated"); + } + async function computeF() { + if (logger) logger.info("··· Computing F polynomial"); + polynomials.F = Polynomial.fromPolynomial(polynomials.C0, curve, logger); + polynomials.F.sub(polynomials.R0); + polynomials.F.divByZerofier(8, challenges.xi); + let f2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); + f2.sub(polynomials.R1); + f2.mulScalar(challenges.alpha); + f2.divByZerofier(4, challenges.xi); + let f3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); + f3.sub(polynomials.R2); + f3.mulScalar(Fr.square(challenges.alpha)); + f3.divByZerofier(3, challenges.xi); + f3.divByZerofier(3, challenges.xiw); + polynomials.F.add(f2); + polynomials.F.add(f3); + if (polynomials.F.degree() >= 9 * zkey.domainSize - 6) throw new Error("F Polynomial is not well calculated"); + } + } + async function round5() { + if (logger) logger.info("> Computing challenge y"); + const transcript = new Keccak256Transcript(curve); + transcript.addScalar(challenges.alpha); + transcript.addPolCommitment(proof.getPolynomial("W1")); + challenges.y = transcript.getChallenge(); + if (logger) logger.info("··· challenges.y: " + Fr.toString(challenges.y)); + if (logger) logger.info("> Computing L polynomial"); + await computeL(); + if (logger) logger.info("> Computing ZTS2 polynomial"); + await computeZTS2(); + let ZTS2Y = polynomials.ZTS2.evaluate(challenges.y); + ZTS2Y = Fr.inv(ZTS2Y); + polynomials.L.mulScalar(ZTS2Y); + const polDividend = Polynomial.fromCoefficientsArray([Fr.neg(challenges.y), Fr.one], curve); + if (logger) logger.info("> Computing W' = L / ZTS2 polynomial"); + const polRemainder = polynomials.L.divBy(polDividend); + if (polRemainder.degree() > 0) throw new Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${polRemainder.degree()} and should be 0`); + if (polynomials.L.degree() >= 9 * zkey.domainSize - 1) throw new Error("Degree of L(X)/(ZTS2(y)(X-y)) is not correct"); + if (logger) logger.info("> Computing W' multi exponentiation"); + let commitW2 = await polynomials.L.multiExponentiation(PTau, "W2"); + proof.addPolynomial("W2", commitW2); + return 0; + async function computeL() { + if (logger) logger.info("··· Computing L polynomial"); + const evalR0Y = polynomials.R0.evaluate(challenges.y); + const evalR1Y = polynomials.R1.evaluate(challenges.y); + const evalR2Y = polynomials.R2.evaluate(challenges.y); + let mulL0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); + for (let i = 1; i < 8; i++) mulL0 = Fr.mul(mulL0, Fr.sub(challenges.y, roots.S0.h0w8[i])); + let mulL1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); + for (let i = 1; i < 4; i++) mulL1 = Fr.mul(mulL1, Fr.sub(challenges.y, roots.S1.h1w4[i])); + let mulL2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); + for (let i = 1; i < 3; i++) mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h2w3[i])); + for (let i = 0; i < 3; i++) mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h3w3[i])); + let preL0 = Fr.mul(mulL1, mulL2); + let preL1 = Fr.mul(challenges.alpha, Fr.mul(mulL0, mulL2)); + let preL2 = Fr.mul(Fr.square(challenges.alpha), Fr.mul(mulL0, mulL1)); + toInverse["denH1"] = mulL1; + toInverse["denH2"] = mulL2; + polynomials.L = Polynomial.fromPolynomial(polynomials.C0, curve, logger); + polynomials.L.subScalar(evalR0Y); + polynomials.L.mulScalar(preL0); + let l2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); + l2.subScalar(evalR1Y); + l2.mulScalar(preL1); + let l3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); + l3.subScalar(evalR2Y); + l3.mulScalar(preL2); + polynomials.L.add(l2); + polynomials.L.add(l3); + if (logger) logger.info("> Computing ZT polynomial"); + await computeZT(); + const evalZTY = polynomials.ZT.evaluate(challenges.y); + polynomials.F.mulScalar(evalZTY); + polynomials.L.sub(polynomials.F); + if (polynomials.L.degree() >= 9 * zkey.domainSize) throw new Error("L Polynomial is not well calculated"); + delete buffers.L; + } + async function computeZT() { + polynomials.ZT = Polynomial.zerofierPolynomial([ + roots.S0.h0w8[0], + roots.S0.h0w8[1], + roots.S0.h0w8[2], + roots.S0.h0w8[3], + roots.S0.h0w8[4], + roots.S0.h0w8[5], + roots.S0.h0w8[6], + roots.S0.h0w8[7], + roots.S1.h1w4[0], + roots.S1.h1w4[1], + roots.S1.h1w4[2], + roots.S1.h1w4[3], + roots.S2.h2w3[0], + roots.S2.h2w3[1], + roots.S2.h2w3[2], + roots.S2.h3w3[0], + roots.S2.h3w3[1], + roots.S2.h3w3[2] + ], curve); + } + async function computeZTS2() { + polynomials.ZTS2 = Polynomial.zerofierPolynomial([ + roots.S1.h1w4[0], + roots.S1.h1w4[1], + roots.S1.h1w4[2], + roots.S1.h1w4[3], + roots.S2.h2w3[0], + roots.S2.h2w3[1], + roots.S2.h2w3[2], + roots.S2.h3w3[0], + roots.S2.h3w3[1], + roots.S2.h3w3[2] + ], curve); + } + } + function getMontgomeryBatchedInverse() { + let xiN = challenges.xi; + for (let i = 0; i < zkey.power; i++) xiN = Fr.square(xiN); + toInverse["zh"] = Fr.sub(xiN, Fr.one); + computeLiS0(toInverse, roots.S0.h0w8, challenges.y, curve); + computeLiS1(toInverse, roots.S1.h1w4, challenges.y, curve); + computeLiS2(toInverse, roots.S2.h2w3, roots.S2.h3w3, challenges.y, challenges.xi, challenges.xiw, curve); + const size = Math.max(1, zkey.nPublic); + let w = Fr.one; + for (let i = 0; i < size; i++) { + toInverse["Li_" + (i + 1)] = Fr.mul(Fr.e(zkey.domainSize), Fr.sub(challenges.xi, w)); + w = Fr.mul(w, Fr.w[zkey.power]); + } + let mulAccumulator = Fr.one; + for (const element of Object.values(toInverse)) if (Array.isArray(element)) for (const subElement of element) mulAccumulator = Fr.mul(mulAccumulator, subElement); + else mulAccumulator = Fr.mul(mulAccumulator, element); + return Fr.inv(mulAccumulator); + function computeLiS0(toInverse, roots, x, curve) { + const Fr = curve.Fr; + const len = roots.length; + const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); + const Li = []; + for (let i = 0; i < len; i++) { + const den2 = roots[(len - 1) * i % len]; + const den3 = Fr.sub(x, roots[i]); + toInverse[["LiS0_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); + } + return Li; + } + function computeLiS1(toInverse, roots, x, curve) { + const Fr = curve.Fr; + const len = roots.length; + const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); + const Li = []; + for (let i = 0; i < len; i++) { + const den2 = roots[(len - 1) * i % len]; + const den3 = Fr.sub(x, roots[i]); + toInverse[["LiS1_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); + } + return Li; + } + function computeLiS2(toInverse, S2, S2p, value, xi, xiw, curve) { + const Fr = curve.Fr; + const Li = []; + const _3h2 = Fr.mul(Fr.e(3), S2[0]); + const xisubxiw = Fr.sub(xi, xiw); + let den1 = Fr.mul(_3h2, xisubxiw); + for (let i = 0; i < 3; i++) { + const den2 = S2[2 * i % 3]; + const den3 = Fr.sub(value, S2[i]); + toInverse[["LiS2_" + (i + 1)]] = Fr.mul(den1, Fr.mul(den2, den3)); + } + const _3h3 = Fr.mul(Fr.e(3), S2p[0]); + const xiwsubxi = Fr.sub(xiw, xi); + den1 = Fr.mul(_3h3, xiwsubxi); + for (let i = 0; i < 3; i++) { + const den2 = S2p[2 * i % 3]; + const den3 = Fr.sub(value, S2p[i]); + toInverse[["LiS2_" + (i + 1 + 3)]] = Fr.mul(den1, Fr.mul(den2, den3)); + } + return Li; + } + } +} +//#endregion +//#region src/fflonk_full_prove.js +var { unstringifyBigInts: unstringifyBigInts$2 } = ffjavascript.utils; async function fflonkFullProve(_input, wasmFilename, zkeyFilename, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$2(_input); - - const wtns= {type: "mem"}; - - // Compute the witness - await wtnsCalculate(input, wasmFilename, wtns, wtnsCalcOptions); - - // Compute the proof - return await fflonkProve(zkeyFilename, wtns, logger, proverOptions); -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - - -const { unstringifyBigInts: unstringifyBigInts$1 } = ffjavascript.utils; - + const input = unstringifyBigInts$2(_input); + const wtns = { type: "mem" }; + await wtnsCalculate(input, wasmFilename, wtns, wtnsCalcOptions); + return await fflonkProve(zkeyFilename, wtns, logger, proverOptions); +} +//#endregion +//#region src/fflonk_verify.js +var { unstringifyBigInts: unstringifyBigInts$1 } = ffjavascript.utils; async function fflonkVerify(_vk_verifier, _publicSignals, _proof, logger) { - if (logger) logger.info("FFLONK VERIFIER STARTED"); - - _vk_verifier = unstringifyBigInts$1(_vk_verifier); - _proof = unstringifyBigInts$1(_proof); - - const curve = await getCurveFromName(_vk_verifier.curve); - - const vk = fromObjectVk(curve, _vk_verifier); - - // TODO ??? Compute wr^3 and check if it matches with w - - const proof = new Proof(curve, logger); - proof.fromObjectProof(_proof); - - const publicSignals = unstringifyBigInts$1(_publicSignals); - - if (publicSignals.length !== vk.nPublic) { - logger.error("Number of public signals does not match with vk"); - return false; - } - - const Fr = curve.Fr; - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK VERIFY SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${vk.power}`); - logger.info(` Domain size: ${2 ** vk.power}`); - logger.info(` Public vars: ${vk.nPublic}`); - logger.info("----------------------------"); - } - - // STEP 1 - Validate that all polynomial commitments ∈ G_1 - if (logger) logger.info("> Checking commitments belong to G1"); - if (!commitmentsBelongToG1(curve, proof, vk)) { - if (logger) logger.error("Proof commitments are not valid"); - return false; - } - - // STEP 2 - Validate that all evaluations ∈ F - if (logger) logger.info("> Checking evaluations belong to F"); - if (!evaluationsAreValid(curve, proof)) { - if (logger) logger.error("Proof evaluations are not valid."); - return false; - } - - // STEP 3 - Validate that w_i ∈ F for i ∈ [l] - if (logger) logger.info("> Checking public inputs belong to F"); - if (!publicInputsAreValid(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - // STEP 4 - Compute the challenges: beta, gamma, xi, alpha and y ∈ F - // as in prover description, from the common preprocessed inputs, public inputs and elements of π_SNARK - if (logger) logger.info("> Computing challenges"); - const { challenges, roots } = computeChallenges(curve, proof, vk, publicSignals, logger); - - // STEP 5 - Compute the zero polynomial evaluation Z_H(xi) = xi^n - 1 - if (logger) logger.info("> Computing Zero polynomial evaluation Z_H(xi)"); - challenges.zh = Fr.sub(challenges.xiN, Fr.one); - challenges.invzh = Fr.inv(challenges.zh); - - // STEP 6 - Compute the lagrange polynomial evaluation L_1(xi) - if (logger) logger.info("> Computing Lagrange evaluations"); - const lagrangeEvals = await computeLagrangeEvaluations(curve, challenges, vk); - - // STEP 7 - Compute public input evaluation PI(xi) - if (logger) logger.info("> Computing polynomial identities PI(X)"); - const pi = calculatePI(curve, publicSignals, lagrangeEvals); - - // STEP 8 - Compute polynomial r0 ∈ F_{<4}[X] - if (logger) logger.info("> Computing r0(y)"); - const r0 = computeR0(proof, challenges, roots, curve, logger); - - // STEP 9 - Compute polynomial r1 ∈ F_{<4}[X] - if (logger) logger.info("> Computing r1(y)"); - const r1 = computeR1(proof, challenges, roots, pi, curve, logger); - - // STEP 9 - Compute polynomial r2 ∈ F_{<6}[X] - if (logger) logger.info("> Computing r2(y)"); - const r2 = computeR2(proof, challenges, roots, lagrangeEvals[1], vk, curve, logger); - - if (logger) logger.info("> Computing F"); - const F = computeF(curve, proof, vk, challenges, roots); - - if (logger) logger.info("> Computing E"); - const E = computeE(curve, proof, challenges, vk, r0, r1, r2); - - if (logger) logger.info("> Computing J"); - const J = computeJ(curve, proof, challenges); - - if (logger) logger.info("> Validate all evaluations with a pairing"); - const res = await isValidPairing(curve, proof, challenges, vk, F, E, J); - - if (logger) { - if (res) { - logger.info("PROOF VERIFIED SUCCESSFULLY"); - } else { - logger.warn("Invalid Proof"); - } - } - - if (logger) logger.info("FFLONK VERIFIER FINISHED"); - - return res; - -} - + if (logger) logger.info("FFLONK VERIFIER STARTED"); + _vk_verifier = unstringifyBigInts$1(_vk_verifier); + _proof = unstringifyBigInts$1(_proof); + const curve = await getCurveFromName(_vk_verifier.curve); + const vk = fromObjectVk(curve, _vk_verifier); + const proof = new Proof(curve, logger); + proof.fromObjectProof(_proof); + const publicSignals = unstringifyBigInts$1(_publicSignals); + if (publicSignals.length !== vk.nPublic) { + logger.error("Number of public signals does not match with vk"); + return false; + } + const Fr = curve.Fr; + if (logger) { + logger.info("----------------------------"); + logger.info(" FFLONK VERIFY SETTINGS"); + logger.info(` Curve: ${curve.name}`); + logger.info(` Circuit power: ${vk.power}`); + logger.info(` Domain size: ${2 ** vk.power}`); + logger.info(` Public vars: ${vk.nPublic}`); + logger.info("----------------------------"); + } + if (logger) logger.info("> Checking commitments belong to G1"); + if (!commitmentsBelongToG1(curve, proof, vk)) { + if (logger) logger.error("Proof commitments are not valid"); + return false; + } + if (logger) logger.info("> Checking evaluations belong to F"); + if (!evaluationsAreValid(curve, proof)) { + if (logger) logger.error("Proof evaluations are not valid."); + return false; + } + if (logger) logger.info("> Checking public inputs belong to F"); + if (!publicInputsAreValid(curve, publicSignals)) { + if (logger) logger.error("Public inputs are not valid."); + return false; + } + if (logger) logger.info("> Computing challenges"); + const { challenges, roots } = computeChallenges(curve, proof, vk, publicSignals, logger); + if (logger) logger.info("> Computing Zero polynomial evaluation Z_H(xi)"); + challenges.zh = Fr.sub(challenges.xiN, Fr.one); + challenges.invzh = Fr.inv(challenges.zh); + if (logger) logger.info("> Computing Lagrange evaluations"); + const lagrangeEvals = await computeLagrangeEvaluations(curve, challenges, vk); + if (logger) logger.info("> Computing polynomial identities PI(X)"); + const pi = calculatePI(curve, publicSignals, lagrangeEvals); + if (logger) logger.info("> Computing r0(y)"); + const r0 = computeR0(proof, challenges, roots, curve, logger); + if (logger) logger.info("> Computing r1(y)"); + const r1 = computeR1(proof, challenges, roots, pi, curve, logger); + if (logger) logger.info("> Computing r2(y)"); + const r2 = computeR2(proof, challenges, roots, lagrangeEvals[1], vk, curve, logger); + if (logger) logger.info("> Computing F"); + const F = computeF(curve, proof, vk, challenges, roots); + if (logger) logger.info("> Computing E"); + const E = computeE(curve, proof, challenges, vk, r0, r1, r2); + if (logger) logger.info("> Computing J"); + const J = computeJ(curve, proof, challenges); + if (logger) logger.info("> Validate all evaluations with a pairing"); + const res = await isValidPairing(curve, proof, challenges, vk, F, E, J); + if (logger) if (res) logger.info("PROOF VERIFIED SUCCESSFULLY"); + else logger.warn("Invalid Proof"); + if (logger) logger.info("FFLONK VERIFIER FINISHED"); + return res; +} function fromObjectVk(curve, vk) { - const res = vk; - res.k1 = curve.Fr.fromObject(vk.k1); - res.k2 = curve.Fr.fromObject(vk.k2); - res.w = curve.Fr.fromObject(vk.w); - // res.wW = curve.Fr.fromObject(vk.wW); - res.w3 = curve.Fr.fromObject(vk.w3); - res.w4 = curve.Fr.fromObject(vk.w4); - res.w8 = curve.Fr.fromObject(vk.w8); - res.wr = curve.Fr.fromObject(vk.wr); - res.X_2 = curve.G2.fromObject(vk.X_2); - res.C0 = curve.G1.fromObject(vk.C0); - return res; -} - + const res = vk; + res.k1 = curve.Fr.fromObject(vk.k1); + res.k2 = curve.Fr.fromObject(vk.k2); + res.w = curve.Fr.fromObject(vk.w); + res.w3 = curve.Fr.fromObject(vk.w3); + res.w4 = curve.Fr.fromObject(vk.w4); + res.w8 = curve.Fr.fromObject(vk.w8); + res.wr = curve.Fr.fromObject(vk.wr); + res.X_2 = curve.G2.fromObject(vk.X_2); + res.C0 = curve.G1.fromObject(vk.C0); + return res; +} function commitmentsBelongToG1(curve, proof, vk) { - const G1 = curve.G1; - return G1.isValid(proof.polynomials.C1) - && G1.isValid(proof.polynomials.C2) - && G1.isValid(proof.polynomials.W1) - && G1.isValid(proof.polynomials.W2) - && G1.isValid(vk.C0); -} - + const G1 = curve.G1; + return G1.isValid(proof.polynomials.C1) && G1.isValid(proof.polynomials.C2) && G1.isValid(proof.polynomials.W1) && G1.isValid(proof.polynomials.W2) && G1.isValid(vk.C0); +} function checkValueBelongToField(curve, value) { - return ffjavascript.Scalar.geq(value, 0) && ffjavascript.Scalar.lt(value, curve.r); + return ffjavascript.Scalar.geq(value, 0) && ffjavascript.Scalar.lt(value, curve.r); } - function checkEvaluationIsValid(curve, evaluation) { - return checkValueBelongToField(curve, ffjavascript.Scalar.fromRprLE(evaluation)); + return checkValueBelongToField(curve, ffjavascript.Scalar.fromRprLE(evaluation)); } - function evaluationsAreValid(curve, proof) { - return checkEvaluationIsValid(curve, proof.evaluations.ql) - && checkEvaluationIsValid(curve, proof.evaluations.qr) - && checkEvaluationIsValid(curve, proof.evaluations.qm) - && checkEvaluationIsValid(curve, proof.evaluations.qo) - && checkEvaluationIsValid(curve, proof.evaluations.qc) - && checkEvaluationIsValid(curve, proof.evaluations.s1) - && checkEvaluationIsValid(curve, proof.evaluations.s2) - && checkEvaluationIsValid(curve, proof.evaluations.s3) - && checkEvaluationIsValid(curve, proof.evaluations.a) - && checkEvaluationIsValid(curve, proof.evaluations.b) - && checkEvaluationIsValid(curve, proof.evaluations.c) - && checkEvaluationIsValid(curve, proof.evaluations.z) - && checkEvaluationIsValid(curve, proof.evaluations.zw) - && checkEvaluationIsValid(curve, proof.evaluations.t1w) - && checkEvaluationIsValid(curve, proof.evaluations.t2w); -} - + return checkEvaluationIsValid(curve, proof.evaluations.ql) && checkEvaluationIsValid(curve, proof.evaluations.qr) && checkEvaluationIsValid(curve, proof.evaluations.qm) && checkEvaluationIsValid(curve, proof.evaluations.qo) && checkEvaluationIsValid(curve, proof.evaluations.qc) && checkEvaluationIsValid(curve, proof.evaluations.s1) && checkEvaluationIsValid(curve, proof.evaluations.s2) && checkEvaluationIsValid(curve, proof.evaluations.s3) && checkEvaluationIsValid(curve, proof.evaluations.a) && checkEvaluationIsValid(curve, proof.evaluations.b) && checkEvaluationIsValid(curve, proof.evaluations.c) && checkEvaluationIsValid(curve, proof.evaluations.z) && checkEvaluationIsValid(curve, proof.evaluations.zw) && checkEvaluationIsValid(curve, proof.evaluations.t1w) && checkEvaluationIsValid(curve, proof.evaluations.t2w); +} function publicInputsAreValid(curve, publicInputs) { - for(let i = 0; i < publicInputs.length; i++) { - if(!checkValueBelongToField(curve, publicInputs[i])) { - return false; - } - } - return true; -} - + for (let i = 0; i < publicInputs.length; i++) if (!checkValueBelongToField(curve, publicInputs[i])) return false; + return true; +} function computeChallenges(curve, proof, vk, publicSignals, logger) { - const Fr = curve.Fr; - - const challenges = {}; - const roots = {}; - const transcript = new Keccak256Transcript(curve); - - // Add C0 to the transcript - transcript.addPolCommitment(vk.C0); - - for (let i = 0; i < publicSignals.length; i++) { - transcript.addScalar(Fr.e(publicSignals[i])); - } - - transcript.addPolCommitment(proof.polynomials.C1); - challenges.beta = transcript.getChallenge(); - transcript.reset(); - - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - - transcript.reset(); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.polynomials.C2); - const xiSeed = transcript.getChallenge(); - const xiSeed2 = Fr.square(xiSeed); - - let w8 = []; - w8[1] = vk.w8; - w8[2] = Fr.square(vk.w8); - w8[3] = Fr.mul(w8[2], vk.w8); - w8[4] = Fr.mul(w8[3], vk.w8); - w8[5] = Fr.mul(w8[4], vk.w8); - w8[6] = Fr.mul(w8[5], vk.w8); - w8[7] = Fr.mul(w8[6], vk.w8); - let w4 = []; - w4[1] = vk.w4; - w4[2] = Fr.square(vk.w4); - w4[3] = Fr.mul(w4[2], vk.w4); - let w3 = []; - w3[1] = vk.w3; - w3[2] = Fr.square(vk.w3); - - // const w4_2 = Fr.square(vk.w4); - // const w4_3 = Fr.mul(w4_2, vk.w4); - // const w3_2 = Fr.square(vk.w3); - - // Compute h0 = xiSeeder^3 - roots.S0 = {}; - roots.S0.h0w8 = []; - roots.S0.h0w8[0] = Fr.mul(xiSeed2, xiSeed); - for (let i = 1; i < 8; i++) { - roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], w8[i]); - } - - // Compute h1 = xi_seeder^6 - roots.S1 = {}; - roots.S1.h1w4 = []; - roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); - for (let i = 1; i < 4; i++) { - roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], w4[i]); - } - - // Compute h2 = xi_seeder^8 - roots.S2 = {}; - roots.S2.h2w3 = []; - roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); - roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], w3[1]); - roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], w3[2]); - - roots.S2.h3w3 = []; - // Multiply h3 by third-root-omega to obtain h_3^3 = xiω - // So, h3 = xi_seeder^8 ω^{1/3} - roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], vk.wr); - roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], w3[1]); - roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], w3[2]); - - // Compute xi = xi_seeder^12 - challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); - challenges.xiw = Fr.mul(challenges.xi, Fr.w[vk.power]); - - challenges.xiN = challenges.xi; - vk.domainSize = 1; - for (let i = 0; i < vk.power; i++) { - challenges.xiN = Fr.square(challenges.xiN); - vk.domainSize *= 2; - } - - transcript.reset(); - transcript.addScalar(xiSeed); - transcript.addScalar(proof.evaluations.ql); - transcript.addScalar(proof.evaluations.qr); - transcript.addScalar(proof.evaluations.qm); - transcript.addScalar(proof.evaluations.qo); - transcript.addScalar(proof.evaluations.qc); - transcript.addScalar(proof.evaluations.s1); - transcript.addScalar(proof.evaluations.s2); - transcript.addScalar(proof.evaluations.s3); - transcript.addScalar(proof.evaluations.a); - transcript.addScalar(proof.evaluations.b); - transcript.addScalar(proof.evaluations.c); - transcript.addScalar(proof.evaluations.z); - transcript.addScalar(proof.evaluations.zw); - transcript.addScalar(proof.evaluations.t1w); - transcript.addScalar(proof.evaluations.t2w); - challenges.alpha = transcript.getChallenge(); - - transcript.reset(); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.polynomials.W1); - challenges.y = transcript.getChallenge(); - - if (logger) { - logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); - logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); - logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); - logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); - logger.info("··· challenges.y: " + Fr.toString(challenges.y)); - } - - return { challenges: challenges, roots: roots }; -} - + const Fr = curve.Fr; + const challenges = {}; + const roots = {}; + const transcript = new Keccak256Transcript(curve); + transcript.addPolCommitment(vk.C0); + for (let i = 0; i < publicSignals.length; i++) transcript.addScalar(Fr.e(publicSignals[i])); + transcript.addPolCommitment(proof.polynomials.C1); + challenges.beta = transcript.getChallenge(); + transcript.reset(); + transcript.addScalar(challenges.beta); + challenges.gamma = transcript.getChallenge(); + transcript.reset(); + transcript.addScalar(challenges.gamma); + transcript.addPolCommitment(proof.polynomials.C2); + const xiSeed = transcript.getChallenge(); + const xiSeed2 = Fr.square(xiSeed); + let w8 = []; + w8[1] = vk.w8; + w8[2] = Fr.square(vk.w8); + w8[3] = Fr.mul(w8[2], vk.w8); + w8[4] = Fr.mul(w8[3], vk.w8); + w8[5] = Fr.mul(w8[4], vk.w8); + w8[6] = Fr.mul(w8[5], vk.w8); + w8[7] = Fr.mul(w8[6], vk.w8); + let w4 = []; + w4[1] = vk.w4; + w4[2] = Fr.square(vk.w4); + w4[3] = Fr.mul(w4[2], vk.w4); + let w3 = []; + w3[1] = vk.w3; + w3[2] = Fr.square(vk.w3); + roots.S0 = {}; + roots.S0.h0w8 = []; + roots.S0.h0w8[0] = Fr.mul(xiSeed2, xiSeed); + for (let i = 1; i < 8; i++) roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], w8[i]); + roots.S1 = {}; + roots.S1.h1w4 = []; + roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); + for (let i = 1; i < 4; i++) roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], w4[i]); + roots.S2 = {}; + roots.S2.h2w3 = []; + roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); + roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], w3[1]); + roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], w3[2]); + roots.S2.h3w3 = []; + roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], vk.wr); + roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], w3[1]); + roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], w3[2]); + challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); + challenges.xiw = Fr.mul(challenges.xi, Fr.w[vk.power]); + challenges.xiN = challenges.xi; + vk.domainSize = 1; + for (let i = 0; i < vk.power; i++) { + challenges.xiN = Fr.square(challenges.xiN); + vk.domainSize *= 2; + } + transcript.reset(); + transcript.addScalar(xiSeed); + transcript.addScalar(proof.evaluations.ql); + transcript.addScalar(proof.evaluations.qr); + transcript.addScalar(proof.evaluations.qm); + transcript.addScalar(proof.evaluations.qo); + transcript.addScalar(proof.evaluations.qc); + transcript.addScalar(proof.evaluations.s1); + transcript.addScalar(proof.evaluations.s2); + transcript.addScalar(proof.evaluations.s3); + transcript.addScalar(proof.evaluations.a); + transcript.addScalar(proof.evaluations.b); + transcript.addScalar(proof.evaluations.c); + transcript.addScalar(proof.evaluations.z); + transcript.addScalar(proof.evaluations.zw); + transcript.addScalar(proof.evaluations.t1w); + transcript.addScalar(proof.evaluations.t2w); + challenges.alpha = transcript.getChallenge(); + transcript.reset(); + transcript.addScalar(challenges.alpha); + transcript.addPolCommitment(proof.polynomials.W1); + challenges.y = transcript.getChallenge(); + if (logger) { + logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); + logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); + logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); + logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); + logger.info("··· challenges.y: " + Fr.toString(challenges.y)); + } + return { + challenges, + roots + }; +} async function computeLagrangeEvaluations(curve, challenges, vk) { - const Fr = curve.Fr; - - const size = Math.max(1, vk.nPublic); - const numArr = new ffjavascript.BigBuffer(size * Fr.n8); - let denArr = new ffjavascript.BigBuffer(size * Fr.n8); - - let w = Fr.one; - for (let i = 0; i < size; i++) { - const i_sFr = i * Fr.n8; - numArr.set(Fr.mul(w, challenges.zh), i_sFr); - denArr.set(Fr.mul(Fr.e(vk.domainSize), Fr.sub(challenges.xi, w)), i_sFr); - w = Fr.mul(w, vk.w); - } - - denArr = await Fr.batchInverse(denArr); - - let L = []; - for (let i = 0; i < size; i++) { - const i_sFr = i * Fr.n8; - L[i + 1] = Fr.mul(numArr.slice(i_sFr, i_sFr + Fr.n8), denArr.slice(i_sFr, i_sFr + Fr.n8)); - } - return L; -} - + const Fr = curve.Fr; + const size = Math.max(1, vk.nPublic); + const numArr = new ffjavascript.BigBuffer(size * Fr.n8); + let denArr = new ffjavascript.BigBuffer(size * Fr.n8); + let w = Fr.one; + for (let i = 0; i < size; i++) { + const i_sFr = i * Fr.n8; + numArr.set(Fr.mul(w, challenges.zh), i_sFr); + denArr.set(Fr.mul(Fr.e(vk.domainSize), Fr.sub(challenges.xi, w)), i_sFr); + w = Fr.mul(w, vk.w); + } + denArr = await Fr.batchInverse(denArr); + let L = []; + for (let i = 0; i < size; i++) { + const i_sFr = i * Fr.n8; + L[i + 1] = Fr.mul(numArr.slice(i_sFr, i_sFr + Fr.n8), denArr.slice(i_sFr, i_sFr + Fr.n8)); + } + return L; +} function calculatePI(curve, publicSignals, lagrangeEvals) { - const Fr = curve.Fr; - - let pi = Fr.zero; - for (let i = 0; i < publicSignals.length; i++) { - const w = Fr.e(publicSignals[i]); - pi = Fr.sub(pi, Fr.mul(w, lagrangeEvals[i + 1])); - } - return pi; -} - + const Fr = curve.Fr; + let pi = Fr.zero; + for (let i = 0; i < publicSignals.length; i++) { + const w = Fr.e(publicSignals[i]); + pi = Fr.sub(pi, Fr.mul(w, lagrangeEvals[i + 1])); + } + return pi; +} function computeR0(proof, challenges, roots, curve, logger) { - const Fr = curve.Fr; - - const Li = computeLagrangeLiSi(roots.S0.h0w8, challenges.y, challenges.xi, curve); - - // r0(y) = ∑_1^8 C_0(h_0 ω_8^{i-1}) L_i(y). To this end we need to compute - - // Compute the 8 C0 values - if (logger) logger.info("··· Computing r0(y)"); - - let res = Fr.zero; - for (let i = 0; i < 8; i++) { - let coefValues = []; - coefValues[1] = roots.S0.h0w8[i]; - for (let j = 2; j < 8; j++) { - coefValues[j] = Fr.mul(coefValues[j - 1], roots.S0.h0w8[i]); - } - - let c0 = Fr.add(proof.evaluations.ql, Fr.mul(proof.evaluations.qr, coefValues[1])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qo, coefValues[2])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qm, coefValues[3])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qc, coefValues[4])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s1, coefValues[5])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s2, coefValues[6])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s3, coefValues[7])); - - res = Fr.add(res, Fr.mul(c0, Li[i])); - } - - return res; -} - + const Fr = curve.Fr; + const Li = computeLagrangeLiSi(roots.S0.h0w8, challenges.y, challenges.xi, curve); + if (logger) logger.info("··· Computing r0(y)"); + let res = Fr.zero; + for (let i = 0; i < 8; i++) { + let coefValues = []; + coefValues[1] = roots.S0.h0w8[i]; + for (let j = 2; j < 8; j++) coefValues[j] = Fr.mul(coefValues[j - 1], roots.S0.h0w8[i]); + let c0 = Fr.add(proof.evaluations.ql, Fr.mul(proof.evaluations.qr, coefValues[1])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.qo, coefValues[2])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.qm, coefValues[3])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.qc, coefValues[4])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.s1, coefValues[5])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.s2, coefValues[6])); + c0 = Fr.add(c0, Fr.mul(proof.evaluations.s3, coefValues[7])); + res = Fr.add(res, Fr.mul(c0, Li[i])); + } + return res; +} function computeR1(proof, challenges, roots, pi, curve, logger) { - const Fr = curve.Fr; - - const Li = computeLagrangeLiSi(roots.S1.h1w4, challenges.y, challenges.xi, curve); - - // r1(y) = ∑_1^4 C_1(h_1 ω_4^{i-1}) L_i(y). To this end we need to compute - // Z1 = {C1(h_1}, C1(h_1 ω_4), C1(h_1 ω_4^2), C1(h_1 ω_4^3)} - // where C_1(h_1 ω_4^{i-1}) = eval.a + h_1 ω_4^i eval.b + (h_1 ω_4^i)^2 eval.c + (h_1 ω_4^i)^3 T0(xi), - // where T0(xi) = [ qL·a + qR·b + qM·a·b + qO·c + qC + PI(xi) ] / Z_H(xi) - - // Compute T0(xi) - if (logger) logger.info("··· Computing T0(xi)"); - let t0 = Fr.mul(proof.evaluations.ql, proof.evaluations.a); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qr, proof.evaluations.b)); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qm, Fr.mul(proof.evaluations.a, proof.evaluations.b))); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qo, proof.evaluations.c)); - t0 = Fr.add(t0, proof.evaluations.qc); - t0 = Fr.add(t0, pi); - t0 = Fr.mul(t0, challenges.invzh); - - // Compute the 4 C1 values - if (logger) logger.info("··· Computing C1(h_1ω_4^i) values"); - - let res = Fr.zero; - for (let i = 0; i < 4; i++) { - let c1 = proof.evaluations.a; - c1 = Fr.add(c1, Fr.mul(roots.S1.h1w4[i], proof.evaluations.b)); - const h1w4Squared = Fr.square(roots.S1.h1w4[i]); - c1 = Fr.add(c1, Fr.mul(h1w4Squared, proof.evaluations.c)); - c1 = Fr.add(c1, Fr.mul(Fr.mul(h1w4Squared, roots.S1.h1w4[i]), t0)); - - res = Fr.add(res, Fr.mul(c1, Li[i])); - } - - return res; -} - + const Fr = curve.Fr; + const Li = computeLagrangeLiSi(roots.S1.h1w4, challenges.y, challenges.xi, curve); + if (logger) logger.info("··· Computing T0(xi)"); + let t0 = Fr.mul(proof.evaluations.ql, proof.evaluations.a); + t0 = Fr.add(t0, Fr.mul(proof.evaluations.qr, proof.evaluations.b)); + t0 = Fr.add(t0, Fr.mul(proof.evaluations.qm, Fr.mul(proof.evaluations.a, proof.evaluations.b))); + t0 = Fr.add(t0, Fr.mul(proof.evaluations.qo, proof.evaluations.c)); + t0 = Fr.add(t0, proof.evaluations.qc); + t0 = Fr.add(t0, pi); + t0 = Fr.mul(t0, challenges.invzh); + if (logger) logger.info("··· Computing C1(h_1ω_4^i) values"); + let res = Fr.zero; + for (let i = 0; i < 4; i++) { + let c1 = proof.evaluations.a; + c1 = Fr.add(c1, Fr.mul(roots.S1.h1w4[i], proof.evaluations.b)); + const h1w4Squared = Fr.square(roots.S1.h1w4[i]); + c1 = Fr.add(c1, Fr.mul(h1w4Squared, proof.evaluations.c)); + c1 = Fr.add(c1, Fr.mul(Fr.mul(h1w4Squared, roots.S1.h1w4[i]), t0)); + res = Fr.add(res, Fr.mul(c1, Li[i])); + } + return res; +} function computeR2(proof, challenges, roots, lagrange1, vk, curve, logger) { - const Fr = curve.Fr; - - const LiS2 = computeLagrangeLiS2([roots.S2.h2w3, roots.S2.h3w3], challenges.y, challenges.xi, challenges.xiw, curve); - - // r2(y) = ∑_1^3 C_2(h_2 ω_3^{i-1}) L_i(y) + ∑_1^3 C_2(h_3 ω_3^{i-1}) L_{i+3}(y). To this end we need to compute - // Z2 = {[C2(h_2}, C2(h_2 ω_3), C2(h_2 ω_3^2)], [C2(h_3}, C2(h_3 ω_3), C2(h_3 ω_3^2)]} - // where C_2(h_2 ω_3^{i-1}) = eval.z + h_2 ω_2^i T1(xi) + (h_2 ω_3^i)^2 T2(xi), - // where C_2(h_3 ω_3^{i-1}) = eval.z + h_3 ω_2^i T1(xi) + (h_3 ω_3^i)^2 T2(xi), - // where T1(xi) = [ L_1(xi)(z-1)] / Z_H(xi) - // and T2(xi) = [ (a + beta·xi + gamma)(b + beta·xi·k1 + gamma)(c + beta·xi·k2 + gamma)z - // - (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma)zω ] / Z_H(xi) - - // Compute T1(xi) - if (logger) logger.info("··· Computing T1(xi)"); - let t1 = Fr.sub(proof.evaluations.z, Fr.one); - t1 = Fr.mul(t1, lagrange1); - t1 = Fr.mul(t1, challenges.invzh); - - // Compute T2(xi) - if (logger) logger.info("··· Computing T2(xi)"); - const betaxi = Fr.mul(challenges.beta, challenges.xi); - const t211 = Fr.add(proof.evaluations.a, Fr.add(betaxi, challenges.gamma)); - const t212 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(betaxi, vk.k1), challenges.gamma)); - const t213 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(betaxi, vk.k2), challenges.gamma)); - const t21 = Fr.mul(t211, Fr.mul(t212, Fr.mul(t213, proof.evaluations.z))); - - const t221 = Fr.add(proof.evaluations.a, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s1), challenges.gamma)); - const t222 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s2), challenges.gamma)); - const t223 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s3), challenges.gamma)); - const t22 = Fr.mul(t221, Fr.mul(t222, Fr.mul(t223, proof.evaluations.zw))); - - let t2 = Fr.sub(t21, t22); - t2 = Fr.mul(t2, challenges.invzh); - - // Compute the 6 C2 values - if (logger) logger.info("··· Computing C2(h_2ω_3^i) values"); - let res = Fr.zero; - for (let i = 0; i < 3; i++) { - let c2 = Fr.add(proof.evaluations.z, Fr.mul(roots.S2.h2w3[i], t1)); - c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h2w3[i]), t2)); - - res = Fr.add(res, Fr.mul(c2, LiS2[i])); - } - - if (logger) logger.info("··· Computing C2(h_3ω_3^i) values"); - for (let i = 0; i < 3; i++) { - let c2 = Fr.add(proof.evaluations.zw, Fr.mul(roots.S2.h3w3[i], proof.evaluations.t1w)); - c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h3w3[i]), proof.evaluations.t2w)); - - res = Fr.add(res, Fr.mul(c2, LiS2[i + 3])); - } - - return res; -} - + const Fr = curve.Fr; + const LiS2 = computeLagrangeLiS2([roots.S2.h2w3, roots.S2.h3w3], challenges.y, challenges.xi, challenges.xiw, curve); + if (logger) logger.info("··· Computing T1(xi)"); + let t1 = Fr.sub(proof.evaluations.z, Fr.one); + t1 = Fr.mul(t1, lagrange1); + t1 = Fr.mul(t1, challenges.invzh); + if (logger) logger.info("··· Computing T2(xi)"); + const betaxi = Fr.mul(challenges.beta, challenges.xi); + const t211 = Fr.add(proof.evaluations.a, Fr.add(betaxi, challenges.gamma)); + const t212 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(betaxi, vk.k1), challenges.gamma)); + const t213 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(betaxi, vk.k2), challenges.gamma)); + const t21 = Fr.mul(t211, Fr.mul(t212, Fr.mul(t213, proof.evaluations.z))); + const t221 = Fr.add(proof.evaluations.a, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s1), challenges.gamma)); + const t222 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s2), challenges.gamma)); + const t223 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s3), challenges.gamma)); + const t22 = Fr.mul(t221, Fr.mul(t222, Fr.mul(t223, proof.evaluations.zw))); + let t2 = Fr.sub(t21, t22); + t2 = Fr.mul(t2, challenges.invzh); + if (logger) logger.info("··· Computing C2(h_2ω_3^i) values"); + let res = Fr.zero; + for (let i = 0; i < 3; i++) { + let c2 = Fr.add(proof.evaluations.z, Fr.mul(roots.S2.h2w3[i], t1)); + c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h2w3[i]), t2)); + res = Fr.add(res, Fr.mul(c2, LiS2[i])); + } + if (logger) logger.info("··· Computing C2(h_3ω_3^i) values"); + for (let i = 0; i < 3; i++) { + let c2 = Fr.add(proof.evaluations.zw, Fr.mul(roots.S2.h3w3[i], proof.evaluations.t1w)); + c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h3w3[i]), proof.evaluations.t2w)); + res = Fr.add(res, Fr.mul(c2, LiS2[i + 3])); + } + return res; +} function computeF(curve, proof, vk, challenges, roots) { - const G1 = curve.G1; - const Fr = curve.Fr; - - let mulH0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); - for (let i = 1; i < 8; i++) { - mulH0 = Fr.mul(mulH0, Fr.sub(challenges.y, roots.S0.h0w8[i])); - } - - challenges.temp = mulH0; - - let mulH1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); - for (let i = 1; i < 4; i++) { - mulH1 = Fr.mul(mulH1, Fr.sub(challenges.y, roots.S1.h1w4[i])); - } - - let mulH2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); - for (let i = 1; i < 3; i++) { - mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h2w3[i])); - } - for (let i = 0; i < 3; i++) { - mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h3w3[i])); - } - - challenges.quotient1 = Fr.mul(challenges.alpha, Fr.div(mulH0, mulH1)); - challenges.quotient2 = Fr.mul(Fr.square(challenges.alpha), Fr.div(mulH0, mulH2)); - - let F2 = G1.timesFr(proof.polynomials.C1, challenges.quotient1); - let F3 = G1.timesFr(proof.polynomials.C2, challenges.quotient2); - - return G1.add(vk.C0, G1.add(F2, F3)); -} - + const G1 = curve.G1; + const Fr = curve.Fr; + let mulH0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); + for (let i = 1; i < 8; i++) mulH0 = Fr.mul(mulH0, Fr.sub(challenges.y, roots.S0.h0w8[i])); + challenges.temp = mulH0; + let mulH1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); + for (let i = 1; i < 4; i++) mulH1 = Fr.mul(mulH1, Fr.sub(challenges.y, roots.S1.h1w4[i])); + let mulH2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); + for (let i = 1; i < 3; i++) mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h2w3[i])); + for (let i = 0; i < 3; i++) mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h3w3[i])); + challenges.quotient1 = Fr.mul(challenges.alpha, Fr.div(mulH0, mulH1)); + challenges.quotient2 = Fr.mul(Fr.square(challenges.alpha), Fr.div(mulH0, mulH2)); + let F2 = G1.timesFr(proof.polynomials.C1, challenges.quotient1); + let F3 = G1.timesFr(proof.polynomials.C2, challenges.quotient2); + return G1.add(vk.C0, G1.add(F2, F3)); +} function computeE(curve, proof, challenges, vk, r0, r1, r2) { - const G1 = curve.G1; - const Fr = curve.Fr; - - let E2 = Fr.mul(r1, challenges.quotient1); - let E3 = Fr.mul(r2, challenges.quotient2); - - return G1.timesFr(G1.one, Fr.add(r0, Fr.add(E2, E3))); -} - + const G1 = curve.G1; + const Fr = curve.Fr; + let E2 = Fr.mul(r1, challenges.quotient1); + let E3 = Fr.mul(r2, challenges.quotient2); + return G1.timesFr(G1.one, Fr.add(r0, Fr.add(E2, E3))); +} function computeJ(curve, proof, challenges) { - const G1 = curve.G1; - - return G1.timesFr(proof.polynomials.W1, challenges.temp); + return curve.G1.timesFr(proof.polynomials.W1, challenges.temp); } - async function isValidPairing(curve, proof, challenges, vk, F, E, J) { - const G1 = curve.G1; - - let A1 = G1.timesFr(proof.polynomials.W2, challenges.y); - A1 = G1.add(G1.sub(G1.sub(F, E), J), A1); - const A2 = curve.G2.one; - - const B1 = proof.polynomials.W2; - const B2 = vk.X_2; - - return await curve.pairingEq(G1.neg(A1), A2, B1, B2); -} - - + const G1 = curve.G1; + let A1 = G1.timesFr(proof.polynomials.W2, challenges.y); + A1 = G1.add(G1.sub(G1.sub(F, E), J), A1); + const A2 = curve.G2.one; + const B1 = proof.polynomials.W2; + const B2 = vk.X_2; + return await curve.pairingEq(G1.neg(A1), A2, B1, B2); +} function computeLagrangeLiSi(roots, x, xi, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const num = Fr.sub(Fr.exp(x, len), xi); - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - Li[i] = Fr.div(num, Fr.mul(Fr.mul(den1, den2), den3)); - } - - return Li; -} - + const Fr = curve.Fr; + const len = roots.length; + const num = Fr.sub(Fr.exp(x, len), xi); + const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); + const Li = []; + for (let i = 0; i < len; i++) { + const den2 = roots[(len - 1) * i % len]; + const den3 = Fr.sub(x, roots[i]); + Li[i] = Fr.div(num, Fr.mul(Fr.mul(den1, den2), den3)); + } + return Li; +} function computeLagrangeLiS2(roots, value, xi0, xi1, curve) { - const Fr = curve.Fr; - - const Li = []; - - const len = roots[0].length; - const n = len * roots.length; - - const num1 = Fr.exp(value, n); - const num2 = Fr.mul(Fr.add(xi0, xi1), Fr.exp(value, len)); - const num3 = Fr.mul(xi0, xi1); - const num = Fr.add(Fr.sub(num1, num2), num3); - - let den1 = Fr.mul(Fr.mul(Fr.e(len), roots[0][0]), Fr.sub(xi0, xi1)); - for (let i = 0; i < len; i++) { - const den2 = roots[0][(len - 1) * i % len]; - const den3 = Fr.sub(value, roots[0][i]); - - const den = Fr.mul(den1,Fr.mul(den2, den3)); - - Li[i] = Fr.div(num, den); - } - - den1 = Fr.mul(Fr.mul(Fr.e(len), roots[1][0]), Fr.sub(xi1, xi0)); - for (let i = 0; i < len; i++) { - const den2 = roots[1][(len - 1) * i % len]; - const den3 = Fr.sub(value, roots[1][i]); - - const den = Fr.mul(den1,Fr.mul(den2, den3)); - - Li[i + len] = Fr.div(num, den); - } - - return Li; -} - -/* - Copyright 2021 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . -*/ - - -const {unstringifyBigInts} = ffjavascript.utils; - + const Fr = curve.Fr; + const Li = []; + const len = roots[0].length; + const n = len * roots.length; + const num1 = Fr.exp(value, n); + const num2 = Fr.mul(Fr.add(xi0, xi1), Fr.exp(value, len)); + const num3 = Fr.mul(xi0, xi1); + const num = Fr.add(Fr.sub(num1, num2), num3); + let den1 = Fr.mul(Fr.mul(Fr.e(len), roots[0][0]), Fr.sub(xi0, xi1)); + for (let i = 0; i < len; i++) { + const den2 = roots[0][(len - 1) * i % len]; + const den3 = Fr.sub(value, roots[0][i]); + const den = Fr.mul(den1, Fr.mul(den2, den3)); + Li[i] = Fr.div(num, den); + } + den1 = Fr.mul(Fr.mul(Fr.e(len), roots[1][0]), Fr.sub(xi1, xi0)); + for (let i = 0; i < len; i++) { + const den2 = roots[1][(len - 1) * i % len]; + const den3 = Fr.sub(value, roots[1][i]); + const den = Fr.mul(den1, Fr.mul(den2, den3)); + Li[i + len] = Fr.div(num, den); + } + return Li; +} +//#endregion +//#region src/fflonk_export_calldata.js +var { unstringifyBigInts } = ffjavascript.utils; function p256(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0" + nstr; - nstr = `0x${nstr}`; - return nstr; + let nstr = n.toString(16); + while (nstr.length < 64) nstr = "0" + nstr; + nstr = `0x${nstr}`; + return nstr; } - async function fflonkExportCallData(_pub, _proof) { - const proof = unstringifyBigInts(_proof); - const pub = unstringifyBigInts(_pub); - - await getCurveFromName(proof.curve); - - let inputs = ""; - for (let i = 0; i < pub.length; i++) { - if (inputs !== "") inputs = inputs + ","; - inputs = inputs + p256(pub[i]); - } - - return `[${p256(proof.polynomials.C1[0])}, ${p256(proof.polynomials.C1[1])},` + - `${p256(proof.polynomials.C2[0])},${p256(proof.polynomials.C2[1])},` + - `${p256(proof.polynomials.W1[0])},${p256(proof.polynomials.W1[1])},` + - `${p256(proof.polynomials.W2[0])},${p256(proof.polynomials.W2[1])},` + - `${p256(proof.evaluations.ql)},${p256(proof.evaluations.qr)},${p256(proof.evaluations.qm)},` + - `${p256(proof.evaluations.qo)},${p256(proof.evaluations.qc)},${p256(proof.evaluations.s1)},` + - `${p256(proof.evaluations.s2)},${p256(proof.evaluations.s3)},${p256(proof.evaluations.a)},` + - `${p256(proof.evaluations.b)},${p256(proof.evaluations.c)},${p256(proof.evaluations.z)},` + - `${p256(proof.evaluations.zw)},${p256(proof.evaluations.t1w)},${p256(proof.evaluations.t2w)},` + - `${p256(proof.evaluations.inv)}],` + - `[${inputs}]`; -} - -/* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . -*/ - -var fflonk = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportSolidityCallData: fflonkExportCallData, - exportSolidityVerifier: fflonkExportSolidityVerifier, - fullProve: fflonkFullProve, - prove: fflonkProve, - setup: fflonkSetup, - verify: fflonkVerify + const proof = unstringifyBigInts(_proof); + const pub = unstringifyBigInts(_pub); + await getCurveFromName(proof.curve); + let inputs = ""; + for (let i = 0; i < pub.length; i++) { + if (inputs !== "") inputs = inputs + ","; + inputs = inputs + p256(pub[i]); + } + return `[${p256(proof.polynomials.C1[0])}, ${p256(proof.polynomials.C1[1])},${p256(proof.polynomials.C2[0])},${p256(proof.polynomials.C2[1])},${p256(proof.polynomials.W1[0])},${p256(proof.polynomials.W1[1])},${p256(proof.polynomials.W2[0])},${p256(proof.polynomials.W2[1])},${p256(proof.evaluations.ql)},${p256(proof.evaluations.qr)},${p256(proof.evaluations.qm)},${p256(proof.evaluations.qo)},${p256(proof.evaluations.qc)},${p256(proof.evaluations.s1)},${p256(proof.evaluations.s2)},${p256(proof.evaluations.s3)},${p256(proof.evaluations.a)},${p256(proof.evaluations.b)},${p256(proof.evaluations.c)},${p256(proof.evaluations.z)},${p256(proof.evaluations.zw)},${p256(proof.evaluations.t1w)},${p256(proof.evaluations.t2w)},${p256(proof.evaluations.inv)}],[${inputs}]`; +} +//#endregion +//#region src/fflonk.js +var fflonk_exports = /* @__PURE__ */ __exportAll({ + exportSolidityCallData: () => fflonkExportCallData, + exportSolidityVerifier: () => fflonkExportSolidityVerifier, + fullProve: () => fflonkFullProve, + prove: () => fflonkProve, + setup: () => fflonkSetup, + verify: () => fflonkVerify +}); +//#endregion +Object.defineProperty(exports, "curves", { + enumerable: true, + get: function() { + return curves_exports; + } +}); +Object.defineProperty(exports, "fflonk", { + enumerable: true, + get: function() { + return fflonk_exports; + } +}); +Object.defineProperty(exports, "groth16", { + enumerable: true, + get: function() { + return groth16_exports; + } +}); +Object.defineProperty(exports, "plonk", { + enumerable: true, + get: function() { + return plonk_exports; + } +}); +Object.defineProperty(exports, "powersOfTau", { + enumerable: true, + get: function() { + return powersoftau_exports; + } +}); +Object.defineProperty(exports, "r1cs", { + enumerable: true, + get: function() { + return r1cs_exports; + } +}); +Object.defineProperty(exports, "wtns", { + enumerable: true, + get: function() { + return wtns_exports; + } +}); +Object.defineProperty(exports, "zKey", { + enumerable: true, + get: function() { + return zkey_exports; + } }); - -exports.curves = curves; -exports.fflonk = fflonk; -exports.groth16 = groth16; -exports.plonk = plonk; -exports.powersOfTau = powersoftau; -exports.r1cs = r1cs; -exports.wtns = wtns; -exports.zKey = zkey; diff --git a/build/snarkjs.js b/build/snarkjs.js deleted file mode 100644 index 3d6a7bd1..00000000 --- a/build/snarkjs.js +++ /dev/null @@ -1,22472 +0,0 @@ -var snarkjs = (function (exports) { - 'use strict'; - - const hexLen = [ 0, 1, 2, 2, 3, 3, 3, 3, 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4]; - - function fromString(s, radix) { - if ((!radix)||(radix==10)) { - return BigInt(s); - } else if (radix==16) { - if (s.slice(0,2) == "0x") { - return BigInt(s); - } else { - return BigInt("0x"+s); - } - } - } - - const e = fromString; - - function fromArray(a, radix) { - let acc =BigInt(0); - radix = BigInt(radix); - for (let i=0; i> BigInt(n); - } - - const shl = shiftLeft; - const shr = shiftRight; - - function isOdd(a) { - return (BigInt(a) & BigInt(1)) == BigInt(1); - } - - - function naf(n) { - let E = BigInt(n); - const res = []; - while (E) { - if (E & BigInt(1)) { - const z = 2 - Number(E % BigInt(4)); - res.push( z ); - E = E - BigInt(z); - } else { - res.push( 0 ); - } - E = E >> BigInt(1); - } - return res; - } - - - function bits(n) { - let E = BigInt(n); - const res = []; - while (E) { - if (E & BigInt(1)) { - res.push(1); - } else { - res.push( 0 ); - } - E = E >> BigInt(1); - } - return res; - } - - function toNumber(s) { - if (s>BigInt(Number.MAX_SAFE_INTEGER )) { - throw new Error("Number too big"); - } - return Number(s); - } - - function toArray(s, radix) { - const res = []; - let rem = BigInt(s); - radix = BigInt(radix); - while (rem) { - res.unshift( Number(rem % radix)); - rem = rem / radix; - } - return res; - } - - - function add$1(a, b) { - return BigInt(a) + BigInt(b); - } - - function sub(a, b) { - return BigInt(a) - BigInt(b); - } - - function neg(a) { - return -BigInt(a); - } - - function mul(a, b) { - return BigInt(a) * BigInt(b); - } - - function square(a) { - return BigInt(a) * BigInt(a); - } - - function pow(a, b) { - return BigInt(a) ** BigInt(b); - } - - function exp$1(a, b) { - return BigInt(a) ** BigInt(b); - } - - function abs(a) { - return BigInt(a) >= 0 ? BigInt(a) : -BigInt(a); - } - - function div(a, b) { - return BigInt(a) / BigInt(b); - } - - function mod(a, b) { - return BigInt(a) % BigInt(b); - } - - function eq(a, b) { - return BigInt(a) == BigInt(b); - } - - function neq(a, b) { - return BigInt(a) != BigInt(b); - } - - function lt(a, b) { - return BigInt(a) < BigInt(b); - } - - function gt(a, b) { - return BigInt(a) > BigInt(b); - } - - function leq(a, b) { - return BigInt(a) <= BigInt(b); - } - - function geq(a, b) { - return BigInt(a) >= BigInt(b); - } - - function band(a, b) { - return BigInt(a) & BigInt(b); - } - - function bor(a, b) { - return BigInt(a) | BigInt(b); - } - - function bxor(a, b) { - return BigInt(a) ^ BigInt(b); - } - - function land(a, b) { - return BigInt(a) && BigInt(b); - } - - function lor(a, b) { - return BigInt(a) || BigInt(b); - } - - function lnot(a) { - return !BigInt(a); - } - - // Returns a buffer with Little Endian Representation - function toRprLE(buff, o, e, n8) { - const s = "0000000" + e.toString(16); - const v = new Uint32Array(buff.buffer, buff.byteOffset + o, n8/4); - const l = (((s.length-7)*4 - 1) >> 5)+1; // Number of 32bit words; - for (let i=0; i> 5)+1; // Number of 32bit words; - for (let i=0; i a[a.length-i-1] = ch.toString(16).padStart(8,"0") ); - return fromString(a.join(""), 16); - } - - // Pases a buffer with Big Endian Representation - function fromRprBE(buff, o, n8) { - n8 = n8 || buff.byteLength; - o = o || 0; - const v = new DataView(buff.buffer, buff.byteOffset + o, n8); - const a = new Array(n8/4); - for (let i=0; i{ - let res = F.zero; - let rem = bigInt(e); - let exp = base; - - while (! rem.eq(bigInt.zero)) { - if (rem.and(bigInt.one).eq(bigInt.one)) { - res = F.add(res, exp); - } - exp = F.double(exp); - rem = rem.shiftRight(1); - } - - return res; - }; - */ - - - function exp(F, base, e) { - - if (isZero(e)) return F.one; - - const n = bits(e); - - if (n.length==0) return F.one; - - let res = base; - - for (let i=n.length-2; i>=0; i--) { - - res = F.square(res); - - if (n[i]) { - res = F.mul(res, base); - } - } - - return res; - } - - // Check here: https://eprint.iacr.org/2012/685.pdf - - function buildSqrt (F) { - if ((F.m % 2) == 1) { - if (eq(mod(F.p, 4), 1 )) { - if (eq(mod(F.p, 8), 1 )) { - if (eq(mod(F.p, 16), 1 )) { - // alg7_muller(F); - alg5_tonelliShanks(F); - } else if (eq(mod(F.p, 16), 9 )) { - alg4_kong(F); - } else { - throw new Error("Field withot sqrt"); - } - } else if (eq(mod(F.p, 8), 5 )) { - alg3_atkin(F); - } else { - throw new Error("Field withot sqrt"); - } - } else if (eq(mod(F.p, 4), 3 )) { - alg2_shanks(F); - } - } else { - const pm2mod4 = mod(pow(F.p, F.m/2), 4); - if (pm2mod4 == 1) { - alg10_adj(F); - } else if (pm2mod4 == 3) { - alg9_adj(F); - } else { - alg8_complex(F); - } - - } - } - - - function alg5_tonelliShanks(F) { - F.sqrt_q = pow(F.p, F.m); - - F.sqrt_s = 0; - F.sqrt_t = sub(F.sqrt_q, 1); - - while (!isOdd(F.sqrt_t)) { - F.sqrt_s = F.sqrt_s + 1; - F.sqrt_t = div(F.sqrt_t, 2); - } - - let c0 = F.one; - - while (F.eq(c0, F.one)) { - const c = F.random(); - F.sqrt_z = F.pow(c, F.sqrt_t); - c0 = F.pow(F.sqrt_z, 2 ** (F.sqrt_s-1) ); - } - - F.sqrt_tm1d2 = div(sub(F.sqrt_t, 1),2); - - F.sqrt = function(a) { - const F=this; - if (F.isZero(a)) return F.zero; - let w = F.pow(a, F.sqrt_tm1d2); - const a0 = F.pow( F.mul(F.square(w), a), 2 ** (F.sqrt_s-1) ); - if (F.eq(a0, F.negone)) return null; - - let v = F.sqrt_s; - let x = F.mul(a, w); - let b = F.mul(x, w); - let z = F.sqrt_z; - while (!F.eq(b, F.one)) { - let b2k = F.square(b); - let k=1; - while (!F.eq(b2k, F.one)) { - b2k = F.square(b2k); - k++; - } - - w = z; - for (let i=0; i>> 0; - st[d] = (st[d] ^ st[a]) >>> 0; - st[d] = ((st[d] << 16) | ((st[d]>>>16) & 0xFFFF)) >>> 0; - - st[c] = (st[c] + st[d]) >>> 0; - st[b] = (st[b] ^ st[c]) >>> 0; - st[b] = ((st[b] << 12) | ((st[b]>>>20) & 0xFFF)) >>> 0; - - st[a] = (st[a] + st[b]) >>> 0; - st[d] = (st[d] ^ st[a]) >>> 0; - st[d] = ((st[d] << 8) | ((st[d]>>>24) & 0xFF)) >>> 0; - - st[c] = (st[c] + st[d]) >>> 0; - st[b] = (st[b] ^ st[c]) >>> 0; - st[b] = ((st[b] << 7) | ((st[b]>>>25) & 0x7F)) >>> 0; - } - - function doubleRound(st) { - quarterRound(st, 0, 4, 8,12); - quarterRound(st, 1, 5, 9,13); - quarterRound(st, 2, 6,10,14); - quarterRound(st, 3, 7,11,15); - - quarterRound(st, 0, 5,10,15); - quarterRound(st, 1, 6,11,12); - quarterRound(st, 2, 7, 8,13); - quarterRound(st, 3, 4, 9,14); - } - - class ChaCha { - - constructor(seed) { - seed = seed || [0,0,0,0,0,0,0,0]; - this.state = [ - 0x61707865, - 0x3320646E, - 0x79622D32, - 0x6B206574, - seed[0], - seed[1], - seed[2], - seed[3], - seed[4], - seed[5], - seed[6], - seed[7], - 0, - 0, - 0, - 0 - ]; - this.idx = 16; - this.buff = new Array(16); - } - - nextU32() { - if (this.idx == 16) this.update(); - return this.buff[this.idx++]; - } - - nextU64() { - return add$1(mul(this.nextU32(), 0x100000000), this.nextU32()); - } - - nextBool() { - return (this.nextU32() & 1) == 1; - } - - update() { - // Copy the state - for (let i=0; i<16; i++) this.buff[i] = this.state[i]; - - // Apply the rounds - for (let i=0; i<10; i++) doubleRound(this.buff); - - // Add to the initial - for (let i=0; i<16; i++) this.buff[i] = (this.buff[i] + this.state[i]) >>> 0; - - this.idx = 0; - - this.state[12] = (this.state[12] + 1) >>> 0; - if (this.state[12] != 0) return; - this.state[13] = (this.state[13] + 1) >>> 0; - if (this.state[13] != 0) return; - this.state[14] = (this.state[14] + 1) >>> 0; - if (this.state[14] != 0) return; - this.state[15] = (this.state[15] + 1) >>> 0; - } - } - - var os = {}; - - function getRandomBytes$1(n) { - let array = new Uint8Array(n); - // Feature-detect rather than rely on `true` (undefined under - // Vite/esbuild/SES -> ReferenceError). Prefer Node crypto (no per-call size - // limit); fall back to Web Crypto chunked to its 65536-byte cap. - if (os && os.randomFillSync) { // Node - os.randomFillSync(array); - } else if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) { - for (let i = 0; i < n; i += 65536) { - globalThis.crypto.getRandomValues(array.subarray(i, Math.min(i + 65536, n))); - } - } else { // insecure last resort - for (let i=0; i>>0; - } - } - return array; - } - - function getRandomSeed() { - const arr = getRandomBytes$1(32); - const arrV = new Uint32Array(arr.buffer); - const seed = []; - for (let i=0; i<8; i++) { - seed.push(arrV[i]); - } - return seed; - } - - let threadRng = null; - - function getThreadRng() { - if (threadRng) return threadRng; - threadRng = new ChaCha(getRandomSeed()); - return threadRng; - } - - /* - Copyright 2018 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - /* - This library does operations on polynomials with coefficients in a field F. - - A polynomial P(x) = p0 + p1 * x + p2 * x^2 + ... + pn * x^n is represented - by the array [ p0, p1, p2, ... , pn ]. - */ - - class FFT { - constructor (G, F, opMulGF) { - this.F = F; - this.G = G; - this.opMulGF = opMulGF; - - let rem = F.sqrt_t || F.t; - let s = F.sqrt_s || F.s; - - let nqr = F.one; - while (F.eq(F.pow(nqr, F.half), F.one)) nqr = F.add(nqr, F.one); - - this.w = new Array(s+1); - this.wi = new Array(s+1); - this.w[s] = this.F.pow(nqr, rem); - this.wi[s] = this.F.inv(this.w[s]); - - let n=s-1; - while (n>=0) { - this.w[n] = this.F.square(this.w[n+1]); - this.wi[n] = this.F.square(this.wi[n+1]); - n--; - } - - - this.roots = []; - /* - for (let i=0; i<16; i++) { - let r = this.F.one; - n = 1 << i; - const rootsi = new Array(n); - for (let j=0; j=0) && (!this.roots[i]); i--) { - let r = this.F.one; - const nroots = 1 << i; - const rootsi = new Array(nroots); - for (let j=0; j> 1; - const p1 = __fft(PF, pall, bits-1, offset, step*2); - const p2 = __fft(PF, pall, bits-1, offset+step, step*2); - - const out = new Array(n); - - for (let i=0; i> this.one; - this.bitLength = bitLength(this.p); - this.mask = (this.one << BigInt(this.bitLength)) - this.one; - - this.n64 = Math.floor((this.bitLength - 1) / 64)+1; - this.n32 = this.n64*2; - this.n8 = this.n64*8; - this.R = this.e(this.one << BigInt(this.n64*64)); - this.Ri = this.inv(this.R); - - const e = this.negone >> this.one; - this.nqr = this.two; - let r = this.pow(this.nqr, e); - while (!this.eq(r, this.negone)) { - this.nqr = this.nqr + this.one; - r = this.pow(this.nqr, e); - } - - - this.s = 0; - this.t = this.negone; - - while ((this.t & this.one) == this.zero) { - this.s = this.s + 1; - this.t = this.t >> this.one; - } - - this.nqr_to_t = this.pow(this.nqr, this.t); - - buildSqrt(this); - - this.FFT = new FFT(this, this, this.mul.bind(this)); - - this.fft = this.FFT.fft.bind(this.FFT); - this.ifft = this.FFT.ifft.bind(this.FFT); - this.w = this.FFT.w; - this.wi = this.FFT.wi; - - this.shift = this.square(this.nqr); - this.k = this.exp(this.nqr, 2**this.s); - } - - e(a,b) { - let res; - if (!b) { - res = BigInt(a); - } else if (b==16) { - res = BigInt("0x"+a); - } - if (res < 0) { - let nres = -res; - if (nres >= this.p) nres = nres % this.p; - return this.p - nres; - } else { - return (res>= this.p) ? res%this.p : res; - } - - } - - add(a, b) { - const res = a + b; - return res >= this.p ? res-this.p : res; - } - - sub(a, b) { - return (a >= b) ? a-b : this.p-b+a; - } - - neg(a) { - return a ? this.p-a : a; - } - - mul(a, b) { - return (a*b)%this.p; - } - - mulScalar(base, s) { - return (base * this.e(s)) % this.p; - } - - square(a) { - return (a*a) % this.p; - } - - eq(a, b) { - return a==b; - } - - neq(a, b) { - return a!=b; - } - - lt(a, b) { - const aa = (a > this.half) ? a - this.p : a; - const bb = (b > this.half) ? b - this.p : b; - return aa < bb; - } - - gt(a, b) { - const aa = (a > this.half) ? a - this.p : a; - const bb = (b > this.half) ? b - this.p : b; - return aa > bb; - } - - leq(a, b) { - const aa = (a > this.half) ? a - this.p : a; - const bb = (b > this.half) ? b - this.p : b; - return aa <= bb; - } - - geq(a, b) { - const aa = (a > this.half) ? a - this.p : a; - const bb = (b > this.half) ? b - this.p : b; - return aa >= bb; - } - - div(a, b) { - return this.mul(a, this.inv(b)); - } - - idiv(a, b) { - if (!b) throw new Error("Division by zero"); - return a / b; - } - - inv(a) { - if (!a) throw new Error("Division by zero"); - - let t = this.zero; - let r = this.p; - let newt = this.one; - let newr = a % this.p; - while (newr) { - let q = r/newr; - [t, newt] = [newt, t-q*newt]; - [r, newr] = [newr, r-q*newr]; - } - if (t= this.p ? res-this.p : res; - } - - bor(a, b) { - const res = ((a | b) & this.mask); - return res >= this.p ? res-this.p : res; - } - - bxor(a, b) { - const res = ((a ^ b) & this.mask); - return res >= this.p ? res-this.p : res; - } - - bnot(a) { - const res = a ^ this.mask; - return res >= this.p ? res-this.p : res; - } - - shl(a, b) { - if (Number(b) < this.bitLength) { - const res = (a << b) & this.mask; - return res >= this.p ? res-this.p : res; - } else { - const nb = this.p - b; - if (Number(nb) < this.bitLength) { - return a >> nb; - } else { - return this.zero; - } - } - } - - shr(a, b) { - if (Number(b) < this.bitLength) { - return a >> b; - } else { - const nb = this.p - b; - if (Number(nb) < this.bitLength) { - const res = (a << nb) & this.mask; - return res >= this.p ? res-this.p : res; - } else { - return 0; - } - } - } - - land(a, b) { - return (a && b) ? this.one : this.zero; - } - - lor(a, b) { - return (a || b) ? this.one : this.zero; - } - - lnot(a) { - return (a) ? this.zero : this.one; - } - - sqrt_old(n) { - - if (n == this.zero) return this.zero; - - // Test that have solution - const res = this.pow(n, this.negone >> this.one); - if ( res != this.one ) return null; - - let m = this.s; - let c = this.nqr_to_t; - let t = this.pow(n, this.t); - let r = this.pow(n, this.add(this.t, this.one) >> this.one ); - - while ( t != this.one ) { - let sq = this.square(t); - let i = 1; - while (sq != this.one ) { - i++; - sq = this.square(sq); - } - - // b = c ^ m-i-1 - let b = c; - for (let j=0; j< m-i-1; j ++) b = this.square(b); - - m = i; - c = this.square(b); - t = this.mul(t, c); - r = this.mul(r, b); - } - - if (r > (this.p >> this.one)) { - r = this.neg(r); - } - - return r; - } - - normalize(a, b) { - a = BigInt(a,b); - if (a < 0) { - let na = -a; - if (na >= this.p) na = na % this.p; - return this.p - na; - } else { - return (a>= this.p) ? a%this.p : a; - } - } - - random() { - const nBytes = (this.bitLength*2 / 8); - let res =this.zero; - for (let i=0; i this.half)&&(base == 10)) { - const v = this.p-a; - vs = "-"+v.toString(base); - } else { - vs = a.toString(base); - } - return vs; - } - - isZero(a) { - return a == this.zero; - } - - fromRng(rng) { - let v; - do { - v=this.zero; - for (let i=0; i= this.p); - v = (v * this.Ri) % this.p; // Convert from montgomery - return v; - } - - fft(a) { - return this.FFT.fft(a); - } - - ifft(a) { - return this.FFT.ifft(a); - } - - // Returns a buffer with Little Endian Representation - toRprLE(buff, o, e) { - toRprLE(buff, o, e, this.n64*8); - } - - // Returns a buffer with Big Endian Representation - toRprBE(buff, o, e) { - toRprBE(buff, o, e, this.n64*8); - } - - // Returns a buffer with Big Endian Montgomery Representation - toRprBEM(buff, o, e) { - return this.toRprBE(buff, o, this.mul(this.R, e)); - } - - toRprLEM(buff, o, e) { - return this.toRprLE(buff, o, this.mul(this.R, e)); - } - - - // Pases a buffer with Little Endian Representation - fromRprLE(buff, o) { - return fromRprLE(buff, o, this.n8); - } - - // Pases a buffer with Big Endian Representation - fromRprBE(buff, o) { - return fromRprBE(buff, o, this.n8); - } - - fromRprLEM(buff, o) { - return this.mul(this.fromRprLE(buff, o), this.Ri); - } - - fromRprBEM(buff, o) { - return this.mul(this.fromRprBE(buff, o), this.Ri); - } - - toObject(a) { - return a; - } - } - - function stringifyBigInts$5(o) { - if (typeof o == "bigint" || o.eq !== undefined) { - return o.toString(10); - } else if (o instanceof Uint8Array) { - return fromRprLE(o, 0); - } else if (Array.isArray(o)) { - return o.map(stringifyBigInts$5); - } else if (typeof o == "object") { - const res = {}; - const keys = Object.keys(o); - keys.forEach((k) => { - res[k] = stringifyBigInts$5(o[k]); - }); - return res; - } else { - return o; - } - } - - function unstringifyBigInts$c(o) { - if (typeof o == "string" && /^[0-9]+$/.test(o)) { - return BigInt(o); - } else if (typeof o == "string" && /^0x[0-9a-fA-F]+$/.test(o)) { - return BigInt(o); - } else if (Array.isArray(o)) { - return o.map(unstringifyBigInts$c); - } else if (typeof o == "object") { - if (o === null) return null; - const res = {}; - const keys = Object.keys(o); - keys.forEach((k) => { - res[k] = unstringifyBigInts$c(o[k]); - }); - return res; - } else { - return o; - } - } - - function beBuff2int(buff) { - let res = BigInt(0); - let i = buff.length; - let offset = 0; - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - while (i > 0) { - if (i >= 4) { - i -= 4; - res += BigInt(buffV.getUint32(i)) << BigInt(offset * 8); - offset += 4; - } else if (i >= 2) { - i -= 2; - res += BigInt(buffV.getUint16(i)) << BigInt(offset * 8); - offset += 2; - } else { - i -= 1; - res += BigInt(buffV.getUint8(i)) << BigInt(offset * 8); - offset += 1; - } - } - return res; - } - - function beInt2Buff(n, len) { - let r = n; - const buff = new Uint8Array(len); - const buffV = new DataView(buff.buffer); - let o = len; - while (o > 0) { - if (o - 4 >= 0) { - o -= 4; - buffV.setUint32(o, Number(r & BigInt(0xffffffff))); - r = r >> BigInt(32); - } else if (o - 2 >= 0) { - o -= 2; - buffV.setUint16(o, Number(r & BigInt(0xffff))); - r = r >> BigInt(16); - } else { - o -= 1; - buffV.setUint8(o, Number(r & BigInt(0xff))); - r = r >> BigInt(8); - } - } - if (r) { - throw new Error("Number does not fit in this length"); - } - return buff; - } - - function leBuff2int(buff) { - let res = BigInt(0); - let i = 0; - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - while (i < buff.length) { - if (i + 4 <= buff.length) { - res += BigInt(buffV.getUint32(i, true)) << BigInt(i * 8); - i += 4; - } else if (i + 2 <= buff.length) { - res += BigInt(buffV.getUint16(i, true)) << BigInt(i * 8); - i += 2; - } else { - res += BigInt(buffV.getUint8(i, true)) << BigInt(i * 8); - i += 1; - } - } - return res; - } - - function leInt2Buff(n, len) { - let r = n; - if (typeof len === "undefined") { - len = Math.floor((bitLength(n) - 1) / 8) + 1; - if (len == 0) len = 1; - } - const buff = new Uint8Array(len); - const buffV = new DataView(buff.buffer); - let o = 0; - while (o < len) { - if (o + 4 <= len) { - buffV.setUint32(o, Number(r & BigInt(0xffffffff)), true); - o += 4; - r = r >> BigInt(32); - } else if (o + 2 <= len) { - buffV.setUint16(o, Number(r & BigInt(0xffff)), true); - o += 2; - r = r >> BigInt(16); - } else { - buffV.setUint8(o, Number(r & BigInt(0xff)), true); - o += 1; - r = r >> BigInt(8); - } - } - if (r) { - throw new Error("Number does not fit in this length"); - } - return buff; - } - - function stringifyFElements(F, o) { - if (typeof o == "bigint" || o.eq !== undefined) { - return o.toString(10); - } else if (o instanceof Uint8Array) { - return F.toString(F.e(o)); - } else if (Array.isArray(o)) { - return o.map(stringifyFElements.bind(this, F)); - } else if (typeof o == "object") { - const res = {}; - const keys = Object.keys(o); - keys.forEach((k) => { - res[k] = stringifyFElements(F, o[k]); - }); - return res; - } else { - return o; - } - } - - function unstringifyFElements(F, o) { - if (typeof o == "string" && /^[0-9]+$/.test(o)) { - return F.e(o); - } else if (typeof o == "string" && /^0x[0-9a-fA-F]+$/.test(o)) { - return F.e(o); - } else if (Array.isArray(o)) { - return o.map(unstringifyFElements.bind(this, F)); - } else if (typeof o == "object") { - if (o === null) return null; - const res = {}; - const keys = Object.keys(o); - keys.forEach((k) => { - res[k] = unstringifyFElements(F, o[k]); - }); - return res; - } else { - return o; - } - } - - const _revTable = []; - for (let i = 0; i < 256; i++) { - _revTable[i] = _revSlow(i, 8); - } - - function _revSlow(idx, bits) { - let res = 0; - let a = idx; - for (let i = 0; i < bits; i++) { - res <<= 1; - res = res | (a & 1); - a >>= 1; - } - return res; - } - - function bitReverse(idx, bits) { - return ( - (_revTable[idx >>> 24] | - (_revTable[(idx >>> 16) & 0xff] << 8) | - (_revTable[(idx >>> 8) & 0xff] << 16) | - (_revTable[idx & 0xff] << 24)) >>> - (32 - bits) - ); - } - - function log2$2(V) { - return ( - ((V & 0xffff0000) !== 0 ? ((V &= 0xffff0000), 16) : 0) | - ((V & 0xff00ff00) !== 0 ? ((V &= 0xff00ff00), 8) : 0) | - ((V & 0xf0f0f0f0) !== 0 ? ((V &= 0xf0f0f0f0), 4) : 0) | - ((V & 0xcccccccc) !== 0 ? ((V &= 0xcccccccc), 2) : 0) | - ((V & 0xaaaaaaaa) !== 0) - ); - } - - function buffReverseBits(buff, eSize) { - const n = buff.byteLength / eSize; - const bits = log2$2(n); - if (n != 1 << bits) { - throw new Error("Invalid number of pointers"); - } - for (let i = 0; i < n; i++) { - const r = bitReverse(i, bits); - if (i > r) { - const tmp = buff.slice(i * eSize, (i + 1) * eSize); - buff.set(buff.slice(r * eSize, (r + 1) * eSize), i * eSize); - buff.set(tmp, r * eSize); - } - } - } - - function array2buffer(arr, sG) { - const buff = new Uint8Array(sG * arr.length); - - for (let i = 0; i < arr.length; i++) { - buff.set(arr[i], i * sG); - } - - return buff; - } - - function buffer2array(buff, sG) { - const n = buff.byteLength / sG; - const arr = new Array(n); - for (let i = 0; i < n; i++) { - arr[i] = buff.slice(i * sG, i * sG + sG); - } - return arr; - } - - var _utils = /*#__PURE__*/Object.freeze({ - __proto__: null, - array2buffer: array2buffer, - beBuff2int: beBuff2int, - beInt2Buff: beInt2Buff, - bitReverse: bitReverse, - buffReverseBits: buffReverseBits, - buffer2array: buffer2array, - leBuff2int: leBuff2int, - leInt2Buff: leInt2Buff, - log2: log2$2, - stringifyBigInts: stringifyBigInts$5, - stringifyFElements: stringifyFElements, - unstringifyBigInts: unstringifyBigInts$c, - unstringifyFElements: unstringifyFElements - }); - - // 1 GiB page size: a deliberately conservative, fragmentation-friendly page -- not - // the engine's max single-buffer length (~8 GiB+), which would defeat paging and - // risk OOM on the multi-GiB G1/G2 buffers large circuits produce. - const PAGE_SIZE$3 = 1 << 30; - - class BigBuffer { - - constructor(size) { - this.buffers = []; - this.byteLength = size; - for (let i=0; i0) { - // bytes to copy from this page - const l = (o+r > PAGE_SIZE$3) ? (PAGE_SIZE$3 -o) : r; - const srcView = new Uint8Array(this.buffers[p].buffer, this.buffers[p].byteOffset+o, l); - if (l == len) return srcView.slice(); - if (!buff) { - if (len <= PAGE_SIZE$3) { - buff = new Uint8Array(len); - } else { - buff = new BigBuffer(len); - } - } - buff.set(srcView, len-r); - r = r-l; - p ++; - o = 0; - } - - return buff; - } - - set(buff, offset) { - if (offset === undefined) offset = 0; - - const len = buff.byteLength; - - if (len==0) return; - - const firstPage = Math.floor(offset / PAGE_SIZE$3); - const lastPage = Math.floor((offset+len-1) / PAGE_SIZE$3); - - if (firstPage == lastPage) { - if ((buff instanceof BigBuffer)&&(buff.buffers.length==1)) { - return this.buffers[firstPage].set(buff.buffers[0], offset % PAGE_SIZE$3); - } else { - return this.buffers[firstPage].set(buff, offset % PAGE_SIZE$3); - } - - } - - - let p = firstPage; - let o = offset % PAGE_SIZE$3; - let r = len; - while (r>0) { - const l = (o+r > PAGE_SIZE$3) ? (PAGE_SIZE$3 -o) : r; - const srcView = buff.slice( len -r, len -r+l); - const dstView = new Uint8Array(this.buffers[p].buffer, this.buffers[p].byteOffset + o, l); - dstView.set(srcView); - r = r-l; - p ++; - o = 0; - } - - } - } - - function buildBatchConvert(tm, fnName, sIn, sOut) { - return async function batchConvert(buffIn) { - const nPoints = Math.floor(buffIn.byteLength / sIn); - if ( nPoints * sIn !== buffIn.byteLength) { - throw new Error("Invalid buffer size"); - } - const pointsPerChunk = Math.floor(nPoints/tm.concurrency); - const opPromises = []; - for (let i=0; i=0; i--) { - this.w[i] = this.square(this.w[i+1]); - } - - if (!this.eq(this.w[0], this.one)) { - throw new Error("Error calculating roots of unity"); - } - - this.batchToMontgomery = buildBatchConvert(tm, prefix + "_batchToMontgomery", this.n8, this.n8); - this.batchFromMontgomery = buildBatchConvert(tm, prefix + "_batchFromMontgomery", this.n8, this.n8); - } - - - op2(opName, a, b) { - this.tm.setBuff(this.pOp1, a); - this.tm.setBuff(this.pOp2, b); - this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2, this.pOp3); - return this.tm.getBuff(this.pOp3, this.n8); - } - - op2Bool(opName, a, b) { - this.tm.setBuff(this.pOp1, a); - this.tm.setBuff(this.pOp2, b); - return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2); - } - - op1(opName, a) { - this.tm.setBuff(this.pOp1, a); - this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3); - return this.tm.getBuff(this.pOp3, this.n8); - } - - op1Bool(opName, a) { - this.tm.setBuff(this.pOp1, a); - return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3); - } - - add(a,b) { - return this.op2("_add", a, b); - } - - - eq(a,b) { - return this.op2Bool("_eq", a, b); - } - - isZero(a) { - return this.op1Bool("_isZero", a); - } - - sub(a,b) { - return this.op2("_sub", a, b); - } - - neg(a) { - return this.op1("_neg", a); - } - - inv(a) { - return this.op1("_inverse", a); - } - - toMontgomery(a) { - return this.op1("_toMontgomery", a); - } - - fromMontgomery(a) { - return this.op1("_fromMontgomery", a); - } - - mul(a,b) { - return this.op2("_mul", a, b); - } - - div(a, b) { - this.tm.setBuff(this.pOp1, a); - this.tm.setBuff(this.pOp2, b); - this.tm.instance.exports[this.prefix + "_inverse"](this.pOp2, this.pOp2); - this.tm.instance.exports[this.prefix + "_mul"](this.pOp1, this.pOp2, this.pOp3); - return this.tm.getBuff(this.pOp3, this.n8); - } - - square(a) { - return this.op1("_square", a); - } - - isSquare(a) { - return this.op1Bool("_isSquare", a); - } - - sqrt(a) { - return this.op1("_sqrt", a); - } - - exp(a, b) { - if (!(b instanceof Uint8Array)) { - b = toLEBuff(e(b)); - } - this.tm.setBuff(this.pOp1, a); - this.tm.setBuff(this.pOp2, b); - this.tm.instance.exports[this.prefix + "_exp"](this.pOp1, this.pOp2, b.byteLength, this.pOp3); - return this.tm.getBuff(this.pOp3, this.n8); - } - - isNegative(a) { - return this.op1Bool("_isNegative", a); - } - - e(a, b) { - if (a instanceof Uint8Array) return a; - let ra = e(a, b); - if (isNegative(ra)) { - ra = neg(ra); - if (gt(ra, this.p)) { - ra = mod(ra, this.p); - } - ra = sub(this.p, ra); - } else { - if (gt(ra, this.p)) { - ra = mod(ra, this.p); - } - } - const buff = leInt2Buff(ra, this.n8); - return this.toMontgomery(buff); - } - - toString(a, radix) { - const an = this.fromMontgomery(a); - const s = fromRprLE(an, 0); - return toString(s, radix); - } - - fromRng(rng) { - let v; - const buff = new Uint8Array(this.n8); - do { - v = zero; - for (let i=0; i (await WebAssembly.instantiate(batchModule, { - env: { "memory": memory }, - curve: { - f_mul: ex[f + "_mul"], f_square: ex[f + "_square"], f_add: ex[f + "_add"], - f_sub: ex[f + "_sub"], f_neg: ex[f + "_neg"], f_inverse: ex[f + "_inverse"], - f_isZero: ex[f + "_isZero"], f_conj: ex[conj], - g_add: ex[g + "_add"], g_addMixed: ex[g + "_addMixed"], - g_double: ex[g + "_double"], g_zero: ex[g + "_zero"], g_isZero: ex[g + "_isZero"], - }, - })).exports; - const n8f = data.n8f; - batchFns = {}; - if (ex.f1m_mul && ex.g1m_addMixed) { - // f_conj is only used by the G2 GLS path; wire a harmless copy for G1 - const b = await mkBatch("f1m", "g1m", "f1m_copy"); - // GLV path (bn254 G1 endomorphism) when the curve advertises it; - // the wasm falls back internally for unexpected sizes. - const useGlv = data.glv && b.multiexpAffineGLV; - const fn = useGlv ? b.multiexpAffineGLV : b.multiexpAffine; - batchFns["g1m_multiexpAffineBatch"] = (pB, pS, sS, n, pr) => fn(pB, pS, sS, n, pr, n8f); - // NoGlv variant, selectable per call ({glv: "disabled"} option) - batchFns["g1m_multiexpAffineBatchNoGlv"] = (pB, pS, sS, n, pr) => b.multiexpAffine(pB, pS, sS, n, pr, n8f); - } - if (ex.f2m_mul && ex.g2m_addMixed) { - const b = await mkBatch("f2m", "g2m", "f2m_conjugate"); - // GLS (bn254 G2 endomorphism) when the curve advertises it; the - // wasm gates internally on chunk size and falls back to batch. - // The NoGls variant is selectable per call ({gls:false} option). - const useGls = data.glv && b.multiexpAffineGLS; - const fn2 = useGls ? b.multiexpAffineGLS : b.multiexpAffine; - batchFns["g2m_multiexpAffineBatch"] = (pB, pS, sS, n, pr) => fn2(pB, pS, sS, n, pr, n8f * 2); - batchFns["g2m_multiexpAffineBatchNoGls"] = (pB, pS, sS, n, pr) => b.multiexpAffine(pB, pS, sS, n, pr, n8f * 2); - } - } - } - - - - // Reverse the low `bits` of a 32-bit integer (O(1) bit-twiddle). - function rev32(x) { - x = ((x & 0x55555555) << 1) | ((x >>> 1) & 0x55555555); - x = ((x & 0x33333333) << 2) | ((x >>> 2) & 0x33333333); - x = ((x & 0x0f0f0f0f) << 4) | ((x >>> 4) & 0x0f0f0f0f); - x = ((x & 0x00ff00ff) << 8) | ((x >>> 8) & 0x00ff00ff); - x = (x << 16) | (x >>> 16); - return x >>> 0; - } - - // In-place bit-reversal permutation of fixed-size (sIn-byte) elements. - // Works for any element size, like the old pure-JS buffReverseBits. When - // the elements are 4-byte aligned it swaps Uint32Array lanes (no BigInt - // boxing, no allocation); otherwise it falls back to a byte-wise swap with - // a single reused temp buffer. Either way it touches no WASM linear memory. - function reverseInPlace(u8, sIn, bits) { - const n = u8.byteLength / sIn; - const shift = 32 - bits; - if (((sIn & 3) === 0) && ((u8.byteOffset & 3) === 0)) { - const lanes = sIn >>> 2; - const u32 = new Uint32Array(u8.buffer, u8.byteOffset, u8.byteLength >>> 2); - for (let i = 0; i < n; i++) { - const ri = rev32(i) >>> shift; - if (i < ri) { - let a = i * lanes; - let b = ri * lanes; - for (let l = 0; l < lanes; l++) { - const t = u32[a + l]; - u32[a + l] = u32[b + l]; - u32[b + l] = t; - } - } - } - } else { - const tmp = new Uint8Array(sIn); // one reused temp, not one per swap - for (let i = 0; i < n; i++) { - const ri = rev32(i) >>> shift; - if (i < ri) { - const ao = i * sIn; - const bo = ri * sIn; - tmp.set(u8.subarray(ao, ao + sIn)); - u8.copyWithin(ao, bo, bo + sIn); - u8.set(tmp, bo); - } - } - } - } - - function alloc(length) { - const u32 = new Uint32Array(memory.buffer, 0, 1); - while (u32[0] & 3) u32[0]++; // Return always aligned pointers - const res = u32[0]; - u32[0] += length; - if (u32[0] + length > memory.buffer.byteLength) { - const currentPages = memory.buffer.byteLength / 0x10000; - let requiredPages = Math.floor((u32[0] + length) / 0x10000)+1; - if (requiredPages>MAXMEM) requiredPages=MAXMEM; - memory.grow(requiredPages-currentPages); - } - return res; - } - - function allocBuffer(buffer) { - const p = alloc(buffer.byteLength); - setBuffer(p, buffer); - return p; - } - - function getBuffer(pointer, length) { - return new Uint8Array(memory.buffer, pointer, length); - } - - function setBuffer(pointer, buffer) { - const u8 = new Uint8Array(memory.buffer); - u8.set(new Uint8Array(buffer), pointer); - } - - function runTask(task) { - clearTimeout(terminationTimer); - if (task[0].cmd === "INIT") { - return init(task[0]); - } - const ctx = { - vars: [], - out: [] - }; - const u32a = new Uint32Array(memory.buffer, 0, 1); - const oldAlloc = u32a[0]; - for (let i=0; i plain - // in-module variant when the batch module is unavailable - // (same 5-arg signature) - if (!fn) { - const base = fname.replace(/Batch(NoGls|NoGlv)?$/, ""); - fn = instance.exports[base]; - } - } - fn(...params); - } - break; - } - case "GET": - ctx.out[task[i].out] = getBuffer(ctx.vars[task[i].var], task[i].len).slice(); - break; - default: - throw new Error("Invalid cmd"); - } - } - const u32b = new Uint32Array(memory.buffer, 0, 1); - u32b[0] = oldAlloc; - - return ctx.out; - } - - return runTask; - } - - /* - Copyright 2019 0KIMS association. - - This file is part of wasmsnark (Web Assembly zkSnark Prover). - - wasmsnark is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - wasmsnark is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with wasmsnark. If not, see . - */ - - // const MEM_SIZE = 1000; // Memory size in 64K Pakes (512Mb) - const MEM_SIZE = 25; // Memory size in 64K Pakes (1600Kb) - - // Robust Node detection that never throws (unlike `true`, which is a - // webpack-ism and is undefined under Vite/esbuild/SES). - const isNode$1 = typeof process !== "undefined" && process.versions != null && process.versions.node != null; - - class Deferred { - constructor() { - this.promise = new Promise((resolve, reject)=> { - this.reject = reject; - this.resolve = resolve; - }); - } - } - - // WorkerSlot holds the native Worker and all per-worker state. - // Each call to startWorker() creates a fresh WorkerSlot instance. - // Message handlers close over the slot reference so that stale messages - // from a replaced worker are detected by a simple identity check - // (tm.pool[i] !== slot). - class WorkerSlot { - constructor(worker) { - this.worker = worker; // native Worker thread - this.initialized = false; - this.initializing= false; - this.working = false; - this.pendingDeferred = null; - this.onMsg = null; // stored so removeEventListener can be called on termination - this.onError = null; - } - } - - // Computed lazily on first worker creation, NOT at module load: a SES - // hardened realm (which runs single-threaded) has no Blob/btoa/URL.createObjectURL, and - // touching them at import time would throw before a curve could even be built. - let workerSource; - function getWorkerSource() { - if (workerSource !== undefined) return workerSource; - const threadStr = `(${"function thread(self) {\n const MAXMEM = 32767;\n let instance;\n let memory;\n let batchFns = null; // batch-affine MSM entry points (per-group wrappers)\n let terminationTimeout = 1500; // milliseconds\n let terminationTimer;\n\n if (self) {\n self.onmessage = function(e) {\n let data;\n if (e.data) {\n data = e.data;\n } else {\n data = e;\n }\n\n try {\n if (data[0].cmd === \"INIT\") {\n init(data[0]).then(function() {\n self.postMessage({status: \"initialized\"});\n // Start idle timer only after init completes so it never\n // fires during async WASM compilation.\n scheduleTermination();\n });\n return; // skip the scheduleTermination() call at the bottom\n } else if (data[0].cmd === \"TERMINATE\") {\n terminate();\n } else {\n let terminateAfterTask = false;\n if (data[data.length-1].cmd === \"TERMINATE\") {\n terminateAfterTask = true;\n data.pop();\n }\n const res = runTask(data);\n let transfers = [];\n for (let i=0; i (await WebAssembly.instantiate(batchModule, {\n env: { \"memory\": memory },\n curve: {\n f_mul: ex[f + \"_mul\"], f_square: ex[f + \"_square\"], f_add: ex[f + \"_add\"],\n f_sub: ex[f + \"_sub\"], f_neg: ex[f + \"_neg\"], f_inverse: ex[f + \"_inverse\"],\n f_isZero: ex[f + \"_isZero\"], f_conj: ex[conj],\n g_add: ex[g + \"_add\"], g_addMixed: ex[g + \"_addMixed\"],\n g_double: ex[g + \"_double\"], g_zero: ex[g + \"_zero\"], g_isZero: ex[g + \"_isZero\"],\n },\n })).exports;\n const n8f = data.n8f;\n batchFns = {};\n if (ex.f1m_mul && ex.g1m_addMixed) {\n // f_conj is only used by the G2 GLS path; wire a harmless copy for G1\n const b = await mkBatch(\"f1m\", \"g1m\", \"f1m_copy\");\n // GLV path (bn254 G1 endomorphism) when the curve advertises it;\n // the wasm falls back internally for unexpected sizes.\n const useGlv = data.glv && b.multiexpAffineGLV;\n const fn = useGlv ? b.multiexpAffineGLV : b.multiexpAffine;\n batchFns[\"g1m_multiexpAffineBatch\"] = (pB, pS, sS, n, pr) => fn(pB, pS, sS, n, pr, n8f);\n // NoGlv variant, selectable per call ({glv: \"disabled\"} option)\n batchFns[\"g1m_multiexpAffineBatchNoGlv\"] = (pB, pS, sS, n, pr) => b.multiexpAffine(pB, pS, sS, n, pr, n8f);\n }\n if (ex.f2m_mul && ex.g2m_addMixed) {\n const b = await mkBatch(\"f2m\", \"g2m\", \"f2m_conjugate\");\n // GLS (bn254 G2 endomorphism) when the curve advertises it; the\n // wasm gates internally on chunk size and falls back to batch.\n // The NoGls variant is selectable per call ({gls:false} option).\n const useGls = data.glv && b.multiexpAffineGLS;\n const fn2 = useGls ? b.multiexpAffineGLS : b.multiexpAffine;\n batchFns[\"g2m_multiexpAffineBatch\"] = (pB, pS, sS, n, pr) => fn2(pB, pS, sS, n, pr, n8f * 2);\n batchFns[\"g2m_multiexpAffineBatchNoGls\"] = (pB, pS, sS, n, pr) => b.multiexpAffine(pB, pS, sS, n, pr, n8f * 2);\n }\n }\n\n if (data.terminationTimeout) {\n terminationTimeout = data.terminationTimeout;\n }\n }\n\n\n\n // Reverse the low `bits` of a 32-bit integer (O(1) bit-twiddle).\n function rev32(x) {\n x = ((x & 0x55555555) << 1) | ((x >>> 1) & 0x55555555);\n x = ((x & 0x33333333) << 2) | ((x >>> 2) & 0x33333333);\n x = ((x & 0x0f0f0f0f) << 4) | ((x >>> 4) & 0x0f0f0f0f);\n x = ((x & 0x00ff00ff) << 8) | ((x >>> 8) & 0x00ff00ff);\n x = (x << 16) | (x >>> 16);\n return x >>> 0;\n }\n\n // In-place bit-reversal permutation of fixed-size (sIn-byte) elements.\n // Works for any element size, like the old pure-JS buffReverseBits. When\n // the elements are 4-byte aligned it swaps Uint32Array lanes (no BigInt\n // boxing, no allocation); otherwise it falls back to a byte-wise swap with\n // a single reused temp buffer. Either way it touches no WASM linear memory.\n function reverseInPlace(u8, sIn, bits) {\n const n = u8.byteLength / sIn;\n const shift = 32 - bits;\n if (((sIn & 3) === 0) && ((u8.byteOffset & 3) === 0)) {\n const lanes = sIn >>> 2;\n const u32 = new Uint32Array(u8.buffer, u8.byteOffset, u8.byteLength >>> 2);\n for (let i = 0; i < n; i++) {\n const ri = rev32(i) >>> shift;\n if (i < ri) {\n let a = i * lanes;\n let b = ri * lanes;\n for (let l = 0; l < lanes; l++) {\n const t = u32[a + l];\n u32[a + l] = u32[b + l];\n u32[b + l] = t;\n }\n }\n }\n } else {\n const tmp = new Uint8Array(sIn); // one reused temp, not one per swap\n for (let i = 0; i < n; i++) {\n const ri = rev32(i) >>> shift;\n if (i < ri) {\n const ao = i * sIn;\n const bo = ri * sIn;\n tmp.set(u8.subarray(ao, ao + sIn));\n u8.copyWithin(ao, bo, bo + sIn);\n u8.set(tmp, bo);\n }\n }\n }\n }\n\n function alloc(length) {\n const u32 = new Uint32Array(memory.buffer, 0, 1);\n while (u32[0] & 3) u32[0]++; // Return always aligned pointers\n const res = u32[0];\n u32[0] += length;\n if (u32[0] + length > memory.buffer.byteLength) {\n const currentPages = memory.buffer.byteLength / 0x10000;\n let requiredPages = Math.floor((u32[0] + length) / 0x10000)+1;\n if (requiredPages>MAXMEM) requiredPages=MAXMEM;\n memory.grow(requiredPages-currentPages);\n }\n return res;\n }\n\n function allocBuffer(buffer) {\n const p = alloc(buffer.byteLength);\n setBuffer(p, buffer);\n return p;\n }\n\n function getBuffer(pointer, length) {\n return new Uint8Array(memory.buffer, pointer, length);\n }\n\n function setBuffer(pointer, buffer) {\n const u8 = new Uint8Array(memory.buffer);\n u8.set(new Uint8Array(buffer), pointer);\n }\n\n function runTask(task) {\n clearTimeout(terminationTimer);\n if (task[0].cmd === \"INIT\") {\n return init(task[0]);\n }\n const ctx = {\n vars: [],\n out: []\n };\n const u32a = new Uint32Array(memory.buffer, 0, 1);\n const oldAlloc = u32a[0];\n for (let i=0; i plain\n // in-module variant when the batch module is unavailable\n // (same 5-arg signature)\n if (!fn) {\n const base = fname.replace(/Batch(NoGls|NoGlv)?$/, \"\");\n fn = instance.exports[base];\n }\n }\n fn(...params);\n }\n break;\n }\n case \"GET\":\n ctx.out[task[i].out] = getBuffer(ctx.vars[task[i].var], task[i].len).slice();\n break;\n default:\n throw new Error(\"Invalid cmd\");\n }\n }\n const u32b = new Uint32Array(memory.buffer, 0, 1);\n u32b[0] = oldAlloc;\n\n return ctx.out;\n }\n\n function scheduleTermination() {\n clearTimeout(terminationTimer);\n if (terminationTimeout > 0) {\n terminationTimer = setTimeout(() => {\n // 2-phase termination: notify main thread first; close only after\n // it acks with TERMINATE. This prevents the race where the main\n // thread dispatches a task to a worker that has already closed.\n if (self) self.postMessage({status: \"want_to_terminate\"});\n }, terminationTimeout);\n }\n }\n\n function terminate() {\n clearTimeout(terminationTimer);\n if (self) {\n self.postMessage({status: \"terminated\"});\n self.close();\n }\n }\n\n return runTask;\n}"})(self)`; - if (isNode$1) { - workerSource = "data:application/javascript;base64," + Buffer.from(threadStr).toString("base64"); - } else if (globalThis?.Blob && globalThis.URL && globalThis.URL.createObjectURL) { - const threadBytes = new TextEncoder().encode(threadStr); - const workerBlob = new Blob([threadBytes], { type: "application/javascript" }); - workerSource = URL.createObjectURL(workerBlob); - } else { - workerSource = "data:application/javascript;base64," + globalThis.btoa(threadStr); - } - return workerSource; - } - - - - async function buildThreadManager(wasm, singleThread) { - const tm = new ThreadManager(); - - tm.memory = new WebAssembly.Memory({initial:MEM_SIZE}); - tm.u8 = new Uint8Array(tm.memory.buffer); - tm.u32 = new Uint32Array(tm.memory.buffer); - - const wasmModule = await WebAssembly.compile(wasm.code); - - tm.instance = await WebAssembly.instantiate(wasmModule, { - env: { - "memory": tm.memory - } - }); - - // Force single-thread when no Worker is available. Covers SES hardened realms - // (no Worker, frozen globals) and old/limited browsers, regardless of what - // the caller requested -- the worker path (and getWorkerSource's - // Blob/btoa) would otherwise fail. Node uses the web-worker import, so it - // keeps multi-threading. - if(!isNode$1 && !globalThis?.Worker) { - singleThread = true; - } - - tm.singleThread = singleThread; - tm.initalPFree = tm.u32[0]; // Save the Pointer to free space. - tm.pq = wasm.pq; - tm.pr = wasm.pr; - tm.pG1gen = wasm.pG1gen; - tm.pG1zero = wasm.pG1zero; - tm.pG2gen = wasm.pG2gen; - tm.pG2zero = wasm.pG2zero; - tm.pOneT = wasm.pOneT; - - tm.code = wasm.code; - tm.wasmModule = wasmModule; - // Batch-affine MSM helper module (optional): compiled once, shipped to every - // worker alongside the main module. n8f = base-field element size in bytes. - tm.batchCode = wasm.batchCode; - tm.batchWasmModule = wasm.batchCode ? await WebAssembly.compile(wasm.batchCode) : undefined; - tm.n8f = wasm.n8q; - tm.glv = !!wasm.glv; - - if (singleThread) { - tm.taskManager = thread(); - await tm.taskManager([{ - cmd: "INIT", - init: MEM_SIZE, - code: tm.code.slice(), - batchCode: tm.batchCode ? tm.batchCode.slice() : undefined, - n8f: tm.n8f, - glv: tm.glv - }]); - tm.concurrency = 1; - } else { - // pool[i] is the active WorkerSlot at slot i, or null if the slot is empty. - tm.pool = []; - - let concurrency = 2; - if (typeof navigator === "object" && navigator.hardwareConcurrency) { - concurrency = navigator.hardwareConcurrency; - } else if (os && os.cpus) { - concurrency = os.cpus().length; - } - - if(concurrency === 0){ - concurrency = 2; - } - - // Limit to 64 threads for memory reasons. - if (concurrency>64) concurrency=64; - tm.concurrency = concurrency; - } - return tm; - } - - class ThreadManager { - constructor() { - this.actionQueue = []; - this.oldPFree = 0; - } - - // Build the message handler for a specific WorkerSlot. - // All state reads/writes go through `slot`; the stale check - // `tm.pool[slotIndex] !== slot` discards messages from replaced workers. - _makeOnMsg(slotIndex, slot) { - const tm = this; - return async function(e) { - const data = (e && e.data) ? e.data : e; - - // Stale check: if pool[slotIndex] no longer points to this slot, - // the message is from a worker that was already replaced. - if (tm.pool[slotIndex] !== slot) { - if (data.status === "terminated") { - // Break the reference cycle so the slot and its WASM memory - // can be collected immediately rather than waiting for GC. - slot.worker.removeEventListener("message", slot.onMsg); - slot.worker.removeEventListener("error", slot.onError); - return; - } - if (!data.status && slot.working) { - // Stale task result: the slot was replaced (want_to_terminate raced - // with a task dispatch — pool[i] was nulled before the result came - // back). The result is still valid; resolve so the caller doesn't hang. - slot.working = false; - slot.pendingDeferred.resolve(data); - } - await tm.processWorks(); - return; - } - - if (data.error) { - slot.working = false; - slot.pendingDeferred.reject(new Error("Worker error: " + data.error)); - if (slot.initializing) { - slot.initializing = false; - tm.pool[slotIndex] = null; - } - throw new Error("Worker error: " + data.error); - } - - if (data.status) { - if (data.status === "initialized") { - slot.initializing = false; - slot.initialized = true; - - } else if (data.status === "want_to_terminate") { - // 2-phase termination: the worker is idle and asking to close. - // Release the slot immediately so processWorks can fill it with a - // fresh worker if the queue needs one. The TERMINATE ack is sent - // to the old worker so it can close cleanly; its later "terminated" - // message will be stale (pool[slotIndex] !== slot) and ignored. - tm.pool[slotIndex] = null; - slot.worker.postMessage([{cmd: "TERMINATE"}]); - await tm.processWorks(); - return; - - } else if (data.status === "terminated") { - // Worker has fully closed. For the 2-phase path the slot was - // already nulled in want_to_terminate, so this message arrives - // stale and is handled above. For a direct TERMINATE - // (tm.terminate() at proof end) we clean up here. - slot.worker.removeEventListener("message", slot.onMsg); - slot.worker.removeEventListener("error", slot.onError); - tm.pool[slotIndex] = null; - if (slot.working) { - // Safety net: reject the pending deferred so the caller - // surfaces an error instead of hanging. - slot.pendingDeferred.reject( - new Error(`Worker at slot ${slotIndex} terminated unexpectedly while processing task`) - ); - slot.working = false; - } - return; - } - // fall through for "initialized" so the INIT deferred is resolved below - } - - slot.working = false; - slot.pendingDeferred.resolve(data); - await tm.processWorks(); - }; - } - - _makeOnError(slotIndex, slot) { - const tm = this; - return function(e) { - if (tm.pool[slotIndex] === slot) { - slot.working = false; - slot.initialized = false; - if (slot.pendingDeferred) { - slot.pendingDeferred.reject(new Error("Worker error: " + e.message)); - } - } - throw new Error("Worker error: " + e.message); - }; - } - - startWorker(slotIndex) { - const nativeWorker = new Worker(getWorkerSource()); - const slot = new WorkerSlot(nativeWorker); - this.pool[slotIndex] = slot; - - slot.onMsg = this._makeOnMsg(slotIndex, slot); - slot.onError = this._makeOnError(slotIndex, slot); - nativeWorker.addEventListener("message", slot.onMsg); - nativeWorker.addEventListener("error", slot.onError); - - slot.initializing = true; - - // postAction sets slot.working = true synchronously before any await, - // so processWorks will not attempt to start this slot again. - this.postAction(slotIndex, [{ - cmd: "INIT", - init: MEM_SIZE, - code: this.wasmModule, - batchCode: this.batchWasmModule, - n8f: this.n8f, - glv: this.glv, - }]).then(() => { - slot.initialized = true; - }); - } - - startSyncOp() { - if (this.oldPFree !== 0) throw new Error("Sync operation in progress"); - this.oldPFree = this.u32[0]; - } - - endSyncOp() { - if (this.oldPFree === 0) throw new Error("No sync operation in progress"); - this.u32[0] = this.oldPFree; - this.oldPFree = 0; - } - - async postAction(slotIndex, e, transfers, _deferred) { - const slot = this.pool[slotIndex]; - if (!slot || slot.working) { - throw new Error("Posting a job to a working worker"); - } - slot.working = true; - slot.pendingDeferred = _deferred ? _deferred : new Deferred(); - await slot.worker.postMessage(e, transfers); - return slot.pendingDeferred.promise; - } - - async processWorks() { - // Dispatch queued tasks to ready workers. - for (let i = 0; i < this.concurrency && this.actionQueue.length > 0; i++) { - const slot = this.pool[i]; - if (slot && slot.initialized && !slot.working) { - const work = this.actionQueue.shift(); - await this.postAction(i, work.data, work.transfers, work.deferred); - } - } - - // Start new workers for slots that need them. - if (this.actionQueue.length > 0) { - let initializingCount = 0; - for (let i = 0; i < this.concurrency; i++) { - const slot = this.pool[i]; - if (slot) { - if (slot.initializing) initializingCount++; - // slot exists: skip whether initialized, initializing, or working - continue; - } - // slot is null: this slot is available to host a new worker - if (initializingCount >= this.actionQueue.length) break; - initializingCount++; - this.startWorker(i); - } - } - } - - async queueAction(actionData, transfers) { - const d = new Deferred(); - - if (this.singleThread) { - const res = this.taskManager(actionData); - d.resolve(res); - } else { - this.actionQueue.push({ - data: actionData, - transfers: transfers, - deferred: d - }); - await this.processWorks(); - } - return d.promise; - } - - resetMemory() { - this.u32[0] = this.initalPFree; - } - - allocBuff(buff) { - const pointer = this.alloc(buff.byteLength); - this.setBuff(pointer, buff); - return pointer; - } - - getBuff(pointer, length) { - return this.u8.slice(pointer, pointer + length); - } - - setBuff(pointer, buffer) { - this.u8.set(new Uint8Array(buffer), pointer); - } - - alloc(length) { - while (this.u32[0] & 3) this.u32[0]++; // Return always aligned pointers - const res = this.u32[0]; - this.u32[0] += length; - return res; - } - - async terminate() { - for (let i = 0; i < this.pool.length; i++) { - if (this.pool[i]) { - this.pool[i].worker.postMessage([{cmd: "TERMINATE"}]); - } - } - } - - } - - function buildBatchApplyKey(curve, groupName) { - const G = curve[groupName]; - const Fr = curve.Fr; - const tm = curve.tm; - - curve[groupName].batchApplyKey = async function(buff, first, inc, inType, outType) { - inType = inType || "affine"; - outType = outType || "affine"; - let fnName, fnAffine; - let sGin, sGmid, sGout; - if (groupName == "G1") { - if (inType == "jacobian") { - sGin = G.F.n8*3; - fnName = "g1m_batchApplyKey"; - } else { - sGin = G.F.n8*2; - fnName = "g1m_batchApplyKeyMixed"; - } - sGmid = G.F.n8*3; - if (outType == "jacobian") { - sGout = G.F.n8*3; - } else { - fnAffine = "g1m_batchToAffine"; - sGout = G.F.n8*2; - } - } else if (groupName == "G2") { - if (inType == "jacobian") { - sGin = G.F.n8*3; - fnName = "g2m_batchApplyKey"; - } else { - sGin = G.F.n8*2; - fnName = "g2m_batchApplyKeyMixed"; - } - sGmid = G.F.n8*3; - if (outType == "jacobian") { - sGout = G.F.n8*3; - } else { - fnAffine = "g2m_batchToAffine"; - sGout = G.F.n8*2; - } - } else if (groupName == "Fr") { - fnName = "frm_batchApplyKey"; - sGin = G.n8; - sGmid = G.n8; - sGout = G.n8; - } else { - throw new Error("Invalid group: " + groupName); - } - const nPoints = Math.floor(buff.byteLength / sGin); - const pointsPerChunk = Math.floor(nPoints/tm.concurrency); - const opPromises = []; - inc = Fr.e(inc); - let t = Fr.e(first); - for (let i=0; i MAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE; - if (chunkSize < MIN_CHUNK_SIZE) chunkSize = MIN_CHUNK_SIZE; - return chunkSize; - } - - // Run the multiexp of one chunk on a worker; returns the partial point. - async function _multiExpChunk(buffBases, buffScalars, inType, batchMode, endoMode, logText) { - if (!(buffBases instanceof Uint8Array)) throw new Error(`${logText} _multiExpChunk buffBases is not Uint8Array`); - if (!(buffScalars instanceof Uint8Array)) throw new Error(`${logText} _multiExpChunk buffScalars is not Uint8Array`); - const sGIn = pointSize(inType); - const nPoints = Math.floor(buffBases.byteLength / sGIn); - if (nPoints === 0) return G.zero; - const sScalar = Math.floor(buffScalars.byteLength / nPoints); - if (sScalar * nPoints !== buffScalars.byteLength) throw new Error(`${logText} Scalar size does not match`); - - const task = [ - {cmd: "ALLOCSET", var: 0, buff: buffBases}, - {cmd: "ALLOCSET", var: 1, buff: buffScalars}, - {cmd: "ALLOC", var: 2, len: G.F.n8*3}, - {cmd: "CALL", fnName: fnNameFor(inType, buffBases.byteLength, batchMode, endoMode), params: [ - {var: 0}, {var: 1}, {val: sScalar}, {val: nPoints}, {var: 2} - ]}, - {cmd: "GET", out: 0, var: 2, len: G.F.n8*3}, - ]; - // transfer the chunk buffers to the worker (zero-copy); one GET -> one point - const out = await tm.queueAction(task, [buffBases.buffer, buffScalars.buffer]); - return out[0]; - } - - // Shared driver. `getChunk(byteOffset, byteLength)` supplies each bases chunk -- - // a synchronous slice of an in-memory buffer, or an async sub-range read. At most - // `maxInFlight` chunks are sourced at once (Infinity = dispatch them all). The - // point set is partitioned across chunks, so the full multiexp is the sum of the - // per-chunk multiexps. - async function _multiExpDispatch(getChunk, buffScalars, nPoints, sGIn, sScalar, inType, maxInFlight, batchMode, endoMode, logger, logText) { - if (nPoints === 0) return G.zero; - const chunkSize = chunkSizeFor(nPoints, sScalar); - const inFlight = new Set(); - const partials = []; - - for (let off = 0; off < nPoints; off += chunkSize) { - const n = Math.min(nPoints - off, chunkSize); - const at = off; - // Backpressure: block until a slot frees (Promise.race also surfaces a - // failed chunk promptly). With maxInFlight = Infinity this never blocks. - while (inFlight.size >= maxInFlight) await Promise.race(inFlight); - if (logger) logger.debug(`Multiexp start: ${logText}: ${at}/${nPoints}`); - const op = (async () => { - const basesChunk = await getChunk(at*sGIn, n*sGIn); - const scalarsChunk = buffScalars.slice(at*sScalar, (at+n)*sScalar); - const r = await _multiExpChunk(basesChunk, scalarsChunk, inType, batchMode, endoMode, logText); - if (logger) logger.debug(`Multiexp end: ${logText}: ${at}/${nPoints}`); - return r; - })(); - // settle-either-way cleanup so a rejected chunk can't wedge the set - const slot = op.finally(() => inFlight.delete(slot)); - inFlight.add(slot); - partials.push(slot); - } - - const result = await Promise.all(partials); - let res = G.zero; - for (let i = result.length-1; i >= 0; i--) res = G.add(res, result[i]); - return res; - } - - // Derive nPoints/sScalar and validate before dispatching. - function geometry(totalBasesBytes, buffScalars, inType) { - const sGIn = pointSize(inType); - const nPoints = Math.floor(totalBasesBytes / sGIn); - let sScalar = 0; - if (nPoints > 0) { - sScalar = Math.floor(buffScalars.byteLength / nPoints); - if (sScalar * nPoints !== buffScalars.byteLength) throw new Error("Scalar size does not match"); - } - return { sGIn, nPoints, sScalar }; - } - - // multiexp over an in-memory bases buffer (sliced per chunk, all dispatched at once). - async function _multiExp(buffBases, buffScalars, inType, batchMode, endoMode, logger, logText) { - const { sGIn, nPoints, sScalar } = geometry(buffBases.byteLength, buffScalars, inType); - const getChunk = (off, len) => buffBases.slice(off, off + len); - return _multiExpDispatch(getChunk, buffScalars, nPoints, sGIn, sScalar, inType, Infinity, batchMode, endoMode, logger, logText); - } - - G.multiExp = async function multiExp(buffBases, buffScalars, logger, logText) { - return _multiExp(buffBases, buffScalars, "jacobian", "disabled", "auto", logger, logText); - }; - // options.batch: "auto" (default) | "enabled" | "disabled" -- see batchModeOf. - // options.glv / options.gls: "auto" (default) | "disabled" -- see endoOf. - G.multiExpAffine = async function multiExpAffine(buffBases, buffScalars, logger, logText, options) { - return _multiExp(buffBases, buffScalars, "affine", batchModeOf(options), endoOf(options), logger, logText); - }; - - // Streaming affine multiexp: bases are produced chunk-by-chunk by `basesReader` - // (e.g. a direct sub-range file read) instead of being read whole and sliced -- - // no main-thread slice copy, and the full section never sits in RAM (reads are - // bounded to a few in-flight chunks). Result is identical to multiExpAffine. - G.multiExpAffineChunked = async function multiExpAffineChunked(basesReader, totalBasesBytes, buffScalars, logger, logText, options) { - if (typeof basesReader !== "function") { - throw new Error(`${logText || "multiExpAffineChunked"}: basesReader must be a function (byteOffset, byteLength) => Promise`); - } - const { sGIn, nPoints, sScalar } = geometry(totalBasesBytes, buffScalars, "affine"); - return _multiExpDispatch(basesReader, buffScalars, nPoints, sGIn, sScalar, "affine", tm.concurrency + 2, batchModeOf(options), endoOf(options), logger, logText); - }; - } - - function buildFFT(curve, groupName) { - const G = curve[groupName]; - const Fr = curve.Fr; - const tm = G.tm; - - // In-place bit-reversal permutation in a worker. The buffer is transferred - // in, reversed where it lies via plain typed-array lane swaps (no WASM - // linear memory grown, nothing allocated), and transferred back. Both - // transfers are pointer moves, so this is zero-copy. The swap is - // memory-bandwidth bound, so a single worker is as fast as splitting across - // many — which is why no SharedArrayBuffer is needed (only concurrent - // multi-worker access to one buffer would require that). - async function _reversePermutation(buff, sIn, bits) { - const res = await tm.queueAction( - [{cmd: "REVERSE", src: buff, sIn, bits}], - [buff.buffer] // transfer in; reversed in place and transferred back - ); - return res[0]; - } - - // `consume`: when true the caller cedes ownership of `buff` -- we skip the - // defensive full-copy below and reverse/transfer the caller's buffer in place - // (its backing ArrayBuffer is detached as a result). Only pass it when the - // input is discarded right after the call (e.g. the groth16 IFFT->applyKey->FFT - // pipeline). Default false preserves the input. - async function _fft(buff, inverse, inType, outType, logger, loggerTxt, consume) { - - inType = inType || "affine"; - outType = outType || "affine"; - const MAX_BITS_THREAD = 14; - - let sIn, sMid, sOut, fnIn2Mid, fnMid2Out, fnFFTMix, fnFFTJoin, fnFFTFinal; - if (groupName == "G1") { - if (inType == "affine") { - sIn = G.F.n8*2; - fnIn2Mid = "g1m_batchToJacobian"; - } else { - sIn = G.F.n8*3; - } - sMid = G.F.n8*3; - if (inverse) { - fnFFTFinal = "g1m_fftFinal"; - } - fnFFTJoin = "g1m_fftJoin"; - fnFFTMix = "g1m_fftMix"; - - if (outType == "affine") { - sOut = G.F.n8*2; - fnMid2Out = "g1m_batchToAffine"; - } else { - sOut = G.F.n8*3; - } - - } else if (groupName == "G2") { - if (inType == "affine") { - sIn = G.F.n8*2; - fnIn2Mid = "g2m_batchToJacobian"; - } else { - sIn = G.F.n8*3; - } - sMid = G.F.n8*3; - if (inverse) { - fnFFTFinal = "g2m_fftFinal"; - } - fnFFTJoin = "g2m_fftJoin"; - fnFFTMix = "g2m_fftMix"; - if (outType == "affine") { - sOut = G.F.n8*2; - fnMid2Out = "g2m_batchToAffine"; - } else { - sOut = G.F.n8*3; - } - } else if (groupName == "Fr") { - sIn = G.n8; - sMid = G.n8; - sOut = G.n8; - if (inverse) { - fnFFTFinal = "frm_fftFinal"; - } - fnFFTMix = "frm_fftMix"; - fnFFTJoin = "frm_fftJoin"; - } - - - let returnArray = false; - if (Array.isArray(buff)) { - buff = array2buffer(buff, sIn); - returnArray = true; - } else if (!consume || !ArrayBuffer.isView(buff)) { - // Defensive copy: the bit-reversal runs in place and chunks are - // transferred, so without consume we must not touch the caller's buffer. - // It also flattens a BigBuffer (no single .buffer to transfer) to a - // Uint8Array, so consume can only be honoured for an ArrayBuffer view. - buff = buff.slice(0, buff.byteLength); - } - - const nPoints = buff.byteLength / sIn; - const bits = log2$2(nPoints); - - if ((1 << bits) != nPoints) { - throw new Error("fft must be multiple of 2" ); - } - - if (bits == Fr.s +1) { - let buffOut; - - if (inverse) { - buffOut = await _fftExtInv(buff, inType, outType, logger, loggerTxt); - } else { - buffOut = await _fftExt(buff, inType, outType, logger, loggerTxt); - } - - if (returnArray) { - return buffer2array(buffOut, sOut); - } else { - return buffOut; - } - } - - let inv; - if (inverse) { - inv = Fr.inv(Fr.e(nPoints)); - } - - let buffOut; - - // Bit-reversal permutation. Like the old pure-JS buffReverseBits, this is - // just a permutation of fixed-size (sIn-byte) elements and works for any - // element size, so it covers Fr, G1 and G2 alike. Reversed in place in a - // worker via typed-array swaps — no WASM linear memory grown, nothing - // allocated. (The previous WASM __reversePermutation swapped n8g-sized - // elements rather than sIn-sized ones, which was wrong whenever - // sIn != n8g, e.g. affine-input G1/G2 FFTs.) - buff = await _reversePermutation(buff, sIn, bits); - - let chunks; - let pointsInChunk = Math.min(1 << MAX_BITS_THREAD, nPoints); - let nChunks = nPoints / pointsInChunk; - - while ((nChunks < tm.concurrency)&&(pointsInChunk>=16)) { - nChunks *= 2; - pointsInChunk /= 2; - } - - const l2Chunk = log2$2(pointsInChunk); - - const promises = []; - if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix start: ${nChunks}`); - for (let i = 0; i< nChunks; i++) { - const task = []; - task.push({cmd: "ALLOC", var: 0, len: sMid*pointsInChunk}); - const buffChunk = buff.slice( (pointsInChunk * i)*sIn, (pointsInChunk * (i+1))*sIn); - task.push({cmd: "SET", var: 0, buff: buffChunk}); - if (fnIn2Mid) { - task.push({cmd: "CALL", fnName:fnIn2Mid, params: [{var:0}, {val: pointsInChunk}, {var: 0}]}); - } - for (let j=1; j<=l2Chunk;j++) { - task.push({cmd: "CALL", fnName:fnFFTMix, params: [{var:0}, {val: pointsInChunk}, {val: j}]}); - } - - if (l2Chunk==bits) { - if (fnFFTFinal) { - task.push({cmd: "ALLOCSET", var: 1, buff: inv}); - task.push({cmd: "CALL", fnName: fnFFTFinal, params:[ - {var: 0}, - {val: pointsInChunk}, - {var: 1}, - ]}); - } - if (fnMid2Out) { - task.push({cmd: "CALL", fnName:fnMid2Out, params: [{var:0}, {val: pointsInChunk}, {var: 0}]}); - } - task.push({cmd: "GET", out: 0, var: 0, len: pointsInChunk*sOut}); - } else { - task.push({cmd: "GET", out:0, var: 0, len: sMid*pointsInChunk}); - } - promises.push(tm.queueAction(task, [buffChunk.buffer])); - } - - chunks = await Promise.all(promises); - if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix end: ${nChunks}`); - for (let i = 0; i< nChunks; i++) chunks[i] = chunks[i][0]; - - for (let i = l2Chunk+1; i<=bits; i++) { - if (logger) logger.debug(`${loggerTxt}: fft ${bits} join: ${i}/${bits}`); - const nGroups = 1 << (bits - i); - const nChunksPerGroup = nChunks / nGroups; - const opPromises = []; - for (let j=0; j0; i--) { - buffOut.set(chunks[i], p); - p += pointsInChunk*sOut; - delete chunks[i]; // Liberate mem - } - buffOut.set(chunks[0].slice(0, (pointsInChunk-1)*sOut), p); - delete chunks[0]; - } else { - for (let i=0; i (1<<28)) { - buffOut = new BigBuffer(res1[0].byteLength*2); - } else { - buffOut = new Uint8Array(res1[0].byteLength*2); - } - - buffOut.set(res1[0]); - buffOut.set(res1[1], res1[0].byteLength); - - return buffOut; - } - - async function _fftExtInv(buff, inType, outType, logger, loggerTxt) { - let b1, b2; - b1 = buff.slice( 0 , buff.byteLength/2); - b2 = buff.slice( buff.byteLength/2, buff.byteLength); - - const promises = []; - - promises.push( _fft(b1, true, inType, "jacobian", logger, loggerTxt)); - promises.push( _fft(b2, true, inType, "jacobian", logger, loggerTxt)); - - [b1, b2] = await Promise.all(promises); - - const res1 = await _fftJoinExt(b1, b2, "fftJoinExtInv", Fr.one, Fr.shiftInv, "jacobian", outType, logger, loggerTxt); - - let buffOut; - if (res1[0].byteLength > (1<<28)) { - buffOut = new BigBuffer(res1[0].byteLength*2); - } else { - buffOut = new Uint8Array(res1[0].byteLength*2); - } - - buffOut.set(res1[0]); - buffOut.set(res1[1], res1[0].byteLength); - - return buffOut; - } - - - async function _fftJoinExt(buff1, buff2, fn, first, inc, inType, outType, logger, loggerTxt) { - const MAX_CHUNK_SIZE = 1<<16; - const MIN_CHUNK_SIZE = 1<<4; - - let fnName; - let fnIn2Mid, fnMid2Out; - let sOut, sIn, sMid; - - if (groupName == "G1") { - if (inType == "affine") { - sIn = G.F.n8*2; - fnIn2Mid = "g1m_batchToJacobian"; - } else { - sIn = G.F.n8*3; - } - sMid = G.F.n8*3; - fnName = "g1m_"+fn; - if (outType == "affine") { - fnMid2Out = "g1m_batchToAffine"; - sOut = G.F.n8*2; - } else { - sOut = G.F.n8*3; - } - } else if (groupName == "G2") { - if (inType == "affine") { - sIn = G.F.n8*2; - fnIn2Mid = "g2m_batchToJacobian"; - } else { - sIn = G.F.n8*3; - } - fnName = "g2m_"+fn; - sMid = G.F.n8*3; - if (outType == "affine") { - fnMid2Out = "g2m_batchToAffine"; - sOut = G.F.n8*2; - } else { - sOut = G.F.n8*3; - } - } else if (groupName == "Fr") { - sIn = Fr.n8; - sOut = Fr.n8; - sMid = Fr.n8; - fnName = "frm_" + fn; - } else { - throw new Error("Invalid group"); - } - - if (buff1.byteLength != buff2.byteLength) { - throw new Error("Invalid buffer size"); - } - const nPoints = Math.floor(buff1.byteLength / sIn); - if (nPoints != 1 << log2$2(nPoints)) { - throw new Error("Invalid number of points"); - } - - let chunkSize = Math.floor(nPoints /tm.concurrency); - if (chunkSize < MIN_CHUNK_SIZE) chunkSize = MIN_CHUNK_SIZE; - if (chunkSize > MAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE; - - const opPromises = []; - - for (let i=0; i { - if (logger) logger.debug(`${loggerTxt}: fftJoinExt End: ${i}/${nPoints}`); - return r; - }) - ); - } - - const result = await Promise.all(opPromises); - - let fullBuffOut1; - let fullBuffOut2; - if (nPoints * sOut > 1<<28) { - fullBuffOut1 = new BigBuffer(nPoints*sOut); - fullBuffOut2 = new BigBuffer(nPoints*sOut); - } else { - fullBuffOut1 = new Uint8Array(nPoints*sOut); - fullBuffOut2 = new Uint8Array(nPoints*sOut); - } - - let p =0; - for (let i=0; i Fr.s+1) { - if (logger) logger.error("lagrangeEvaluations input too big"); - throw new Error("lagrangeEvaluations input too big"); - } - - let t0 = buff.slice(0, buff.byteLength/2); - let t1 = buff.slice(buff.byteLength/2, buff.byteLength); - - - const shiftToSmallM = Fr.exp(Fr.shift, nPoints/2); - const sConst = Fr.inv( Fr.sub(Fr.one, shiftToSmallM)); - - [t0, t1] = await _fftJoinExt(t0, t1, "prepareLagrangeEvaluation", sConst, Fr.shiftInv, inType, "jacobian", logger, loggerTxt + " prep"); - - const promises = []; - - promises.push( _fft(t0, true, "jacobian", outType, logger, loggerTxt + " t0")); - promises.push( _fft(t1, true, "jacobian", outType, logger, loggerTxt + " t1")); - - [t0, t1] = await Promise.all(promises); - - let buffOut; - if (t0.byteLength > (1<<28)) { - buffOut = new BigBuffer(t0.byteLength*2); - } else { - buffOut = new Uint8Array(t0.byteLength*2); - } - - buffOut.set(t0); - buffOut.set(t1, t0.byteLength); - - return buffOut; - }; - - G.fftMix = async function fftMix(buff) { - const sG = G.F.n8*3; - let fnName, fnFFTJoin; - if (groupName == "G1") { - fnName = "g1m_fftMix"; - fnFFTJoin = "g1m_fftJoin"; - } else if (groupName == "G2") { - fnName = "g2m_fftMix"; - fnFFTJoin = "g2m_fftJoin"; - } else if (groupName == "Fr") { - fnName = "frm_fftMix"; - fnFFTJoin = "frm_fftJoin"; - } else { - throw new Error("Invalid group"); - } - - const nPoints = Math.floor(buff.byteLength / sG); - const power = log2$2(nPoints); - - let nChunks = 1 << log2$2(tm.concurrency); - - if (nPoints <= nChunks*2) nChunks = 1; - - const pointsPerChunk = nPoints / nChunks; - - const powerChunk = log2$2(pointsPerChunk); - - const opPromises = []; - for (let i=0; i=0; i--) { - fullBuffOut.set(result[i][0], p); - p+=result[i][0].byteLength; - } - - return fullBuffOut; - }; - } - - async function buildEngine(params) { - - const tm = await buildThreadManager(params.wasm, params.singleThread); - - - const curve = {}; - - curve.q = e(params.wasm.q.toString()); - curve.r = e(params.wasm.r.toString()); - curve.name = params.name; - curve.tm = tm; - curve.prePSize = params.wasm.prePSize; - curve.preQSize = params.wasm.preQSize; - curve.Fr = new WasmField1(tm, "frm", params.n8r, params.r); - curve.F1 = new WasmField1(tm, "f1m", params.n8q, params.q); - curve.F2 = new WasmField2(tm, "f2m", curve.F1); - curve.G1 = new WasmCurve(tm, "g1m", curve.F1, params.wasm.pG1gen, params.wasm.pG1b, params.cofactorG1); - curve.G2 = new WasmCurve(tm, "g2m", curve.F2, params.wasm.pG2gen, params.wasm.pG2b, params.cofactorG2); - curve.F6 = new WasmField3(tm, "f6m", curve.F2); - curve.F12 = new WasmField2(tm, "ftm", curve.F6); - - curve.Gt = curve.F12; - - buildBatchApplyKey(curve, "G1"); - buildBatchApplyKey(curve, "G2"); - buildBatchApplyKey(curve, "Fr"); - - buildMultiexp(curve, "G1"); - buildMultiexp(curve, "G2"); - - buildFFT(curve, "G1"); - buildFFT(curve, "G2"); - buildFFT(curve, "Fr"); - - buildPairing(curve); - - curve.array2buffer = function(arr, sG) { - const buff = new Uint8Array(sG*arr.length); - - for (let i=0; i Uint8Array, used once at curve load to decode the vendored wasm. - // - // Prefer the platform decoder (Buffer in Node, atob in browsers/extensions) for - // speed, and fall back to a pure-JS implementation only where neither exists -- - // e.g. a SES hardened realm that has not endowed atob/Buffer. The fallback keeps the - // curve loadable everywhere without depending on any host base64 primitive. - - const CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - let LOOKUP; - - function decodePureJs(b64) { - if (!LOOKUP) { - LOOKUP = new Uint8Array(256); - for (let i = 0; i < CHARS.length; i++) LOOKUP[CHARS.charCodeAt(i)] = i; - } - const len = b64.length; - let pad = 0; - if (len > 0 && b64[len - 1] === "=") pad++; - if (len > 1 && b64[len - 2] === "=") pad++; - const outLen = ((len * 3) >> 2) - pad; - const out = new Uint8Array(outLen); - let o = 0; - for (let i = 0; i < len; i += 4) { - const a = LOOKUP[b64.charCodeAt(i)]; - const b = LOOKUP[b64.charCodeAt(i + 1)]; - const c = LOOKUP[b64.charCodeAt(i + 2)]; - const d = LOOKUP[b64.charCodeAt(i + 3)]; - if (o < outLen) out[o++] = (a << 2) | (b >> 4); - if (o < outLen) out[o++] = ((b & 15) << 4) | (c >> 2); - if (o < outLen) out[o++] = ((c & 3) << 6) | d; - } - return out; - } - - function base64ToUint8Array(b64) { - if (typeof Buffer !== "undefined" && typeof Buffer.from === "function") { - // Node (and Node-compatible runtimes) — fastest. - return new Uint8Array(Buffer.from(b64, "base64")); - } - if (typeof atob === "function") { - // Browsers, extensions, modern Node, Deno. - const bin = atob(b64); - const out = new Uint8Array(bin.length); - for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i); - return out; - } - // SES hardened realm or any host without a base64 primitive. - return decodePureJs(b64); - } - - // Module-local singleton cache. Must NOT be on globalThis: assigning to a frozen - // globalThis (e.g. a SES hardened-profile realm) throws at module load. - let curve_bn128 = null; - - async function buildBn128(singleThread, plugins) { - if ((!singleThread) && (curve_bn128)) return curve_bn128; - - let bn128wasm = {}; - - { - // Vendored, uncompressed prebuilt wasm: statically imported (no runtime - // wasmcurves dependency, no dynamic import) and base64-decoded without - // atob/DecompressionStream, so it loads in Node, browsers and SES - // hardened realms alike. Regenerate the vendored module with `npm run gen-wasm`. - bn128wasm.code = base64ToUint8Array(code$2); - bn128wasm.pq = pq$1; - bn128wasm.pr = pq$1; - bn128wasm.pG1gen = pG1gen$1; - bn128wasm.pG1zero = pG1zero$1; - bn128wasm.pG1b = pG1b$1; - bn128wasm.pG2gen = pG2gen$1; - bn128wasm.pG2zero = pG2zero$1; - bn128wasm.pG2b = pG2b$1; - bn128wasm.pOneT = pOneT$1; - bn128wasm.prePSize = prePSize$1; - bn128wasm.preQSize = preQSize$1; - bn128wasm.n8q = 32; - bn128wasm.n8r = 32; - bn128wasm.q = q$1; - bn128wasm.r = r$1; - } - - // Batch-affine MSM helper module (curve-independent; links against the - // main module's exports + memory at runtime in each worker). - bn128wasm.batchCode = base64ToUint8Array(code$1); - // The batch module's GLV path hardcodes the bn254 endomorphism constants. - bn128wasm.glv = true; - - const params = { - name: "bn128", - wasm: bn128wasm, - q: e("21888242871839275222246405745257275088696311157297823662689037894645226208583"), - r: e("21888242871839275222246405745257275088548364400416034343698204186575808495617"), - n8q: 32, - n8r: 32, - cofactorG2: e("30644e72e131a029b85045b68181585e06ceecda572a2489345f2299c0f9fa8d", 16), - singleThread: singleThread ? true : false - }; - - const curve = await buildEngine(params); - curve.terminate = async function () { - if (!params.singleThread) { - curve_bn128 = null; - await this.tm.terminate(); - } - }; - - if (!singleThread) { - curve_bn128 = curve; - } - - return curve; - } - - // AUTO-GENERATED from wasmcurves/build/bls12381_wasm.js — do not edit. - // Regenerate with: npm run gen-wasm - // 'code' is base64 of the wasm-opt -O2 optimized wasm; the rest are - // pointer offsets / field moduli. - const code = "AGFzbQEAAAABjwERYAJ/fwBgA39/fwBgAX8Bf2AEf39/fwBgBX9/f39/AGABfwBgAn9/AX9gBn9/f39/fwBgA39/fwF/YAh/f39/f39/fwBgAn9+AGAEf39/fwF/YAp/f39/f39/f39/AGAFf39/f38Bf2AHf39/f39/fwF/YAl/f39/f39/f38Bf2ALf39/f39/f39/f38BfwIPAQNlbnYGbWVtb3J5AgAZA68CrQIABQIFBgYICAEAAAoDAQIBAQAAAQAAAAACAgAFAQMEAQEDAAIABQIFBgYICAEAAAMBAgEBAAABAAAAAAICAAUBAwQBAQMAAgEAAAICAgUFAAAABgYGAAABAQEAAAEBAQAAAAAAAgIBAAEAAAAAAQEBAQELBwkECQQDAwADAgAABAcHAQEHAAMMBAMCBQABAQABAQAAAwICBAMAAgICBQUAAAAGBgYAAAEBAQAAAQEBAAAAAAACAgEAAAAAAAEBAQEBCQQJBAMDAQADAAAEBwcBAQcBAAMAAAQHBwEBBwEBBAQEBAQAAgIFBQABAAEBAAIGAAMCBAMAAgIFBQABAQABAQAAAAAGAAMCAgQDAAIBAwQBAAAAAAAAAAAAAAICAgIAAAEAAAAACA0ODxABB74nvQIJaW50cV9jb3B5AAAJaW50cV96ZXJvAAEIaW50cV9vbmUAAwtpbnRxX2lzWmVybwACB2ludHFfZXEABAhpbnRxX2d0ZQAFCGludHFfYWRkAAYIaW50cV9zdWIABwhpbnRxX211bAAIC2ludHFfc3F1YXJlAAkOaW50cV9zcXVhcmVPbGQACghpbnRxX2RpdgAMD2ludHFfaW52ZXJzZU1vZAANCGYxbV9jb3B5AAAIZjFtX3plcm8AAQpmMW1faXNaZXJvAAIGZjFtX2VxAAQHZjFtX2FkZAAPB2YxbV9zdWIAEAdmMW1fbmVnABEOZjFtX2lzTmVnYXRpdmUAGAlmMW1faXNPbmUADghmMW1fc2lnbgAZC2YxbV9tUmVkdWN0ABIHZjFtX211bAATCmYxbV9zcXVhcmUAFA1mMW1fc3F1YXJlT2xkABUSZjFtX2Zyb21Nb250Z29tZXJ5ABcQZjFtX3RvTW9udGdvbWVyeQAWC2YxbV9pbnZlcnNlABoHZjFtX29uZQAbCGYxbV9sb2FkABwPZjFtX3RpbWVzU2NhbGFyAB0HZjFtX2V4cAAhEGYxbV9iYXRjaEludmVyc2UAHghmMW1fc3FydAAiDGYxbV9pc1NxdWFyZQAjFWYxbV9iYXRjaFRvTW9udGdvbWVyeQAfF2YxbV9iYXRjaEZyb21Nb250Z29tZXJ5ACAJaW50cl9jb3B5ACQJaW50cl96ZXJvACUIaW50cl9vbmUAJwtpbnRyX2lzWmVybwAmB2ludHJfZXEAKAhpbnRyX2d0ZQApCGludHJfYWRkACoIaW50cl9zdWIAKwhpbnRyX211bAAsC2ludHJfc3F1YXJlAC0OaW50cl9zcXVhcmVPbGQALghpbnRyX2RpdgAvD2ludHJfaW52ZXJzZU1vZAAwCGZybV9jb3B5ACQIZnJtX3plcm8AJQpmcm1faXNaZXJvACYGZnJtX2VxACgHZnJtX2FkZAAyB2ZybV9zdWIAMwdmcm1fbmVnADQOZnJtX2lzTmVnYXRpdmUAOwlmcm1faXNPbmUAMQhmcm1fc2lnbgA8C2ZybV9tUmVkdWN0ADUHZnJtX211bAA2CmZybV9zcXVhcmUANw1mcm1fc3F1YXJlT2xkADgSZnJtX2Zyb21Nb250Z29tZXJ5ADoQZnJtX3RvTW9udGdvbWVyeQA5C2ZybV9pbnZlcnNlAD0HZnJtX29uZQA+CGZybV9sb2FkAD8PZnJtX3RpbWVzU2NhbGFyAEAHZnJtX2V4cABEEGZybV9iYXRjaEludmVyc2UAQQhmcm1fc3FydABFDGZybV9pc1NxdWFyZQBGFWZybV9iYXRjaFRvTW9udGdvbWVyeQBCF2ZybV9iYXRjaEZyb21Nb250Z29tZXJ5AEMGZnJfYWRkADIGZnJfc3ViADMGZnJfbmVnADQGZnJfbXVsAEcJZnJfc3F1YXJlAEgKZnJfaW52ZXJzZQBJDWZyX2lzTmVnYXRpdmUASgdmcl9jb3B5ACQHZnJfemVybwAlBmZyX29uZQA+CWZyX2lzWmVybwAmBWZyX2VxACgMZzFtX211bHRpZXhwAHUSZzFtX211bHRpZXhwX2NodW5rAHQSZzFtX211bHRpZXhwQWZmaW5lAHcYZzFtX211bHRpZXhwQWZmaW5lX2NodW5rAHYKZzFtX2lzWmVybwBMEGcxbV9pc1plcm9BZmZpbmUASwZnMW1fZXEAVAtnMW1fZXFNaXhlZABTDGcxbV9lcUFmZmluZQBSCGcxbV9jb3B5AFAOZzFtX2NvcHlBZmZpbmUATwhnMW1femVybwBODmcxbV96ZXJvQWZmaW5lAE0KZzFtX2RvdWJsZQBWEGcxbV9kb3VibGVBZmZpbmUAVQdnMW1fYWRkAFkMZzFtX2FkZE1peGVkAFgNZzFtX2FkZEFmZmluZQBXB2cxbV9uZWcAWw1nMW1fbmVnQWZmaW5lAFoHZzFtX3N1YgBeDGcxbV9zdWJNaXhlZABdDWcxbV9zdWJBZmZpbmUAXBJnMW1fZnJvbU1vbnRnb21lcnkAYBhnMW1fZnJvbU1vbnRnb21lcnlBZmZpbmUAXxBnMW1fdG9Nb250Z29tZXJ5AGIWZzFtX3RvTW9udGdvbWVyeUFmZmluZQBhD2cxbV90aW1lc1NjYWxhcgB4FWcxbV90aW1lc1NjYWxhckFmZmluZQB5DWcxbV9ub3JtYWxpemUAZwpnMW1fTEVNdG9VAGkKZzFtX0xFTXRvQwBqCmcxbV9VdG9MRU0AawpnMW1fQ3RvTEVNAGwPZzFtX2JhdGNoTEVNdG9VAG0PZzFtX2JhdGNoTEVNdG9DAG4PZzFtX2JhdGNoVXRvTEVNAG8PZzFtX2JhdGNoQ3RvTEVNAHAMZzFtX3RvQWZmaW5lAGMOZzFtX3RvSmFjb2JpYW4AURFnMW1fYmF0Y2hUb0FmZmluZQBmE2cxbV9iYXRjaFRvSmFjb2JpYW4AcQtnMW1faW5DdXJ2ZQBlEWcxbV9pbkN1cnZlQWZmaW5lAGQXZnJtX19yZXZlcnNlUGVybXV0YXRpb24Aegdmcm1fZmZ0AH0IZnJtX2lmZnQAfgpmcm1fcmF3ZmZ0AHsLZnJtX2ZmdEpvaW4Afw5mcm1fZmZ0Sm9pbkV4dACAARFmcm1fZmZ0Sm9pbkV4dEludgCBAQpmcm1fZmZ0TWl4AIIBDGZybV9mZnRGaW5hbACDAR1mcm1fcHJlcGFyZUxhZ3JhbmdlRXZhbHVhdGlvbgCEAQhwb2xfemVybwCFAQ9wb2xfY29uc3RydWN0TEMAhgEMcWFwX2J1aWxkQUJDAIcBC3FhcF9qb2luQUJDAIgBDHFhcF9iYXRjaEFkZACJAQpmMm1faXNaZXJvAEsJZjJtX2lzT25lAIoBCGYybV96ZXJvAE0HZjJtX29uZQCLAQhmMm1fY29weQCMAQdmMm1fbXVsAI0BCGYybV9tdWwxAI4BCmYybV9zcXVhcmUAjwEHZjJtX2FkZACQAQdmMm1fc3ViAJEBB2YybV9uZWcAkgEIZjJtX3NpZ24AlQENZjJtX2Nvbmp1Z2F0ZQBaEmYybV9mcm9tTW9udGdvbWVyeQBfEGYybV90b01vbnRnb21lcnkAYQZmMm1fZXEAUgtmMm1faW52ZXJzZQCTAQdmMm1fZXhwAJgBD2YybV90aW1lc1NjYWxhcgCUARBmMm1fYmF0Y2hJbnZlcnNlAJcBCGYybV9zcXJ0AJkBDGYybV9pc1NxdWFyZQCaAQ5mMm1faXNOZWdhdGl2ZQCWAQxnMm1fbXVsdGlleHAAwgESZzJtX211bHRpZXhwX2NodW5rAMEBEmcybV9tdWx0aWV4cEFmZmluZQDEARhnMm1fbXVsdGlleHBBZmZpbmVfY2h1bmsAwwEKZzJtX2lzWmVybwCcARBnMm1faXNaZXJvQWZmaW5lAJsBBmcybV9lcQCkAQtnMm1fZXFNaXhlZACjAQxnMm1fZXFBZmZpbmUAogEIZzJtX2NvcHkAoAEOZzJtX2NvcHlBZmZpbmUAnwEIZzJtX3plcm8AngEOZzJtX3plcm9BZmZpbmUAnQEKZzJtX2RvdWJsZQCmARBnMm1fZG91YmxlQWZmaW5lAKUBB2cybV9hZGQAqQEMZzJtX2FkZE1peGVkAKgBDWcybV9hZGRBZmZpbmUApwEHZzJtX25lZwCrAQ1nMm1fbmVnQWZmaW5lAKoBB2cybV9zdWIArgEMZzJtX3N1Yk1peGVkAK0BDWcybV9zdWJBZmZpbmUArAESZzJtX2Zyb21Nb250Z29tZXJ5ALABGGcybV9mcm9tTW9udGdvbWVyeUFmZmluZQCvARBnMm1fdG9Nb250Z29tZXJ5ALIBFmcybV90b01vbnRnb21lcnlBZmZpbmUAsQEPZzJtX3RpbWVzU2NhbGFyAMUBFWcybV90aW1lc1NjYWxhckFmZmluZQDGAQ1nMm1fbm9ybWFsaXplALcBCmcybV9MRU10b1UAuAEKZzJtX0xFTXRvQwC5AQpnMm1fVXRvTEVNALoBCmcybV9DdG9MRU0AuwEPZzJtX2JhdGNoTEVNdG9VALwBD2cybV9iYXRjaExFTXRvQwC9AQ9nMm1fYmF0Y2hVdG9MRU0AvgEPZzJtX2JhdGNoQ3RvTEVNAL8BDGcybV90b0FmZmluZQCzAQ5nMm1fdG9KYWNvYmlhbgChARFnMm1fYmF0Y2hUb0FmZmluZQC2ARNnMm1fYmF0Y2hUb0phY29iaWFuAMABC2cybV9pbkN1cnZlALUBEWcybV9pbkN1cnZlQWZmaW5lALQBC2cxbV90aW1lc0ZyAMcBF2cxbV9fcmV2ZXJzZVBlcm11dGF0aW9uAMgBB2cxbV9mZnQAygEIZzFtX2lmZnQAywEKZzFtX3Jhd2ZmdADJAQtnMW1fZmZ0Sm9pbgDMAQ5nMW1fZmZ0Sm9pbkV4dADNARFnMW1fZmZ0Sm9pbkV4dEludgDOAQpnMW1fZmZ0TWl4AM8BDGcxbV9mZnRGaW5hbADQAR1nMW1fcHJlcGFyZUxhZ3JhbmdlRXZhbHVhdGlvbgDRAQtnMm1fdGltZXNGcgDSARdnMm1fX3JldmVyc2VQZXJtdXRhdGlvbgDTAQdnMm1fZmZ0ANUBCGcybV9pZmZ0ANYBCmcybV9yYXdmZnQA1AELZzJtX2ZmdEpvaW4A1wEOZzJtX2ZmdEpvaW5FeHQA2AERZzJtX2ZmdEpvaW5FeHRJbnYA2QEKZzJtX2ZmdE1peADaAQxnMm1fZmZ0RmluYWwA2wEdZzJtX3ByZXBhcmVMYWdyYW5nZUV2YWx1YXRpb24A3AERZzFtX3RpbWVzRnJBZmZpbmUA3QERZzJtX3RpbWVzRnJBZmZpbmUA3gERZnJtX2JhdGNoQXBwbHlLZXkA3wERZzFtX2JhdGNoQXBwbHlLZXkA4AEWZzFtX2JhdGNoQXBwbHlLZXlNaXhlZADhARFnMm1fYmF0Y2hBcHBseUtleQDiARZnMm1fYmF0Y2hBcHBseUtleU1peGVkAOMBCmY2bV9pc1plcm8A5QEJZjZtX2lzT25lAOYBCGY2bV96ZXJvAOcBB2Y2bV9vbmUA6AEIZjZtX2NvcHkA6QEHZjZtX211bADqAQpmNm1fc3F1YXJlAOsBB2Y2bV9hZGQA7AEHZjZtX3N1YgDtAQdmNm1fbmVnAO4BCGY2bV9zaWduAO8BEmY2bV9mcm9tTW9udGdvbWVyeQCwARBmNm1fdG9Nb250Z29tZXJ5ALIBBmY2bV9lcQDwAQtmNm1faW52ZXJzZQDxAQdmNm1fZXhwAPUBD2Y2bV90aW1lc1NjYWxhcgDyARBmNm1fYmF0Y2hJbnZlcnNlAPQBDmY2bV9pc05lZ2F0aXZlAPMBCmZ0bV9pc1plcm8A9wEJZnRtX2lzT25lAPgBCGZ0bV96ZXJvAPkBB2Z0bV9vbmUA+gEIZnRtX2NvcHkA+wEHZnRtX211bAD8AQhmdG1fbXVsMQD9AQpmdG1fc3F1YXJlAP4BB2Z0bV9hZGQA/wEHZnRtX3N1YgCAAgdmdG1fbmVnAIECCGZ0bV9zaWduAIgCDWZ0bV9jb25qdWdhdGUAggISZnRtX2Zyb21Nb250Z29tZXJ5AIQCEGZ0bV90b01vbnRnb21lcnkAgwIGZnRtX2VxAIUCC2Z0bV9pbnZlcnNlAIYCB2Z0bV9leHAAiwIPZnRtX3RpbWVzU2NhbGFyAIcCEGZ0bV9iYXRjaEludmVyc2UAigIIZnRtX3NxcnQAjAIMZnRtX2lzU3F1YXJlAI0CDmZ0bV9pc05lZ2F0aXZlAIkCEWZ0bV9mcm9iZW5pdXNNYXAwAJICEWZ0bV9mcm9iZW5pdXNNYXAxAJMCEWZ0bV9mcm9iZW5pdXNNYXAyAJQCEWZ0bV9mcm9iZW5pdXNNYXAzAJUCEWZ0bV9mcm9iZW5pdXNNYXA0AJYCEWZ0bV9mcm9iZW5pdXNNYXA1AJcCEWZ0bV9mcm9iZW5pdXNNYXA2AJgCEWZ0bV9mcm9iZW5pdXNNYXA3AJkCEWZ0bV9mcm9iZW5pdXNNYXA4AJoCEWZ0bV9mcm9iZW5pdXNNYXA5AJsCE2JsczEyMzgxX3BhaXJpbmdFcTEApwITYmxzMTIzODFfcGFpcmluZ0VxMgCoAhNibHMxMjM4MV9wYWlyaW5nRXEzAKkCE2JsczEyMzgxX3BhaXJpbmdFcTQAqgITYmxzMTIzODFfcGFpcmluZ0VxNQCrAhBibHMxMjM4MV9wYWlyaW5nAKwCEmJsczEyMzgxX3ByZXBhcmVHMQCgAhJibHMxMjM4MV9wcmVwYXJlRzIAoQITYmxzMTIzODFfbWlsbGVyTG9vcACiAhxibHMxMjM4MV9maW5hbEV4cG9uZW50aWF0aW9uAKYCH2JsczEyMzgxX2ZpbmFsRXhwb25lbnRpYXRpb25PbGQAowIaYmxzMTIzODFfX2N5Y2xvdG9taWNTcXVhcmUApAIaYmxzMTIzODFfX2N5Y2xvdG9taWNFeHBfdzAApQIIZjZtX211bDEAjgIJZjZtX211bDAxAI8CCmZ0bV9tdWwwMTQAkAIRZzFtX2luR3JvdXBBZmZpbmUAnAILZzFtX2luR3JvdXAAnQIRZzJtX2luR3JvdXBBZmZpbmUAngILZzJtX2luR3JvdXAAnwIK7dgErQI+ACABIAApAwA3AwAgASAAKQMINwMIIAEgACkDEDcDECABIAApAxg3AxggASAAKQMgNwMgIAEgACkDKDcDKAssACAAQgA3AwAgAEIANwMIIABCADcDECAAQgA3AxggAEIANwMgIABCADcDKAtEACAAKQMoUAR+IAApAyBQBH4gACkDGFAEfiAAKQMQUAR+IAApAwhQBH4gACkDAAVCAQsFQgELBUIBCwVCAQsFQgELUAssACAAQgE3AwAgAEIANwMIIABCADcDECAAQgA3AxggAEIANwMgIABCADcDKAtiACAAKQMoIAEpAyhRBH8gACkDICABKQMgUQR/IAApAxggASkDGFEEfyAAKQMQIAEpAxBRBH8gACkDCCABKQMIUQR/IAApAwAgASkDAFEFQQALBUEACwVBAAsFQQALBUEACwu3AQAgACkDKCABKQMoVAR/QQAFIAApAyggASkDKFYEf0EBBSAAKQMgIAEpAyBUBH9BAAUgACkDICABKQMgVgR/QQEFIAApAxggASkDGFQEf0EABSAAKQMYIAEpAxhWBH9BAQUgACkDECABKQMQVAR/QQAFIAApAxAgASkDEFYEf0EBBSAAKQMIIAEpAwhUBH9BAAUgACkDCCABKQMIVgR/QQEFIAApAwAgASkDAFoLCwsLCwsLCwsLC6QCAQF+IAIgADUCACABNQIAfCIDPgIAIAIgADUCBCABNQIEfCADQiCIfCIDPgIEIAIgADUCCCABNQIIfCADQiCIfCIDPgIIIAIgADUCDCABNQIMfCADQiCIfCIDPgIMIAIgADUCECABNQIQfCADQiCIfCIDPgIQIAIgADUCFCABNQIUfCADQiCIfCIDPgIUIAIgADUCGCABNQIYfCADQiCIfCIDPgIYIAIgADUCHCABNQIcfCADQiCIfCIDPgIcIAIgADUCICABNQIgfCADQiCIfCIDPgIgIAIgADUCJCABNQIkfCADQiCIfCIDPgIkIAIgADUCKCABNQIofCADQiCIfCIDPgIoIAIgADUCLCABNQIsfCADQiCIfCIDPgIsIANCIIinC/gCAQF+IAIgADUCACABNQIAfSIDQv////8Pgz4CACACIAA1AgQgATUCBH0gA0Igh3wiA0L/////D4M+AgQgAiAANQIIIAE1Agh9IANCIId8IgNC/////w+DPgIIIAIgADUCDCABNQIMfSADQiCHfCIDQv////8Pgz4CDCACIAA1AhAgATUCEH0gA0Igh3wiA0L/////D4M+AhAgAiAANQIUIAE1AhR9IANCIId8IgNC/////w+DPgIUIAIgADUCGCABNQIYfSADQiCHfCIDQv////8Pgz4CGCACIAA1AhwgATUCHH0gA0Igh3wiA0L/////D4M+AhwgAiAANQIgIAE1AiB9IANCIId8IgNC/////w+DPgIgIAIgADUCJCABNQIkfSADQiCHfCIDQv////8Pgz4CJCACIAA1AiggATUCKH0gA0Igh3wiA0L/////D4M+AiggAiAANQIsIAE1Aix9IANCIId8IgNC/////w+DPgIsIANCIIenC84fARl+IAQgADUCACIFIAE1AgAiBn4gA0L/////D4N8IgNCIIh8IQQgAiADPgIAIARCIIghAyADIAUgATUCBCIHfiAEQv////8Pg3wiBEIgiHwhAyADIAA1AgQiCCAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AgQgA0IgiCEEIAQgBSABNQIIIgl+IANC/////w+DfCIDQiCIfCEEIAQgByAIfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AggiCiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AgggBEIgiCEDIAMgBSABNQIMIgt+IARC/////w+DfCIEQiCIfCEDIAMgCCAJfiAEQv////8Pg3wiBEIgiHwhAyADIAcgCn4gBEL/////D4N8IgRCIIh8IQMgAyAANQIMIgwgBn4gBEL/////D4N8IgRCIIh8IQMgAiAEPgIMIANCIIghBCAEIAUgATUCECINfiADQv////8Pg3wiA0IgiHwhBCAEIAggC34gA0L/////D4N8IgNCIIh8IQQgBCAJIAp+IANC/////w+DfCIDQiCIfCEEIAQgByAMfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AhAiDiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AhAgBEIgiCEDIAMgBSABNQIUIg9+IARC/////w+DfCIEQiCIfCEDIAMgCCANfiAEQv////8Pg3wiBEIgiHwhAyADIAogC34gBEL/////D4N8IgRCIIh8IQMgAyAJIAx+IARC/////w+DfCIEQiCIfCEDIAMgByAOfiAEQv////8Pg3wiBEIgiHwhAyADIAA1AhQiECAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AhQgA0IgiCEEIAQgBSABNQIYIhF+IANC/////w+DfCIDQiCIfCEEIAQgCCAPfiADQv////8Pg3wiA0IgiHwhBCAEIAogDX4gA0L/////D4N8IgNCIIh8IQQgBCALIAx+IANC/////w+DfCIDQiCIfCEEIAQgCSAOfiADQv////8Pg3wiA0IgiHwhBCAEIAcgEH4gA0L/////D4N8IgNCIIh8IQQgBCAANQIYIhIgBn4gA0L/////D4N8IgNCIIh8IQQgAiADPgIYIARCIIghAyADIAUgATUCHCITfiAEQv////8Pg3wiBEIgiHwhAyADIAggEX4gBEL/////D4N8IgRCIIh8IQMgAyAKIA9+IARC/////w+DfCIEQiCIfCEDIAMgDCANfiAEQv////8Pg3wiBEIgiHwhAyADIAsgDn4gBEL/////D4N8IgRCIIh8IQMgAyAJIBB+IARC/////w+DfCIEQiCIfCEDIAMgByASfiAEQv////8Pg3wiBEIgiHwhAyADIAA1AhwiFCAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AhwgA0IgiCEEIAQgBSABNQIgIhV+IANC/////w+DfCIDQiCIfCEEIAQgCCATfiADQv////8Pg3wiA0IgiHwhBCAEIAogEX4gA0L/////D4N8IgNCIIh8IQQgBCAMIA9+IANC/////w+DfCIDQiCIfCEEIAQgDSAOfiADQv////8Pg3wiA0IgiHwhBCAEIAsgEH4gA0L/////D4N8IgNCIIh8IQQgBCAJIBJ+IANC/////w+DfCIDQiCIfCEEIAQgByAUfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AiAiFiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AiAgBEIgiCEDIAMgBSABNQIkIhd+IARC/////w+DfCIEQiCIfCEDIAMgCCAVfiAEQv////8Pg3wiBEIgiHwhAyADIAogE34gBEL/////D4N8IgRCIIh8IQMgAyAMIBF+IARC/////w+DfCIEQiCIfCEDIAMgDiAPfiAEQv////8Pg3wiBEIgiHwhAyADIA0gEH4gBEL/////D4N8IgRCIIh8IQMgAyALIBJ+IARC/////w+DfCIEQiCIfCEDIAMgCSAUfiAEQv////8Pg3wiBEIgiHwhAyADIAcgFn4gBEL/////D4N8IgRCIIh8IQMgAyAANQIkIhggBn4gBEL/////D4N8IgRCIIh8IQMgAiAEPgIkIANCIIghBCAEIAUgATUCKCIZfiADQv////8Pg3wiA0IgiHwhBCAEIAggF34gA0L/////D4N8IgNCIIh8IQQgBCAKIBV+IANC/////w+DfCIDQiCIfCEEIAQgDCATfiADQv////8Pg3wiA0IgiHwhBCAEIA4gEX4gA0L/////D4N8IgNCIIh8IQQgBCAPIBB+IANC/////w+DfCIDQiCIfCEEIAQgDSASfiADQv////8Pg3wiA0IgiHwhBCAEIAsgFH4gA0L/////D4N8IgNCIIh8IQQgBCAJIBZ+IANC/////w+DfCIDQiCIfCEEIAQgByAYfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AigiGiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AiggBEIgiCEDIAMgBSABNQIsIht+IARC/////w+DfCIEQiCIfCEDIAMgCCAZfiAEQv////8Pg3wiBEIgiHwhAyADIAogF34gBEL/////D4N8IgRCIIh8IQMgAyAMIBV+IARC/////w+DfCIEQiCIfCEDIAMgDiATfiAEQv////8Pg3wiBEIgiHwhAyADIBAgEX4gBEL/////D4N8IgRCIIh8IQMgAyAPIBJ+IARC/////w+DfCIEQiCIfCEDIAMgDSAUfiAEQv////8Pg3wiBEIgiHwhAyADIAsgFn4gBEL/////D4N8IgRCIIh8IQMgAyAJIBh+IARC/////w+DfCIEQiCIfCEDIAMgByAafiAEQv////8Pg3wiBEIgiHwhAyADIAA1AiwiBSAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AiwgA0IgiCEEIAQgCCAbfiADQv////8Pg3wiA0IgiHwhBCAEIAogGX4gA0L/////D4N8IgNCIIh8IQQgBCAMIBd+IANC/////w+DfCIDQiCIfCEEIAQgDiAVfiADQv////8Pg3wiA0IgiHwhBCAEIBAgE34gA0L/////D4N8IgNCIIh8IQQgBCARIBJ+IANC/////w+DfCIDQiCIfCEEIAQgDyAUfiADQv////8Pg3wiA0IgiHwhBCAEIA0gFn4gA0L/////D4N8IgNCIIh8IQQgBCALIBh+IANC/////w+DfCIDQiCIfCEEIAQgCSAafiADQv////8Pg3wiA0IgiHwhBCAEIAUgB34gA0L/////D4N8IgNCIIh8IQQgAiADPgIwIARCIIghAyADIAogG34gBEL/////D4N8IgRCIIh8IQMgAyAMIBl+IARC/////w+DfCIEQiCIfCEDIAMgDiAXfiAEQv////8Pg3wiBEIgiHwhAyADIBAgFX4gBEL/////D4N8IgRCIIh8IQMgAyASIBN+IARC/////w+DfCIEQiCIfCEDIAMgESAUfiAEQv////8Pg3wiBEIgiHwhAyADIA8gFn4gBEL/////D4N8IgRCIIh8IQMgAyANIBh+IARC/////w+DfCIEQiCIfCEDIAMgCyAafiAEQv////8Pg3wiBEIgiHwhAyADIAUgCX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgI0IANCIIghBCAEIAwgG34gA0L/////D4N8IgNCIIh8IQQgBCAOIBl+IANC/////w+DfCIDQiCIfCEEIAQgECAXfiADQv////8Pg3wiA0IgiHwhBCAEIBIgFX4gA0L/////D4N8IgNCIIh8IQQgBCATIBR+IANC/////w+DfCIDQiCIfCEEIAQgESAWfiADQv////8Pg3wiA0IgiHwhBCAEIA8gGH4gA0L/////D4N8IgNCIIh8IQQgBCANIBp+IANC/////w+DfCIDQiCIfCEEIAQgBSALfiADQv////8Pg3wiA0IgiHwhBCACIAM+AjggBEIgiCEDIAMgDiAbfiAEQv////8Pg3wiBEIgiHwhAyADIBAgGX4gBEL/////D4N8IgRCIIh8IQMgAyASIBd+IARC/////w+DfCIEQiCIfCEDIAMgFCAVfiAEQv////8Pg3wiBEIgiHwhAyADIBMgFn4gBEL/////D4N8IgRCIIh8IQMgAyARIBh+IARC/////w+DfCIEQiCIfCEDIAMgDyAafiAEQv////8Pg3wiBEIgiHwhAyADIAUgDX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgI8IANCIIghBCAEIBAgG34gA0L/////D4N8IgNCIIh8IQQgBCASIBl+IANC/////w+DfCIDQiCIfCEEIAQgFCAXfiADQv////8Pg3wiA0IgiHwhBCAEIBUgFn4gA0L/////D4N8IgNCIIh8IQQgBCATIBh+IANC/////w+DfCIDQiCIfCEEIAQgESAafiADQv////8Pg3wiA0IgiHwhBCAEIAUgD34gA0L/////D4N8IgNCIIh8IQQgAiADPgJAIARCIIghAyADIBIgG34gBEL/////D4N8IgRCIIh8IQMgAyAUIBl+IARC/////w+DfCIEQiCIfCEDIAMgFiAXfiAEQv////8Pg3wiBEIgiHwhAyADIBUgGH4gBEL/////D4N8IgRCIIh8IQMgAyATIBp+IARC/////w+DfCIEQiCIfCEDIAMgBSARfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AkQgA0IgiCEEIAQgFCAbfiADQv////8Pg3wiA0IgiHwhBCAEIBYgGX4gA0L/////D4N8IgNCIIh8IQQgBCAXIBh+IANC/////w+DfCIDQiCIfCEEIAQgFSAafiADQv////8Pg3wiA0IgiHwhBCAEIAUgE34gA0L/////D4N8IgNCIIh8IQQgAiADPgJIIARCIIghAyADIBYgG34gBEL/////D4N8IgRCIIh8IQMgAyAYIBl+IARC/////w+DfCIEQiCIfCEDIAMgFyAafiAEQv////8Pg3wiBEIgiHwhAyADIAUgFX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgJMIANCIIghBCAEIBggG34gA0L/////D4N8IgNCIIh8IQQgBCAZIBp+IANC/////w+DfCIDQiCIfCEEIAQgBSAXfiADQv////8Pg3wiA0IgiHwhBCACIAM+AlAgBEIgiCEDIAMgGiAbfiAEQv////8Pg3wiBEIgiHwhAyADIAUgGX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgJUIANCIIghBCAEIAUgG34gA0L/////D4N8IgNCIIh8IQQgAiADPgJYIAIgBD4CXAu8GQEQfiADIAA1AgAiBiAGfiACQv////8Pg3wiAkIgiHwhAyABIAI+AgAgAyIEQiCIIQUgADUCBCIHIAZ+IgJCIIhCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CBCADIgRCIIghBSAANQIIIgggBn4iAkIgiEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgByAHfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CCCADIgRCIIghBSAANQIMIgkgBn4iAkIgiCEDIAMgByAIfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CDCADIgRCIIghBSAANQIQIgogBn4iAkIgiCEDIAMgByAJfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAggCH4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AhAgAyIEQiCIIQUgADUCFCILIAZ+IgJCIIghAyADIAcgCn4gAkL/////D4N8IgJCIIh8IQMgAyAIIAl+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIUIAMiBEIgiCEFIAA1AhgiDCAGfiICQiCIIQMgAyAHIAt+IAJC/////w+DfCICQiCIfCEDIAMgCCAKfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAkgCX4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AhggAyIEQiCIIQUgADUCHCINIAZ+IgJCIIghAyADIAcgDH4gAkL/////D4N8IgJCIIh8IQMgAyAIIAt+IAJC/////w+DfCICQiCIfCEDIAMgCSAKfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CHCADIgRCIIghBSAANQIgIg4gBn4iAkIgiCEDIAMgByANfiACQv////8Pg3wiAkIgiHwhAyADIAggDH4gAkL/////D4N8IgJCIIh8IQMgAyAJIAt+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgCiAKfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CICADIgRCIIghBSAANQIkIg8gBn4iAkIgiCEDIAMgByAOfiACQv////8Pg3wiAkIgiHwhAyADIAggDX4gAkL/////D4N8IgJCIIh8IQMgAyAJIAx+IAJC/////w+DfCICQiCIfCEDIAMgCiALfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CJCADIgRCIIghBSAANQIoIhAgBn4iAkIgiCEDIAMgByAPfiACQv////8Pg3wiAkIgiHwhAyADIAggDn4gAkL/////D4N8IgJCIIh8IQMgAyAJIA1+IAJC/////w+DfCICQiCIfCEDIAMgCiAMfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAsgC34gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AiggAyIEQiCIIQUgADUCLCIRIAZ+IgJCIIghAyADIAcgEH4gAkL/////D4N8IgJCIIh8IQMgAyAIIA9+IAJC/////w+DfCICQiCIfCEDIAMgCSAOfiACQv////8Pg3wiAkIgiHwhAyADIAogDX4gAkL/////D4N8IgJCIIh8IQMgAyALIAx+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIsIAMiBEIgiCEFIAcgEX4iAkIgiCEDIAMgCCAQfiACQv////8Pg3wiAkIgiHwhAyADIAkgD34gAkL/////D4N8IgJCIIh8IQMgAyAKIA5+IAJC/////w+DfCICQiCIfCEDIAMgCyANfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAwgDH4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AjAgAyIEQiCIIQUgCCARfiICQiCIIQMgAyAJIBB+IAJC/////w+DfCICQiCIfCEDIAMgCiAPfiACQv////8Pg3wiAkIgiHwhAyADIAsgDn4gAkL/////D4N8IgJCIIh8IQMgAyAMIA1+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgI0IAMiBEIgiCEFIAkgEX4iAkIgiCEDIAMgCiAQfiACQv////8Pg3wiAkIgiHwhAyADIAsgD34gAkL/////D4N8IgJCIIh8IQMgAyAMIA5+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgDSANfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4COCADIgRCIIghBSAKIBF+IgJCIIghAyADIAsgEH4gAkL/////D4N8IgJCIIh8IQMgAyAMIA9+IAJC/////w+DfCICQiCIfCEDIAMgDSAOfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CPCADIgRCIIghBSALIBF+IgJCIIghAyADIAwgEH4gAkL/////D4N8IgJCIIh8IQMgAyANIA9+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgDiAOfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CQCADIgRCIIghBSAMIBF+IgJCIIghAyADIA0gEH4gAkL/////D4N8IgJCIIh8IQMgAyAOIA9+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgJEIAMiBEIgiCEFIA0gEX4iAkIgiCEDIAMgDiAQfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIA8gD34gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AkggAyIEQiCIIQUgDiARfiICQiCIIQMgAyAPIBB+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgJMIAMiBEIgiCEFIA8gEX4iAkIgiEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgECAQfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CUCADIgRCIIghBSAQIBF+IgJCIIhCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CVCADIgRCIIghBUIAIQJCACEDIAMgESARfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CWCABIAM+AlwLCgAgACAAIAEQCAtBACAAIAA1AAAgAXwiAT4AACABQiCIIQEDQCABUEUEQCAAQQRqIgA1AAAgAXwhASAAIAE+AAAgAUIgiCEBDAELCwuEBAIDfgF/IAAgA0GIASADGyIDEAAgAUEoEAAgAkHYACACGyIHEAFBuAEQAUEvIQBBLyEBA0AgAUEoai0AACABQQNGckUEQCABQQFrIQEMAQsLIAFBJWo1AABCAXwiBkIBUQRAQgBCAIAaCwNAAkADQCAAIANqLQAAIABBB0ZyRQRAIABBAWshAAwBCwsgACADakEHaykAACAGgCEFIAAgAWtBBGshAgNAIAVCgICAgHCDUCACQQBOcUUEQCAFQgiIIQUgAkEBaiECDAELCyAFUARAIANBKBAFRQ0BQgEhBUEAIQILQegBQSg1AAAgBX4iBD4AAEHsAUEsNQAAIAV+IARCIIh8IgQ+AABB8AFBMDUAACAFfiAEQiCIfCIEPgAAQfQBQTQ1AAAgBX4gBEIgiHwiBD4AAEH4AUE4NQAAIAV+IARCIIh8IgQ+AABB/AFBPDUAACAFfiAEQiCIfCIEPgAAQYACQcAANQAAIAV+IARCIIh8IgQ+AABBhAJBxAA1AAAgBX4gBEIgiHwiBD4AAEGIAkHIADUAACAFfiAEQiCIfCIEPgAAQYwCQcwANQAAIAV+IARCIIh8IgQ+AABBkAJB0AA1AAAgBX4gBEIgiHwiBD4AAEGUAkHUADUAACAFfiAEQiCIfD4AACADQegBIAJrIAMQBxogAiAHaiAFEAsMAQsLC44CAQp/QZgCIQNBmAIQAUHIAiEIIAFByAIQAEH4AiEJQfgCEANBqAMhBiAAQagDEABB2AMhC0GIBCEKQZgFIQQDQCAGEAJFBEAgCCAGIAsgChAMIAsgCUG4BBAIIAcEfyAFBH9BuAQgAxAFBH9BuAQgAyAEEAcaQQAFIANBuAQgBBAHGkEBCwVBuAQgAyAEEAYaQQELBSAFBH9BuAQgAyAEEAYaQQAFIANBuAQQBQR/IANBuAQgBBAHGkEABUG4BCADIAQQBxpBAQsLCyEMIAMhACAJIQMgBCEJIAAhBCAFIQcgDCEFIAghACAGIQggCiEGIAAhCgwBCwsgBwRAIAEgAyACEAcaBSADIAIQAAsLCQAgAEGoBhAECywAIAAgASACEAYEQCACQcgFIAIQBxoFIAJByAUQBQRAIAJByAUgAhAHGgsLCxcAIAAgASACEAcEQCACQcgFIAIQBhoLCwsAQdgGIAAgARAQC8YhAQN+IAAgADUCAEL9//P/DyIEIAA1AgB+Qv////8PgyIDQcgFNQIAfnwiAj4CACAAIAA1AgQgAkIgiHxBzAU1AgAgA358IgI+AgQgACAANQIIIAJCIIh8QdAFNQIAIAN+fCICPgIIIAAgADUCDCACQiCIfEHUBTUCACADfnwiAj4CDCAAIAA1AhAgAkIgiHxB2AU1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QdwFNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEHgBTUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxB5AU1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QegFNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEHsBTUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxB8AU1AgAgA358IgI+AiggACAANQIsIAJCIIh8QfQFNQIAIAN+fCICPgIsQfgIIAJCIIg+AgAgACAANQIEIAA1AgQgBH5C/////w+DIgNByAU1AgB+fCICPgIEIAAgADUCCCACQiCIfEHMBTUCACADfnwiAj4CCCAAIAA1AgwgAkIgiHxB0AU1AgAgA358IgI+AgwgACAANQIQIAJCIIh8QdQFNQIAIAN+fCICPgIQIAAgADUCFCACQiCIfEHYBTUCACADfnwiAj4CFCAAIAA1AhggAkIgiHxB3AU1AgAgA358IgI+AhggACAANQIcIAJCIIh8QeAFNQIAIAN+fCICPgIcIAAgADUCICACQiCIfEHkBTUCACADfnwiAj4CICAAIAA1AiQgAkIgiHxB6AU1AgAgA358IgI+AiQgACAANQIoIAJCIIh8QewFNQIAIAN+fCICPgIoIAAgADUCLCACQiCIfEHwBTUCACADfnwiAj4CLCAAIAA1AjAgAkIgiHxB9AU1AgAgA358IgI+AjBB/AggAkIgiD4CACAAIAA1AgggADUCCCAEfkL/////D4MiA0HIBTUCAH58IgI+AgggACAANQIMIAJCIIh8QcwFNQIAIAN+fCICPgIMIAAgADUCECACQiCIfEHQBTUCACADfnwiAj4CECAAIAA1AhQgAkIgiHxB1AU1AgAgA358IgI+AhQgACAANQIYIAJCIIh8QdgFNQIAIAN+fCICPgIYIAAgADUCHCACQiCIfEHcBTUCACADfnwiAj4CHCAAIAA1AiAgAkIgiHxB4AU1AgAgA358IgI+AiAgACAANQIkIAJCIIh8QeQFNQIAIAN+fCICPgIkIAAgADUCKCACQiCIfEHoBTUCACADfnwiAj4CKCAAIAA1AiwgAkIgiHxB7AU1AgAgA358IgI+AiwgACAANQIwIAJCIIh8QfAFNQIAIAN+fCICPgIwIAAgADUCNCACQiCIfEH0BTUCACADfnwiAj4CNEGACSACQiCIPgIAIAAgADUCDCAANQIMIAR+Qv////8PgyIDQcgFNQIAfnwiAj4CDCAAIAA1AhAgAkIgiHxBzAU1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QdAFNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEHUBTUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxB2AU1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QdwFNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEHgBTUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxB5AU1AgAgA358IgI+AiggACAANQIsIAJCIIh8QegFNQIAIAN+fCICPgIsIAAgADUCMCACQiCIfEHsBTUCACADfnwiAj4CMCAAIAA1AjQgAkIgiHxB8AU1AgAgA358IgI+AjQgACAANQI4IAJCIIh8QfQFNQIAIAN+fCICPgI4QYQJIAJCIIg+AgAgACAANQIQIAA1AhAgBH5C/////w+DIgNByAU1AgB+fCICPgIQIAAgADUCFCACQiCIfEHMBTUCACADfnwiAj4CFCAAIAA1AhggAkIgiHxB0AU1AgAgA358IgI+AhggACAANQIcIAJCIIh8QdQFNQIAIAN+fCICPgIcIAAgADUCICACQiCIfEHYBTUCACADfnwiAj4CICAAIAA1AiQgAkIgiHxB3AU1AgAgA358IgI+AiQgACAANQIoIAJCIIh8QeAFNQIAIAN+fCICPgIoIAAgADUCLCACQiCIfEHkBTUCACADfnwiAj4CLCAAIAA1AjAgAkIgiHxB6AU1AgAgA358IgI+AjAgACAANQI0IAJCIIh8QewFNQIAIAN+fCICPgI0IAAgADUCOCACQiCIfEHwBTUCACADfnwiAj4COCAAIAA1AjwgAkIgiHxB9AU1AgAgA358IgI+AjxBiAkgAkIgiD4CACAAIAA1AhQgADUCFCAEfkL/////D4MiA0HIBTUCAH58IgI+AhQgACAANQIYIAJCIIh8QcwFNQIAIAN+fCICPgIYIAAgADUCHCACQiCIfEHQBTUCACADfnwiAj4CHCAAIAA1AiAgAkIgiHxB1AU1AgAgA358IgI+AiAgACAANQIkIAJCIIh8QdgFNQIAIAN+fCICPgIkIAAgADUCKCACQiCIfEHcBTUCACADfnwiAj4CKCAAIAA1AiwgAkIgiHxB4AU1AgAgA358IgI+AiwgACAANQIwIAJCIIh8QeQFNQIAIAN+fCICPgIwIAAgADUCNCACQiCIfEHoBTUCACADfnwiAj4CNCAAIAA1AjggAkIgiHxB7AU1AgAgA358IgI+AjggACAANQI8IAJCIIh8QfAFNQIAIAN+fCICPgI8IAAgADUC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AlRBoAkgAkIgiD4CACAAIAA1AiwgADUCLCAEfkL/////D4MiA0HIBTUCAH58IgI+AiwgACAANQIwIAJCIIh8QcwFNQIAIAN+fCICPgIwIAAgADUCNCACQiCIfEHQBTUCACADfnwiAj4CNCAAIAA1AjggAkIgiHxB1AU1AgAgA358IgI+AjggACAANQI8IAJCIIh8QdgFNQIAIAN+fCICPgI8IAAgADUCQCACQiCIfEHcBTUCACADfnwiAj4CQCAAIAA1AkQgAkIgiHxB4AU1AgAgA358IgI+AkQgACAANQJIIAJCIIh8QeQFNQIAIAN+fCICPgJIIAAgADUCTCACQiCIfEHoBTUCACADfnwiAj4CTCAAIAA1AlAgAkIgiHxB7AU1AgAgA358IgI+AlAgACAANQJUIAJCIIh8QfAFNQIAIAN+fCICPgJUIAAgADUCWCACQiCIfEH0BTUCACADfnwiAj4CWEGkCSACQiCIPgIAQfgIIABBMGogARAPC/Q+ARt+IAUgATUCACIEIAA1AgAiEn58IgNC/////w+DIQUgBiAANQIEIhMgBH58IANCIIh8IgNC/////w+DIQYgByAANQIIIhQgBH58IANCIIh8IgNC/////w+DIQcgCCAANQIMIhUgBH58IANCIIh8IgNC/////w+DIQggCSAANQIQIhYgBH58IANCIIh8IgNC/////w+DIQkgCiAANQIUIhcgBH58IANCIIh8IgNC/////w+DIQogCyAANQIYIhggBH58IANCIIh8IgNC/////w+DIQsgDCAANQIcIhkgBH58IANCIIh8IgNC/////w+DIQwgDSAANQIgIhogBH58IANCIIh8IgNC/////w+DIQ0gDiAANQIkIhsgBH58IANCIIh8IgNC/////w+DIQ4gDyAANQIoIhwgBH58IANCIIh8IgNC/////w+DIQ8gECAANQIsIh0gBH58IANCIIh8IgNC/////w+DIRAgA0IgiCERIAUgBUL9//P/D35C/////w+DIgRCq9X+/w9+fEIgiCAGIARC///7zwt+fHwiA0L/////D4MhBSAHIARC///Pigt+fCADQiCIfCIDQv////8PgyEGIAggBEL+/6/1AX58IANCIIh8IgNC/////w+DIQcgCSAEQqTsw7UPfnwgA0IgiHwiA0L/////D4MhCCAKIARCoKXDuQZ+fCADQiCIfCIDQv////8PgyEJIAsgBEK/pZScD358IANCIIh8IgNC/////w+DIQogDCAEQoSX3aMGfnwgA0IgiHwiA0L/////D4MhCyANIARC19mumgR+fCADQiCIfCIDQv////8PgyEMIA4gBEK2z+7YBH58IANCIIh8IgNC/////w+DIQ0gDyAEQprN/8sDfnwgA0IgiHwiA0L/////D4MhDiAQIARC6qOE0AF+fCADQiCIfCIDQv////8PgyEPIBEgA0IgiHwhECAFIBIgATUCBCIEfnwiA0L/////D4MhBSAGIAQgE358IANCIIh8IgNC/////w+DIQYgByAEIBR+fCADQiCIfCIDQv////8PgyEHIAggBCAVfnwgA0IgiHwiA0L/////D4MhCCAJIAQgFn58IANCIIh8IgNC/////w+DIQkgCiAEIBd+fCADQiCIfCIDQv////8PgyEKIAsgBCAYfnwgA0IgiHwiA0L/////D4MhCyAMIAQgGX58IANCIIh8IgNC/////w+DIQwgDSAEIBp+fCADQiCIfCIDQv////8PgyENIA4gBCAbfnwgA0IgiHwiA0L/////D4MhDiAPIAQgHH58IANCIIh8IgNC/////w+DIQ8gECAEIB1+fCADQiCIfCIDQv////8PgyEQIANCIIghESAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DIQUgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4MhBiAIIARC/v+v9QF+fCADQiCIfCIDQv////8PgyEHIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DIQggCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4MhCSALIARCv6WUnA9+fCADQiCIfCIDQv////8PgyEKIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DIQsgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4MhDCAOIARCts/u2AR+fCADQiCIfCIDQv////8PgyENIA8gBEKazf/LA358IANCIIh8IgNC/////w+DIQ4gECAEQuqjhNABfnwgA0IgiHwiA0L/////D4MhDyARIANCIIh8IRAgBSASIAE1AggiBH58IgNC/////w+DIQUgBiAEIBN+fCADQiCIfCIDQv////8PgyEGIAcgBCAUfnwgA0IgiHwiA0L/////D4MhByAIIAQgFX58IANCIIh8IgNC/////w+DIQggCSAEIBZ+fCADQiCIfCIDQv////8PgyEJIAogBCAXfnwgA0IgiHwiA0L/////D4MhCiALIAQgGH58IANCIIh8IgNC/////w+DIQsgDCAEIBl+fCADQiCIfCIDQv////8PgyEMIA0gBCAafnwgA0IgiHwiA0L/////D4MhDSAOIAQgG358IANCIIh8IgNC/////w+DIQ4gDyAEIBx+fCADQiCIfCIDQv////8PgyEPIBAgBCAdfnwgA0IgiHwiA0L/////D4MhECADQiCIIREgBSAFQv3/8/8PfkL/////D4MiBEKr1f7/D358QiCIIAYgBEL///vPC358fCIDQv////8PgyEFIAcgBEL//8+KC358IANCIIh8IgNC/////w+DIQYgCCAEQv7/r/UBfnwgA0IgiHwiA0L/////D4MhByAJIARCpOzDtQ9+fCADQiCIfCIDQv////8PgyEIIAogBEKgpcO5Bn58IANCIIh8IgNC/////w+DIQkgCyAEQr+llJwPfnwgA0IgiHwiA0L/////D4MhCiAMIARChJfdowZ+fCADQiCIfCIDQv////8PgyELIA0gBELX2a6aBH58IANCIIh8IgNC/////w+DIQwgDiAEQrbP7tgEfnwgA0IgiHwiA0L/////D4MhDSAPIARCms3/ywN+fCADQiCIfCIDQv////8PgyEOIBAgBELqo4TQAX58IANCIIh8IgNC/////w+DIQ8gESADQiCIfCEQIAUgEiABNQIMIgR+fCIDQv////8PgyEFIAYgBCATfnwgA0IgiHwiA0L/////D4MhBiAHIAQgFH58IANCIIh8IgNC/////w+DIQcgCCAEIBV+fCADQiCIfCIDQv////8PgyEIIAkgBCAWfnwgA0IgiHwiA0L/////D4MhCSAKIAQgF358IANCIIh8IgNC/////w+DIQogCyAEIBh+fCADQiCIfCIDQv////8PgyELIAwgBCAZfnwgA0IgiHwiA0L/////D4MhDCANIAQgGn58IANCIIh8IgNC/////w+DIQ0gDiAEIBt+fCADQiCIfCIDQv////8PgyEOIA8gBCAcfnwgA0IgiHwiA0L/////D4MhDyAQIAQgHX58IANCIIh8IgNC/////w+DIRAgA0IgiCERIAUgBUL9//P/D35C/////w+DIgRCq9X+/w9+fEIgiCAGIARC///7zwt+fHwiA0L/////D4MhBSAHIARC///Pigt+fCADQiCIfCIDQv////8PgyEGIAggBEL+/6/1AX58IANCIIh8IgNC/////w+DIQcgCSAEQqTsw7UPfnwgA0IgiHwiA0L/////D4MhCCAKIARCoKXDuQZ+fCADQiCIfCIDQv////8PgyEJIAsgBEK/pZScD358IANCIIh8IgNC/////w+DIQogDCAEQoSX3aMGfnwgA0IgiHwiA0L/////D4MhCyANIARC19mumgR+fCADQiCIfCIDQv////8PgyEMIA4gBEK2z+7YBH58IANCIIh8IgNC/////w+DIQ0gDyAEQprN/8sDfnwgA0IgiHwiA0L/////D4MhDiAQIARC6qOE0AF+fCADQiCIfCIDQv////8PgyEPIBEgA0IgiHwhECAFIBIgATUCECIEfnwiA0L/////D4MhBSAGIAQgE358IANCIIh8IgNC/////w+DIQYgByAEIBR+fCADQiCIfCIDQv////8PgyEHIAggBCAVfnwgA0IgiHwiA0L/////D4MhCCAJIAQgFn58IANCIIh8IgNC/////w+DIQkgCiAEIBd+fCADQiCIfCIDQv////8PgyEKIAsgBCAYfnwgA0IgiHwiA0L/////D4MhCyAMIAQgGX58IANCIIh8IgNC/////w+DIQwgDSAEIBp+fCADQiCIfCIDQv////8PgyENIA4gBCAbfnwgA0IgiHwiA0L/////D4MhDiAPIAQgHH58IANCIIh8IgNC/////w+DIQ8gECAEIB1+fCADQiCIfCIDQv////8PgyEQIANCIIghESAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DIQUgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4MhBiAIIARC/v+v9QF+fCADQiCIfCIDQv////8PgyEHIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DIQggCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4MhCSALIARCv6WUnA9+fCADQiCIfCIDQv////8PgyEKIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DIQsgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4MhDCAOIARCts/u2AR+fCADQiCIfCIDQv////8PgyENIA8gBEKazf/LA358IANCIIh8IgNC/////w+DIQ4gECAEQuqjhNABfnwgA0IgiHwiA0L/////D4MhDyARIANCIIh8IRAgBSASIAE1AhQiBH58IgNC/////w+DIQUgBiAEIBN+fCADQiCIfCIDQv////8PgyEGIAcgBCAUfnwgA0IgiHwiA0L/////D4MhByAIIAQgFX58IANCIIh8IgNC/////w+DIQggCSAEIBZ+fCADQiCIfCIDQv////8PgyEJIAogBCAXfnwgA0IgiHwiA0L/////D4MhCiALIAQgGH58IANCIIh8IgNC/////w+DIQsgDCAEIBl+fCADQiCIfCIDQv////8PgyEMIA0gBCAafnwgA0IgiHwiA0L/////D4MhDSAOIAQgG358IANCIIh8IgNC/////w+DIQ4gDyAEIBx+fCADQiCIfCIDQv////8PgyEPIBAgBCAdfnwgA0IgiHwiA0L/////D4MhECADQiCIIREgBSAFQv3/8/8PfkL/////D4MiBEKr1f7/D358QiCIIAYgBEL///vPC358fCIDQv////8PgyEFIAcgBEL//8+KC358IANCIIh8IgNC/////w+DIQYgCCAEQv7/r/UBfnwgA0IgiHwiA0L/////D4MhByAJIARCpOzDtQ9+fCADQiCIfCIDQv////8PgyEIIAogBEKgpcO5Bn58IANCIIh8IgNC/////w+DIQkgCyAEQr+llJwPfnwgA0IgiHwiA0L/////D4MhCiAMIARChJfdowZ+fCADQiCIfCIDQv////8PgyELIA0gBELX2a6aBH58IANCIIh8IgNC/////w+DIQwgDiAEQrbP7tgEfnwgA0IgiHwiA0L/////D4MhDSAPIARCms3/ywN+fCADQiCIfCIDQv////8PgyEOIBAgBELqo4TQAX58IANCIIh8IgNC/////w+DIQ8gESADQiCIfCEQIAUgEiABNQIYIgR+fCIDQv////8PgyEFIAYgBCATfnwgA0IgiHwiA0L/////D4MhBiAHIAQgFH58IANCIIh8IgNC/////w+DIQcgCCAEIBV+fCADQiCIfCIDQv////8PgyEIIAkgBCAWfnwgA0IgiHwiA0L/////D4MhCSAKIAQgF358IANCIIh8IgNC/////w+DIQogCyAEIBh+fCADQiCIfCIDQv////8PgyELIAwgBCAZfnwgA0IgiHwiA0L/////D4MhDCANIAQgGn58IANCIIh8IgNC/////w+DIQ0gDiAEIBt+fCADQiCIfCIDQv////8PgyEOIA8gBCAcfnwgA0IgiHwiA0L/////D4MhDyAQIAQgHX58IANCIIh8IgNC/////w+DIRAgA0IgiCERIAUgBUL9//P/D35C/////w+DIgRCq9X+/w9+fEIgiCAGIARC///7zwt+fHwiA0L/////D4MhBSAHIARC///Pigt+fCADQiCIfCIDQv////8PgyEGIAggBEL+/6/1AX58IANCIIh8IgNC/////w+DIQcgCSAEQqTsw7UPfnwgA0IgiHwiA0L/////D4MhCCAKIARCoKXDuQZ+fCADQiCIfCIDQv////8PgyEJIAsgBEK/pZScD358IANCIIh8IgNC/////w+DIQogDCAEQoSX3aMGfnwgA0IgiHwiA0L/////D4MhCyANIARC19mumgR+fCADQiCIfCIDQv////8PgyEMIA4gBEK2z+7YBH58IANCIIh8IgNC/////w+DIQ0gDyAEQprN/8sDfnwgA0IgiHwiA0L/////D4MhDiAQIARC6qOE0AF+fCADQiCIfCIDQv////8PgyEPIBEgA0IgiHwhECAFIBIgATUCHCIEfnwiA0L/////D4MhBSAGIAQgE358IANCIIh8IgNC/////w+DIQYgByAEIBR+fCADQiCIfCIDQv////8PgyEHIAggBCAVfnwgA0IgiHwiA0L/////D4MhCCAJIAQgFn58IANCIIh8IgNC/////w+DIQkgCiAEIBd+fCADQiCIfCIDQv////8PgyEKIAsgBCAYfnwgA0IgiHwiA0L/////D4MhCyAMIAQgGX58IANCIIh8IgNC/////w+DIQwgDSAEIBp+fCADQiCIfCIDQv////8PgyENIA4gBCAbfnwgA0IgiHwiA0L/////D4MhDiAPIAQgHH58IANCIIh8IgNC/////w+DIQ8gECAEIB1+fCADQiCIfCIDQv////8PgyEQIANCIIghESAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DIQUgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4MhBiAIIARC/v+v9QF+fCADQiCIfCIDQv////8PgyEHIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DIQggCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4MhCSALIARCv6WUnA9+fCADQiCIfCIDQv////8PgyEKIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DIQsgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4MhDCAOIARCts/u2AR+fCADQiCIfCIDQv////8PgyENIA8gBEKazf/LA358IANCIIh8IgNC/////w+DIQ4gECAEQuqjhNABfnwgA0IgiHwiA0L/////D4MhDyARIANCIIh8IRAgBSASIAE1AiAiBH58IgNC/////w+DIQUgBiAEIBN+fCADQiCIfCIDQv////8PgyEGIAcgBCAUfnwgA0IgiHwiA0L/////D4MhByAIIAQgFX58IANCIIh8IgNC/////w+DIQggCSAEIBZ+fCADQiCIfCIDQv////8PgyEJIAogBCAXfnwgA0IgiHwiA0L/////D4MhCiALIAQgGH58IANCIIh8IgNC/////w+DIQsgDCAEIBl+fCADQiCIfCIDQv////8PgyEMIA0gBCAafnwgA0IgiHwiA0L/////D4MhDSAOIAQgG358IANCIIh8IgNC/////w+DIQ4gDyAEIBx+fCADQiCIfCIDQv////8PgyEPIBAgBCAdfnwgA0IgiHwiA0L/////D4MhECADQiCIIREgBSAFQv3/8/8PfkL/////D4MiBEKr1f7/D358QiCIIAYgBEL///vPC358fCIDQv////8PgyEFIAcgBEL//8+KC358IANCIIh8IgNC/////w+DIQYgCCAEQv7/r/UBfnwgA0IgiHwiA0L/////D4MhByAJIARCpOzDtQ9+fCADQiCIfCIDQv////8PgyEIIAogBEKgpcO5Bn58IANCIIh8IgNC/////w+DIQkgCyAEQr+llJwPfnwgA0IgiHwiA0L/////D4MhCiAMIARChJfdowZ+fCADQiCIfCIDQv////8PgyELIA0gBELX2a6aBH58IANCIIh8IgNC/////w+DIQwgDiAEQrbP7tgEfnwgA0IgiHwiA0L/////D4MhDSAPIARCms3/ywN+fCADQiCIfCIDQv////8PgyEOIBAgBELqo4TQAX58IANCIIh8IgNC/////w+DIQ8gESADQiCIfCEQIAUgEiABNQIkIgR+fCIDQv////8PgyEFIAYgBCATfnwgA0IgiHwiA0L/////D4MhBiAHIAQgFH58IANCIIh8IgNC/////w+DIQcgCCAEIBV+fCADQiCIfCIDQv////8PgyEIIAkgBCAWfnwgA0IgiHwiA0L/////D4MhCSAKIAQgF358IANCIIh8IgNC/////w+DIQogCyAEIBh+fCADQiCIfCIDQv////8PgyELIAwgBCAZfnwgA0IgiHwiA0L/////D4MhDCANIAQgGn58IANCIIh8IgNC/////w+DIQ0gDiAEIBt+fCADQiCIfCIDQv////8PgyEOIA8gBCAcfnwgA0IgiHwiA0L/////D4MhDyAQIAQgHX58IANCIIh8IgNC/////w+DIRAgA0IgiCERIAUgBUL9//P/D35C/////w+DIgRCq9X+/w9+fEIgiCAGIARC///7zwt+fHwiA0L/////D4MhBSAHIARC///Pigt+fCADQiCIfCIDQv////8PgyEGIAggBEL+/6/1AX58IANCIIh8IgNC/////w+DIQcgCSAEQqTsw7UPfnwgA0IgiHwiA0L/////D4MhCCAKIARCoKXDuQZ+fCADQiCIfCIDQv////8PgyEJIAsgBEK/pZScD358IANCIIh8IgNC/////w+DIQogDCAEQoSX3aMGfnwgA0IgiHwiA0L/////D4MhCyANIARC19mumgR+fCADQiCIfCIDQv////8PgyEMIA4gBEK2z+7YBH58IANCIIh8IgNC/////w+DIQ0gDyAEQprN/8sDfnwgA0IgiHwiA0L/////D4MhDiAQIARC6qOE0AF+fCADQiCIfCIDQv////8PgyEPIBEgA0IgiHwhECAFIBIgATUCKCIEfnwiA0L/////D4MhBSAGIAQgE358IANCIIh8IgNC/////w+DIQYgByAEIBR+fCADQiCIfCIDQv////8PgyEHIAggBCAVfnwgA0IgiHwiA0L/////D4MhCCAJIAQgFn58IANCIIh8IgNC/////w+DIQkgCiAEIBd+fCADQiCIfCIDQv////8PgyEKIAsgBCAYfnwgA0IgiHwiA0L/////D4MhCyAMIAQgGX58IANCIIh8IgNC/////w+DIQwgDSAEIBp+fCADQiCIfCIDQv////8PgyENIA4gBCAbfnwgA0IgiHwiA0L/////D4MhDiAPIAQgHH58IANCIIh8IgNC/////w+DIQ8gECAEIB1+fCADQiCIfCIDQv////8PgyEQIANCIIghESAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DIQUgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4MhBiAIIARC/v+v9QF+fCADQiCIfCIDQv////8PgyEHIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DIQggCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4MhCSALIARCv6WUnA9+fCADQiCIfCIDQv////8PgyEKIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DIQsgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4MhDCAOIARCts/u2AR+fCADQiCIfCIDQv////8PgyENIA8gBEKazf/LA358IANCIIh8IgNC/////w+DIQ4gECAEQuqjhNABfnwgA0IgiHwiA0L/////D4MhDyARIANCIIh8IRAgBSASIAE1AiwiBH58IgNC/////w+DIQUgBiAEIBN+fCADQiCIfCIDQv////8PgyEGIAcgBCAUfnwgA0IgiHwiA0L/////D4MhByAIIAQgFX58IANCIIh8IgNC/////w+DIQggCSAEIBZ+fCADQiCIfCIDQv////8PgyEJIAogBCAXfnwgA0IgiHwiA0L/////D4MhCiALIAQgGH58IANCIIh8IgNC/////w+DIQsgDCAEIBl+fCADQiCIfCIDQv////8PgyEMIA0gBCAafnwgA0IgiHwiA0L/////D4MhDSAOIAQgG358IANCIIh8IgNC/////w+DIQ4gDyAEIBx+fCADQiCIfCIDQv////8PgyEPIBAgBCAdfnwgA0IgiHwiA0L/////D4MhECADQiCIIREgAiAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DPgIAIAIgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4M+AgQgAiAIIARC/v+v9QF+fCADQiCIfCIDQv////8Pgz4CCCACIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DPgIMIAIgCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4M+AhAgAiALIARCv6WUnA9+fCADQiCIfCIDQv////8Pgz4CFCACIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DPgIYIAIgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4M+AhwgAiAOIARCts/u2AR+fCADQiCIfCIDQv////8Pgz4CICACIA8gBEKazf/LA358IANCIIh8IgNC/////w+DPgIkIAIgECAEQuqjhNABfnwgA0IgiHwiA0L/////D4M+AiggAiARIANCIIh8PgIsIAJByAUQBQRAIAJByAUgAhAHGgsLiEABG34gCiAANQIAIhEgEX58IgJC/////w+DIQogECAANQIEIhMgEX4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIRAgA0IgiEIBhiACQiCIfCAPIAA1AggiFCARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQ8gA0IgiEIBhiACQiCIfCAOIAA1AgwiFSARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQ4gA0IgiEIBhiACQiCIfCANIAA1AhAiFiARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQ0gA0IgiEIBhiACQiCIfCAMIAA1AhQiFyARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIAA1AhgiGCARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAJIAA1AhwiGSARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQkgA0IgiEIBhiACQiCIfCAIIAA1AiAiGiARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIAA1AiQiGyARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIAA1AigiHCARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQYgA0IgiEIBhiACQiCIfCAEIBEgADUCLCIRfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIBIgAkIgiHwhEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIBAgEyATfnwiAkL/////D4MhECAPIBMgFH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQ8gA0IgiEIBhiACQiCIfCAOIBMgFX4iA0L/////D4NCAYZ8fCICQv////8PgyEOIANCIIhCAYYgAkIgiHwgDSATIBZ+IgNC/////w+DQgGGfHwiAkL/////D4MhDSADQiCIQgGGIAJCIIh8IAwgEyAXfiIDQv////8Pg0IBhnx8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIBMgGH4iA0L/////D4NCAYZ8fCICQv////8PgyELIANCIIhCAYYgAkIgiHwgCSATIBl+IgNC/////w+DQgGGfHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAggEyAafiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBMgG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiATIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESATfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIA8gFCAUfnwiAkL/////D4MhDyAOIBQgFX4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQ4gA0IgiEIBhiACQiCIfCANIBQgFn4iA0L/////D4NCAYZ8fCICQv////8PgyENIANCIIhCAYYgAkIgiHwgDCAUIBd+IgNC/////w+DQgGGfHwiAkL/////D4MhDCADQiCIQgGGIAJCIIh8IAsgFCAYfiIDQv////8Pg0IBhnx8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAJIBQgGX4iA0L/////D4NCAYZ8fCICQv////8PgyEJIANCIIhCAYYgAkIgiHwgCCAUIBp+IgNC/////w+DQgGGfHwiAkL/////D4MhCCADQiCIQgGGIAJCIIh8IAcgFCAbfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIBQgHH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCARIBR+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCESIAogCkL9//P/D35C/////w+DIgNCq9X+/w9+fEIgiCAQIANC///7zwt+fHwiAkL/////D4MhCiAPIANC///Pigt+fCACQiCIfCICQv////8PgyEQIA4gA0L+/6/1AX58IAJCIIh8IgJC/////w+DIQ8gDSADQqTsw7UPfnwgAkIgiHwiAkL/////D4MhDiAMIANCoKXDuQZ+fCACQiCIfCICQv////8PgyENIAsgA0K/pZScD358IAJCIIh8IgJC/////w+DIQwgCSADQoSX3aMGfnwgAkIgiHwiAkL/////D4MhCyAIIANC19mumgR+fCACQiCIfCICQv////8PgyEJIAcgA0K2z+7YBH58IAJCIIh8IgJC/////w+DIQggBiADQprN/8sDfnwgAkIgiHwiAkL/////D4MhByAEIANC6qOE0AF+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCASIAJCIIh8IQUgDiAVIBV+fCICQv////8PgyEOIA0gFSAWfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhDSADQiCIQgGGIAJCIIh8IAwgFSAXfiIDQv////8Pg0IBhnx8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIBUgGH4iA0L/////D4NCAYZ8fCICQv////8PgyELIANCIIhCAYYgAkIgiHwgCSAVIBl+IgNC/////w+DQgGGfHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAggFSAafiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBUgG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAVIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAVfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIA0gFiAWfnwiAkL/////D4MhDSAMIBYgF34iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIBYgGH4iA0L/////D4NCAYZ8fCICQv////8PgyELIANCIIhCAYYgAkIgiHwgCSAWIBl+IgNC/////w+DQgGGfHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAggFiAafiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBYgG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAWIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAWfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAwgFyAXfnwiAkL/////D4MhDCALIBcgGH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAJIBcgGX4iA0L/////D4NCAYZ8fCICQv////8PgyEJIANCIIhCAYYgAkIgiHwgCCAXIBp+IgNC/////w+DQgGGfHwiAkL/////D4MhCCADQiCIQgGGIAJCIIh8IAcgFyAbfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIBcgHH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCARIBd+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCESIAogCkL9//P/D35C/////w+DIgNCq9X+/w9+fEIgiCAQIANC///7zwt+fHwiAkL/////D4MhCiAPIANC///Pigt+fCACQiCIfCICQv////8PgyEQIA4gA0L+/6/1AX58IAJCIIh8IgJC/////w+DIQ8gDSADQqTsw7UPfnwgAkIgiHwiAkL/////D4MhDiAMIANCoKXDuQZ+fCACQiCIfCICQv////8PgyENIAsgA0K/pZScD358IAJCIIh8IgJC/////w+DIQwgCSADQoSX3aMGfnwgAkIgiHwiAkL/////D4MhCyAIIANC19mumgR+fCACQiCIfCICQv////8PgyEJIAcgA0K2z+7YBH58IAJCIIh8IgJC/////w+DIQggBiADQprN/8sDfnwgAkIgiHwiAkL/////D4MhByAEIANC6qOE0AF+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCASIAJCIIh8IQUgCyAYIBh+fCICQv////8PgyELIAkgGCAZfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAggGCAafiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBggG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAYIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAYfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAkgGSAZfnwiAkL/////D4MhCSAIIBkgGn4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBkgG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAZIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAZfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAggGiAafnwiAkL/////D4MhCCAHIBogG34iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIBogHH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCARIBp+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCESIAogCkL9//P/D35C/////w+DIgNCq9X+/w9+fEIgiCAQIANC///7zwt+fHwiAkL/////D4MhCiAPIANC///Pigt+fCACQiCIfCICQv////8PgyEQIA4gA0L+/6/1AX58IAJCIIh8IgJC/////w+DIQ8gDSADQqTsw7UPfnwgAkIgiHwiAkL/////D4MhDiAMIANCoKXDuQZ+fCACQiCIfCICQv////8PgyENIAsgA0K/pZScD358IAJCIIh8IgJC/////w+DIQwgCSADQoSX3aMGfnwgAkIgiHwiAkL/////D4MhCyAIIANC19mumgR+fCACQiCIfCICQv////8PgyEJIAcgA0K2z+7YBH58IAJCIIh8IgJC/////w+DIQggBiADQprN/8sDfnwgAkIgiHwiAkL/////D4MhByAEIANC6qOE0AF+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCASIAJCIIh8IQUgByAbIBt+fCICQv////8PgyEHIAYgGyAcfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAbfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAYgHCAcfnwiAkL/////D4MhBiAEIBEgHH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAQgESARfnwiAkL/////D4MhBCAFIAJCIIh8IgJC/////w+DIQUgAkIgiCESIAEgCiAKQv3/8/8PfkL/////D4MiA0Kr1f7/D358QiCIIBAgA0L///vPC358fCICQv////8Pgz4CACABIA8gA0L//8+KC358IAJCIIh8IgJC/////w+DPgIEIAEgDiADQv7/r/UBfnwgAkIgiHwiAkL/////D4M+AgggASANIANCpOzDtQ9+fCACQiCIfCICQv////8Pgz4CDCABIAwgA0KgpcO5Bn58IAJCIIh8IgJC/////w+DPgIQIAEgCyADQr+llJwPfnwgAkIgiHwiAkL/////D4M+AhQgASAJIANChJfdowZ+fCACQiCIfCICQv////8Pgz4CGCABIAggA0LX2a6aBH58IAJCIIh8IgJC/////w+DPgIcIAEgByADQrbP7tgEfnwgAkIgiHwiAkL/////D4M+AiAgASAGIANCms3/ywN+fCACQiCIfCICQv////8Pgz4CJCABIAQgA0Lqo4TQAX58IAJCIIh8IgJC/////w+DPgIoIAEgBSACQiCIfCICQv////8Pgz4CLCASIAJCIIh8pwRAIAFByAUgARAHGgUgAUHIBRAFBEAgAUHIBSABEAcaCwsLCgAgACAAIAEQEwsLACAAQfgFIAEQEwsVACAAQfgREABBqBIQAUH4ESABEBILEQAgAEHYEhAXQdgSQbgHEAULIwAgABACBEBBAA8LIABBiBMQF0GIE0G4BxAFBEBBfw8LQQELFwAgACABEBcgAUHIBSABEA0gASABEBYLCQBBqAYgABAAC7wBAQJ/IAIQAUEwIQMDQCABIANPBEAgA0EwRgRAQbgTEBsFQbgTQfgFQbgTEBMLIABBuBNB6BMQEyACQegTIAIQDyAAQTBqIQAgA0EwaiEDDAELCyABQTBwIgRFBEAPC0HoExABQQAhAQNAIAEgBEZFBEAgASAALQAAOgDoEyAAQQFqIQAgAUEBaiEBDAELCyADQTBGBEBBuBMQGwVBuBNB+AVBuBMQEwtB6BNBuBNB6BMQEyACQegTIAIQDwscACABIAJBmBQQHEGYFEGYFBAWIABBmBQgAxATC+EBAQJ/QQBBACgCACIFIAJBAWpBMGxqNgIAIAUQGyAFQTBqIQUDQCACIAZHBEAgABACBEAgBUEwayAFEAAFIAAgBUEwayAFEBMLIAAgAWohACAFQTBqIQUgBkEBaiEGDAELCyAAIAFrIQAgAyACQQFrIARsaiECIAVBMGsiBSAFEBoDQCAGBEAgABACBEAgBSAFQTBrEAAgAhABBSAFQTBrQcgUEAAgBSAAIAVBMGsQEyAFQcgUIAIQEwsgACABayEAIAIgBGshAiAFQTBrIQUgBkEBayEGDAELC0EAIAU2AgALLQEBfwNAIAEgA0ZFBEAgACACEBYgAEEwaiEAIAJBMGohAiADQQFqIQMMAQsLCy0BAX8DQCABIANGRQRAIAAgAhAXIABBMGohACACQTBqIQIgA0EBaiEDDAELCwuXAgAgAkUEQCADEBsPCyAAQfgUEAAgAxAbA0AgAkEBayICIAFqLQAAIQAgAyADEBQgAEGAAU8EQCADQfgUIAMQEyAAQYABayEACyADIAMQFCAAQcAATwRAIANB+BQgAxATIABBQGohAAsgAyADEBQgAEEgTwRAIANB+BQgAxATIABBIGshAAsgAyADEBQgAEEQTwRAIANB+BQgAxATIABBEGshAAsgAyADEBQgAEEITwRAIANB+BQgAxATIABBCGshAAsgAyADEBQgAEEETwRAIANB+BQgAxATIABBBGshAAsgAyADEBQgAEECTwRAIANB+BQgAxATIABBAmshAAsgAyADEBQgAARAIANB+BQgAxATCyACDQALC9UBAQF/IAAQAgRAIAEQAQ8LQQEhAkGYCEGoFRAAIABB6AdBMEHYFRAhIABByAhBMEGIFhAhA0BB2BVBqAYQBEUEQEHYFUG4FhAUQQEhAANAQbgWQagGEARFBEBBuBZBuBYQFCAAQQFqIQAMAQsLQagVQegWEAAgAiAAa0EBayECA0AgAgRAQegWQegWEBQgAkEBayECDAELCyAAIQJB6BZBqBUQFEHYFUGoFUHYFRATQYgWQegWQYgWEBMMAQsLQYgWEBgEQEGIFiABEBEFQYgWIAEQAAsLIAAgABACBEBBAQ8LIABBiAdBMEGYFxAhQZgXQagGEAQLKgAgASAAKQMANwMAIAEgACkDCDcDCCABIAApAxA3AxAgASAAKQMYNwMYCx4AIABCADcDACAAQgA3AwggAEIANwMQIABCADcDGAssACAAKQMYUAR+IAApAxBQBH4gACkDCFAEfiAAKQMABUIBCwVCAQsFQgELUAseACAAQgE3AwAgAEIANwMIIABCADcDECAAQgA3AxgLQAAgACkDGCABKQMYUQR/IAApAxAgASkDEFEEfyAAKQMIIAEpAwhRBH8gACkDACABKQMAUQVBAAsFQQALBUEACwtzACAAKQMYIAEpAxhUBH9BAAUgACkDGCABKQMYVgR/QQEFIAApAxAgASkDEFQEf0EABSAAKQMQIAEpAxBWBH9BAQUgACkDCCABKQMIVAR/QQAFIAApAwggASkDCFYEf0EBBSAAKQMAIAEpAwBaCwsLCwsLC8QBAQF+IAIgADUCACABNQIAfCIDPgIAIAIgADUCBCABNQIEfCADQiCIfCIDPgIEIAIgADUCCCABNQIIfCADQiCIfCIDPgIIIAIgADUCDCABNQIMfCADQiCIfCIDPgIMIAIgADUCECABNQIQfCADQiCIfCIDPgIQIAIgADUCFCABNQIUfCADQiCIfCIDPgIUIAIgADUCGCABNQIYfCADQiCIfCIDPgIYIAIgADUCHCABNQIcfCADQiCIfCIDPgIcIANCIIinC/wBAQF+IAIgADUCACABNQIAfSIDQv////8Pgz4CACACIAA1AgQgATUCBH0gA0Igh3wiA0L/////D4M+AgQgAiAANQIIIAE1Agh9IANCIId8IgNC/////w+DPgIIIAIgADUCDCABNQIMfSADQiCHfCIDQv////8Pgz4CDCACIAA1AhAgATUCEH0gA0Igh3wiA0L/////D4M+AhAgAiAANQIUIAE1AhR9IANCIId8IgNC/////w+DPgIUIAIgADUCGCABNQIYfSADQiCHfCIDQv////8Pgz4CGCACIAA1AhwgATUCHH0gA0Igh3wiA0L/////D4M+AhwgA0Igh6cL5g4BEX4gBCAANQIAIgUgATUCACIGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AgAgBEIgiCEDIAMgBSABNQIEIgd+IARC/////w+DfCIEQiCIfCEDIAMgADUCBCIIIAZ+IARC/////w+DfCIEQiCIfCEDIAIgBD4CBCADQiCIIQQgBCAFIAE1AggiCX4gA0L/////D4N8IgNCIIh8IQQgBCAHIAh+IANC/////w+DfCIDQiCIfCEEIAQgADUCCCIKIAZ+IANC/////w+DfCIDQiCIfCEEIAIgAz4CCCAEQiCIIQMgAyAFIAE1AgwiC34gBEL/////D4N8IgRCIIh8IQMgAyAIIAl+IARC/////w+DfCIEQiCIfCEDIAMgByAKfiAEQv////8Pg3wiBEIgiHwhAyADIAA1AgwiDCAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AgwgA0IgiCEEIAQgBSABNQIQIg1+IANC/////w+DfCIDQiCIfCEEIAQgCCALfiADQv////8Pg3wiA0IgiHwhBCAEIAkgCn4gA0L/////D4N8IgNCIIh8IQQgBCAHIAx+IANC/////w+DfCIDQiCIfCEEIAQgADUCECIOIAZ+IANC/////w+DfCIDQiCIfCEEIAIgAz4CECAEQiCIIQMgAyAFIAE1AhQiD34gBEL/////D4N8IgRCIIh8IQMgAyAIIA1+IARC/////w+DfCIEQiCIfCEDIAMgCiALfiAEQv////8Pg3wiBEIgiHwhAyADIAkgDH4gBEL/////D4N8IgRCIIh8IQMgAyAHIA5+IARC/////w+DfCIEQiCIfCEDIAMgADUCFCIQIAZ+IARC/////w+DfCIEQiCIfCEDIAIgBD4CFCADQiCIIQQgBCAFIAE1AhgiEX4gA0L/////D4N8IgNCIIh8IQQgBCAIIA9+IANC/////w+DfCIDQiCIfCEEIAQgCiANfiADQv////8Pg3wiA0IgiHwhBCAEIAsgDH4gA0L/////D4N8IgNCIIh8IQQgBCAJIA5+IANC/////w+DfCIDQiCIfCEEIAQgByAQfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AhgiEiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AhggBEIgiCEDIAMgBSABNQIcIhN+IARC/////w+DfCIEQiCIfCEDIAMgCCARfiAEQv////8Pg3wiBEIgiHwhAyADIAogD34gBEL/////D4N8IgRCIIh8IQMgAyAMIA1+IARC/////w+DfCIEQiCIfCEDIAMgCyAOfiAEQv////8Pg3wiBEIgiHwhAyADIAkgEH4gBEL/////D4N8IgRCIIh8IQMgAyAHIBJ+IARC/////w+DfCIEQiCIfCEDIAMgADUCHCIFIAZ+IARC/////w+DfCIEQiCIfCEDIAIgBD4CHCADQiCIIQQgBCAIIBN+IANC/////w+DfCIDQiCIfCEEIAQgCiARfiADQv////8Pg3wiA0IgiHwhBCAEIAwgD34gA0L/////D4N8IgNCIIh8IQQgBCANIA5+IANC/////w+DfCIDQiCIfCEEIAQgCyAQfiADQv////8Pg3wiA0IgiHwhBCAEIAkgEn4gA0L/////D4N8IgNCIIh8IQQgBCAFIAd+IANC/////w+DfCIDQiCIfCEEIAIgAz4CICAEQiCIIQMgAyAKIBN+IARC/////w+DfCIEQiCIfCEDIAMgDCARfiAEQv////8Pg3wiBEIgiHwhAyADIA4gD34gBEL/////D4N8IgRCIIh8IQMgAyANIBB+IARC/////w+DfCIEQiCIfCEDIAMgCyASfiAEQv////8Pg3wiBEIgiHwhAyADIAUgCX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgIkIANCIIghBCAEIAwgE34gA0L/////D4N8IgNCIIh8IQQgBCAOIBF+IANC/////w+DfCIDQiCIfCEEIAQgDyAQfiADQv////8Pg3wiA0IgiHwhBCAEIA0gEn4gA0L/////D4N8IgNCIIh8IQQgBCAFIAt+IANC/////w+DfCIDQiCIfCEEIAIgAz4CKCAEQiCIIQMgAyAOIBN+IARC/////w+DfCIEQiCIfCEDIAMgECARfiAEQv////8Pg3wiBEIgiHwhAyADIA8gEn4gBEL/////D4N8IgRCIIh8IQMgAyAFIA1+IARC/////w+DfCIEQiCIfCEDIAIgBD4CLCADQiCIIQQgBCAQIBN+IANC/////w+DfCIDQiCIfCEEIAQgESASfiADQv////8Pg3wiA0IgiHwhBCAEIAUgD34gA0L/////D4N8IgNCIIh8IQQgAiADPgIwIARCIIghAyADIBIgE34gBEL/////D4N8IgRCIIh8IQMgAyAFIBF+IARC/////w+DfCIEQiCIfCEDIAIgBD4CNCADQiCIIQQgBCAFIBN+IANC/////w+DfCIDQiCIfCEEIAIgAz4COCACIAQ+AjwLzg0BDH4gAyAANQIAIgYgBn4gAkL/////D4N8IgJCIIh8IQMgASACPgIAIAMiBEIgiCEFIAA1AgQiByAGfiICQiCIQgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AgQgAyIEQiCIIQUgADUCCCIIIAZ+IgJCIIhCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAcgB34gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AgggAyIEQiCIIQUgADUCDCIJIAZ+IgJCIIghAyADIAcgCH4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AgwgAyIEQiCIIQUgADUCECIKIAZ+IgJCIIghAyADIAcgCX4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyAIIAh+IAJC/////w+DfCICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIQIAMiBEIgiCEFIAA1AhQiCyAGfiICQiCIIQMgAyAHIAp+IAJC/////w+DfCICQiCIfCEDIAMgCCAJfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CFCADIgRCIIghBSAANQIYIgwgBn4iAkIgiCEDIAMgByALfiACQv////8Pg3wiAkIgiHwhAyADIAggCn4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyAJIAl+IAJC/////w+DfCICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIYIAMiBEIgiCEFIAA1AhwiDSAGfiICQiCIIQMgAyAHIAx+IAJC/////w+DfCICQiCIfCEDIAMgCCALfiACQv////8Pg3wiAkIgiHwhAyADIAkgCn4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AhwgAyIEQiCIIQUgByANfiICQiCIIQMgAyAIIAx+IAJC/////w+DfCICQiCIfCEDIAMgCSALfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAogCn4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AiAgAyIEQiCIIQUgCCANfiICQiCIIQMgAyAJIAx+IAJC/////w+DfCICQiCIfCEDIAMgCiALfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CJCADIgRCIIghBSAJIA1+IgJCIIghAyADIAogDH4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyALIAt+IAJC/////w+DfCICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIoIAMiBEIgiCEFIAogDX4iAkIgiCEDIAMgCyAMfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CLCADIgRCIIghBSALIA1+IgJCIIhCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAwgDH4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AjAgAyIEQiCIIQUgDCANfiICQiCIQgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AjQgAyIEQiCIIQVCACECQgAhAyADIA0gDX4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AjggASADPgI8CwoAIAAgACABECwLsgMCA34BfyAAIANBiBggAxsiAxAkIAFByBcQJCACQegXIAIbIgcQJUGoGBAlQR8hAEEfIQEDQCABQcgXai0AACABQQNGckUEQCABQQFrIQEMAQsLIAFBxRdqNQAAQgF8IgZCAVEEQEIAQgCAGgsDQAJAA0AgACADai0AACAAQQdGckUEQCAAQQFrIQAMAQsLIAAgA2pBB2spAAAgBoAhBCAAIAFrQQRrIQIDQCAEQoCAgIBwg1AgAkEATnFFBEAgBEIIiCEEIAJBAWohAgwBCwsgBFAEQCADQcgXEClFDQFCASEEQQAhAgtByBhByBc1AAAgBH4iBT4AAEHMGEHMFzUAACAEfiAFQiCIfCIFPgAAQdAYQdAXNQAAIAR+IAVCIIh8IgU+AABB1BhB1Bc1AAAgBH4gBUIgiHwiBT4AAEHYGEHYFzUAACAEfiAFQiCIfCIFPgAAQdwYQdwXNQAAIAR+IAVCIIh8IgU+AABB4BhB4Bc1AAAgBH4gBUIgiHwiBT4AAEHkGEHkFzUAACAEfiAFQiCIfD4AACADQcgYIAJrIAMQKxogAiAHaiAEEAsMAQsLC44CAQp/QegYIQNB6BgQJUGIGSEIIAFBiBkQJEGoGSEJQagZECdByBkhBiAAQcgZECRB6BkhC0GIGiEKQegaIQQDQCAGECZFBEAgCCAGIAsgChAvIAsgCUGoGhAsIAcEfyAFBH9BqBogAxApBH9BqBogAyAEECsaQQAFIANBqBogBBArGkEBCwVBqBogAyAEECoaQQELBSAFBH9BqBogAyAEECoaQQAFIANBqBoQKQR/IANBqBogBBArGkEABUGoGiADIAQQKxpBAQsLCyEMIAMhACAJIQMgBCEJIAAhBCAFIQcgDCEFIAghACAGIQggCiEGIAAhCgwBCwsgBwRAIAEgAyACECsaBSADIAIQJAsLCQAgAEHIGxAoCywAIAAgASACECoEQCACQYgbIAIQKxoFIAJBiBsQKQRAIAJBiBsgAhArGgsLCxcAIAAgASACECsEQCACQYgbIAIQKhoLCwsAQegbIAAgARAzC7YPAQN+IAAgADUCAEL/////DyIEIAA1AgB+Qv////8PgyIDQYgbNQIAfnwiAj4CACAAIAA1AgQgAkIgiHxBjBs1AgAgA358IgI+AgQgACAANQIIIAJCIIh8QZAbNQIAIAN+fCICPgIIIAAgADUCDCACQiCIfEGUGzUCACADfnwiAj4CDCAAIAA1AhAgAkIgiHxBmBs1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QZwbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGgGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBpBs1AgAgA358IgI+AhxBqB0gAkIgiD4CACAAIAA1AgQgADUCBCAEfkL/////D4MiA0GIGzUCAH58IgI+AgQgACAANQIIIAJCIIh8QYwbNQIAIAN+fCICPgIIIAAgADUCDCACQiCIfEGQGzUCACADfnwiAj4CDCAAIAA1AhAgAkIgiHxBlBs1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QZgbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGcGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBoBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QaQbNQIAIAN+fCICPgIgQawdIAJCIIg+AgAgACAANQIIIAA1AgggBH5C/////w+DIgNBiBs1AgB+fCICPgIIIAAgADUCDCACQiCIfEGMGzUCACADfnwiAj4CDCAAIAA1AhAgAkIgiHxBkBs1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QZQbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGYGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBnBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QaAbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGkGzUCACADfnwiAj4CJEGwHSACQiCIPgIAIAAgADUCDCAANQIMIAR+Qv////8PgyIDQYgbNQIAfnwiAj4CDCAAIAA1AhAgAkIgiHxBjBs1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QZAbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGUGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBmBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QZwbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGgGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBpBs1AgAgA358IgI+AihBtB0gAkIgiD4CACAAIAA1AhAgADUCECAEfkL/////D4MiA0GIGzUCAH58IgI+AhAgACAANQIUIAJCIIh8QYwbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGQGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBlBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QZgbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGcGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBoBs1AgAgA358IgI+AiggACAANQIsIAJCIIh8QaQbNQIAIAN+fCICPgIsQbgdIAJCIIg+AgAgACAANQIUIAA1AhQgBH5C/////w+DIgNBiBs1AgB+fCICPgIUIAAgADUCGCACQiCIfEGMGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBkBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QZQbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGYGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBnBs1AgAgA358IgI+AiggACAANQIsIAJCIIh8QaAbNQIAIAN+fCICPgIsIAAgADUCMCACQiCIfEGkGzUCACADfnwiAj4CMEG8HSACQiCIPgIAIAAgADUCGCAANQIYIAR+Qv////8PgyIDQYgbNQIAfnwiAj4CGCAAIAA1AhwgAkIgiHxBjBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QZAbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGUGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBmBs1AgAgA358IgI+AiggACAANQIsIAJCIIh8QZwbNQIAIAN+fCICPgIsIAAgADUCMCACQiCIfEGgGzUCACADfnwiAj4CMCAAIAA1AjQgAkIgiHxBpBs1AgAgA358IgI+AjRBwB0gAkIgiD4CACAAIAA1AhwgADUCHCAEfkL/////D4MiA0GIGzUCAH58IgI+AhwgACAANQIgIAJCIIh8QYwbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGQGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBlBs1AgAgA358IgI+AiggACAANQIsIAJCIIh8QZgbNQIAIAN+fCICPgIsIAAgADUCMCACQiCIfEGcGzUCACADfnwiAj4CMCAAIAA1AjQgAkIgiHxBoBs1AgAgA358IgI+AjQgACAANQI4IAJCIIh8QaQbNQIAIAN+fCICPgI4QcQdIAJCIIg+AgBBqB0gAEEgaiABEDILiBwBE34gBSABNQIAIgQgADUCACIOfnwiA0L/////D4MhBSAGIAA1AgQiDyAEfnwgA0IgiHwiA0L/////D4MhBiAHIAA1AggiECAEfnwgA0IgiHwiA0L/////D4MhByAIIAA1AgwiESAEfnwgA0IgiHwiA0L/////D4MhCCAJIAA1AhAiEiAEfnwgA0IgiHwiA0L/////D4MhCSAKIAA1AhQiEyAEfnwgA0IgiHwiA0L/////D4MhCiALIAA1AhgiFCAEfnwgA0IgiHwiA0L/////D4MhCyAMIAA1AhwiFSAEfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIEIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIIIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIMIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIQIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIUIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIYIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIcIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gAiAFIAVC/////w9+Qv////8PgyIEfEIgiCAGIARC/////w9+fHwiA0L/////D4M+AgAgAiAHIARC/rf5/w9+fCADQiCIfCIDQv////8Pgz4CBCACIAggBEKCyPadBX58IANCIIh8IgNC/////w+DPgIIIAIgCSAEQoWwh80AfnwgA0IgiHwiA0L/////D4M+AgwgAiAKIARCiLDnmQN+fCADQiCIfCIDQv////8Pgz4CECACIAsgBELI+vXMAn58IANCIIh8IgNC/////w+DPgIUIAIgDCAEQtPOtp8HfnwgA0IgiHwiA0L/////D4M+AhggAiANIANCIIh8PgIcIAJBiBsQKQRAIAJBiBsgAhArGgsLsB0BE34gCCAANQIAIg0gDX58IgJC/////w+DIQggDCAANQIEIg8gDX4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIAA1AggiECANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAKIAA1AgwiESANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQogA0IgiEIBhiACQiCIfCAJIAA1AhAiEiANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQkgA0IgiEIBhiACQiCIfCAHIAA1AhQiEyANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIAA1AhgiFCANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQYgA0IgiEIBhiACQiCIfCAEIA0gADUCHCINfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIA4gAkIgiHwhDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAwgDyAPfnwiAkL/////D4MhDCALIA8gEH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAKIA8gEX4iA0L/////D4NCAYZ8fCICQv////8PgyEKIANCIIhCAYYgAkIgiHwgCSAPIBJ+IgNC/////w+DQgGGfHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAcgDyATfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIA8gFH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCANIA9+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCEOIAggCEL/////D35C/////w+DIgN8QiCIIAwgA0L/////D358fCICQv////8PgyEIIAsgA0L+t/n/D358IAJCIIh8IgJC/////w+DIQwgCiADQoLI9p0FfnwgAkIgiHwiAkL/////D4MhCyAJIANChbCHzQB+fCACQiCIfCICQv////8PgyEKIAcgA0KIsOeZA358IAJCIIh8IgJC/////w+DIQkgBiADQsj69cwCfnwgAkIgiHwiAkL/////D4MhByAEIANC0862nwd+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCAOIAJCIIh8IQUgCyAQIBB+fCICQv////8PgyELIAogECARfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhCiADQiCIQgGGIAJCIIh8IAkgECASfiIDQv////8Pg0IBhnx8IgJC/////w+DIQkgA0IgiEIBhiACQiCIfCAHIBAgE34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAQIBR+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgDSAQfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAogESARfnwiAkL/////D4MhCiAJIBEgEn4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQkgA0IgiEIBhiACQiCIfCAHIBEgE34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiARIBR+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgDSARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAkgEiASfnwiAkL/////D4MhCSAHIBIgE34iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIBIgFH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCANIBJ+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCEOIAggCEL/////D35C/////w+DIgN8QiCIIAwgA0L/////D358fCICQv////8PgyEIIAsgA0L+t/n/D358IAJCIIh8IgJC/////w+DIQwgCiADQoLI9p0FfnwgAkIgiHwiAkL/////D4MhCyAJIANChbCHzQB+fCACQiCIfCICQv////8PgyEKIAcgA0KIsOeZA358IAJCIIh8IgJC/////w+DIQkgBiADQsj69cwCfnwgAkIgiHwiAkL/////D4MhByAEIANC0862nwd+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCAOIAJCIIh8IQUgByATIBN+fCICQv////8PgyEHIAYgEyAUfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgDSATfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAYgFCAUfnwiAkL/////D4MhBiAEIA0gFH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAQgDSANfnwiAkL/////D4MhBCAFIAJCIIh8IgJC/////w+DIQUgAkIgiCEOIAEgCCAIQv////8PfkL/////D4MiA3xCIIggDCADQv////8Pfnx8IgJC/////w+DPgIAIAEgCyADQv63+f8PfnwgAkIgiHwiAkL/////D4M+AgQgASAKIANCgsj2nQV+fCACQiCIfCICQv////8Pgz4CCCABIAkgA0KFsIfNAH58IAJCIIh8IgJC/////w+DPgIMIAEgByADQoiw55kDfnwgAkIgiHwiAkL/////D4M+AhAgASAGIANCyPr1zAJ+fCACQiCIfCICQv////8Pgz4CFCABIAQgA0LTzrafB358IAJCIIh8IgJC/////w+DPgIYIAEgBSACQiCIfCICQv////8Pgz4CHCAOIAJCIIh8pwRAIAFBiBsgARArGgUgAUGIGxApBEAgAUGIGyABECsaCwsLCgAgACAAIAEQNgsLACAAQagbIAEQNgsVACAAQaghECRByCEQJUGoISABEDULEQAgAEHoIRA6QeghQagcECkLIwAgABAmBEBBAA8LIABBiCIQOkGIIkGoHBApBEBBfw8LQQELFwAgACABEDogAUGIGyABEDAgASABEDkLCQBByBsgABAkC7wBAQJ/IAIQJUEgIQMDQCABIANPBEAgA0EgRgRAQagiED4FQagiQagbQagiEDYLIABBqCJByCIQNiACQcgiIAIQMiAAQSBqIQAgA0EgaiEDDAELCyABQR9xIgRFBEAPC0HIIhAlQQAhAQNAIAEgBEZFBEAgASAALQAAOgDIIiAAQQFqIQAgAUEBaiEBDAELCyADQSBGBEBBqCIQPgVBqCJBqBtBqCIQNgtByCJBqCJByCIQNiACQcgiIAIQMgscACABIAJB6CIQP0HoIkHoIhA5IABB6CIgAxA2C+EBAQJ/QQBBACgCACIFIAJBAWpBBXRqNgIAIAUQPiAFQSBqIQUDQCACIAZHBEAgABAmBEAgBUEgayAFECQFIAAgBUEgayAFEDYLIAAgAWohACAFQSBqIQUgBkEBaiEGDAELCyAAIAFrIQAgAyACQQFrIARsaiECIAVBIGsiBSAFED0DQCAGBEAgABAmBEAgBSAFQSBrECQgAhAlBSAFQSBrQYgjECQgBSAAIAVBIGsQNiAFQYgjIAIQNgsgACABayEAIAIgBGshAiAFQSBrIQUgBkEBayEGDAELC0EAIAU2AgALLQEBfwNAIAEgA0ZFBEAgACACEDkgAEEgaiEAIAJBIGohAiADQQFqIQMMAQsLCy0BAX8DQCABIANGRQRAIAAgAhA6IABBIGohACACQSBqIQIgA0EBaiEDDAELCwuXAgAgAkUEQCADED4PCyAAQagjECQgAxA+A0AgAkEBayICIAFqLQAAIQAgAyADEDcgAEGAAU8EQCADQagjIAMQNiAAQYABayEACyADIAMQNyAAQcAATwRAIANBqCMgAxA2IABBQGohAAsgAyADEDcgAEEgTwRAIANBqCMgAxA2IABBIGshAAsgAyADEDcgAEEQTwRAIANBqCMgAxA2IABBEGshAAsgAyADEDcgAEEITwRAIANBqCMgAxA2IABBCGshAAsgAyADEDcgAEEETwRAIANBqCMgAxA2IABBBGshAAsgAyADEDcgAEECTwRAIANBqCMgAxA2IABBAmshAAsgAyADEDcgAARAIANBqCMgAxA2CyACDQALC9UBAQF/IAAQJgRAIAEQJQ8LQSAhAkHoHEHIIxAkIABByBxBIEHoIxBEIABBiB1BIEGIJBBEA0BB6CNByBsQKEUEQEHoI0GoJBA3QQEhAANAQagkQcgbEChFBEBBqCRBqCQQNyAAQQFqIQAMAQsLQcgjQcgkECQgAiAAa0EBayECA0AgAgRAQcgkQcgkEDcgAkEBayECDAELCyAAIQJByCRByCMQN0HoI0HII0HoIxA2QYgkQcgkQYgkEDYMAQsLQYgkEDsEQEGIJCABEDQFQYgkIAEQJAsLIAAgABAmBEBBAQ8LIABBiBxBIEHoJBBEQegkQcgbECgLFQAgACABQYglEDZBiCVBqBsgAhA2CwoAIAAgACABEEcLCwAgAEGIGyABEDALCQAgAEGoHBApCw4AIAAQAiAAQTBqEAJxCwoAIABB4ABqEAILDQAgABABIABBMGoQAQsVACAAEAEgAEEwahAbIABB4ABqEAELegAgASAAKQMANwMAIAEgACkDCDcDCCABIAApAxA3AxAgASAAKQMYNwMYIAEgACkDIDcDICABIAApAyg3AyggASAAKQMwNwMwIAEgACkDODcDOCABIAApA0A3A0AgASAAKQNINwNIIAEgACkDUDcDUCABIAApA1g3A1gLugEAIAEgACkDADcDACABIAApAwg3AwggASAAKQMQNwMQIAEgACkDGDcDGCABIAApAyA3AyAgASAAKQMoNwMoIAEgACkDMDcDMCABIAApAzg3AzggASAAKQNANwNAIAEgACkDSDcDSCABIAApA1A3A1AgASAAKQNYNwNYIAEgACkDYDcDYCABIAApA2g3A2ggASAAKQNwNwNwIAEgACkDeDcDeCABIAApA4ABNwOAASABIAApA4gBNwOIAQsoACAAEEsEQCABEE4FIAFB4ABqEBsgAEEwaiABQTBqEAAgACABEAALCxUAIAAgARAEIABBMGogAUEwahAEcQtyAQF/IAAQTARAIAEQSw8LIAEQSwRAQQAPCyAAQeAAaiICEA4EQCAAIAEQUg8LIAJB2CUQFCABQdglQYgmEBMgAkHYJUG4JhATIAFBMGpBuCZB6CYQEyAAQYgmEAQEQCAAQTBqQegmEAQE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AEEwaiABQTBqEBELIgAgACABEAAgAEEwaiABQTBqEBEgAEHgAGogAUHgAGoQAAsSACABQeg+EFogAEHoPiACEFcLEgAgAUH4PxBaIABB+D8gAhBYCxQAIAFBiMEAEFsgAEGIwQAgAhBZCxQAIAAgARAXIABBMGogAUEwahAXCyIAIAAgARAXIABBMGogAUEwahAXIABB4ABqIAFB4ABqEBcLFAAgACABEBYgAEEwaiABQTBqEBYLIgAgACABEBYgAEEwaiABQTBqEBYgAEHgAGogAUHgAGoQFgtTACAAEEwEQCABEAEgAUEwahABBSAAQeAAakGYwgAQGkGYwgBByMIAEBRBmMIAQcjCAEH4wgAQEyAAQcjCACABEBMgAEEwakH4wgAgAUEwahATCws4ACAAQTBqQajDABAUIABB2MMAEBQgAEHYwwBB2MMAEBNB2MMAQaglQdjDABAPQajDAEHYwwAQBAsQACAAQYjEABBjQYjEABBkC5gBAQN/QQBBACgCACIEIAFBMGxqNgIAIABB4ABqQZABIAEgBEEwEB4gBCEDA0AgASAFRwRAIAMQAgRAIAIQASACQTBqEAEFIAMgAEEwakHoxAAQEyADIAMQFCADIAAgAhATIANB6MQAIAJBMGoQEwsgAEGQAWohACACQeAAaiECIANBMGohAyAFQQFqIQUMAQsLQQAgBDYCAAtUACAAEEwEQCABEE4FIABB4ABqQZjFABAaQZjFAEHIxQAQFEGYxQBByMUAQfjFABATIABByMUAIAEQEyAAQTBqQfjFACABQTBqEBMgAUHgAGoQGwsLMgAgASACakEBayEBA0AgASACSEUEQCABIAAtAAA6AAAgAUEBayEBIABBAWohAAwBCwsLLQAgABBLBEAgARBNDwsgAEGoxgAQX0GoxgBBMCABEGhB2MYAQTAgAUEwahBoC0MAIAAQSwRAIAEQASABQcAAOgAADwsgAEGIxwAQF0GIxwBBMCABEGggAEEwahAZQX9GBEAgASABLQAAQYABcjoAAAsLMgAgAC0AAEHAAHEEQCABEE0PCyAAQTBBuMcAEGggAEEwakEwQejHABBoQbjHACABEGELwQEBAn8gAC0AACICQcAAcQRAIAEQTQ8LIAJBgAFxIQMgAEHIyAAQAEHIyAAgAkE/cToAAEHIyABBMEGYyAAQaEGYyAAg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A2g3A2ggASAAKQNwNwNwIAEgACkDeDcDeCABIAApA4ABNwOAASABIAApA4gBNwOIASABIAApA5ABNwOQASABIAApA5gBNwOYASABIAApA6ABNwOgASABIAApA6gBNwOoASABIAApA7ABNwOwASABIAApA7gBNwO4AQuSAwAgASAAKQMANwMAIAEgACkDCDcDCCABIAApAxA3AxAgASAAKQMYNwMYIAEgACkDIDcDICABIAApAyg3AyggASAAKQMwNwMwIAEgACkDODcDOCABIAApA0A3A0AgASAAKQNINwNIIAEgACkDUDcDUCABIAApA1g3A1ggASAAKQNgNwNgIAEgACkDaDcDaCABIAApA3A3A3AgASAAKQN4NwN4IAEgACkDgAE3A4ABIAEgACkDiAE3A4gBIAEgACkDkAE3A5ABIAEgACkDmAE3A5gBIAEgACkDoAE3A6ABIAEgACkDqAE3A6gBIAEgACkDsAE3A7ABIAEgACkDuAE3A7gBIAEgACkDwAE3A8ABIAEgACkDyAE3A8gBIAEgACkD0AE3A9ABIAEgACkD2AE3A9gBIAEgACkD4AE3A+ABIAEgACkD6AE3A+gBIAEgACkD8AE3A/ABIAEgACkD+AE3A/gBIAEgACkDgAI3A4ACIAEgACkDiAI3A4gCIAEgACkDkAI3A5ACIAEgACkDmAI3A5gCCy8AIAAQmwEEQCABEJ4BBSABQcABahCLASAAQeAAaiABQeAAahCMASAAIAEQjAELCxcAIAAgARBSIABB4ABqIAFB4ABqEFJxC4YBAQF/IAAQnAEEQCABEJsBDwsgARCbAQRAQQAPCyAAQcABaiICEIoBBEAgACABEKIBDwsgAkHYhwEQjwEgAUHYhwFBuIgBEI0BIAJB2IcBQZiJARCNASABQeAAakGYiQFB+IkBEI0BIABBuIgBEFIEQCAAQeAAakH4iQEQUgRAQQEPCwtBAAvQAQECfyAAEJwBBEAgARCcAQ8LIAEQnAEEQEEADwsgAEHAAWoiAhCKAQRAIAEgABCjAQ8LIAFBwAFqIgMQigEEQCAAIAEQowEPCyACQdiKARCPASADQbiLARCPASAAQbiLAUGYjAEQjQEgAUHYigFB+IwBEI0BIAJB2IoBQdiNARCNASADQbiLAUG4jgEQjQEgAEHgAGpBuI4BQZiPARCNASABQeAA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AEHgAGoQTSAAQcABahBNCycAIAAgARCMASAAQeAAaiABQeAAahCMASAAQcABaiABQcABahCMAQvlAgAgACABQYjcAhCNASAAQeAAaiABQeAAakHo3AIQjQEgAEHAAWogAUHAAWpByN0CEI0BIAAgAEHgAGpBqN4CEJABIAEgAUHgAGpBiN8CEJABIAAgAEHAAWpB6N8CEJABIAEgAUHAAWpByOACEJABIABB4ABqIABBwAFqQajhAhCQASABQeAAaiABQcABakGI4gIQkAFBiNwCQejcAkHo4gIQkAFBiNwCQcjdAkHI4wIQkAFB6NwCQcjdAkGo5AIQkAFBqOECQYjiAiACEI0BIAJBqOQCIAIQkQEgAiACEOQBQYjcAiACIAIQkAFBqN4CQYjfAiACQeAAahCNASACQeAAakHo4gIgAkHgAGoQkQFByN0CQYjlAhDkASACQeAAakGI5QIgAkHgAGoQkAFB6N8CQcjgAiACQcABahCNASACQcABakHI4wIgAkHAAWoQkQEgAkHAAWpB6NwCIAJBwAFqEJABC4ECACAAQejlAhCPASAAIABB4ABqQcjmAhCNAUHI5gJByOYCQajnAhCQASAAIABB4ABqQYjoAhCRAUGI6AIgAEHAAWpBiOgCEJABQYjoAkGI6AIQjwEgAEHgAGogAEHAAWpB6OgCEI0BQejoAkHo6AJByOkCEJABIABBwAFqQajqAhCPAUHI6QIgARDkAUHo5QIgASABEJABQajqAiABQeAAahDkAUGo5wIgAUHgAGogAUHgAGoQkAFB6OUCQajqAiABQcABahCQAUHI6QIgAUHAAWogAUHAAWoQkQFBiOgCIAFBwAFqIAFBwAFqEJABQajnAiABQcABaiABQcABahCQAQs1ACAAIAEgAhCQASAAQeAAaiABQeAAaiACQeAAahCQASAAQcABaiABQcABaiACQcABahCQAQs1ACAAIAEgAhCRASAAQeAAaiABQeAAaiACQeAAahCRASAAQcABaiABQcABaiACQcABahCRAQsnACAAIAEQkgEgAEHgAGogAUHgAGoQkgEgAEHAAWogAUHAAWoQkgELKwEBfyAAQcABahCVASIBBEAgAQ8LIABB4ABqEJUBIgEEQCABDwsgABCVAQsmACAAIAEQUiAAQeAAaiABQeAAahBScSAAQcABaiABQcAB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QeAAaiABIAJBwAFqEI0BQcjRAyABIAIQjQEgAiACQcABaiACEJEBIAIgAhDkAUHo0AMgASACQeAAahCNASACQeAAaiACQcABaiACQeAAahCRAQvsAQAgACABQajSAxCNASAAQeAAaiACQYjTAxCNASAAIABB4ABqQejTAxCQASAAIABBwAFqQcjUAxCQASAAQeAAaiAAQcABaiADEJABIAMgAiADEI0BIANBiNMDIAMQkQEgAyADEOQBIANBqNIDIAMQkAEgASACIANB4ABqEJABIANB4ABqQejTAyADQeAAahCNASADQeAAakGo0gMgA0HgAGoQkQEgA0HgAGpBiNMDIANB4ABqEJEBQcjUAyABIANBwAFqEI0BIANBwAFqQajSAyADQcABahCRASADQcABakGI0wMgA0HAAWoQkAELkAEAIAAgASACQajVAxCPAiAAQaACaiADQcjXAxCOAiACIANB6NkDEJABIABBoAJqIAAgBEGgAmoQ7AEgBEGgAmogAUHo2QMgBEGgAmoQjwIgBEGgAmpBqNUDIARBoAJqEO0BIARBoAJqQcjXAyAEQaACahDtAUHI1wMgBBDpASAEIAQQ9gEgBEGo1QMgBBDsAQtQACABIABBMGpByNoDEBMgAUEwaiAAQTBqQfjaAxATIAFB4ABqIABBqNsDEBMgAUGQAWogAEHY2wMQEyACIAFBwAFqQajbA0HI2gMgAhCQAgtsACAAQYj+BCABEI0BIABB4ABqQej+BCABQeAAahCNASAAQcABakHI/wQgAUHAAWoQjQEgAEGgAmpBqIAFIAFBoAJqEI0BIABBgANqQYiBBSABQYADahCNASAAQeADakHogQUgAUHgA2oQjQELigIAIAAgARAAIABBMGogAUEwahARIAFByIIFIAEQjQEgAEHgAGogAUHgAGoQACAAQZABaiABQZABahARIAFB4ABqQaiDBSABQeAAahCNASAAQcABaiABQcABahAAIABB8AFqIAFB8AFqEBEgAUHAAWpBiIQFIAFBwAFqEI0BIABBoAJqIAFBoAJqEAAgAEHQAmogAUHQAmoQESABQaACakHohAUgAUGgAmoQjQEgAEGAA2ogAUGAA2oQACAAQbADaiABQbADahARIAFBgANqQciFBSABQYADahCNASAAQeADaiABQeADahAAIABBkARqIAFBkARqEBEgAUHgA2pBqIYFIAFB4ANqEI0BC2wAIABBiIcFIAEQjQEgAEHgAGpB6IcFIAFB4ABqEI0BIABBwAFqQciIBSABQcABahCNASAAQaACakGoiQUgAUGgAmoQjQEgAEGAA2pBiIoFIAFBgANqEI0BIABB4ANqQeiKBSABQeADahCNAQuKAgAgACABEAAgAEEwaiABQTBqEBEgAUHIiwUgARCNASAAQeAAaiABQeAAahAAIABBkAFqIAFBkAFqEBEgAUHgAGpBqIwFIAFB4ABqEI0BIABBwAFqIAFBwAFqEAAgAEHwAWogAUHwAWoQESABQcABakGIjQUgAUHAAWoQjQEgAEGgAmogAUGgAmoQACAAQdACaiABQdACahARIAFBoAJqQeiNBSABQaACahCNASAAQYADaiABQYADahAAIABBsANqIAFBsANqEBEgAUGAA2pByI4FIAFBgANqEI0BIABB4ANqIAFB4ANqEAAgAEGQBGogAUGQBGoQESABQeADakGojwUgAUHgA2oQjQELbAAgAEGIkAUgARCNASAAQeAAakHokAUgAUHgAGoQjQEgAEHAAWpByJEFIAFBwAFqEI0BIABBoAJqQaiSBSABQaACahCNASAAQYADakGIkwUgAUGAA2oQjQEgAEHgA2pB6JMFIAFB4ANqEI0BC4oCACAAIAEQACAAQTBqIAFBMGoQESABQciUBSABEI0BIABB4ABqIAFB4ABqEAAgAEGQAWogAUGQAWoQESABQeAAakGolQUgAUHgAGoQjQEgAEHAAWogAUHAAWoQACAAQfABaiABQfABahARIAFBwAFqQYiWBSABQcABahCNASAAQaACaiABQaACahAAIABB0AJqIAFB0AJqEBEgAUGgAmpB6JYFIAFBoAJqEI0BIABBgANqIAFBgANqEAAgAEGwA2ogAUGwA2oQESABQYADakHIlwUgAUGAA2oQjQEgAEHgA2ogAUHgA2oQACAAQZAEaiABQZAEahARIAFB4ANqQaiYBSABQeADahCNAQtsACAAQYiZBSABEI0BIABB4ABqQeiZBSABQeAAahCNASAAQcABakHImgUgAUHAAWoQjQEgAEGgAmpBqJsFIAFBoAJqEI0BIABBgANqQYicBSABQYADahCNASAAQeADakHonAUgAUHgA2oQjQELigIAIAAgARAAIABBMGogAUEwahARIAFByJ0FIAEQjQEgAEHgAGogAUHgAGoQACAAQZABaiABQZABahARIAFB4ABqQaieBSABQeAAahCNASAAQcABaiABQcABahAAIABB8AFqIAFB8AFqEBEgAUHAAWpBiJ8FIAFBwAFqEI0BIABBoAJqIAFBoAJqEAAgAEHQAmogAUHQAmoQESABQaACakHonwUgAUGgAmoQjQEgAEGAA2ogAUGAA2oQACAAQbADaiABQbADahARIAFBgANqQcigBSABQYADahCNASAAQeADaiABQeADahAAIABBkARqIAFBkARqEBEgAUHgA2pBqKEFIAFB4ANqEI0BC2wAIABBiKIFIAEQjQEgAEHgAGpB6KIFIAFB4ABqEI0BIABBwAFqQcijBSABQcABahCNASAAQaACakGopAUgAUGgAmoQjQEgAEGAA2pBiKUFIAFBgANqEI0BIABB4ANqQeilBSABQeADahCNAQuKAgAgACABEAAgAEEwaiABQTBqEBEgAUHIpgUgARCNASAAQeAAaiABQeAAahAAIABBkAFqIAFBkAFqEBEgAUHgAGpBqKcFIAFB4ABqEI0BIABBwAFqIAFBwAFqEAAgAEHwAWogAUHwAWoQESABQcABakGIqAUgAUHAAWoQjQEgAEGgAmogAUGgAmoQACAAQdACaiABQdACahARIAFBoAJqQeioBSABQaACahCNASAAQYADaiABQYADahAAIABBsANqIAFBsANqEBEgAUGAA2pByKkFIAFBgANqEI0BIABB4ANqIAFB4ANqEAAgAEGQBGogAUGQBGoQESABQeADakGoqgUgAUHgA2oQjQELgwEAIAAQSwRAQQEPCyAAEGRFBEBBAA8LIABBiKsFQfirBRATIABBMGpBqKwFEAAgAEG4qwVBiK0FEBMgAEEwakG4rQUQAEH4qwVB+KsFEFVB+KsFIABB+KsFEF1B+KsFQYitBUH4qwUQXUH4qwVB6KsFQRBB+KsFEHhB+KsFQYitBRBTCxEAIABB6K0FEGNB6K0FEJwCC7MCACAAEJsBBEBBAQ8LIAAQtAFFBEBBAA8LIABByK4FQfCwBRCNASAAQeAAakHIrgVB0LEFEI0BQfCwBUGorwVBsLIFEI4BQdCxBUGQswUQkgFB8LAFQfCzBRCSAUHQsQVB2K8FQdC0BRCNAUGwsgVB4LIF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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHongMLoAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQYi8AwugAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBqNADC0AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAB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"; - const pq = 712; - const pr = 3464; - const pG1gen = 42968; - const pG1zero = 43112; - const pG1b = 4776; - const pG2gen = 43256; - const pG2zero = 43544; - const pG2b = 17272; - const pOneT = 43832; - const prePSize = 288; - const preQSize = 20448; - const q = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"; - const r = "52435875175126190479447740508185965837690552500527637822603658699938581184513"; - - // Module-local singleton cache. Must NOT be on globalThis: assigning to a frozen - // globalThis (e.g. a SES hardened-profile realm) throws at module load. - let curve_bls12381 = null; - - async function buildBls12381(singleThread, plugins) { - if ((!singleThread) && (curve_bls12381)) return curve_bls12381; - - const bls12381wasm = {}; - - { - // Vendored, uncompressed prebuilt wasm: static import (no runtime - // wasmcurves dependency, no dynamic import) and base64-decoded without - // atob/DecompressionStream, so it loads in Node, browsers and SES - // hardened realms alike. Also avoids recompiling the wasm on every load. - // Regenerate the vendored module with `npm run gen-wasm`. - bls12381wasm.code = base64ToUint8Array(code); - bls12381wasm.pq = pq; - bls12381wasm.pr = pr; - bls12381wasm.pG1gen = pG1gen; - bls12381wasm.pG1zero = pG1zero; - bls12381wasm.pG1b = pG1b; - bls12381wasm.pG2gen = pG2gen; - bls12381wasm.pG2zero = pG2zero; - bls12381wasm.pG2b = pG2b; - bls12381wasm.pOneT = pOneT; - bls12381wasm.prePSize = prePSize; - bls12381wasm.preQSize = preQSize; - bls12381wasm.n8q = 48; - bls12381wasm.n8r = 32; - bls12381wasm.q = q; - bls12381wasm.r = r; - } - - - // Batch-affine MSM helper module (curve-independent; links against the - // main module's exports + memory at runtime in each worker). - bls12381wasm.batchCode = base64ToUint8Array(code$1); - // The batch module's GLV path carries bls12-381 G1 constants too (G2 GLS - // is bn254-only; the wasm falls through internally for bls G2 sizes). - bls12381wasm.glv = true; - - const params = { - name: "bls12381", - wasm: bls12381wasm, - q: e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16), - r: e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16), - n8q: 48, - n8r: 32, - cofactorG1: e("0x396c8c005555e1568c00aaab0000aaab", 16), - cofactorG2: e("0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5", 16), - singleThread: singleThread ? true : false - }; - - const curve = await buildEngine(params); - curve.terminate = async function () { - if (!params.singleThread) { - curve_bls12381 = null; - await this.tm.terminate(); - } - }; - - if (!singleThread) { - curve_bls12381 = curve; - } - - return curve; - } - - const bls12381r$2 = e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); - const bn128r$2 = e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - - e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16); - e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); - - async function getCurveFromR$1(r, singleThread, plugins) { - let curve; - if (eq(r, bn128r$2)) { - curve = await buildBn128(singleThread); - } else if (eq(r, bls12381r$2)) { - curve = await buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${toString(r)}`); - } - return curve; - } - - const Scalar=_Scalar; - const utils = _utils; - - var fs = {}; - - async function open$2(fileName, openFlags, cacheSize, pageSize) { - cacheSize = cacheSize || 4096*64; - if (typeof openFlags !== "number" && ["w+", "wx+", "r", "ax+", "a+"].indexOf(openFlags) <0) - throw new Error("Invalid open option"); - const fd =await fs.promises.open(fileName, openFlags); - - const stats = await fd.stat(); - - return new FastFile$2(fd, stats, cacheSize, pageSize, fileName); - } - - - let FastFile$2 = class FastFile { - - constructor(fd, stats, cacheSize, pageSize, fileName) { - this.fileName = fileName; - this.fd = fd; - this.pos = 0; - this.pageSize = pageSize || (1 << 8); - while (this.pageSize < stats.blksize) { - this.pageSize *= 2; - } - this.totalSize = stats.size; - this.totalPages = Math.floor((stats.size -1) / this.pageSize)+1; - this.maxPagesLoaded = Math.floor( cacheSize / this.pageSize)+1; - // Reads/writes at least this large bypass the page cache and move bytes - // straight between disk and the caller's buffer (see readToBuffer / - // write), avoiding the extra buffer<->page copy that dominates large - // sequential transfers (e.g. zkey/ptau sections). - this.directReadThreshold = 1 << 20; - this.directWriteThreshold = 1 << 20; - this.pages = {}; - this.pendingLoads = []; - this.writing = false; - this.reading = false; - this.avBuffs = []; - this.history = {}; - } - - _loadPage(p) { - const self = this; - const P = new Promise((resolve, reject)=> { - self.pendingLoads.push({ - page: p, - resolve: resolve, - reject: reject - }); - }); - self.__statusPage("After Load request: ", p); - return P; - } - - __statusPage(s, p) { - const logEntry = []; - const self=this; - if (!self.logHistory) return; - logEntry.push("==" + s+ " " +p); - let S = ""; - for (let i=0; i " + self.history[p][i][j]); - } - } - } - - - - _triggerLoad() { - const self = this; - - if (self.reading) return; - if (self.pendingLoads.length==0) return; - - const pageIdxs = Object.keys(self.pages); - - const deletablePages = []; - for (let i=0; i0) && - ( (typeof self.pages[self.pendingLoads[0].page] != "undefined" ) - ||( (freePages>0) - ||(deletablePages.length>0)))) { - const load = self.pendingLoads.shift(); - if (typeof self.pages[load.page] != "undefined") { - self.pages[load.page].pendingOps ++; - const idx = deletablePages.indexOf(load.page); - if (idx>=0) deletablePages.splice(idx, 1); - if (self.pages[load.page].loading) { - self.pages[load.page].loading.push(load); - } else { - load.resolve(); - } - self.__statusPage("After Load (cached): ", load.page); - - } else { - if (freePages) { - freePages--; - } else { - const fp = deletablePages.shift(); - self.__statusPage("Before Unload: ", fp); - self.avBuffs.unshift(self.pages[fp]); - delete self.pages[fp]; - self.__statusPage("After Unload: ", fp); - } - - if (load.page>=self.totalPages) { - self.pages[load.page] = getNewPage(); - load.resolve(); - self.__statusPage("After Load (new): ", load.page); - } else { - self.reading = true; - self.pages[load.page] = getNewPage(); - self.pages[load.page].loading = [load]; - ops.push(self.fd.read(self.pages[load.page].buff, 0, self.pageSize, load.page*self.pageSize).then((res)=> { - self.pages[load.page].size = res.bytesRead; - const loading = self.pages[load.page].loading; - delete self.pages[load.page].loading; - for (let i=0; i { - load.reject(err); - })); - self.__statusPage("After Load (loading): ", load.page); - } - } - } - // if (ops.length>1) console.log(ops.length); - - Promise.all(ops).then( () => { - self.reading = false; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - self._tryClose(); - }); - - function getNewPage() { - if (self.avBuffs.length>0) { - const p = self.avBuffs.shift(); - p.dirty = false; - p.pendingOps = 1; - p.size =0; - return p; - } else { - return { - dirty: false, - buff: new Uint8Array(self.pageSize), - pendingOps: 1, - size: 0 - }; - } - } - - } - - - _triggerWrite() { - const self = this; - if (self.writing) return; - - const pageIdxs = Object.keys(self.pages); - - const ops = []; - - for (let i=0; i { - page.writing = false; - return; - }, (err) => { - console.log("ERROR Writing: "+err); - self.error = err; - self._tryClose(); - })); - } - } - - if (self.writing) { - Promise.all(ops).then( () => { - self.writing = false; - setImmediate(self._triggerWrite.bind(self)); - self._tryClose(); - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - }); - } - } - - _getDirtyPage() { - for (let p in this.pages) { - if (this.pages[p].dirty) return p; - } - return -1; - } - - // Iterate the actually-cached pages (usually few) rather than every page - // index in [firstPage, lastPage], so the check stays O(cached pages) even - // for very large ranges / small page sizes. - _rangeHasCachedPages(pos, len) { - const firstPage = Math.floor(pos / this.pageSize); - const lastPage = Math.floor((pos + len - 1) / this.pageSize); - for (const k of Object.keys(this.pages)) { - const p = +k; - if (p >= firstPage && p <= lastPage) return true; - } - return false; - } - - async write(buff, pos) { - if (buff.byteLength == 0) return; - const self = this; - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+buff.byteLength; - if (self.totalSize < pos + buff.byteLength) self.totalSize = pos + buff.byteLength; - if (self.pendingClose) - throw new Error("Writing a closing file"); - - // Direct-write fast path: for large writes to a region with no cached - // pages, write straight to disk, skipping the buff->page copy and the - // deferred page flush. Any cached page in range (even clean) would go - // stale after a direct write, so we fall back to the cached path then. - // ArrayBuffer.isView gate: fd.write needs a real TypedArray/DataView; a - // BigBuffer (paged, not a view) must use the cached path. - if (buff.byteLength >= self.directWriteThreshold && ArrayBuffer.isView(buff) && !self._rangeHasCachedPages(pos, buff.byteLength)) { - let done = 0; - while (done < buff.byteLength) { - const { bytesWritten } = await self.fd.write(buff, done, buff.byteLength - done, pos + done); - if (bytesWritten === 0) break; // should not happen - done += bytesWritten; - } - const lastPage = Math.floor((pos + buff.byteLength - 1) / self.pageSize); - if (lastPage + 1 > self.totalPages) self.totalPages = lastPage + 1; - return; - } - - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + buff.byteLength -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - let r = buff.byteLength; - while (r>0) { - await pagePromises[p-firstPage]; - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = buff.slice( buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.pages[p].buff.buffer, o, l); - dstView.set(srcView); - self.pages[p].dirty = true; - self.pages[p].pendingOps --; - self.pages[p].size = Math.max(o+l, self.pages[p].size); - if (p>=self.totalPages) { - self.totalPages = p+1; - } - r = r-l; - p ++; - o = 0; - if (!self.writing) setImmediate(self._triggerWrite.bind(self)); - } - } - - async read(len, pos) { - const self = this; - let buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - // Iterate the actually-cached pages (usually few) rather than every page - // index in [firstPage, lastPage], so the check stays O(cached pages) even - // for very large ranges / small page sizes. - _rangeHasDirtyPages(pos, len) { - const firstPage = Math.floor(pos / this.pageSize); - const lastPage = Math.floor((pos + len - 1) / this.pageSize); - for (const k of Object.keys(this.pages)) { - const p = +k; - if (p >= firstPage && p <= lastPage) { - const page = this.pages[p]; - if (page.dirty || page.writing) return true; - } - } - return false; - } - - async readToBuffer(buffDst, offset, len, pos) { - if (len == 0) { - return; - } - const self = this; - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+len; - if (self.pendingClose) - throw new Error("Reading a closing file"); - - // Direct-read fast path: for large reads with no overlapping unwritten - // (dirty) pages, copy straight from disk into the destination buffer. - // This skips the page cache and the page->destination copy it incurs, - // which dominates large sequential reads (e.g. zkey/ptau sections). - // ArrayBuffer.isView gate: the direct path hands buffDst to fd.read, which - // needs a real TypedArray/DataView. A BigBuffer (paged, not a view) must - // go through the cached path, which copies into it via its own .set(). - if (len >= self.directReadThreshold && ArrayBuffer.isView(buffDst) && !self._rangeHasDirtyPages(pos, len)) { - let toRead = (pos + len > self.totalSize) ? (self.totalSize - pos) : len; - if (toRead < 0) toRead = 0; - let done = 0; - while (done < toRead) { - const { bytesRead } = await self.fd.read(buffDst, offset + done, toRead - done, pos + done); - if (bytesRead === 0) break; // EOF - done += bytesRead; - } - return; - } - - if (len > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(len * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + len -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - // Remaining bytes to read - let r = pos + len > self.totalSize ? len - (pos + len - self.totalSize): len; - while (r>0) { - await pagePromises[p - firstPage]; - self.__statusPage("After Await (read): ", p); - - // bytes to copy from this page - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = new Uint8Array(self.pages[p].buff.buffer, self.pages[p].buff.byteOffset + o, l); - buffDst.set(srcView, offset+len-r); - self.pages[p].pendingOps --; - - self.__statusPage("After Op done: ", p); - - r = r-l; - p ++; - o = 0; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - } - - this.pos = pos + len; - - } - - - _tryClose() { - const self = this; - if (!self.pendingClose) return; - if (self.error) { - self.pendingCloseReject(self.error); - } - const p = self._getDirtyPage(); - if ((p>=0) || (self.writing) || (self.reading) || (self.pendingLoads.length>0)) return; - self.pendingClose(); - } - - close() { - const self = this; - if (self.pendingClose) - throw new Error("Closing the file twice"); - return new Promise((resolve, reject) => { - self.pendingClose = resolve; - self.pendingCloseReject = reject; - self._tryClose(); - }).then(()=> { - self.fd.close(); - }, (err) => { - self.fd.close(); - throw (err); - }); - } - - async discard() { - const self = this; - await self.close(); - await fs.promises.unlink(this.fileName); - } - - async writeULE32(v, pos) { - const self = this; - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, true); - - await self.write(tmpBuff32, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, false); - - await self.write(tmpBuff32, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - const tmpBuff64 = new Uint8Array(8); - const tmpBuff64v = new DataView(tmpBuff64.buffer); - - tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64, pos); - } - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - if (self.pendingClose) { - throw new Error("Reading a closing file"); - } - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - let currentPage = Math.floor(currentPosition / self.pageSize); - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - //Read page - let pagePromise = self._loadPage(currentPage); - self._triggerLoad(); - await pagePromise; - self.__statusPage("After Await (read): ", currentPage); - - let offsetOnPage = currentPosition % self.pageSize; - - const dataArray = new Uint8Array( - self.pages[currentPage].buff.buffer, - self.pages[currentPage].buff.byteOffset + offsetOnPage, - self.pageSize - offsetOnPage - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * this.pageSize + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * this.pageSize + offsetOnPage + dataArray.length; - } - - self.pages[currentPage].pendingOps--; - self.__statusPage("After Op done: ", currentPage); - - currentPosition = self.pos; - currentPage++; - - if (self.pendingLoads.length > 0) setImmediate(self._triggerLoad.bind(self)); - } - - return str; - } - }; - - function createNew$3(o) { - const initialSize = o.initialSize || 1<<20; - const fd = new MemFile$2(); - fd.o = o; - fd.o.data = new Uint8Array(initialSize); - fd.allocSize = initialSize; - fd.totalSize = 0; - fd.readOnly = false; - fd.pos = 0; - return fd; - } - - function readExisting$8(o) { - const fd = new MemFile$2(); - fd.o = o; - fd.allocSize = o.data.byteLength; - fd.totalSize = o.data.byteLength; - fd.readOnly = true; - fd.pos = 0; - return fd; - } - - const tmpBuff32$5 = new Uint8Array(4); - const tmpBuff32v$5 = new DataView(tmpBuff32$5.buffer); - const tmpBuff64$5 = new Uint8Array(8); - const tmpBuff64v$5 = new DataView(tmpBuff64$5.buffer); - - let MemFile$2 = class MemFile { - - constructor() { - this.pageSize = 1 << 14; // for compatibility - } - - _resizeIfNeeded(newLen) { - if (newLen > this.allocSize) { - const newAllocSize = Math.max( - this.allocSize + (1 << 20), - Math.floor(this.allocSize * 1.1), - newLen - ); - const newData = new Uint8Array(newAllocSize); - newData.set(this.o.data); - this.o.data = newData; - this.allocSize = newAllocSize; - } - } - - async write(buff, pos) { - const self =this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) throw new Error("Writing a read only file"); - - this._resizeIfNeeded(pos + buff.byteLength); - - this.o.data.set(buff.slice(), pos); - - if (pos + buff.byteLength > this.totalSize) this.totalSize = pos + buff.byteLength; - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDest, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const buffSrc = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + pos, len); - - buffDest.set(buffSrc, offset); - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - - const buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - if (this.o.data.byteLength != this.totalSize) { - this.o.data = this.o.data.slice(0, this.totalSize); - } - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$5.setUint32(0, v, true); - - await self.write(tmpBuff32$5, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$5.setUint32(0, v, false); - - await self.write(tmpBuff32$5, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$5.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$5.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$5, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - const dataArray = new Uint8Array( - self.o.data.buffer, - currentPosition, - this.totalSize - currentPosition - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - let endOfStringFound = indexEndOfString !== -1; - - let str = ""; - if (endOfStringFound) { - str = new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPosition + indexEndOfString + 1; - } else { - self.pos = currentPosition; - } - return str; - } - }; - - const PAGE_SIZE$2 = 1<<22; - - function createNew$2(o) { - const initialSize = o.initialSize || 0; - const fd = new BigMemFile$2(); - fd.o = o; - const nPages = initialSize ? Math.floor((initialSize - 1) / PAGE_SIZE$2)+1 : 0; - fd.o.data = []; - for (let i=0; i0) { - const l = (o+r > PAGE_SIZE$2) ? (PAGE_SIZE$2 -o) : r; - const srcView = buff.slice(buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.o.data[p].buffer, o, l); - dstView.set(srcView); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDst, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const firstPage = Math.floor(pos / PAGE_SIZE$2); - - let p = firstPage; - let o = pos % PAGE_SIZE$2; - // Remaining bytes to read - let r = len; - while (r>0) { - // bytes to copy from this page - const l = (o+r > PAGE_SIZE$2) ? (PAGE_SIZE$2 -o) : r; - const srcView = new Uint8Array(self.o.data[p].buffer, o, l); - buffDst.set(srcView, offset+len-r); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - const buff = new Uint8Array(len); - - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$4.setUint32(0, v, true); - - await self.write(tmpBuff32$4, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$4.setUint32(0, v, false); - - await self.write(tmpBuff32$4, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$4.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$4.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$4, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - const fixedSize = 2048; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - let currentPage = Math.floor(currentPosition / PAGE_SIZE$2); - let offsetOnPage = currentPosition % PAGE_SIZE$2; - - if (self.o.data[currentPage] === undefined) { - throw new Error("ERROR"); - } - - let readLength = Math.min(fixedSize, self.o.data[currentPage].length - offsetOnPage); - const dataArray = new Uint8Array(self.o.data[currentPage].buffer, offsetOnPage, readLength); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * PAGE_SIZE$2 + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * PAGE_SIZE$2 + offsetOnPage + dataArray.length; - } - - currentPosition = self.pos; - } - return str; - } - }; - - const O_TRUNC = 512; - const O_CREAT = 64; - const O_RDWR = 2; - const O_RDONLY = 0; - - const DEFAULT_CACHE_SIZE$1 = (1 << 16); - const DEFAULT_PAGE_SIZE$1 = (1 << 13); - - // Robust Node detection that never throws (unlike `true`, which is a - // webpack-ism and is undefined under Vite/esbuild/SES). - const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null; - - - async function createOverride$1(o, b, c) { - if (typeof o === "string") { - o = { - type: "file", - fileName: o, - cacheSize: b || DEFAULT_CACHE_SIZE$1, - pageSize: c || DEFAULT_PAGE_SIZE$1 - }; - } - if (o.type == "file") { - return await open$2(o.fileName, O_TRUNC | O_CREAT | O_RDWR, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return createNew$3(o); - } else if (o.type == "bigMem") { - return createNew$2(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } - } - - async function readExisting$6(o, b, c) { - if (o instanceof Uint8Array) { - o = { - type: "mem", - data: o - }; - } - if (!isNode) { - if (typeof o === "string") { - const buff = await fetch(o).then( function(res) { - return res.arrayBuffer(); - }).then(function (ab) { - return new Uint8Array(ab); - }); - o = { - type: "mem", - data: buff - }; - } - } else { - if (typeof o === "string") { - o = { - type: "file", - fileName: o, - cacheSize: b || DEFAULT_CACHE_SIZE$1, - pageSize: c || DEFAULT_PAGE_SIZE$1 - }; - } - } - if (o.type == "file") { - return await open$2(o.fileName, O_RDONLY, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return await readExisting$8(o); - } else if (o.type == "bigMem") { - return await readExisting$7(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } - } - - // 1 GiB threshold (matched to BigBuffer's page size): sections at/above this are - // read into a paged BigBuffer instead of one flat Uint8Array. - const MAX_BUFFER_SIZE = 1 << 30; - - async function readBinFile$1(fileName, type, maxVersion, cacheSize, pageSize) { - - const fd = await readExisting$6(fileName, cacheSize, pageSize); - - const b = await fd.read(4); - let readedType = ""; - for (let i=0; i<4; i++) readedType += String.fromCharCode(b[i]); - - if (readedType != type) throw new Error(fileName + ": Invalid File format"); - - let v = await fd.readULE32(); - - if (v>maxVersion) throw new Error("Version not supported"); - - const nSections = await fd.readULE32(); - - // Scan sections - let sections = []; - for (let i=0; i1) throw new Error(fd.fileName +": Section Duplicated " +idSection); - - fd.pos = sections[idSection][0].p; - - fd.readingSection = sections[idSection][0]; - } - - async function endReadSection$1(fd, noCheck) { - if (typeof fd.readingSection === "undefined") throw new Error("Not reading a section"); - if (!noCheck) { - if (fd.pos-fd.readingSection.p != fd.readingSection.size) throw new Error("Invalid section size reading"); - } - delete fd.readingSection; - } - - async function writeBigInt(fd, n, n8, pos) { - const buff = new Uint8Array(n8); - Scalar.toRprLE(buff, 0, n, n8); - await fd.write(buff, pos); - } - - async function readBigInt$1(fd, n8, pos) { - const buff = await fd.read(n8, pos); - return Scalar.fromRprLE(buff, 0, n8); - } - - async function copySection(fdFrom, sections, fdTo, sectionId, size) { - if (typeof size === "undefined") { - size = sections[sectionId][0].size; - } - const chunkSize = fdFrom.pageSize; - await startReadUniqueSection$1(fdFrom, sections, sectionId); - await startWriteSection(fdTo, sectionId); - for (let p=0; p sections[idSection][0].size) { - throw new Error("Reading out of the range of the section"); - } - - let buff; - if (length < MAX_BUFFER_SIZE) { - buff = new Uint8Array(length); - } else { - buff = new BigBuffer(length); - } - - await fd.readToBuffer(buff, 0, length, sections[idSection][0].p + offset); - - - return buff; - } - - - async function sectionIsEqual(fd1, sections1, fd2, sections2, idSection) { - const MAX_BUFF_SIZE = fd1.pageSize * 16; - await startReadUniqueSection$1(fd1, sections1, idSection); - await startReadUniqueSection$1(fd2, sections2, idSection); - if (sections1[idSection][0].size != sections2[idSection][0].size) return false; - const totalBytes=sections1[idSection][0].size; - for (let i=0; i= 0) { - curve = await buildBn128(singleThread); - } else if (["BLS12381"].indexOf(normName) >= 0) { - curve = await buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${name}`); - } - return curve; - - function normalizeName(n) { - return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); - } - - } - - var curves = /*#__PURE__*/Object.freeze({ - __proto__: null, - getCurveFromName: getCurveFromName, - getCurveFromQ: getCurveFromQ, - getCurveFromR: getCurveFromR - }); - - /** - * Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. - * @param a - value to test - * @returns `true` when the value is a Uint8Array-compatible view. - * @example - * Check whether a value is a Uint8Array-compatible view. - * ```ts - * isBytes(new Uint8Array([1, 2, 3])); - * ``` - */ - function isBytes(a) { - // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases. - // The fallback still requires a real ArrayBuffer view, so plain - // JSON-deserialized `{ constructor: ... }` spoofing is rejected, and - // `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views. - return (a instanceof Uint8Array || - (ArrayBuffer.isView(a) && - a.constructor.name === 'Uint8Array' && - 'BYTES_PER_ELEMENT' in a && - a.BYTES_PER_ELEMENT === 1)); - } - /** - * Asserts something is a non-negative integer. - * @param n - number to validate - * @param title - label included in thrown errors - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validate a non-negative integer option. - * ```ts - * anumber(32, 'length'); - * ``` - */ - function anumber(n, title = '') { - if (typeof n !== 'number') { - const prefix = title && `"${title}" `; - throw new TypeError(`${prefix}expected number, got ${typeof n}`); - } - if (!Number.isSafeInteger(n) || n < 0) { - const prefix = title && `"${title}" `; - throw new RangeError(`${prefix}expected integer >= 0, got ${n}`); - } - } - /** - * Asserts something is Uint8Array. - * @param value - value to validate - * @param length - optional exact length constraint - * @param title - label included in thrown errors - * @returns The validated byte array. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validate that a value is a byte array. - * ```ts - * abytes(new Uint8Array([1, 2, 3])); - * ``` - */ - function abytes(value, length, title = '') { - const bytes = isBytes(value); - const len = value?.length; - const needsLen = length !== undefined; - if (!bytes || (needsLen && len !== length)) { - const prefix = title && `"${title}" `; - const ofLen = needsLen ? ` of length ${length}` : ''; - const got = bytes ? `length=${len}` : `type=${typeof value}`; - const message = prefix + 'expected Uint8Array' + ofLen + ', got ' + got; - if (!bytes) - throw new TypeError(message); - throw new RangeError(message); - } - return value; - } - /** - * Asserts a hash instance has not been destroyed or finished. - * @param instance - hash instance to validate - * @param checkFinished - whether to reject finalized instances - * @throws If the hash instance has already been destroyed or finalized. {@link Error} - * @example - * Validate that a hash instance is still usable. - * ```ts - * import { aexists } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * const hash = sha256.create(); - * aexists(hash); - * ``` - */ - function aexists(instance, checkFinished = true) { - if (instance.destroyed) - throw new Error('Hash instance has been destroyed'); - if (checkFinished && instance.finished) - throw new Error('Hash#digest() has already been called'); - } - /** - * Asserts output is a sufficiently-sized byte array. - * @param out - destination buffer - * @param instance - hash instance providing output length - * Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validate a caller-provided digest buffer. - * ```ts - * import { aoutput } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * const hash = sha256.create(); - * aoutput(new Uint8Array(hash.outputLen), hash); - * ``` - */ - function aoutput(out, instance) { - abytes(out, undefined, 'digestInto() output'); - const min = instance.outputLen; - if (out.length < min) { - throw new RangeError('"digestInto() output" expected to be of length >=' + min); - } - } - /** - * Casts a typed array view to Uint32Array. - * `arr.byteOffset` must already be 4-byte aligned or the platform - * Uint32Array constructor will throw. - * @param arr - source typed array - * @returns Uint32Array view over the same buffer. - * @example - * Reinterpret a byte array as 32-bit words. - * ```ts - * u32(new Uint8Array(8)); - * ``` - */ - function u32(arr) { - return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); - } - /** - * Zeroizes typed arrays in place. Warning: JS provides no guarantees. - * @param arrays - arrays to overwrite with zeros - * @example - * Zeroize sensitive buffers in place. - * ```ts - * clean(new Uint8Array([1, 2, 3])); - * ``` - */ - function clean(...arrays) { - for (let i = 0; i < arrays.length; i++) { - arrays[i].fill(0); - } - } - /** Whether the current platform is little-endian. */ - const isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)(); - /** - * Byte-swap operation for uint32 values. - * @param word - source word - * @returns Word with reversed byte order. - * @example - * Reverse the byte order of a 32-bit word. - * ```ts - * byteSwap(0x11223344); - * ``` - */ - function byteSwap(word) { - return (((word << 24) & 0xff000000) | - ((word << 8) & 0xff0000) | - ((word >>> 8) & 0xff00) | - ((word >>> 24) & 0xff)); - } - /** - * Conditionally byte-swaps one 32-bit word on big-endian platforms. - * @param n - source word - * @returns Original or byte-swapped word depending on platform endianness. - * @example - * Normalize a 32-bit word for host endianness. - * ```ts - * swap8IfBE(0x11223344); - * ``` - */ - const swap8IfBE = isLE - ? (n) => n - : (n) => byteSwap(n) >>> 0; - /** - * Byte-swaps every word of a Uint32Array in place. - * @param arr - array to mutate - * @returns The same array after mutation; callers pass live state arrays here. - * @example - * Reverse the byte order of every word in place. - * ```ts - * byteSwap32(new Uint32Array([0x11223344])); - * ``` - */ - function byteSwap32(arr) { - for (let i = 0; i < arr.length; i++) { - arr[i] = byteSwap(arr[i]); - } - return arr; - } - /** - * Conditionally byte-swaps a Uint32Array on big-endian platforms. - * @param u - array to normalize for host endianness - * @returns Original or byte-swapped array depending on platform endianness. - * On big-endian runtimes this mutates `u` in place via `byteSwap32(...)`. - * @example - * Normalize a word array for host endianness. - * ```ts - * swap32IfBE(new Uint32Array([0x11223344])); - * ``` - */ - const swap32IfBE = isLE - ? (u) => u - : byteSwap32; - /** - * Creates a callable hash function from a stateful class constructor. - * @param hashCons - hash constructor or factory - * @param info - optional metadata such as DER OID - * @returns Frozen callable hash wrapper with `.create()`. - * Wrapper construction eagerly calls `hashCons(undefined)` once to read - * `outputLen` / `blockLen`, so constructor side effects happen at module - * init time. - * @example - * Wrap a stateful hash constructor into a callable helper. - * ```ts - * import { createHasher } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * const wrapped = createHasher(sha256.create, { oid: sha256.oid }); - * wrapped(new Uint8Array([1])); - * ``` - */ - function createHasher(hashCons, info = {}) { - const hashC = (msg, opts) => hashCons(opts) - .update(msg) - .digest(); - const tmp = hashCons(undefined); - hashC.outputLen = tmp.outputLen; - hashC.blockLen = tmp.blockLen; - hashC.canXOF = tmp.canXOF; - hashC.create = (opts) => hashCons(opts); - Object.assign(hashC, info); - return Object.freeze(hashC); - } - - /** - * Internal helpers for blake hash. - * @module - */ - /** - * Internal blake permutation table. - * Rows `0..9` serve BLAKE2s, rows `0..11` serve BLAKE2b with `10..11 = 0..1`, and Blake1 also - * reuses the later rows shown below. Blake1 expands rounds `10..15` as `SIGMA[i % 10]`, so rows - * `10..15` intentionally repeat rows `0..5` for the 14-round (256) and 16-round (512) variants. - */ - // prettier-ignore - const BSIGMA = /* @__PURE__ */ Uint8Array.from([ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, - 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, - 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, - 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, - 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, - 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, - 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, - 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, - 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, - // Blake1, unused in others - 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, - 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, - 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, - 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, - ]); - - const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1); - const _32n = /* @__PURE__ */ BigInt(32); - // Split bigint into two 32-bit halves. With `le=true`, returned fields become `{ h: low, l: high - // }` to match little-endian word order rather than the property names. - function fromBig(n, le = false) { - if (le) - return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) }; - return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 }; - } - // Split bigint list into `[highWords, lowWords]` when `le=false`; with `le=true`, the first array - // holds the low halves because `fromBig(...)` swaps the semantic meaning of `h` and `l`. - function split(lst, le = false) { - const len = lst.length; - let Ah = new Uint32Array(len); - let Al = new Uint32Array(len); - for (let i = 0; i < len; i++) { - const { h, l } = fromBig(lst[i], le); - [Ah[i], Al[i]] = [h, l]; - } - return [Ah, Al]; - } - // High 32-bit half of a 64-bit right rotate, valid for `s` in `1..31`. - const rotrSH = (h, l, s) => (h >>> s) | (l << (32 - s)); - // Low 32-bit half of a 64-bit right rotate, valid for `s` in `1..31`. - const rotrSL = (h, l, s) => (h << (32 - s)) | (l >>> s); - // High 32-bit half of a 64-bit right rotate, valid for `s` in `33..63`; `32` uses `rotr32*`. - const rotrBH = (h, l, s) => (h << (64 - s)) | (l >>> (s - 32)); - // Low 32-bit half of a 64-bit right rotate, valid for `s` in `33..63`; `32` uses `rotr32*`. - const rotrBL = (h, l, s) => (h >>> (s - 32)) | (l << (64 - s)); - // High 32-bit half of a 64-bit right rotate for `s === 32`; this is just the swapped low half. - const rotr32H = (_h, l) => l; - // Low 32-bit half of a 64-bit right rotate for `s === 32`; this is just the swapped high half. - const rotr32L = (h, _l) => h; - // High 32-bit half of a 64-bit left rotate, valid for `s` in `1..31`. - const rotlSH = (h, l, s) => (h << s) | (l >>> (32 - s)); - // Low 32-bit half of a 64-bit left rotate, valid for `s` in `1..31`. - const rotlSL = (h, l, s) => (l << s) | (h >>> (32 - s)); - // High 32-bit half of a 64-bit left rotate, valid for `s` in `33..63`; `32` uses `rotr32*`. - const rotlBH = (h, l, s) => (l << (s - 32)) | (h >>> (64 - s)); - // Low 32-bit half of a 64-bit left rotate, valid for `s` in `33..63`; `32` uses `rotr32*`. - const rotlBL = (h, l, s) => (h << (s - 32)) | (l >>> (64 - s)); - // Add two split 64-bit words and return the split `{ h, l }` sum. - // JS uses 32-bit signed integers for bitwise operations, so we cannot simply shift the carry out - // of the low sum and instead use division. - function add(Ah, Al, Bh, Bl) { - const l = (Al >>> 0) + (Bl >>> 0); - return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 }; - } - // Addition with more than 2 elements - // Unmasked low-word accumulator for 3-way addition; pass the raw result into `add3H(...)`. - const add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0); - // High-word finalize step for 3-way addition; `low` must be the untruncated output of `add3L(...)`. - const add3H = (low, Ah, Bh, Ch) => (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0; - - /** - * blake2b (64-bit) & blake2s (8 to 32-bit) hash functions. - * b could have been faster, but there is no fast u64 in js, so s is 1.5x faster. - * @module - */ - // Same IV words as `SHA512_IV`, but endian-swapped into LE u32 low/high halves - // for the BLAKE2b u64 helpers below. - const B2B_IV = /* @__PURE__ */ Uint32Array.from([ - 0xf3bcc908, 0x6a09e667, 0x84caa73b, 0xbb67ae85, 0xfe94f82b, 0x3c6ef372, 0x5f1d36f1, 0xa54ff53a, - 0xade682d1, 0x510e527f, 0x2b3e6c1f, 0x9b05688c, 0xfb41bd6b, 0x1f83d9ab, 0x137e2179, 0x5be0cd19, - ]); - // Shared synchronous BLAKE2b work vector as LE u32 low/high halves. - const BBUF = /* @__PURE__ */ new Uint32Array(32); - // BLAKE2b G mix split into two half-rounds over LE u32 low/high limbs. - function G1b(a, b, c, d, msg, x) { - // NOTE: V is LE here - const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore - let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore - let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore - let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore - let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore - // v[a] = (v[a] + v[b] + x) | 0; - let ll = add3L(Al, Bl, Xl); - Ah = add3H(ll, Ah, Bh, Xh); - Al = ll | 0; - // v[d] = rotr(v[d] ^ v[a], 32) - ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al }); - ({ Dh, Dl } = { Dh: rotr32H(Dh, Dl), Dl: rotr32L(Dh) }); - // v[c] = (v[c] + v[d]) | 0; - ({ h: Ch, l: Cl } = add(Ch, Cl, Dh, Dl)); - // v[b] = rotr(v[b] ^ v[c], 24) - ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl }); - ({ Bh, Bl } = { Bh: rotrSH(Bh, Bl, 24), Bl: rotrSL(Bh, Bl, 24) }); - ((BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah)); - ((BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh)); - ((BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch)); - ((BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh)); - } - // Second half-round of the same LE-limb BLAKE2b G mix; `x` is the message word offset. - function G2b(a, b, c, d, msg, x) { - // NOTE: V is LE here - const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore - let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore - let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore - let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore - let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore - // v[a] = (v[a] + v[b] + x) | 0; - let ll = add3L(Al, Bl, Xl); - Ah = add3H(ll, Ah, Bh, Xh); - Al = ll | 0; - // v[d] = rotr(v[d] ^ v[a], 16) - ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al }); - ({ Dh, Dl } = { Dh: rotrSH(Dh, Dl, 16), Dl: rotrSL(Dh, Dl, 16) }); - // v[c] = (v[c] + v[d]) | 0; - ({ h: Ch, l: Cl } = add(Ch, Cl, Dh, Dl)); - // v[b] = rotr(v[b] ^ v[c], 63) - ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl }); - ({ Bh, Bl } = { Bh: rotrBH(Bh, Bl, 63), Bl: rotrBL(Bh, Bl, 63) }); - ((BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah)); - ((BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh)); - ((BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch)); - ((BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh)); - } - function checkBlake2Opts(outputLen, opts = {}, keyLen, saltLen, persLen) { - anumber(keyLen); - // RFC 7693 §2.1 requires digest length nn in 1..keyLen. - if (outputLen <= 0 || outputLen > keyLen) - throw new Error('outputLen bigger than keyLen'); - const { key, salt, personalization } = opts; - // This API uses `undefined` for the RFC 7693 `kk = 0` case, so a provided key must be non-empty. - if (key !== undefined && (key.length < 1 || key.length > keyLen)) - throw new Error('"key" expected to be undefined or of length=1..' + keyLen); - if (salt !== undefined) - abytes(salt, saltLen, 'salt'); - if (personalization !== undefined) - abytes(personalization, persLen, 'personalization'); - } - /** Internal base class for BLAKE2. */ - class _BLAKE2 { - buffer; - buffer32; - finished = false; - destroyed = false; - length = 0; - pos = 0; - blockLen; - outputLen; - canXOF = false; - constructor(blockLen, outputLen) { - anumber(blockLen); - anumber(outputLen); - this.blockLen = blockLen; - this.outputLen = outputLen; - this.buffer = new Uint8Array(blockLen); - this.buffer32 = u32(this.buffer); - } - update(data) { - aexists(this); - abytes(data); - // Main difference with other hashes: there is flag for last block, - // so we cannot process current block before we know that there - // is the next one. This significantly complicates logic and reduces ability - // to do zero-copy processing - const { blockLen, buffer, buffer32 } = this; - const len = data.length; - const offset = data.byteOffset; - const buf = data.buffer; - for (let pos = 0; pos < len;) { - // If buffer is full and we still have input (don't process last block, same as blake2s) - if (this.pos === blockLen) { - swap32IfBE(buffer32); - this.compress(buffer32, 0, false); - swap32IfBE(buffer32); - this.pos = 0; - } - const take = Math.min(blockLen - this.pos, len - pos); - const dataOffset = offset + pos; - // Zero-copy only for full, 4-byte-aligned, non-final blocks. - if (take === blockLen && !(dataOffset % 4) && pos + take < len) { - const data32 = new Uint32Array(buf, dataOffset, Math.floor((len - pos) / 4)); - swap32IfBE(data32); - for (let pos32 = 0; pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) { - this.length += blockLen; - this.compress(data32, pos32, false); - } - swap32IfBE(data32); - continue; - } - buffer.set(data.subarray(pos, pos + take), this.pos); - this.pos += take; - this.length += take; - pos += take; - } - return this; - } - digestInto(out) { - aexists(this); - aoutput(out, this); - const { pos, buffer32 } = this; - this.finished = true; - // Padding - clean(this.buffer.subarray(pos)); - swap32IfBE(buffer32); - this.compress(buffer32, 0, true); - swap32IfBE(buffer32); - // Reject unaligned views explicitly instead of hiding them behind a full scratch copy. - if (out.byteOffset & 3) - throw new RangeError('"digestInto() output" expected 4-byte aligned byteOffset, got ' + out.byteOffset); - const state = this.get(); - const out32 = u32(out); - const full = Math.floor(this.outputLen / 4); - for (let i = 0; i < full; i++) - out32[i] = swap8IfBE(state[i]); - const tail = this.outputLen % 4; - if (!tail) - return; - const off = full * 4; - const word = state[full]; - for (let i = 0; i < tail; i++) - out[off + i] = word >>> (8 * i); - } - digest() { - const { buffer, outputLen } = this; - this.digestInto(buffer); - // Return a copy so callers do not alias the instance scratch buffer used during finalization. - const res = buffer.slice(0, outputLen); - this.destroy(); - return res; - } - _cloneInto(to) { - const { buffer, length, finished, destroyed, outputLen, pos } = this; - // Recreate only `dkLen`; key/salt/personalization are already absorbed into the copied state. - to ||= new this.constructor({ dkLen: outputLen }); - to.set(...this.get()); - to.buffer.set(buffer); - to.destroyed = destroyed; - to.finished = finished; - to.length = length; - to.pos = pos; - // @ts-ignore - to.outputLen = outputLen; - return to; - } - clone() { - return this._cloneInto(); - } - } - /** Internal blake2b hash class with state stored as LE u32 low/high halves. */ - class _BLAKE2b extends _BLAKE2 { - // Same IV words as SHA-512 / BLAKE2b, encoded as LE u32 low/high halves. - v0l = B2B_IV[0] | 0; - v0h = B2B_IV[1] | 0; - v1l = B2B_IV[2] | 0; - v1h = B2B_IV[3] | 0; - v2l = B2B_IV[4] | 0; - v2h = B2B_IV[5] | 0; - v3l = B2B_IV[6] | 0; - v3h = B2B_IV[7] | 0; - v4l = B2B_IV[8] | 0; - v4h = B2B_IV[9] | 0; - v5l = B2B_IV[10] | 0; - v5h = B2B_IV[11] | 0; - v6l = B2B_IV[12] | 0; - v6h = B2B_IV[13] | 0; - v7l = B2B_IV[14] | 0; - v7h = B2B_IV[15] | 0; - constructor(opts = {}) { - const olen = opts.dkLen === undefined ? 64 : opts.dkLen; - super(128, olen); - checkBlake2Opts(olen, opts, 64, 16, 16); - let { key, personalization, salt } = opts; - let keyLength = 0; - if (key !== undefined) { - abytes(key, undefined, 'key'); - keyLength = key.length; - } - // RFC 7693 §2.5: xor `p[0] = 0x0101kknn` into the low 32 bits of `h[0]`; - // the high 32 bits stay at `IV[0]`. - this.v0l ^= this.outputLen | (keyLength << 8) | (0x01 << 16) | (0x01 << 24); - if (salt !== undefined) { - abytes(salt, undefined, 'salt'); - const slt = u32(salt); - this.v4l ^= swap8IfBE(slt[0]); - this.v4h ^= swap8IfBE(slt[1]); - this.v5l ^= swap8IfBE(slt[2]); - this.v5h ^= swap8IfBE(slt[3]); - } - if (personalization !== undefined) { - abytes(personalization, undefined, 'personalization'); - const pers = u32(personalization); - this.v6l ^= swap8IfBE(pers[0]); - this.v6h ^= swap8IfBE(pers[1]); - this.v7l ^= swap8IfBE(pers[2]); - this.v7h ^= swap8IfBE(pers[3]); - } - if (key !== undefined) { - // Pad to blockLen and update - const tmp = new Uint8Array(this.blockLen); - tmp.set(key); - this.update(tmp); - } - } - // prettier-ignore - get() { - let { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this; - return [v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h]; - } - // prettier-ignore - set(v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h) { - this.v0l = v0l | 0; - this.v0h = v0h | 0; - this.v1l = v1l | 0; - this.v1h = v1h | 0; - this.v2l = v2l | 0; - this.v2h = v2h | 0; - this.v3l = v3l | 0; - this.v3h = v3h | 0; - this.v4l = v4l | 0; - this.v4h = v4h | 0; - this.v5l = v5l | 0; - this.v5h = v5h | 0; - this.v6l = v6l | 0; - this.v6h = v6h | 0; - this.v7l = v7l | 0; - this.v7h = v7h | 0; - } - compress(msg, offset, isLast) { - this.get().forEach((v, i) => (BBUF[i] = v)); // First half from state. - BBUF.set(B2B_IV, 16); // Second half from IV. - let { h, l } = fromBig(BigInt(this.length)); - BBUF[24] = B2B_IV[8] ^ l; // Low word of the offset. - BBUF[25] = B2B_IV[9] ^ h; // High word. - // Invert all bits for last block - if (isLast) { - BBUF[28] = ~BBUF[28]; - BBUF[29] = ~BBUF[29]; - } - let j = 0; - const s = BSIGMA; - // SIGMA selects 64-bit message words; multiply by 2 because `msg` stores - // each word as [low32, high32]. - for (let i = 0; i < 12; i++) { - G1b(0, 4, 8, 12, msg, offset + 2 * s[j++]); - G2b(0, 4, 8, 12, msg, offset + 2 * s[j++]); - G1b(1, 5, 9, 13, msg, offset + 2 * s[j++]); - G2b(1, 5, 9, 13, msg, offset + 2 * s[j++]); - G1b(2, 6, 10, 14, msg, offset + 2 * s[j++]); - G2b(2, 6, 10, 14, msg, offset + 2 * s[j++]); - G1b(3, 7, 11, 15, msg, offset + 2 * s[j++]); - G2b(3, 7, 11, 15, msg, offset + 2 * s[j++]); - G1b(0, 5, 10, 15, msg, offset + 2 * s[j++]); - G2b(0, 5, 10, 15, msg, offset + 2 * s[j++]); - G1b(1, 6, 11, 12, msg, offset + 2 * s[j++]); - G2b(1, 6, 11, 12, msg, offset + 2 * s[j++]); - G1b(2, 7, 8, 13, msg, offset + 2 * s[j++]); - G2b(2, 7, 8, 13, msg, offset + 2 * s[j++]); - G1b(3, 4, 9, 14, msg, offset + 2 * s[j++]); - G2b(3, 4, 9, 14, msg, offset + 2 * s[j++]); - } - this.v0l ^= BBUF[0] ^ BBUF[16]; - this.v0h ^= BBUF[1] ^ BBUF[17]; - this.v1l ^= BBUF[2] ^ BBUF[18]; - this.v1h ^= BBUF[3] ^ BBUF[19]; - this.v2l ^= BBUF[4] ^ BBUF[20]; - this.v2h ^= BBUF[5] ^ BBUF[21]; - this.v3l ^= BBUF[6] ^ BBUF[22]; - this.v3h ^= BBUF[7] ^ BBUF[23]; - this.v4l ^= BBUF[8] ^ BBUF[24]; - this.v4h ^= BBUF[9] ^ BBUF[25]; - this.v5l ^= BBUF[10] ^ BBUF[26]; - this.v5h ^= BBUF[11] ^ BBUF[27]; - this.v6l ^= BBUF[12] ^ BBUF[28]; - this.v6h ^= BBUF[13] ^ BBUF[29]; - this.v7l ^= BBUF[14] ^ BBUF[30]; - this.v7h ^= BBUF[15] ^ BBUF[31]; - clean(BBUF); - } - destroy() { - this.destroyed = true; - clean(this.buffer32); - this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - } - /** - * Blake2b hash function. 64-bit. 1.5x slower than blake2s in JS. - * @param msg - message that would be hashed - * @param opts - Optional output, MAC, salt, and personalization settings. - * `dkLen` must be 1..64 bytes; `salt` and `personalization`, if present, - * must be 16 bytes each. See {@link Blake2Opts}. - * @returns Digest bytes. - * @example - * Hash a message with Blake2b. - * ```ts - * blake2b(new Uint8Array([97, 98, 99])); - * ``` - */ - const blake2b = /* @__PURE__ */ createHasher((opts) => new _BLAKE2b(opts)); - - var readline = {}; - - var crypto = {}; - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - - function log2( V ) - { - return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) ); - } - - - function formatHash(b, title) { - const a = new DataView(b.buffer, b.byteOffset, b.byteLength); - let S = ""; - for (let i=0; i<4; i++) { - if (i>0) S += "\n"; - S += "\t\t"; - for (let j=0; j<4; j++) { - if (j>0) S += " "; - S += a.getUint32(i*16+j*4).toString(16).padStart(8, "0"); - } - } - if (title) S = title + "\n" + S; - return S; - } - - function hashIsEqual(h1, h2) { - if (h1.byteLength != h2.byteLength) return false; - var dv1 = new Int8Array(h1); - var dv2 = new Int8Array(h2); - for (var i = 0 ; i != h1.byteLength ; i++) - { - if (dv1[i] != dv2[i]) return false; - } - return true; - } - - function cloneHasher(h) { - return h.clone(); - } - - function fromPartialHash(partial) { - // NOTE: this is unsafe and uses internal API - const buf = partial.subarray(0, 128); - const rest = u32(partial.subarray(128)); - const res = blake2b.create({ dkLen: 64 }); - res.buffer.set(buf); - (res.v0l = rest[0] | 0), (res.v0h = rest[1] | 0); - (res.v1l = rest[2] | 0), (res.v1h = rest[3] | 0); - (res.v2l = rest[4] | 0), (res.v2h = rest[5] | 0); - (res.v3l = rest[6] | 0), (res.v3h = rest[7] | 0); - (res.v4l = rest[8] | 0), (res.v4h = rest[9] | 0); - (res.v5l = rest[10] | 0), (res.v5h = rest[11] | 0); - (res.v6l = rest[12] | 0), (res.v6h = rest[13] | 0); - (res.v7l = rest[14] | 0), (res.v7h = rest[15] | 0); - const shift = 2 ** 32; - const len = rest[16] + rest[17] * shift; - const pos = rest[18] + rest[19] * shift; - res.length = len + pos; - res.pos = pos; - return res; - } - - function toPartialHash(hash){ - // NOTE: this is unsafe and uses internal API - const res = new Uint8Array(216); - const res32 = u32(res.subarray(128)); - res.set(hash.buffer); - (res32[0] = hash.v0l), (res32[1] = hash.v0h); - (res32[2] = hash.v1l), (res32[3] = hash.v1h); - (res32[4] = hash.v2l), (res32[5] = hash.v2h); - (res32[6] = hash.v3l), (res32[7] = hash.v3h); - (res32[8] = hash.v4l), (res32[9] = hash.v4h); - (res32[10] = hash.v5l), (res32[11] = hash.v5h); - (res32[12] = hash.v6l), (res32[13] = hash.v6h); - (res32[14] = hash.v7l), (res32[15] = hash.v7h); - res32[18] = hash.pos; - res32[16] = hash.length-hash.pos; - return res; - } - - async function sameRatio$2(curve, g1s, g1sx, g2s, g2sx) { - if (curve.G1.isZero(g1s)) return false; - if (curve.G1.isZero(g1sx)) return false; - if (curve.G2.isZero(g2s)) return false; - if (curve.G2.isZero(g2sx)) return false; - // return curve.F12.eq(curve.pairing(g1s, g2sx), curve.pairing(g1sx, g2s)); - const res = await curve.pairingEq(g1s, g2sx, curve.G1.neg(g1sx), g2s); - return res; - } - - - function askEntropy() { - // Use the browser prompt only when a real DOM window exists. "not Node" is - // NOT the same as "browser" (Bun/Deno/edge/SES have neither window nor are - // classic Node), so detect the actual API. - if (typeof window !== "undefined" && typeof window.prompt === "function") { - return window.prompt("Enter a random text. (Entropy): ", ""); - } else { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); - - return new Promise((resolve) => { - rl.question("Enter a random text. (Entropy): ", (input) => resolve(input) ); - }); - } - } - - function getRandomBytes(n) { - let array = new Uint8Array(n); - if (crypto && crypto.randomFillSync) { // Node: no per-call size limit - crypto.randomFillSync(array); - } else if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) { - // Web Crypto caps each call at 65536 bytes; fill in windows. - for (let i = 0; i < n; i += 65536) { - globalThis.crypto.getRandomValues(array.subarray(i, Math.min(i + 65536, n))); - } - } else { - throw new Error("No secure random source available"); - } - return array; - } - - async function sha256digest(data) { - if (crypto && crypto.createHash) { // Node - return crypto.createHash("sha256").update(data).digest(); - } else { - // Web Crypto: pass the view (data), not data.buffer, so byteOffset and - // byteLength of subarray views are respected. - const buffer = await globalThis.crypto.subtle.digest("SHA-256", data); - return new Uint8Array(buffer); - } - } - - /** - * @param {Uint8Array} data - * @param {number} offset - */ - function readUInt32BE(data, offset) { - return new DataView(data.buffer).getUint32(offset, false); - } - - async function getRandomRng(entropy) { - // Generate a random Rng - while (!entropy) { - entropy = await askEntropy(); - } - const hasher = blake2b.create(64); - hasher.update(getRandomBytes(64)); - const enc = new TextEncoder(); // always utf-8 - hasher.update(enc.encode(entropy)); - const hash = hasher.digest(); - - const seed = []; - for (let i=0;i<8;i++) { - seed[i] = readUInt32BE(hash, i*4); - } - const rng = new ChaCha(seed); - return rng; - } - - async function rngFromBeaconParams(beaconHash, numIterationsExp) { - let nIterationsInner; - let nIterationsOuter; - if (numIterationsExp<32) { - nIterationsInner = (1 << numIterationsExp) >>> 0; - nIterationsOuter = 1; - } else { - nIterationsInner = 0x100000000; - nIterationsOuter = (1 << (numIterationsExp-32)) >>> 0; - } - - let curHash = beaconHash; - for (let i=0; i { - res[k] = stringifyBigIntsWithField(Fr, o[k]); - }); - return res; - } else if ((typeof(o) == "bigint") || o.eq !== undefined) { - return o.toString(10); - } else { - return o; - } - } - - const HEADER_ZKEY_SECTION = 1; - - const GROTH16_PROTOCOL_ID = 1; - const PLONK_PROTOCOL_ID = 2; - const FFLONK_PROTOCOL_ID = 10; - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - // FFlonk constants - const FF_T_POL_DEG_MIN = 3; - - // ZKEY constants - const ZKEY_FF_NSECTIONS = 17; - - const ZKEY_FF_HEADER_SECTION = 2; - const ZKEY_FF_ADDITIONS_SECTION = 3; - const ZKEY_FF_A_MAP_SECTION = 4; - const ZKEY_FF_B_MAP_SECTION = 5; - const ZKEY_FF_C_MAP_SECTION = 6; - const ZKEY_FF_QL_SECTION = 7; - const ZKEY_FF_QR_SECTION = 8; - const ZKEY_FF_QM_SECTION = 9; - const ZKEY_FF_QO_SECTION = 10; - const ZKEY_FF_QC_SECTION = 11; - const ZKEY_FF_SIGMA1_SECTION = 12; - const ZKEY_FF_SIGMA2_SECTION = 13; - const ZKEY_FF_SIGMA3_SECTION = 14; - const ZKEY_FF_LAGRANGE_SECTION = 15; - const ZKEY_FF_PTAU_SECTION = 16; - const ZKEY_FF_C0_SECTION = 17; - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - async function writeHeader(fd, zkey) { - - // Write the header - /////////// - await startWriteSection(fd, 1); - await fd.writeULE32(1); // Groth - await endWriteSection(fd); - - // Write the Groth header section - /////////// - - const curve = await getCurveFromQ(zkey.q); - - await startWriteSection(fd, 2); - const primeQ = curve.q; - const n8q = (Math.floor( (Scalar.bitLength(primeQ) - 1) / 64) +1)*8; - - const primeR = curve.r; - const n8r = (Math.floor( (Scalar.bitLength(primeR) - 1) / 64) +1)*8; - - await fd.writeULE32(n8q); - await writeBigInt(fd, primeQ, n8q); - await fd.writeULE32(n8r); - await writeBigInt(fd, primeR, n8r); - await fd.writeULE32(zkey.nVars); // Total number of bars - await fd.writeULE32(zkey.nPublic); // Total number of public vars (not including ONE) - await fd.writeULE32(zkey.domainSize); // domainSize - await writeG1(fd, curve, zkey.vk_alpha_1); - await writeG1(fd, curve, zkey.vk_beta_1); - await writeG2(fd, curve, zkey.vk_beta_2); - await writeG2(fd, curve, zkey.vk_gamma_2); - await writeG1(fd, curve, zkey.vk_delta_1); - await writeG2(fd, curve, zkey.vk_delta_2); - - await endWriteSection(fd); - - - } - - async function writeG1(fd, curve, p) { - const buff = new Uint8Array(curve.G1.F.n8*2); - curve.G1.toRprLEM(buff, 0, p); - await fd.write(buff); - } - - async function writeG2(fd, curve, p) { - const buff = new Uint8Array(curve.G2.F.n8*2); - curve.G2.toRprLEM(buff, 0, p); - await fd.write(buff); - } - - async function readG1(fd, curve, toObject) { - const buff = await fd.read(curve.G1.F.n8*2); - const res = curve.G1.fromRprLEM(buff, 0); - return toObject ? curve.G1.toObject(res) : res; - } - - async function readG2(fd, curve, toObject) { - const buff = await fd.read(curve.G2.F.n8*2); - const res = curve.G2.fromRprLEM(buff, 0); - return toObject ? curve.G2.toObject(res) : res; - } - - - async function readHeader$1(fd, sections, toObject, options) { - // Read Header - ///////////////////// - await startReadUniqueSection$1(fd, sections, 1); - const protocolId = await fd.readULE32(); - await endReadSection$1(fd); - - if (protocolId === GROTH16_PROTOCOL_ID) { - return await readHeaderGroth16(fd, sections, toObject, options); - } else if (protocolId === PLONK_PROTOCOL_ID) { - return await readHeaderPlonk(fd, sections, toObject, options); - } else if (protocolId === FFLONK_PROTOCOL_ID) { - return await readHeaderFFlonk(fd, sections, toObject, options); - } else { - throw new Error("Protocol not supported: "); - } - } - - - - - async function readHeaderGroth16(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "groth16"; - - // Read Groth Header - ///////////////////// - await startReadUniqueSection$1(fd, sections, 2); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await readBigInt$1(fd, n8q); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await readBigInt$1(fd, n8r); - zkey.curve = await getCurveFromQ(zkey.q, options); - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.vk_alpha_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_beta_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_beta_2 = await readG2(fd, zkey.curve, toObject); - zkey.vk_gamma_2 = await readG2(fd, zkey.curve, toObject); - zkey.vk_delta_1 = await readG1(fd, zkey.curve, toObject); - zkey.vk_delta_2 = await readG2(fd, zkey.curve, toObject); - await endReadSection$1(fd); - - return zkey; - - } - - async function readHeaderPlonk(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "plonk"; - - // Read Plonk Header - ///////////////////// - await startReadUniqueSection$1(fd, sections, 2); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await readBigInt$1(fd, n8q); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await readBigInt$1(fd, n8r); - zkey.curve = await getCurveFromQ(zkey.q, options); - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.nAdditions = await fd.readULE32(); - zkey.nConstraints = await fd.readULE32(); - zkey.k1 = await fd.read(n8r); - zkey.k2 = await fd.read(n8r); - - zkey.Qm = await readG1(fd, zkey.curve, toObject); - zkey.Ql = await readG1(fd, zkey.curve, toObject); - zkey.Qr = await readG1(fd, zkey.curve, toObject); - zkey.Qo = await readG1(fd, zkey.curve, toObject); - zkey.Qc = await readG1(fd, zkey.curve, toObject); - zkey.S1 = await readG1(fd, zkey.curve, toObject); - zkey.S2 = await readG1(fd, zkey.curve, toObject); - zkey.S3 = await readG1(fd, zkey.curve, toObject); - zkey.X_2 = await readG2(fd, zkey.curve, toObject); - - await endReadSection$1(fd); - - return zkey; - } - - async function readHeaderFFlonk(fd, sections, toObject, options) { - const zkey = {}; - - zkey.protocol = "fflonk"; - zkey.protocolId = FFLONK_PROTOCOL_ID; - - await startReadUniqueSection$1(fd, sections, ZKEY_FF_HEADER_SECTION); - const n8q = await fd.readULE32(); - zkey.n8q = n8q; - zkey.q = await readBigInt$1(fd, n8q); - zkey.curve = await getCurveFromQ(zkey.q, options); - - const n8r = await fd.readULE32(); - zkey.n8r = n8r; - zkey.r = await readBigInt$1(fd, n8r); - - zkey.nVars = await fd.readULE32(); - zkey.nPublic = await fd.readULE32(); - zkey.domainSize = await fd.readULE32(); - zkey.power = log2(zkey.domainSize); - zkey.nAdditions = await fd.readULE32(); - zkey.nConstraints = await fd.readULE32(); - - zkey.k1 = await fd.read(n8r); - zkey.k2 = await fd.read(n8r); - - zkey.w3 = await fd.read(n8r); - zkey.w4 = await fd.read(n8r); - zkey.w8 = await fd.read(n8r); - zkey.wr = await fd.read(n8r); - - zkey.X_2 = await readG2(fd, zkey.curve, toObject); - - zkey.C0 = await readG1(fd, zkey.curve, toObject); - - await endReadSection$1(fd); - - return zkey; - } - - async function readZKey(fileName, toObject) { - const {fd, sections} = await readBinFile$1(fileName, "zkey", 1); - - const zkey = await readHeader$1(fd, sections, toObject); - - const Fr = new ZqField(zkey.r); - const Rr = Scalar.mod(Scalar.shl(1, zkey.n8r*8), zkey.r); - const Rri = Fr.inv(Rr); - const Rri2 = Fr.mul(Rri, Rri); - - let curve = await getCurveFromQ(zkey.q); - - // Read IC Section - /////////// - await startReadUniqueSection$1(fd, sections, 3); - zkey.IC = []; - for (let i=0; i<= zkey.nPublic; i++) { - const P = await readG1(fd, curve, toObject); - zkey.IC.push(P); - } - await endReadSection$1(fd); - - - // Read Coefs - /////////// - await startReadUniqueSection$1(fd, sections, 4); - const nCCoefs = await fd.readULE32(); - zkey.ccoefs = []; - for (let i=0; i0) { - const paramsBuff = new Uint8Array(params); - await fd.writeULE32(paramsBuff.byteLength); - await fd.write(paramsBuff); - } else { - await fd.writeULE32(0); - } - - } - - async function writeMPCParams(fd, curve, mpcParams) { - await startWriteSection(fd, 10); - await fd.write(mpcParams.csHash); - await fd.writeULE32(mpcParams.contributions.length); - for (let i=0; i. - */ - - - - async function write(fd, witness, prime) { - - await startWriteSection(fd, 1); - const n8 = (Math.floor( (Scalar.bitLength(prime) - 1) / 64) +1)*8; - await fd.writeULE32(n8); - await writeBigInt(fd, prime, n8); - await fd.writeULE32(witness.length); - await endWriteSection(fd); - - await startWriteSection(fd, 2); - for (let i=0; i. - */ - - const {stringifyBigInts: stringifyBigInts$4} = utils; - - async function groth16Prove(zkeyFileName, witnessFileName, logger, options) { - // Opt-in periodic memory-usage logging (heap/RSS/external/ArrayBuffers). - // options.memoryLogging: true (1s interval) or an interval in ms. - // Node-only: process.memoryUsage does not exist in browsers. - let memTimer = null; - if (logger && options && options.memoryLogging - && typeof process !== "undefined" && typeof process.memoryUsage === "function") { - const interval = Number(options.memoryLogging) > 1 ? Number(options.memoryLogging) : 1000; - memTimer = monitorMemoryUsage(logger, interval); - } - try { - return await _groth16Prove(zkeyFileName, witnessFileName, logger, options); - } finally { - if (memTimer) { - clearInterval(memTimer); - memUsage(logger); - } - } - } - - async function _groth16Prove(zkeyFileName, witnessFileName, logger, options) { - - const {fd: fdWtns, sections: sectionsWtns} = await readBinFile$1(witnessFileName, "wtns", 2, 1<<25, 1<<23); - - const wtns = await readHeader(fdWtns, sectionsWtns); - - const {fd: fdZKey, sections: sectionsZKey} = await readBinFile$1(zkeyFileName, "zkey", 2, 1<<25, 1<<23); - - const zkey = await readHeader$1(fdZKey, sectionsZKey, undefined, options); - - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - if (!Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness != zkey.nVars) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}`); - } - - const curve = zkey.curve; - const Fr = curve.Fr; - const G1 = curve.G1; - const G2 = curve.G2; - - options = options || {}; - - // MSM batching mode, threaded to every multiexp below: - // "auto" (default) use the batch-affine MSM module only for - // cache-friendly chunk sizes (where it is measurably faster); - // "enabled" always use it (best for small/medium circuits); - // "disabled" never use it (plain in-module multiexp; lowest memory). - const msmBatching = options.msmBatching || "auto"; - if (msmBatching !== "auto" && msmBatching !== "enabled" && msmBatching !== "disabled") { - throw new Error(`groth16Prove: invalid msmBatching "${msmBatching}" (expected "auto", "enabled" or "disabled")`); - } - // msmGlv / msmGls: "auto" (default -- use the G1/G2 endomorphism MSM paths - // where the curve supports them; the wasm still gates internally on chunk - // sizes) or "disabled" (generic batch accumulation). A/B and debugging - // aids, like msmBatching. - const msmGlv = options.msmGlv || "auto"; - const msmGls = options.msmGls || "auto"; - for (const [name, v] of [["msmGlv", msmGlv], ["msmGls", msmGls]]) { - if (v !== "auto" && v !== "disabled") { - throw new Error(`groth16Prove: invalid ${name} "${v}" (expected "auto" or "disabled")`); - } - } - const msmOpts = { batch: msmBatching, glv: msmGlv, gls: msmGls }; - - const power = log2(zkey.domainSize); - - if (logger) logger.debug("Reading Wtns"); - const buffWitness = await readSection$1(fdWtns, sectionsWtns, 2); - - // Reader for a zkey section that returns an arbitrary sub-range directly from - // disk, used to feed multiExp bases to the workers in chunks instead of - // reading the whole (potentially hundreds of MB) section into one buffer and - // slicing it. Bounds the bases resident in RAM to a few in-flight chunks. - const mkSectionReader = (idSection) => { - const start = sectionsZKey[idSection][0].p; - const size = sectionsZKey[idSection][0].size; - return async (off, len) => { - if (off + len > size) throw new Error(`groth16Prove: read out of range of section ${idSection}`); - const buff = new Uint8Array(len); - await fdZKey.readToBuffer(buff, 0, len, start + off); - return buff; - }; - }; - - let resH; - let resHPromise; - let buffPodd_T; - - let abcPromise = (async function (){ - let buffA_T, buffB_T, buffC_T; - - await (async function (){ - if (logger) logger.debug("Reading Coeffs"); - const buffCoeffs = await readSection$1(fdZKey, sectionsZKey, 4); - - if (logger) logger.debug("Building ABC"); - - if (options.buildABC === "js") { - [buffA_T, buffB_T, buffC_T] = await buildABC1(curve, zkey, buffWitness, buffCoeffs, logger); - } else if (options.buildABC === "stream") { - const p = pickStreamParams(curve, zkey, buffCoeffs, options); - [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); - } else { - // Default: streaming build (bounded worker memory, tunable - // parallelism). The per-chunk witness gather keeps the witness - // out of WASM entirely, so there is no witness size limit. - const p = pickStreamParams(curve, zkey, buffCoeffs, options); - if (logger) logger.debug(`buildABC: stream nChunks=${p.nChunks} maxInFlight=${p.maxInFlight}`); - [buffA_T, buffB_T, buffC_T] = await buildABCStream(curve, zkey, buffWitness, buffCoeffs, logger, p.nChunks, p.maxInFlight); - } - })(); - - - // Do not call gc() here. gc() is a stop-the-world pause that blocks the - // Node.js event loop. If the pause exceeds the worker idle-termination - // timeout (1s), a worker closes its port while the main thread is blocked, - // and the next task dispatched to it is silently dropped → hang. The - // coefficients buffer goes out of scope at the end of the inner IIFE above - // and is reclaimed by V8's incremental GC automatically. - - const inc = power === Fr.s ? curve.Fr.shift : curve.Fr.w[power+1]; - - let buffAodd_T, buffBodd_T, buffCodd_T; - // The IFFT input (buffX_T) is dropped immediately, and the FFT input - // (buffXodd) goes out of scope right after -- so both can be consumed - // (consume=true), skipping ffjavascript's defensive full-input copy. - await Promise.all([ - (async function () { - let buffA = await Fr.ifft(buffA_T, "", "", logger, "IFFT_A", true); - buffA_T = null; - const buffAodd = await Fr.batchApplyKey(buffA, Fr.e(1), inc); - buffAodd_T = await Fr.fft(buffAodd, "", "", logger, "FFT_A", true); - })(), - (async function () { - let buffB = await Fr.ifft(buffB_T, "", "", logger, "IFFT_B", true); - buffB_T = null; - const buffBodd = await Fr.batchApplyKey(buffB, Fr.e(1), inc); - buffBodd_T = await Fr.fft(buffBodd, "", "", logger, "FFT_B", true); - })(), - (async function () { - let buffC = await Fr.ifft(buffC_T, "", "", logger, "IFFT_C", true); - buffC_T = null; - const buffCodd = await Fr.batchApplyKey(buffC, Fr.e(1), inc); - buffCodd_T = await Fr.fft(buffCodd, "", "", logger, "FFT_C", true); - })(), - ]); - - if (logger) logger.debug("Join ABC"); - buffPodd_T = await joinABC(curve, zkey, buffAodd_T, buffBodd_T, buffCodd_T, logger); - if (logger) logger.debug("Join ABC finished"); - buffAodd_T = null; - buffBodd_T = null; - buffCodd_T = null; - - if (globalThis.gc) {globalThis.gc();} - })(); - //await abcPromise; - - let proof = {}; - - async function calcPiA(){ - if (logger) logger.debug("Reading A Points"); - proof.pi_a = await curve.G1.multiExpAffineChunked(mkSectionReader(5), sectionsZKey[5][0].size, buffWitness, logger, "multiexp A", msmOpts); - } - - let piaPromise = calcPiA(); - //await piaPromise; - - let pib1; - - async function calcPiB1() { - if (logger) logger.debug("Reading B1 Points"); - pib1 = await curve.G1.multiExpAffineChunked(mkSectionReader(6), sectionsZKey[6][0].size, buffWitness, logger, "multiexp B1", msmOpts); - } - - let pib1Promise = calcPiB1(); - //await pib1Promise; - - async function calcPiB() { - if (logger) logger.debug("Reading B2 Points"); - proof.pi_b = await curve.G2.multiExpAffineChunked(mkSectionReader(7), sectionsZKey[7][0].size, buffWitness, logger, "multiexp B2", msmOpts); - } - - let pibPromise = calcPiB(); - //await pibPromise; - - let picPromise = (async function (){ - if (logger) logger.debug("Reading C Points"); - proof.pi_c = await curve.G1.multiExpAffineChunked(mkSectionReader(8), sectionsZKey[8][0].size, buffWitness.slice((zkey.nPublic+1)*curve.Fr.n8), logger, "multiexp C", msmOpts); - })(); - //await picPromise; - - resHPromise = (async function (){ - if (logger) logger.debug("Reading H Points"); - await abcPromise; - resH = await curve.G1.multiExpAffineChunked(mkSectionReader(9), sectionsZKey[9][0].size, buffPodd_T, logger, "multiexp H", msmOpts); - })(); - //await resHPromise; - - - const r = curve.Fr.random(); - const s = curve.Fr.random(); - - await piaPromise; - proof.pi_a = G1.add( proof.pi_a, zkey.vk_alpha_1 ); - proof.pi_a = G1.add( proof.pi_a, G1.timesFr( zkey.vk_delta_1, r )); - - await pibPromise; - proof.pi_b = G2.add( proof.pi_b, zkey.vk_beta_2 ); - proof.pi_b = G2.add( proof.pi_b, G2.timesFr( zkey.vk_delta_2, s )); - - await pib1Promise; - pib1 = G1.add( pib1, zkey.vk_beta_1 ); - pib1 = G1.add( pib1, G1.timesFr( zkey.vk_delta_1, s )); - - await Promise.all([picPromise, resHPromise]); - proof.pi_c = G1.add(proof.pi_c, resH); - - - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( proof.pi_a, s )); - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( pib1, r )); - proof.pi_c = G1.add( proof.pi_c, G1.timesFr( zkey.vk_delta_1, Fr.neg(Fr.mul(r,s) ))); - - - let publicSignals = []; - - for (let i=1; i<= zkey.nPublic; i++) { - const b = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8); - publicSignals.push(Scalar.fromRprLE(b)); - } - - proof.pi_a = G1.toObject(G1.toAffine(proof.pi_a)); - proof.pi_b = G2.toObject(G2.toAffine(proof.pi_b)); - proof.pi_c = G1.toObject(G1.toAffine(proof.pi_c)); - - proof.protocol = "groth16"; - proof.curve = curve.name; - - await fdZKey.close(); - await fdWtns.close(); - - proof = stringifyBigInts$4(proof); - publicSignals = stringifyBigInts$4(publicSignals); - - return {proof, publicSignals}; - } - - - async function buildABC1(curve, zkey, witness, coeffs, logger) { - const n8 = curve.Fr.n8; - const sCoef = 4*3 + zkey.n8r; - const nCoef = (coeffs.byteLength-4) / sCoef; - - const outBuffA = new BigBuffer(zkey.domainSize * n8); - const outBuffB = new BigBuffer(zkey.domainSize * n8); - const outBuffC = new BigBuffer(zkey.domainSize * n8); - - const outBuf = [ outBuffA, outBuffB ]; - for (let i=0; i coeffsDV[Math.floor(pos / PAGE_LEN)].getUint32(pos % PAGE_LEN, true); - } else { - const coeffsDV = new DataView(coeffs.buffer, coeffs.byteOffset, coeffs.byteLength); - getUint32 = (pos) => coeffsDV.getUint32(pos, true); - } - function getCutPoint(v) { - let m = 0, n = getUint32(0); - while (m < n) { - const k = Math.floor((n + m) / 2); - const va = getUint32(4 + k * sCoef + 4); - if (va > v) n = k - 1; else if (va < v) m = k + 1; else n = k; - } - return 4 + m * sCoef; - } - - const elementsPerChunk = Math.floor((domainSize - 1) / nChunks) + 1; - const cutPoints = []; - for (let i = 0; i < nChunks; i++) cutPoints.push(getCutPoint(i * elementsPerChunk)); - cutPoints.push(coeffs.byteLength); - - // Return a flat Uint8Array when the domain fits under BigBuffer's 1 GiB page, - // so the downstream IFFT can consume it in place (skip its defensive copy). - // Larger domains stay paged BigBuffers (the IFFT flattens those as before). - const outBytes = domainSize * n8; - const mkOut = () => (outBytes < (1 << 30)) ? new Uint8Array(outBytes) : new BigBuffer(outBytes); - const outBuffA = mkOut(); - const outBuffB = mkOut(); - const outBuffC = mkOut(); - - const inFlight = new Set(); - const tasks = []; - for (let i = 0; i < nChunks; i++) { - const outOffset = i * elementsPerChunk; - const n = Math.min(elementsPerChunk, domainSize - outOffset); - if (n <= 0) break; - const cpA = cutPoints[i], cpB = cutPoints[i + 1]; - while (inFlight.size >= maxInFlight) await Promise.race(inFlight); - if (logger) logger.debug(`buildABCStream: ${i}/${nChunks}`); - const op = (async () => { - // Gather the witness values this chunk references into a compact - // buffer (one entry per coefficient, in coefficient order) and - // rewrite each coefficient's s-index to its sequential position. - // The witness itself never enters WASM, so its size is unbounded - // (it can stay a BigBuffer) and each task ships only what it uses - // -- typically much less than a full witness copy per task. - const coeffChunk = coeffs.slice(cpA, cpB); - const nCoefChunk = (cpB - cpA) / sCoef; - const gathered = new Uint8Array(nCoefChunk * n8); - // Hot loop (one iteration per coefficient): use typed-array lane - // copies instead of set(subarray) -- per-element memcpy dispatch - // dominated the profile otherwise. Uint32 lanes on purpose: the - // data is integer bit patterns, and Float64Array stores may - // legally canonicalize NaN-patterned lanes (SetValueInBuffer is - // implementation-defined for NaN encodings). The s-field offsets - // are 4-byte aligned (sCoef and the +8 offset are multiples of 4). - const chunkU32 = new Uint32Array(coeffChunk.buffer, coeffChunk.byteOffset, coeffChunk.byteLength >> 2); - const sStep = sCoef >> 2; - const laneFast = !!witness.buffer && ((witness.byteOffset & 3) === 0) && (n8 === 32); - if (laneFast) { - const wU32 = new Uint32Array(witness.buffer, witness.byteOffset, witness.byteLength >> 2); - const gU32 = new Uint32Array(gathered.buffer); - for (let j = 0; j < nCoefChunk; j++) { - const si = chunkU32[j * sStep + 2]; - const so = si << 3, go = j << 3; - gU32[go] = wU32[so]; gU32[go + 1] = wU32[so + 1]; - gU32[go + 2] = wU32[so + 2]; gU32[go + 3] = wU32[so + 3]; - gU32[go + 4] = wU32[so + 4]; gU32[go + 5] = wU32[so + 5]; - gU32[go + 6] = wU32[so + 6]; gU32[go + 7] = wU32[so + 7]; - chunkU32[j * sStep + 2] = j; - } - } else { - const witnessIsView = !!witness.buffer; - for (let j = 0; j < nCoefChunk; j++) { - const s = chunkU32[j * sStep + 2]; - if (witnessIsView) gathered.set(witness.subarray(s * n8, (s + 1) * n8), j * n8); - else gathered.set(witness.slice(s * n8, (s + 1) * n8), j * n8); - chunkU32[j * sStep + 2] = j; - } - } - const task = [ - {cmd: "ALLOCSET", var: 0, buff: coeffChunk}, - {cmd: "ALLOCSET", var: 1, buff: gathered}, - {cmd: "ALLOC", var: 2, len: n * n8}, - {cmd: "ALLOC", var: 3, len: n * n8}, - {cmd: "ALLOC", var: 4, len: n * n8}, - {cmd: "CALL", fnName: "qap_buildABC", params: [ - {var: 0}, {val: nCoefChunk}, {var: 1}, - {var: 2}, {var: 3}, {var: 4}, - {val: outOffset}, {val: n}, {val: 0}, {val: nCoefChunk}, - ]}, - {cmd: "GET", out: 0, var: 2, len: n * n8}, - {cmd: "GET", out: 1, var: 3, len: n * n8}, - {cmd: "GET", out: 2, var: 4, len: n * n8}, - ]; - const r = await curve.tm.queueAction(task, [coeffChunk.buffer, gathered.buffer]); - outBuffA.set(r[0], outOffset * n8); - outBuffB.set(r[1], outOffset * n8); - outBuffC.set(r[2], outOffset * n8); - })(); - const slot = op.finally(() => inFlight.delete(slot)); - inFlight.add(slot); - tasks.push(slot); - } - await Promise.all(tasks); - return [outBuffA, outBuffB, outBuffC]; - } - - async function joinABC(curve, zkey, a, b, c, logger) { - const MAX_CHUNK_SIZE = 1 << 16; - - const n8 = curve.Fr.n8; - const nElements = Math.floor(a.byteLength / curve.Fr.n8); - - const promises = []; - - for (let i=0; i { - memUsage(logger); - }, interval); - } - - async function open$1(fileName, openFlags, cacheSize, pageSize) { - cacheSize = cacheSize || 4096*64; - if (typeof openFlags !== "number" && ["w+", "wx+", "r", "ax+", "a+"].indexOf(openFlags) <0) - throw new Error("Invalid open option"); - const fd =await fs.promises.open(fileName, openFlags); - - const stats = await fd.stat(); - - return new FastFile$1(fd, stats, cacheSize, pageSize, fileName); - } - - - let FastFile$1 = class FastFile { - - constructor(fd, stats, cacheSize, pageSize, fileName) { - this.fileName = fileName; - this.fd = fd; - this.pos = 0; - this.pageSize = pageSize || (1 << 8); - while (this.pageSize < stats.blksize) { - this.pageSize *= 2; - } - this.totalSize = stats.size; - this.totalPages = Math.floor((stats.size -1) / this.pageSize)+1; - this.maxPagesLoaded = Math.floor( cacheSize / this.pageSize)+1; - this.pages = {}; - this.pendingLoads = []; - this.writing = false; - this.reading = false; - this.avBuffs = []; - this.history = {}; - } - - _loadPage(p) { - const self = this; - const P = new Promise((resolve, reject)=> { - self.pendingLoads.push({ - page: p, - resolve: resolve, - reject: reject - }); - }); - self.__statusPage("After Load request: ", p); - return P; - } - - __statusPage(s, p) { - const logEntry = []; - const self=this; - if (!self.logHistory) return; - logEntry.push("==" + s+ " " +p); - let S = ""; - for (let i=0; i " + self.history[p][i][j]); - } - } - } - - - - _triggerLoad() { - const self = this; - - if (self.reading) return; - if (self.pendingLoads.length==0) return; - - const pageIdxs = Object.keys(self.pages); - - const deletablePages = []; - for (let i=0; i0) && - ( (typeof self.pages[self.pendingLoads[0].page] != "undefined" ) - ||( (freePages>0) - ||(deletablePages.length>0)))) { - const load = self.pendingLoads.shift(); - if (typeof self.pages[load.page] != "undefined") { - self.pages[load.page].pendingOps ++; - const idx = deletablePages.indexOf(load.page); - if (idx>=0) deletablePages.splice(idx, 1); - if (self.pages[load.page].loading) { - self.pages[load.page].loading.push(load); - } else { - load.resolve(); - } - self.__statusPage("After Load (cached): ", load.page); - - } else { - if (freePages) { - freePages--; - } else { - const fp = deletablePages.shift(); - self.__statusPage("Before Unload: ", fp); - self.avBuffs.unshift(self.pages[fp]); - delete self.pages[fp]; - self.__statusPage("After Unload: ", fp); - } - - if (load.page>=self.totalPages) { - self.pages[load.page] = getNewPage(); - load.resolve(); - self.__statusPage("After Load (new): ", load.page); - } else { - self.reading = true; - self.pages[load.page] = getNewPage(); - self.pages[load.page].loading = [load]; - ops.push(self.fd.read(self.pages[load.page].buff, 0, self.pageSize, load.page*self.pageSize).then((res)=> { - self.pages[load.page].size = res.bytesRead; - const loading = self.pages[load.page].loading; - delete self.pages[load.page].loading; - for (let i=0; i { - load.reject(err); - })); - self.__statusPage("After Load (loading): ", load.page); - } - } - } - // if (ops.length>1) console.log(ops.length); - - Promise.all(ops).then( () => { - self.reading = false; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - self._tryClose(); - }); - - function getNewPage() { - if (self.avBuffs.length>0) { - const p = self.avBuffs.shift(); - p.dirty = false; - p.pendingOps = 1; - p.size =0; - return p; - } else { - return { - dirty: false, - buff: new Uint8Array(self.pageSize), - pendingOps: 1, - size: 0 - }; - } - } - - } - - - _triggerWrite() { - const self = this; - if (self.writing) return; - - const pageIdxs = Object.keys(self.pages); - - const ops = []; - - for (let i=0; i { - page.writing = false; - return; - }, (err) => { - console.log("ERROR Writing: "+err); - self.error = err; - self._tryClose(); - })); - } - } - - if (self.writing) { - Promise.all(ops).then( () => { - self.writing = false; - setImmediate(self._triggerWrite.bind(self)); - self._tryClose(); - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - }); - } - } - - _getDirtyPage() { - for (let p in this.pages) { - if (this.pages[p].dirty) return p; - } - return -1; - } - - async write(buff, pos) { - if (buff.byteLength == 0) return; - const self = this; - /* - if (buff.byteLength > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(buff.byteLength * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } - */ - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+buff.byteLength; - if (self.totalSize < pos + buff.byteLength) self.totalSize = pos + buff.byteLength; - if (self.pendingClose) - throw new Error("Writing a closing file"); - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + buff.byteLength -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - let r = buff.byteLength; - while (r>0) { - await pagePromises[p-firstPage]; - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = buff.slice( buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.pages[p].buff.buffer, o, l); - dstView.set(srcView); - self.pages[p].dirty = true; - self.pages[p].pendingOps --; - self.pages[p].size = Math.max(o+l, self.pages[p].size); - if (p>=self.totalPages) { - self.totalPages = p+1; - } - r = r-l; - p ++; - o = 0; - if (!self.writing) setImmediate(self._triggerWrite.bind(self)); - } - } - - async read(len, pos) { - const self = this; - let buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - async readToBuffer(buffDst, offset, len, pos) { - if (len == 0) { - return; - } - const self = this; - if (len > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(len * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+len; - if (self.pendingClose) - throw new Error("Reading a closing file"); - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + len -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - // Remaining bytes to read - let r = pos + len > self.totalSize ? len - (pos + len - self.totalSize): len; - while (r>0) { - await pagePromises[p - firstPage]; - self.__statusPage("After Await (read): ", p); - - // bytes to copy from this page - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = new Uint8Array(self.pages[p].buff.buffer, self.pages[p].buff.byteOffset + o, l); - buffDst.set(srcView, offset+len-r); - self.pages[p].pendingOps --; - - self.__statusPage("After Op done: ", p); - - r = r-l; - p ++; - o = 0; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - } - - this.pos = pos + len; - - } - - - _tryClose() { - const self = this; - if (!self.pendingClose) return; - if (self.error) { - self.pendingCloseReject(self.error); - } - const p = self._getDirtyPage(); - if ((p>=0) || (self.writing) || (self.reading) || (self.pendingLoads.length>0)) return; - self.pendingClose(); - } - - close() { - const self = this; - if (self.pendingClose) - throw new Error("Closing the file twice"); - return new Promise((resolve, reject) => { - self.pendingClose = resolve; - self.pendingCloseReject = reject; - self._tryClose(); - }).then(()=> { - self.fd.close(); - }, (err) => { - self.fd.close(); - throw (err); - }); - } - - async discard() { - const self = this; - await self.close(); - await fs.promises.unlink(this.fileName); - } - - async writeULE32(v, pos) { - const self = this; - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, true); - - await self.write(tmpBuff32, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, false); - - await self.write(tmpBuff32, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - const tmpBuff64 = new Uint8Array(8); - const tmpBuff64v = new DataView(tmpBuff64.buffer); - - tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64, pos); - } - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - if (self.pendingClose) { - throw new Error("Reading a closing file"); - } - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - let currentPage = Math.floor(currentPosition / self.pageSize); - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - //Read page - let pagePromise = self._loadPage(currentPage); - self._triggerLoad(); - await pagePromise; - self.__statusPage("After Await (read): ", currentPage); - - let offsetOnPage = currentPosition % self.pageSize; - - const dataArray = new Uint8Array( - self.pages[currentPage].buff.buffer, - self.pages[currentPage].buff.byteOffset + offsetOnPage, - self.pageSize - offsetOnPage - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * this.pageSize + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * this.pageSize + offsetOnPage + dataArray.length; - } - - self.pages[currentPage].pendingOps--; - self.__statusPage("After Op done: ", currentPage); - - currentPosition = self.pos; - currentPage++; - - if (self.pendingLoads.length > 0) setImmediate(self._triggerLoad.bind(self)); - } - - return str; - } - }; - - function createNew$1(o) { - const initialSize = o.initialSize || 1<<20; - const fd = new MemFile$1(); - fd.o = o; - fd.o.data = new Uint8Array(initialSize); - fd.allocSize = initialSize; - fd.totalSize = 0; - fd.readOnly = false; - fd.pos = 0; - return fd; - } - - function readExisting$5(o) { - const fd = new MemFile$1(); - fd.o = o; - fd.allocSize = o.data.byteLength; - fd.totalSize = o.data.byteLength; - fd.readOnly = true; - fd.pos = 0; - return fd; - } - - const tmpBuff32$3 = new Uint8Array(4); - const tmpBuff32v$3 = new DataView(tmpBuff32$3.buffer); - const tmpBuff64$3 = new Uint8Array(8); - const tmpBuff64v$3 = new DataView(tmpBuff64$3.buffer); - - let MemFile$1 = class MemFile { - - constructor() { - this.pageSize = 1 << 14; // for compatibility - } - - _resizeIfNeeded(newLen) { - if (newLen > this.allocSize) { - const newAllocSize = Math.max( - this.allocSize + (1 << 20), - Math.floor(this.allocSize * 1.1), - newLen - ); - const newData = new Uint8Array(newAllocSize); - newData.set(this.o.data); - this.o.data = newData; - this.allocSize = newAllocSize; - } - } - - async write(buff, pos) { - const self =this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) throw new Error("Writing a read only file"); - - this._resizeIfNeeded(pos + buff.byteLength); - - this.o.data.set(buff.slice(), pos); - - if (pos + buff.byteLength > this.totalSize) this.totalSize = pos + buff.byteLength; - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDest, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const buffSrc = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + pos, len); - - buffDest.set(buffSrc, offset); - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - - const buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - if (this.o.data.byteLength != this.totalSize) { - this.o.data = this.o.data.slice(0, this.totalSize); - } - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$3.setUint32(0, v, true); - - await self.write(tmpBuff32$3, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$3.setUint32(0, v, false); - - await self.write(tmpBuff32$3, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$3.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$3.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$3, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - const dataArray = new Uint8Array( - self.o.data.buffer, - currentPosition, - this.totalSize - currentPosition - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - let endOfStringFound = indexEndOfString !== -1; - - let str = ""; - if (endOfStringFound) { - str = new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPosition + indexEndOfString + 1; - } else { - self.pos = currentPosition; - } - return str; - } - }; - - const PAGE_SIZE$1 = 1<<22; - - function createNew(o) { - const initialSize = o.initialSize || 0; - const fd = new BigMemFile$1(); - fd.o = o; - const nPages = initialSize ? Math.floor((initialSize - 1) / PAGE_SIZE$1)+1 : 0; - fd.o.data = []; - for (let i=0; i0) { - const l = (o+r > PAGE_SIZE$1) ? (PAGE_SIZE$1 -o) : r; - const srcView = buff.slice(buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.o.data[p].buffer, o, l); - dstView.set(srcView); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDst, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const firstPage = Math.floor(pos / PAGE_SIZE$1); - - let p = firstPage; - let o = pos % PAGE_SIZE$1; - // Remaining bytes to read - let r = len; - while (r>0) { - // bytes to copy from this page - const l = (o+r > PAGE_SIZE$1) ? (PAGE_SIZE$1 -o) : r; - const srcView = new Uint8Array(self.o.data[p].buffer, o, l); - buffDst.set(srcView, offset+len-r); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - const buff = new Uint8Array(len); - - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$2.setUint32(0, v, true); - - await self.write(tmpBuff32$2, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$2.setUint32(0, v, false); - - await self.write(tmpBuff32$2, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$2.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$2.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$2, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - const fixedSize = 2048; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - let currentPage = Math.floor(currentPosition / PAGE_SIZE$1); - let offsetOnPage = currentPosition % PAGE_SIZE$1; - - if (self.o.data[currentPage] === undefined) { - throw new Error("ERROR"); - } - - let readLength = Math.min(fixedSize, self.o.data[currentPage].length - offsetOnPage); - const dataArray = new Uint8Array(self.o.data[currentPage].buffer, offsetOnPage, readLength); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * PAGE_SIZE$1 + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * PAGE_SIZE$1 + offsetOnPage + dataArray.length; - } - - currentPosition = self.pos; - } - return str; - } - }; - - /* global fetch */ - - const DEFAULT_CACHE_SIZE = (1 << 16); - const DEFAULT_PAGE_SIZE = (1 << 13); - - - async function createOverride(o, b, c) { - if (typeof o === "string") { - o = { - type: "file", - fileName: o, - cacheSize: DEFAULT_CACHE_SIZE, - pageSize: DEFAULT_PAGE_SIZE - }; - } - if (o.type == "file") { - return await open$1(o.fileName, O_TRUNC | O_CREAT | O_RDWR, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return createNew$1(o); - } else if (o.type == "bigMem") { - return createNew(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } - } - - async function readExisting$3(o, b, c) { - if (o instanceof Uint8Array) { - o = { - type: "mem", - data: o - }; - } - { - if (typeof o === "string") { - const buff = await fetch(o).then( function(res) { - return res.arrayBuffer(); - }).then(function (ab) { - return new Uint8Array(ab); - }); - o = { - type: "mem", - data: buff - }; - } - } - if (o.type == "file") { - return await open$1(o.fileName, O_RDONLY, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return await readExisting$5(o); - } else if (o.type == "bigMem") { - return await readExisting$4(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } - } - - /* - - Copyright 2020 0KIMS association. - - 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. - - */ - - function flatArray(a) { - let res = []; - fillArray(res, a); - return res; - - function fillArray(res, a) { - if (Array.isArray(a)) { - for (let i = 0; i < a.length; i++) { - fillArray(res, a[i]); - } - } else { - res.push(a); - } - } - } - - // Ref https://github.com/iden3/circom/commit/ec6388cf6eb62463539cb4c40cc3ceae9826de19 - function normalize(n, prime) { - let res = BigInt(n) % prime; - if (res < 0) res += prime; - return res; - } - - function fnvHash(str) { - const uint64_max = BigInt(2) ** BigInt(64); - let hash = BigInt("0xCBF29CE484222325"); - for (let i = 0; i < str.length; i++) { - hash ^= BigInt(str[i].charCodeAt(0)); - hash *= BigInt(0x100000001B3); - hash %= uint64_max; - } - let shash = hash.toString(16); - let n = 16 - shash.length; - shash = "0".repeat(n).concat(shash); - return shash; - } - - // Note that this pads zeros - function toArray32(s, size) { - const res = []; //new Uint32Array(size); //has no unshift - let rem = BigInt(s); - const radix = BigInt(0x100000000); - while (rem) { - res.unshift(Number(rem % radix)); - rem = rem / radix; - } - if (size) { - let i = size - res.length; - while (i > 0) { - res.unshift(0); - i--; - } - } - return res; - } - - /* globals WebAssembly */ - /* - - Copyright 2020 0KIMS association. - - 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. - - */ - - - async function builder(code, options) { - let instance; - let wc; - let memory; - options = options || {}; - - // Only circom 2 implements version lookup through exports in the WASM - // We default to `1` and update if we see the `getVersion` export (major version) - // These are updated after the instance is instantiated, assuming the functions are available - let majorVersion = 1; - // After Circom 2.0.7, Blaine added exported functions for getting minor and patch versions - let minorVersion = 0; - // If we can't look up the patch version, assume the lowest - let patchVersion = 0; - - let codeIsWebAssemblyInstance = false; - - // If code is already prepared WebAssembly.Instance, we use it directly - if (code instanceof WebAssembly.Instance) { - instance = code; - codeIsWebAssemblyInstance = true; - } else { - let memorySize = 32767; - - if (options.memorySize) { - // make sure we have int - memorySize = parseInt(options.memorySize); - if (memorySize < 0) { - throw new Error("Invalid memory size"); - } - } - - let memoryAllocated = false; - while (!memoryAllocated) { - try { - memory = new WebAssembly.Memory({initial: memorySize}); - memoryAllocated = true; - } catch (err) { - if (memorySize <= 1) { - throw err; - } - console.warn("Could not allocate " + memorySize * 1024 * 64 + " bytes. This may cause severe instability. Trying with " + memorySize * 1024 * 64 / 2 + " bytes"); - memorySize = Math.floor(memorySize / 2); - } - } - - const wasmModule = await WebAssembly.compile(code); - - let errStr = ""; - let msgStr = ""; - - instance = await WebAssembly.instantiate(wasmModule, { - env: { - "memory": memory - }, - runtime: { - printDebug : function(value) { - console.log("printDebug:", value); - }, - exceptionHandler: function (code) { - let err; - if (code === 1) { - err = "Signal not found. "; - } else if (code === 2) { - err = "Too many signals set. "; - } else if (code === 3) { - err = "Signal already set. "; - } else if (code === 4) { - err = "Assert Failed. "; - } else if (code === 5) { - err = "Not enough memory. "; - } else if (code === 6) { - err = "Input signal array access exceeds the size. "; - } else { - err = "Unknown error. "; - } - console.error("ERROR: ", code, errStr); - throw new Error(err + errStr); - }, - // A new way of logging messages was added in Circom 2.0.7 that requires 2 new imports - // `printErrorMessage` and `writeBufferMessage`. - printErrorMessage: function () { - errStr += getMessage() + "\n"; - }, - writeBufferMessage: function () { - const msg = getMessage(); - // Any calls to `log()` will always end with a `\n`, so that's when we print and reset - if (msg === "\n") { - console.log(msgStr); - msgStr = ""; - } else { - // If we've buffered other content, put a space in between the items - if (msgStr !== "") { - msgStr += " "; - } - // Then append the message to the message we are creating - msgStr += msg; - } - }, - showSharedRWMemory: function () { - const shared_rw_memory_size = instance.exports.getFieldNumLen32(); - const arr = new Uint32Array(shared_rw_memory_size); - for (let j = 0; j < shared_rw_memory_size; j++) { - arr[shared_rw_memory_size - 1 - j] = instance.exports.readSharedRWMemory(j); - } - - // In circom 2.0.7, they changed the log() function to allow strings and changed the - // output API. This smoothes over the breaking change. - if (majorVersion >= 2 && (minorVersion >= 1 || patchVersion >= 7)) { - // If we've buffered other content, put a space in between the items - if (msgStr !== "") { - msgStr += " "; - } - // Then append the value to the message we are creating - const msg = (Scalar.fromArray(arr, 0x100000000).toString()); - msgStr += msg; - } else { - console.log(Scalar.fromArray(arr, 0x100000000)); - } - }, - error: function (code, pstr, a, b, c, d) { - let errStr; - if (code === 7) { - errStr = p2str(pstr) + " " + wc.getFr(b).toString() + " != " + wc.getFr(c).toString() + " " + p2str(d); - } else if (code === 9) { - errStr = p2str(pstr) + " " + wc.getFr(b).toString() + " " + p2str(c); - } else if ((code === 5) && (options.sym)) { - errStr = p2str(pstr) + " " + options.sym.labelIdx2Name[c]; - } else { - errStr = p2str(pstr) + " " + a + " " + b + " " + c + " " + d; - } - console.log("ERROR: ", code, errStr); - throw new Error(errStr); - }, - log: function (a) { - console.log(wc.getFr(a).toString()); - }, - logGetSignal: function (signal, pVal) { - if (options.logGetSignal) { - options.logGetSignal(signal, wc.getFr(pVal)); - } - }, - logSetSignal: function (signal, pVal) { - if (options.logSetSignal) { - options.logSetSignal(signal, wc.getFr(pVal)); - } - }, - logStartComponent: function (cIdx) { - if (options.logStartComponent) { - options.logStartComponent(cIdx); - } - }, - logFinishComponent: function (cIdx) { - if (options.logFinishComponent) { - options.logFinishComponent(cIdx); - } - } - } - }); - } - - if (typeof instance.exports.getVersion == "function") { - majorVersion = instance.exports.getVersion(); - } - if (typeof instance.exports.getMinorVersion == "function") { - minorVersion = instance.exports.getMinorVersion(); - } - if (typeof instance.exports.getPatchVersion == "function") { - patchVersion = instance.exports.getPatchVersion(); - } - - const sanityCheck = - options && - ( - options.sanityCheck || - options.logGetSignal || - options.logSetSignal || - options.logStartComponent || - options.logFinishComponent - ); - - // We explicitly check for major version 2 in case there's a circom v3 in the future - if (majorVersion === 2) { - wc = new WitnessCalculatorCircom2(instance, sanityCheck); - } else if (majorVersion === 1) { - if (codeIsWebAssemblyInstance) { - throw new Error('Loading code from WebAssembly instance is not supported for circom version 1'); - } - wc = new WitnessCalculatorCircom1(memory, instance, sanityCheck); - } else { - throw new Error(`Unsupported circom version: ${majorVersion}`); - } - return wc; - - function getMessage() { - let message = ""; - let c = instance.exports.getMessageChar(); - while (c !== 0) { - message += String.fromCharCode(c); - c = instance.exports.getMessageChar(); - } - return message; - } - - function p2str(p) { - const i8 = new Uint8Array(memory.buffer); - - const bytes = []; - - for (let i = 0; i8[p + i] > 0; i++) bytes.push(i8[p + i]); - - return String.fromCharCode.apply(null, bytes); - } - } - - class WitnessCalculatorCircom1 { - constructor(memory, instance, sanityCheck) { - this.memory = memory; - this.i32 = new Uint32Array(memory.buffer); - this.instance = instance; - - this.n32 = (this.instance.exports.getFrLen() >> 2) - 2; - const pRawPrime = this.instance.exports.getPRawPrime(); - - const arr = new Array(this.n32); - for (let i = 0; i < this.n32; i++) { - arr[this.n32 - 1 - i] = this.i32[(pRawPrime >> 2) + i]; - } - - this.prime = Scalar.fromArray(arr, 0x100000000); - - this.Fr = new ZqField(this.prime); - - this.mask32 = Scalar.fromString("FFFFFFFF", 16); - this.NVars = this.instance.exports.getNVars(); - this.n64 = Math.floor((this.Fr.bitLength - 1) / 64) + 1; - this.R = this.Fr.e(Scalar.shiftLeft(1, this.n64 * 64)); - this.RInv = this.Fr.inv(this.R); - this.sanityCheck = sanityCheck; - } - - circom_version() { - return 1; - } - - async _doCalculateWitness(input, sanityCheck) { - this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0); - const pSigOffset = this.allocInt(); - const pFr = this.allocFr(); - const keys = Object.keys(input); - keys.forEach((k) => { - const h = fnvHash(k); - const hMSB = parseInt(h.slice(0, 8), 16); - const hLSB = parseInt(h.slice(8, 16), 16); - try { - this.instance.exports.getSignalOffset32(pSigOffset, 0, hMSB, hLSB); - } catch (err) { - throw new Error(`Signal ${k} is not an input of the circuit.`); - } - const sigOffset = this.getInt(pSigOffset); - const fArr = flatArray(input[k]); - for (let i = 0; i < fArr.length; i++) { - this.setFr(pFr, fArr[i]); - this.instance.exports.setSignal(0, 0, sigOffset + i, pFr); - } - }); - } - - async calculateWitness(input, sanityCheck) { - const self = this; - - const old0 = self.i32[0]; - const w = []; - - await self._doCalculateWitness(input, sanityCheck); - - for (let i = 0; i < self.NVars; i++) { - const pWitness = self.instance.exports.getPWitness(i); - w.push(self.getFr(pWitness)); - } - - self.i32[0] = old0; - return w; - } - - async calculateBinWitness(input, sanityCheck) { - const self = this; - - const old0 = self.i32[0]; - - await self._doCalculateWitness(input, sanityCheck); - - const pWitnessBuffer = self.instance.exports.getWitnessBuffer(); - - self.i32[0] = old0; - - const buff = self.memory.buffer.slice(pWitnessBuffer, pWitnessBuffer + (self.NVars * self.n64 * 8)); - return new Uint8Array(buff); - } - - allocInt() { - const p = this.i32[0]; - this.i32[0] = p + 8; - return p; - } - - allocFr() { - const p = this.i32[0]; - this.i32[0] = p + this.n32 * 4 + 8; - return p; - } - - getInt(p) { - return this.i32[p >> 2]; - } - - setInt(p, v) { - this.i32[p >> 2] = v; - } - - getFr(p) { - const self = this; - const idx = (p >> 2); - - if (self.i32[idx + 1] & 0x80000000) { - const arr = new Array(self.n32); - for (let i = 0; i < self.n32; i++) { - arr[self.n32 - 1 - i] = self.i32[idx + 2 + i]; - } - const res = self.Fr.e(Scalar.fromArray(arr, 0x100000000)); - if (self.i32[idx + 1] & 0x40000000) { - return fromMontgomery(res); - } else { - return res; - } - - } else { - if (self.i32[idx] & 0x80000000) { - return self.Fr.e(self.i32[idx] - 0x100000000); - } else { - return self.Fr.e(self.i32[idx]); - } - } - - function fromMontgomery(n) { - return self.Fr.mul(self.RInv, n); - } - - } - - - setFr(p, v) { - const self = this; - - v = self.Fr.e(v); - - const minShort = self.Fr.neg(self.Fr.e("80000000", 16)); - const maxShort = self.Fr.e("7FFFFFFF", 16); - - if ((self.Fr.geq(v, minShort)) - && (self.Fr.leq(v, maxShort))) { - let a; - if (self.Fr.geq(v, self.Fr.zero)) { - a = Scalar.toNumber(v); - } else { - a = Scalar.toNumber(self.Fr.sub(v, minShort)); - a = a - 0x80000000; - a = 0x100000000 + a; - } - self.i32[(p >> 2)] = a; - self.i32[(p >> 2) + 1] = 0; - return; - } - - self.i32[(p >> 2)] = 0; - self.i32[(p >> 2) + 1] = 0x80000000; - const arr = Scalar.toArray(v, 0x100000000); - for (let i = 0; i < self.n32; i++) { - const idx = arr.length - 1 - i; - - if (idx >= 0) { - self.i32[(p >> 2) + 2 + i] = arr[idx]; - } else { - self.i32[(p >> 2) + 2 + i] = 0; - } - } - } - } - - class WitnessCalculatorCircom2 { - constructor(instance, sanityCheck) { - this.instance = instance; - - this.version = this.instance.exports.getVersion(); - this.n32 = this.instance.exports.getFieldNumLen32(); - - this.instance.exports.getRawPrime(); - const arr = new Uint32Array(this.n32); - for (let i = 0; i < this.n32; i++) { - arr[this.n32 - 1 - i] = this.instance.exports.readSharedRWMemory(i); - } - this.prime = Scalar.fromArray(arr, 0x100000000); - - this.witnessSize = this.instance.exports.getWitnessSize(); - - this.sanityCheck = sanityCheck; - } - - circom_version() { - return this.instance.exports.getVersion(); - } - - async _doCalculateWitness(input, sanityCheck) { - //input is assumed to be a map from signals to arrays of bigints - this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0); - const keys = Object.keys(input); - let input_counter = 0; - keys.forEach((k) => { - const h = fnvHash(k); - const hMSB = parseInt(h.slice(0, 8), 16); - const hLSB = parseInt(h.slice(8, 16), 16); - const fArr = flatArray(input[k]); - // Slight deviation from https://github.com/iden3/circom/blob/v2.1.6/code_producers/src/wasm_elements/common/witness_calculator.js - // because I don't know when this exported function was added - if (typeof this.instance.exports.getInputSignalSize === "function") { - let signalSize = this.instance.exports.getInputSignalSize(hMSB, hLSB); - if (signalSize < 0) { - throw new Error(`Signal ${k} not found\n`); - } - if (fArr.length < signalSize) { - throw new Error(`Not enough values for input signal ${k}\n`); - } - if (fArr.length > signalSize) { - throw new Error(`Too many values for input signal ${k}\n`); - } - } - for (let i = 0; i < fArr.length; i++) { - const arrFr = toArray32(normalize(fArr[i], this.prime), this.n32); - for (let j = 0; j < this.n32; j++) { - this.instance.exports.writeSharedRWMemory(j, arrFr[this.n32 - 1 - j]); - } - try { - this.instance.exports.setInputSignal(hMSB, hLSB, i); - input_counter++; - } catch (err) { - // console.log(`After adding signal ${i} of ${k}`) - throw new Error(err); - } - } - - }); - if (input_counter < this.instance.exports.getInputSize()) { - throw new Error(`Not all inputs have been set. Only ${input_counter} out of ${this.instance.exports.getInputSize()}`); - } - } - - async calculateWitness(input, sanityCheck) { - const w = []; - - await this._doCalculateWitness(input, sanityCheck); - - for (let i = 0; i < this.witnessSize; i++) { - this.instance.exports.getWitness(i); - const arr = new Uint32Array(this.n32); - for (let j = 0; j < this.n32; j++) { - arr[this.n32 - 1 - j] = this.instance.exports.readSharedRWMemory(j); - } - w.push(Scalar.fromArray(arr, 0x100000000)); - } - - return w; - } - - async calculateWTNSBin(input, sanityCheck) { - const buff32 = new Uint32Array(this.witnessSize * this.n32 + this.n32 + 11); - const buff = new Uint8Array(buff32.buffer); - await this._doCalculateWitness(input, sanityCheck); - - //"wtns" - buff[0] = "w".charCodeAt(0); - buff[1] = "t".charCodeAt(0); - buff[2] = "n".charCodeAt(0); - buff[3] = "s".charCodeAt(0); - - //version 2 - buff32[1] = 2; - - //number of sections: 2 - buff32[2] = 2; - - //id section 1 - buff32[3] = 1; - - const n8 = this.n32 * 4; - //id section 1 length in 64bytes - const idSection1length = 8 + n8; - const idSection1lengthHex = idSection1length.toString(16); - buff32[4] = parseInt(idSection1lengthHex.slice(0, 8), 16); - buff32[5] = parseInt(idSection1lengthHex.slice(8, 16), 16); - - //this.n32 - buff32[6] = n8; - - //prime number - this.instance.exports.getRawPrime(); - - let pos = 7; - for (let j = 0; j < this.n32; j++) { - buff32[pos + j] = this.instance.exports.readSharedRWMemory(j); - } - pos += this.n32; - - // witness size - buff32[pos] = this.witnessSize; - pos++; - - //id section 2 - buff32[pos] = 2; - pos++; - - // section 2 length - const idSection2length = n8 * this.witnessSize; - const idSection2lengthHex = idSection2length.toString(16); - buff32[pos] = parseInt(idSection2lengthHex.slice(0, 8), 16); - buff32[pos + 1] = parseInt(idSection2lengthHex.slice(8, 16), 16); - - pos += 2; - for (let i = 0; i < this.witnessSize; i++) { - this.instance.exports.getWitness(i); - for (let j = 0; j < this.n32; j++) { - buff32[pos + j] = this.instance.exports.readSharedRWMemory(j); - } - pos += this.n32; - } - - return buff; - } - - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - const { unstringifyBigInts: unstringifyBigInts$b} = utils; - - async function wtnsCalculate(_input, wasmFileName, wtnsFileName, options) { - const input = unstringifyBigInts$b(_input); - - const fdWasm = await readExisting$3(wasmFileName); - const wasm = await fdWasm.read(fdWasm.totalSize); - await fdWasm.close(); - - const wc = await builder(wasm, options); - if (wc.circom_version() === 1) { - const w = await wc.calculateBinWitness(input); - - const fdWtns = await createBinFile(wtnsFileName, "wtns", 2, 2); - - await writeBin(fdWtns, w, wc.prime); - await fdWtns.close(); - } else { - const fdWtns = await createOverride(wtnsFileName); - - const w = await wc.calculateWTNSBin(input); - - await fdWtns.write(w); - await fdWtns.close(); - } - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - const {unstringifyBigInts: unstringifyBigInts$a} = utils; - - async function groth16FullProve(_input, wasmFile, zkeyFileName, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$a(_input); - - const wtns= { - type: "mem" - }; - await wtnsCalculate(input, wasmFile, wtns, wtnsCalcOptions); - return await groth16Prove(zkeyFileName, wtns, logger, proverOptions); - } - - /* - Copyright 2018 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - const {unstringifyBigInts: unstringifyBigInts$9} = utils; - - async function groth16Verify(_vk_verifier, _publicSignals, _proof, logger) { - /* - let cpub = vk_verifier.IC[0]; - for (let s= 0; s< vk_verifier.nPublic; s++) { - cpub = G1.add( cpub, G1.timesScalar( vk_verifier.IC[s+1], publicSignals[s])); - } - */ - - const vk_verifier = unstringifyBigInts$9(_vk_verifier); - const proof = unstringifyBigInts$9(_proof); - const publicSignals = unstringifyBigInts$9(_publicSignals); - - const curve = await getCurveFromName(vk_verifier.curve); - - const IC0 = curve.G1.fromObject(vk_verifier.IC[0]); - const IC = new Uint8Array(curve.G1.F.n8*2 * publicSignals.length); - const w = new Uint8Array(curve.Fr.n8 * publicSignals.length); - - if (!publicInputsAreValid$2(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - for (let i=0; i. - */ - const { unstringifyBigInts: unstringifyBigInts$8} = utils; - - function p256$2(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0"+nstr; - nstr = `"0x${nstr}"`; - return nstr; - } - - async function groth16ExportSolidityCallData(_proof, _pub) { - const proof = unstringifyBigInts$8(_proof); - const pub = unstringifyBigInts$8(_pub); - - let inputs = ""; - for (let i=0; i. - */ - - var groth16 = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportSolidityCallData: groth16ExportSolidityCallData, - fullProve: groth16FullProve, - prove: groth16Prove, - verify: groth16Verify - }); - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - function hashToG2(curve, hash) { - const hashV = new DataView(hash.buffer, hash.byteOffset, hash.byteLength); - const seed = []; - for (let i=0; i<8; i++) { - seed[i] = hashV.getUint32(i*4); - } - - const rng = new ChaCha(seed); - - const g2_sp = curve.G2.fromRng(rng); - - return g2_sp; - } - - function getG2sp(curve, persinalization, challenge, g1s, g1sx) { - - const h = blake2b.create({ dkLen: 64 }); - const b1 = new Uint8Array([persinalization]); - h.update(b1); - h.update(challenge); - const b3 = curve.G1.toUncompressed(g1s); - h.update( b3); - const b4 = curve.G1.toUncompressed(g1sx); - h.update( b4); - const hash =h.digest(); - - return hashToG2(curve, hash); - } - - function calculatePubKey(k, curve, personalization, challengeHash, rng ) { - k.g1_s = curve.G1.toAffine(curve.G1.fromRng(rng)); - k.g1_sx = curve.G1.toAffine(curve.G1.timesFr(k.g1_s, k.prvKey)); - k.g2_sp = curve.G2.toAffine(getG2sp(curve, personalization, challengeHash, k.g1_s, k.g1_sx)); - k.g2_spx = curve.G2.toAffine(curve.G2.timesFr(k.g2_sp, k.prvKey)); - return k; - } - - function createPTauKey(curve, challengeHash, rng) { - const key = { - tau: {}, - alpha: {}, - beta: {} - }; - key.tau.prvKey = curve.Fr.fromRng(rng); - key.alpha.prvKey = curve.Fr.fromRng(rng); - key.beta.prvKey = curve.Fr.fromRng(rng); - calculatePubKey(key.tau, curve, 0, challengeHash, rng); - calculatePubKey(key.alpha, curve, 1, challengeHash, rng); - calculatePubKey(key.beta, curve, 2, challengeHash, rng); - return key; - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - async function writePTauHeader(fd, curve, power, ceremonyPower) { - // Write the header - /////////// - - if (! ceremonyPower) ceremonyPower = power; - await fd.writeULE32(1); // Header type - const pHeaderSize = fd.pos; - await fd.writeULE64(0); // Temporally set to 0 length - - await fd.writeULE32(curve.F1.n64*8); - - const buff = new Uint8Array(curve.F1.n8); - Scalar.toRprLE(buff, 0, curve.q, curve.F1.n8); - await fd.write(buff); - await fd.writeULE32(power); // power - await fd.writeULE32(ceremonyPower); // power - - const headerSize = fd.pos - pHeaderSize - 8; - - const oldPos = fd.pos; - - await fd.writeULE64(headerSize, pHeaderSize); - - fd.pos = oldPos; - } - - async function readPTauHeader(fd, sections) { - if (!sections[1]) throw new Error(fd.fileName + ": File has no header"); - if (sections[1].length>1) throw new Error(fd.fileName +": File has more than one header"); - - fd.pos = sections[1][0].p; - const n8 = await fd.readULE32(); - const buff = await fd.read(n8); - const q = Scalar.fromRprLE(buff); - - const curve = await getCurveFromQ(q); - - if (curve.F1.n64*8 != n8) throw new Error(fd.fileName +": Invalid size"); - - const power = await fd.readULE32(); - const ceremonyPower = await fd.readULE32(); - - if (fd.pos-sections[1][0].p != sections[1][0].size) throw new Error("Invalid PTau header size"); - - return {curve, power, ceremonyPower}; - } - - - async function readPtauPubKey(fd, curve, montgomery) { - - const buff = await fd.read(curve.F1.n8*2*6 + curve.F2.n8*2*3); - - return fromPtauPubKeyRpr(buff, 0, curve, montgomery); - } - - function fromPtauPubKeyRpr(buff, pos, curve, montgomery) { - - const key = { - tau: {}, - alpha: {}, - beta: {} - }; - - key.tau.g1_s = readG1(); - key.tau.g1_sx = readG1(); - key.alpha.g1_s = readG1(); - key.alpha.g1_sx = readG1(); - key.beta.g1_s = readG1(); - key.beta.g1_sx = readG1(); - key.tau.g2_spx = readG2(); - key.alpha.g2_spx = readG2(); - key.beta.g2_spx = readG2(); - - return key; - - function readG1() { - let p; - if (montgomery) { - p = curve.G1.fromRprLEM( buff, pos ); - } else { - p = curve.G1.fromRprUncompressed( buff, pos ); - } - pos += curve.G1.F.n8*2; - return p; - } - - function readG2() { - let p; - if (montgomery) { - p = curve.G2.fromRprLEM( buff, pos ); - } else { - p = curve.G2.fromRprUncompressed( buff, pos ); - } - pos += curve.G2.F.n8*2; - return p; - } - } - - function toPtauPubKeyRpr(buff, pos, curve, key, montgomery) { - - writeG1(key.tau.g1_s); - writeG1(key.tau.g1_sx); - writeG1(key.alpha.g1_s); - writeG1(key.alpha.g1_sx); - writeG1(key.beta.g1_s); - writeG1(key.beta.g1_sx); - writeG2(key.tau.g2_spx); - writeG2(key.alpha.g2_spx); - writeG2(key.beta.g2_spx); - - async function writeG1(p) { - if (montgomery) { - curve.G1.toRprLEM(buff, pos, p); - } else { - curve.G1.toRprUncompressed(buff, pos, p); - } - pos += curve.F1.n8*2; - } - - async function writeG2(p) { - if (montgomery) { - curve.G2.toRprLEM(buff, pos, p); - } else { - curve.G2.toRprUncompressed(buff, pos, p); - } - pos += curve.F2.n8*2; - } - - return buff; - } - - async function writePtauPubKey(fd, curve, key, montgomery) { - const buff = new Uint8Array(curve.F1.n8*2*6 + curve.F2.n8*2*3); - toPtauPubKeyRpr(buff, 0, curve, key, montgomery); - await fd.write(buff); - } - - async function readContribution(fd, curve) { - const c = {}; - - c.tauG1 = await readG1(); - c.tauG2 = await readG2(); - c.alphaG1 = await readG1(); - c.betaG1 = await readG1(); - c.betaG2 = await readG2(); - c.key = await readPtauPubKey(fd, curve, true); - c.partialHash = await fd.read(216); - c.nextChallenge = await fd.read(64); - c.type = await fd.readULE32(); - - const buffV = new Uint8Array(curve.G1.F.n8*2*6+curve.G2.F.n8*2*3); - toPtauPubKeyRpr(buffV, 0, curve, c.key, false); - - const responseHasher = fromPartialHash(c.partialHash); - responseHasher.update(buffV); - c.responseHash = responseHasher.digest(); - - const paramLength = await fd.readULE32(); - const curPos = fd.pos; - let lastType =0; - while (fd.pos-curPos < paramLength) { - const buffType = await readDV(1); - if (buffType[0]<= lastType) throw new Error("Parameters in the contribution must be sorted"); - lastType = buffType[0]; - if (buffType[0]==1) { // Name - const buffLen = await readDV(1); - const buffStr = await readDV(buffLen[0]); - c.name = new TextDecoder().decode(buffStr); - } else if (buffType[0]==2) { - const buffExp = await readDV(1); - c.numIterationsExp = buffExp[0]; - } else if (buffType[0]==3) { - const buffLen = await readDV(1); - c.beaconHash = await readDV(buffLen[0]); - } else { - throw new Error("Parameter not recognized"); - } - } - if (fd.pos != curPos + paramLength) { - throw new Error("Parameters do not match"); - } - - return c; - - async function readG1() { - const pBuff = await fd.read(curve.G1.F.n8*2); - return curve.G1.fromRprLEM( pBuff ); - } - - async function readG2() { - const pBuff = await fd.read(curve.G2.F.n8*2); - return curve.G2.fromRprLEM( pBuff ); - } - - async function readDV(n) { - const b = await fd.read(n); - return new Uint8Array(b); - } - } - - async function readContributions(fd, curve, sections) { - if (!sections[7]) throw new Error(fd.fileName + ": File has no contributions"); - if (sections[7][0].length>1) throw new Error(fd.fileName +": File has more than one contributions section"); - - fd.pos = sections[7][0].p; - const nContributions = await fd.readULE32(); - const contributions = []; - for (let i=0; i0) { - const paramsBuff = new Uint8Array(params); - await fd.writeULE32(paramsBuff.byteLength); - await fd.write(paramsBuff); - } else { - await fd.writeULE32(0); - } - - - async function writeG1(p) { - curve.G1.toRprLEM(buffG1, 0, p); - await fd.write(buffG1); - } - - async function writeG2(p) { - curve.G2.toRprLEM(buffG2, 0, p); - await fd.write(buffG2); - } - - } - - async function writeContributions(fd, curve, contributions) { - - await fd.writeULE32(7); // Header type - const pContributionsSize = fd.pos; - await fd.writeULE64(0); // Temporally set to 0 length - - await fd.writeULE32(contributions.length); - for (let i=0; i< contributions.length; i++) { - await writeContribution(fd, curve, contributions[i]); - } - const contributionsSize = fd.pos - pContributionsSize - 8; - - const oldPos = fd.pos; - - await fd.writeULE64(contributionsSize, pContributionsSize); - fd.pos = oldPos; - } - - function calculateFirstChallengeHash(curve, power, logger) { - if (logger) logger.debug("Calculating First Challenge Hash"); - - const hasher = blake2b.create({ dkLen: 64 }); - - const vG1 = new Uint8Array(curve.G1.F.n8*2); - const vG2 = new Uint8Array(curve.G2.F.n8*2); - curve.G1.toRprUncompressed(vG1, 0, curve.G1.g); - curve.G2.toRprUncompressed(vG2, 0, curve.G2.g); - - hasher.update(blake2b.create({ dkLen: 64 }).digest()); - - let n; - - n=(2 ** power)*2 -1; - if (logger) logger.debug("Calculate Initial Hash: tauG1"); - hashBlock(vG1, n); - n= 2 ** power; - if (logger) logger.debug("Calculate Initial Hash: tauG2"); - hashBlock(vG2, n); - if (logger) logger.debug("Calculate Initial Hash: alphaTauG1"); - hashBlock(vG1, n); - if (logger) logger.debug("Calculate Initial Hash: betaTauG1"); - hashBlock(vG1, n); - hasher.update(vG2); - - return hasher.digest(); - - function hashBlock(buff, n) { - // this block size is a good compromise between speed and the maximum - // input size of the Blake2b update method (65,535,720 bytes). - const blockSize = 341000; - const nBlocks = Math.floor(n / blockSize); - const rem = n % blockSize; - const bigBuff = new Uint8Array(blockSize * buff.byteLength); - for (let i=0; i. - */ - - - async function newAccumulator(curve, power, fileName, logger) { - - const fd = await createBinFile(fileName, "ptau", 1, 7); - - await writePTauHeader(fd, curve, power, 0); - - const buffG1 = curve.G1.oneAffine; - const buffG2 = curve.G2.oneAffine; - - // Write tauG1 - /////////// - await startWriteSection(fd, 2); - const nTauG1 = (2 ** power) * 2 -1; - for (let i=0; i< nTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("tauG1: " + i); - } - await endWriteSection(fd); - - // Write tauG2 - /////////// - await startWriteSection(fd, 3); - const nTauG2 = (2 ** power); - for (let i=0; i< nTauG2; i++) { - await fd.write(buffG2); - if ((logger)&&((i%100000) == 0)&&i) logger.log("tauG2: " + i); - } - await endWriteSection(fd); - - // Write alphaTauG1 - /////////// - await startWriteSection(fd, 4); - const nAlfaTauG1 = (2 ** power); - for (let i=0; i< nAlfaTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("alphaTauG1: " + i); - } - await endWriteSection(fd); - - // Write betaTauG1 - /////////// - await startWriteSection(fd, 5); - const nBetaTauG1 = (2 ** power); - for (let i=0; i< nBetaTauG1; i++) { - await fd.write(buffG1); - if ((logger)&&((i%100000) == 0)&&i) logger.log("betaTauG1: " + i); - } - await endWriteSection(fd); - - // Write betaG2 - /////////// - await startWriteSection(fd, 6); - await fd.write(buffG2); - await endWriteSection(fd); - - // Contributions - /////////// - await startWriteSection(fd, 7); - await fd.writeULE32(0); // 0 Contributions - await endWriteSection(fd); - - await fd.close(); - - const firstChallengeHash = calculateFirstChallengeHash(curve, power, logger); - - if (logger) logger.debug(formatHash(blake2b.create({ dkLen: 64 }).digest(), "Blank Contribution Hash:")); - - if (logger) logger.info(formatHash(firstChallengeHash, "First Contribution Hash:")); - - return firstChallengeHash; - - } - - // Format of the outpu - // Hash of the last contribution 64Bytes - // 2^N * 2 -1 TauG1 points (uncompressed) - // 2^N TauG2 Points (uncompressed) - // 2^N AlphaTauG1 Points (uncompressed) - // 2^N BetaTauG1 Points (uncompressed) - // BetaG2 (uncompressed) - - - async function exportChallenge(pTauFilename, challengeFilename, logger) { - const {fd: fdFrom, sections} = await readBinFile$1(pTauFilename, "ptau", 1); - - const {curve, power} = await readPTauHeader(fdFrom, sections); - - const contributions = await readContributions(fdFrom, curve, sections); - let lastResponseHash, curChallengeHash; - if (contributions.length == 0) { - lastResponseHash = blake2b.create({ dkLen: 64 }).digest(); - curChallengeHash = calculateFirstChallengeHash(curve, power); - } else { - lastResponseHash = contributions[contributions.length-1].responseHash; - curChallengeHash = contributions[contributions.length-1].nextChallenge; - } - - if (logger) logger.info(formatHash(lastResponseHash, "Last Response Hash: ")); - - if (logger) logger.info(formatHash(curChallengeHash, "New Challenge Hash: ")); - - - const fdTo = await createOverride(challengeFilename); - - const toHash = blake2b.create({ dkLen: 64 }); - await fdTo.write(lastResponseHash); - toHash.update(lastResponseHash); - - await exportSection(2, "G1", (2 ** power) * 2 -1, "tauG1"); - await exportSection(3, "G2", (2 ** power) , "tauG2"); - await exportSection(4, "G1", (2 ** power) , "alphaTauG1"); - await exportSection(5, "G1", (2 ** power) , "betaTauG1"); - await exportSection(6, "G2", 1 , "betaG2"); - - await fdFrom.close(); - await fdTo.close(); - - const calcCurChallengeHash = toHash.digest(); - - if (!hashIsEqual (curChallengeHash, calcCurChallengeHash)) { - if (logger) logger.info(formatHash(calcCurChallengeHash, "Calc Curret Challenge Hash: ")); - - if (logger) logger.error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); - throw new Error("PTau file is corrupted. Calculated new challenge hash does not match with the eclared one"); - } - - return curChallengeHash; - - async function exportSection(sectionId, groupName, nPoints, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPointsChunk = Math.floor((1<<24)/sG); - - await startReadUniqueSection$1(fdFrom, sections, sectionId); - for (let i=0; i< nPoints; i+= nPointsChunk) { - if (logger) logger.debug(`Exporting ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - let buff; - buff = await fdFrom.read(n*sG); - buff = await G.batchLEMtoU(buff); - await fdTo.write(buff); - toHash.update(buff); - } - await endReadSection$1(fdFrom); - } - - - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - async function importResponse(oldPtauFilename, contributionFilename, newPTauFilename, name, importPoints, logger) { - - const noHash = new Uint8Array(64); - for (let i=0; i<64; i++) noHash[i] = 0xFF; - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - const contributions = await readContributions(fdOld, curve, sections); - const currentContribution = {}; - - if (name) currentContribution.name = name; - - const sG1 = curve.F1.n8*2; - const scG1 = curve.F1.n8; // Compressed size - const sG2 = curve.F2.n8*2; - const scG2 = curve.F2.n8; // Compressed size - - const fdResponse = await readExisting$3(contributionFilename); - - if (fdResponse.totalSize != - 64 + // Old Hash - ((2 ** power)*2-1)*scG1 + - (2 ** power)*scG2 + - (2 ** power)*scG1 + - (2 ** power)*scG1 + - scG2 + - sG1*6 + sG2*3) - throw new Error("Size of the contribution is invalid"); - - let lastChallengeHash; - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, importPoints ? 7: 2); - await writePTauHeader(fdNew, curve, power); - - const contributionPreviousHash = await fdResponse.read(64); - - if (hashIsEqual(noHash,lastChallengeHash)) { - lastChallengeHash = contributionPreviousHash; - contributions[contributions.length-1].nextChallenge = lastChallengeHash; - } - - if(!hashIsEqual(contributionPreviousHash,lastChallengeHash)) - throw new Error("Wrong contribution. This contribution is not based on the previous hash"); - - const hasherResponse = blake2b.create({ dkLen: 64 }); - hasherResponse.update(contributionPreviousHash); - - const startSections = []; - let res; - res = await processSection(fdResponse, fdNew, "G1", 2, (2 ** power) * 2 -1, [1], "tauG1"); - currentContribution.tauG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G2", 3, (2 ** power) , [1], "tauG2"); - currentContribution.tauG2 = res[0]; - res = await processSection(fdResponse, fdNew, "G1", 4, (2 ** power) , [0], "alphaG1"); - currentContribution.alphaG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G1", 5, (2 ** power) , [0], "betaG1"); - currentContribution.betaG1 = res[0]; - res = await processSection(fdResponse, fdNew, "G2", 6, 1 , [0], "betaG2"); - currentContribution.betaG2 = res[0]; - - currentContribution.partialHash = toPartialHash(hasherResponse); - - - const buffKey = await fdResponse.read(curve.F1.n8*2*6+curve.F2.n8*2*3); - - currentContribution.key = fromPtauPubKeyRpr(buffKey, 0, curve, false); - - hasherResponse.update(new Uint8Array(buffKey)); - const hashResponse = hasherResponse.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - if (importPoints) { - const nextChallengeHasher = blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(nextChallengeHasher, fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G2", 3, (2 ** power) , "tauG2", logger); - await hashSection(nextChallengeHasher, fdNew, "G1", 4, (2 ** power) , "alphaTauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G1", 5, (2 ** power) , "betaTauG1", logger); - await hashSection(nextChallengeHasher, fdNew, "G2", 6, 1 , "betaG2", logger); - - currentContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(currentContribution.nextChallenge, "Next Challenge Hash: ")); - } else { - currentContribution.nextChallenge = noHash; - } - - contributions.push(currentContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdResponse.close(); - await fdNew.close(); - await fdOld.close(); - - return currentContribution.nextChallenge; - - async function processSection(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - if (importPoints) { - return await processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); - } else { - return await processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName); - } - } - - async function processSectionImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - - const G = curve[groupName]; - const scG = G.F.n8; - const sG = G.F.n8*2; - - const singularPoints = []; - - await startWriteSection(fdTo, sectionId); - const nPointsChunk = Math.floor((1<<24)/sG); - - startSections[sectionId] = fdTo.pos; - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffC = await fdFrom.read(n * scG); - hasherResponse.update(buffC); - - const buffLEM = await G.batchCtoLEM(buffC); - - await fdTo.write(buffLEM); - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprLEM(buffLEM, (sp-i)*sG); - singularPoints.push(P); - } - } - } - - await endWriteSection(fdTo); - - return singularPoints; - } - - - async function processSectionNoImportPoints(fdFrom, fdTo, groupName, sectionId, nPoints, singularPointIndexes, sectionName) { - - const G = curve[groupName]; - const scG = G.F.n8; - - const singularPoints = []; - - const nPointsChunk = Math.floor((1<<24)/scG); - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Importing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffC = await fdFrom.read(n * scG); - hasherResponse.update(buffC); - - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprCompressed(buffC, (sp-i)*scG); - singularPoints.push(P); - } - } - } - - return singularPoints; - } - - - async function hashSection(nextChallengeHasher, fdTo, groupName, sectionId, nPoints, sectionName, logger) { - - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPointsChunk = Math.floor((1<<24)/sG); - - const oldPos = fdTo.pos; - fdTo.pos = startSections[sectionId]; - - for (let i=0; i< nPoints; i += nPointsChunk) { - if (logger) logger.debug(`Hashing ${sectionName}: ${i}/${nPoints}`); - const n = Math.min(nPoints-i, nPointsChunk); - - const buffLEM = await fdTo.read(n * sG); - - const buffU = await G.batchLEMtoU(buffLEM); - - nextChallengeHasher.update(buffU); - } - - fdTo.pos = oldPos; - } - - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - const sameRatio$1 = sameRatio$2; - - async function verifyContribution(curve, cur, prev, logger) { - let sr; - if (cur.type == 1) { // Verify the beacon. - const beaconKey = await keyFromBeacon(curve, prev.nextChallenge, cur.beaconHash, cur.numIterationsExp); - - if (!curve.G1.eq(cur.key.tau.g1_s, beaconKey.tau.g1_s)) { - if (logger) logger.error(`BEACON key (tauG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.tau.g1_sx, beaconKey.tau.g1_sx)) { - if (logger) logger.error(`BEACON key (tauG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.tau.g2_spx, beaconKey.tau.g2_spx)) { - if (logger) logger.error(`BEACON key (tauG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - - if (!curve.G1.eq(cur.key.alpha.g1_s, beaconKey.alpha.g1_s)) { - if (logger) logger.error(`BEACON key (alphaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.alpha.g1_sx, beaconKey.alpha.g1_sx)) { - if (logger) logger.error(`BEACON key (alphaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.alpha.g2_spx, beaconKey.alpha.g2_spx)) { - if (logger) logger.error(`BEACON key (alphaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - - if (!curve.G1.eq(cur.key.beta.g1_s, beaconKey.beta.g1_s)) { - if (logger) logger.error(`BEACON key (betaG1_s) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G1.eq(cur.key.beta.g1_sx, beaconKey.beta.g1_sx)) { - if (logger) logger.error(`BEACON key (betaG1_sx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - if (!curve.G2.eq(cur.key.beta.g2_spx, beaconKey.beta.g2_spx)) { - if (logger) logger.error(`BEACON key (betaG2_spx) is not generated correctly in challenge #${cur.id} ${cur.name || ""}` ); - return false; - } - } - - cur.key.tau.g2_sp = curve.G2.toAffine(getG2sp(curve, 0, prev.nextChallenge, cur.key.tau.g1_s, cur.key.tau.g1_sx)); - cur.key.alpha.g2_sp = curve.G2.toAffine(getG2sp(curve, 1, prev.nextChallenge, cur.key.alpha.g1_s, cur.key.alpha.g1_sx)); - cur.key.beta.g2_sp = curve.G2.toAffine(getG2sp(curve, 2, prev.nextChallenge, cur.key.beta.g1_s, cur.key.beta.g1_sx)); - - sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, cur.key.tau.g2_sp, cur.key.tau.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (tau) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, cur.key.alpha.g1_s, cur.key.alpha.g1_sx, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (alpha) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, cur.key.beta.g2_sp, cur.key.beta.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID key (beta) in challenge #"+cur.id); - return false; - } - - sr = await sameRatio$1(curve, prev.tauG1, cur.tauG1, cur.key.tau.g2_sp, cur.key.tau.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID tau*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, cur.key.tau.g1_s, cur.key.tau.g1_sx, prev.tauG2, cur.tauG2); - if (sr !== true) { - if (logger) logger.error("INVALID tau*G2. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, prev.alphaG1, cur.alphaG1, cur.key.alpha.g2_sp, cur.key.alpha.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID alpha*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, prev.betaG1, cur.betaG1, cur.key.beta.g2_sp, cur.key.beta.g2_spx); - if (sr !== true) { - if (logger) logger.error("INVALID beta*G1. challenge #"+cur.id+" It does not follow the previous contribution"); - return false; - } - - sr = await sameRatio$1(curve, cur.key.beta.g1_s, cur.key.beta.g1_sx, prev.betaG2, cur.betaG2); - if (sr !== true) { - if (logger) logger.error("INVALID beta*G2. challenge #"+cur.id+"It does not follow the previous contribution"); - return false; - } - - if (logger) logger.info("Powers Of tau file OK!"); - return true; - } - - async function verify(tauFilename, logger) { - let sr; - - const {fd, sections} = await readBinFile$1(tauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fd, sections); - const contrs = await readContributions(fd, curve, sections); - - if (logger) logger.debug("power: 2**" + power); - // Verify Last contribution - - if (logger) logger.debug("Computing initial contribution hash"); - const initialContribution = { - tauG1: curve.G1.g, - tauG2: curve.G2.g, - alphaG1: curve.G1.g, - betaG1: curve.G1.g, - betaG2: curve.G2.g, - nextChallenge: calculateFirstChallengeHash(curve, ceremonyPower, logger), - responseHash: blake2b.create({ dkLen: 64 }).digest() - }; - - if (contrs.length == 0) { - if (logger) logger.error("This file has no contribution! It cannot be used in production"); - return false; - } - - let prevContr; - if (contrs.length>1) { - prevContr = contrs[contrs.length-2]; - } else { - prevContr = initialContribution; - } - const curContr = contrs[contrs.length-1]; - if (logger) logger.debug("Validating contribution #"+contrs[contrs.length-1].id); - const res = await verifyContribution(curve, curContr, prevContr, logger); - if (!res) return false; - - - const nextContributionHasher = blake2b.create({ dkLen: 64 }); - nextContributionHasher.update(curContr.responseHash); - - // Verify powers and compute nextChallengeHash - - // await test(); - - // Verify Section tau*G1 - if (logger) logger.debug("Verifying powers in tau*G1 section"); - const rTau1 = await processSection(2, "G1", "tauG1", (2 ** power)*2-1, [0, 1], logger); - sr = await sameRatio$1(curve, rTau1.R1, rTau1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("tauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curve.G1.g, rTau1.singularPoints[0])) { - if (logger) logger.error("First element of tau*G1 section must be the generator"); - return false; - } - if (!curve.G1.eq(curContr.tauG1, rTau1.singularPoints[1])) { - if (logger) logger.error("Second element of tau*G1 section does not match the one in the contribution section"); - return false; - } - - // await test(); - - // Verify Section tau*G2 - if (logger) logger.debug("Verifying powers in tau*G2 section"); - const rTau2 = await processSection(3, "G2", "tauG2", 2 ** power, [0, 1], logger); - sr = await sameRatio$1(curve, curve.G1.g, curContr.tauG1, rTau2.R1, rTau2.R2); - if (sr !== true) { - if (logger) logger.error("tauG2 section. Powers do not match"); - return false; - } - if (!curve.G2.eq(curve.G2.g, rTau2.singularPoints[0])) { - if (logger) logger.error("First element of tau*G2 section must be the generator"); - return false; - } - if (!curve.G2.eq(curContr.tauG2, rTau2.singularPoints[1])) { - if (logger) logger.error("Second element of tau*G2 section does not match the one in the contribution section"); - return false; - } - - // Verify Section alpha*tau*G1 - if (logger) logger.debug("Verifying powers in alpha*tau*G1 section"); - const rAlphaTauG1 = await processSection(4, "G1", "alphatauG1", 2 ** power, [0], logger); - sr = await sameRatio$1(curve, rAlphaTauG1.R1, rAlphaTauG1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("alphaTauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curContr.alphaG1, rAlphaTauG1.singularPoints[0])) { - if (logger) logger.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"); - return false; - } - - // Verify Section beta*tau*G1 - if (logger) logger.debug("Verifying powers in beta*tau*G1 section"); - const rBetaTauG1 = await processSection(5, "G1", "betatauG1", 2 ** power, [0], logger); - sr = await sameRatio$1(curve, rBetaTauG1.R1, rBetaTauG1.R2, curve.G2.g, curContr.tauG2); - if (sr !== true) { - if (logger) logger.error("betaTauG1 section. Powers do not match"); - return false; - } - if (!curve.G1.eq(curContr.betaG1, rBetaTauG1.singularPoints[0])) { - if (logger) logger.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"); - return false; - } - - //Verify Beta G2 - const betaG2 = await processSectionBetaG2(logger); - if (!curve.G2.eq(curContr.betaG2, betaG2)) { - if (logger) logger.error("betaG2 element in betaG2 section does not match the one in the contribution section"); - return false; - } - - - const nextContributionHash = nextContributionHasher.digest(); - - // Check the nextChallengeHash - if (power == ceremonyPower) { - if (!hashIsEqual(nextContributionHash,curContr.nextChallenge)) { - if (logger) logger.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"); - return false; - } - } - - if (logger) logger.info(formatHash(nextContributionHash, "Next challenge hash: ")); - - // Verify Previous contributions - - printContribution(curContr, prevContr); - for (let i = contrs.length-2; i>=0; i--) { - const curContr = contrs[i]; - const prevContr = (i>0) ? contrs[i-1] : initialContribution; - const res = await verifyContribution(curve, curContr, prevContr, logger); - if (!res) return false; - printContribution(curContr, prevContr); - } - if (logger) logger.info("-----------------------------------------------------"); - - if ((!sections[12]) || (!sections[13]) || (!sections[14]) || (!sections[15])) { - if (logger) logger.warn( - "this file does not contain phase2 precalculated values. Please run: \n" + - " snarkjs \"powersoftau preparephase2\" to prepare this file to be used in the phase2 ceremony." - ); - } else { - let res; - res = await verifyLagrangeEvaluations("G1", 2, 12, "tauG1", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G2", 3, 13, "tauG2", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G1", 4, 14, "alphaTauG1", logger); - if (!res) return false; - res = await verifyLagrangeEvaluations("G1", 5, 15, "betaTauG1", logger); - if (!res) return false; - } - - await fd.close(); - - if (logger) logger.info("Powers of Tau Ok!"); - - return true; - - function printContribution(curContr, prevContr) { - if (!logger) return; - logger.info("-----------------------------------------------------"); - logger.info(`Contribution #${curContr.id}: ${curContr.name ||""}`); - - logger.info(formatHash(curContr.nextChallenge, "Next Challenge: ")); - - const buffV = new Uint8Array(curve.G1.F.n8*2*6+curve.G2.F.n8*2*3); - toPtauPubKeyRpr(buffV, 0, curve, curContr.key, false); - - const responseHasher = fromPartialHash(curContr.partialHash); - responseHasher.update(buffV); - const responseHash = responseHasher.digest(); - - logger.info(formatHash(responseHash, "Response Hash:")); - - logger.info(formatHash(prevContr.nextChallenge, "Response Hash:")); - - if (curContr.type == 1) { - logger.info(`Beacon generator: ${byteArray2hex(curContr.beaconHash)}`); - logger.info(`Beacon iterations Exp: ${curContr.numIterationsExp}`); - } - - } - - async function processSectionBetaG2(logger) { - const G = curve.G2; - const sG = G.F.n8*2; - const buffUv = new Uint8Array(sG); - - if (!sections[6]) { - logger.error("File has no BetaG2 section"); - throw new Error("File has no BetaG2 section"); - } - if (sections[6].length>1) { - logger.error("File has no BetaG2 section"); - throw new Error("File has more than one GetaG2 section"); - } - fd.pos = sections[6][0].p; - - const buff = await fd.read(sG); - const P = G.fromRprLEM(buff); - - G.toRprUncompressed(buffUv, 0, P); - nextContributionHasher.update(buffUv); - - return P; - } - - async function processSection(idSection, groupName, sectionName, nPoints, singularPointIndexes, logger) { - const MAX_CHUNK_SIZE = 1<<16; - const G = curve[groupName]; - const sG = G.F.n8*2; - await startReadUniqueSection$1(fd, sections, idSection); - - const singularPoints = []; - - let R1 = G.zero; - let R2 = G.zero; - - let lastBase = G.zero; - - for (let i=0; i0) { - const firstBase = G.fromRprLEM(bases, 0); - const r = readUInt32BE(getRandomBytes(4), 0); - - R1 = G.add(R1, G.timesScalar(lastBase, r)); - R2 = G.add(R2, G.timesScalar(firstBase, r)); - } - - const r1 = await G.multiExpAffine(bases.slice(0, (n-1)*sG), scalars); - const r2 = await G.multiExpAffine(bases.slice(sG), scalars); - - R1 = G.add(R1, r1); - R2 = G.add(R2, r2); - - lastBase = G.fromRprLEM( bases, (n-1)*sG); - - for (let j=0; j=i) && (sp < i+n)) { - const P = G.fromRprLEM(bases, (sp-i)*sG); - singularPoints.push(P); - } - } - - } - await endReadSection$1(fd); - - return { - R1: R1, - R2: R2, - singularPoints: singularPoints - }; - - } - - async function verifyLagrangeEvaluations(gName, tauSection, lagrangeSection, sectionName, logger) { - - if (logger) logger.debug(`Verifying phase2 calculated values ${sectionName}...`); - const G = curve[gName]; - const sG = G.F.n8*2; - - const seed= new Array(8); - for (let i=0; i<8; i++) { - seed[i] = readUInt32BE(getRandomBytes(4), 0); - } - - for (let p=0; p<= power; p ++) { - const res = await verifyPower(p); - if (!res) return false; - } - - if (tauSection == 2) { - const res = await verifyPower(power+1); - if (!res) return false; - } - - return true; - - async function verifyPower(p) { - if (logger) logger.debug(`Power ${p}...`); - const n8r = curve.Fr.n8; - const nPoints = 2 ** p; - let buff_r = new Uint32Array(nPoints); - let buffG; - - let rng = new ChaCha(seed); - - if (logger) logger.debug(`Creating random numbers Powers${p}...`); - for (let i=0; i. - */ - - - /* - This function creates a new section in the fdTo file with id idSection. - It multiplies the points in fdFrom by first, first*inc, first*inc^2, .... - nPoint Times. - It also updates the newChallengeHasher with the new points - */ - - async function applyKeyToSection(fdOld, sections, fdNew, idSection, curve, groupName, first, inc, sectionName, logger) { - const MAX_CHUNK_SIZE = 1 << 16; - const G = curve[groupName]; - const sG = G.F.n8*2; - const nPoints = sections[idSection][0].size / sG; - - await startReadUniqueSection$1(fdOld, sections,idSection ); - await startWriteSection(fdNew, idSection); - - let t = first; - for (let i=0; i. - */ - - - async function challengeContribute(curve, challengeFilename, responseFileName, entropy, logger) { - const fdFrom = await readExisting$3(challengeFilename); - - - const sG1 = curve.F1.n64*8*2; - const sG2 = curve.F2.n64*8*2; - const domainSize = (fdFrom.totalSize + sG1 - 64 - sG2) / (4*sG1 + sG2); - let e = domainSize; - let power = 0; - while (e>1) { - e = e /2; - power += 1; - } - - if (2 ** power != domainSize) throw new Error("Invalid file size"); - if (logger) logger.debug("Power to tau size: "+power); - - const rng = await getRandomRng(entropy); - - const fdTo = await createOverride(responseFileName); - - // Calculate the hash - const challengeHasher = blake2b.create({ dkLen: 64 }); - for (let i=0; i { - logger.debug(k + ".g1_s: " + curve.G1.toString(key[k].g1_s, 16)); - logger.debug(k + ".g1_sx: " + curve.G1.toString(key[k].g1_sx, 16)); - logger.debug(k + ".g2_sp: " + curve.G2.toString(key[k].g2_sp, 16)); - logger.debug(k + ".g2_spx: " + curve.G2.toString(key[k].g2_spx, 16)); - logger.debug(""); - }); - } - - const responseHasher = blake2b.create({ dkLen: 64 }); - - await fdTo.write(challengeHash); - responseHasher.update(challengeHash); - - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power)*2-1, curve.Fr.one , key.tau.prvKey, "COMPRESSED", "tauG1" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", (2 ** power) , curve.Fr.one , key.tau.prvKey, "COMPRESSED", "tauG2" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power) , key.alpha.prvKey, key.tau.prvKey, "COMPRESSED", "alphaTauG1", logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G1", (2 ** power) , key.beta.prvKey , key.tau.prvKey, "COMPRESSED", "betaTauG1" , logger ); - await applyKeyToChallengeSection(fdFrom, fdTo, responseHasher, curve, "G2", 1 , key.beta.prvKey , key.tau.prvKey, "COMPRESSED", "betaTauG2" , logger ); - - // Write and hash key - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - toPtauPubKeyRpr(buffKey, 0, curve, key, false); - await fdTo.write(buffKey); - responseHasher.update(buffKey); - const responseHash = responseHasher.digest(); - if (logger) logger.info(formatHash(responseHash, "Contribution Response Hash: ")); - - await fdTo.close(); - await fdFrom.close(); - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - async function beacon$1(oldPtauFilename, newPTauFilename, name, beaconHashStr,numIterationsExp, logger) { - const beaconHash = hex2ByteArray(beaconHashStr); - if ( (beaconHash.byteLength == 0) - || (beaconHash.byteLength*2 !=beaconHashStr.length)) - { - if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); - return false; - } - if (beaconHash.length>=256) { - if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); - return false; - } - - numIterationsExp = parseInt(numIterationsExp); - if ((numIterationsExp<10)||(numIterationsExp>63)) { - if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); - return false; - } - - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - if (power != ceremonyPower) { - if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); - return false; - } - if (sections[12]) { - if (logger) logger.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); - } - const contributions = await readContributions(fdOld, curve, sections); - const curContribution = { - name: name, - type: 1, // Beacon - numIterationsExp: numIterationsExp, - beaconHash: beaconHash - }; - - let lastChallengeHash; - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - curContribution.key = await keyFromBeacon(curve, lastChallengeHash, beaconHash, numIterationsExp); - - const responseHasher = blake2b.create({ dkLen: 64 }); - responseHasher.update(lastChallengeHash); - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, 7); - await writePTauHeader(fdNew, curve, power); - - const startSections = []; - - let firstPoints; - firstPoints = await processSection(2, "G1", (2 ** power) * 2 -1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1", logger ); - curContribution.tauG1 = firstPoints[1]; - firstPoints = await processSection(3, "G2", (2 ** power) , curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2", logger ); - curContribution.tauG2 = firstPoints[1]; - firstPoints = await processSection(4, "G1", (2 ** power) , curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1", logger ); - curContribution.alphaG1 = firstPoints[0]; - firstPoints = await processSection(5, "G1", (2 ** power) , curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1", logger ); - curContribution.betaG1 = firstPoints[0]; - firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2", logger ); - curContribution.betaG2 = firstPoints[0]; - - curContribution.partialHash = toPartialHash(responseHasher); - - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - - toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); - - responseHasher.update(new Uint8Array(buffKey)); - const hashResponse = responseHasher.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - const nextChallengeHasher = blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1", logger); - await hashSection(fdNew, "G2", 3, (2 ** power) , "tauG2", logger); - await hashSection(fdNew, "G1", 4, (2 ** power) , "alphaTauG1", logger); - await hashSection(fdNew, "G1", 5, (2 ** power) , "betaTauG1", logger); - await hashSection(fdNew, "G2", 6, 1 , "betaG2", logger); - - curContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); - - contributions.push(curContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdOld.close(); - await fdNew.close(); - - return hashResponse; - - async function processSection(sectionId, groupName, NPoints, first, inc, sectionName, logger) { - const res = []; - fdOld.pos = sections[sectionId][0].p; - - await startWriteSection(fdNew, sectionId); - - startSections[sectionId] = fdNew.pos; - - const G = curve[groupName]; - const sG = G.F.n8*2; - const chunkSize = Math.floor((1<<20) / sG); // 128Mb chunks - let t = first; - for (let i=0 ; i. - */ - - - async function contribute(oldPtauFilename, newPTauFilename, name, entropy, logger) { - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - if (power != ceremonyPower) { - if (logger) logger.error("This file has been reduced. You cannot contribute into a reduced file."); - throw new Error("This file has been reduced. You cannot contribute into a reduced file."); - } - if (sections[12]) { - if (logger) logger.warn("WARNING: Contributing into a file that has phase2 calculated. You will have to prepare phase2 again."); - } - const contributions = await readContributions(fdOld, curve, sections); - const curContribution = { - name: name, - type: 0, // Beacon - }; - - let lastChallengeHash; - - const rng = await getRandomRng(entropy); - - if (contributions.length>0) { - lastChallengeHash = contributions[contributions.length-1].nextChallenge; - } else { - lastChallengeHash = calculateFirstChallengeHash(curve, power, logger); - } - - // Generate a random key - - - curContribution.key = createPTauKey(curve, lastChallengeHash, rng); - - - const responseHasher = blake2b.create({ dkLen: 64 }); - responseHasher.update(lastChallengeHash); - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, 7); - await writePTauHeader(fdNew, curve, power); - - const startSections = []; - - let firstPoints; - firstPoints = await processSection(2, "G1", (2 ** power) * 2 -1, curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG1" ); - curContribution.tauG1 = firstPoints[1]; - firstPoints = await processSection(3, "G2", (2 ** power) , curve.Fr.e(1), curContribution.key.tau.prvKey, "tauG2" ); - curContribution.tauG2 = firstPoints[1]; - firstPoints = await processSection(4, "G1", (2 ** power) , curContribution.key.alpha.prvKey, curContribution.key.tau.prvKey, "alphaTauG1" ); - curContribution.alphaG1 = firstPoints[0]; - firstPoints = await processSection(5, "G1", (2 ** power) , curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG1" ); - curContribution.betaG1 = firstPoints[0]; - firstPoints = await processSection(6, "G2", 1, curContribution.key.beta.prvKey, curContribution.key.tau.prvKey, "betaTauG2" ); - curContribution.betaG2 = firstPoints[0]; - - curContribution.partialHash = toPartialHash(responseHasher); - - const buffKey = new Uint8Array(curve.F1.n8*2*6+curve.F2.n8*2*3); - - toPtauPubKeyRpr(buffKey, 0, curve, curContribution.key, false); - - responseHasher.update(new Uint8Array(buffKey)); - const hashResponse = responseHasher.digest(); - - if (logger) logger.info(formatHash(hashResponse, "Contribution Response Hash imported: ")); - - const nextChallengeHasher = blake2b.create({ dkLen: 64 }); - nextChallengeHasher.update(hashResponse); - - await hashSection(fdNew, "G1", 2, (2 ** power) * 2 -1, "tauG1"); - await hashSection(fdNew, "G2", 3, (2 ** power) , "tauG2"); - await hashSection(fdNew, "G1", 4, (2 ** power) , "alphaTauG1"); - await hashSection(fdNew, "G1", 5, (2 ** power) , "betaTauG1"); - await hashSection(fdNew, "G2", 6, 1 , "betaG2"); - - curContribution.nextChallenge = nextChallengeHasher.digest(); - - if (logger) logger.info(formatHash(curContribution.nextChallenge, "Next Challenge Hash: ")); - - contributions.push(curContribution); - - await writeContributions(fdNew, curve, contributions); - - await fdOld.close(); - await fdNew.close(); - - return hashResponse; - - async function processSection(sectionId, groupName, NPoints, first, inc, sectionName) { - const res = []; - fdOld.pos = sections[sectionId][0].p; - - await startWriteSection(fdNew, sectionId); - - startSections[sectionId] = fdNew.pos; - - const G = curve[groupName]; - const sG = G.F.n8*2; - const chunkSize = Math.floor((1<<20) / sG); // 128Mb chunks - let t = first; - for (let i=0 ; i. - */ - - - async function preparePhase2(oldPtauFilename, newPTauFilename, logger) { - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, 11); - await writePTauHeader(fdNew, curve, power); - - await copySection(fdOld, sections, fdNew, 2); - await copySection(fdOld, sections, fdNew, 3); - await copySection(fdOld, sections, fdNew, 4); - await copySection(fdOld, sections, fdNew, 5); - await copySection(fdOld, sections, fdNew, 6); - await copySection(fdOld, sections, fdNew, 7); - - await processSection(2, 12, "G1", "tauG1" ); - await processSection(3, 13, "G2", "tauG2" ); - await processSection(4, 14, "G1", "alphaTauG1" ); - await processSection(5, 15, "G1", "betaTauG1" ); - - await fdOld.close(); - await fdNew.close(); - - // await fs.promises.unlink(newPTauFilename+ ".tmp"); - - return; - - async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { - if (logger) logger.debug("Starting section: "+sectionName); - - await startWriteSection(fdNew, newSectionId); - - for (let p=0; p<=power; p++) { - await processSectionPower(p); - } - - if (oldSectionId == 2) { - await processSectionPower(power+1); - } - - await endWriteSection(fdNew); - - - async function processSectionPower(p) { - const nPoints = 2 ** p; - const G = curve[Gstr]; - const sGin = G.F.n8*2; - - let buff; - buff = new BigBuffer(nPoints*sGin); - - await startReadUniqueSection$1(fdOld, sections, oldSectionId); - if ((oldSectionId == 2)&&(p==power+1)) { - await fdOld.readToBuffer(buff, 0,(nPoints-1)*sGin ); - buff.set(curve.G1.zeroAffine, (nPoints-1)*sGin ); - } else { - await fdOld.readToBuffer(buff, 0,nPoints*sGin ); - } - await endReadSection$1(fdOld, true); - - - buff = await G.lagrangeEvaluations(buff, "affine", "affine", logger, sectionName); - await fdNew.write(buff); - - /* - if (p <= curve.Fr.s) { - buff = await G.ifft(buff, "affine", "affine", logger, sectionName); - await fdNew.write(buff); - } else if (p == curve.Fr.s+1) { - const smallM = 1<. - */ - - - async function truncate(ptauFilename, template, logger) { - - const {fd: fdOld, sections} = await readBinFile$1(ptauFilename, "ptau", 1); - const {curve, power, ceremonyPower} = await readPTauHeader(fdOld, sections); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - for (let p=1; p. - */ - - - async function convert(oldPtauFilename, newPTauFilename, logger) { - - const {fd: fdOld, sections} = await readBinFile$1(oldPtauFilename, "ptau", 1); - const {curve, power} = await readPTauHeader(fdOld, sections); - - const fdNew = await createBinFile(newPTauFilename, "ptau", 1, 11); - await writePTauHeader(fdNew, curve, power); - - // const fdTmp = await fastFile.createOverride(newPTauFilename+ ".tmp"); - - await copySection(fdOld, sections, fdNew, 2); - await copySection(fdOld, sections, fdNew, 3); - await copySection(fdOld, sections, fdNew, 4); - await copySection(fdOld, sections, fdNew, 5); - await copySection(fdOld, sections, fdNew, 6); - await copySection(fdOld, sections, fdNew, 7); - - await processSection(2, 12, "G1", "tauG1" ); - await copySection(fdOld, sections, fdNew, 13); - await copySection(fdOld, sections, fdNew, 14); - await copySection(fdOld, sections, fdNew, 15); - - await fdOld.close(); - await fdNew.close(); - - // await fs.promises.unlink(newPTauFilename+ ".tmp"); - - return; - - async function processSection(oldSectionId, newSectionId, Gstr, sectionName) { - if (logger) logger.debug("Starting section: "+sectionName); - - await startWriteSection(fdNew, newSectionId); - - const size = sections[newSectionId][0].size; - const chunkSize = fdOld.pageSize; - await startReadUniqueSection$1(fdOld, sections, newSectionId); - for (let p=0; p. - */ - - - async function exportJson(pTauFilename, verbose) { - const {fd, sections} = await readBinFile$1(pTauFilename, "ptau", 1); - - const {curve, power} = await readPTauHeader(fd, sections); - - const pTau = {}; - pTau.q = curve.q; - pTau.power = power; - pTau.contributions = await readContributions(fd, curve, sections); - - pTau.tauG1 = await exportSection(2, "G1", (2 ** power)*2 -1, "tauG1"); - pTau.tauG2 = await exportSection(3, "G2", (2 ** power), "tauG2"); - pTau.alphaTauG1 = await exportSection(4, "G1", (2 ** power), "alphaTauG1"); - pTau.betaTauG1 = await exportSection(5, "G1", (2 ** power), "betaTauG1"); - pTau.betaG2 = await exportSection(6, "G2", 1, "betaG2"); - - pTau.lTauG1 = await exportLagrange(12, "G1", "lTauG1"); - pTau.lTauG2 = await exportLagrange(13, "G2", "lTauG2"); - pTau.lAlphaTauG1 = await exportLagrange(14, "G1", "lAlphaTauG2"); - pTau.lBetaTauG1 = await exportLagrange(15, "G1", "lBetaTauG2"); - - await fd.close(); - - return stringifyBigIntsWithField(curve.Fr, pTau); - - - - async function exportSection(sectionId, groupName, nPoints, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - - const res = []; - await startReadUniqueSection$1(fd, sections, sectionId); - for (let i=0; i< nPoints; i++) { - if ((verbose)&&i&&(i%10000 == 0)) console.log(`${sectionName}: ` + i); - const buff = await fd.read(sG); - res.push(G.fromRprLEM(buff, 0)); - } - await endReadSection$1(fd); - - return res; - } - - async function exportLagrange(sectionId, groupName, sectionName) { - const G = curve[groupName]; - const sG = G.F.n8*2; - - const res = []; - await startReadUniqueSection$1(fd, sections, sectionId); - for (let p=0; p<=power; p++) { - if (verbose) console.log(`${sectionName}: Power: ${p}`); - res[p] = []; - const nPoints = (2 ** p); - for (let i=0; i. - */ - - var powersoftau = /*#__PURE__*/Object.freeze({ - __proto__: null, - beacon: beacon$1, - challengeContribute: challengeContribute, - contribute: contribute, - convert: convert, - exportChallenge: exportChallenge, - exportJson: exportJson, - importResponse: importResponse, - newAccumulator: newAccumulator, - preparePhase2: preparePhase2, - truncate: truncate, - verify: verify - }); - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - function r1csPrint(r1cs, syms, logger) { - for (let i=0; i { - let S = ""; - const keys = Object.keys(lc); - keys.forEach( (k) => { - let name = syms.varIdx2Name[k]; - if (name == "one") name = "1"; - - let vs = r1cs.curve.Fr.toString(lc[k]); - if (vs == "1") vs = ""; // Do not show ones - if (vs == "-1") vs = "-"; // Do not show ones - if ((S!="")&&(vs[0]!="-")) vs = "+"+vs; - if (S!="") vs = " "+vs; - S= S + vs + name; - }); - return S; - }; - const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`; - if (logger) logger.info(S); - } - - } - - const SUBARRAY_SIZE$1 = 0x40000; - - const BigArrayHandler$1 = { - get: function(obj, prop) { - if (!isNaN(prop)) { - return obj.getElement(prop); - } else return obj[prop]; - }, - set: function(obj, prop, value) { - if (!isNaN(prop)) { - return obj.setElement(prop, value); - } else { - obj[prop] = value; - return true; - } - } - }; - - let _BigArray$1 = class _BigArray { - constructor (initSize) { - this.length = initSize || 0; - this.arr = new Array(SUBARRAY_SIZE$1); - - for (let i=0; i= this.length) this.length = idx+1; - return true; - } - getKeys() { - const newA = new BigArray$1(); - for (let i=0; i { - self.pendingLoads.push({ - page: p, - resolve: resolve, - reject: reject - }); - }); - self.__statusPage("After Load request: ", p); - return P; - } - - __statusPage(s, p) { - const logEntry = []; - const self=this; - if (!self.logHistory) return; - logEntry.push("==" + s+ " " +p); - let S = ""; - for (let i=0; i " + self.history[p][i][j]); - } - } - } - - - - _triggerLoad() { - const self = this; - - if (self.reading) return; - if (self.pendingLoads.length==0) return; - - const pageIdxs = Object.keys(self.pages); - - const deletablePages = []; - for (let i=0; i0) && - ( (typeof self.pages[self.pendingLoads[0].page] != "undefined" ) - ||( (freePages>0) - ||(deletablePages.length>0)))) { - const load = self.pendingLoads.shift(); - if (typeof self.pages[load.page] != "undefined") { - self.pages[load.page].pendingOps ++; - const idx = deletablePages.indexOf(load.page); - if (idx>=0) deletablePages.splice(idx, 1); - if (self.pages[load.page].loading) { - self.pages[load.page].loading.push(load); - } else { - load.resolve(); - } - self.__statusPage("After Load (cached): ", load.page); - - } else { - if (freePages) { - freePages--; - } else { - const fp = deletablePages.shift(); - self.__statusPage("Before Unload: ", fp); - self.avBuffs.unshift(self.pages[fp]); - delete self.pages[fp]; - self.__statusPage("After Unload: ", fp); - } - - if (load.page>=self.totalPages) { - self.pages[load.page] = getNewPage(); - load.resolve(); - self.__statusPage("After Load (new): ", load.page); - } else { - self.reading = true; - self.pages[load.page] = getNewPage(); - self.pages[load.page].loading = [load]; - ops.push(self.fd.read(self.pages[load.page].buff, 0, self.pageSize, load.page*self.pageSize).then((res)=> { - self.pages[load.page].size = res.bytesRead; - const loading = self.pages[load.page].loading; - delete self.pages[load.page].loading; - for (let i=0; i { - load.reject(err); - })); - self.__statusPage("After Load (loading): ", load.page); - } - } - } - // if (ops.length>1) console.log(ops.length); - - Promise.all(ops).then( () => { - self.reading = false; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - self._tryClose(); - }); - - function getNewPage() { - if (self.avBuffs.length>0) { - const p = self.avBuffs.shift(); - p.dirty = false; - p.pendingOps = 1; - p.size =0; - return p; - } else { - return { - dirty: false, - buff: new Uint8Array(self.pageSize), - pendingOps: 1, - size: 0 - }; - } - } - - } - - - _triggerWrite() { - const self = this; - if (self.writing) return; - - const pageIdxs = Object.keys(self.pages); - - const ops = []; - - for (let i=0; i { - page.writing = false; - return; - }, (err) => { - console.log("ERROR Writing: "+err); - self.error = err; - self._tryClose(); - })); - } - } - - if (self.writing) { - Promise.all(ops).then( () => { - self.writing = false; - setImmediate(self._triggerWrite.bind(self)); - self._tryClose(); - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - }); - } - } - - _getDirtyPage() { - for (let p in this.pages) { - if (this.pages[p].dirty) return p; - } - return -1; - } - - async write(buff, pos) { - if (buff.byteLength == 0) return; - const self = this; - /* - if (buff.byteLength > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(buff.byteLength * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } - */ - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+buff.byteLength; - if (self.totalSize < pos + buff.byteLength) self.totalSize = pos + buff.byteLength; - if (self.pendingClose) - throw new Error("Writing a closing file"); - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + buff.byteLength -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - let r = buff.byteLength; - while (r>0) { - await pagePromises[p-firstPage]; - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = buff.slice( buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.pages[p].buff.buffer, o, l); - dstView.set(srcView); - self.pages[p].dirty = true; - self.pages[p].pendingOps --; - self.pages[p].size = Math.max(o+l, self.pages[p].size); - if (p>=self.totalPages) { - self.totalPages = p+1; - } - r = r-l; - p ++; - o = 0; - if (!self.writing) setImmediate(self._triggerWrite.bind(self)); - } - } - - async read(len, pos) { - const self = this; - let buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - async readToBuffer(buffDst, offset, len, pos) { - if (len == 0) { - return; - } - const self = this; - if (len > self.pageSize*self.maxPagesLoaded*0.8) { - const cacheSize = Math.floor(len * 1.1); - this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; - } - if (typeof pos == "undefined") pos = self.pos; - self.pos = pos+len; - if (self.pendingClose) - throw new Error("Reading a closing file"); - const firstPage = Math.floor(pos / self.pageSize); - const lastPage = Math.floor((pos + len -1) / self.pageSize); - - const pagePromises = []; - for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); - - self._triggerLoad(); - - let p = firstPage; - let o = pos % self.pageSize; - // Remaining bytes to read - let r = pos + len > self.totalSize ? len - (pos + len - self.totalSize): len; - while (r>0) { - await pagePromises[p - firstPage]; - self.__statusPage("After Await (read): ", p); - - // bytes to copy from this page - const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; - const srcView = new Uint8Array(self.pages[p].buff.buffer, self.pages[p].buff.byteOffset + o, l); - buffDst.set(srcView, offset+len-r); - self.pages[p].pendingOps --; - - self.__statusPage("After Op done: ", p); - - r = r-l; - p ++; - o = 0; - if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); - } - - this.pos = pos + len; - - } - - - _tryClose() { - const self = this; - if (!self.pendingClose) return; - if (self.error) { - self.pendingCloseReject(self.error); - } - const p = self._getDirtyPage(); - if ((p>=0) || (self.writing) || (self.reading) || (self.pendingLoads.length>0)) return; - self.pendingClose(); - } - - close() { - const self = this; - if (self.pendingClose) - throw new Error("Closing the file twice"); - return new Promise((resolve, reject) => { - self.pendingClose = resolve; - self.pendingCloseReject = reject; - self._tryClose(); - }).then(()=> { - self.fd.close(); - }, (err) => { - self.fd.close(); - throw (err); - }); - } - - async discard() { - const self = this; - await self.close(); - await fs.promises.unlink(this.fileName); - } - - async writeULE32(v, pos) { - const self = this; - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, true); - - await self.write(tmpBuff32, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - - tmpBuff32v.setUint32(0, v, false); - - await self.write(tmpBuff32, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - const tmpBuff64 = new Uint8Array(8); - const tmpBuff64v = new DataView(tmpBuff64.buffer); - - tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64, pos); - } - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - if (self.pendingClose) { - throw new Error("Reading a closing file"); - } - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - let currentPage = Math.floor(currentPosition / self.pageSize); - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - //Read page - let pagePromise = self._loadPage(currentPage); - self._triggerLoad(); - await pagePromise; - self.__statusPage("After Await (read): ", currentPage); - - let offsetOnPage = currentPosition % self.pageSize; - - const dataArray = new Uint8Array( - self.pages[currentPage].buff.buffer, - self.pages[currentPage].buff.byteOffset + offsetOnPage, - self.pageSize - offsetOnPage - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * this.pageSize + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * this.pageSize + offsetOnPage + dataArray.length; - } - - self.pages[currentPage].pendingOps--; - self.__statusPage("After Op done: ", currentPage); - - currentPosition = self.pos; - currentPage++; - - if (self.pendingLoads.length > 0) setImmediate(self._triggerLoad.bind(self)); - } - - return str; - } - } - - function readExisting$2(o) { - const fd = new MemFile(); - fd.o = o; - fd.allocSize = o.data.byteLength; - fd.totalSize = o.data.byteLength; - fd.readOnly = true; - fd.pos = 0; - return fd; - } - - const tmpBuff32$1 = new Uint8Array(4); - const tmpBuff32v$1 = new DataView(tmpBuff32$1.buffer); - const tmpBuff64$1 = new Uint8Array(8); - const tmpBuff64v$1 = new DataView(tmpBuff64$1.buffer); - - class MemFile { - - constructor() { - this.pageSize = 1 << 14; // for compatibility - } - - _resizeIfNeeded(newLen) { - if (newLen > this.allocSize) { - const newAllocSize = Math.max( - this.allocSize + (1 << 20), - Math.floor(this.allocSize * 1.1), - newLen - ); - const newData = new Uint8Array(newAllocSize); - newData.set(this.o.data); - this.o.data = newData; - this.allocSize = newAllocSize; - } - } - - async write(buff, pos) { - const self =this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) throw new Error("Writing a read only file"); - - this._resizeIfNeeded(pos + buff.byteLength); - - this.o.data.set(buff.slice(), pos); - - if (pos + buff.byteLength > this.totalSize) this.totalSize = pos + buff.byteLength; - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDest, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const buffSrc = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + pos, len); - - buffDest.set(buffSrc, offset); - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - - const buff = new Uint8Array(len); - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - if (this.o.data.byteLength != this.totalSize) { - this.o.data = this.o.data.slice(0, this.totalSize); - } - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v$1.setUint32(0, v, true); - - await self.write(tmpBuff32$1, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v$1.setUint32(0, v, false); - - await self.write(tmpBuff32$1, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v$1.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v$1.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64$1, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - const dataArray = new Uint8Array( - self.o.data.buffer, - currentPosition, - this.totalSize - currentPosition - ); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - let endOfStringFound = indexEndOfString !== -1; - - let str = ""; - if (endOfStringFound) { - str = new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPosition + indexEndOfString + 1; - } else { - self.pos = currentPosition; - } - return str; - } - } - - const PAGE_SIZE = 1<<22; - - function readExisting$1(o) { - const fd = new BigMemFile(); - fd.o = o; - fd.totalSize = (o.data.length-1)* PAGE_SIZE + o.data[o.data.length-1].byteLength; - fd.readOnly = true; - fd.pos = 0; - return fd; - } - - const tmpBuff32 = new Uint8Array(4); - const tmpBuff32v = new DataView(tmpBuff32.buffer); - const tmpBuff64 = new Uint8Array(8); - const tmpBuff64v = new DataView(tmpBuff64.buffer); - - class BigMemFile { - - constructor() { - this.pageSize = 1 << 14; // for compatibility - } - - _resizeIfNeeded(newLen) { - - if (newLen <= this.totalSize) return; - - if (this.readOnly) throw new Error("Reading out of file bounds"); - - const nPages = Math.floor((newLen - 1) / PAGE_SIZE)+1; - for (let i= Math.max(this.o.data.length-1, 0); i0) { - const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; - const srcView = buff.slice(buff.byteLength - r, buff.byteLength - r + l); - const dstView = new Uint8Array(self.o.data[p].buffer, o, l); - dstView.set(srcView); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + buff.byteLength; - } - - async readToBuffer(buffDst, offset, len, pos) { - const self = this; - if (typeof pos == "undefined") pos = self.pos; - if (this.readOnly) { - if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos + len); - - const firstPage = Math.floor(pos / PAGE_SIZE); - - let p = firstPage; - let o = pos % PAGE_SIZE; - // Remaining bytes to read - let r = len; - while (r>0) { - // bytes to copy from this page - const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; - const srcView = new Uint8Array(self.o.data[p].buffer, o, l); - buffDst.set(srcView, offset+len-r); - r = r-l; - p ++; - o = 0; - } - - this.pos = pos + len; - } - - async read(len, pos) { - const self = this; - const buff = new Uint8Array(len); - - await self.readToBuffer(buff, 0, len, pos); - - return buff; - } - - close() { - } - - async discard() { - } - - - async writeULE32(v, pos) { - const self = this; - - tmpBuff32v.setUint32(0, v, true); - - await self.write(tmpBuff32, pos); - } - - async writeUBE32(v, pos) { - const self = this; - - tmpBuff32v.setUint32(0, v, false); - - await self.write(tmpBuff32, pos); - } - - - async writeULE64(v, pos) { - const self = this; - - tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); - tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); - - await self.write(tmpBuff64, pos); - } - - - async readULE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new Uint32Array(b.buffer); - - return view[0]; - } - - async readUBE32(pos) { - const self = this; - const b = await self.read(4, pos); - - const view = new DataView(b.buffer); - - return view.getUint32(0, false); - } - - async readULE64(pos) { - const self = this; - const b = await self.read(8, pos); - - const view = new Uint32Array(b.buffer); - - return view[1] * 0x100000000 + view[0]; - } - - async readString(pos) { - const self = this; - const fixedSize = 2048; - - let currentPosition = typeof pos == "undefined" ? self.pos : pos; - - if (currentPosition > this.totalSize) { - if (this.readOnly) { - throw new Error("Reading out of bounds"); - } - this._resizeIfNeeded(pos); - } - - let endOfStringFound = false; - let str = ""; - - while (!endOfStringFound) { - let currentPage = Math.floor(currentPosition / PAGE_SIZE); - let offsetOnPage = currentPosition % PAGE_SIZE; - - if (self.o.data[currentPage] === undefined) { - throw new Error("ERROR"); - } - - let readLength = Math.min(fixedSize, self.o.data[currentPage].length - offsetOnPage); - const dataArray = new Uint8Array(self.o.data[currentPage].buffer, offsetOnPage, readLength); - - let indexEndOfString = dataArray.findIndex(element => element === 0); - endOfStringFound = indexEndOfString !== -1; - - if (endOfStringFound) { - str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); - self.pos = currentPage * PAGE_SIZE + offsetOnPage + indexEndOfString + 1; - } else { - str += new TextDecoder().decode(dataArray); - self.pos = currentPage * PAGE_SIZE + offsetOnPage + dataArray.length; - } - - currentPosition = self.pos; - } - return str; - } - } - - /* global fetch */ - - async function readExisting(o, b, c) { - if (o instanceof Uint8Array) { - o = { - type: "mem", - data: o - }; - } - { - if (typeof o === "string") { - const buff = await fetch(o).then( function(res) { - return res.arrayBuffer(); - }).then(function (ab) { - return new Uint8Array(ab); - }); - o = { - type: "mem", - data: buff - }; - } - } - if (o.type == "file") { - return await open(o.fileName, O_RDONLY, o.cacheSize, o.pageSize); - } else if (o.type == "mem") { - return await readExisting$2(o); - } else if (o.type == "bigMem") { - return await readExisting$1(o); - } else { - throw new Error("Invalid FastFile type: "+o.type); - } - } - - async function readBinFile(fileName, type, maxVersion, cacheSize, pageSize) { - - const fd = await readExisting(fileName); - - const b = await fd.read(4); - let readedType = ""; - for (let i=0; i<4; i++) readedType += String.fromCharCode(b[i]); - - if (readedType != type) throw new Error(fileName + ": Invalid File format"); - - let v = await fd.readULE32(); - - if (v>maxVersion) throw new Error("Version not supported"); - - const nSections = await fd.readULE32(); - - // Scan sections - let sections = []; - for (let i=0; i1) throw new Error(fd.fileName +": Section Duplicated " +idSection); - - fd.pos = sections[idSection][0].p; - - fd.readingSection = sections[idSection][0]; - } - - async function endReadSection(fd, noCheck) { - if (typeof fd.readingSection === "undefined") throw new Error("Not reading a section"); - { - if (fd.pos-fd.readingSection.p != fd.readingSection.size) throw new Error("Invalid section size reading"); - } - delete fd.readingSection; - } - - async function readBigInt(fd, n8, pos) { - const buff = await fd.read(n8, pos); - return Scalar.fromRprLE(buff, 0, n8); - } - - async function readSection(fd, sections, idSection, offset, length) { - - offset = (typeof offset === "undefined") ? 0 : offset; - length = (typeof length === "undefined") ? sections[idSection][0].size - offset : length; - - if (offset + length > sections[idSection][0].size) { - throw new Error("Reading out of the range of the section"); - } - - let buff; - if (length < (1 << 30) ) { - buff = new Uint8Array(length); - } else { - buff = new BigBuffer(length); - } - - await fd.readToBuffer(buff, 0, length, sections[idSection][0].p + offset); - return buff; - } - - const R1CS_FILE_CUSTOM_GATES_LIST_SECTION = 4; - const R1CS_FILE_CUSTOM_GATES_USES_SECTION = 5; - - async function readR1csHeader(fd,sections,singleThread) { - let options; - if (typeof singleThread === "object") { - options = singleThread; - } else if (typeof singleThread === "undefined") { - options= { - singleThread: false, - }; - } else { - options = { - singleThread: singleThread, - }; - } - - const res = {}; - await startReadUniqueSection(fd, sections, 1); - // Read Header - res.n8 = await fd.readULE32(); - res.prime = await readBigInt(fd, res.n8); - - if (options.F) { - if (options.F.p != res.prime) throw new Error("Different Prime"); - res.F = options.F; - } else if (options.getFieldFromPrime) { - res.F = await options.getFieldFromPrime(res.prime, options.singleThread); - } else if (options.getCurveFromPrime) { - res.curve = await options.getCurveFromPrime(res.prime, options.singleThread); - res.F = res.curve.Fr; - } else { - try { - res.curve = await getCurveFromR$1(res.prime, options.singleThread); - res.F = res.curve.Fr; - } catch { - res.F = new ZqField(res.prime); - } - } - - res.nVars = await fd.readULE32(); - res.nOutputs = await fd.readULE32(); - res.nPubInputs = await fd.readULE32(); - res.nPrvInputs = await fd.readULE32(); - res.nLabels = await fd.readULE64(); - res.nConstraints = await fd.readULE32(); - res.useCustomGates = typeof sections[R1CS_FILE_CUSTOM_GATES_LIST_SECTION] !== "undefined" && sections[R1CS_FILE_CUSTOM_GATES_LIST_SECTION] !== null - && typeof sections[R1CS_FILE_CUSTOM_GATES_USES_SECTION] !== "undefined" && sections[R1CS_FILE_CUSTOM_GATES_USES_SECTION] !== null; - - await endReadSection(fd); - - return res; - } - - async function readConstraints(fd,sections, r1cs, logger, loggerCtx) { - let options; - if (typeof logger === "object") { - options = logger; - } else if (typeof logger === "undefined") { - options= {}; - } else { - options = { - logger: logger, - loggerCtx: loggerCtx, - }; - } - - const bR1cs = await readSection(fd, sections, 2); - let bR1csPos = 0; - let constraints; - if (r1cs.nConstraints>1<<20) { - constraints = new BigArray$1(); - } else { - constraints = []; - } - for (let i=0; i1<<20) { - map = new BigArray$1(); - } else { - map = []; - } - for (let i=0; i true by default - * loadMap: false by default - * loadCustomGates: true by default - */ - - if(typeof options !== "object") { - throw new Error("readR1csFd: options must be an object"); - } - - options.loadConstraints = "loadConstraints" in options ? options.loadConstraints : true; - options.loadMap = "loadMap" in options ? options.loadMap : false; - options.loadCustomGates = "loadCustomGates" in options ? options.loadCustomGates : true; - - const res = await readR1csHeader(fd, sections, options); - - if (options.loadConstraints) { - res.constraints = await readConstraints(fd, sections, res, options); - } - - // Read Labels - - if (options.loadMap) { - res.map = await readMap(fd, sections, res, options); - } - - if (options.loadCustomGates) { - if (res.useCustomGates) { - res.customGates = await readCustomGatesListSection(fd, sections, res); - res.customGatesUses = await readCustomGatesUsesSection(fd, sections, options); - } else { - res.customGates = []; - res.customGatesUses = []; - } - } - return res; - } - - async function readR1cs(fileName, loadConstraints, loadMap, singleThread, logger, loggerCtx) { - let options; - if (typeof loadConstraints === "object") { - options = loadConstraints; - } else if (typeof loadConstraints === "undefined") { - options= { - loadConstraints: true, - loadMap: false, - loadCustomGates: true - }; - } else { - options = { - loadConstraints: loadConstraints, - loadMap: loadMap, - singleThread: singleThread, - logger: logger, - loggerCtx: loggerCtx - }; - } - - const {fd, sections} = await readBinFile(fileName, "r1cs", 1); - - const res = await readR1csFd(fd, sections, options); - - await fd.close(); - - return res; - } - - async function readCustomGatesListSection(fd, sections, res) { - await startReadUniqueSection(fd, sections, R1CS_FILE_CUSTOM_GATES_LIST_SECTION); - - let num = await fd.readULE32(); - - let customGates = []; - for (let i = 0; i < num; i++) { - let customGate = {}; - customGate.templateName = await fd.readString(); - let numParameters = await fd.readULE32(); - - customGate.parameters = Array(numParameters); - let buff = await fd.read(res.n8 * numParameters); - - for (let j = 0; j < numParameters; j++) { - customGate.parameters[j] = res.F.fromRprLE(buff, j * res.n8, res.n8); } - customGates.push(customGate); - } - await endReadSection(fd); - - return customGates; - } - - async function readCustomGatesUsesSection(fd,sections, options) { - const bR1cs = await readSection(fd, sections, R1CS_FILE_CUSTOM_GATES_USES_SECTION); - const bR1cs32 = new Uint32Array(bR1cs.buffer, bR1cs.byteOffset, bR1cs.byteLength/4); - const nCustomGateUses = bR1cs32[0]; - let bR1csPos = 1; - let customGatesUses; - if (nCustomGateUses>1<<20) { - customGatesUses = new BigArray$1(); - } else { - customGatesUses = []; - } - for (let i=0; i. - */ - - - const bls12381r = Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); - const bn128r = Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - - async function r1csInfo(r1csName, logger) { - - // Only the header (section 1) is needed for these counts; loading the - // constraints + wire-to-label map would read the whole (potentially many-GB) - // file for nothing. - const cir = await readR1cs(r1csName, {loadConstraints: false, loadMap: false}); - - if (Scalar.eq(cir.prime, bn128r)) { - if (logger) logger.info("Curve: bn-128"); - } else if (Scalar.eq(cir.prime, bls12381r)) { - if (logger) logger.info("Curve: bls12-381"); - } else { - if (logger) logger.info(`Unknown Curve. Prime: ${Scalar.toString(cir.prime)}`); - } - if (logger) logger.info(`# of Wires: ${cir.nVars}`); - if (logger) logger.info(`# of Constraints: ${cir.nConstraints}`); - if (logger) logger.info(`# of Private Inputs: ${cir.nPrvInputs}`); - if (logger) logger.info(`# of Public Inputs: ${cir.nPubInputs}`); - if (logger) logger.info(`# of Labels: ${cir.nLabels}`); - if (logger) logger.info(`# of Outputs: ${cir.nOutputs}`); - - return cir; - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - - async function r1csExportJson(r1csFileName, logger) { - - const cir = await readR1cs(r1csFileName, true, true, true, logger); - const Fr=cir.curve.Fr; - delete cir.curve; - delete cir.F; - - return stringifyBigIntsWithField(Fr, cir); - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - var r1cs = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportJson: r1csExportJson, - info: r1csInfo, - print: r1csPrint - }); - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - async function loadSymbols(symFileName) { - const sym = { - labelIdx2Name: [ "one" ], - varIdx2Name: [ "one" ], - componentIdx2Name: [] - }; - const fd = await readExisting$3(symFileName); - const buff = await fd.read(fd.totalSize); - const symsStr = new TextDecoder("utf-8").decode(buff); - const lines = symsStr.split("\n"); - for (let i=0; i. - */ - - const {unstringifyBigInts: unstringifyBigInts$7} = utils; - - - async function wtnsDebug(_input, wasmFileName, wtnsFileName, symName, options, logger) { - - const input = unstringifyBigInts$7(_input); - - const fdWasm = await readExisting$3(wasmFileName); - const wasm = await fdWasm.read(fdWasm.totalSize); - await fdWasm.close(); - - const wcOps = {...options, sanityCheck: true}; - let sym = await loadSymbols(symName); - if (options.set) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logSetSignal= function(labelIdx, value) { - // The line below splits the arrow log into 2 strings to avoid some Secure ECMAScript issues - if (logger) logger.info("SET " + sym.labelIdx2Name[labelIdx] + " <" + "-- " + value.toString()); - }; - } - if (options.get) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logGetSignal= function(varIdx, value) { - // The line below splits the arrow log into 2 strings to avoid some Secure ECMAScript issues - if (logger) logger.info("GET " + sym.labelIdx2Name[varIdx] + " --" + "> " + value.toString()); - }; - } - if (options.trigger) { - if (!sym) sym = await loadSymbols(symName); - wcOps.logStartComponent= function(cIdx) { - if (logger) logger.info("START: " + sym.componentIdx2Name[cIdx]); - }; - wcOps.logFinishComponent= function(cIdx) { - if (logger) logger.info("FINISH: " + sym.componentIdx2Name[cIdx]); - }; - } - wcOps.sym = sym; - - const wc = await builder(wasm, wcOps); - const w = await wc.calculateWitness(input, true); - - const fdWtns = await createBinFile(wtnsFileName, "wtns", 2, 2); - - await write(fdWtns, w, wc.prime); - - await fdWtns.close(); - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - async function wtnsExportJson(wtnsFileName) { - - const w = await read(wtnsFileName); - - return w; - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - async function wtnsCheck(r1csFilename, wtnsFilename, logger) { - - if (logger) logger.info("WITNESS CHECKING STARTED"); - - // Read r1cs file - if (logger) logger.info("> Reading r1cs file"); - const { - fd: fdR1cs, - sections: sectionsR1cs - } = await readBinFile$1(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); - const r1cs = await readR1csFd(fdR1cs, sectionsR1cs, { loadConstraints: false, loadCustomGates: false }); - - // Read witness file - if (logger) logger.info("> Reading witness file"); - const { - fd: fdWtns, - sections: wtnsSections - } = await readBinFile$1(wtnsFilename, "wtns", 2, 1 << 22, 1 << 24); - const wtnsHeader = await readHeader(fdWtns, wtnsSections); - - if (!Scalar.eq(r1cs.prime, wtnsHeader.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - const buffWitness = await readSection$1(fdWtns, wtnsSections, 2); - await fdWtns.close(); - - const curve = await getCurveFromR(r1cs.prime); - const Fr = curve.Fr; - const sFr = Fr.n8; - - const bR1cs = await readSection$1(fdR1cs, sectionsR1cs, 2); - - if (logger) { - logger.info("----------------------------"); - logger.info(" WITNESS CHECK"); - logger.info(` Curve: ${r1cs.curve.name}`); - logger.info(` Vars (wires): ${r1cs.nVars}`); - logger.info(` Outputs: ${r1cs.nOutputs}`); - logger.info(` Public Inputs: ${r1cs.nPubInputs}`); - logger.info(` Private Inputs: ${r1cs.nPrvInputs}`); - logger.info(` Labels: ${r1cs.nLabels}`); - logger.info(` Constraints: ${r1cs.nConstraints}`); - logger.info(` Custom Gates: ${r1cs.useCustomGates}`); - logger.info("----------------------------"); - } - - if (logger) logger.info("> Checking witness correctness"); - - let bR1csPos = 0; - let res = true; - for (let i = 0; i < r1cs.nConstraints; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(`··· processing r1cs constraints ${i}/${r1cs.nConstraints}`); - } - - //Read the three linear combinations of the constraint where A * B - C = 0 - const lcA = readLC(); - const lcB = readLC(); - const lcC = readLC(); - - // Evaluate the linear combinations - const evalA = EvaluateLinearCombination(lcA); - const evalB = EvaluateLinearCombination(lcB); - const evalC = EvaluateLinearCombination(lcC); - - // Check that A * B - C == 0 - if (!Fr.eq(Fr.sub(Fr.mul(evalA, evalB), evalC), Fr.zero)) { - logger.warn("··· aborting checking process at constraint " + i); - res = false; - break; - } - } - - fdR1cs.close(); - - if (logger) { - if (res) { - logger.info("WITNESS IS CORRECT"); - logger.info("WITNESS CHECKING FINISHED SUCCESSFULLY"); - } else { - logger.warn("WITNESS IS NOT CORRECT"); - logger.warn("WITNESS CHECKING FINISHED UNSUCCESSFULLY"); - } - } - - return res; - - function EvaluateLinearCombination(lc) { - let res = Fr.zero; - - const keys = Object.keys(lc); - keys.forEach((signalId) => { - const signalValue = getWitnessValue(signalId); - const signalFactor = lc[signalId]; - - res = Fr.add(res, Fr.mul(signalValue, signalFactor)); - }); - - return res; - } - - function readLC() { - const lc = {}; - - const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); - bR1csPos += 4; - const buffUL32V = new DataView(buffUL32.buffer); - const nIdx = buffUL32V.getUint32(0, true); - - const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); - bR1csPos += (4 + r1cs.n8) * nIdx; - const buffV = new DataView(buff.buffer); - for (let i = 0; i < nIdx; i++) { - const idx = buffV.getUint32(i * (4 + r1cs.n8), true); - const val = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); - lc[idx] = val; - } - return lc; - } - - function getWitnessValue(signalId) { - return Fr.fromRprLE(buffWitness.slice(signalId * sFr, signalId * sFr + sFr)); - } - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - var wtns = /*#__PURE__*/Object.freeze({ - __proto__: null, - calculate: wtnsCalculate, - check: wtnsCheck, - debug: wtnsDebug, - exportJson: wtnsExportJson - }); - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - const SUBARRAY_SIZE = 0x40000; - - const BigArrayHandler = { - get: function(obj, prop) { - if (!isNaN(prop)) { - return obj.getElement(prop); - } else return obj[prop]; - }, - set: function(obj, prop, value) { - if (!isNaN(prop)) { - return obj.setElement(prop, value); - } else { - obj[prop] = value; - return true; - } - } - }; - - class _BigArray { - constructor (initSize) { - this.length = initSize || 0; - this.arr = new Array(SUBARRAY_SIZE); - - for (let i=0; i= this.length) this.length = idx+1; - return true; - } - getKeys() { - const newA = new BigArray(); - for (let i=0; i. - */ - - - async function newZKey(r1csName, ptauName, zkeyName, logger) { - - const TAU_G1 = 0; - const TAU_G2 = 1; - const ALPHATAU_G1 = 2; - const BETATAU_G1 = 3; - const csHasher = blake2b.create({ dkLen: 64 }); - - const {fd: fdPTau, sections: sectionsPTau} = await readBinFile$1(ptauName, "ptau", 1, 1<<22, 1<<24); - const {curve, power} = await readPTauHeader(fdPTau, sectionsPTau); - const {fd: fdR1cs, sections: sectionsR1cs} = await readBinFile$1(r1csName, "r1cs", 1, 1<<22, 1<<24); - const r1cs = await readR1csHeader(fdR1cs, sectionsR1cs, false); - - const fdZKey = await createBinFile(zkeyName, "zkey", 1, 10, 1<<22, 1<<24); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - if (r1cs.prime != curve.r) { - if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); - return -1; - } - - const cirPower = log2(r1cs.nConstraints + r1cs.nPubInputs + r1cs.nOutputs +1 -1) +1; - - if (cirPower > power) { - if (logger) logger.error(`circuit too big for this power of tau ceremony. ${r1cs.nConstraints}*2 > 2**${power}`); - return -1; - } - - if (!sectionsPTau[12]) { - if (logger) logger.error("Powers of tau is not prepared."); - return -1; - } - - const nPublic = r1cs.nOutputs + r1cs.nPubInputs; - const domainSize = 2 ** cirPower; - - // Write the header - /////////// - await startWriteSection(fdZKey, 1); - await fdZKey.writeULE32(1); // Groth - await endWriteSection(fdZKey); - - // Write the Groth header section - /////////// - - await startWriteSection(fdZKey, 2); - const primeQ = curve.q; - const n8q = (Math.floor( (Scalar.bitLength(primeQ) - 1) / 64) +1)*8; - - const primeR = curve.r; - const n8r = (Math.floor( (Scalar.bitLength(primeR) - 1) / 64) +1)*8; - const Rr = Scalar.mod(Scalar.shl(1, n8r*8), primeR); - const R2r = curve.Fr.e(Scalar.mod(Scalar.mul(Rr,Rr), primeR)); - - await fdZKey.writeULE32(n8q); - await writeBigInt(fdZKey, primeQ, n8q); - await fdZKey.writeULE32(n8r); - await writeBigInt(fdZKey, primeR, n8r); - await fdZKey.writeULE32(r1cs.nVars); // Total number of bars - await fdZKey.writeULE32(nPublic); // Total number of public vars (not including ONE) - await fdZKey.writeULE32(domainSize); // domainSize - - let bAlpha1; - bAlpha1 = await fdPTau.read(sG1, sectionsPTau[4][0].p); - await fdZKey.write(bAlpha1); - bAlpha1 = await curve.G1.batchLEMtoU(bAlpha1); - csHasher.update(bAlpha1); - - let bBeta1; - bBeta1 = await fdPTau.read(sG1, sectionsPTau[5][0].p); - await fdZKey.write(bBeta1); - bBeta1 = await curve.G1.batchLEMtoU(bBeta1); - csHasher.update(bBeta1); - - let bBeta2; - bBeta2 = await fdPTau.read(sG2, sectionsPTau[6][0].p); - await fdZKey.write(bBeta2); - bBeta2 = await curve.G2.batchLEMtoU(bBeta2); - csHasher.update(bBeta2); - - const bg1 = new Uint8Array(sG1); - curve.G1.toRprLEM(bg1, 0, curve.G1.g); - const bg2 = new Uint8Array(sG2); - curve.G2.toRprLEM(bg2, 0, curve.G2.g); - const bg1U = new Uint8Array(sG1); - curve.G1.toRprUncompressed(bg1U, 0, curve.G1.g); - const bg2U = new Uint8Array(sG2); - curve.G2.toRprUncompressed(bg2U, 0, curve.G2.g); - - await fdZKey.write(bg2); // gamma2 - await fdZKey.write(bg1); // delta1 - await fdZKey.write(bg2); // delta2 - csHasher.update(bg2U); // gamma2 - csHasher.update(bg1U); // delta1 - csHasher.update(bg2U); // delta2 - await endWriteSection(fdZKey); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Reading r1cs"); - let sR1cs = await readSection$1(fdR1cs, sectionsR1cs, 2); - await fdR1cs.close(); - - let A = new BigArray(r1cs.nVars); - let B1 = new BigArray(r1cs.nVars); - let B2 = new BigArray(r1cs.nVars); - let C = new BigArray(r1cs.nVars- nPublic -1); - let IC = new Array(nPublic+1); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Reading tauG1"); - let sTauG1 = await readSection$1(fdPTau, sectionsPTau, 12, (domainSize -1)*sG1, domainSize*sG1); - if (logger) logger.info("Reading tauG2"); - let sTauG2 = await readSection$1(fdPTau, sectionsPTau, 13, (domainSize -1)*sG2, domainSize*sG2); - if (logger) logger.info("Reading alphatauG1"); - let sAlphaTauG1 = await readSection$1(fdPTau, sectionsPTau, 14, (domainSize -1)*sG1, domainSize*sG1); - if (logger) logger.info("Reading betatauG1"); - let sBetaTauG1 = await readSection$1(fdPTau, sectionsPTau, 15, (domainSize -1)*sG1, domainSize*sG1); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("processConstraints"); - await processConstraints(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints"); - await composeAndWritePoints(3, "G1", IC, "IC"); - - IC = null; - // const gc = runInNewContext("gc"); // nocommit - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("writeHs"); - await writeHs(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("hashHPoints"); - await hashHPoints(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 8 G1 C"); - await composeAndWritePoints(8, "G1", C, "C"); - - C = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 5 G1 A"); - await composeAndWritePoints(5, "G1", A, "A"); - - A = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 6 G1 B1"); - await composeAndWritePoints(6, "G1", B1, "B1"); - - B1 = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("composeAndWritePoints 7 G2 B2"); - await composeAndWritePoints(7, "G2", B2, "B2"); - - B2 = null; - // gc(); - - if (logger) logger.info(memUsage()); - if (logger) logger.info("Contributions section"); - const csHash = csHasher.digest(); - // Contributions section - await startWriteSection(fdZKey, 10); - await fdZKey.write(csHash); - await fdZKey.writeULE32(0); - await endWriteSection(fdZKey); - - if (logger) logger.info(formatHash(csHash, "Circuit hash: ")); - - - await fdZKey.close(); - await fdPTau.close(); - - return csHash; - - async function writeHs() { - await startWriteSection(fdZKey, 9); - const buffOut = new BigBuffer(domainSize*sG1); - if (cirPower < curve.Fr.s) { - let sTauG1 = await readSection$1(fdPTau, sectionsPTau, 12, (domainSize*2-1)*sG1, domainSize*2*sG1); - for (let i=0; i< domainSize; i++) { - if ((logger)&&(i%10000 == 0)) logger.debug(`splitting buffer: ${i}/${domainSize}`); - const buff = sTauG1.slice( (i*2+1)*sG1, (i*2+1)*sG1 + sG1 ); - buffOut.set(buff, i*sG1); - } - } else if (cirPower == curve.Fr.s) { - const o = sectionsPTau[12][0].p + ((2 ** (cirPower+1)) -1)*sG1; - await fdPTau.readToBuffer(buffOut, 0, domainSize*sG1, o + domainSize*sG1); - } else { - if (logger) logger.error("Circuit too big"); - throw new Error("Circuit too big for this curve"); - } - await fdZKey.write(buffOut); - await endWriteSection(fdZKey); - } - - async function processConstraints() { - const buffCoeff = new Uint8Array(12 + curve.Fr.n8); - const buffCoeffV = new DataView(buffCoeff.buffer); - const bOne = new Uint8Array(curve.Fr.n8); - curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); - - let r1csPos = 0; - - function r1cs_readULE32() { - const buff = sR1cs.slice(r1csPos, r1csPos+4); - r1csPos += 4; - const buffV = new DataView(buff.buffer); - return buffV.getUint32(0, true); - } - - const coefs = new BigArray(); - for (let c=0; c=0) { - n = curve.Fr.fromRprLE(sR1cs.slice(c[3], c[3] + curve.Fr.n8), 0); - } else { - n = curve.Fr.fromRprLE(bOne, 0); - } - const nR2 = curve.Fr.mul(n, R2r); - curve.Fr.toRprLE(buffCoeff, 12, nR2); - buffSection.set(buffCoeff, coefsPos); - coefsPos += buffCoeff.length; - } - - } - - async function composeAndWritePoints(idSection, groupName, arr, sectionName) { - const CHUNK_SIZE= 1<<15; - const G = curve[groupName]; - - hashU32(arr.length); - await startWriteSection(fdZKey, idSection); - - let opPromises = []; - - let i=0; - while (i { - if (logger) logger.debug(`Writing points end ${sectionName}: ${_i}/${arr.length}`); - return r; - })); - i += n; - t++; - } - - const result = await Promise.all(opPromises); - - for (let k=0; k 2<<14) { - bBases = new BigBuffer(acc*sGin); - bScalars = new BigBuffer(acc*curve.Fr.n8); - } else { - bBases = new Uint8Array(acc*sGin); - bScalars = new Uint8Array(acc*curve.Fr.n8); - } - let pB =0; - let pS =0; - - const sBuffs = [ - sTauG1, - sTauG2, - sAlphaTauG1, - sBetaTauG1 - ]; - - const bOne = new Uint8Array(curve.Fr.n8); - curve.Fr.toRprLE(bOne, 0, curve.Fr.e(1)); - - let offset = 0; - for (let i=0; i=0) { - bScalars.set( - sR1cs.slice( - arr[i][j][2], - arr[i][j][2] + curve.Fr.n8 - ), - offset*curve.Fr.n8 - ); - } else { - bScalars.set(bOne, offset*curve.Fr.n8); - } - offset ++; - } - } - - if (arr.length>1) { - const task = []; - task.push({cmd: "ALLOCSET", var: 0, buff: bBases}); - task.push({cmd: "ALLOCSET", var: 1, buff: bScalars}); - task.push({cmd: "ALLOC", var: 2, len: arr.length*sGmid}); - pB = 0; - pS = 0; - let pD =0; - for (let i=0; i. - */ - - - async function phase2importMPCParams(zkeyNameOld, mpcparamsName, zkeyNameNew, name, logger) { - - const {fd: fdZKeyOld, sections: sectionsZKeyOld} = await readBinFile$1(zkeyNameOld, "zkey", 2); - const zkeyHeader = await readHeader$1(fdZKeyOld, sectionsZKeyOld, false); - if (zkeyHeader.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkeyHeader.q); - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - const oldMPCParams = await readMPCParams(fdZKeyOld, curve, sectionsZKeyOld); - const newMPCParams = {}; - - const fdMPCParams = await readExisting$3(mpcparamsName); - - fdMPCParams.pos = - sG1*3 + sG2*3 + // vKey - 8 + sG1*zkeyHeader.nVars + // IC + C - 4 + sG1*(zkeyHeader.domainSize-1) + // H - 4 + sG1*zkeyHeader.nVars + // A - 4 + sG1*zkeyHeader.nVars + // B1 - 4 + sG2*zkeyHeader.nVars; // B2 - - // csHash - newMPCParams.csHash = await fdMPCParams.read(64); - - const nContributions = await fdMPCParams.readUBE32(); - newMPCParams.contributions = []; - for (let i=0; i newMPCParams.contributions.length) { - if (logger) logger.error("The impoerted file does not include new contributions"); - return false; - } - - for (let i=0; i. - */ - - const sameRatio = sameRatio$2; - - - - async function phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger) { - - let sr; - const {fd, sections} = await readBinFile$1(zkeyFileName, "zkey", 2); - const zkey = await readHeader$1(fd, sections, false); - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkey.q); - const sG1 = curve.G1.F.n8*2; - - const mpcParams = await readMPCParams(fd, curve, sections); - - const accumulatedHasher = blake2b.create({ dkLen: 64 }); - accumulatedHasher.update(mpcParams.csHash); - let curDelta = curve.G1.g; - for (let i=0; i=0; i--) { - const c = mpcParams.contributions[i]; - if (logger) logger.info("-------------------------"); - if (logger) logger.info(formatHash(c.contributionHash, `contribution #${i+1} ${c.name ? c.name : ""}:`)); - if (c.type == 1) { - if (logger) logger.info(`Beacon generator: ${byteArray2hex(c.beaconHash)}`); - if (logger) logger.info(`Beacon iterations Exp: ${c.numIterationsExp}`); - } - } - if (logger) logger.info("-------------------------"); - - if (logger) logger.info("ZKey Ok!"); - - return true; - - - async function sectionHasSameRatio(groupName, fd1, sections1, fd2, sections2, idSection, g2sp, g2spx, sectionName) { - const MAX_CHUNK_SIZE = 1<<20; - const G = curve[groupName]; - const sG = G.F.n8*2; - await startReadUniqueSection$1(fd1, sections1, idSection); - await startReadUniqueSection$1(fd2, sections2, idSection); - - let R1 = G.zero; - let R2 = G.zero; - - const nPoints = sections1[idSection][0].size / sG; - - for (let i=0; i. - */ - - - async function phase2verifyFromR1cs(r1csFileName, pTauFileName, zkeyFileName, logger) { - - // const initFileName = "~" + zkeyFileName + ".init"; - const initFileName = {type: "bigMem"}; - await newZKey(r1csFileName, pTauFileName, initFileName, logger); - - return await phase2verifyFromInit(initFileName, pTauFileName, zkeyFileName, logger); - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - async function phase2contribute(zkeyNameOld, zkeyNameNew, name, entropy, logger) { - - const {fd: fdOld, sections: sections} = await readBinFile$1(zkeyNameOld, "zkey", 2); - const zkey = await readHeader$1(fdOld, sections); - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - const curve = await getCurveFromQ(zkey.q); - - const mpcParams = await readMPCParams(fdOld, curve, sections); - - const fdNew = await createBinFile(zkeyNameNew, "zkey", 1, 10); - - - const rng = await getRandomRng(entropy); - - const transcriptHasher = blake2b.create({ dkLen: 64 }); - transcriptHasher.update(mpcParams.csHash); - for (let i=0; i. - */ - - - - async function beacon(zkeyNameOld, zkeyNameNew, name, beaconHashStr, numIterationsExp, logger) { - const beaconHash = hex2ByteArray(beaconHashStr); - if ( (beaconHash.byteLength == 0) - || (beaconHash.byteLength*2 !=beaconHashStr.length)) - { - if (logger) logger.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"); - return false; - } - if (beaconHash.length>=256) { - if (logger) logger.error("Maximum length of beacon hash is 255 bytes"); - return false; - } - - numIterationsExp = parseInt(numIterationsExp); - if ((numIterationsExp<10)||(numIterationsExp>63)) { - if (logger) logger.error("Invalid numIterationsExp. (Must be between 10 and 63)"); - return false; - } - - - const {fd: fdOld, sections: sections} = await readBinFile$1(zkeyNameOld, "zkey", 2); - const zkey = await readHeader$1(fdOld, sections); - - if (zkey.protocol != "groth16") { - throw new Error("zkey file is not groth16"); - } - - - const curve = await getCurveFromQ(zkey.q); - - const mpcParams = await readMPCParams(fdOld, curve, sections); - - const fdNew = await createBinFile(zkeyNameNew, "zkey", 1, 10); - - const rng = await rngFromBeaconParams(beaconHash, numIterationsExp); - - const transcriptHasher = blake2b.create({ dkLen: 64 }); transcriptHasher.update(mpcParams.csHash); - for (let i=0; i. - */ - - - async function bellmanContribute(curve, challengeFilename, responseFileName, entropy, logger) { - const rng = await getRandomRng(entropy); - - const delta = curve.Fr.fromRng(rng); - const invDelta = curve.Fr.inv(delta); - - const sG1 = curve.G1.F.n8*2; - const sG2 = curve.G2.F.n8*2; - - const fdFrom = await readExisting$3(challengeFilename); - const fdTo = await createOverride(responseFileName); - - - await copy(sG1); // alpha1 - await copy(sG1); // beta1 - await copy(sG2); // beta2 - await copy(sG2); // gamma2 - const oldDelta1 = await readG1(); - const delta1 = curve.G1.timesFr(oldDelta1, delta); - await writeG1(delta1); - const oldDelta2 = await readG2(); - const delta2 = curve.G2.timesFr(oldDelta2, delta); - await writeG2(delta2); - - // IC - const nIC = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nIC); - await copy(nIC*sG1); - - // H - const nH = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nH); - await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nH, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "H", logger); - - // L - const nL = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nL); - await applyKeyToChallengeSection(fdFrom, fdTo, null, curve, "G1", nL, invDelta, curve.Fr.e(1), "UNCOMPRESSED", "L", logger); - - // A - const nA = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nA); - await copy(nA*sG1); - - // B1 - const nB1 = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nB1); - await copy(nB1*sG1); - - // B2 - const nB2 = await fdFrom.readUBE32(); - await fdTo.writeUBE32(nB2); - await copy(nB2*sG2); - - - ////////// - /// Read contributions - ////////// - const transcriptHasher = blake2b.create({ dkLen: 64 }); - const mpcParams = {}; - // csHash - mpcParams.csHash = await fdFrom.read(64); - transcriptHasher.update(mpcParams.csHash); - - const nContributions = await fdFrom.readUBE32(); - mpcParams.contributions = []; - for (let i=0; i. - */ - - - const {stringifyBigInts: stringifyBigInts$3} = utils; - - async function zkeyExportVerificationKey(zkeyName, logger) { - if (logger) logger.info("EXPORT VERIFICATION KEY STARTED"); - - const {fd, sections} = await readBinFile$1(zkeyName, "zkey", 2); - const zkey = await readHeader$1(fd, sections); - - if (logger) logger.info("> Detected protocol: " + zkey.protocol); - - let res; - if (zkey.protocol === "groth16") { - res = await groth16Vk(zkey, fd, sections); - } else if (zkey.protocol === "plonk") { - res = await plonkVk(zkey); - } else if (zkey.protocolId && zkey.protocolId === FFLONK_PROTOCOL_ID) { - res = await exportFFlonkVk(zkey); - } else { - throw new Error("zkey file protocol unrecognized"); - } - - await fd.close(); - - if (logger) logger.info("EXPORT VERIFICATION KEY FINISHED"); - - return res; - } - - - async function groth16Vk(zkey, fd, sections) { - const curve = await getCurveFromQ(zkey.q); - const sG1 = curve.G1.F.n8 * 2; - - const alphaBeta = await curve.pairing(zkey.vk_alpha_1, zkey.vk_beta_2); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - - vk_alpha_1: curve.G1.toObject(zkey.vk_alpha_1), - - vk_beta_2: curve.G2.toObject(zkey.vk_beta_2), - vk_gamma_2: curve.G2.toObject(zkey.vk_gamma_2), - vk_delta_2: curve.G2.toObject(zkey.vk_delta_2), - - vk_alphabeta_12: curve.Gt.toObject(alphaBeta) - }; - - // Read IC Section - /////////// - await startReadUniqueSection$1(fd, sections, 3); - vKey.IC = []; - for (let i = 0; i <= zkey.nPublic; i++) { - const buff = await fd.read(sG1); - const P = curve.G1.toObject(buff); - vKey.IC.push(P); - } - await endReadSection$1(fd); - - vKey = stringifyBigInts$3(vKey); - - return vKey; - } - - - async function plonkVk(zkey) { - const curve = await getCurveFromQ(zkey.q); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - power: zkey.power, - - k1: curve.Fr.toObject(zkey.k1), - k2: curve.Fr.toObject(zkey.k2), - - Qm: curve.G1.toObject(zkey.Qm), - Ql: curve.G1.toObject(zkey.Ql), - Qr: curve.G1.toObject(zkey.Qr), - Qo: curve.G1.toObject(zkey.Qo), - Qc: curve.G1.toObject(zkey.Qc), - S1: curve.G1.toObject(zkey.S1), - S2: curve.G1.toObject(zkey.S2), - S3: curve.G1.toObject(zkey.S3), - - X_2: curve.G2.toObject(zkey.X_2), - - w: curve.Fr.toObject(curve.Fr.w[zkey.power]) - }; - - vKey = stringifyBigInts$3(vKey); - - return vKey; - } - - async function exportFFlonkVk(zkey, logger) { - const curve = await getCurveFromQ(zkey.q); - - let vKey = { - protocol: zkey.protocol, - curve: curve.name, - nPublic: zkey.nPublic, - power: zkey.power, - - k1: curve.Fr.toObject(zkey.k1), - k2: curve.Fr.toObject(zkey.k2), - - w: curve.Fr.toObject(curve.Fr.w[zkey.power]), - //wW: curve.Fr.toObject(curve.Fr.w[zkey.power + 1]), - w3: curve.Fr.toObject(zkey.w3), - w4: curve.Fr.toObject(zkey.w4), - w8: curve.Fr.toObject(zkey.w8), - wr: curve.Fr.toObject(zkey.wr), - - X_2: curve.G2.toObject(zkey.X_2), - - C0: curve.G1.toObject(zkey.C0), - }; - - return stringifyBigInts$3(vKey); - } - - /* - Copyright 2021 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - const {unstringifyBigInts: unstringifyBigInts$6, stringifyBigInts: stringifyBigInts$2} = utils; - - async function fflonkExportSolidityVerifier(vk, templates, logger) { - if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER STARTED"); - - const curve = await getCurveFromName(vk.curve); - - // Precompute w3_2, w4_2 and w4_3 - let w3 = fromVkey(vk.w3); - vk.w3_2 = toVkey(curve.Fr.square(w3)); - - let w4 = fromVkey(vk.w4); - vk.w4_2 = toVkey(curve.Fr.square(w4)); - vk.w4_3 = toVkey(curve.Fr.mul(curve.Fr.square(w4), w4)); - - let w8 = fromVkey(vk.w8); - let acc = curve.Fr.one; - - for (let i = 1; i < 8; i++) { - acc = curve.Fr.mul(acc, w8); - vk["w8_" + i] = toVkey(acc); - } - - let template = templates[vk.protocol]; - - if (logger) logger.info("FFLONK EXPORT SOLIDITY VERIFIER FINISHED"); - - const {default: ejs} = await Promise.resolve().then(function () { return _virtual_ejs$1; }); - return ejs.render(template, vk); - - function fromVkey(str) { - const val = unstringifyBigInts$6(str); - return curve.Fr.fromObject(val); - } - - function toVkey(val) { - const str = curve.Fr.toObject(val); - return stringifyBigInts$2(str); - } - } - - // Not ready yet - // module.exports.generateVerifier_kimleeoh = generateVerifier_kimleeoh; - - async function exportSolidityVerifier(zKeyName, templates, logger) { - - const verificationKey = await zkeyExportVerificationKey(zKeyName, logger); - - if ("fflonk" === verificationKey.protocol) { - return fflonkExportSolidityVerifier(verificationKey, templates, logger); - } - - let template = templates[verificationKey.protocol]; - - const {default: ejs} = await Promise.resolve().then(function () { return _virtual_ejs$1; }); - - return ejs.render(template, verificationKey); - } - - /* - Copyright 2018 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - var zkey = /*#__PURE__*/Object.freeze({ - __proto__: null, - beacon: beacon, - bellmanContribute: bellmanContribute, - contribute: phase2contribute, - exportBellman: phase2exportMPCParams, - exportJson: zkeyExportJson, - exportSolidityVerifier: exportSolidityVerifier, - exportVerificationKey: zkeyExportVerificationKey, - importBellman: phase2importMPCParams, - newZKey: newZKey, - verifyFromInit: phase2verifyFromInit, - verifyFromR1cs: phase2verifyFromR1cs - }); - - /* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - - - async function plonkSetup(r1csName, ptauName, zkeyName, logger) { - - if (globalThis.gc) {globalThis.gc();} - - const {fd: fdPTau, sections: sectionsPTau} = await readBinFile$1(ptauName, "ptau", 1, 1<<22, 1<<24); - const {curve, power} = await readPTauHeader(fdPTau, sectionsPTau); - const {fd: fdR1cs, sections: sectionsR1cs} = await readBinFile$1(r1csName, "r1cs", 1, 1<<22, 1<<24); - - const r1cs = await readR1csFd(fdR1cs, sectionsR1cs, {loadConstraints: true, loadCustomGates: true}); - - const sG1 = curve.G1.F.n8*2; - const G1 = curve.G1; - const sG2 = curve.G2.F.n8*2; - const Fr = curve.Fr; - const n8r = curve.Fr.n8; - - if (logger) logger.info("Reading r1cs"); - - const plonkConstraints = new BigArray(); - const plonkAdditions = new BigArray(); - let plonkNVars = r1cs.nVars; - - const nPublic = r1cs.nOutputs + r1cs.nPubInputs; - - await processConstraints(curve.Fr, r1cs, logger); - - if (globalThis.gc) {globalThis.gc();} - - const fdZKey = await createBinFile(zkeyName, "zkey", 1, 14, 1<<22, 1<<24); - - - if (r1cs.prime != curve.r) { - if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve"); - return -1; - } - - let cirPower = log2(plonkConstraints.length -1) +1; - if (cirPower < 3) cirPower = 3; // As the t polynomial is n+5 we need at least a power of 4 - const domainSize = 2 ** cirPower; - - if (logger) logger.info("Plonk constraints: " + plonkConstraints.length); - if (cirPower > power) { - if (logger) logger.error(`circuit too big for this power of tau ceremony. ${plonkConstraints.length} > 2**${power}`); - return -1; - } - - if (!sectionsPTau[12]) { - if (logger) logger.error("Powers of tau is not prepared."); - return -1; - } - - - const LPoints = new BigBuffer(domainSize*sG1); - const o = sectionsPTau[12][0].p + ((2 ** (cirPower)) -1)*sG1; - await fdPTau.readToBuffer(LPoints, 0, domainSize*sG1, o); - - const [k1, k2] = getK1K2(); - - const vk = {}; - - - await writeAdditions(3, "Additions"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(4, 0, "Amap"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(5, 1, "Bmap"); - if (globalThis.gc) {globalThis.gc();} - await writeWitnessMap(6, 2, "Cmap"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(7, 3, "Qm"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(8, 4, "Ql"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(9, 5, "Qr"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(10, 6, "Qo"); - if (globalThis.gc) {globalThis.gc();} - await writeQMap(11, 7, "Qc"); - if (globalThis.gc) {globalThis.gc();} - await writeSigma(12, "sigma"); - if (globalThis.gc) {globalThis.gc();} - await writeLs(13, "lagrange polynomials"); - if (globalThis.gc) {globalThis.gc();} - - // Write PTau points - //////////// - - await startWriteSection(fdZKey, 14); - const buffOut = new BigBuffer((domainSize+6)*sG1); - await fdPTau.readToBuffer(buffOut, 0, (domainSize+6)*sG1, sectionsPTau[2][0].p); - await fdZKey.write(buffOut); - await endWriteSection(fdZKey); - if (globalThis.gc) {globalThis.gc();} - - - await writeHeaders(); - - await fdZKey.close(); - await fdR1cs.close(); - await fdPTau.close(); - - if (logger) logger.info("Setup Finished"); - - return ; - - async function processConstraints(Fr, r1cs, logger) { - - function normalize(linearComb) { - const ss = Object.keys(linearComb); - for (let i = 0; i < ss.length; i++) { - if (linearComb[ss[i]] == 0n) delete linearComb[ss[i]]; - } - } - - function join(linearComb1, k, linearComb2) { - const res = {}; - - for (let s in linearComb1) { - if (typeof res[s] == "undefined") { - res[s] = Fr.mul(k, linearComb1[s]); - } else { - res[s] = Fr.add(res[s], Fr.mul(k, linearComb1[s])); - } - } - - for (let s in linearComb2) { - if (typeof res[s] == "undefined") { - res[s] = linearComb2[s]; - } else { - res[s] = Fr.add(res[s], linearComb2[s]); - } - } - normalize(res); - return res; - } - - function reduceCoefs(linearComb, maxC) { - const res = { - k: Fr.zero, - s: [], - coefs: [] - }; - const cs = []; - - for (let s in linearComb) { - if (s == 0) { - res.k = Fr.add(res.k, linearComb[s]); - } else if (linearComb[s] != 0n) { - cs.push([Number(s), linearComb[s]]); - } - } - while (cs.length > maxC) { - const c1 = cs.shift(); - const c2 = cs.shift(); - - const sl = c1[0]; - const sr = c2[0]; - const so = plonkNVars++; - const qm = Fr.zero; - const ql = Fr.neg(c1[1]); - const qr = Fr.neg(c2[1]); - const qo = Fr.one; - const qc = Fr.zero; - - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - - plonkAdditions.push([sl, sr, c1[1], c2[1]]); - - cs.push([so, Fr.one]); - } - for (let i = 0; i < cs.length; i++) { - res.s[i] = cs[i][0]; - res.coefs[i] = cs[i][1]; - } - while (res.coefs.length < maxC) { - res.s.push(0); - res.coefs.push(Fr.zero); - } - return res; - } - - function addConstraintSum(lc) { - const C = reduceCoefs(lc, 3); - const sl = C.s[0]; - const sr = C.s[1]; - const so = C.s[2]; - const qm = Fr.zero; - const ql = C.coefs[0]; - const qr = C.coefs[1]; - const qo = C.coefs[2]; - const qc = C.k; - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - function addConstraintMul(lcA, lcB, lcC) { - const A = reduceCoefs(lcA, 1); - const B = reduceCoefs(lcB, 1); - const C = reduceCoefs(lcC, 1); - - - const sl = A.s[0]; - const sr = B.s[0]; - const so = C.s[0]; - const qm = Fr.mul(A.coefs[0], B.coefs[0]); - const ql = Fr.mul(A.coefs[0], B.k); - const qr = Fr.mul(A.k, B.coefs[0]); - const qo = Fr.neg(C.coefs[0]); - const qc = Fr.sub(Fr.mul(A.k, B.k), C.k); - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - function getLinearCombinationType(lc) { - let k = Fr.zero; - let n = 0; - const ss = Object.keys(lc); - for (let i = 0; i < ss.length; i++) { - if (lc[ss[i]] == 0n) { - delete lc[ss[i]]; - } else if (ss[i] == 0) { - k = Fr.add(k, lc[ss[i]]); - } else { - n++; - } - } - if (n > 0) return n.toString(); - if (k != Fr.zero) return "k"; - return "0"; - } - - function process(lcA, lcB, lcC) { - const lctA = getLinearCombinationType(lcA); - const lctB = getLinearCombinationType(lcB); - if ((lctA === "0") || (lctB === "0")) { - normalize(lcC); - addConstraintSum(lcC); - } else if (lctA === "k") { - const lcCC = join(lcB, lcA[0], lcC); - addConstraintSum(lcCC); - } else if (lctB === "k") { - const lcCC = join(lcA, lcB[0], lcC); - addConstraintSum(lcCC); - } else { - addConstraintMul(lcA, lcB, lcC); - } - } - - for (let s = 1; s <= nPublic; s++) { - const sl = s; - const sr = 0; - const so = 0; - const qm = Fr.zero; - const ql = Fr.one; - const qr = Fr.zero; - const qo = Fr.zero; - const qc = Fr.zero; - - plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]); - } - - for (let c = 0; c < r1cs.constraints.length; c++) { - if ((logger) && (c % 10000 === 0)) logger.debug(`processing constraints: ${c}/${r1cs.nConstraints}`); - process(...r1cs.constraints[c]); - } - } - - async function writeWitnessMap(sectionNum, posConstraint, name) { - await startWriteSection(fdZKey, sectionNum); - for (let i=0; i. - */ - - class Proof { - constructor(curve, logger) { - this.curve = curve; - this.logger = logger; - - this.resetProof(); - } - - resetProof() { - this.polynomials = {}; - this.evaluations = {}; - } - - addPolynomial(key, polynomial) { - if (key in this.polynomials) { - this.logger.warn(`proof: polynomial.${key} already exist in proof`); - } - this.polynomials[key] = polynomial; - } - - getPolynomial(key) { - if (!(key in this.polynomials)) { - this.logger.warn(`proof: polynomial ${key} does not exist in proof`); - } - return this.polynomials[key]; - } - - addEvaluation(key, evaluation) { - if (key in this.evaluations) { - this.logger.warn(`proof: evaluations.${key} already exist in proof`); - } - this.evaluations[key] = evaluation; - } - - getEvaluation(key) { - if (!(key in this.evaluations)) { - this.logger.warn(`proof: evaluation ${key} does not exist in proof`); - } - return this.evaluations[key]; - } - - toObjectProof(splitFields = true) { - let res = splitFields ? {polynomials: {}, evaluations: {}} : {}; - - Object.keys(this.polynomials).forEach(key => { - const value = this.curve.G1.toObject(this.polynomials[key]); - if(splitFields) { - res.polynomials[key] = value; - } else { - res[key] = value; - } - }); - - Object.keys(this.evaluations).forEach(key => { - const value = this.curve.Fr.toObject(this.evaluations[key]); - if(splitFields) { - res.evaluations[key] = value; - } else { - res[key] = value; - } - }); - - return res; - } - - fromObjectProof(objectProof) { - this.resetProof(); - - Object.keys(objectProof.polynomials).forEach(key => { - this.polynomials[key] = this.curve.G1.fromObject(objectProof.polynomials[key]); - }); - - Object.keys(objectProof.evaluations).forEach(key => { - this.evaluations[key] = this.curve.Fr.fromObject(objectProof.evaluations[key]); - }); - } - } - - /** - * SHA3 (keccak) hash function, based on a new "Sponge function" design. - * Different from older hashes, the internal state is bigger than output size. - * - * Check out - * {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf | FIPS-202}, - * {@link https://keccak.team/keccak.html | Website}, and - * {@link https://crypto.stackexchange.com/q/15727 | the differences between - * SHA-3 and Keccak}. - * - * Check out `sha3-addons` module for cSHAKE, k12, and others. - * @module - */ - // No __PURE__ annotations in sha3 header: - // EVERYTHING is in fact used on every export. - // Various per round constants calculations - const _0n = BigInt(0); - const _1n = BigInt(1); - const _2n = BigInt(2); - const _7n = BigInt(7); - const _256n = BigInt(256); - // FIPS 202 Algorithm 5 rc(): when the outgoing bit is 1, the 8-bit LFSR xors - // taps 0, 4, 5, and 6, which compresses to the feedback mask `0x71`. - const _0x71n = BigInt(0x71); - const SHA3_PI = []; - const SHA3_ROTL = []; - const _SHA3_IOTA = []; // no pure annotation: var is always used - for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) { - // Pi - [x, y] = [y, (2 * x + 3 * y) % 5]; - SHA3_PI.push(2 * (5 * y + x)); - // Rotational - SHA3_ROTL.push((((round + 1) * (round + 2)) / 2) % 64); - // Iota - let t = _0n; - for (let j = 0; j < 7; j++) { - R = ((R << _1n) ^ ((R >> _7n) * _0x71n)) % _256n; - if (R & _2n) - t ^= _1n << ((_1n << BigInt(j)) - _1n); - } - _SHA3_IOTA.push(t); - } - const IOTAS = split(_SHA3_IOTA, true); - // `split(..., true)` keeps the local little-endian lane-word layout used by - // `state32`, so these `H` / `L` tables follow the file's first-word / - // second-word lane slots rather than `_u64.ts`'s usual high/low naming. - const SHA3_IOTA_H = IOTAS[0]; - const SHA3_IOTA_L = IOTAS[1]; - // Left rotation (without 0, 32, 64) - const rotlH = (h, l, s) => (s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s)); - const rotlL = (h, l, s) => (s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s)); - /** - * `keccakf1600` internal permutation, additionally allows adjusting the round count. - * @param s - 5x5 Keccak state encoded as 25 lanes split into 50 uint32 words - * in this file's local little-endian lane-word order - * @param rounds - number of rounds to execute - * @throws If `rounds` is outside the supported `1..24` range. {@link Error} - * @example - * Permute a Keccak state with the default 24 rounds. - * ```ts - * keccakP(new Uint32Array(50)); - * ``` - */ - function keccakP(s, rounds = 24) { - anumber(rounds, 'rounds'); - // This implementation precomputes only the standard Keccak-f[1600] 24-round Iota table. - if (rounds < 1 || rounds > 24) - throw new Error('"rounds" expected integer 1..24'); - const B = new Uint32Array(5 * 2); - // NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js) - for (let round = 24 - rounds; round < 24; round++) { - // Theta θ - for (let x = 0; x < 10; x++) - B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40]; - for (let x = 0; x < 10; x += 2) { - const idx1 = (x + 8) % 10; - const idx0 = (x + 2) % 10; - const B0 = B[idx0]; - const B1 = B[idx0 + 1]; - const Th = rotlH(B0, B1, 1) ^ B[idx1]; - const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1]; - for (let y = 0; y < 50; y += 10) { - s[x + y] ^= Th; - s[x + y + 1] ^= Tl; - } - } - // Rho (ρ) and Pi (π) - let curH = s[2]; - let curL = s[3]; - for (let t = 0; t < 24; t++) { - const shift = SHA3_ROTL[t]; - const Th = rotlH(curH, curL, shift); - const Tl = rotlL(curH, curL, shift); - const PI = SHA3_PI[t]; - curH = s[PI]; - curL = s[PI + 1]; - s[PI] = Th; - s[PI + 1] = Tl; - } - // Chi (χ) - // Same as: - // for (let x = 0; x < 10; x++) B[x] = s[y + x]; - // for (let x = 0; x < 10; x++) s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10]; - for (let y = 0; y < 50; y += 10) { - const b0 = s[y], b1 = s[y + 1], b2 = s[y + 2], b3 = s[y + 3]; - s[y] ^= ~s[y + 2] & s[y + 4]; - s[y + 1] ^= ~s[y + 3] & s[y + 5]; - s[y + 2] ^= ~s[y + 4] & s[y + 6]; - s[y + 3] ^= ~s[y + 5] & s[y + 7]; - s[y + 4] ^= ~s[y + 6] & s[y + 8]; - s[y + 5] ^= ~s[y + 7] & s[y + 9]; - s[y + 6] ^= ~s[y + 8] & b0; - s[y + 7] ^= ~s[y + 9] & b1; - s[y + 8] ^= ~b0 & b2; - s[y + 9] ^= ~b1 & b3; - } - // Iota (ι) - s[0] ^= SHA3_IOTA_H[round]; - s[1] ^= SHA3_IOTA_L[round]; - } - clean(B); - } - /** - * Keccak sponge function. - * @param blockLen - absorb/squeeze rate in bytes - * @param suffix - domain separation suffix byte - * @param outputLen - default digest length in bytes. This base sponge only - * requires a non-negative integer; wrappers that need positive output - * lengths must enforce that themselves. - * @param enableXOF - whether XOF output is allowed - * @param rounds - number of Keccak-f rounds - * @example - * Build a sponge state, absorb bytes, then finalize a digest. - * ```ts - * const hash = new Keccak(136, 0x06, 32); - * hash.update(new Uint8Array([1, 2, 3])); - * hash.digest(); - * ``` - */ - class Keccak { - state; - pos = 0; - posOut = 0; - finished = false; - state32; - destroyed = false; - blockLen; - suffix; - outputLen; - canXOF; - enableXOF = false; - rounds; - // NOTE: we accept arguments in bytes instead of bits here. - constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) { - this.blockLen = blockLen; - this.suffix = suffix; - this.outputLen = outputLen; - this.enableXOF = enableXOF; - this.canXOF = enableXOF; - this.rounds = rounds; - // Can be passed from user as dkLen - anumber(outputLen, 'outputLen'); - // 1600 = 5x5 matrix of 64bit. 1600 bits === 200 bytes - // 0 < blockLen < 200 - if (!(0 < blockLen && blockLen < 200)) - throw new Error('only keccak-f1600 function is supported'); - this.state = new Uint8Array(200); - this.state32 = u32(this.state); - } - clone() { - return this._cloneInto(); - } - keccak() { - swap32IfBE(this.state32); - keccakP(this.state32, this.rounds); - swap32IfBE(this.state32); - this.posOut = 0; - this.pos = 0; - } - update(data) { - aexists(this); - abytes(data); - const { blockLen, state } = this; - const len = data.length; - for (let pos = 0; pos < len;) { - const take = Math.min(blockLen - this.pos, len - pos); - for (let i = 0; i < take; i++) - state[this.pos++] ^= data[pos++]; - if (this.pos === blockLen) - this.keccak(); - } - return this; - } - finish() { - if (this.finished) - return; - this.finished = true; - const { state, suffix, pos, blockLen } = this; - // FIPS 202 appends the SHA3/SHAKE domain-separation suffix before pad10*1. - // These byte values already include the first padding bit, while the - // final `0x80` below supplies the closing `1` bit in the last rate byte. - state[pos] ^= suffix; - // If that combined suffix lands in the last rate byte and already sets - // bit 7, absorb it first so the final pad10*1 bit can be xored into a - // fresh block. - if ((suffix & 0x80) !== 0 && pos === blockLen - 1) - this.keccak(); - state[blockLen - 1] ^= 0x80; - this.keccak(); - } - writeInto(out) { - aexists(this, false); - abytes(out); - this.finish(); - const bufferOut = this.state; - const { blockLen } = this; - for (let pos = 0, len = out.length; pos < len;) { - if (this.posOut >= blockLen) - this.keccak(); - const take = Math.min(blockLen - this.posOut, len - pos); - out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos); - this.posOut += take; - pos += take; - } - return out; - } - xofInto(out) { - // Plain SHA3/Keccak usage with XOF is probably a mistake, but this base - // class is also reused by SHAKE/cSHAKE/KMAC/TupleHash/ParallelHash/ - // TurboSHAKE/KangarooTwelve wrappers that intentionally enable XOF. - if (!this.enableXOF) - throw new Error('XOF is not possible for this instance'); - return this.writeInto(out); - } - xof(bytes) { - anumber(bytes); - return this.xofInto(new Uint8Array(bytes)); - } - digestInto(out) { - aoutput(out, this); - if (this.finished) - throw new Error('digest() was already called'); - // `aoutput(...)` allows oversized buffers; digestInto() must fill only the advertised digest. - this.writeInto(out.subarray(0, this.outputLen)); - this.destroy(); - } - digest() { - const out = new Uint8Array(this.outputLen); - this.digestInto(out); - return out; - } - destroy() { - this.destroyed = true; - clean(this.state); - } - _cloneInto(to) { - const { blockLen, suffix, outputLen, rounds, enableXOF } = this; - to ||= new Keccak(blockLen, suffix, outputLen, enableXOF, rounds); - // Reused destinations can come from a different rate/capacity variant, so clone must rewrite - // the sponge geometry as well as the state words. - to.blockLen = blockLen; - to.state32.set(this.state32); - to.pos = this.pos; - to.posOut = this.posOut; - to.finished = this.finished; - to.rounds = rounds; - // Suffix can change in cSHAKE - to.suffix = suffix; - to.outputLen = outputLen; - to.enableXOF = enableXOF; - // Clones must preserve the public capability bit too; `_KMAC` reuses this path and deep clone - // tests compare instance fields directly, so leaving `canXOF` behind makes the clone lie. - to.canXOF = this.canXOF; - to.destroyed = this.destroyed; - return to; - } - } - const genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info); - /** - * Keccak-256 hash function. Different from SHA3-256. - * @param msg - message bytes to hash - * @returns Digest bytes. - * @example - * Hash a message with Keccak-256. - * ```ts - * keccak_256(new Uint8Array([97, 98, 99])); - * ``` - */ - const keccak_256 = /* @__PURE__ */ genKeccak(0x01, 136, 32); - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - - const POLYNOMIAL = 0; - const SCALAR = 1; - - class Keccak256Transcript { - constructor(curve) { - this.G1 = curve.G1; - this.Fr = curve.Fr; - - this.reset(); - } - - reset() { - this.data = []; - } - - addPolCommitment(polynomialCommitment) { - this.data.push({type: POLYNOMIAL, data: polynomialCommitment}); - } - - addScalar(scalar) { - this.data.push({type: SCALAR, data: scalar}); - } - - getChallenge() { - if(0 === this.data.length) { - throw new Error("Keccak256Transcript: No data to generate a transcript"); - } - - let nPolynomials = 0; - let nScalars = 0; - - this.data.forEach(element => POLYNOMIAL === element.type ? nPolynomials++ : nScalars++); - - let buffer = new Uint8Array(nScalars * this.Fr.n8 + nPolynomials * this.G1.F.n8 * 2); - let offset = 0; - - for (let i = 0; i < this.data.length; i++) { - if (POLYNOMIAL === this.data[i].type) { - this.G1.toRprUncompressed(buffer, offset, this.data[i].data); - offset += this.G1.F.n8 * 2; - } else { - this.Fr.toRprBE(buffer, offset, this.data[i].data); - offset += this.Fr.n8; - } - } - - const value = Scalar.fromRprBE(keccak_256(buffer)); - return this.Fr.e(value); - } - } - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - class MulZ { - static getZ1(Fr) { - return [ - Fr.zero, - Fr.add(Fr.e(-1), Fr.w[2]), - Fr.e(-2), - Fr.sub(Fr.e(-1), Fr.w[2]), - ]; - } - - static getZ2(Fr) { - return [ - Fr.zero, - Fr.add(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), - Fr.e(4), - Fr.sub(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])), - ]; - } - - static getZ3(Fr) { - return [ - Fr.zero, - Fr.add(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), - Fr.e(-8), - Fr.sub(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])), - ]; - - } - - static mul2(a, b, ap, bp, p, Fr) { - const Z1 = this.getZ1(Fr); - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - r = a_b; - - let a0 = Fr.add(a_bp, ap_b); - - let a1 = ap_bp; - - rz = a0; - if (p) { - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - } - - return [r, rz]; - } - - static mul3(a, b, c, ap, bp, cp, p, Fr) { - const Z1 = this.getZ1(Fr); - const Z2 = this.getZ2(Fr); - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - r = Fr.mul(a_b, c); - - let a0 = Fr.mul(ap_b, c); - a0 = Fr.add(a0, Fr.mul(a_bp, c)); - a0 = Fr.add(a0, Fr.mul(a_b, cp)); - - let a1 = Fr.mul(ap_bp, c); - a1 = Fr.add(a1, Fr.mul(a_bp, cp)); - a1 = Fr.add(a1, Fr.mul(ap_b, cp)); - - rz = a0; - if (p) { - const a2 = Fr.mul(ap_bp, cp); - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - rz = Fr.add(rz, Fr.mul(Z2[p], a2)); - } - - return [r, rz]; - } - - static mul4(a, b, c, d, ap, bp, cp, dp, p, Fr) { - const Z1 = this.getZ1(Fr); - const Z2 = this.getZ2(Fr); - const Z3 = this.getZ3(Fr); - - let r, rz; - - const a_b = Fr.mul(a, b); - const a_bp = Fr.mul(a, bp); - const ap_b = Fr.mul(ap, b); - const ap_bp = Fr.mul(ap, bp); - - const c_d = Fr.mul(c, d); - const c_dp = Fr.mul(c, dp); - const cp_d = Fr.mul(cp, d); - const cp_dp = Fr.mul(cp, dp); - - r = Fr.mul(a_b, c_d); - - let a0 = Fr.mul(ap_b, c_d); - a0 = Fr.add(a0, Fr.mul(a_bp, c_d)); - a0 = Fr.add(a0, Fr.mul(a_b, cp_d)); - a0 = Fr.add(a0, Fr.mul(a_b, c_dp)); - - let a1 = Fr.mul(ap_bp, c_d); - a1 = Fr.add(a1, Fr.mul(ap_b, cp_d)); - a1 = Fr.add(a1, Fr.mul(ap_b, c_dp)); - a1 = Fr.add(a1, Fr.mul(a_bp, cp_d)); - a1 = Fr.add(a1, Fr.mul(a_bp, c_dp)); - a1 = Fr.add(a1, Fr.mul(a_b, cp_dp)); - - let a2 = Fr.mul(a_bp, cp_dp); - a2 = Fr.add(a2, Fr.mul(ap_b, cp_dp)); - a2 = Fr.add(a2, Fr.mul(ap_bp, c_dp)); - a2 = Fr.add(a2, Fr.mul(ap_bp, cp_d)); - - let a3 = Fr.mul(ap_bp, cp_dp); - - rz = a0; - if (p) { - rz = Fr.add(rz, Fr.mul(Z1[p], a1)); - rz = Fr.add(rz, Fr.mul(Z2[p], a2)); - rz = Fr.add(rz, Fr.mul(Z3[p], a3)); - } - - return [r, rz]; - } - } - - const ZKEY_PL_ADDITIONS_SECTION = 3; - const ZKEY_PL_A_MAP_SECTION = 4; - const ZKEY_PL_B_MAP_SECTION = 5; - const ZKEY_PL_C_MAP_SECTION = 6; - const ZKEY_PL_QM_SECTION = 7; - const ZKEY_PL_QL_SECTION = 8; - const ZKEY_PL_QR_SECTION = 9; - const ZKEY_PL_QO_SECTION = 10; - const ZKEY_PL_QC_SECTION = 11; - const ZKEY_PL_SIGMA_SECTION = 12; - const ZKEY_PL_LAGRANGE_SECTION = 13; - const ZKEY_PL_PTAU_SECTION = 14; - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - - class Polynomial { - constructor(coefficients, curve, logger) { - this.coef = coefficients; - this.curve = curve; - this.Fr = curve.Fr; - this.G1 = curve.G1; - this.logger = logger; - } - - static async fromEvaluations(buffer, curve, logger) { - let coefficients = await curve.Fr.ifft(buffer); - - return new Polynomial(coefficients, curve, logger); - } - - static fromCoefficientsArray(array, curve, logger) { - const Fr = curve.Fr; - let buff = array.length > 2 << 14 ? - new BigBuffer(array.length * Fr.n8) : new Uint8Array(array.length * Fr.n8); - for (let i = 0; i < array.length; i++) buff.set(array[i], i * Fr.n8); - - return new Polynomial(buff, curve, logger); - } - - static fromPolynomial(polynomial, curve, logger) { - let length = polynomial.length(); - let Fr = curve.Fr; - - let buff = length > 2 << 14 ? - new BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - buff.set(polynomial.coef.slice(), 0); - - return new Polynomial(buff, curve, logger); - } - - isEqual(polynomial) { - const degree = this.degree(); - if (degree !== polynomial.degree()) return false; - - for (let i = 0; i < degree + 1; i++) { - if (!this.Fr.eq(this.getCoef(i), polynomial.getCoef(i))) return false; - } - - return true; - } - - blindCoefficients(blindingFactors) { - blindingFactors = blindingFactors || []; - - const blindedCoefficients = (this.length() + blindingFactors.length) > 2 << 14 ? - new BigBuffer((this.length() + blindingFactors.length) * this.Fr.n8) : - new Uint8Array((this.length() + blindingFactors.length) * this.Fr.n8); - - blindedCoefficients.set(this.coef, 0); - for (let i = 0; i < blindingFactors.length; i++) { - blindedCoefficients.set( - this.Fr.add( - blindedCoefficients.slice((this.length() + i) * this.Fr.n8, (this.length() + i + 1) * this.Fr.n8), - blindingFactors[i] - ), - (this.length() + i) * this.Fr.n8 - ); - blindedCoefficients.set( - this.Fr.sub( - blindedCoefficients.slice(i * this.Fr.n8, (i + 1) * this.Fr.n8), - blindingFactors[i] - ), - i * this.Fr.n8 - ); - } - this.coef = blindedCoefficients; - } - - getCoef(index) { - const i_n8 = index * this.Fr.n8; - - if (i_n8 + this.Fr.n8 > this.coef.byteLength) return this.Fr.zero; - - return this.coef.slice(i_n8, i_n8 + this.Fr.n8); - } - - setCoef(index, value) { - if (index > (this.length() - 1)) { - throw new Error("Coef index is not available"); - } - - this.coef.set(value, index * this.Fr.n8); - } - - static async to4T(buffer, domainSize, blindingFactors, Fr) { - blindingFactors = blindingFactors || []; - let a = await Fr.ifft(buffer); - - const a4 = (domainSize * 4) > 2 << 14 ? - new BigBuffer(domainSize * 4 * Fr.n8) : new Uint8Array(domainSize * 4 * Fr.n8); - a4.set(a, 0); - - const A4 = await Fr.fft(a4); - - if (blindingFactors.length === 0) { - return [a, A4]; - } - - const a1 = domainSize + blindingFactors.length > 2 << 14 ? - new BigBuffer((domainSize + blindingFactors.length) * Fr.n8) : - new Uint8Array((domainSize + blindingFactors.length) * Fr.n8); - - a1.set(a, 0); - for (let i = 0; i < blindingFactors.length; i++) { - a1.set( - Fr.add( - a1.slice((domainSize + i) * Fr.n8, (domainSize + i + 1) * Fr.n8), - blindingFactors[i] - ), - (domainSize + i) * Fr.n8 - ); - a1.set( - Fr.sub( - a1.slice(i * Fr.n8, (i + 1) * Fr.n8), - blindingFactors[i] - ), - i * Fr.n8 - ); - } - - return [a1, A4]; - } - - length() { - let length = this.coef.byteLength / this.Fr.n8; - if (length !== Math.floor(this.coef.byteLength / this.Fr.n8)) { - throw new Error("Polynomial coefficients buffer has incorrect size"); - } - if (0 === length) { - if (this.logger) { - this.logger.warn("Polynomial has length zero"); - } - } - return length; - } - - degree() { - for (let i = this.length() - 1; i > 0; i--) { - const i_n8 = i * this.Fr.n8; - if (!this.Fr.eq(this.Fr.zero, this.coef.slice(i_n8, i_n8 + this.Fr.n8))) { - return i; - } - } - - return 0; - } - - evaluate(point) { - let res = this.Fr.zero; - - for (let i = this.degree() + 1; i > 0; i--) { - let i_n8 = i * this.Fr.n8; - const currentCoefficient = this.coef.slice(i_n8 - this.Fr.n8, i_n8); - res = this.Fr.add(currentCoefficient, this.Fr.mul(res, point)); - } - - return res; - } - - fastEvaluate(point) { - const Fr = this.Fr; - let nThreads = 3; - - let nCoefs = this.degree() + 1; - let coefsThread = parseInt(nCoefs / nThreads); - let residualCoefs = nCoefs - coefsThread * nThreads; - - let res = []; - let xN = []; - - xN[0] = Fr.one; - - for (let i = 0; i < nThreads; i++) { - res[i] = Fr.zero; - - let nCoefs = i === (nThreads - 1) ? coefsThread + residualCoefs : coefsThread; - for (let j = nCoefs; j > 0; j--) { - res[i] = Fr.add(this.getCoef((i * coefsThread) + j - 1), Fr.mul(res[i], point)); - - if (i === 0) xN[0] = Fr.mul(xN[0], point); - } - } - - for (let i = 1; i < nThreads; i++) { - res[0] = Fr.add(res[0], Fr.mul(xN[i - 1], res[i])); - xN[i] = Fr.mul(xN[i - 1], xN[0]); - } - - return res[0]; - } - - add(polynomial, blindingValue) { - let other = false; - - if (polynomial.length() > this.length()) { - other = true; - } - - const thisLength = this.length(); - const polyLength = polynomial.length(); - for (let i = 0; i < Math.max(thisLength, polyLength); i++) { - const i_n8 = i * this.Fr.n8; - - const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - - if (blindingValue !== undefined) { - b = this.Fr.mul(b, blindingValue); - } - if (other) { - polynomial.coef.set(this.Fr.add(a, b), i_n8); - } else { - this.coef.set(this.Fr.add(a, b), i_n8); - } - } - if (other) { - delete this.coef; - this.coef = polynomial.coef; - } - } - - sub(polynomial, blindingValue) { - let other = false; - - if (polynomial.length() > this.length()) { - other = true; - } - - const thisLength = this.length(); - const polyLength = polynomial.length(); - for (let i = 0; i < Math.max(thisLength, polyLength); i++) { - const i_n8 = i * this.Fr.n8; - - const a = i < thisLength ? this.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - let b = i < polyLength ? polynomial.coef.slice(i_n8, i_n8 + this.Fr.n8) : this.Fr.zero; - - if (blindingValue !== undefined) { - b = this.Fr.mul(b, blindingValue); - } - if (other) { - polynomial.coef.set(this.Fr.sub(a, b), i_n8); - } else { - this.coef.set(this.Fr.sub(a, b), i_n8); - } - } - if (other) { - delete this.coef; - this.coef = polynomial.coef; - } - } - - mulScalar(value) { - for (let i = 0; i < this.length(); i++) { - const i_n8 = i * this.Fr.n8; - - this.coef.set(this.Fr.mul(this.coef.slice(i_n8, i_n8 + this.Fr.n8), value), i_n8); - } - } - - addScalar(value) { - const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); - this.coef.set(this.Fr.add(currentValue, value), 0); - } - - subScalar(value) { - const currentValue = 0 === this.length() ? this.Fr.zero : this.coef.slice(0, this.Fr.n8); - this.coef.set(this.Fr.sub(currentValue, value), 0); - } - - // Multiply current polynomial by the polynomial (X - value) - byXSubValue(value) { - const Fr = this.Fr; - const resize = !Fr.eq(Fr.zero, this.getCoef(this.length() - 1)); - - const length = resize ? this.length() + 1 : this.length(); - const buff = length > 2 << 14 ? new BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - let pol = new Polynomial(buff, this.curve, this.logger); - - // Step 0: Set current coefficients to the new buffer shifted one position - pol.coef.set(this.coef.slice(0, (length - 1) * Fr.n8), 32); - - // Step 1: multiply each coefficient by (-value) - this.mulScalar(Fr.neg(value)); - - // Step 2: Add current polynomial to destination polynomial - pol.add(this); - - // Swap buffers - this.coef = pol.coef; - } - - // Multiply current polynomial by the polynomial (X^n + value) - byXNSubValue(n, value) { - const Fr = this.Fr; - const resize = !(this.length() - n - 1 >= this.degree()); - - const length = resize ? this.length() + n : this.length(); - const buff = length > 2 << 14 ? new BigBuffer(length * Fr.n8) : new Uint8Array(length * Fr.n8); - let pol = new Polynomial(buff, this.curve, this.logger); - - // Step 0: Set current coefficients to the new buffer shifted one position - pol.coef.set(this.coef.slice(0, (this.degree() + 1) * 32, ), n * 32); - - // Step 1: multiply each coefficient by (- value) - this.mulScalar(value); - - // Step 2: Add current polynomial to destination polynomial - pol.add(this); - - // Swap buffers - this.coef = pol.coef; - } - - // Euclidean division - divBy(polynomial) { - const Fr = this.Fr; - const degreeA = this.degree(); - const degreeB = polynomial.degree(); - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - for (let i = degreeA - degreeB; i >= 0; i--) { - this.setCoef(i, Fr.div(polR.getCoef(i + degreeB), polynomial.getCoef(degreeB))); - for (let j = 0; j <= degreeB; j++) { - polR.setCoef(i + j, Fr.sub(polR.getCoef(i + j), Fr.mul(this.getCoef(i), polynomial.getCoef(j)))); - } - } - - return polR; - } - - // Division by a Polynomial of the form (x^m - beta) - divByMonic(m, beta) { - const Fr = this.Fr; - - let d = this.degree(); - - let buffer = this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - let quotient = new Polynomial(buffer, this.curve, this.logger); - - let bArr = []; - - // Add the m leading coefficients of this to quotient - for (let i = 0; i < m; i++) { - quotient.setCoef((d - i) - m, this.getCoef(d - i)); - bArr[i] = this.getCoef(d - i); - } - - let nThreads = m; - for (let k = 0; k < nThreads; k++) { - for (let i = d - 2 * m - k; i >= 0; i = i - nThreads) { - if (i < 0) break; - let idx = k; - bArr[idx] = Fr.add(this.getCoef(i + m), Fr.mul(bArr[idx], beta)); - - quotient.setCoef(i, bArr[idx]); - } - } - - this.coef = quotient.coef; - } - - divByVanishing(n, beta) { - if (this.degree() < n) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - const Fr = this.Fr; - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - for (let i = this.length() - 1; i >= n; i--) { - let leadingCoef = polR.getCoef(i); - if (Fr.eq(Fr.zero, leadingCoef)) continue; - - polR.setCoef(i, Fr.zero); - polR.setCoef(i - n, Fr.add(polR.getCoef(i - n), Fr.mul(beta, leadingCoef))); - this.setCoef(i - n, Fr.add(this.getCoef(i - n), leadingCoef)); - } - - return polR; - } - - divByVanishing2(m, beta) { - if (this.degree() < m) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - const Fr = this.Fr; - - let polR = new Polynomial(this.coef, this.curve, this.logger); - - this.coef = this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8); - - let nThreads = 3; - let nTotal = this.length() - m; - let nElementsChunk = Math.floor(nTotal / nThreads); - let nElementsLast = nTotal - (nThreads - 1) * nElementsChunk; - - console.log(nTotal); - console.log(nElementsChunk + " " + nElementsLast); - for (let k = 0; k < nThreads; k++) { - console.log("> Thread " + k); - for (let i = (k === 0 ? nElementsLast : nElementsChunk); i > 0; i--) { - let idxDst = i - 1; - if (k !== 0) idxDst += (k - 1) * nElementsChunk + nElementsLast; - let idxSrc = idxDst + m; - - let leadingCoef = polR.getCoef(idxSrc); - if (Fr.eq(Fr.zero, leadingCoef)) continue; - - polR.setCoef(idxSrc, Fr.zero); - polR.setCoef(idxDst, Fr.add(polR.getCoef(idxDst), Fr.mul(beta, leadingCoef))); - this.setCoef(idxDst, Fr.add(this.getCoef(idxDst), leadingCoef)); - console.log(idxDst + " <-- " + idxSrc); - } - } - - this.print(); - return polR; - } - - fastDivByVanishing(data) { - const Fr = this.Fr; - - for (let i = 0; i < data.length; i++) { - - let m = data[i][0]; - let beta = data[i][1]; - - if (this.degree() < m) { - throw new Error("divByVanishing polynomial divisor must be of degree lower than the dividend polynomial"); - } - - let nThreads = 5; - let nElements = this.length() - m; - let nElementsBucket = Math.floor(nElements / nThreads / m); - let nElementsChunk = nElementsBucket * m; - let nElementsLast = nElements - nThreads * nElementsChunk; - - //In C++ implementation this buffer will be allocated only once outside the loop - let polTmp = new Polynomial(this.length() > 2 << 14 ? - new BigBuffer(this.length() * Fr.n8) : new Uint8Array(this.length() * Fr.n8), this.curve, this.logger); - - let ptr = this.coef; - this.coef = polTmp.coef; - polTmp.coef = ptr; - - // STEP 1: Setejar els m valors del següent bucket al chunk actual, PARALEL·LITZAR - for (let k = 0; k < nThreads; k++) { - let idx0 = (k + 1) * nElementsChunk + nElementsLast; - for (let i = 0; i < m; i++) { - this.setCoef(idx0 + i - m, polTmp.getCoef(idx0 + i)); - } - - for (let i = 0; i < nElementsChunk - m; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); - this.setCoef(offset - m, val); - } - } - - //STEP 2: Setejar els valors del elements last NO PARAL·LELITZAR - let idx0 = nElementsLast; - let pending = nElementsLast; - for (let i = 0; i < m && pending; i++) { - this.setCoef(idx0 - i - 1, polTmp.getCoef(idx0 + m - i - 1)); - pending--; - } - - for (let i = 0; i < pending; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(polTmp.getCoef(offset), Fr.mul(beta, this.getCoef(offset))); - this.setCoef(offset - m, val); - } - - //Step 3: calcular acumulats NO PARALEL·LITZAR - - let acc = []; - let betaPow = Fr.one; - for (let i = 0; i < nElementsBucket; i++) { - betaPow = Fr.mul(betaPow, beta); - } - let currentBeta = Fr.one; - - for (let k = nThreads; k > 0; k--) { - let idThread = k - 1; - let idx0 = idThread * nElementsChunk + nElementsLast; - acc[idThread] = []; - - for (let i = 0; i < m; i++) { - acc[idThread][i] = this.getCoef(idx0 + i); - - if (k !== nThreads) { - acc[idThread][i] = Fr.add(acc[idThread][i], Fr.mul(betaPow, acc[idThread + 1][i])); - } - } - currentBeta = Fr.mul(currentBeta, betaPow); - } - - //STEP 4 recalcular PARALEL·LITZAR - for (let k = 0; k < nThreads; k++) { - - let idx0 = k * nElementsChunk + nElementsLast; - let currentBeta = beta; //Quan hopassem a C++ i ho paralelitzem aquesta variable ha de ser privada - let currentM = m - 1; - - let limit = k === 0 ? nElementsLast : nElementsChunk; - for (let i = 0; i < limit; i++) { - let offset = idx0 - i - 1; - let val = Fr.add(this.getCoef(offset), Fr.mul(currentBeta, acc[k][currentM])); - - this.setCoef(offset, val); - - // To avoid modular operations in each loop... - if (currentM === 0) { - currentM = m - 1; - currentBeta = Fr.mul(currentBeta, beta); - } else { - currentM--; - } - } - } - } - } - - - // Divide polynomial by X - value - divByXSubValue(value) { - const coefs = this.length() > 2 << 14 ? - new BigBuffer(this.length() * this.Fr.n8) : new Uint8Array(this.length() * this.Fr.n8); - - coefs.set(this.Fr.zero, (this.length() - 1) * this.Fr.n8); - coefs.set(this.coef.slice((this.length() - 1) * this.Fr.n8, this.length() * this.Fr.n8), (this.length() - 2) * this.Fr.n8); - for (let i = this.length() - 3; i >= 0; i--) { - let i_n8 = i * this.Fr.n8; - coefs.set( - this.Fr.add( - this.coef.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8), - this.Fr.mul(value, coefs.slice(i_n8 + this.Fr.n8, i_n8 + 2 * this.Fr.n8)) - ), - i * this.Fr.n8 - ); - } - if (!this.Fr.eq( - this.coef.slice(0, this.Fr.n8), - this.Fr.mul(this.Fr.neg(value), coefs.slice(0, this.Fr.n8)) - )) { - throw new Error("Polynomial does not divide"); - } - - this.coef = coefs; - } - - divZh(domainSize, extensions = 4) { - for (let i = 0; i < domainSize; i++) { - const i_n8 = i * this.Fr.n8; - this.coef.set(this.Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)), i_n8); - } - - const upperBound = this.coef.byteLength / this.Fr.n8; - for (let i = domainSize; i < upperBound; i++) { - const i_n8 = i * this.Fr.n8; - - const a = this.Fr.sub( - this.coef.slice((i - domainSize) * this.Fr.n8, (i - domainSize) * this.Fr.n8 + this.Fr.n8), - this.coef.slice(i_n8, i_n8 + this.Fr.n8) - ); - this.coef.set(a, i_n8); - if (i > (domainSize * (extensions-1) - extensions)) { - if (!this.Fr.isZero(a)) { - throw new Error("Polynomial is not divisible"); - } - } - } - - return this; - } - - divByZerofier(n, beta) { - let Fr = this.Fr; - const invBeta = Fr.inv(beta); - const invBetaNeg = Fr.neg(invBeta); - - let isOne = Fr.eq(Fr.one, invBetaNeg); - let isNegOne = Fr.eq(Fr.negone, invBetaNeg); - - if (!isOne) { - for (let i = 0; i < n; i++) { - const i_n8 = i * this.Fr.n8; - let element; - - // If invBetaNeg === -1 we'll save a multiplication changing it by a neg function call - if (isNegOne) { - element = Fr.neg(this.coef.slice(i_n8, i_n8 + this.Fr.n8)); - } else { - element = Fr.mul(invBetaNeg, this.coef.slice(i_n8, i_n8 + this.Fr.n8)); - } - - this.coef.set(element, i_n8); - } - } - - isOne = Fr.eq(Fr.one, invBeta); - isNegOne = Fr.eq(Fr.negone, invBeta); - - for (let i = n; i < this.length(); i++) { - const i_n8 = i * this.Fr.n8; - const i_prev_n8 = (i - n) * this.Fr.n8; - - let element = this.Fr.sub( - this.coef.slice(i_prev_n8, i_prev_n8 + this.Fr.n8), - this.coef.slice(i_n8, i_n8 + this.Fr.n8) - ); - - // If invBeta === 1 we'll not do anything - if(!isOne) { - // If invBeta === -1 we'll save a multiplication changing it by a neg function call - if(isNegOne) { - element = Fr.neg(element); - } else { - element = Fr.mul(invBeta, element); - } - } - - this.coef.set(element, i_n8); - - // Check if polynomial is divisible by checking if n high coefficients are zero - if (i > this.length() - n - 1) { - if (!this.Fr.isZero(element)) { - throw new Error("Polynomial is not divisible"); - } - } - } - - return this; - } - - // function divideByVanishing(f, n, p) { - // // polynomial division f(X) / (X^n - 1) with remainder - // // very cheap, 0 multiplications - // // strategy: - // // start with q(X) = 0, r(X) = f(X) - // // then start changing q, r while preserving the identity: - // // f(X) = q(X) * (X^n - 1) + r(X) - // // in every step, move highest-degree term of r into the product - // // => r eventually has degree < n and we're done - // let q = Array(f.length).fill(0n); - // let r = [...f]; - // for (let i = f.length - 1; i >= n; i--) { - // let leadingCoeff = r[i]; - // if (leadingCoeff === 0n) continue; - // r[i] = 0n; - // r[i - n] = mod(r[i - n] + leadingCoeff, p); - // q[i - n] = mod(q[i - n] + leadingCoeff, p); - // } - // return [q, r]; - // } - - byX() { - const coefs = (this.length() + 1) > 2 << 14 ? - new BigBuffer(this.coef.byteLength + this.Fr.n8) : new Uint8Array(this.coef.byteLength + this.Fr.n8); - coefs.set(this.Fr.zero, 0); - coefs.set(this.coef, this.Fr.n8); - - this.coef = coefs; - } - - // Compute a new polynomial f(x^n) from f(x) - // f(x) = a_0 + a_1·x + a_2·x^2 + ... + a_j·x^j - // f(x^n) = a_0 + a_1·x^n + a_2·x^2n + ... + a_j·x^jn - static - async expX(polynomial, n, truncate = false) { - const Fr = polynomial.Fr; - - if (n < 1) { - // n == 0 not allowed because it has no sense, but if it's necessary we have to return - // a zero degree polynomial with a constant coefficient equals to the sum of all the original coefficients - throw new Error("Compute a new polynomial to a zero or negative number is not allowed"); - } else if (1 === n) { - return await Polynomial.fromEvaluations(polynomial.coef, polynomial.curve, polynomial.logger); - } - - // length is the length of non-constant coefficients - // if truncate === true, the highest zero coefficients (if exist) will be removed - const length = truncate ? polynomial.degree() : (polynomial.length() - 1); - const bufferDst = (length * n + 1) > 2 << 14 ? - new BigBuffer((length * n + 1) * Fr.n8) : new Uint8Array((length * n + 1) * Fr.n8); - - // Copy constant coefficient as is because is not related to x - bufferDst.set(polynomial.getCoef(0), 0); - - for (let i = 1; i <= length; i++) { - const i_sFr = i * Fr.n8; - - const coef = polynomial.getCoef(i); - bufferDst.set(coef, i_sFr * n); - } - - return new Polynomial(bufferDst, polynomial.curve, polynomial.logger); - } - - split(numPols, degPols, blindingFactors) { - if (numPols < 1) { - throw new Error(`Polynomials can't be split in ${numPols} parts`); - } else if (1 === numPols) { - return [this]; - } - - //blinding factors can be void or must have a length of numPols - 1 - if (0 !== blindingFactors.length && blindingFactors.length < numPols - 1) { - throw new Error(`Blinding factors length must be ${numPols - 1}`); - } - - const chunkByteLength = (degPols + 1) * this.Fr.n8; - let res = []; - - // Check polynomial can be split in numChunks parts of chunkSize bytes... - const numRealPols = Math.ceil((this.degree() + 1) * this.Fr.n8 / chunkByteLength); - if (numRealPols < numPols) { - //throw new Error(`Polynomial is short to be split in ${numPols} parts of ${degPols} coefficients each.`); - for (let i = numRealPols; i < numPols; i++) { - res[i] = new Polynomial(new Uint8Array(this.Fr.n8), this.curve, this.logger); - } - } - - numPols = Math.min(numPols, numRealPols); - for (let i = 0; i < numPols; i++) { - const isLast = (numPols - 1) === i; - const byteLength = isLast ? this.coef.byteLength - ((numPols - 1) * chunkByteLength) : chunkByteLength + this.Fr.n8; - - let buff = (byteLength / this.Fr.n8) > 2 << 14 ? new BigBuffer(byteLength) : new Uint8Array(byteLength); - res[i] = new Polynomial(buff, this.curve, this.logger); - - const fr = i * chunkByteLength; - const to = isLast ? this.coef.byteLength : (i + 1) * chunkByteLength; - res[i].coef.set(this.coef.slice(fr, to), 0); - - // Add a blinding factor as higher degree - if (!isLast) { - res[i].coef.set(blindingFactors[i], chunkByteLength); - } - - // Sub blinding factor to the lowest degree - if (0 !== i) { - const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); - res[i].coef.set(lowestDegree, 0); - } - - if (isLast) { - res[i].truncate(); - } - } - - return res; - - // // compute t_low(X) - // let polTLow = new BigBuffer((chunkSize + 1) * n8r); - // polTLow.set(t.slice(0, zkey.domainSize * n8r), 0); - // // Add blinding scalar b_10 as a new coefficient n - // polTLow.set(ch.b[10], zkey.domainSize * n8r); - // - // // compute t_mid(X) - // let polTMid = new BigBuffer((zkey.domainSize + 1) * n8r); - // polTMid.set(t.slice(zkey.domainSize * n8r, zkey.domainSize * 2 * n8r), 0); - // // Subtract blinding scalar b_10 to the lowest coefficient of t_mid - // const lowestMid = Fr.sub(polTMid.slice(0, n8r), ch.b[10]); - // polTMid.set(lowestMid, 0); - // // Add blinding scalar b_11 as a new coefficient n - // polTMid.set(ch.b[11], zkey.domainSize * n8r); - // - // // compute t_high(X) - // let polTHigh = new BigBuffer((zkey.domainSize + 6) * n8r); - // polTHigh.set(t.slice(zkey.domainSize * 2 * n8r, (zkey.domainSize * 3 + 6) * n8r), 0); - // //Subtract blinding scalar b_11 to the lowest coefficient of t_high - // const lowestHigh = Fr.sub(polTHigh.slice(0, n8r), ch.b[11]); - // polTHigh.set(lowestHigh, 0); - // - // proof.T1 = await expTau(polTLow, "multiexp T1"); - // proof.T2 = await expTau(polTMid, "multiexp T2"); - // proof.T3 = await expTau(polTHigh, "multiexp T3"); - } - - // split2(degPols, blindingFactors) { - // let currentDegree = this.degree(); - // const numFilledPols = Math.ceil((currentDegree + 1) / (degPols + 1)); - // - // //blinding factors can be void or must have a length of numPols - 1 - // if (0 !== blindingFactors.length && blindingFactors.length < numFilledPols - 1) { - // throw new Error(`Blinding factors length must be ${numFilledPols - 1}`); - // } - // - // const chunkByteLength = (degPols + 1) * this.Fr.n8; - // - // // Check polynomial can be split in numChunks parts of chunkSize bytes... - // if (this.coef.byteLength / chunkByteLength <= numFilledPols - 1) { - // throw new Error(`Polynomial is short to be split in ${numFilledPols} parts of ${degPols} coefficients each.`); - // } - // - // let res = []; - // for (let i = 0; i < numFilledPols; i++) { - // const isLast = (numFilledPols - 1) === i; - // const byteLength = isLast ? (currentDegree + 1) * this.Fr.n8 - ((numFilledPols - 1) * chunkByteLength) : chunkByteLength + this.Fr.n8; - // - // res[i] = new Polynomial(new BigBuffer(byteLength), this.Fr, this.logger); - // const fr = i * chunkByteLength; - // const to = isLast ? (currentDegree + 1) * this.Fr.n8 : (i + 1) * chunkByteLength; - // res[i].coef.set(this.coef.slice(fr, to), 0); - // - // // Add a blinding factor as higher degree - // if (!isLast) { - // res[i].coef.set(blindingFactors[i], chunkByteLength); - // } - // - // // Sub blinding factor to the lowest degree - // if (0 !== i) { - // const lowestDegree = this.Fr.sub(res[i].coef.slice(0, this.Fr.n8), blindingFactors[i - 1]); - // res[i].coef.set(lowestDegree, 0); - // } - // } - // - // return res; - // } - - // merge(pols, overlap = true) { - // let length = 0; - // for (let i = 0; i < pols.length; i++) { - // length += pols[i].length(); - // } - // - // if (overlap) { - // length -= pols.length - 1; - // } - // - // let res = new Polynomial(new BigBuffer(length * this.Fr.n8)); - // for (let i = 0; i < pols.length; i++) { - // const byteLength = pols[i].coef.byteLength; - // if (0 === i) { - // res.coef.set(pols[i].coef, 0); - // } else { - // - // } - // } - // - // return res; - // } - - truncate() { - const deg = this.degree(); - if (deg + 1 < this.coef.byteLength / this.Fr.n8) { - const newCoefs = (deg + 1) > 2 << 14 ? - new BigBuffer((deg + 1) * this.Fr.n8) : new Uint8Array((deg + 1) * this.Fr.n8); - - newCoefs.set(this.coef.slice(0, (deg + 1) * this.Fr.n8), 0); - this.coef = newCoefs; - } - } - - static lagrangePolynomialInterpolation(xArr, yArr, curve) { - const Fr = curve.Fr; - let polynomial = computeLagrangePolynomial(0); - for (let i = 1; i < xArr.length; i++) { - polynomial.add(computeLagrangePolynomial(i)); - } - - return polynomial; - - function computeLagrangePolynomial(i) { - let polynomial; - - for (let j = 0; j < xArr.length; j++) { - if (j === i) continue; - - if (polynomial === undefined) { - let buff = (xArr.length) > 2 << 14 ? - new BigBuffer((xArr.length) * Fr.n8) : new Uint8Array((xArr.length) * Fr.n8); - polynomial = new Polynomial(buff, curve); - polynomial.setCoef(0, Fr.neg(xArr[j])); - polynomial.setCoef(1, Fr.one); - } else { - polynomial.byXSubValue(xArr[j]); - } - } - - let denominator = polynomial.evaluate(xArr[i]); - denominator = Fr.inv(denominator); - const mulFactor = Fr.mul(yArr[i], denominator); - - polynomial.mulScalar(mulFactor); - - return polynomial; - } - } - - static zerofierPolynomial(xArr, curve) { - const Fr = curve.Fr; - let buff = (xArr.length + 1) > 2 << 14 ? - new BigBuffer((xArr.length + 1) * Fr.n8) : new Uint8Array((xArr.length + 1) * Fr.n8); - let polynomial = new Polynomial(buff, curve); - - // Build a zerofier polynomial with the following form: - // zerofier(X) = (X-xArr[0])(X-xArr[1])...(X-xArr[n]) - polynomial.setCoef(0, Fr.neg(xArr[0])); - polynomial.setCoef(1, Fr.one); - - for (let i = 1; i < xArr.length; i++) { - polynomial.byXSubValue(xArr[i]); - } - - return polynomial; - } - - print() { - const Fr = this.Fr; - let res = ""; - for (let i = this.degree(); i >= 0; i--) { - const coef = this.getCoef(i); - if (!Fr.eq(Fr.zero, coef)) { - if (Fr.isNegative(coef)) { - res += " - "; - } else if (i !== this.degree()) { - res += " + "; - } - res += Fr.toString(coef); - if (i > 0) { - res += i > 1 ? "x^" + i : "x"; - } - } - } - console.log(res); - } - - async multiExponentiation(PTau, name) { - const n = this.coef.byteLength / this.Fr.n8; - const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); - const bm = await this.Fr.batchFromMontgomery(this.coef); - let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); - res = this.G1.toAffine(res); - return res; - } - } - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - - class Evaluations { - constructor(evaluations, curve, logger) { - this.eval = evaluations; - this.curve = curve; - this.Fr = curve.Fr; - this.logger = logger; - } - - static async fromPolynomial(polynomial, extension, curve, logger) { - const coefficientsN = new BigBuffer(polynomial.length() * extension * curve.Fr.n8); - coefficientsN.set(polynomial.coef, 0); - - const evaluations = await curve.Fr.fft(coefficientsN); - - return new Evaluations(evaluations, curve, logger); - } - - getEvaluation(index) { - const i_n8 = index * this.Fr.n8; - - if (i_n8 + this.Fr.n8 > this.eval.byteLength) { - throw new Error("Evaluations.getEvaluation() out of bounds"); - } - - return this.eval.slice(i_n8, i_n8 + this.Fr.n8); - } - - length() { - let length = this.eval.byteLength / this.Fr.n8; - if (length !== Math.floor(this.eval.byteLength / this.Fr.n8)) { - throw new Error("Polynomial evaluations buffer has incorrect size"); - } - if (0 === length) { - this.logger.warn("Polynomial has length zero"); - } - return length; - } - } - - /* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - const {stringifyBigInts: stringifyBigInts$1} = utils; - - async function plonk16Prove(zkeyFileName, witnessFileName, logger, options) { - const {fd: fdWtns, sections: sectionsWtns} = await readBinFile$1(witnessFileName, "wtns", 2, 1<<25, 1<<23); - - // Read witness file - if (logger) logger.debug("> Reading witness file"); - const wtns = await readHeader(fdWtns, sectionsWtns); - - // Read zkey file - if (logger) logger.debug("> Reading zkey file"); - const {fd: fdZKey, sections: zkeySections} = await readBinFile$1(zkeyFileName, "zkey", 2, 1<<25, 1<<23); - - const zkey = await readHeader$1(fdZKey, zkeySections, undefined, options); - if (zkey.protocol != "plonk") { - throw new Error("zkey file is not plonk"); - } - - if (!Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness != zkey.nVars -zkey.nAdditions) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); - } - - const curve = zkey.curve; - - const Fr = curve.Fr; - const n8r = curve.Fr.n8; - const sDomain = zkey.domainSize * n8r; - - if (logger) { - logger.debug("----------------------------"); - logger.debug(" PLONK PROVE SETTINGS"); - logger.debug(` Curve: ${curve.name}`); - logger.debug(` Circuit power: ${zkey.power}`); - logger.debug(` Domain size: ${zkey.domainSize}`); - logger.debug(` Vars: ${zkey.nVars}`); - logger.debug(` Public vars: ${zkey.nPublic}`); - logger.debug(` Constraints: ${zkey.nConstraints}`); - logger.debug(` Additions: ${zkey.nAdditions}`); - logger.debug("----------------------------"); - } - - //Read witness data - if (logger) logger.debug("> Reading witness file data"); - const buffWitness = await readSection$1(fdWtns, sectionsWtns, 2); - - // First element in plonk is not used and can be any value. (But always the same). - // We set it to zero to go faster in the exponentiations. - buffWitness.set(Fr.zero, 0); - const buffInternalWitness = new BigBuffer(n8r*zkey.nAdditions); - - let buffers = {}; - let polynomials = {}; - let evaluations = {}; - - let challenges = {}; - let proof = new Proof(curve, logger); - const transcript = new Keccak256Transcript(curve); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_ADDITIONS_SECTION}. Additions`); - await calculateAdditions(); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_SIGMA_SECTION}. Sigma1, Sigma2 & Sigma 3`); - if (logger) logger.debug("··· Reading Sigma polynomials "); - polynomials.Sigma1 = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.Sigma2 = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.Sigma3 = new Polynomial(new BigBuffer(sDomain), curve, logger); - - await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 5 * sDomain); - await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 10 * sDomain); - - if (logger) logger.debug("··· Reading Sigma evaluations"); - evaluations.Sigma1 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma2 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma3 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - - await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 6 * sDomain); - await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_SIGMA_SECTION][0].p + 11 * sDomain); - - if (logger) logger.debug(`> Reading Section ${ZKEY_PL_PTAU_SECTION}. Powers of Tau`); - const PTau = await readSection$1(fdZKey, zkeySections, ZKEY_PL_PTAU_SECTION); - - let publicSignals = []; - - for (let i=1; i<= zkey.nPublic; i++) { - const pub = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8); - publicSignals.push(Scalar.fromRprLE(pub)); - } - - if (logger) logger.debug(""); - if (logger) logger.debug("> ROUND 1"); - await round1(); - - if (logger) logger.debug("> ROUND 2"); - await round2(); - - if (logger) logger.debug("> ROUND 3"); - await round3(); - - if (logger) logger.debug("> ROUND 4"); - await round4(); - - if (logger) logger.debug("> ROUND 5"); - await round5(); - - /////////////////////// - // Final adjustments // - /////////////////////// - - await fdZKey.close(); - await fdWtns.close(); - - // Prepare proof - let _proof = proof.toObjectProof(false); - _proof.protocol = "plonk"; - _proof.curve = curve.name; - - if (logger) logger.debug("PLONK PROVER FINISHED"); - - return { - proof: stringifyBigInts$1(_proof), - publicSignals: stringifyBigInts$1(publicSignals) - }; - - async function calculateAdditions() { - if (logger) logger.debug("··· Computing additions"); - const additionsBuff = await readSection$1(fdZKey, zkeySections, ZKEY_PL_ADDITIONS_SECTION); - - // sizes: wireId_x = 4 bytes (32 bits), factor_x = field size bits - // Addition form: wireId_a wireId_b factor_a factor_b (size is 4 + 4 + sFr + sFr) - const sSum = 8 + n8r * 2; - - for (let i = 0; i < zkey.nAdditions; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.debug(` addition ${i}/${zkey.nAdditions}`); - - // Read addition values - let offset = i * sSum; - const signalId1 = readUInt32(additionsBuff, offset); - offset += 4; - const signalId2 = readUInt32(additionsBuff, offset); - offset += 4; - const factor1 = additionsBuff.slice(offset, offset + n8r); - offset += n8r; - const factor2 = additionsBuff.slice(offset, offset + n8r); - - // Get witness value - const witness1 = getWitness(signalId1); - const witness2 = getWitness(signalId2); - - //Calculate final result - const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); - - buffInternalWitness.set(result, n8r * i); - } - } - - function readUInt32(b, o) { - const buff = b.slice(o, o+4); - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - return buffV.getUint32(0, true); - } - - function getWitness(idx) { - if (idx < zkey.nVars-zkey.nAdditions) { - return buffWitness.slice(idx*n8r, idx*n8r+n8r); - } else if (idx < zkey.nVars) { - return buffInternalWitness.slice((idx - (zkey.nVars-zkey.nAdditions))*n8r, (idx-(zkey.nVars-zkey.nAdditions))*n8r + n8r); - } else { - return curve.Fr.zero; - } - } - - async function round1() { - // STEP 1.1 - Generate random blinding scalars (b1, ..., b11) ∈ F - challenges.b = []; - for (let i=1; i<=11; i++) { - challenges.b[i] = curve.Fr.random(); - } - - // STEP 1.2 - Compute wire polynomials a(X), b(X) and c(X) - if (logger) logger.debug("> Computing A, B, C wire polynomials"); - await computeWirePolynomials(); - - // STEP 1.3 - Compute [a]_1, [b]_1, [c]_1 - if (logger) logger.debug("> Computing A, B, C MSM"); - let commitA = await polynomials.A.multiExponentiation(PTau, "A"); - let commitB = await polynomials.B.multiExponentiation(PTau, "B"); - let commitC = await polynomials.C.multiExponentiation(PTau, "C"); - - // First output of the prover is ([A]_1, [B]_1, [C]_1) - proof.addPolynomial("A", commitA); - proof.addPolynomial("B", commitB); - proof.addPolynomial("C", commitC); - - return 0; - } - - async function computeWirePolynomials() { - if (logger) logger.debug("··· Reading data from zkey file"); - - // Build A, B and C evaluations buffer from zkey and witness files - buffers.A = new BigBuffer(sDomain); - buffers.B = new BigBuffer(sDomain); - buffers.C = new BigBuffer(sDomain); - - // Read zkey file to the buffers - const aMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_PL_A_MAP_SECTION); - const bMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_PL_B_MAP_SECTION); - const cMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_PL_C_MAP_SECTION); - - // Compute all witness from signal ids and set them to A,B & C buffers - for (let i = 0; i < zkey.nConstraints; i++) { - const i_sFr = i * n8r; - const offset = i * 4; - - // Compute A value from a signal id - const signalIdA = readUInt32(aMapBuff, offset); - buffers.A.set(getWitness(signalIdA), i_sFr); - - // Compute B value from a signal id - const signalIdB = readUInt32(bMapBuff, offset); - buffers.B.set(getWitness(signalIdB), i_sFr); - - // Compute C value from a signal id - const signalIdC = readUInt32(cMapBuff, offset); - buffers.C.set(getWitness(signalIdC), i_sFr); - } - - buffers.A = await Fr.batchToMontgomery(buffers.A); - buffers.B = await Fr.batchToMontgomery(buffers.B); - buffers.C = await Fr.batchToMontgomery(buffers.C); - - // Compute the coefficients of the wire polynomials a(X), b(X) and c(X) from A,B & C buffers - if (logger) logger.debug("··· Computing A ifft"); - polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); - if (logger) logger.debug("··· Computing B ifft"); - polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); - if (logger) logger.debug("··· Computing C ifft"); - polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); - - // Compute extended evaluations of a(X), b(X) and c(X) polynomials - if (logger) logger.debug("··· Computing A fft"); - evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); - if (logger) logger.debug("··· Computing B fft"); - evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); - if (logger) logger.debug("··· Computing C fft"); - evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); - - // Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b - polynomials.A.blindCoefficients([challenges.b[2], challenges.b[1]]); - polynomials.B.blindCoefficients([challenges.b[4], challenges.b[3]]); - polynomials.C.blindCoefficients([challenges.b[6], challenges.b[5]]); - - // Check degrees - if (polynomials.A.degree() >= zkey.domainSize + 2) { - throw new Error("A Polynomial is not well calculated"); - } - if (polynomials.B.degree() >= zkey.domainSize + 2) { - throw new Error("B Polynomial is not well calculated"); - } - if (polynomials.C.degree() >= zkey.domainSize + 2) { - throw new Error("C Polynomial is not well calculated"); - } - } - - async function round2() { - // STEP 2.1 - Compute permutation challenge beta and gamma ∈ F - // Compute permutation challenge beta - if (logger) logger.debug("> Computing challenges beta and gamma"); - transcript.reset(); - - transcript.addPolCommitment(zkey.Qm); - transcript.addPolCommitment(zkey.Ql); - transcript.addPolCommitment(zkey.Qr); - transcript.addPolCommitment(zkey.Qo); - transcript.addPolCommitment(zkey.Qc); - transcript.addPolCommitment(zkey.S1); - transcript.addPolCommitment(zkey.S2); - transcript.addPolCommitment(zkey.S3); - - // Add A to the transcript - for (let i = 0; i < zkey.nPublic; i++) { - transcript.addScalar(buffers.A.slice(i * n8r, i * n8r + n8r)); - } - - // Add A, B, C to the transcript - transcript.addPolCommitment(proof.getPolynomial("A")); - transcript.addPolCommitment(proof.getPolynomial("B")); - transcript.addPolCommitment(proof.getPolynomial("C")); - - challenges.beta = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.beta: " + Fr.toString(challenges.beta, 16)); - - // Compute permutation challenge gamma - transcript.reset(); - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.gamma: " + Fr.toString(challenges.gamma, 16)); - - // STEP 2.2 - Compute permutation polynomial z(X) - if (logger) logger.debug("> Computing Z polynomial"); - await computeZ(); - - // STEP 2.3 - Compute permutation [z]_1 - if (logger) logger.debug("> Computing Z MSM"); - let commitZ = await polynomials.Z.multiExponentiation(PTau, "Z"); - - // Second output of the prover is ([Z]_1) - proof.addPolynomial("Z", commitZ); - } - - async function computeZ() { - if (logger) logger.debug("··· Computing Z evaluations"); - - let numArr = new BigBuffer(sDomain); - let denArr = new BigBuffer(sDomain); - - // Set the first values to 1 - numArr.set(Fr.one, 0); - denArr.set(Fr.one, 0); - - // Set initial omega - let w = Fr.one; - for (let i = 0; i < zkey.domainSize; i++) { - const i_n8r = i * n8r; - - const a = buffers.A.slice(i_n8r, i_n8r + n8r); - const b = buffers.B.slice(i_n8r, i_n8r + n8r); - const c = buffers.C.slice(i_n8r, i_n8r + n8r); - - // Z(X) := numArr / denArr - // numArr := (a + beta·ω + gamma)(b + beta·ω·k1 + gamma)(c + beta·ω·k2 + gamma) - const betaw = Fr.mul(challenges.beta, w); - - let n1 = Fr.add(a, betaw); - n1 = Fr.add(n1, challenges.gamma); - - let n2 = Fr.add(b, Fr.mul(zkey.k1, betaw)); - n2 = Fr.add(n2, challenges.gamma); - - let n3 = Fr.add(c, Fr.mul(zkey.k2, betaw)); - n3 = Fr.add(n3, challenges.gamma); - - let num = Fr.mul(n1, Fr.mul(n2, n3)); - - // denArr := (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma) - let d1 = Fr.add(a, Fr.mul(evaluations.Sigma1.getEvaluation(i * 4), challenges.beta)); - d1 = Fr.add(d1, challenges.gamma); - - let d2 = Fr.add(b, Fr.mul(evaluations.Sigma2.getEvaluation(i * 4), challenges.beta)); - d2 = Fr.add(d2, challenges.gamma); - - let d3 = Fr.add(c, Fr.mul(evaluations.Sigma3.getEvaluation(i * 4), challenges.beta)); - d3 = Fr.add(d3, challenges.gamma); - - let den = Fr.mul(d1, Fr.mul(d2, d3)); - - // Multiply current num value with the previous one saved in numArr - num = Fr.mul(numArr.slice(i_n8r, i_n8r + n8r), num); - numArr.set(num, ((i + 1) % zkey.domainSize) * n8r); - - // Multiply current den value with the previous one saved in denArr - den = Fr.mul(denArr.slice(i_n8r, i_n8r + n8r), den); - denArr.set(den, ((i + 1) % zkey.domainSize) * n8r); - - w = Fr.mul(w, Fr.w[zkey.power]); - } - - // Compute the inverse of denArr to compute in the next command the - // division numArr/denArr by multiplying num · 1/denArr - denArr = await Fr.batchInverse(denArr); - - // TODO: Do it in assembly and in parallel - // Multiply numArr · denArr where denArr was inverted in the previous command - for (let i = 0; i < zkey.domainSize; i++) { - const i_sFr = i * n8r; - - const z = Fr.mul(numArr.slice(i_sFr, i_sFr + n8r), denArr.slice(i_sFr, i_sFr + n8r)); - numArr.set(z, i_sFr); - } - - // From now on the values saved on numArr will be Z(X) buffer - buffers.Z = numArr; - - if (!Fr.eq(numArr.slice(0, n8r), Fr.one)) { - throw new Error("Copy constraints does not match"); - } - - // Compute polynomial coefficients z(X) from buffers.Z - if (logger) logger.debug("··· Computing Z ifft"); - polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); - - // Compute extended evaluations of z(X) polynomial - if (logger) logger.debug("··· Computing Z fft"); - evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); - - // Blind z(X) polynomial coefficients with blinding scalars b - polynomials.Z.blindCoefficients([challenges.b[9], challenges.b[8], challenges.b[7]]); - - // Check degree - if (polynomials.Z.degree() >= zkey.domainSize + 3) { - throw new Error("Z Polynomial is not well calculated"); - } - - delete buffers.Z; - } - - async function round3() { - if (logger) logger.debug("> Computing challenge alpha"); - - // STEP 3.1 - Compute evaluation challenge alpha ∈ F - transcript.reset(); - transcript.addScalar(challenges.beta); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.getPolynomial("Z")); - - challenges.alpha = transcript.getChallenge(); - challenges.alpha2 = Fr.square(challenges.alpha); - if (logger) logger.debug("··· challenges.alpha: " + Fr.toString(challenges.alpha, 16)); - - // Compute quotient polynomial T(X) - if (logger) logger.debug("> Computing T polynomial"); - await computeT(); - - // Compute [T1]_1, [T2]_1, [T3]_1 - if (logger) logger.debug("> Computing T MSM"); - let commitT1 = await polynomials.T1.multiExponentiation(PTau, "T1"); - let commitT2 = await polynomials.T2.multiExponentiation(PTau, "T2"); - let commitT3 = await polynomials.T3.multiExponentiation(PTau, "T3"); - - // Third output of the prover is ([T1]_1, [T2]_1, [T3]_1) - proof.addPolynomial("T1", commitT1); - proof.addPolynomial("T2", commitT2); - proof.addPolynomial("T3", commitT3); - } - - async function computeT() { - if (logger) - logger.debug(`··· Reading sections ${ZKEY_PL_QL_SECTION}, ${ZKEY_PL_QR_SECTION}` + - `, ${ZKEY_PL_QM_SECTION}, ${ZKEY_PL_QO_SECTION}, ${ZKEY_PL_QC_SECTION}. Q selectors`); - // Reserve memory for Q's evaluations - evaluations.QL = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QR = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QM = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QO = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QC = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QL_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QR_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QM_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QO_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[ZKEY_PL_QC_SECTION][0].p + sDomain); - - // Read Lagrange polynomials & evaluations from zkey file - evaluations.Lagrange = new Evaluations(new BigBuffer(sDomain * 4 * zkey.nPublic), curve, logger); - - for (let i = 0; i < zkey.nPublic; i++) { - await fdZKey.readToBuffer(evaluations.Lagrange.eval, i * sDomain * 4, sDomain * 4, zkeySections[ZKEY_PL_LAGRANGE_SECTION][0].p + i * 5 * sDomain + sDomain); - } - - buffers.T = new BigBuffer(sDomain * 4); - buffers.Tz = new BigBuffer(sDomain * 4); - - if (logger) logger.debug("··· Computing T evaluations"); - - let w = Fr.one; - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) - logger.debug(` T evaluation ${i}/${zkey.domainSize * 4}`); - - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - const z = evaluations.Z.getEvaluation(i); - const zw = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); - - const qm = evaluations.QM.getEvaluation(i); - const ql = evaluations.QL.getEvaluation(i); - const qr = evaluations.QR.getEvaluation(i); - const qo = evaluations.QO.getEvaluation(i); - const qc = evaluations.QC.getEvaluation(i); - const s1 = evaluations.Sigma1.getEvaluation(i); - const s2 = evaluations.Sigma2.getEvaluation(i); - const s3 = evaluations.Sigma3.getEvaluation(i); - - const ap = Fr.add(challenges.b[2], Fr.mul(challenges.b[1], w)); - const bp = Fr.add(challenges.b[4], Fr.mul(challenges.b[3], w)); - const cp = Fr.add(challenges.b[6], Fr.mul(challenges.b[5], w)); - - const w2 = Fr.square(w); - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], w2), Fr.mul(challenges.b[8], w)), challenges.b[9]); - const wW = Fr.mul(w, Fr.w[zkey.power]); - const wW2 = Fr.square(wW); - const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], wW2), Fr.mul(challenges.b[8], wW)), challenges.b[9]); - - let pi = Fr.zero; - for (let j = 0; j < zkey.nPublic; j++) { - const offset = (j * 4 * zkey.domainSize) + i; - - const lPol = evaluations.Lagrange.getEvaluation(offset); - const aVal = buffers.A.slice(j * n8r, (j + 1) * n8r); - - pi = Fr.sub(pi, Fr.mul(lPol, aVal)); - } - - // e1 := a(X)b(X)qM(X) + a(X)qL(X) + b(X)qR(X) + c(X)qO(X) + PI(X) + qC(X) - let [e1, e1z] = MulZ.mul2(a, b, ap, bp, i % 4, Fr); - e1 = Fr.mul(e1, qm); - e1z = Fr.mul(e1z, qm); - - e1 = Fr.add(e1, Fr.mul(a, ql)); - e1z = Fr.add(e1z, Fr.mul(ap, ql)); - - e1 = Fr.add(e1, Fr.mul(b, qr)); - e1z = Fr.add(e1z, Fr.mul(bp, qr)); - - e1 = Fr.add(e1, Fr.mul(c, qo)); - e1z = Fr.add(e1z, Fr.mul(cp, qo)); - - e1 = Fr.add(e1, pi); - e1 = Fr.add(e1, qc); - - // e2 := α[(a(X) + βX + γ)(b(X) + βk1X + γ)(c(X) + βk2X + γ)z(X)] - const betaw = Fr.mul(challenges.beta, w); - let e2a = a; - e2a = Fr.add(e2a, betaw); - e2a = Fr.add(e2a, challenges.gamma); - - let e2b = b; - e2b = Fr.add(e2b, Fr.mul(betaw, zkey.k1)); - e2b = Fr.add(e2b, challenges.gamma); - - let e2c = c; - e2c = Fr.add(e2c, Fr.mul(betaw, zkey.k2)); - e2c = Fr.add(e2c, challenges.gamma); - - let e2d = z; - - let [e2, e2z] = MulZ.mul4(e2a, e2b, e2c, e2d, ap, bp, cp, zp, i % 4, Fr); - e2 = Fr.mul(e2, challenges.alpha); - e2z = Fr.mul(e2z, challenges.alpha); - - // e3 := α[(a(X) + βSσ1(X) + γ)(b(X) + βSσ2(X) + γ)(c(X) + βSσ3(X) + γ)z(Xω)] - let e3a = a; - e3a = Fr.add(e3a, Fr.mul(challenges.beta, s1)); - e3a = Fr.add(e3a, challenges.gamma); - - let e3b = b; - e3b = Fr.add(e3b, Fr.mul(challenges.beta, s2)); - e3b = Fr.add(e3b, challenges.gamma); - - let e3c = c; - e3c = Fr.add(e3c, Fr.mul(challenges.beta, s3)); - e3c = Fr.add(e3c, challenges.gamma); - - let e3d = zw; - let [e3, e3z] = MulZ.mul4(e3a, e3b, e3c, e3d, ap, bp, cp, zWp, i % 4, Fr); - - e3 = Fr.mul(e3, challenges.alpha); - e3z = Fr.mul(e3z, challenges.alpha); - - // e4 := α^2(z(X)−1)L1(X) - let e4 = Fr.sub(z, Fr.one); - e4 = Fr.mul(e4, evaluations.Lagrange.getEvaluation(i)); - e4 = Fr.mul(e4, challenges.alpha2); - - let e4z = Fr.mul(zp, evaluations.Lagrange.getEvaluation(i)); - e4z = Fr.mul(e4z, challenges.alpha2); - - - let t = Fr.add(Fr.sub(Fr.add(e1, e2), e3), e4); - let tz = Fr.add(Fr.sub(Fr.add(e1z, e2z), e3z), e4z); - - buffers.T.set(t, i * n8r); - buffers.Tz.set(tz, i * n8r); - - w = Fr.mul(w, Fr.w[zkey.power + 2]); - } - - // Compute the coefficients of the polynomial T0(X) from buffers.T0 - if (logger) - logger.debug("··· Computing T ifft"); - polynomials.T = await Polynomial.fromEvaluations(buffers.T, curve, logger); - - // Divide the polynomial T0 by Z_H(X) - if (logger) - logger.debug("··· Computing T / ZH"); - polynomials.T.divZh(zkey.domainSize, 4); - - // Compute the coefficients of the polynomial Tz(X) from buffers.Tz - if (logger) - logger.debug("··· Computing Tz ifft"); - polynomials.Tz = await Polynomial.fromEvaluations(buffers.Tz, curve, logger); - - // Add the polynomial T1z to T1 to get the final polynomial T1 - polynomials.T.add(polynomials.Tz); - - // Check degree - if (polynomials.T.degree() >= zkey.domainSize * 3 + 6) { - throw new Error("T Polynomial is not well calculated"); - } - - // t(x) has degree 3n + 5, we are going to split t(x) into three smaller polynomials: - // T1' and T2' with a degree < n and T3' with a degree n+5 - // such that t(x) = T1'(X) + X^n T2'(X) + X^{2n} T3'(X) - // To randomize the parts we use blinding scalars b_10 and b_11 in a way that doesn't change t(X): - // T1(X) = T1'(X) + b_10 X^n - // T2(X) = T2'(X) - b_10 + b_11 X^n - // T3(X) = T3'(X) - b_11 - // such that - // t(X) = T1(X) + X^n T2(X) + X^2n T3(X) - if (logger) logger.debug("··· Computing T1, T2, T3 polynomials"); - polynomials.T1 = new Polynomial(new BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); - polynomials.T2 = new Polynomial(new BigBuffer((zkey.domainSize + 1) * n8r), curve, logger); - polynomials.T3 = new Polynomial(new BigBuffer((zkey.domainSize + 6) * n8r), curve, logger); - - polynomials.T1.coef.set(polynomials.T.coef.slice(0, sDomain), 0); - polynomials.T2.coef.set(polynomials.T.coef.slice(sDomain, sDomain * 2), 0); - polynomials.T3.coef.set(polynomials.T.coef.slice(sDomain * 2, sDomain * 3 + 6 * n8r), 0); - - // Add blinding scalar b_10 as a new coefficient n - polynomials.T1.setCoef(zkey.domainSize, challenges.b[10]); - - // compute t_mid(X) - // Subtract blinding scalar b_10 to the lowest coefficient of t_mid - const lowestMid = Fr.sub(polynomials.T2.getCoef(0), challenges.b[10]); - polynomials.T2.setCoef(0, lowestMid); - polynomials.T2.setCoef(zkey.domainSize, challenges.b[11]); - - // compute t_high(X) - //Subtract blinding scalar b_11 to the lowest coefficient of t_high - const lowestHigh = Fr.sub(polynomials.T3.getCoef(0), challenges.b[11]); - polynomials.T3.setCoef(0, lowestHigh); - } - - async function round4() { - if (logger) logger.debug("> Computing challenge xi"); - - // STEP 4.1 - Compute evaluation challenge xi ∈ F - transcript.reset(); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.getPolynomial("T1")); - transcript.addPolCommitment(proof.getPolynomial("T2")); - transcript.addPolCommitment(proof.getPolynomial("T3")); - - challenges.xi = transcript.getChallenge(); - challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); - - if (logger) logger.debug("··· challenges.xi: " + Fr.toString(challenges.xi, 16)); - - // Fourth output of the prover is ( a(xi), b(xi), c(xi), s1(xi), s2(xi), z(xiw) ) - proof.addEvaluation("eval_a", polynomials.A.evaluate(challenges.xi)); - proof.addEvaluation("eval_b", polynomials.B.evaluate(challenges.xi)); - proof.addEvaluation("eval_c", polynomials.C.evaluate(challenges.xi)); - proof.addEvaluation("eval_s1", polynomials.Sigma1.evaluate(challenges.xi)); - proof.addEvaluation("eval_s2", polynomials.Sigma2.evaluate(challenges.xi)); - proof.addEvaluation("eval_zw", polynomials.Z.evaluate(challenges.xiw)); - } - - async function round5() { - if (logger) logger.debug("> Computing challenge v"); - - // STEP 5.1 - Compute evaluation challenge v ∈ F - transcript.reset(); - transcript.addScalar(challenges.xi); - transcript.addScalar(proof.getEvaluation("eval_a")); - transcript.addScalar(proof.getEvaluation("eval_b")); - transcript.addScalar(proof.getEvaluation("eval_c")); - transcript.addScalar(proof.getEvaluation("eval_s1")); - transcript.addScalar(proof.getEvaluation("eval_s2")); - transcript.addScalar(proof.getEvaluation("eval_zw")); - - challenges.v = []; - challenges.v[1] = transcript.getChallenge(); - if (logger) logger.debug("··· challenges.v: " + Fr.toString(challenges.v[1], 16)); - - for (let i = 2; i < 6; i++) { - challenges.v[i] = Fr.mul(challenges.v[i - 1], challenges.v[1]); - } - - // STEP 5.2 Compute linearisation polynomial r(X) - if (logger) logger.debug("> Computing linearisation polynomial R(X)"); - await computeR(); - - //STEP 5.3 Compute opening proof polynomial Wxi(X) - if (logger) logger.debug("> Computing opening proof polynomial Wxi(X) polynomial"); - computeWxi(); - - //STEP 5.4 Compute opening proof polynomial Wxiw(X) - if (logger) logger.debug("> Computing opening proof polynomial Wxiw(X) polynomial"); - computeWxiw(); - - if (logger) logger.debug("> Computing Wxi, Wxiw MSM"); - let commitWxi = await polynomials.Wxi.multiExponentiation(PTau, "Wxi"); - let commitWxiw = await polynomials.Wxiw.multiExponentiation(PTau, "Wxiw"); - - // Fifth output of the prover is ([Wxi]_1, [Wxiw]_1) - proof.addPolynomial("Wxi", commitWxi); - proof.addPolynomial("Wxiw", commitWxiw); - } - - async function computeR() { - const Fr = curve.Fr; - - // Reserve memory for Q's polynomials - polynomials.QL = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QR = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QM = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QO = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QC = new Polynomial(new BigBuffer(sDomain), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[ZKEY_PL_QL_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[ZKEY_PL_QR_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[ZKEY_PL_QM_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[ZKEY_PL_QO_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[ZKEY_PL_QC_SECTION][0].p); - - challenges.xin = challenges.xi; - for (let i = 0; i < zkey.power; i++) { - challenges.xin = Fr.square(challenges.xin); - } - - challenges.zh = Fr.sub(challenges.xin, Fr.one); - - const L = []; - - const n = Fr.e(zkey.domainSize); - let w = Fr.one; - for (let i = 1; i <= Math.max(1, zkey.nPublic); i++) { - L[i] = Fr.div(Fr.mul(w, challenges.zh), Fr.mul(n, Fr.sub(challenges.xi, w))); - w = Fr.mul(w, Fr.w[zkey.power]); - } - - const eval_l1 = Fr.div( - Fr.sub(challenges.xin, Fr.one), - Fr.mul(n, Fr.sub(challenges.xi, Fr.one)) - ); - - if (logger) { - logger.debug("Lagrange Evaluations: "); - for (let i=1; i. - */ - - const {unstringifyBigInts: unstringifyBigInts$5} = utils; - - async function plonkFullProve(_input, wasmFile, zkeyFileName, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$5(_input); - - const wtns= { - type: "mem" - }; - await wtnsCalculate(input, wasmFile, wtns, wtnsCalcOptions); - return await plonk16Prove(zkeyFileName, wtns, logger, proverOptions); - } - - /* - Copyright 2021 0kims association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - - const { unstringifyBigInts: unstringifyBigInts$4 } = utils; - - async function plonkVerify(_vk_verifier, _publicSignals, _proof, logger) { - let vk_verifier = unstringifyBigInts$4(_vk_verifier); - _proof = unstringifyBigInts$4(_proof); - let publicSignals = unstringifyBigInts$4(_publicSignals); - - const curve = await getCurveFromName(vk_verifier.curve); - - const Fr = curve.Fr; - const G1 = curve.G1; - - if (logger) logger.info("PLONK VERIFIER STARTED"); - - let proof = fromObjectProof(curve,_proof); - vk_verifier = fromObjectVk$1(curve, vk_verifier); - - if (!isWellConstructed(curve, proof)) { - logger.error("Proof commitments are not valid."); - return false; - } - - if (publicSignals.length != vk_verifier.nPublic) { - if (logger) logger.error("Invalid number of public inputs"); - return false; - } - - if (!evaluationsAreValid$1(curve, proof)) { - if (logger) logger.error("Proof evaluations are not valid"); - return false; - } - - if (!publicInputsAreValid$1(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - const challenges = calculatechallenges(curve, proof, publicSignals, vk_verifier); - if (logger) { - logger.debug("beta: " + Fr.toString(challenges.beta, 16)); - logger.debug("gamma: " + Fr.toString(challenges.gamma, 16)); - logger.debug("alpha: " + Fr.toString(challenges.alpha, 16)); - logger.debug("xi: " + Fr.toString(challenges.xi, 16)); - for(let i=1;i<6;i++) { - if (logger) logger.debug("v: " + Fr.toString(challenges.v[i], 16)); - } - logger.debug("u: " + Fr.toString(challenges.u, 16)); - } - const L = calculateLagrangeEvaluations(curve, challenges, vk_verifier); - if (logger) { - for (let i=1; i. - */ - - const { unstringifyBigInts: unstringifyBigInts$3} = utils; - - function p256$1(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0"+nstr; - nstr = `"0x${nstr}"`; - return nstr; - } - - async function plonkExportSolidityCallData(_proof, _pub) { - const proof = unstringifyBigInts$3(_proof); - const pub = unstringifyBigInts$3(_pub); - - await getCurveFromName(proof.curve); - - let inputs = ""; - for (let i=0; i. - */ - - var plonk = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportSolidityCallData: plonkExportSolidityCallData, - fullProve: plonkFullProve, - prove: plonk16Prove, - setup: plonkSetup, - verify: plonkVerify - }); - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - // We export to zkey the signals and values of the a, b, c, ql, qr, qm, qo and qc - - // a, b and c are signals id (32-bit integers) - // ql, qr, qm, qo and qc are field values - - function getFFlonkConstantConstraint(signal1, Fr) { - return [signal1, 0, 0, Fr.one, Fr.zero, Fr.zero, Fr.zero, Fr.zero]; - } - - function getFFlonkAdditionConstraint(signal1, signal2, signalOut, ql, qr, qm, qo, qc) { - return [signal1, signal2, signalOut, ql, qr, qm, qo, qc]; - } - - function getFFlonkMultiplicationConstraint(signal1, signal2, signalOut, ql, qr, qm, qo, qc, Fr) { - return [signal1, signal2, signalOut, ql, qr, qm, qo, qc]; - } - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - const LINEAR_COMBINATION_NULLABLE = 0; - const LINEAR_COMBINATION_CONSTANT = 1; - const LINEAR_COMBINATION_VARIABLE = 2; - - class r1csConstraintProcessor { - constructor(Fr, fnGetConstantConstraint, fnGetAdditionConstraint, fnGetMultiplicationConstraint, logger) { - this.Fr = Fr; - this.logger = logger; - this.fnGetAdditionConstraint = fnGetAdditionConstraint; - this.fnGetMultiplicationConstraint = fnGetMultiplicationConstraint; - } - - processR1csConstraint(settings, lcA, lcB, lcC) { - this.normalizeLinearCombination(lcA); - this.normalizeLinearCombination(lcB); - this.normalizeLinearCombination(lcC); - - const lctA = this.getLinearCombinationType(lcA); - const lctB = this.getLinearCombinationType(lcB); - - if ((lctA === LINEAR_COMBINATION_NULLABLE) || (lctB === LINEAR_COMBINATION_NULLABLE)) { - return this.processR1csAdditionConstraint(settings, lcC); - } else if (lctA === LINEAR_COMBINATION_CONSTANT) { - const lcCC = this.joinLinearCombinations(lcB, lcC, lcA[0]); - return this.processR1csAdditionConstraint(settings, lcCC); - } else if (lctB === LINEAR_COMBINATION_CONSTANT) { - const lcCC = this.joinLinearCombinations(lcA, lcC, lcB[0]); - return this.processR1csAdditionConstraint(settings, lcCC); - } else { - return this.processR1csMultiplicationConstraint(settings, lcA, lcB, lcC); - } - } - - getLinearCombinationType(linCom) { - // let k = this.Fr.zero; - // - // const signalIds = Object.keys(linCom); - // for (let i = 0; i < signalIds.length; i++) { - // if (signalIds[i] === "0") { - // k = this.Fr.add(k, linCom[signalIds[i]]); - // } else { - // return LINEAR_COMBINATION_VARIABLE; - // } - // } - // - // if (!this.Fr.eq(k, this.Fr.zero)) return LINEAR_COMBINATION_CONSTANT; - // - // return LINEAR_COMBINATION_NULLABLE; - - let k = this.Fr.zero; - let n = 0; - const ss = Object.keys(linCom); - for (let i = 0; i < ss.length; i++) { - if (linCom[ss[i]] == 0n) { - delete linCom[ss[i]]; - } else if (ss[i] == 0) { - k = this.Fr.add(k, linCom[ss[i]]); - } else { - n++; - } - } - if (n > 0) return LINEAR_COMBINATION_VARIABLE; - if (!this.Fr.isZero(k)) return LINEAR_COMBINATION_CONSTANT; - return LINEAR_COMBINATION_NULLABLE; - } - - normalizeLinearCombination(linCom) { - const signalIds = Object.keys(linCom); - for (let i = 0; i < signalIds.length; i++) { - if (this.Fr.isZero(linCom[signalIds[i]])) delete linCom[signalIds[i]]; - } - - return linCom; - } - - joinLinearCombinations(linCom1, linCom2, k) { - const res = {}; - - // for (let s in linCom1) { - // const val = this.Fr.mul(k, linCom1[s]); - // res[s] = !(s in res) ? val : this.Fr.add(val, res[s]); - // } - // - // for (let s in linCom2) { - // const val = this.Fr.mul(k, linCom2[s]); - // res[s] = !(s in res) ? val : this.Fr.add(val, res[s]); - // } - - for (let s in linCom1) { - if (typeof res[s] == "undefined") { - res[s] = this.Fr.mul(k, linCom1[s]); - } else { - res[s] = this.Fr.add(res[s], this.Fr.mul(k, linCom1[s])); - } - } - - for (let s in linCom2) { - if (typeof res[s] == "undefined") { - res[s] = linCom2[s]; - } else { - res[s] = this.Fr.add(res[s], linCom2[s]); - } - } - - return this.normalizeLinearCombination(res); - } - - reduceCoefs(settings, constraintsArr, additionsArr, linCom, maxC) { - const res = { - k: this.Fr.zero, - signals: [], - coefs: [] - }; - const cs = []; - - for (let signalId in linCom) { - if (signalId == 0) { - res.k = this.Fr.add(res.k, linCom[signalId]); - } else if (linCom[signalId] != 0n) { - cs.push([Number(signalId), linCom[signalId]]); - } - } - - while (cs.length > maxC) { - const c1 = cs.shift(); - const c2 = cs.shift(); - const so = settings.nVars++; - - const constraints = this.fnGetAdditionConstraint( - c1[0], c2[0], so, - this.Fr.neg(c1[1]), this.Fr.neg(c2[1]), this.Fr.zero, this.Fr.one, this.Fr.zero); - - constraintsArr.push(constraints); - additionsArr.push([c1[0], c2[0], c1[1], c2[1]]); - - cs.push([so, this.Fr.one]); - } - - for (let i = 0; i < cs.length; i++) { - res.signals[i] = cs[i][0]; - res.coefs[i] = cs[i][1]; - } - - while (res.coefs.length < maxC) { - res.signals.push(0); - res.coefs.push(this.Fr.zero); - } - - return res; - } - - processR1csAdditionConstraint(settings, linCom) { - const constraintsArr = []; - const additionsArr = []; - - const C = this.reduceCoefs(settings, constraintsArr, additionsArr, linCom, 3); - - const constraints = this.fnGetAdditionConstraint( - C.signals[0], C.signals[1], C.signals[2], - C.coefs[0], C.coefs[1], this.Fr.zero, C.coefs[2], C.k); - - constraintsArr.push(constraints); - - return [constraintsArr, additionsArr]; - } - - processR1csMultiplicationConstraint(settings, lcA, lcB, lcC) { - const constraintsArr = []; - const additionsArr = []; - - const A = this.reduceCoefs(settings, constraintsArr, additionsArr, lcA, 1); - const B = this.reduceCoefs(settings, constraintsArr, additionsArr, lcB, 1); - const C = this.reduceCoefs(settings, constraintsArr, additionsArr, lcC, 1); - - const constraints = this.fnGetMultiplicationConstraint( - A.signals[0], B.signals[0], C.signals[0], - this.Fr.mul(A.coefs[0], B.k), - this.Fr.mul(A.k, B.coefs[0]), - this.Fr.mul(A.coefs[0], B.coefs[0]), - this.Fr.neg(C.coefs[0]), - this.Fr.sub(this.Fr.mul(A.k, B.k), C.k)); - - constraintsArr.push(constraints); - - return [constraintsArr, additionsArr]; - } - } - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - - class CPolynomial { - constructor(n, curve, logger) { - this.n = n; - this.polynomials = Array(n).fill(undefined); - this.curve = curve; - this.Fr = curve.Fr; - this.G1 = curve.G1; - this.logger = logger; - } - - addPolynomial(position, polynomial) { - if (position > this.n - 1) { - throw new Error("CPolynomial:addPolynomial, cannot add a polynomial to a position greater than n-1"); - } - - this.polynomials[position] = polynomial; - } - - degree() { - let degrees = this.polynomials.map( - (polynomial, index) => polynomial === undefined ? 0 : polynomial.degree() * this.n + index); - return Math.max(...degrees); - } - - getPolynomial() { - let degrees = this.polynomials.map(polynomial => polynomial === undefined ? 0 : polynomial.degree()); - const maxDegree = this.degree(); - const lengthBuffer = 2 ** (log2(maxDegree - 1) + 1); - const sFr = this.Fr.n8; - - let polynomial = new Polynomial(new BigBuffer(lengthBuffer * sFr), this.curve, this.logger); - - for (let i = 0; i < maxDegree; i++) { - const i_n8 = i * sFr; - const i_sFr = i_n8 * this.n; - - for (let j = 0; j < this.n; j++) { - if (this.polynomials[j] !== undefined) { - if (i <= degrees[j]) polynomial.coef.set(this.polynomials[j].coef.slice(i_n8, i_n8 + sFr), i_sFr + j * sFr); - } - } - } - - return polynomial; - } - - async multiExponentiation(PTau, name) { - let polynomial = this.getPolynomial(); - const n = polynomial.coef.byteLength / this.Fr.n8; - const PTauN = PTau.slice(0, n * this.G1.F.n8 * 2); - const bm = await this.Fr.batchFromMontgomery(polynomial.coef); - let res = await this.G1.multiExpAffine(PTauN, bm, this.logger, name); - res = this.G1.toAffine(res); - return res; - } - } - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - - - async function fflonkSetup(r1csFilename, ptauFilename, zkeyFilename, logger) { - if (logger) logger.info("FFLONK SETUP STARTED"); - - if (globalThis.gc) globalThis.gc(); - - // Read PTau file - if (logger) logger.info("> Reading PTau file"); - const {fd: fdPTau, sections: pTauSections} = await readBinFile$1(ptauFilename, "ptau", 1, 1 << 22, 1 << 24); - if (!pTauSections[12]) { - throw new Error("Powers of Tau is not well prepared. Section 12 missing."); - } - - // Get curve defined in PTau - if (logger) logger.info("> Getting curve from PTau settings"); - const {curve} = await readPTauHeader(fdPTau, pTauSections); - - // Read r1cs file - if (logger) logger.info("> Reading r1cs file"); - const {fd: fdR1cs, sections: sectionsR1cs} = await readBinFile$1(r1csFilename, "r1cs", 1, 1 << 22, 1 << 24); - const r1cs = await readR1csFd(fdR1cs, sectionsR1cs, {loadConstraints: false, loadCustomGates: true}); - - // Potential error checks - if (r1cs.prime !== curve.r) { - throw new Error("r1cs curve does not match powers of tau ceremony curve"); - } - - // Initializations - const Fr = curve.Fr; - - const sFr = curve.Fr.n8; - const sG1 = curve.G1.F.n8 * 2; - const sG2 = curve.G2.F.n8 * 2; - - let polynomials = {}; - let evaluations = {}; - let PTau; - - let settings = { - nVars: r1cs.nVars, - nPublic: r1cs.nOutputs + r1cs.nPubInputs - }; - - const plonkConstraints = new BigArray(); - let plonkAdditions = new BigArray(); - - // Process constraints inside r1cs - if (logger) logger.info("> Processing FFlonk constraints"); - await computeFFConstraints(curve.Fr, r1cs, logger); - if (globalThis.gc) globalThis.gc(); - - // As the t polynomial is n+5 we need at least a power of 4 - //TODO check!!!! - // NOTE : plonkConstraints + 2 = #constraints + blinding coefficients for each wire polynomial - settings.cirPower = Math.max(FF_T_POL_DEG_MIN, log2((plonkConstraints.length + 2) - 1) + 1); - settings.domainSize = 2 ** settings.cirPower; - - if (pTauSections[2][0].size < (settings.domainSize * 9 + 18) * sG1) { - throw new Error("Powers of Tau is not big enough for this circuit size. Section 2 too small."); - } - if (pTauSections[3][0].size < sG2) { - throw new Error("Powers of Tau is not well prepared. Section 3 too small."); - } - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK SETUP SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${settings.cirPower}`); - logger.info(` Domain size: ${settings.domainSize}`); - logger.info(` Vars: ${settings.nVars}`); - logger.info(` Public vars: ${settings.nPublic}`); - logger.info(` Constraints: ${plonkConstraints.length}`); - logger.info(` Additions: ${plonkAdditions.length}`); - logger.info("----------------------------"); - } - - // Compute k1 and k2 to be used in the permutation checks - if (logger) logger.info("> computing k1 and k2"); - const [k1, k2] = computeK1K2(); - - // Compute omega 3 (w3) and omega 4 (w4) to be used in the prover and the verifier - // w3^3 = 1 and w4^4 = 1 - if (logger) logger.info("> computing w3"); - const w3 = computeW3(); - if (logger) logger.info("> computing w4"); - const w4 = computeW4(); - if (logger) logger.info("> computing w8"); - const w8 = computeW8(); - if (logger) logger.info("> computing wr"); - const wr = getOmegaCubicRoot(settings.cirPower, curve.Fr); - - // Write output zkey file - await writeZkeyFile(); - - await fdR1cs.close(); - await fdPTau.close(); - - if (logger) logger.info("FFLONK SETUP FINISHED"); - - return 0; - - async function computeFFConstraints(Fr, r1cs, logger) { - // Add public inputs and outputs - for (let i = 0; i < settings.nPublic; i++) { - plonkConstraints.push(getFFlonkConstantConstraint(i + 1, Fr)); - } - - // Add all constraints from r1cs file - const r1csProcessor = new r1csConstraintProcessor(Fr, getFFlonkConstantConstraint, getFFlonkAdditionConstraint, getFFlonkMultiplicationConstraint, logger); - - const bR1cs = await readSection$1(fdR1cs, sectionsR1cs, 2); - let bR1csPos = 0; - for (let i = 0; i < r1cs.nConstraints; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` processing r1cs constraints ${i}/${r1cs.nConstraints}`); - } - const [constraints, additions] = r1csProcessor.processR1csConstraint(settings, ...readConstraint()); - - plonkConstraints.push(...constraints); - plonkAdditions.push(...additions); - } - - function readConstraint() { - const c = []; - c[0] = readLC(); - c[1] = readLC(); - c[2] = readLC(); - return c; - } - - function readLC() { - const lc = {}; - - const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos + 4); - bR1csPos += 4; - const buffUL32V = new DataView(buffUL32.buffer); - const nIdx = buffUL32V.getUint32(0, true); - - const buff = bR1cs.slice(bR1csPos, bR1csPos + (4 + r1cs.n8) * nIdx); - bR1csPos += (4 + r1cs.n8) * nIdx; - const buffV = new DataView(buff.buffer); - for (let i = 0; i < nIdx; i++) { - const idx = buffV.getUint32(i * (4 + r1cs.n8), true); - const val = r1cs.F.fromRprLE(buff, i * (4 + r1cs.n8) + 4); - lc[idx] = val; - } - return lc; - } - - return 0; - } - - async function writeZkeyFile() { - if (logger) logger.info("> Writing the zkey file"); - const fdZKey = await createBinFile(zkeyFilename, "zkey", 1, ZKEY_FF_NSECTIONS, 1 << 22, 1 << 24); - - if (logger) logger.info(`··· Writing Section ${HEADER_ZKEY_SECTION}. Zkey Header`); - await writeZkeyHeader(fdZKey); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_ADDITIONS_SECTION}. Additions`); - await writeAdditions(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_A_MAP_SECTION}. A Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_A_MAP_SECTION, 0, "A map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_B_MAP_SECTION}. B Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_B_MAP_SECTION, 1, "B map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_C_MAP_SECTION}. C Map`); - await writeWitnessMap(fdZKey, ZKEY_FF_C_MAP_SECTION, 2, "C map"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QL_SECTION}. QL`); - await writeQMap(fdZKey, ZKEY_FF_QL_SECTION, 3, "QL"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QR_SECTION}. QR`); - await writeQMap(fdZKey, ZKEY_FF_QR_SECTION, 4, "QR"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QM_SECTION}. QM`); - await writeQMap(fdZKey, ZKEY_FF_QM_SECTION, 5, "QM"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QO_SECTION}. QO`); - await writeQMap(fdZKey, ZKEY_FF_QO_SECTION, 6, "QO"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_QC_SECTION}. QC`); - await writeQMap(fdZKey, ZKEY_FF_QC_SECTION, 7, "QC"); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Sections ${ZKEY_FF_SIGMA1_SECTION},${ZKEY_FF_SIGMA2_SECTION},${ZKEY_FF_SIGMA3_SECTION}. Sigma1, Sigma2 & Sigma 3`); - await writeSigma(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_LAGRANGE_SECTION}. Lagrange Polynomials`); - await writeLagrangePolynomials(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_PTAU_SECTION}. Powers of Tau`); - await writePtau(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_C0_SECTION}. C0`); - await writeC0(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info(`··· Writing Section ${ZKEY_FF_HEADER_SECTION}. FFlonk Header`); - await writeFFlonkHeader(fdZKey); - if (globalThis.gc) globalThis.gc(); - - if (logger) logger.info("> Writing the zkey file finished"); - - await fdZKey.close(); - } - - async function writeZkeyHeader(fdZKey) { - await startWriteSection(fdZKey, HEADER_ZKEY_SECTION); - await fdZKey.writeULE32(FFLONK_PROTOCOL_ID); - await endWriteSection(fdZKey); - } - - async function writeAdditions(fdZKey) { - await startWriteSection(fdZKey, ZKEY_FF_ADDITIONS_SECTION); - - // Written values are 2 * 32 bit integers (2 * 4 bytes) + 2 field size values ( 2 * sFr bytes) - const buffOut = new Uint8Array(8 + 2 * sFr); - const buffOutV = new DataView(buffOut.buffer); - - for (let i = 0; i < plonkAdditions.length; i++) { - if ((logger) && (i !== 0) && (i % 500000 === 0)) logger.info(` writing Additions: ${i}/${plonkAdditions.length}`); - - const addition = plonkAdditions[i]; - - buffOutV.setUint32(0, addition[0], true); - buffOutV.setUint32(4, addition[1], true); - buffOut.set(addition[2], 8); - buffOut.set(addition[3], 8 + sFr); - - await fdZKey.write(buffOut); - } - await endWriteSection(fdZKey); - } - - async function writeWitnessMap(fdZKey, sectionNum, posConstraint, name) { - await startWriteSection(fdZKey, sectionNum); - for (let i = 0; i < plonkConstraints.length; i++) { - if (logger && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing witness ${name}: ${i}/${plonkConstraints.length}`); - } - - await fdZKey.writeULE32(plonkConstraints[i][posConstraint]); - } - await endWriteSection(fdZKey); - } - - async function writeQMap(fdZKey, sectionNum, posConstraint, name) { - // Compute Q from q evaluations - let Q = new BigBuffer(settings.domainSize * sFr); - - for (let i = 0; i < plonkConstraints.length; i++) { - Q.set(plonkConstraints[i][posConstraint], i * sFr); - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing ${name}: ${i}/${plonkConstraints.length}`); - } - } - - polynomials[name] = await Polynomial.fromEvaluations(Q, curve, logger); - evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); - - // Write Q coefficients and evaluations - await startWriteSection(fdZKey, sectionNum); - await fdZKey.write(polynomials[name].coef); - await fdZKey.write(evaluations[name].eval); - await endWriteSection(fdZKey); - } - - async function writeSigma(fdZKey) { - // Compute sigma - const sigma = new BigBuffer(sFr * settings.domainSize * 3); - const lastSeen = new BigArray(settings.nVars); - const firstPos = new BigArray(settings.nVars); - - let w = Fr.one; - for (let i = 0; i < settings.domainSize; i++) { - if (i < plonkConstraints.length) { - buildSigma(plonkConstraints[i][0], i); - buildSigma(plonkConstraints[i][1], settings.domainSize + i); - buildSigma(plonkConstraints[i][2], settings.domainSize * 2 + i); - } else if (i < settings.domainSize - 2) { - buildSigma(0, i); - buildSigma(0, settings.domainSize + i); - buildSigma(0, settings.domainSize * 2 + i); - } else { - sigma.set(w, i * sFr); - sigma.set(Fr.mul(w, k1), (settings.domainSize + i) * sFr); - sigma.set(Fr.mul(w, k2), (settings.domainSize * 2 + i) * sFr); - } - - w = Fr.mul(w, Fr.w[settings.cirPower]); - - if ((logger) && (i !== 0) && (i % 500000 === 0)) { - logger.info(` writing sigma phase1: ${i}/${plonkConstraints.length}`); - } - } - - for (let i = 0; i < settings.nVars; i++) { - if (typeof firstPos[i] !== "undefined") { - sigma.set(lastSeen[i], firstPos[i] * sFr); - } else { - // throw new Error("Variable not used"); - console.log("Variable not used"); - } - if ((logger) && (i !== 0) && (i % 500000 === 0)) logger.info(` writing sigma phase2: ${i}/${settings.nVars}`); - } - - if (globalThis.gc) globalThis.gc(); - - // Write sigma coefficients and evaluations - for (let i = 0; i < 3; i++) { - const sectionId = 0 === i ? ZKEY_FF_SIGMA1_SECTION : 1 === i ? ZKEY_FF_SIGMA2_SECTION : ZKEY_FF_SIGMA3_SECTION; - - let name = "S" + (i + 1); - polynomials[name] = await Polynomial.fromEvaluations(sigma.slice(settings.domainSize * sFr * i, settings.domainSize * sFr * (i + 1)), curve, logger); - evaluations[name] = await Evaluations.fromPolynomial(polynomials[name], 4, curve, logger); - await startWriteSection(fdZKey, sectionId); - await fdZKey.write(polynomials[name].coef); - await fdZKey.write(evaluations[name].eval); - await endWriteSection(fdZKey); - - if (globalThis.gc) globalThis.gc(); - } - - return 0; - - function buildSigma(signalId, idx) { - if (typeof lastSeen[signalId] === "undefined") { - firstPos[signalId] = idx; - } else { - sigma.set(lastSeen[signalId], idx * sFr); - } - let v; - if (idx < settings.domainSize) { - v = w; - } else if (idx < 2 * settings.domainSize) { - v = Fr.mul(w, k1); - } else { - v = Fr.mul(w, k2); - } - - lastSeen[signalId] = v; - } - } - - async function writeLagrangePolynomials(fdZKey) { - await startWriteSection(fdZKey, ZKEY_FF_LAGRANGE_SECTION); - - const l = Math.max(settings.nPublic, 1); - for (let i = 0; i < l; i++) { - let buff = new BigBuffer(settings.domainSize * sFr); - buff.set(Fr.one, i * sFr); - - await writeP4(fdZKey, buff); - } - await endWriteSection(fdZKey); - } - - async function writePtau(fdZKey) { - await startWriteSection(fdZKey, ZKEY_FF_PTAU_SECTION); - - // domainSize * 9 + 18 = maximum SRS length needed, specifically to commit C2 - PTau = new BigBuffer((settings.domainSize * 9 + 18) * sG1); - await fdPTau.readToBuffer(PTau, 0, (settings.domainSize * 9 + 18) * sG1, pTauSections[2][0].p); - - await fdZKey.write(PTau); - await endWriteSection(fdZKey); - } - - async function writeC0(fdZKey) { - // C0(X) := QL(X^8) + X · QR(X^8) + X^2 · QO(X^8) + X^3 · QM(X^8) + X^4 · QC(X^8) - // + X^5 · SIGMA1(X^8) + X^6 · SIGMA2(X^8) + X^7 · SIGMA3(X^8) - let C0 = new CPolynomial(8, curve, logger); - C0.addPolynomial(0, polynomials.QL); - C0.addPolynomial(1, polynomials.QR); - C0.addPolynomial(2, polynomials.QO); - C0.addPolynomial(3, polynomials.QM); - C0.addPolynomial(4, polynomials.QC); - C0.addPolynomial(5, polynomials.S1); - C0.addPolynomial(6, polynomials.S2); - C0.addPolynomial(7, polynomials.S3); - - polynomials.C0 = C0.getPolynomial(); - - // Check degree - if (polynomials.C0.degree() >= 8 * settings.domainSize) { - throw new Error("C0 Polynomial is not well calculated"); - } - - await startWriteSection(fdZKey, ZKEY_FF_C0_SECTION); - await fdZKey.write(polynomials.C0.coef); - await endWriteSection(fdZKey); - } - - async function writeFFlonkHeader(fdZKey) { - await startWriteSection(fdZKey, ZKEY_FF_HEADER_SECTION); - - const primeQ = curve.q; - const n8q = (Math.floor((Scalar.bitLength(primeQ) - 1) / 64) + 1) * 8; - await fdZKey.writeULE32(n8q); - await writeBigInt(fdZKey, primeQ, n8q); - - const primeR = curve.r; - const n8r = (Math.floor((Scalar.bitLength(primeR) - 1) / 64) + 1) * 8; - await fdZKey.writeULE32(n8r); - await writeBigInt(fdZKey, primeR, n8r); - - // Total number of r1cs vars - await fdZKey.writeULE32(settings.nVars); - // Total number of r1cs public vars = outputs + public inputs - await fdZKey.writeULE32(settings.nPublic); - await fdZKey.writeULE32(settings.domainSize); - await fdZKey.writeULE32(plonkAdditions.length); - await fdZKey.writeULE32(plonkConstraints.length); - - await fdZKey.write(k1); - await fdZKey.write(k2); - - await fdZKey.write(w3); - await fdZKey.write(w4); - await fdZKey.write(w8); - await fdZKey.write(wr); - - let bX_2; - bX_2 = await fdPTau.read(sG2, pTauSections[3][0].p + sG2); - await fdZKey.write(bX_2); - - let commitC0 = await polynomials.C0.multiExponentiation(PTau, "C0"); - await fdZKey.write(commitC0); - - await endWriteSection(fdZKey); - } - - async function writeP4(fdZKey, buff) { - const [coefficients, evaluations4] = await Polynomial.to4T(buff, settings.domainSize, [], Fr); - await fdZKey.write(coefficients); - await fdZKey.write(evaluations4); - - return [coefficients, evaluations4]; - } - - function computeK1K2() { - let k1 = Fr.two; - while (isIncluded(k1, [], settings.cirPower)) Fr.add(k1, Fr.one); - let k2 = Fr.add(k1, Fr.one); - while (isIncluded(k2, [k1], settings.cirPower)) Fr.add(k2, Fr.one); - return [k1, k2]; - - function isIncluded(k, kArr, pow) { - const domainSize = 2 ** pow; - let w = Fr.one; - for (let i = 0; i < domainSize; i++) { - if (Fr.eq(k, w)) return true; - for (let j = 0; j < kArr.length; j++) { - if (Fr.eq(k, Fr.mul(kArr[j], w))) return true; - } - w = Fr.mul(w, Fr.w[pow]); - } - return false; - } - } - - function computeW3() { - let generator = Fr.e(31624); - - // Exponent is order(r - 1) / 3 - let orderRsub1 = 3648040478639879203707734290876212514758060733402672390616367364429301415936n; - let exponent = Scalar.div(orderRsub1, Scalar.e(3)); - - return Fr.exp(generator, exponent); - } - - function computeW4() { - return Fr.w[2]; - } - - function computeW8() { - return Fr.w[3]; - } - - function getOmegaCubicRoot(power, Fr) { - // Hardcorded 3th-root of Fr.w[28] - const firstRoot = Fr.e(467799165886069610036046866799264026481344299079011762026774533774345988080n); - - return Fr.exp(firstRoot, 2 ** (28 - power)); - } - } - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - - const { stringifyBigInts } = utils; - - - async function fflonkProve(zkeyFileName, witnessFileName, logger, options) { - if (logger) logger.info("FFLONK PROVER STARTED"); - - // Read witness file - if (logger) logger.info("> Reading witness file"); - const { - fd: fdWtns, - sections: wtnsSections - } = await readBinFile$1(witnessFileName, "wtns", 2, 1 << 25, 1 << 23); - const wtns = await readHeader(fdWtns, wtnsSections); - - //Read zkey file - if (logger) logger.info("> Reading zkey file"); - const { - fd: fdZKey, - sections: zkeySections - } = await readBinFile$1(zkeyFileName, "zkey", 2, 1 << 25, 1 << 23); - - const zkey = await readHeader$1(fdZKey, zkeySections, undefined, options); - - if (zkey.protocolId !== FFLONK_PROTOCOL_ID) { - throw new Error("zkey file is not fflonk"); - } - - if (!Scalar.eq(zkey.r, wtns.q)) { - throw new Error("Curve of the witness does not match the curve of the proving key"); - } - - if (wtns.nWitness !== zkey.nVars - zkey.nAdditions) { - throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`); - } - - const curve = zkey.curve; - - const Fr = curve.Fr; - - const sFr = curve.Fr.n8; - const sG1 = curve.G1.F.n8 * 2; - const sDomain = zkey.domainSize * sFr; - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK PROVE SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${zkey.power}`); - logger.info(` Domain size: ${zkey.domainSize}`); - logger.info(` Vars: ${zkey.nVars}`); - logger.info(` Public vars: ${zkey.nPublic}`); - logger.info(` Constraints: ${zkey.nConstraints}`); - logger.info(` Additions: ${zkey.nAdditions}`); - logger.info("----------------------------"); - } - - //Read witness data - if (logger) logger.info("> Reading witness file data"); - const buffWitness = await readSection$1(fdWtns, wtnsSections, 2); - await fdWtns.close(); - - // First element in plonk is not used and can be any value. (But always the same). - // We set it to zero to go faster in the exponentiations. - buffWitness.set(Fr.zero, 0); - const buffInternalWitness = new BigBuffer(zkey.nAdditions * sFr); - - let buffers = {}; - let polynomials = {}; - let evaluations = {}; - - // To divide prime fields the Extended Euclidean Algorithm for computing modular inverses is needed. - // NOTE: This is the equivalent of compute 1/denominator and then multiply it by the numerator. - // The Extended Euclidean Algorithm is expensive in terms of computation. - // For the special case where we need to do many modular inverses, there's a simple mathematical trick - // that allows us to compute many inverses, called Montgomery batch inversion. - // More info: https://vitalik.ca/general/2018/07/21/starks_part_3.html - // Montgomery batch inversion reduces the n inverse computations to a single one - // To save this (single) inverse computation on-chain, will compute it in proving time and send it to the verifier. - // The verifier will have to check: - // 1) the denominator is correct multiplying by himself non-inverted -> a * 1/a == 1 - // 2) compute the rest of the denominators using the Montgomery batch inversion - // The inversions are: - // · denominator needed in step 8 and 9 of the verifier to multiply by 1/Z_H(xi) - // · denominator needed in step 10 and 11 of the verifier - // · denominator needed in the verifier when computing L_i^{S1}(X) and L_i^{S2}(X) - // · L_i i=1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) - let toInverse = {}; - - let challenges = {}; - let roots = {}; - - let proof = new Proof(curve, logger); - - if (logger) logger.info(`> Reading Section ${ZKEY_FF_ADDITIONS_SECTION}. Additions`); - await calculateAdditions(); - - if (logger) logger.info(`> Reading Sections ${ZKEY_FF_SIGMA1_SECTION},${ZKEY_FF_SIGMA2_SECTION},${ZKEY_FF_SIGMA3_SECTION}. Sigma1, Sigma2 & Sigma 3`); - if (logger) logger.info("··· Reading Sigma polynomials "); - polynomials.Sigma1 = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.Sigma2 = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.Sigma3 = new Polynomial(new BigBuffer(sDomain), curve, logger); - - await fdZKey.readToBuffer(polynomials.Sigma1.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA1_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma2.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA2_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.Sigma3.coef, 0, sDomain, zkeySections[ZKEY_FF_SIGMA3_SECTION][0].p); - - if (logger) logger.info("··· Reading Sigma evaluations"); - evaluations.Sigma1 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma2 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.Sigma3 = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - - await fdZKey.readToBuffer(evaluations.Sigma1.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA1_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma2.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA2_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.Sigma3.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_SIGMA3_SECTION][0].p + sDomain); - - if (logger) logger.info(`> Reading Section ${ZKEY_FF_PTAU_SECTION}. Powers of Tau`); - const PTau = new BigBuffer(zkey.domainSize * 16 * sG1); - // domainSize * 9 + 18 = SRS length in the zkey saved in setup process. - // it corresponds to the maximum SRS length needed, specifically to commit C2 - // notice that the reserved buffers size is zkey.domainSize * 16 * sG1 because a power of two buffer size is needed - // the remaining buffer not filled from SRS are set to 0 - await fdZKey.readToBuffer(PTau, 0, (zkey.domainSize * 9 + 18) * sG1, zkeySections[ZKEY_FF_PTAU_SECTION][0].p); - - // START FFLONK PROVER PROTOCOL - if (globalThis.gc) globalThis.gc(); - - // ROUND 1. Compute C1(X) polynomial - if (logger) logger.info(""); - if (logger) logger.info("> ROUND 1"); - await round1(); - - delete polynomials.T0; - delete evaluations.QL; - delete evaluations.QR; - delete evaluations.QM; - delete evaluations.QO; - delete evaluations.QC; - if (globalThis.gc) globalThis.gc(); - - // ROUND 2. Compute C2(X) polynomial - if (logger) logger.info("> ROUND 2"); - await round2(); - - delete buffers.A; - delete buffers.B; - delete buffers.C; - delete evaluations.A; - delete evaluations.B; - delete evaluations.C; - delete evaluations.Sigma1; - delete evaluations.Sigma2; - delete evaluations.Sigma3; - delete evaluations.lagrange1; - delete evaluations.Z; - if (globalThis.gc) globalThis.gc(); - - // ROUND 3. Compute opening evaluations - if (logger) logger.info("> ROUND 3"); - await round3(); - - delete polynomials.A; - delete polynomials.B; - delete polynomials.C; - delete polynomials.Z; - delete polynomials.T1; - delete polynomials.T2; - delete polynomials.Sigma1; - delete polynomials.Sigma2; - delete polynomials.Sigma3; - delete polynomials.QL; - delete polynomials.QR; - delete polynomials.QM; - delete polynomials.QC; - delete polynomials.QO; - if (globalThis.gc) globalThis.gc(); - - // ROUND 4. Compute W(X) polynomial - if (logger) logger.info("> ROUND 4"); - await round4(); - if (globalThis.gc) globalThis.gc(); - - // ROUND 5. Compute W'(X) polynomial - if (logger) logger.info("> ROUND 5"); - await round5(); - - delete polynomials.C0; - delete polynomials.C1; - delete polynomials.C2; - delete polynomials.R1; - delete polynomials.R2; - delete polynomials.F; - delete polynomials.L; - delete polynomials.ZT; - delete polynomials.ZTS2; - await fdZKey.close(); - if (globalThis.gc) globalThis.gc(); - - proof.addEvaluation("inv", getMontgomeryBatchedInverse()); - - // Prepare proof - let _proof = proof.toObjectProof(); - _proof.protocol = "fflonk"; - _proof.curve = curve.name; - - // Prepare public inputs - let publicSignals = []; - - for (let i = 1; i <= zkey.nPublic; i++) { - const i_sFr = i * sFr; - - const pub = buffWitness.slice(i_sFr, i_sFr + sFr); - publicSignals.push(Scalar.fromRprLE(pub)); - } - - if (logger) logger.info("FFLONK PROVER FINISHED"); - - return { - proof: stringifyBigInts(_proof), - publicSignals: stringifyBigInts(publicSignals) - }; - - async function calculateAdditions() { - if (logger) logger.info("··· Computing additions"); - const additionsBuff = await readSection$1(fdZKey, zkeySections, ZKEY_FF_ADDITIONS_SECTION); - - // sizes: wireId_x = 4 bytes (32 bits), factor_x = field size bits - // Addition form: wireId_a wireId_b factor_a factor_b (size is 4 + 4 + sFr + sFr) - const sSum = 8 + sFr * 2; - - for (let i = 0; i < zkey.nAdditions; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` addition ${i}/${zkey.nAdditions}`); - - // Read addition values - let offset = i * sSum; - const signalId1 = readUInt32(additionsBuff, offset); - offset += 4; - const signalId2 = readUInt32(additionsBuff, offset); - offset += 4; - const factor1 = additionsBuff.slice(offset, offset + sFr); - offset += sFr; - const factor2 = additionsBuff.slice(offset, offset + sFr); - - // Get witness value - const witness1 = getWitness(signalId1); - const witness2 = getWitness(signalId2); - - //Calculate final result - const result = Fr.add(Fr.mul(factor1, witness1), Fr.mul(factor2, witness2)); - - buffInternalWitness.set(result, sFr * i); - } - } - - function readUInt32(b, o) { - const buff = b.slice(o, o + 4); - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - return buffV.getUint32(0, true); - } - - function getWitness(idx) { - let diff = zkey.nVars - zkey.nAdditions; - if (idx < diff) { - return buffWitness.slice(idx * sFr, idx * sFr + sFr); - } else if (idx < zkey.nVars) { - const offset = (idx - diff) * sFr; - return buffInternalWitness.slice(offset, offset + sFr); - } - - return Fr.zero; - } - - async function round1() { - // STEP 1.1 - Generate random blinding scalars (b_1, ..., b9) ∈ F - challenges.b = []; - for (let i = 1; i <= 9; i++) { - challenges.b[i] = Fr.random(); - } - - // STEP 1.2 - Compute wire polynomials a(X), b(X) and c(X) - if (logger) logger.info("> Computing A, B, C wire polynomials"); - await computeWirePolynomials(); - - // STEP 1.3 - Compute the quotient polynomial T0(X) - if (logger) logger.info("> Computing T0 polynomial"); - await computeT0(); - - // STEP 1.4 - Compute the FFT-style combination polynomial C1(X) - if (logger) logger.info("> Computing C1 polynomial"); - await computeC1(); - - // The first output of the prover is ([C1]_1) - if (logger) logger.info("> Computing C1 multi exponentiation"); - let commitC1 = await polynomials.C1.multiExponentiation(PTau, "C1"); - proof.addPolynomial("C1", commitC1); - - return 0; - - async function computeWirePolynomials() { - if (logger) logger.info("··· Reading data from zkey file"); - // Build A, B and C evaluations buffer from zkey and witness files - buffers.A = new BigBuffer(sDomain); - buffers.B = new BigBuffer(sDomain); - buffers.C = new BigBuffer(sDomain); - - // Read zkey sections and fill the buffers - const aMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_FF_A_MAP_SECTION); - const bMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_FF_B_MAP_SECTION); - const cMapBuff = await readSection$1(fdZKey, zkeySections, ZKEY_FF_C_MAP_SECTION); - - // Compute all witness from signal ids and set them to A,B & C buffers - for (let i = 0; i < zkey.nConstraints; i++) { - const i_sFr = i * sFr; - const offset = i * 4; - - // Compute A value from a signal id - const signalIdA = readUInt32(aMapBuff, offset); - buffers.A.set(getWitness(signalIdA), i_sFr); - - // Compute B value from a signal id - const signalIdB = readUInt32(bMapBuff, offset); - buffers.B.set(getWitness(signalIdB), i_sFr); - - // Compute C value from a signal id - const signalIdC = readUInt32(cMapBuff, offset); - buffers.C.set(getWitness(signalIdC), i_sFr); - } - - // Blind a(X), b(X) and c(X) polynomials coefficients with blinding scalars b - buffers.A.set(challenges.b[1], sDomain - 64); - buffers.A.set(challenges.b[2], sDomain - 32); - buffers.B.set(challenges.b[3], sDomain - 64); - buffers.B.set(challenges.b[4], sDomain - 32); - buffers.C.set(challenges.b[5], sDomain - 64); - buffers.C.set(challenges.b[6], sDomain - 32); - - buffers.A = await Fr.batchToMontgomery(buffers.A); - buffers.B = await Fr.batchToMontgomery(buffers.B); - buffers.C = await Fr.batchToMontgomery(buffers.C); - - // Compute the coefficients of the wire polynomials a(X), b(X) and c(X) from A,B & C buffers - if (logger) logger.info("··· Computing A ifft"); - polynomials.A = await Polynomial.fromEvaluations(buffers.A, curve, logger); - if (logger) logger.info("··· Computing B ifft"); - polynomials.B = await Polynomial.fromEvaluations(buffers.B, curve, logger); - if (logger) logger.info("··· Computing C ifft"); - polynomials.C = await Polynomial.fromEvaluations(buffers.C, curve, logger); - - // Compute extended evaluations of a(X), b(X) and c(X) polynomials - if (logger) logger.info("··· Computing A fft"); - evaluations.A = await Evaluations.fromPolynomial(polynomials.A, 4, curve, logger); - if (logger) logger.info("··· Computing B fft"); - evaluations.B = await Evaluations.fromPolynomial(polynomials.B, 4, curve, logger); - if (logger) logger.info("··· Computing C fft"); - evaluations.C = await Evaluations.fromPolynomial(polynomials.C, 4, curve, logger); - - // Check degrees - if (polynomials.A.degree() >= zkey.domainSize) { - throw new Error("A Polynomial is not well calculated"); - } - if (polynomials.B.degree() >= zkey.domainSize) { - throw new Error("B Polynomial is not well calculated"); - } - if (polynomials.C.degree() >= zkey.domainSize) { - throw new Error("C Polynomial is not well calculated"); - } - } - - async function computeT0() { - if (logger) logger.info(`··· Reading sections ${ZKEY_FF_QL_SECTION}, ${ZKEY_FF_QR_SECTION}` + - `, ${ZKEY_FF_QM_SECTION}, ${ZKEY_FF_QO_SECTION}, ${ZKEY_FF_QC_SECTION}. Q selectors`); - // Reserve memory for Q's evaluations - evaluations.QL = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QR = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QM = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QO = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - evaluations.QC = new Evaluations(new BigBuffer(sDomain * 4), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(evaluations.QL.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QL_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QR.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QR_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QM.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QM_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QO.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QO_SECTION][0].p + sDomain); - await fdZKey.readToBuffer(evaluations.QC.eval, 0, sDomain * 4, zkeySections[ZKEY_FF_QC_SECTION][0].p + sDomain); - - // Read Lagrange polynomials & evaluations from zkey file - const lagrangePolynomials = await readSection$1(fdZKey, zkeySections, ZKEY_FF_LAGRANGE_SECTION); - evaluations.lagrange1 = new Evaluations(lagrangePolynomials, curve, logger); - - // Reserve memory for buffers T0 - buffers.T0 = new BigBuffer(sDomain * 4); - - if (logger) logger.info("··· Computing T0 evaluations"); - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T0 evaluation ${i}/${zkey.domainSize * 4}`); - - // Get related evaluations to compute current T0 evaluation - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - - const ql = evaluations.QL.getEvaluation(i); - const qr = evaluations.QR.getEvaluation(i); - const qm = evaluations.QM.getEvaluation(i); - const qo = evaluations.QO.getEvaluation(i); - const qc = evaluations.QC.getEvaluation(i); - - // Compute current public input - let pi = Fr.zero; - for (let j = 0; j < zkey.nPublic; j++) { - const offset = (j * 5 * zkey.domainSize) + zkey.domainSize + i; - - const lPol = evaluations.lagrange1.getEvaluation(offset); - const aVal = buffers.A.slice(j * sFr, (j + 1) * sFr); - - pi = Fr.sub(pi, Fr.mul(lPol, aVal)); - } - - //T0(X) = [q_L(X)·a(X) + q_R(X)·b(X) + q_M(X)·a(X)·b(X) + q_O(X)·c(X) + q_C(X) + PI(X)] · 1/Z_H(X) - // Compute first T0(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - // expression 1 -> q_L(X)·a(X) - const e1 = Fr.mul(a, ql); - - // expression 2 -> q_R(X)·b(X) - const e2 = Fr.mul(b, qr); - - // expression 3 -> q_M(X)·a(X)·b(X) - const e3 = Fr.mul(Fr.mul(a, b), qm); - - // expression 4 -> q_O(X)·c(X) - const e4 = Fr.mul(c, qo); - - // t0 = expressions 1 + expression 2 + expression 3 + expression 4 + qc + pi - const t0 = Fr.add(e1, Fr.add(e2, Fr.add(e3, Fr.add(e4, Fr.add(qc, pi))))); - - buffers.T0.set(t0, i * sFr); - } - - if (logger) logger.info("buffer T0: " + buffers.T0.byteLength / sFr); - - // Compute the coefficients of the polynomial T0(X) from buffers.T0 - if (logger) logger.info("··· Computing T0 ifft"); - polynomials.T0 = await Polynomial.fromEvaluations(buffers.T0, curve, logger); - - if (logger) logger.info("T0 length: " + polynomials.T0.length()); - if (logger) logger.info("T0 degree: " + polynomials.T0.degree()); - - // Divide the polynomial T0 by Z_H(X) - if (logger) logger.info("··· Computing T0 / ZH"); - polynomials.T0.divByZerofier(zkey.domainSize, Fr.one); - - // Check degree - if (polynomials.T0.degree() >= 2 * zkey.domainSize - 2) { - throw new Error(`T0 Polynomial is not well calculated (degree is ${polynomials.T0.degree()} and must be less than ${2 * zkey.domainSize + 2}`); - } - - delete buffers.T0; - } - - async function computeC1() { - let C1 = new CPolynomial(4, curve, logger); - C1.addPolynomial(0, polynomials.A); - C1.addPolynomial(1, polynomials.B); - C1.addPolynomial(2, polynomials.C); - C1.addPolynomial(3, polynomials.T0); - - polynomials.C1 = C1.getPolynomial(); - - // Check degree - if (polynomials.C1.degree() >= 8 * zkey.domainSize - 8) { - throw new Error("C1 Polynomial is not well calculated"); - } - } - } - - async function round2() { - // STEP 2.1 - Compute permutation challenge beta and gamma ∈ F - // Compute permutation challenge beta - if (logger) logger.info("> Computing challenges beta and gamma"); - const transcript = new Keccak256Transcript(curve); - - // Add C0 to the transcript - transcript.addPolCommitment(zkey.C0); - - // Add A to the transcript - for (let i = 0; i < zkey.nPublic; i++) { - transcript.addScalar(buffers.A.slice(i * sFr, i * sFr + sFr)); - } - - // Add C1 to the transcript - transcript.addPolCommitment(proof.getPolynomial("C1")); - - challenges.beta = transcript.getChallenge(); - if (logger) logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); - - // Compute permutation challenge gamma - transcript.reset(); - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - if (logger) logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); - - // STEP 2.2 - Compute permutation polynomial z(X) - if (logger) logger.info("> Computing Z polynomial"); - await computeZ(); - - // STEP 2.3 - Compute quotient polynomial T1(X) and T2(X) - if (logger) logger.info("> Computing T1 polynomial"); - await computeT1(); - if (logger) logger.info("> Computing T2 polynomial"); - await computeT2(); - - // STEP 2.4 - Compute the FFT-style combination polynomial C2(X) - if (logger) logger.info("> Computing C2 polynomial"); - await computeC2(); - - // The second output of the prover is ([C2]_1) - if (logger) logger.info("> Computing C2 multi exponentiation"); - let commitC2 = await polynomials.C2.multiExponentiation(PTau, "C2"); - proof.addPolynomial("C2", commitC2); - - return 0; - - async function computeZ() { - if (logger) logger.info("··· Computing Z evaluations"); - - let numArr = new BigBuffer(sDomain); - let denArr = new BigBuffer(sDomain); - - // Set the first values to 1 - numArr.set(Fr.one, 0); - denArr.set(Fr.one, 0); - - // Set initial omega - let w = Fr.one; - for (let i = 0; i < zkey.domainSize; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` Z evaluation ${i}/${zkey.domainSize}`); - const i_sFr = i * sFr; - - // Z(X) := numArr / denArr - // numArr := (a + beta·ω + gamma)(b + beta·ω·k1 + gamma)(c + beta·ω·k2 + gamma) - const betaw = Fr.mul(challenges.beta, w); - - let num1 = buffers.A.slice(i_sFr, i_sFr + sFr); - num1 = Fr.add(num1, betaw); - num1 = Fr.add(num1, challenges.gamma); - - let num2 = buffers.B.slice(i_sFr, i_sFr + sFr); - num2 = Fr.add(num2, Fr.mul(zkey.k1, betaw)); - num2 = Fr.add(num2, challenges.gamma); - - let num3 = buffers.C.slice(i_sFr, i_sFr + sFr); - num3 = Fr.add(num3, Fr.mul(zkey.k2, betaw)); - num3 = Fr.add(num3, challenges.gamma); - - let num = Fr.mul(num1, Fr.mul(num2, num3)); - - // denArr := (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma) - let den1 = buffers.A.slice(i_sFr, i_sFr + sFr); - den1 = Fr.add(den1, Fr.mul(challenges.beta, evaluations.Sigma1.getEvaluation(i * 4))); - den1 = Fr.add(den1, challenges.gamma); - - let den2 = buffers.B.slice(i_sFr, i_sFr + sFr); - den2 = Fr.add(den2, Fr.mul(challenges.beta, evaluations.Sigma2.getEvaluation(i * 4))); - den2 = Fr.add(den2, challenges.gamma); - - let den3 = buffers.C.slice(i_sFr, i_sFr + sFr); - den3 = Fr.add(den3, Fr.mul(challenges.beta, evaluations.Sigma3.getEvaluation(i * 4))); - den3 = Fr.add(den3, challenges.gamma); - - let den = Fr.mul(den1, Fr.mul(den2, den3)); - - // Multiply current num value with the previous one saved in numArr - num = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), num); - numArr.set(num, ((i + 1) % zkey.domainSize) * sFr); - - // Multiply current den value with the previous one saved in denArr - den = Fr.mul(denArr.slice(i_sFr, i_sFr + sFr), den); - denArr.set(den, ((i + 1) % zkey.domainSize) * sFr); - - // Next omega - w = Fr.mul(w, Fr.w[zkey.power]); - } - // Compute the inverse of denArr to compute in the next command the - // division numArr/denArr by multiplying num · 1/denArr - denArr = await Fr.batchInverse(denArr); - - // TODO: Do it in assembly and in parallel - // Multiply numArr · denArr where denArr was inverted in the previous command - for (let i = 0; i < zkey.domainSize; i++) { - const i_sFr = i * sFr; - - const z = Fr.mul(numArr.slice(i_sFr, i_sFr + sFr), denArr.slice(i_sFr, i_sFr + sFr)); - numArr.set(z, i_sFr); - } - // From now on the values saved on numArr will be Z(X) buffer - buffers.Z = numArr; - - if (!Fr.eq(numArr.slice(0, sFr), Fr.one)) { - throw new Error("Copy constraints does not match"); - } - - // Compute polynomial coefficients z(X) from buffers.Z - if (logger) logger.info("··· Computing Z ifft"); - polynomials.Z = await Polynomial.fromEvaluations(buffers.Z, curve, logger); - - // Compute extended evaluations of z(X) polynomial - if (logger) logger.info("··· Computing Z fft"); - evaluations.Z = await Evaluations.fromPolynomial(polynomials.Z, 4, curve, logger); - - // Blind z(X) polynomial coefficients with blinding scalars b - polynomials.Z.blindCoefficients([challenges.b[9], challenges.b[8], challenges.b[7]]); - - // Check degree - if (polynomials.Z.degree() >= zkey.domainSize + 3) { - throw new Error("Z Polynomial is not well calculated"); - } - - delete buffers.Z; - } - - async function computeT1() { - if (logger) logger.info("··· Computing T1 evaluations"); - - buffers.T1 = new BigBuffer(sDomain * 2); - buffers.T1z = new BigBuffer(sDomain * 2); - - // Set initial omega - let omega = Fr.one; - for (let i = 0; i < zkey.domainSize * 2; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T1 evaluation ${i}/${zkey.domainSize * 4}`); - - const omega2 = Fr.square(omega); - - const z = evaluations.Z.getEvaluation(i * 2); - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); - - // T1(X) := (z(X) - 1) · L_1(X) - // Compute first T1(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - const lagrange1 = evaluations.lagrange1.getEvaluation(zkey.domainSize + i * 2); - let t1 = Fr.mul(Fr.sub(z, Fr.one), lagrange1); - let t1z = Fr.mul(zp, lagrange1); - - buffers.T1.set(t1, i * sFr); - buffers.T1z.set(t1z, i * sFr); - - // Compute next omega - omega = Fr.mul(omega, Fr.w[zkey.power + 1]); - } - - // Compute the coefficients of the polynomial T1(X) from buffers.T1 - if (logger) logger.info("··· Computing T1 ifft"); - polynomials.T1 = await Polynomial.fromEvaluations(buffers.T1, curve, logger); - - // Divide the polynomial T1 by Z_H(X) - polynomials.T1.divByZerofier(zkey.domainSize, Fr.one); - - // Compute the coefficients of the polynomial T1z(X) from buffers.T1z - if (logger) logger.info("··· Computing T1z ifft"); - polynomials.T1z = await Polynomial.fromEvaluations(buffers.T1z, curve, logger); - - // Add the polynomial T1z to T1 to get the final polynomial T1 - polynomials.T1.add(polynomials.T1z); - - // Check degree - if (polynomials.T1.degree() >= zkey.domainSize + 2) { - throw new Error("T1 Polynomial is not well calculated"); - } - - delete buffers.T1; - delete buffers.T1z; - delete polynomials.T1z; - } - - async function computeT2() { - if (logger) logger.info("··· Computing T2 evaluations"); - - buffers.T2 = new BigBuffer(sDomain * 4); - buffers.T2z = new BigBuffer(sDomain * 4); - - // Set initial omega - let omega = Fr.one; - for (let i = 0; i < zkey.domainSize * 4; i++) { - if (logger && (0 !== i) && (i % 100000 === 0)) logger.info(` T2 evaluation ${i}/${zkey.domainSize * 4}`); - - const omega2 = Fr.square(omega); - const omegaW = Fr.mul(omega, Fr.w[zkey.power]); - const omegaW2 = Fr.square(omegaW); - - const a = evaluations.A.getEvaluation(i); - const b = evaluations.B.getEvaluation(i); - const c = evaluations.C.getEvaluation(i); - const z = evaluations.Z.getEvaluation(i); - const zW = evaluations.Z.getEvaluation((zkey.domainSize * 4 + 4 + i) % (zkey.domainSize * 4)); - - const zp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omega2), Fr.mul(challenges.b[8], omega)), challenges.b[9]); - const zWp = Fr.add(Fr.add(Fr.mul(challenges.b[7], omegaW2), Fr.mul(challenges.b[8], omegaW)), challenges.b[9]); - - const sigma1 = evaluations.Sigma1.getEvaluation(i); - const sigma2 = evaluations.Sigma2.getEvaluation(i); - const sigma3 = evaluations.Sigma3.getEvaluation(i); - - // T2(X) := [ (a(X) + beta·X + gamma)(b(X) + beta·k1·X + gamma)(c(X) + beta·k2·X + gamma)z(X) - // -(a(X) + beta·sigma1(X) + gamma)(b(X) + beta·sigma2(X) + gamma)(c(X) + beta·sigma3(X) + gamma)z(Xω)] · 1/Z_H(X) - // Compute first T2(X)·Z_H(X), so divide later the resulting polynomial by Z_H(X) - - // expression 1 -> (a(X) + beta·X + gamma)(b(X) + beta·k1·X + gamma)(c(X) + beta·k2·X + gamma)z(X) - const betaX = Fr.mul(challenges.beta, omega); - - let e11 = Fr.add(a, betaX); - e11 = Fr.add(e11, challenges.gamma); - - let e12 = Fr.add(b, Fr.mul(betaX, zkey.k1)); - e12 = Fr.add(e12, challenges.gamma); - - let e13 = Fr.add(c, Fr.mul(betaX, zkey.k2)); - e13 = Fr.add(e13, challenges.gamma); - - let e1 = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), z); - let e1z = Fr.mul(Fr.mul(Fr.mul(e11, e12), e13), zp); - // const [e1, e1z] = MulZ.mul4(e11, e12, e13, z, ap, bp, cp, zp, i % 4, Fr); - - // expression 2 -> (a(X) + beta·sigma1(X) + gamma)(b(X) + beta·sigma2(X) + gamma)(c(X) + beta·sigma3(X) + gamma)z(Xω) - let e21 = Fr.add(a, Fr.mul(challenges.beta, sigma1)); - e21 = Fr.add(e21, challenges.gamma); - - let e22 = Fr.add(b, Fr.mul(challenges.beta, sigma2)); - e22 = Fr.add(e22, challenges.gamma); - - let e23 = Fr.add(c, Fr.mul(challenges.beta, sigma3)); - e23 = Fr.add(e23, challenges.gamma); - - let e2 = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zW); - let e2z = Fr.mul(Fr.mul(Fr.mul(e21, e22), e23), zWp); - // const [e2, e2z] = MulZ.mul4(e21, e22, e23, zW, ap, bp, cp, zWp, i % 4, Fr); - - let t2 = Fr.sub(e1, e2); - let t2z = Fr.sub(e1z, e2z); - - buffers.T2.set(t2, i * sFr); - buffers.T2z.set(t2z, i * sFr); - - // Compute next omega - omega = Fr.mul(omega, Fr.w[zkey.power + 2]); - } - - // Compute the coefficients of the polynomial T2(X) from buffers.T2 - if (logger) logger.info("··· Computing T2 ifft"); - polynomials.T2 = await Polynomial.fromEvaluations(buffers.T2, curve, logger); - - // Divide the polynomial T2 by Z_H(X) - if (logger) logger.info("··· Computing T2 / ZH"); - polynomials.T2.divByZerofier(zkey.domainSize, Fr.one); - - // Compute the coefficients of the polynomial T2z(X) from buffers.T2z - if (logger) logger.info("··· Computing T2z ifft"); - polynomials.T2z = await Polynomial.fromEvaluations(buffers.T2z, curve, logger); - - // Add the polynomial T2z to T2 to get the final polynomial T2 - polynomials.T2.add(polynomials.T2z); - - // Check degree - if (polynomials.T2.degree() >= 3 * zkey.domainSize) { - throw new Error("T2 Polynomial is not well calculated"); - } - - delete buffers.T2; - delete buffers.T2z; - delete polynomials.T2z; - } - - async function computeC2() { - let C2 = new CPolynomial(3, curve, logger); - C2.addPolynomial(0, polynomials.Z); - C2.addPolynomial(1, polynomials.T1); - C2.addPolynomial(2, polynomials.T2); - - polynomials.C2 = C2.getPolynomial(); - - // Check degree - if (polynomials.C2.degree() >= 9 * zkey.domainSize) { - throw new Error("C2 Polynomial is not well calculated"); - } - } - } - - async function round3() { - if (logger) logger.info("> Computing challenge xi"); - // STEP 3.1 - Compute evaluation challenge xi ∈ S - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.getPolynomial("C2")); - - // Obtain a xi_seeder from the transcript - // To force h1^4 = xi, h2^3 = xi and h_3^2 = xiω - // we compute xi = xi_seeder^12, h1 = xi_seeder^3, h2 = xi_seeder^4 and h3 = xi_seeder^6 - challenges.xiSeed = transcript.getChallenge(); - const xiSeed2 = Fr.square(challenges.xiSeed); - - // Compute omega8, omega4 and omega3 - roots.w8 = []; - roots.w8[0] = Fr.one; - for (let i = 1; i < 8; i++) { - roots.w8[i] = Fr.mul(roots.w8[i - 1], zkey.w8); - } - - roots.w4 = []; - roots.w4[0] = Fr.one; - for (let i = 1; i < 4; i++) { - roots.w4[i] = Fr.mul(roots.w4[i - 1], zkey.w4); - } - - roots.w3 = []; - roots.w3[0] = Fr.one; - roots.w3[1] = zkey.w3; - roots.w3[2] = Fr.square(zkey.w3); - - // Compute h0 = xiSeeder^3 - roots.S0 = {}; - roots.S0.h0w8 = []; - roots.S0.h0w8[0] = Fr.mul(xiSeed2, challenges.xiSeed); - for (let i = 1; i < 8; i++) { - roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], roots.w8[i]); - } - - // Compute h1 = xi_seeder^6 - roots.S1 = {}; - roots.S1.h1w4 = []; - roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); - for (let i = 1; i < 4; i++) { - roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], roots.w4[i]); - } - - // Compute h2 = xi_seeder^8 - roots.S2 = {}; - roots.S2.h2w3 = []; - roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); - roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], roots.w3[1]); - roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], roots.w3[2]); - - roots.S2.h3w3 = []; - // Multiply h3 by third-root-omega to obtain h_3^3 = xiω - // So, h3 = xi_seeder^8 ω^{1/3} - roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], zkey.wr); - roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], roots.w3[1]); - roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], roots.w3[2]); - - // Compute xi = xi_seeder^24 - challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); - - if (logger) logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); - - // Reserve memory for Q's polynomials - polynomials.QL = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QR = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QM = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QO = new Polynomial(new BigBuffer(sDomain), curve, logger); - polynomials.QC = new Polynomial(new BigBuffer(sDomain), curve, logger); - - // Read Q's evaluations from zkey file - await fdZKey.readToBuffer(polynomials.QL.coef, 0, sDomain, zkeySections[ZKEY_FF_QL_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QR.coef, 0, sDomain, zkeySections[ZKEY_FF_QR_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QM.coef, 0, sDomain, zkeySections[ZKEY_FF_QM_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QO.coef, 0, sDomain, zkeySections[ZKEY_FF_QO_SECTION][0].p); - await fdZKey.readToBuffer(polynomials.QC.coef, 0, sDomain, zkeySections[ZKEY_FF_QC_SECTION][0].p); - - // STEP 3.2 - Compute opening evaluations and add them to the proof (third output of the prover) - if (logger) logger.info("··· Computing evaluations"); - proof.addEvaluation("ql", polynomials.QL.evaluate(challenges.xi)); - proof.addEvaluation("qr", polynomials.QR.evaluate(challenges.xi)); - proof.addEvaluation("qm", polynomials.QM.evaluate(challenges.xi)); - proof.addEvaluation("qo", polynomials.QO.evaluate(challenges.xi)); - proof.addEvaluation("qc", polynomials.QC.evaluate(challenges.xi)); - proof.addEvaluation("s1", polynomials.Sigma1.evaluate(challenges.xi)); - proof.addEvaluation("s2", polynomials.Sigma2.evaluate(challenges.xi)); - proof.addEvaluation("s3", polynomials.Sigma3.evaluate(challenges.xi)); - proof.addEvaluation("a", polynomials.A.evaluate(challenges.xi)); - proof.addEvaluation("b", polynomials.B.evaluate(challenges.xi)); - proof.addEvaluation("c", polynomials.C.evaluate(challenges.xi)); - proof.addEvaluation("z", polynomials.Z.evaluate(challenges.xi)); - - challenges.xiw = Fr.mul(challenges.xi, Fr.w[zkey.power]); - proof.addEvaluation("zw", polynomials.Z.evaluate(challenges.xiw)); - proof.addEvaluation("t1w", polynomials.T1.evaluate(challenges.xiw)); - proof.addEvaluation("t2w", polynomials.T2.evaluate(challenges.xiw)); - } - - async function round4() { - if (logger) logger.info("> Computing challenge alpha"); - // STEP 4.1 - Compute challenge alpha ∈ F - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.xiSeed); - transcript.addScalar(proof.getEvaluation("ql")); - transcript.addScalar(proof.getEvaluation("qr")); - transcript.addScalar(proof.getEvaluation("qm")); - transcript.addScalar(proof.getEvaluation("qo")); - transcript.addScalar(proof.getEvaluation("qc")); - transcript.addScalar(proof.getEvaluation("s1")); - transcript.addScalar(proof.getEvaluation("s2")); - transcript.addScalar(proof.getEvaluation("s3")); - transcript.addScalar(proof.getEvaluation("a")); - transcript.addScalar(proof.getEvaluation("b")); - transcript.addScalar(proof.getEvaluation("c")); - transcript.addScalar(proof.getEvaluation("z")); - transcript.addScalar(proof.getEvaluation("zw")); - transcript.addScalar(proof.getEvaluation("t1w")); - transcript.addScalar(proof.getEvaluation("t2w")); - challenges.alpha = transcript.getChallenge(); - if (logger) logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); - - // STEP 4.2 - Compute F(X) - if (logger) logger.info("> Reading C0 polynomial"); - polynomials.C0 = new Polynomial(new BigBuffer(sDomain * 8), curve, logger); - await fdZKey.readToBuffer(polynomials.C0.coef, 0, sDomain * 8, zkeySections[ZKEY_FF_C0_SECTION][0].p); - - if (logger) logger.info("> Computing R0 polynomial"); - computeR0(); - if (logger) logger.info("> Computing R1 polynomial"); - computeR1(); - if (logger) logger.info("> Computing R2 polynomial"); - computeR2(); - - if (logger) logger.info("> Computing F polynomial"); - await computeF(); - - // The fourth output of the prover is ([W1]_1), where W1:=(f/Z_t)(x) - if (logger) logger.info("> Computing W1 multi exponentiation"); - let commitW1 = await polynomials.F.multiExponentiation(PTau, "W1"); - proof.addPolynomial("W1", commitW1); - - return 0; - - function computeR0() { - // COMPUTE R0 - // Compute the coefficients of R0(X) from 8 evaluations using lagrange interpolation. R0(X) ∈ F_{<8}[X] - // We decide to use Lagrange interpolations because the R0 degree is very small (deg(R0)===7), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R0 = Polynomial.lagrangePolynomialInterpolation( - [roots.S0.h0w8[0], roots.S0.h0w8[1], roots.S0.h0w8[2], roots.S0.h0w8[3], - roots.S0.h0w8[4], roots.S0.h0w8[5], roots.S0.h0w8[6], roots.S0.h0w8[7]], - [polynomials.C0.evaluate(roots.S0.h0w8[0]), polynomials.C0.evaluate(roots.S0.h0w8[1]), - polynomials.C0.evaluate(roots.S0.h0w8[2]), polynomials.C0.evaluate(roots.S0.h0w8[3]), - polynomials.C0.evaluate(roots.S0.h0w8[4]), polynomials.C0.evaluate(roots.S0.h0w8[5]), - polynomials.C0.evaluate(roots.S0.h0w8[6]), polynomials.C0.evaluate(roots.S0.h0w8[7])], curve); - - // Check the degree of r0(X) < 8 - if (polynomials.R0.degree() > 7) { - throw new Error("R0 Polynomial is not well calculated"); - } - } - - function computeR1() { - // COMPUTE R1 - // Compute the coefficients of R1(X) from 4 evaluations using lagrange interpolation. R1(X) ∈ F_{<4}[X] - // We decide to use Lagrange interpolations because the R1 degree is very small (deg(R1)===3), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R1 = Polynomial.lagrangePolynomialInterpolation( - [roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3]], - [polynomials.C1.evaluate(roots.S1.h1w4[0]), polynomials.C1.evaluate(roots.S1.h1w4[1]), - polynomials.C1.evaluate(roots.S1.h1w4[2]), polynomials.C1.evaluate(roots.S1.h1w4[3])], curve); - - // Check the degree of r1(X) < 4 - if (polynomials.R1.degree() > 3) { - throw new Error("R1 Polynomial is not well calculated"); - } - } - - function computeR2() { - // COMPUTE R2 - // Compute the coefficients of r2(X) from 6 evaluations using lagrange interpolation. r2(X) ∈ F_{<6}[X] - // We decide to use Lagrange interpolations because the R2.degree is very small (deg(R2)===5), - // and we were not able to compute it using current ifft implementation because the omega are different - polynomials.R2 = Polynomial.lagrangePolynomialInterpolation( - [roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], - [polynomials.C2.evaluate(roots.S2.h2w3[0]), polynomials.C2.evaluate(roots.S2.h2w3[1]), - polynomials.C2.evaluate(roots.S2.h2w3[2]), polynomials.C2.evaluate(roots.S2.h3w3[0]), - polynomials.C2.evaluate(roots.S2.h3w3[1]), polynomials.C2.evaluate(roots.S2.h3w3[2])], curve); - - // Check the degree of r2(X) < 6 - if (polynomials.R2.degree() > 5) { - throw new Error("R2 Polynomial is not well calculated"); - } - } - - async function computeF() { - if (logger) logger.info("··· Computing F polynomial"); - - // COMPUTE F(X) - polynomials.F = Polynomial.fromPolynomial(polynomials.C0, curve, logger); - polynomials.F.sub(polynomials.R0); - polynomials.F.divByZerofier(8, challenges.xi); - - let f2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); - f2.sub(polynomials.R1); - f2.mulScalar(challenges.alpha); - f2.divByZerofier(4, challenges.xi); - - let f3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); - f3.sub(polynomials.R2); - f3.mulScalar(Fr.square(challenges.alpha)); - f3.divByZerofier(3, challenges.xi); - f3.divByZerofier(3, challenges.xiw); - - polynomials.F.add(f2); - polynomials.F.add(f3); - - if (polynomials.F.degree() >= 9 * zkey.domainSize - 6) { - throw new Error("F Polynomial is not well calculated"); - } - } - } - - async function round5() { - if (logger) logger.info("> Computing challenge y"); - - // STEP 5.1 - Compute random evaluation point y ∈ F - const transcript = new Keccak256Transcript(curve); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.getPolynomial("W1")); - - challenges.y = transcript.getChallenge(); - if (logger) logger.info("··· challenges.y: " + Fr.toString(challenges.y)); - - // STEP 5.2 - Compute L(X) - if (logger) logger.info("> Computing L polynomial"); - await computeL(); - - if (logger) logger.info("> Computing ZTS2 polynomial"); - await computeZTS2(); - - let ZTS2Y = polynomials.ZTS2.evaluate(challenges.y); - ZTS2Y = Fr.inv(ZTS2Y); - polynomials.L.mulScalar(ZTS2Y); - - const polDividend = Polynomial.fromCoefficientsArray([Fr.neg(challenges.y), Fr.one], curve); - if (logger) logger.info("> Computing W' = L / ZTS2 polynomial"); - const polRemainder = polynomials.L.divBy(polDividend); - - //Check polReminder degree is equal to zero - if (polRemainder.degree() > 0) { - throw new Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${polRemainder.degree()} and should be 0`); - } - - if (polynomials.L.degree() >= 9 * zkey.domainSize - 1) { - throw new Error("Degree of L(X)/(ZTS2(y)(X-y)) is not correct"); - } - - // The fifth output of the prover is ([W2]_1), where W2:=(f/Z_t)(x) - if (logger) logger.info("> Computing W' multi exponentiation"); - let commitW2 = await polynomials.L.multiExponentiation(PTau, "W2"); - proof.addPolynomial("W2", commitW2); - - return 0; - - async function computeL() { - if (logger) logger.info("··· Computing L polynomial"); - - const evalR0Y = polynomials.R0.evaluate(challenges.y); - const evalR1Y = polynomials.R1.evaluate(challenges.y); - const evalR2Y = polynomials.R2.evaluate(challenges.y); - - let mulL0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); - for (let i = 1; i < 8; i++) { - mulL0 = Fr.mul(mulL0, Fr.sub(challenges.y, roots.S0.h0w8[i])); - } - - let mulL1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); - for (let i = 1; i < 4; i++) { - mulL1 = Fr.mul(mulL1, Fr.sub(challenges.y, roots.S1.h1w4[i])); - } - - let mulL2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); - for (let i = 1; i < 3; i++) { - mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h2w3[i])); - } - for (let i = 0; i < 3; i++) { - mulL2 = Fr.mul(mulL2, Fr.sub(challenges.y, roots.S2.h3w3[i])); - } - - let preL0 = Fr.mul(mulL1, mulL2); - let preL1 = Fr.mul(challenges.alpha, Fr.mul(mulL0, mulL2)); - let preL2 = Fr.mul(Fr.square(challenges.alpha), Fr.mul(mulL0, mulL1)); - - toInverse["denH1"] = mulL1; - toInverse["denH2"] = mulL2; - - // COMPUTE L(X) - polynomials.L = Polynomial.fromPolynomial(polynomials.C0, curve, logger); - polynomials.L.subScalar(evalR0Y); - polynomials.L.mulScalar(preL0); - - let l2 = Polynomial.fromPolynomial(polynomials.C1, curve, logger); - l2.subScalar(evalR1Y); - l2.mulScalar(preL1); - - let l3 = Polynomial.fromPolynomial(polynomials.C2, curve, logger); - l3.subScalar(evalR2Y); - l3.mulScalar(preL2); - - polynomials.L.add(l2); - polynomials.L.add(l3); - - if (logger) logger.info("> Computing ZT polynomial"); - await computeZT(); - - const evalZTY = polynomials.ZT.evaluate(challenges.y); - polynomials.F.mulScalar(evalZTY); - polynomials.L.sub(polynomials.F); - - // Check degree - if (polynomials.L.degree() >= 9 * zkey.domainSize) { - throw new Error("L Polynomial is not well calculated"); - } - - delete buffers.L; - } - - async function computeZT() { - polynomials.ZT = Polynomial.zerofierPolynomial( - [ - roots.S0.h0w8[0], roots.S0.h0w8[1], roots.S0.h0w8[2], roots.S0.h0w8[3], - roots.S0.h0w8[4], roots.S0.h0w8[5], roots.S0.h0w8[6], roots.S0.h0w8[7], - roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3], - roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], curve); - } - - async function computeZTS2() { - polynomials.ZTS2 = Polynomial.zerofierPolynomial( - [roots.S1.h1w4[0], roots.S1.h1w4[1], roots.S1.h1w4[2], roots.S1.h1w4[3], - roots.S2.h2w3[0], roots.S2.h2w3[1], roots.S2.h2w3[2], - roots.S2.h3w3[0], roots.S2.h3w3[1], roots.S2.h3w3[2]], curve); - } - } - - function getMontgomeryBatchedInverse() { - // · denominator needed in step 8 and 9 of the verifier to multiply by 1/Z_H(xi) - let xiN = challenges.xi; - for (let i = 0; i < zkey.power; i++) { - xiN = Fr.square(xiN); - } - toInverse["zh"] = Fr.sub(xiN, Fr.one); - - // · denominator needed in step 10 and 11 of the verifier - // toInverse.denH1 & toInverse.denH2 -> Computed in round5, computeL() - - // · denominator needed in the verifier when computing L_i^{S0}(X), L_i^{S1}(X) and L_i^{S2}(X) - computeLiS0(toInverse, roots.S0.h0w8, challenges.y, curve); - - computeLiS1(toInverse, roots.S1.h1w4, challenges.y, curve); - - computeLiS2(toInverse, roots.S2.h2w3, roots.S2.h3w3, challenges.y, challenges.xi, challenges.xiw, curve); - - // · L_i i=1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) - const size = Math.max(1, zkey.nPublic); - - let w = Fr.one; - for (let i = 0; i < size; i++) { - toInverse["Li_" + (i + 1)] = Fr.mul(Fr.e(zkey.domainSize), Fr.sub(challenges.xi, w)); - w = Fr.mul(w, Fr.w[zkey.power]); - } - - let mulAccumulator = Fr.one; - for (const element of Object.values(toInverse)) { - if(Array.isArray(element)) { - for (const subElement of element) { - mulAccumulator = Fr.mul(mulAccumulator, subElement); - } - } else { - mulAccumulator = Fr.mul(mulAccumulator, element); - } - } - return Fr.inv(mulAccumulator); - - - function computeLiS0(toInverse, roots, x, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - toInverse[["LiS0_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); - } - - return Li; - } - - function computeLiS1(toInverse, roots, x, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - toInverse[["LiS1_" + (i + 1)]] = Fr.mul(Fr.mul(den1, den2), den3); - - } - - return Li; - } - - function computeLiS2(toInverse, S2, S2p, value, xi, xiw, curve) { - const Fr = curve.Fr; - - const Li = []; - - const _3h2 = Fr.mul(Fr.e(3), S2[0]); - const xisubxiw = Fr.sub(xi, xiw); - let den1 = Fr.mul(_3h2, xisubxiw); - for (let i = 0; i < 3; i++) { - const den2 = S2[2 * i % 3]; - const den3 = Fr.sub(value, S2[i]); - - toInverse[["LiS2_" + (i + 1)]] = Fr.mul(den1,Fr.mul(den2, den3)); - - } - - const _3h3 = Fr.mul(Fr.e(3), S2p[0]); - const xiwsubxi = Fr.sub(xiw, xi); - den1 = Fr.mul(_3h3, xiwsubxi); - for (let i = 0; i < 3; i++) { - const den2 = S2p[2 * i % 3]; - const den3 = Fr.sub(value, S2p[i]); - - toInverse[["LiS2_" + (i + 1 + 3)]] = Fr.mul(den1,Fr.mul(den2, den3)); - } - - return Li; - } - } - } - - /* - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - const {unstringifyBigInts: unstringifyBigInts$2} = utils; - - async function fflonkFullProve(_input, wasmFilename, zkeyFilename, logger, wtnsCalcOptions, proverOptions) { - const input = unstringifyBigInts$2(_input); - - const wtns= {type: "mem"}; - - // Compute the witness - await wtnsCalculate(input, wasmFilename, wtns, wtnsCalcOptions); - - // Compute the proof - return await fflonkProve(zkeyFilename, wtns, logger, proverOptions); - } - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - - const { unstringifyBigInts: unstringifyBigInts$1 } = utils; - - async function fflonkVerify(_vk_verifier, _publicSignals, _proof, logger) { - if (logger) logger.info("FFLONK VERIFIER STARTED"); - - _vk_verifier = unstringifyBigInts$1(_vk_verifier); - _proof = unstringifyBigInts$1(_proof); - - const curve = await getCurveFromName(_vk_verifier.curve); - - const vk = fromObjectVk(curve, _vk_verifier); - - // TODO ??? Compute wr^3 and check if it matches with w - - const proof = new Proof(curve, logger); - proof.fromObjectProof(_proof); - - const publicSignals = unstringifyBigInts$1(_publicSignals); - - if (publicSignals.length !== vk.nPublic) { - logger.error("Number of public signals does not match with vk"); - return false; - } - - const Fr = curve.Fr; - - if (logger) { - logger.info("----------------------------"); - logger.info(" FFLONK VERIFY SETTINGS"); - logger.info(` Curve: ${curve.name}`); - logger.info(` Circuit power: ${vk.power}`); - logger.info(` Domain size: ${2 ** vk.power}`); - logger.info(` Public vars: ${vk.nPublic}`); - logger.info("----------------------------"); - } - - // STEP 1 - Validate that all polynomial commitments ∈ G_1 - if (logger) logger.info("> Checking commitments belong to G1"); - if (!commitmentsBelongToG1(curve, proof, vk)) { - if (logger) logger.error("Proof commitments are not valid"); - return false; - } - - // STEP 2 - Validate that all evaluations ∈ F - if (logger) logger.info("> Checking evaluations belong to F"); - if (!evaluationsAreValid(curve, proof)) { - if (logger) logger.error("Proof evaluations are not valid."); - return false; - } - - // STEP 3 - Validate that w_i ∈ F for i ∈ [l] - if (logger) logger.info("> Checking public inputs belong to F"); - if (!publicInputsAreValid(curve, publicSignals)) { - if (logger) logger.error("Public inputs are not valid."); - return false; - } - - // STEP 4 - Compute the challenges: beta, gamma, xi, alpha and y ∈ F - // as in prover description, from the common preprocessed inputs, public inputs and elements of π_SNARK - if (logger) logger.info("> Computing challenges"); - const { challenges, roots } = computeChallenges(curve, proof, vk, publicSignals, logger); - - // STEP 5 - Compute the zero polynomial evaluation Z_H(xi) = xi^n - 1 - if (logger) logger.info("> Computing Zero polynomial evaluation Z_H(xi)"); - challenges.zh = Fr.sub(challenges.xiN, Fr.one); - challenges.invzh = Fr.inv(challenges.zh); - - // STEP 6 - Compute the lagrange polynomial evaluation L_1(xi) - if (logger) logger.info("> Computing Lagrange evaluations"); - const lagrangeEvals = await computeLagrangeEvaluations(curve, challenges, vk); - - // STEP 7 - Compute public input evaluation PI(xi) - if (logger) logger.info("> Computing polynomial identities PI(X)"); - const pi = calculatePI(curve, publicSignals, lagrangeEvals); - - // STEP 8 - Compute polynomial r0 ∈ F_{<4}[X] - if (logger) logger.info("> Computing r0(y)"); - const r0 = computeR0(proof, challenges, roots, curve, logger); - - // STEP 9 - Compute polynomial r1 ∈ F_{<4}[X] - if (logger) logger.info("> Computing r1(y)"); - const r1 = computeR1(proof, challenges, roots, pi, curve, logger); - - // STEP 9 - Compute polynomial r2 ∈ F_{<6}[X] - if (logger) logger.info("> Computing r2(y)"); - const r2 = computeR2(proof, challenges, roots, lagrangeEvals[1], vk, curve, logger); - - if (logger) logger.info("> Computing F"); - const F = computeF(curve, proof, vk, challenges, roots); - - if (logger) logger.info("> Computing E"); - const E = computeE(curve, proof, challenges, vk, r0, r1, r2); - - if (logger) logger.info("> Computing J"); - const J = computeJ(curve, proof, challenges); - - if (logger) logger.info("> Validate all evaluations with a pairing"); - const res = await isValidPairing(curve, proof, challenges, vk, F, E, J); - - if (logger) { - if (res) { - logger.info("PROOF VERIFIED SUCCESSFULLY"); - } else { - logger.warn("Invalid Proof"); - } - } - - if (logger) logger.info("FFLONK VERIFIER FINISHED"); - - return res; - - } - - function fromObjectVk(curve, vk) { - const res = vk; - res.k1 = curve.Fr.fromObject(vk.k1); - res.k2 = curve.Fr.fromObject(vk.k2); - res.w = curve.Fr.fromObject(vk.w); - // res.wW = curve.Fr.fromObject(vk.wW); - res.w3 = curve.Fr.fromObject(vk.w3); - res.w4 = curve.Fr.fromObject(vk.w4); - res.w8 = curve.Fr.fromObject(vk.w8); - res.wr = curve.Fr.fromObject(vk.wr); - res.X_2 = curve.G2.fromObject(vk.X_2); - res.C0 = curve.G1.fromObject(vk.C0); - return res; - } - - function commitmentsBelongToG1(curve, proof, vk) { - const G1 = curve.G1; - return G1.isValid(proof.polynomials.C1) - && G1.isValid(proof.polynomials.C2) - && G1.isValid(proof.polynomials.W1) - && G1.isValid(proof.polynomials.W2) - && G1.isValid(vk.C0); - } - - function checkValueBelongToField(curve, value) { - return Scalar.geq(value, 0) && Scalar.lt(value, curve.r); - } - - function checkEvaluationIsValid(curve, evaluation) { - return checkValueBelongToField(curve, Scalar.fromRprLE(evaluation)); - } - - function evaluationsAreValid(curve, proof) { - return checkEvaluationIsValid(curve, proof.evaluations.ql) - && checkEvaluationIsValid(curve, proof.evaluations.qr) - && checkEvaluationIsValid(curve, proof.evaluations.qm) - && checkEvaluationIsValid(curve, proof.evaluations.qo) - && checkEvaluationIsValid(curve, proof.evaluations.qc) - && checkEvaluationIsValid(curve, proof.evaluations.s1) - && checkEvaluationIsValid(curve, proof.evaluations.s2) - && checkEvaluationIsValid(curve, proof.evaluations.s3) - && checkEvaluationIsValid(curve, proof.evaluations.a) - && checkEvaluationIsValid(curve, proof.evaluations.b) - && checkEvaluationIsValid(curve, proof.evaluations.c) - && checkEvaluationIsValid(curve, proof.evaluations.z) - && checkEvaluationIsValid(curve, proof.evaluations.zw) - && checkEvaluationIsValid(curve, proof.evaluations.t1w) - && checkEvaluationIsValid(curve, proof.evaluations.t2w); - } - - function publicInputsAreValid(curve, publicInputs) { - for(let i = 0; i < publicInputs.length; i++) { - if(!checkValueBelongToField(curve, publicInputs[i])) { - return false; - } - } - return true; - } - - function computeChallenges(curve, proof, vk, publicSignals, logger) { - const Fr = curve.Fr; - - const challenges = {}; - const roots = {}; - const transcript = new Keccak256Transcript(curve); - - // Add C0 to the transcript - transcript.addPolCommitment(vk.C0); - - for (let i = 0; i < publicSignals.length; i++) { - transcript.addScalar(Fr.e(publicSignals[i])); - } - - transcript.addPolCommitment(proof.polynomials.C1); - challenges.beta = transcript.getChallenge(); - transcript.reset(); - - transcript.addScalar(challenges.beta); - challenges.gamma = transcript.getChallenge(); - - transcript.reset(); - transcript.addScalar(challenges.gamma); - transcript.addPolCommitment(proof.polynomials.C2); - const xiSeed = transcript.getChallenge(); - const xiSeed2 = Fr.square(xiSeed); - - let w8 = []; - w8[1] = vk.w8; - w8[2] = Fr.square(vk.w8); - w8[3] = Fr.mul(w8[2], vk.w8); - w8[4] = Fr.mul(w8[3], vk.w8); - w8[5] = Fr.mul(w8[4], vk.w8); - w8[6] = Fr.mul(w8[5], vk.w8); - w8[7] = Fr.mul(w8[6], vk.w8); - let w4 = []; - w4[1] = vk.w4; - w4[2] = Fr.square(vk.w4); - w4[3] = Fr.mul(w4[2], vk.w4); - let w3 = []; - w3[1] = vk.w3; - w3[2] = Fr.square(vk.w3); - - // const w4_2 = Fr.square(vk.w4); - // const w4_3 = Fr.mul(w4_2, vk.w4); - // const w3_2 = Fr.square(vk.w3); - - // Compute h0 = xiSeeder^3 - roots.S0 = {}; - roots.S0.h0w8 = []; - roots.S0.h0w8[0] = Fr.mul(xiSeed2, xiSeed); - for (let i = 1; i < 8; i++) { - roots.S0.h0w8[i] = Fr.mul(roots.S0.h0w8[0], w8[i]); - } - - // Compute h1 = xi_seeder^6 - roots.S1 = {}; - roots.S1.h1w4 = []; - roots.S1.h1w4[0] = Fr.square(roots.S0.h0w8[0]); - for (let i = 1; i < 4; i++) { - roots.S1.h1w4[i] = Fr.mul(roots.S1.h1w4[0], w4[i]); - } - - // Compute h2 = xi_seeder^8 - roots.S2 = {}; - roots.S2.h2w3 = []; - roots.S2.h2w3[0] = Fr.mul(roots.S1.h1w4[0], xiSeed2); - roots.S2.h2w3[1] = Fr.mul(roots.S2.h2w3[0], w3[1]); - roots.S2.h2w3[2] = Fr.mul(roots.S2.h2w3[0], w3[2]); - - roots.S2.h3w3 = []; - // Multiply h3 by third-root-omega to obtain h_3^3 = xiω - // So, h3 = xi_seeder^8 ω^{1/3} - roots.S2.h3w3[0] = Fr.mul(roots.S2.h2w3[0], vk.wr); - roots.S2.h3w3[1] = Fr.mul(roots.S2.h3w3[0], w3[1]); - roots.S2.h3w3[2] = Fr.mul(roots.S2.h3w3[0], w3[2]); - - // Compute xi = xi_seeder^12 - challenges.xi = Fr.mul(Fr.square(roots.S2.h2w3[0]), roots.S2.h2w3[0]); - challenges.xiw = Fr.mul(challenges.xi, Fr.w[vk.power]); - - challenges.xiN = challenges.xi; - vk.domainSize = 1; - for (let i = 0; i < vk.power; i++) { - challenges.xiN = Fr.square(challenges.xiN); - vk.domainSize *= 2; - } - - transcript.reset(); - transcript.addScalar(xiSeed); - transcript.addScalar(proof.evaluations.ql); - transcript.addScalar(proof.evaluations.qr); - transcript.addScalar(proof.evaluations.qm); - transcript.addScalar(proof.evaluations.qo); - transcript.addScalar(proof.evaluations.qc); - transcript.addScalar(proof.evaluations.s1); - transcript.addScalar(proof.evaluations.s2); - transcript.addScalar(proof.evaluations.s3); - transcript.addScalar(proof.evaluations.a); - transcript.addScalar(proof.evaluations.b); - transcript.addScalar(proof.evaluations.c); - transcript.addScalar(proof.evaluations.z); - transcript.addScalar(proof.evaluations.zw); - transcript.addScalar(proof.evaluations.t1w); - transcript.addScalar(proof.evaluations.t2w); - challenges.alpha = transcript.getChallenge(); - - transcript.reset(); - transcript.addScalar(challenges.alpha); - transcript.addPolCommitment(proof.polynomials.W1); - challenges.y = transcript.getChallenge(); - - if (logger) { - logger.info("··· challenges.beta: " + Fr.toString(challenges.beta)); - logger.info("··· challenges.gamma: " + Fr.toString(challenges.gamma)); - logger.info("··· challenges.xi: " + Fr.toString(challenges.xi)); - logger.info("··· challenges.alpha: " + Fr.toString(challenges.alpha)); - logger.info("··· challenges.y: " + Fr.toString(challenges.y)); - } - - return { challenges: challenges, roots: roots }; - } - - async function computeLagrangeEvaluations(curve, challenges, vk) { - const Fr = curve.Fr; - - const size = Math.max(1, vk.nPublic); - const numArr = new BigBuffer(size * Fr.n8); - let denArr = new BigBuffer(size * Fr.n8); - - let w = Fr.one; - for (let i = 0; i < size; i++) { - const i_sFr = i * Fr.n8; - numArr.set(Fr.mul(w, challenges.zh), i_sFr); - denArr.set(Fr.mul(Fr.e(vk.domainSize), Fr.sub(challenges.xi, w)), i_sFr); - w = Fr.mul(w, vk.w); - } - - denArr = await Fr.batchInverse(denArr); - - let L = []; - for (let i = 0; i < size; i++) { - const i_sFr = i * Fr.n8; - L[i + 1] = Fr.mul(numArr.slice(i_sFr, i_sFr + Fr.n8), denArr.slice(i_sFr, i_sFr + Fr.n8)); - } - return L; - } - - function calculatePI(curve, publicSignals, lagrangeEvals) { - const Fr = curve.Fr; - - let pi = Fr.zero; - for (let i = 0; i < publicSignals.length; i++) { - const w = Fr.e(publicSignals[i]); - pi = Fr.sub(pi, Fr.mul(w, lagrangeEvals[i + 1])); - } - return pi; - } - - function computeR0(proof, challenges, roots, curve, logger) { - const Fr = curve.Fr; - - const Li = computeLagrangeLiSi(roots.S0.h0w8, challenges.y, challenges.xi, curve); - - // r0(y) = ∑_1^8 C_0(h_0 ω_8^{i-1}) L_i(y). To this end we need to compute - - // Compute the 8 C0 values - if (logger) logger.info("··· Computing r0(y)"); - - let res = Fr.zero; - for (let i = 0; i < 8; i++) { - let coefValues = []; - coefValues[1] = roots.S0.h0w8[i]; - for (let j = 2; j < 8; j++) { - coefValues[j] = Fr.mul(coefValues[j - 1], roots.S0.h0w8[i]); - } - - let c0 = Fr.add(proof.evaluations.ql, Fr.mul(proof.evaluations.qr, coefValues[1])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qo, coefValues[2])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qm, coefValues[3])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.qc, coefValues[4])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s1, coefValues[5])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s2, coefValues[6])); - c0 = Fr.add(c0, Fr.mul(proof.evaluations.s3, coefValues[7])); - - res = Fr.add(res, Fr.mul(c0, Li[i])); - } - - return res; - } - - function computeR1(proof, challenges, roots, pi, curve, logger) { - const Fr = curve.Fr; - - const Li = computeLagrangeLiSi(roots.S1.h1w4, challenges.y, challenges.xi, curve); - - // r1(y) = ∑_1^4 C_1(h_1 ω_4^{i-1}) L_i(y). To this end we need to compute - // Z1 = {C1(h_1}, C1(h_1 ω_4), C1(h_1 ω_4^2), C1(h_1 ω_4^3)} - // where C_1(h_1 ω_4^{i-1}) = eval.a + h_1 ω_4^i eval.b + (h_1 ω_4^i)^2 eval.c + (h_1 ω_4^i)^3 T0(xi), - // where T0(xi) = [ qL·a + qR·b + qM·a·b + qO·c + qC + PI(xi) ] / Z_H(xi) - - // Compute T0(xi) - if (logger) logger.info("··· Computing T0(xi)"); - let t0 = Fr.mul(proof.evaluations.ql, proof.evaluations.a); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qr, proof.evaluations.b)); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qm, Fr.mul(proof.evaluations.a, proof.evaluations.b))); - t0 = Fr.add(t0, Fr.mul(proof.evaluations.qo, proof.evaluations.c)); - t0 = Fr.add(t0, proof.evaluations.qc); - t0 = Fr.add(t0, pi); - t0 = Fr.mul(t0, challenges.invzh); - - // Compute the 4 C1 values - if (logger) logger.info("··· Computing C1(h_1ω_4^i) values"); - - let res = Fr.zero; - for (let i = 0; i < 4; i++) { - let c1 = proof.evaluations.a; - c1 = Fr.add(c1, Fr.mul(roots.S1.h1w4[i], proof.evaluations.b)); - const h1w4Squared = Fr.square(roots.S1.h1w4[i]); - c1 = Fr.add(c1, Fr.mul(h1w4Squared, proof.evaluations.c)); - c1 = Fr.add(c1, Fr.mul(Fr.mul(h1w4Squared, roots.S1.h1w4[i]), t0)); - - res = Fr.add(res, Fr.mul(c1, Li[i])); - } - - return res; - } - - function computeR2(proof, challenges, roots, lagrange1, vk, curve, logger) { - const Fr = curve.Fr; - - const LiS2 = computeLagrangeLiS2([roots.S2.h2w3, roots.S2.h3w3], challenges.y, challenges.xi, challenges.xiw, curve); - - // r2(y) = ∑_1^3 C_2(h_2 ω_3^{i-1}) L_i(y) + ∑_1^3 C_2(h_3 ω_3^{i-1}) L_{i+3}(y). To this end we need to compute - // Z2 = {[C2(h_2}, C2(h_2 ω_3), C2(h_2 ω_3^2)], [C2(h_3}, C2(h_3 ω_3), C2(h_3 ω_3^2)]} - // where C_2(h_2 ω_3^{i-1}) = eval.z + h_2 ω_2^i T1(xi) + (h_2 ω_3^i)^2 T2(xi), - // where C_2(h_3 ω_3^{i-1}) = eval.z + h_3 ω_2^i T1(xi) + (h_3 ω_3^i)^2 T2(xi), - // where T1(xi) = [ L_1(xi)(z-1)] / Z_H(xi) - // and T2(xi) = [ (a + beta·xi + gamma)(b + beta·xi·k1 + gamma)(c + beta·xi·k2 + gamma)z - // - (a + beta·sigma1 + gamma)(b + beta·sigma2 + gamma)(c + beta·sigma3 + gamma)zω ] / Z_H(xi) - - // Compute T1(xi) - if (logger) logger.info("··· Computing T1(xi)"); - let t1 = Fr.sub(proof.evaluations.z, Fr.one); - t1 = Fr.mul(t1, lagrange1); - t1 = Fr.mul(t1, challenges.invzh); - - // Compute T2(xi) - if (logger) logger.info("··· Computing T2(xi)"); - const betaxi = Fr.mul(challenges.beta, challenges.xi); - const t211 = Fr.add(proof.evaluations.a, Fr.add(betaxi, challenges.gamma)); - const t212 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(betaxi, vk.k1), challenges.gamma)); - const t213 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(betaxi, vk.k2), challenges.gamma)); - const t21 = Fr.mul(t211, Fr.mul(t212, Fr.mul(t213, proof.evaluations.z))); - - const t221 = Fr.add(proof.evaluations.a, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s1), challenges.gamma)); - const t222 = Fr.add(proof.evaluations.b, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s2), challenges.gamma)); - const t223 = Fr.add(proof.evaluations.c, Fr.add(Fr.mul(challenges.beta, proof.evaluations.s3), challenges.gamma)); - const t22 = Fr.mul(t221, Fr.mul(t222, Fr.mul(t223, proof.evaluations.zw))); - - let t2 = Fr.sub(t21, t22); - t2 = Fr.mul(t2, challenges.invzh); - - // Compute the 6 C2 values - if (logger) logger.info("··· Computing C2(h_2ω_3^i) values"); - let res = Fr.zero; - for (let i = 0; i < 3; i++) { - let c2 = Fr.add(proof.evaluations.z, Fr.mul(roots.S2.h2w3[i], t1)); - c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h2w3[i]), t2)); - - res = Fr.add(res, Fr.mul(c2, LiS2[i])); - } - - if (logger) logger.info("··· Computing C2(h_3ω_3^i) values"); - for (let i = 0; i < 3; i++) { - let c2 = Fr.add(proof.evaluations.zw, Fr.mul(roots.S2.h3w3[i], proof.evaluations.t1w)); - c2 = Fr.add(c2, Fr.mul(Fr.square(roots.S2.h3w3[i]), proof.evaluations.t2w)); - - res = Fr.add(res, Fr.mul(c2, LiS2[i + 3])); - } - - return res; - } - - function computeF(curve, proof, vk, challenges, roots) { - const G1 = curve.G1; - const Fr = curve.Fr; - - let mulH0 = Fr.sub(challenges.y, roots.S0.h0w8[0]); - for (let i = 1; i < 8; i++) { - mulH0 = Fr.mul(mulH0, Fr.sub(challenges.y, roots.S0.h0w8[i])); - } - - challenges.temp = mulH0; - - let mulH1 = Fr.sub(challenges.y, roots.S1.h1w4[0]); - for (let i = 1; i < 4; i++) { - mulH1 = Fr.mul(mulH1, Fr.sub(challenges.y, roots.S1.h1w4[i])); - } - - let mulH2 = Fr.sub(challenges.y, roots.S2.h2w3[0]); - for (let i = 1; i < 3; i++) { - mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h2w3[i])); - } - for (let i = 0; i < 3; i++) { - mulH2 = Fr.mul(mulH2, Fr.sub(challenges.y, roots.S2.h3w3[i])); - } - - challenges.quotient1 = Fr.mul(challenges.alpha, Fr.div(mulH0, mulH1)); - challenges.quotient2 = Fr.mul(Fr.square(challenges.alpha), Fr.div(mulH0, mulH2)); - - let F2 = G1.timesFr(proof.polynomials.C1, challenges.quotient1); - let F3 = G1.timesFr(proof.polynomials.C2, challenges.quotient2); - - return G1.add(vk.C0, G1.add(F2, F3)); - } - - function computeE(curve, proof, challenges, vk, r0, r1, r2) { - const G1 = curve.G1; - const Fr = curve.Fr; - - let E2 = Fr.mul(r1, challenges.quotient1); - let E3 = Fr.mul(r2, challenges.quotient2); - - return G1.timesFr(G1.one, Fr.add(r0, Fr.add(E2, E3))); - } - - function computeJ(curve, proof, challenges) { - const G1 = curve.G1; - - return G1.timesFr(proof.polynomials.W1, challenges.temp); - } - - async function isValidPairing(curve, proof, challenges, vk, F, E, J) { - const G1 = curve.G1; - - let A1 = G1.timesFr(proof.polynomials.W2, challenges.y); - A1 = G1.add(G1.sub(G1.sub(F, E), J), A1); - const A2 = curve.G2.one; - - const B1 = proof.polynomials.W2; - const B2 = vk.X_2; - - return await curve.pairingEq(G1.neg(A1), A2, B1, B2); - } - - - function computeLagrangeLiSi(roots, x, xi, curve) { - const Fr = curve.Fr; - const len = roots.length; - - const num = Fr.sub(Fr.exp(x, len), xi); - const den1 = Fr.mul(Fr.e(len), Fr.exp(roots[0], len - 2)); - - const Li = []; - for (let i = 0; i < len; i++) { - const den2 = roots[((len - 1) * i) % len]; - const den3 = Fr.sub(x, roots[i]); - - Li[i] = Fr.div(num, Fr.mul(Fr.mul(den1, den2), den3)); - } - - return Li; - } - - function computeLagrangeLiS2(roots, value, xi0, xi1, curve) { - const Fr = curve.Fr; - - const Li = []; - - const len = roots[0].length; - const n = len * roots.length; - - const num1 = Fr.exp(value, n); - const num2 = Fr.mul(Fr.add(xi0, xi1), Fr.exp(value, len)); - const num3 = Fr.mul(xi0, xi1); - const num = Fr.add(Fr.sub(num1, num2), num3); - - let den1 = Fr.mul(Fr.mul(Fr.e(len), roots[0][0]), Fr.sub(xi0, xi1)); - for (let i = 0; i < len; i++) { - const den2 = roots[0][(len - 1) * i % len]; - const den3 = Fr.sub(value, roots[0][i]); - - const den = Fr.mul(den1,Fr.mul(den2, den3)); - - Li[i] = Fr.div(num, den); - } - - den1 = Fr.mul(Fr.mul(Fr.e(len), roots[1][0]), Fr.sub(xi1, xi0)); - for (let i = 0; i < len; i++) { - const den2 = roots[1][(len - 1) * i % len]; - const den3 = Fr.sub(value, roots[1][i]); - - const den = Fr.mul(den1,Fr.mul(den2, den3)); - - Li[i + len] = Fr.div(num, den); - } - - return Li; - } - - /* - Copyright 2021 0KIMS association. - - This file is part of snarkJS. - - snarkJS is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - snarkJS is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with snarkJS. If not, see . - */ - - - const {unstringifyBigInts} = utils; - - function p256(n) { - let nstr = n.toString(16); - while (nstr.length < 64) nstr = "0" + nstr; - nstr = `0x${nstr}`; - return nstr; - } - - async function fflonkExportCallData(_pub, _proof) { - const proof = unstringifyBigInts(_proof); - const pub = unstringifyBigInts(_pub); - - await getCurveFromName(proof.curve); - - let inputs = ""; - for (let i = 0; i < pub.length; i++) { - if (inputs !== "") inputs = inputs + ","; - inputs = inputs + p256(pub[i]); - } - - return `[${p256(proof.polynomials.C1[0])}, ${p256(proof.polynomials.C1[1])},` + - `${p256(proof.polynomials.C2[0])},${p256(proof.polynomials.C2[1])},` + - `${p256(proof.polynomials.W1[0])},${p256(proof.polynomials.W1[1])},` + - `${p256(proof.polynomials.W2[0])},${p256(proof.polynomials.W2[1])},` + - `${p256(proof.evaluations.ql)},${p256(proof.evaluations.qr)},${p256(proof.evaluations.qm)},` + - `${p256(proof.evaluations.qo)},${p256(proof.evaluations.qc)},${p256(proof.evaluations.s1)},` + - `${p256(proof.evaluations.s2)},${p256(proof.evaluations.s3)},${p256(proof.evaluations.a)},` + - `${p256(proof.evaluations.b)},${p256(proof.evaluations.c)},${p256(proof.evaluations.z)},` + - `${p256(proof.evaluations.zw)},${p256(proof.evaluations.t1w)},${p256(proof.evaluations.t2w)},` + - `${p256(proof.evaluations.inv)}],` + - `[${inputs}]`; - } - - /* - Copyright 2022 iden3 association. - - This file is part of snarkjs. - - snarkjs is a free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by the - Free Software Foundation, either version 3 of the License, or (at your option) - any later version. - - snarkjs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - snarkjs. If not, see . - */ - - var fflonk = /*#__PURE__*/Object.freeze({ - __proto__: null, - exportSolidityCallData: fflonkExportCallData, - exportSolidityVerifier: fflonkExportSolidityVerifier, - fullProve: fflonkFullProve, - prove: fflonkProve, - setup: fflonkSetup, - verify: fflonkVerify - }); - - var _virtual_ejs = {}; - - var _virtual_ejs$1 = /*#__PURE__*/Object.freeze({ - __proto__: null, - default: _virtual_ejs - }); - - exports.curves = curves; - exports.fflonk = fflonk; - exports.groth16 = groth16; - exports.plonk = plonk; - exports.powersOfTau = powersoftau; - exports.r1cs = r1cs; - exports.wtns = wtns; - exports.zKey = zkey; - - return exports; - -})({}); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic25hcmtqcy5qcyIsInNvdXJjZXMiOlsiLi4vLi4vZmZqYXZhc2NyaXB0L2J1aWxkL2Jyb3dzZXIuZXNtLmpzIiwiLi4vLi4vZmFzdGZpbGUvc3JjL29zZmlsZS5qcyIsIi4uLy4uL2Zhc3RmaWxlL3NyYy9tZW1maWxlLmpzIiwiLi4vLi4vZmFzdGZpbGUvc3JjL2JpZ21lbWZpbGUuanMiLCIuLi8uLi9mYXN0ZmlsZS9zcmMvZmFzdGZpbGUuanMiLCIuLi8uLi9iaW5maWxldXRpbHMvc3JjL2JpbmZpbGV1dGlscy5qcyIsIi4uL3NyYy9jdXJ2ZXMuanMiLCIuLi9ub2RlX21vZHVsZXMvQG5vYmxlL2hhc2hlcy91dGlscy5qcyIsIi4uL25vZGVfbW9kdWxlcy9Abm9ibGUvaGFzaGVzL19ibGFrZS5qcyIsIi4uL25vZGVfbW9kdWxlcy9Abm9ibGUvaGFzaGVzL191NjQuanMiLCIuLi9ub2RlX21vZHVsZXMvQG5vYmxlL2hhc2hlcy9ibGFrZTIuanMiLCIuLi9zcmMvbWlzYy5qcyIsIi4uL3NyYy96a2V5X2NvbnN0YW50cy5qcyIsIi4uL3NyYy9mZmxvbmtfY29uc3RhbnRzLmpzIiwiLi4vc3JjL3prZXlfdXRpbHMuanMiLCIuLi9zcmMvd3Ruc191dGlscy5qcyIsIi4uL3NyYy9ncm90aDE2X3Byb3ZlLmpzIiwiLi4vbm9kZV9tb2R1bGVzL2Zhc3RmaWxlL3NyYy9vc2ZpbGUuanMiLCIuLi9ub2RlX21vZHVsZXMvZmFzdGZpbGUvc3JjL21lbWZpbGUuanMiLCIuLi9ub2RlX21vZHVsZXMvZmFzdGZpbGUvc3JjL2JpZ21lbWZpbGUuanMiLCIuLi9ub2RlX21vZHVsZXMvZmFzdGZpbGUvc3JjL2Zhc3RmaWxlLmpzIiwiLi4vbm9kZV9tb2R1bGVzL2NpcmNvbV9ydW50aW1lL2pzL3V0aWxzLmpzIiwiLi4vbm9kZV9tb2R1bGVzL2NpcmNvbV9ydW50aW1lL2pzL3dpdG5lc3NfY2FsY3VsYXRvci5qcyIsIi4uL3NyYy93dG5zX2NhbGN1bGF0ZS5qcyIsIi4uL3NyYy9ncm90aDE2X2Z1bGxwcm92ZS5qcyIsIi4uL3NyYy9ncm90aDE2X3ZlcmlmeS5qcyIsIi4uL3NyYy9ncm90aDE2X2V4cG9ydHNvbGlkaXR5Y2FsbGRhdGEuanMiLCIuLi9zcmMvZ3JvdGgxNi5qcyIsIi4uL3NyYy9rZXlwYWlyLmpzIiwiLi4vc3JjL3Bvd2Vyc29mdGF1X3V0aWxzLmpzIiwiLi4vc3JjL3Bvd2Vyc29mdGF1X25ldy5qcyIsIi4uL3NyYy9wb3dlcnNvZnRhdV9leHBvcnRfY2hhbGxlbmdlLmpzIiwiLi4vc3JjL3Bvd2Vyc29mdGF1X2ltcG9ydC5qcyIsIi4uL3NyYy9wb3dlcnNvZnRhdV92ZXJpZnkuanMiLCIuLi9zcmMvbXBjX2FwcGx5a2V5LmpzIiwiLi4vc3JjL3Bvd2Vyc29mdGF1X2NoYWxsZW5nZV9jb250cmlidXRlLmpzIiwiLi4vc3JjL3Bvd2Vyc29mdGF1X2JlYWNvbi5qcyIsIi4uL3NyYy9wb3dlcnNvZnRhdV9jb250cmlidXRlLmpzIiwiLi4vc3JjL3Bvd2Vyc29mdGF1X3ByZXBhcmVwaGFzZTIuanMiLCIuLi9zcmMvcG93ZXJzb2Z0YXVfdHJ1bmNhdGUuanMiLCIuLi9zcmMvcG93ZXJzb2Z0YXVfY29udmVydC5qcyIsIi4uL3NyYy9wb3dlcnNvZnRhdV9leHBvcnRfanNvbi5qcyIsIi4uL3NyYy9wb3dlcnNvZnRhdS5qcyIsIi4uL3NyYy9yMWNzX3ByaW50LmpzIiwiLi4vLi4vcjFjc2ZpbGUvbm9kZV9tb2R1bGVzL0BpZGVuMy9iaWdhcnJheS9zcmMvYmlnYXJyYXkuanMiLCIuLi8uLi9yMWNzZmlsZS9ub2RlX21vZHVsZXMvZmFzdGZpbGUvc3JjL29zZmlsZS5qcyIsIi4uLy4uL3IxY3NmaWxlL25vZGVfbW9kdWxlcy9mYXN0ZmlsZS9zcmMvbWVtZmlsZS5qcyIsIi4uLy4uL3IxY3NmaWxlL25vZGVfbW9kdWxlcy9mYXN0ZmlsZS9zcmMvYmlnbWVtZmlsZS5qcyIsIi4uLy4uL3IxY3NmaWxlL25vZGVfbW9kdWxlcy9mYXN0ZmlsZS9zcmMvZmFzdGZpbGUuanMiLCIuLi8uLi9yMWNzZmlsZS9ub2RlX21vZHVsZXMvQGlkZW4zL2JpbmZpbGV1dGlscy9zcmMvYmluZmlsZXV0aWxzLmpzIiwiLi4vLi4vcjFjc2ZpbGUvc3JjL3IxY3NmaWxlLmpzIiwiLi4vc3JjL3IxY3NfaW5mby5qcyIsIi4uL3NyYy9yMWNzX2V4cG9ydF9qc29uLmpzIiwiLi4vc3JjL3IxY3MuanMiLCIuLi9zcmMvbG9hZHN5bXMuanMiLCIuLi9zcmMvd3Ruc19kZWJ1Zy5qcyIsIi4uL3NyYy93dG5zX2V4cG9ydF9qc29uLmpzIiwiLi4vc3JjL3d0bnNfY2hlY2suanMiLCIuLi9zcmMvd3Rucy5qcyIsIi4uL3NyYy9iaWdhcnJheS5qcyIsIi4uL3NyYy96a2V5X25ldy5qcyIsIi4uL3NyYy96a2V5X2V4cG9ydF9iZWxsbWFuLmpzIiwiLi4vc3JjL3prZXlfaW1wb3J0X2JlbGxtYW4uanMiLCIuLi9zcmMvemtleV92ZXJpZnlfZnJvbWluaXQuanMiLCIuLi9zcmMvemtleV92ZXJpZnlfZnJvbXIxY3MuanMiLCIuLi9zcmMvemtleV9jb250cmlidXRlLmpzIiwiLi4vc3JjL3prZXlfYmVhY29uLmpzIiwiLi4vc3JjL3prZXlfZXhwb3J0X2pzb24uanMiLCIuLi9zcmMvemtleV9iZWxsbWFuX2NvbnRyaWJ1dGUuanMiLCIuLi9zcmMvemtleV9leHBvcnRfdmVyaWZpY2F0aW9ua2V5LmpzIiwiLi4vc3JjL2ZmbG9ua19leHBvcnRfc29saWRpdHlfdmVyaWZpZXIuanMiLCIuLi9zcmMvemtleV9leHBvcnRfc29saWRpdHl2ZXJpZmllci5qcyIsIi4uL3NyYy96a2V5LmpzIiwiLi4vc3JjL3Bsb25rX3NldHVwLmpzIiwiLi4vc3JjL3Byb29mLmpzIiwiLi4vbm9kZV9tb2R1bGVzL0Bub2JsZS9oYXNoZXMvc2hhMy5qcyIsIi4uL3NyYy9LZWNjYWsyNTZUcmFuc2NyaXB0LmpzIiwiLi4vc3JjL211bF96LmpzIiwiLi4vc3JjL3Bsb25rX2NvbnN0YW50cy5qcyIsIi4uL3NyYy9wb2x5bm9taWFsL3BvbHlub21pYWwuanMiLCIuLi9zcmMvcG9seW5vbWlhbC9ldmFsdWF0aW9ucy5qcyIsIi4uL3NyYy9wbG9ua19wcm92ZS5qcyIsIi4uL3NyYy9wbG9ua19mdWxscHJvdmUuanMiLCIuLi9zcmMvcGxvbmtfdmVyaWZ5LmpzIiwiLi4vc3JjL3Bsb25rX2V4cG9ydHNvbGlkaXR5Y2FsbGRhdGEuanMiLCIuLi9zcmMvcGxvbmsuanMiLCIuLi9zcmMvcGxvbmtfZXF1YXRpb24uanMiLCIuLi9zcmMvcjFjc19jb25zdHJhaW50X3Byb2Nlc3Nvci5qcyIsIi4uL3NyYy9wb2x5bm9taWFsL2Nwb2x5bm9taWFsLmpzIiwiLi4vc3JjL2ZmbG9ua19zZXR1cC5qcyIsIi4uL3NyYy9mZmxvbmtfcHJvdmUuanMiLCIuLi9zcmMvZmZsb25rX2Z1bGxfcHJvdmUuanMiLCIuLi9zcmMvZmZsb25rX3ZlcmlmeS5qcyIsIi4uL3NyYy9mZmxvbmtfZXhwb3J0X2NhbGxkYXRhLmpzIiwiLi4vc3JjL2ZmbG9uay5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBoZXhMZW4gPSBbIDAsIDEsIDIsIDIsIDMsIDMsIDMsIDMsIDQgLDQgLDQgLDQgLDQgLDQgLDQgLDRdO1xuXG5mdW5jdGlvbiBmcm9tU3RyaW5nKHMsIHJhZGl4KSB7XG4gICAgaWYgKCghcmFkaXgpfHwocmFkaXg9PTEwKSkge1xuICAgICAgICByZXR1cm4gQmlnSW50KHMpO1xuICAgIH0gZWxzZSBpZiAocmFkaXg9PTE2KSB7XG4gICAgICAgIGlmIChzLnNsaWNlKDAsMikgPT0gXCIweFwiKSB7XG4gICAgICAgICAgICByZXR1cm4gQmlnSW50KHMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIEJpZ0ludChcIjB4XCIrcyk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmNvbnN0IGUgPSBmcm9tU3RyaW5nO1xuXG5mdW5jdGlvbiBmcm9tQXJyYXkoYSwgcmFkaXgpIHtcbiAgICBsZXQgYWNjID1CaWdJbnQoMCk7XG4gICAgcmFkaXggPSBCaWdJbnQocmFkaXgpO1xuICAgIGZvciAobGV0IGk9MDsgaTxhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGFjYyA9IGFjYypyYWRpeCArIEJpZ0ludChhW2ldKTtcbiAgICB9XG4gICAgcmV0dXJuIGFjYztcbn1cblxuZnVuY3Rpb24gYml0TGVuZ3RoKGEpIHtcbiAgICBjb25zdCBhUyA9YS50b1N0cmluZygxNik7XG4gICAgcmV0dXJuIChhUy5sZW5ndGgtMSkqNCAraGV4TGVuW3BhcnNlSW50KGFTWzBdLCAxNildO1xufVxuXG5mdW5jdGlvbiBpc05lZ2F0aXZlKGEpIHtcbiAgICByZXR1cm4gQmlnSW50KGEpIDwgQmlnSW50KDApO1xufVxuXG5mdW5jdGlvbiBpc1plcm8oYSkge1xuICAgIHJldHVybiAhYTtcbn1cblxuZnVuY3Rpb24gc2hpZnRMZWZ0KGEsIG4pIHtcbiAgICByZXR1cm4gQmlnSW50KGEpIDw8IEJpZ0ludChuKTtcbn1cblxuZnVuY3Rpb24gc2hpZnRSaWdodChhLCBuKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSA+PiBCaWdJbnQobik7XG59XG5cbmNvbnN0IHNobCA9IHNoaWZ0TGVmdDtcbmNvbnN0IHNociA9IHNoaWZ0UmlnaHQ7XG5cbmZ1bmN0aW9uIGlzT2RkKGEpIHtcbiAgICByZXR1cm4gKEJpZ0ludChhKSAmIEJpZ0ludCgxKSkgPT0gQmlnSW50KDEpO1xufVxuXG5cbmZ1bmN0aW9uIG5hZihuKSB7XG4gICAgbGV0IEUgPSBCaWdJbnQobik7XG4gICAgY29uc3QgcmVzID0gW107XG4gICAgd2hpbGUgKEUpIHtcbiAgICAgICAgaWYgKEUgJiBCaWdJbnQoMSkpIHtcbiAgICAgICAgICAgIGNvbnN0IHogPSAyIC0gTnVtYmVyKEUgJSBCaWdJbnQoNCkpO1xuICAgICAgICAgICAgcmVzLnB1c2goIHogKTtcbiAgICAgICAgICAgIEUgPSBFIC0gQmlnSW50KHopO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzLnB1c2goIDAgKTtcbiAgICAgICAgfVxuICAgICAgICBFID0gRSA+PiBCaWdJbnQoMSk7XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5cblxuZnVuY3Rpb24gYml0cyhuKSB7XG4gICAgbGV0IEUgPSBCaWdJbnQobik7XG4gICAgY29uc3QgcmVzID0gW107XG4gICAgd2hpbGUgKEUpIHtcbiAgICAgICAgaWYgKEUgJiBCaWdJbnQoMSkpIHtcbiAgICAgICAgICAgIHJlcy5wdXNoKDEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzLnB1c2goIDAgKTtcbiAgICAgICAgfVxuICAgICAgICBFID0gRSA+PiBCaWdJbnQoMSk7XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5cbmZ1bmN0aW9uIHRvTnVtYmVyKHMpIHtcbiAgICBpZiAocz5CaWdJbnQoTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIgKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJOdW1iZXIgdG9vIGJpZ1wiKTtcbiAgICB9XG4gICAgcmV0dXJuIE51bWJlcihzKTtcbn1cblxuZnVuY3Rpb24gdG9BcnJheShzLCByYWRpeCkge1xuICAgIGNvbnN0IHJlcyA9IFtdO1xuICAgIGxldCByZW0gPSBCaWdJbnQocyk7XG4gICAgcmFkaXggPSBCaWdJbnQocmFkaXgpO1xuICAgIHdoaWxlIChyZW0pIHtcbiAgICAgICAgcmVzLnVuc2hpZnQoIE51bWJlcihyZW0gJSByYWRpeCkpO1xuICAgICAgICByZW0gPSByZW0gLyByYWRpeDtcbiAgICB9XG4gICAgcmV0dXJuIHJlcztcbn1cblxuXG5mdW5jdGlvbiBhZGQoYSwgYikge1xuICAgIHJldHVybiBCaWdJbnQoYSkgKyBCaWdJbnQoYik7XG59XG5cbmZ1bmN0aW9uIHN1YihhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSAtIEJpZ0ludChiKTtcbn1cblxuZnVuY3Rpb24gbmVnKGEpIHtcbiAgICByZXR1cm4gLUJpZ0ludChhKTtcbn1cblxuZnVuY3Rpb24gbXVsKGEsIGIpIHtcbiAgICByZXR1cm4gQmlnSW50KGEpICogQmlnSW50KGIpO1xufVxuXG5mdW5jdGlvbiBzcXVhcmUoYSkge1xuICAgIHJldHVybiBCaWdJbnQoYSkgKiBCaWdJbnQoYSk7XG59XG5cbmZ1bmN0aW9uIHBvdyhhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSAqKiBCaWdJbnQoYik7XG59XG5cbmZ1bmN0aW9uIGV4cCQxKGEsIGIpIHtcbiAgICByZXR1cm4gQmlnSW50KGEpICoqIEJpZ0ludChiKTtcbn1cblxuZnVuY3Rpb24gYWJzKGEpIHtcbiAgICByZXR1cm4gQmlnSW50KGEpID49IDAgPyBCaWdJbnQoYSkgOiAtQmlnSW50KGEpO1xufVxuXG5mdW5jdGlvbiBkaXYoYSwgYikge1xuICAgIHJldHVybiBCaWdJbnQoYSkgLyBCaWdJbnQoYik7XG59XG5cbmZ1bmN0aW9uIG1vZChhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSAlIEJpZ0ludChiKTtcbn1cblxuZnVuY3Rpb24gZXEoYSwgYikge1xuICAgIHJldHVybiBCaWdJbnQoYSkgPT0gQmlnSW50KGIpO1xufVxuXG5mdW5jdGlvbiBuZXEoYSwgYikge1xuICAgIHJldHVybiBCaWdJbnQoYSkgIT0gQmlnSW50KGIpO1xufVxuXG5mdW5jdGlvbiBsdChhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSA8IEJpZ0ludChiKTtcbn1cblxuZnVuY3Rpb24gZ3QoYSwgYikge1xuICAgIHJldHVybiBCaWdJbnQoYSkgPiBCaWdJbnQoYik7XG59XG5cbmZ1bmN0aW9uIGxlcShhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSA8PSBCaWdJbnQoYik7XG59XG5cbmZ1bmN0aW9uIGdlcShhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSA+PSBCaWdJbnQoYik7XG59XG5cbmZ1bmN0aW9uIGJhbmQoYSwgYikge1xuICAgIHJldHVybiBCaWdJbnQoYSkgJiBCaWdJbnQoYik7XG59XG5cbmZ1bmN0aW9uIGJvcihhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSB8IEJpZ0ludChiKTtcbn1cblxuZnVuY3Rpb24gYnhvcihhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSBeIEJpZ0ludChiKTtcbn1cblxuZnVuY3Rpb24gbGFuZChhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSAmJiBCaWdJbnQoYik7XG59XG5cbmZ1bmN0aW9uIGxvcihhLCBiKSB7XG4gICAgcmV0dXJuIEJpZ0ludChhKSB8fCBCaWdJbnQoYik7XG59XG5cbmZ1bmN0aW9uIGxub3QoYSkge1xuICAgIHJldHVybiAhQmlnSW50KGEpO1xufVxuXG4vLyBSZXR1cm5zIGEgYnVmZmVyIHdpdGggTGl0dGxlIEVuZGlhbiBSZXByZXNlbnRhdGlvblxuZnVuY3Rpb24gdG9ScHJMRShidWZmLCBvLCBlLCBuOCkge1xuICAgIGNvbnN0IHMgPSBcIjAwMDAwMDBcIiArIGUudG9TdHJpbmcoMTYpO1xuICAgIGNvbnN0IHYgPSBuZXcgVWludDMyQXJyYXkoYnVmZi5idWZmZXIsIGJ1ZmYuYnl0ZU9mZnNldCArIG8sIG44LzQpO1xuICAgIGNvbnN0IGwgPSAoKChzLmxlbmd0aC03KSo0IC0gMSkgPj4gNSkrMTsgICAgLy8gTnVtYmVyIG9mIDMyYml0IHdvcmRzO1xuICAgIGZvciAobGV0IGk9MDsgaTxsOyBpKyspIHZbaV0gPSBwYXJzZUludChzLnN1YnN0cmluZyhzLmxlbmd0aC04KmktOCwgcy5sZW5ndGgtOCppKSwgMTYpO1xuICAgIGZvciAobGV0IGk9bDsgaTx2Lmxlbmd0aDsgaSsrKSB2W2ldID0gMDtcbiAgICBmb3IgKGxldCBpPXYubGVuZ3RoKjQ7IGk8bjg7IGkrKykgYnVmZltpXSA9IHRvTnVtYmVyKGJhbmQoc2hpZnRSaWdodChlLCBpKjgpLCAweEZGKSk7XG59XG5cbi8vIFJldHVybnMgYSBidWZmZXIgd2l0aCBCaWcgRW5kaWFuIFJlcHJlc2VudGF0aW9uXG5mdW5jdGlvbiB0b1JwckJFKGJ1ZmYsIG8sIGUsIG44KSB7XG4gICAgY29uc3QgcyA9IFwiMDAwMDAwMFwiICsgZS50b1N0cmluZygxNik7XG4gICAgY29uc3QgdiA9IG5ldyBEYXRhVmlldyhidWZmLmJ1ZmZlciwgYnVmZi5ieXRlT2Zmc2V0ICsgbywgbjgpO1xuICAgIGNvbnN0IGwgPSAoKChzLmxlbmd0aC03KSo0IC0gMSkgPj4gNSkrMTsgICAgLy8gTnVtYmVyIG9mIDMyYml0IHdvcmRzO1xuICAgIGZvciAobGV0IGk9MDsgaTxsOyBpKyspIHYuc2V0VWludDMyKG44LWkqNCAtNCwgcGFyc2VJbnQocy5zdWJzdHJpbmcocy5sZW5ndGgtOCppLTgsIHMubGVuZ3RoLTgqaSksIDE2KSwgZmFsc2UpO1xuICAgIGZvciAobGV0IGk9MDsgaTxuOC80LWw7IGkrKykgdltpXSA9IDA7XG59XG5cbi8vIFBhc2VzIGEgYnVmZmVyIHdpdGggTGl0dGxlIEVuZGlhbiBSZXByZXNlbnRhdGlvblxuZnVuY3Rpb24gZnJvbVJwckxFKGJ1ZmYsIG8sIG44KSB7XG4gICAgbjggPSBuOCB8fCBidWZmLmJ5dGVMZW5ndGg7XG4gICAgbyA9IG8gfHwgMDtcbiAgICBjb25zdCB2ID0gbmV3IFVpbnQzMkFycmF5KGJ1ZmYuYnVmZmVyLCBidWZmLmJ5dGVPZmZzZXQgKyBvLCBuOC80KTtcbiAgICBjb25zdCBhID0gbmV3IEFycmF5KG44LzQpO1xuICAgIHYuZm9yRWFjaCggKGNoLGkpID0+IGFbYS5sZW5ndGgtaS0xXSA9IGNoLnRvU3RyaW5nKDE2KS5wYWRTdGFydCg4LFwiMFwiKSApO1xuICAgIHJldHVybiBmcm9tU3RyaW5nKGEuam9pbihcIlwiKSwgMTYpO1xufVxuXG4vLyBQYXNlcyBhIGJ1ZmZlciB3aXRoIEJpZyBFbmRpYW4gUmVwcmVzZW50YXRpb25cbmZ1bmN0aW9uIGZyb21ScHJCRShidWZmLCBvLCBuOCkge1xuICAgIG44ID0gbjggfHwgYnVmZi5ieXRlTGVuZ3RoO1xuICAgIG8gPSBvIHx8IDA7XG4gICAgY29uc3QgdiA9IG5ldyBEYXRhVmlldyhidWZmLmJ1ZmZlciwgYnVmZi5ieXRlT2Zmc2V0ICsgbywgbjgpO1xuICAgIGNvbnN0IGEgPSBuZXcgQXJyYXkobjgvNCk7XG4gICAgZm9yIChsZXQgaT0wOyBpPG44LzQ7IGkrKykge1xuICAgICAgICBhW2ldID0gdi5nZXRVaW50MzIoaSo0LCBmYWxzZSkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDgsIFwiMFwiKTtcbiAgICB9XG4gICAgcmV0dXJuIGZyb21TdHJpbmcoYS5qb2luKFwiXCIpLCAxNik7XG59XG5cbmZ1bmN0aW9uIHRvU3RyaW5nKGEsIHJhZGl4KSB7XG4gICAgcmV0dXJuIGEudG9TdHJpbmcocmFkaXgpO1xufVxuXG5mdW5jdGlvbiB0b0xFQnVmZihhKSB7XG4gICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KE1hdGguZmxvb3IoKGJpdExlbmd0aChhKSAtIDEpIC8gOCkgKzEpO1xuICAgIHRvUnByTEUoYnVmZiwgMCwgYSwgYnVmZi5ieXRlTGVuZ3RoKTtcbiAgICByZXR1cm4gYnVmZjtcbn1cblxuY29uc3QgemVybyA9IGUoMCk7XG5jb25zdCBvbmUgPSBlKDEpO1xuXG52YXIgX1NjYWxhciA9IC8qI19fUFVSRV9fKi9PYmplY3QuZnJlZXplKHtcbiAgICBfX3Byb3RvX186IG51bGwsXG4gICAgYWJzOiBhYnMsXG4gICAgYWRkOiBhZGQsXG4gICAgYmFuZDogYmFuZCxcbiAgICBiaXRMZW5ndGg6IGJpdExlbmd0aCxcbiAgICBiaXRzOiBiaXRzLFxuICAgIGJvcjogYm9yLFxuICAgIGJ4b3I6IGJ4b3IsXG4gICAgZGl2OiBkaXYsXG4gICAgZTogZSxcbiAgICBlcTogZXEsXG4gICAgZXhwOiBleHAkMSxcbiAgICBmcm9tQXJyYXk6IGZyb21BcnJheSxcbiAgICBmcm9tUnByQkU6IGZyb21ScHJCRSxcbiAgICBmcm9tUnByTEU6IGZyb21ScHJMRSxcbiAgICBmcm9tU3RyaW5nOiBmcm9tU3RyaW5nLFxuICAgIGdlcTogZ2VxLFxuICAgIGd0OiBndCxcbiAgICBpc05lZ2F0aXZlOiBpc05lZ2F0aXZlLFxuICAgIGlzT2RkOiBpc09kZCxcbiAgICBpc1plcm86IGlzWmVybyxcbiAgICBsYW5kOiBsYW5kLFxuICAgIGxlcTogbGVxLFxuICAgIGxub3Q6IGxub3QsXG4gICAgbG9yOiBsb3IsXG4gICAgbHQ6IGx0LFxuICAgIG1vZDogbW9kLFxuICAgIG11bDogbXVsLFxuICAgIG5hZjogbmFmLFxuICAgIG5lZzogbmVnLFxuICAgIG5lcTogbmVxLFxuICAgIG9uZTogb25lLFxuICAgIHBvdzogcG93LFxuICAgIHNoaWZ0TGVmdDogc2hpZnRMZWZ0LFxuICAgIHNoaWZ0UmlnaHQ6IHNoaWZ0UmlnaHQsXG4gICAgc2hsOiBzaGwsXG4gICAgc2hyOiBzaHIsXG4gICAgc3F1YXJlOiBzcXVhcmUsXG4gICAgc3ViOiBzdWIsXG4gICAgdG9BcnJheTogdG9BcnJheSxcbiAgICB0b0xFQnVmZjogdG9MRUJ1ZmYsXG4gICAgdG9OdW1iZXI6IHRvTnVtYmVyLFxuICAgIHRvUnByQkU6IHRvUnByQkUsXG4gICAgdG9ScHJMRTogdG9ScHJMRSxcbiAgICB0b1N0cmluZzogdG9TdHJpbmcsXG4gICAgemVybzogemVyb1xufSk7XG5cbi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMGtpbXMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya2pzLlxuXG4gICAgc25hcmtqcyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuICAgIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGVcbiAgICBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbilcbiAgICBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJranMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3JcbiAgICBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoXG4gICAgc25hcmtqcy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbi8qXG4gICAgVGhpcyBsaWJyYXJ5IGRvZXMgb3BlcmF0aW9ucyBvbiBwb2x5bm9taWFscyB3aXRoIGNvZWZmaWNpZW50cyBpbiBhIGZpZWxkIEYuXG5cbiAgICBBIHBvbHlub21pYWwgUCh4KSA9IHAwICsgcDEgKiB4ICsgcDIgKiB4XjIgKyAuLi4gKyBwbiAqIHhebiAgaXMgcmVwcmVzZW50ZWRcbiAgICBieSB0aGUgYXJyYXkgWyBwMCwgcDEsIHAyLCAuLi4gLCBwbiBdLlxuICovXG5cbmNsYXNzIFBvbEZpZWxkIHtcbiAgICBjb25zdHJ1Y3RvciAoRikge1xuICAgICAgICB0aGlzLkYgPSBGO1xuXG4gICAgICAgIGxldCByZW0gPSBGLnNxcnRfdDtcbiAgICAgICAgbGV0IHMgPSBGLnNxcnRfcztcblxuICAgICAgICBjb25zdCBmaXZlID0gdGhpcy5GLmFkZCh0aGlzLkYuYWRkKHRoaXMuRi50d28sIHRoaXMuRi50d28pLCB0aGlzLkYub25lKTtcblxuICAgICAgICB0aGlzLncgPSBuZXcgQXJyYXkocysxKTtcbiAgICAgICAgdGhpcy53aSA9IG5ldyBBcnJheShzKzEpO1xuICAgICAgICB0aGlzLndbc10gPSB0aGlzLkYucG93KGZpdmUsIHJlbSk7XG4gICAgICAgIHRoaXMud2lbc10gPSB0aGlzLkYuaW52KHRoaXMud1tzXSk7XG5cbiAgICAgICAgbGV0IG49cy0xO1xuICAgICAgICB3aGlsZSAobj49MCkge1xuICAgICAgICAgICAgdGhpcy53W25dID0gdGhpcy5GLnNxdWFyZSh0aGlzLndbbisxXSk7XG4gICAgICAgICAgICB0aGlzLndpW25dID0gdGhpcy5GLnNxdWFyZSh0aGlzLndpW24rMV0pO1xuICAgICAgICAgICAgbi0tO1xuICAgICAgICB9XG5cblxuICAgICAgICB0aGlzLnJvb3RzID0gW107XG4gICAgICAgIC8qICAgICAgICBmb3IgKGxldCBpPTA7IGk8MTY7IGkrKykge1xuICAgICAgICAgICAgbGV0IHIgPSB0aGlzLkYub25lO1xuICAgICAgICAgICAgbiA9IDEgPDwgaTtcbiAgICAgICAgICAgIGNvbnN0IHJvb3RzaSA9IG5ldyBBcnJheShuKTtcbiAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxuOyBqKyspIHtcbiAgICAgICAgICAgICAgICByb290c2lbal0gPSByO1xuICAgICAgICAgICAgICAgIHIgPSB0aGlzLkYubXVsKHIsIHRoaXMud1tpXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMucm9vdHMucHVzaChyb290c2kpO1xuICAgICAgICB9XG4gICAgKi9cbiAgICAgICAgdGhpcy5fc2V0Um9vdHMoMTUpO1xuICAgIH1cblxuICAgIF9zZXRSb290cyhuKSB7XG4gICAgICAgIGlmIChuID4gdGhpcy5GLnNxcnRfcykgbiA9IHRoaXMucztcbiAgICAgICAgZm9yIChsZXQgaT1uOyAoaT49MCkgJiYgKCF0aGlzLnJvb3RzW2ldKTsgaS0tKSB7XG4gICAgICAgICAgICBsZXQgciA9IHRoaXMuRi5vbmU7XG4gICAgICAgICAgICBjb25zdCBucm9vdHMgPSAxIDw8IGk7XG4gICAgICAgICAgICBjb25zdCByb290c2kgPSBuZXcgQXJyYXkobnJvb3RzKTtcbiAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxucm9vdHM7IGorKykge1xuICAgICAgICAgICAgICAgIHJvb3RzaVtqXSA9IHI7XG4gICAgICAgICAgICAgICAgciA9IHRoaXMuRi5tdWwociwgdGhpcy53W2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMucm9vdHNbaV0gPSByb290c2k7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhZGQoYSwgYikge1xuICAgICAgICBjb25zdCBtID0gTWF0aC5tYXgoYS5sZW5ndGgsIGIubGVuZ3RoKTtcbiAgICAgICAgY29uc3QgcmVzID0gbmV3IEFycmF5KG0pO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8bTsgaSsrKSB7XG4gICAgICAgICAgICByZXNbaV0gPSB0aGlzLkYuYWRkKGFbaV0gfHwgdGhpcy5GLnplcm8sIGJbaV0gfHwgdGhpcy5GLnplcm8pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnJlZHVjZShyZXMpO1xuICAgIH1cblxuICAgIGRvdWJsZShhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFkZChhLGEpO1xuICAgIH1cblxuICAgIHN1YihhLCBiKSB7XG4gICAgICAgIGNvbnN0IG0gPSBNYXRoLm1heChhLmxlbmd0aCwgYi5sZW5ndGgpO1xuICAgICAgICBjb25zdCByZXMgPSBuZXcgQXJyYXkobSk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxtOyBpKyspIHtcbiAgICAgICAgICAgIHJlc1tpXSA9IHRoaXMuRi5zdWIoYVtpXSB8fCB0aGlzLkYuemVybywgYltpXSB8fCB0aGlzLkYuemVybyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlKHJlcyk7XG4gICAgfVxuXG4gICAgbXVsU2NhbGFyKHAsIGIpIHtcbiAgICAgICAgaWYgKHRoaXMuRi5lcShiLCB0aGlzLkYuemVybykpIHJldHVybiBbXTtcbiAgICAgICAgaWYgKHRoaXMuRi5lcShiLCB0aGlzLkYub25lKSkgcmV0dXJuIHA7XG4gICAgICAgIGNvbnN0IHJlcyA9IG5ldyBBcnJheShwLmxlbmd0aCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxwLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICByZXNbaV0gPSB0aGlzLkYubXVsKHBbaV0sIGIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG5cblxuICAgIG11bChhLCBiKSB7XG4gICAgICAgIGlmIChhLmxlbmd0aCA9PSAwKSByZXR1cm4gW107XG4gICAgICAgIGlmIChiLmxlbmd0aCA9PSAwKSByZXR1cm4gW107XG4gICAgICAgIGlmIChhLmxlbmd0aCA9PSAxKSByZXR1cm4gdGhpcy5tdWxTY2FsYXIoYiwgYVswXSk7XG4gICAgICAgIGlmIChiLmxlbmd0aCA9PSAxKSByZXR1cm4gdGhpcy5tdWxTY2FsYXIoYSwgYlswXSk7XG5cbiAgICAgICAgaWYgKGIubGVuZ3RoID4gYS5sZW5ndGgpIHtcbiAgICAgICAgICAgIFtiLCBhXSA9IFthLCBiXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgoYi5sZW5ndGggPD0gMikgfHwgKGIubGVuZ3RoIDwgbG9nMiQyKGEubGVuZ3RoKSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm11bE5vcm1hbChhLGIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubXVsRkZUKGEsYik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBtdWxOb3JtYWwoYSwgYikge1xuICAgICAgICBsZXQgcmVzID0gW107XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxiLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICByZXMgPSB0aGlzLmFkZChyZXMsIHRoaXMuc2NhbGVYKHRoaXMubXVsU2NhbGFyKGEsIGJbaV0pLCBpKSApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgbXVsRkZUKGEsYikge1xuICAgICAgICBjb25zdCBsb25nZXN0TiA9IE1hdGgubWF4KGEubGVuZ3RoLCBiLmxlbmd0aCk7XG4gICAgICAgIGNvbnN0IGJpdHNSZXN1bHQgPSBsb2cyJDIobG9uZ2VzdE4tMSkrMjtcbiAgICAgICAgdGhpcy5fc2V0Um9vdHMoYml0c1Jlc3VsdCk7XG5cbiAgICAgICAgY29uc3QgbSA9IDEgPDwgYml0c1Jlc3VsdDtcbiAgICAgICAgY29uc3QgZWEgPSB0aGlzLmV4dGVuZChhLG0pO1xuICAgICAgICBjb25zdCBlYiA9IHRoaXMuZXh0ZW5kKGIsbSk7XG5cbiAgICAgICAgY29uc3QgdGEgPSBfX2ZmdCQxKHRoaXMsIGVhLCBiaXRzUmVzdWx0LCAwLCAxKTtcbiAgICAgICAgY29uc3QgdGIgPSBfX2ZmdCQxKHRoaXMsIGViLCBiaXRzUmVzdWx0LCAwLCAxKTtcblxuICAgICAgICBjb25zdCB0cmVzID0gbmV3IEFycmF5KG0pO1xuXG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxtOyBpKyspIHtcbiAgICAgICAgICAgIHRyZXNbaV0gPSB0aGlzLkYubXVsKHRhW2ldLCB0YltpXSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXMgPSBfX2ZmdCQxKHRoaXMsIHRyZXMsIGJpdHNSZXN1bHQsIDAsIDEpO1xuXG4gICAgICAgIGNvbnN0IHR3b2ludm0gPSB0aGlzLkYuaW52KCB0aGlzLkYubXVsU2NhbGFyKHRoaXMuRi5vbmUsIG0pICk7XG4gICAgICAgIGNvbnN0IHJlc24gPSBuZXcgQXJyYXkobSk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxtOyBpKyspIHtcbiAgICAgICAgICAgIHJlc25baV0gPSB0aGlzLkYubXVsKHJlc1sobS1pKSVtXSwgdHdvaW52bSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5yZWR1Y2UocmVzbik7XG4gICAgfVxuXG5cblxuICAgIHNxdWFyZShhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm11bChhLGEpO1xuICAgIH1cblxuICAgIHNjYWxlWChwLCBuKSB7XG4gICAgICAgIGlmIChuPT0wKSB7XG4gICAgICAgICAgICByZXR1cm4gcDtcbiAgICAgICAgfSBlbHNlIGlmIChuPjApIHtcbiAgICAgICAgICAgIGNvbnN0IHogPSBuZXcgQXJyYXkobikuZmlsbCh0aGlzLkYuemVybyk7XG4gICAgICAgICAgICByZXR1cm4gei5jb25jYXQocCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoLW4gPj0gcC5sZW5ndGgpIHJldHVybiBbXTtcbiAgICAgICAgICAgIHJldHVybiBwLnNsaWNlKC1uKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGV2YWwyKHAsIHgpIHtcbiAgICAgICAgbGV0IHYgPSB0aGlzLkYuemVybztcbiAgICAgICAgbGV0IGl4ID0gdGhpcy5GLm9uZTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHAubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHYgPSB0aGlzLkYuYWRkKHYsIHRoaXMuRi5tdWwocFtpXSwgaXgpKTtcbiAgICAgICAgICAgIGl4ID0gdGhpcy5GLm11bChpeCwgeCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHY7XG4gICAgfVxuXG4gICAgZXZhbHVhdGUocCx4KSB7XG4gICAgICAgIGNvbnN0IEYgPSB0aGlzLkY7XG4gICAgICAgIGlmIChwLmxlbmd0aCA9PSAwKSByZXR1cm4gRi56ZXJvO1xuICAgICAgICBjb25zdCBtID0gdGhpcy5fbmV4dDJQb3dlcihwLmxlbmd0aCk7XG4gICAgICAgIGNvbnN0IGVwID0gdGhpcy5leHRlbmQocCwgbSk7XG5cbiAgICAgICAgcmV0dXJuIF9ldmFsKGVwLCB4LCAwLCAxLCBtKTtcblxuICAgICAgICBmdW5jdGlvbiBfZXZhbChwLCB4LCBvZmZzZXQsIHN0ZXAsIG4pIHtcbiAgICAgICAgICAgIGlmIChuPT0xKSByZXR1cm4gcFtvZmZzZXRdO1xuICAgICAgICAgICAgY29uc3QgbmV3WCA9IEYuc3F1YXJlKHgpO1xuICAgICAgICAgICAgY29uc3QgcmVzPSBGLmFkZChcbiAgICAgICAgICAgICAgICBfZXZhbChwLCBuZXdYLCBvZmZzZXQsIHN0ZXAgPDwgMSwgbiA+PiAxKSxcbiAgICAgICAgICAgICAgICBGLm11bChcbiAgICAgICAgICAgICAgICAgICAgeCxcbiAgICAgICAgICAgICAgICAgICAgX2V2YWwocCwgbmV3WCwgb2Zmc2V0K3N0ZXAgLCBzdGVwIDw8IDEsIG4gPj4gMSkpKTtcbiAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBsYWdyYW5nZShwb2ludHMpIHtcbiAgICAgICAgbGV0IHJvb3RzID0gW3RoaXMuRi5vbmVdO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8cG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICByb290cyA9IHRoaXMubXVsKHJvb3RzLCBbdGhpcy5GLm5lZyhwb2ludHNbaV1bMF0pLCB0aGlzLkYub25lXSk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgc3VtID0gW107XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxwb2ludHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGxldCBtcG9sID0gdGhpcy5ydWZmaW5pKHJvb3RzLCBwb2ludHNbaV1bMF0pO1xuICAgICAgICAgICAgY29uc3QgZmFjdG9yID1cbiAgICAgICAgICAgICAgICB0aGlzLkYubXVsKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLkYuaW52KHRoaXMuZXZhbHVhdGUobXBvbCwgcG9pbnRzW2ldWzBdKSksXG4gICAgICAgICAgICAgICAgICAgIHBvaW50c1tpXVsxXSk7XG4gICAgICAgICAgICBtcG9sID0gdGhpcy5tdWxTY2FsYXIobXBvbCwgZmFjdG9yKTtcbiAgICAgICAgICAgIHN1bSA9IHRoaXMuYWRkKHN1bSwgbXBvbCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN1bTtcbiAgICB9XG5cblxuICAgIGZmdChwKSB7XG4gICAgICAgIGlmIChwLmxlbmd0aCA8PSAxKSByZXR1cm4gcDtcbiAgICAgICAgY29uc3QgYml0cyA9IGxvZzIkMihwLmxlbmd0aC0xKSsxO1xuICAgICAgICB0aGlzLl9zZXRSb290cyhiaXRzKTtcblxuICAgICAgICBjb25zdCBtID0gMSA8PCBiaXRzO1xuICAgICAgICBjb25zdCBlcCA9IHRoaXMuZXh0ZW5kKHAsIG0pO1xuICAgICAgICBjb25zdCByZXMgPSBfX2ZmdCQxKHRoaXMsIGVwLCBiaXRzLCAwLCAxKTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICBmZnQyKHApIHtcbiAgICAgICAgaWYgKHAubGVuZ3RoIDw9IDEpIHJldHVybiBwO1xuICAgICAgICBjb25zdCBiaXRzID0gbG9nMiQyKHAubGVuZ3RoLTEpKzE7XG4gICAgICAgIHRoaXMuX3NldFJvb3RzKGJpdHMpO1xuXG4gICAgICAgIGNvbnN0IG0gPSAxIDw8IGJpdHM7XG4gICAgICAgIGNvbnN0IGVwID0gdGhpcy5leHRlbmQocCwgbSk7XG4gICAgICAgIF9fYml0UmV2ZXJzZShlcCwgYml0cyk7XG4gICAgICAgIGNvbnN0IHJlcyA9IF9fZmZ0Mih0aGlzLCBlcCwgYml0cyk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG5cbiAgICBpZmZ0KHApIHtcblxuICAgICAgICBpZiAocC5sZW5ndGggPD0gMSkgcmV0dXJuIHA7XG4gICAgICAgIGNvbnN0IGJpdHMgPSBsb2cyJDIocC5sZW5ndGgtMSkrMTtcbiAgICAgICAgdGhpcy5fc2V0Um9vdHMoYml0cyk7XG4gICAgICAgIGNvbnN0IG0gPSAxIDw8IGJpdHM7XG4gICAgICAgIGNvbnN0IGVwID0gdGhpcy5leHRlbmQocCwgbSk7XG4gICAgICAgIGNvbnN0IHJlcyA9ICBfX2ZmdCQxKHRoaXMsIGVwLCBiaXRzLCAwLCAxKTtcblxuICAgICAgICBjb25zdCB0d29pbnZtID0gdGhpcy5GLmludiggdGhpcy5GLm11bFNjYWxhcih0aGlzLkYub25lLCBtKSApO1xuICAgICAgICBjb25zdCByZXNuID0gbmV3IEFycmF5KG0pO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8bTsgaSsrKSB7XG4gICAgICAgICAgICByZXNuW2ldID0gdGhpcy5GLm11bChyZXNbKG0taSklbV0sIHR3b2ludm0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc247XG5cbiAgICB9XG5cblxuICAgIGlmZnQyKHApIHtcblxuICAgICAgICBpZiAocC5sZW5ndGggPD0gMSkgcmV0dXJuIHA7XG4gICAgICAgIGNvbnN0IGJpdHMgPSBsb2cyJDIocC5sZW5ndGgtMSkrMTtcbiAgICAgICAgdGhpcy5fc2V0Um9vdHMoYml0cyk7XG4gICAgICAgIGNvbnN0IG0gPSAxIDw8IGJpdHM7XG4gICAgICAgIGNvbnN0IGVwID0gdGhpcy5leHRlbmQocCwgbSk7XG4gICAgICAgIF9fYml0UmV2ZXJzZShlcCwgYml0cyk7XG4gICAgICAgIGNvbnN0IHJlcyA9ICBfX2ZmdDIodGhpcywgZXAsIGJpdHMpO1xuXG4gICAgICAgIGNvbnN0IHR3b2ludm0gPSB0aGlzLkYuaW52KCB0aGlzLkYubXVsU2NhbGFyKHRoaXMuRi5vbmUsIG0pICk7XG4gICAgICAgIGNvbnN0IHJlc24gPSBuZXcgQXJyYXkobSk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxtOyBpKyspIHtcbiAgICAgICAgICAgIHJlc25baV0gPSB0aGlzLkYubXVsKHJlc1sobS1pKSVtXSwgdHdvaW52bSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzbjtcblxuICAgIH1cblxuICAgIF9mZnQocGFsbCwgYml0cywgb2Zmc2V0LCBzdGVwKSB7XG5cbiAgICAgICAgY29uc3QgbiA9IDEgPDwgYml0cztcbiAgICAgICAgaWYgKG49PTEpIHtcbiAgICAgICAgICAgIHJldHVybiBbIHBhbGxbb2Zmc2V0XSBdO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbmRpdjIgPSBuID4+IDE7XG4gICAgICAgIGNvbnN0IHAxID0gdGhpcy5fZmZ0KHBhbGwsIGJpdHMtMSwgb2Zmc2V0LCBzdGVwKjIpO1xuICAgICAgICBjb25zdCBwMiA9IHRoaXMuX2ZmdChwYWxsLCBiaXRzLTEsIG9mZnNldCtzdGVwLCBzdGVwKjIpO1xuXG4gICAgICAgIGNvbnN0IG91dCA9IG5ldyBBcnJheShuKTtcblxuICAgICAgICBsZXQgbT0gdGhpcy5GLm9uZTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPG5kaXYyOyBpKyspIHtcbiAgICAgICAgICAgIG91dFtpXSA9IHRoaXMuRi5hZGQocDFbaV0sIHRoaXMuRi5tdWwobSwgcDJbaV0pKTtcbiAgICAgICAgICAgIG91dFtpK25kaXYyXSA9IHRoaXMuRi5zdWIocDFbaV0sIHRoaXMuRi5tdWwobSwgcDJbaV0pKTtcbiAgICAgICAgICAgIG0gPSB0aGlzLkYubXVsKG0sIHRoaXMud1tiaXRzXSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gb3V0O1xuICAgIH1cblxuICAgIGV4dGVuZChwLCBlKSB7XG4gICAgICAgIGlmIChlID09IHAubGVuZ3RoKSByZXR1cm4gcDtcbiAgICAgICAgY29uc3QgeiA9IG5ldyBBcnJheShlLXAubGVuZ3RoKS5maWxsKHRoaXMuRi56ZXJvKTtcblxuICAgICAgICByZXR1cm4gcC5jb25jYXQoeik7XG4gICAgfVxuXG4gICAgcmVkdWNlKHApIHtcbiAgICAgICAgaWYgKHAubGVuZ3RoID09IDApIHJldHVybiBwO1xuICAgICAgICBpZiAoISB0aGlzLkYuZXEocFtwLmxlbmd0aC0xXSwgdGhpcy5GLnplcm8pICkgcmV0dXJuIHA7XG4gICAgICAgIGxldCBpPXAubGVuZ3RoLTE7XG4gICAgICAgIHdoaWxlKCBpPjAgJiYgdGhpcy5GLmVxKHBbaV0sIHRoaXMuRi56ZXJvKSApIGktLTtcbiAgICAgICAgcmV0dXJuIHAuc2xpY2UoMCwgaSsxKTtcbiAgICB9XG5cbiAgICBlcShhLCBiKSB7XG4gICAgICAgIGNvbnN0IHBhID0gdGhpcy5yZWR1Y2UoYSk7XG4gICAgICAgIGNvbnN0IHBiID0gdGhpcy5yZWR1Y2UoYik7XG5cbiAgICAgICAgaWYgKHBhLmxlbmd0aCAhPSBwYi5sZW5ndGgpIHJldHVybiBmYWxzZTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHBiLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuRi5lcShwYVtpXSwgcGJbaV0pKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBydWZmaW5pKHAsIHIpIHtcbiAgICAgICAgY29uc3QgcmVzID0gbmV3IEFycmF5KHAubGVuZ3RoLTEpO1xuICAgICAgICByZXNbcmVzLmxlbmd0aC0xXSA9IHBbcC5sZW5ndGgtMV07XG4gICAgICAgIGZvciAobGV0IGkgPSByZXMubGVuZ3RoLTI7IGk+PTA7IGktLSkge1xuICAgICAgICAgICAgcmVzW2ldID0gdGhpcy5GLmFkZCh0aGlzLkYubXVsKHJlc1tpKzFdLCByKSwgcFtpKzFdKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuICAgIF9uZXh0MlBvd2VyKHYpIHtcbiAgICAgICAgdi0tO1xuICAgICAgICB2IHw9IHYgPj4gMTtcbiAgICAgICAgdiB8PSB2ID4+IDI7XG4gICAgICAgIHYgfD0gdiA+PiA0O1xuICAgICAgICB2IHw9IHYgPj4gODtcbiAgICAgICAgdiB8PSB2ID4+IDE2O1xuICAgICAgICB2Kys7XG4gICAgICAgIHJldHVybiB2O1xuICAgIH1cblxuICAgIHRvU3RyaW5nKHApIHtcbiAgICAgICAgY29uc3QgYXAgPSB0aGlzLm5vcm1hbGl6ZShwKTtcbiAgICAgICAgbGV0IFMgPSBcIlwiO1xuICAgICAgICBmb3IgKGxldCBpPWFwLmxlbmd0aC0xOyBpPj0wOyBpLS0pIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5GLmVxKHBbaV0sIHRoaXMuRi56ZXJvKSkge1xuICAgICAgICAgICAgICAgIGlmIChTIT1cIlwiKSBTICs9IFwiICsgXCI7XG4gICAgICAgICAgICAgICAgUyA9IFMgKyBwW2ldLnRvU3RyaW5nKDEwKTtcbiAgICAgICAgICAgICAgICBpZiAoaT4wKSB7XG4gICAgICAgICAgICAgICAgICAgIFMgPSBTICsgXCJ4XCI7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpPjEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFMgPSBTICsgXCJeXCIgK2k7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFM7XG4gICAgfVxuXG4gICAgbm9ybWFsaXplKHApIHtcbiAgICAgICAgY29uc3QgcmVzICA9IG5ldyBBcnJheShwLmxlbmd0aCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxwLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICByZXNbaV0gPSB0aGlzLkYubm9ybWFsaXplKHBbaV0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG5cbiAgICBfcmVjaXByb2NhbChwLCBiaXRzKSB7XG4gICAgICAgIGNvbnN0IGsgPSAxIDw8IGJpdHM7XG4gICAgICAgIGlmIChrPT0xKSB7XG4gICAgICAgICAgICByZXR1cm4gWyB0aGlzLkYuaW52KHBbMF0pIF07XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbnAgPSB0aGlzLnNjYWxlWChwLCAtay8yKTtcbiAgICAgICAgY29uc3QgcSA9IHRoaXMuX3JlY2lwcm9jYWwobnAsIGJpdHMtMSk7XG4gICAgICAgIGNvbnN0IGEgPSB0aGlzLnNjYWxlWCh0aGlzLmRvdWJsZShxKSwgMyprLzItMik7XG4gICAgICAgIGNvbnN0IGIgPSB0aGlzLm11bCggdGhpcy5zcXVhcmUocSksIHApO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnNjYWxlWCh0aGlzLnN1YihhLGIpLCAgIC0oay0yKSk7XG4gICAgfVxuXG4gICAgLy8gZGl2aWRlcyB4Xm0gLyB2XG4gICAgX2RpdjIobSwgdikge1xuICAgICAgICBjb25zdCBrYml0cyA9IGxvZzIkMih2Lmxlbmd0aC0xKSsxO1xuICAgICAgICBjb25zdCBrID0gMSA8PCBrYml0cztcblxuICAgICAgICBjb25zdCBzY2FsZVYgPSBrIC0gdi5sZW5ndGg7XG5cbiAgICAgICAgLy8gcmVjID0geF4oayAtIDIpIC8gdiogeF5zY2FsZVYgPT5cbiAgICAgICAgLy8gcmVjID0geF4oay0yLXNjYWxlVikvIHZcbiAgICAgICAgLy9cbiAgICAgICAgLy8gcmVzID0geF5tL3YgPSB4XihtICsgKDIqay0yIC0gc2NhbGVWKSAtICgyKmstMiAtIHNjYWxlVikpIC92ID0+XG4gICAgICAgIC8vIHJlcyA9IHJlYyAqIHheKG0gLSAoMiprLTIgLSBzY2FsZVYpKSA9PlxuICAgICAgICAvLyByZXMgPSByZWMgKiB4XihtIC0gMiprICsgMiArIHNjYWxlVilcblxuICAgICAgICBjb25zdCByZWMgPSB0aGlzLl9yZWNpcHJvY2FsKHRoaXMuc2NhbGVYKHYsIHNjYWxlViksIGtiaXRzKTtcbiAgICAgICAgY29uc3QgcmVzID0gdGhpcy5zY2FsZVgocmVjLCBtIC0gMiprICsgMiArIHNjYWxlVik7XG5cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICBkaXYoX3UsIF92KSB7XG4gICAgICAgIGlmIChfdS5sZW5ndGggPCBfdi5sZW5ndGgpIHJldHVybiBbXTtcbiAgICAgICAgY29uc3Qga2JpdHMgPSBsb2cyJDIoX3YubGVuZ3RoLTEpKzE7XG4gICAgICAgIGNvbnN0IGsgPSAxIDw8IGtiaXRzO1xuXG4gICAgICAgIGNvbnN0IHUgPSB0aGlzLnNjYWxlWChfdSwgay1fdi5sZW5ndGgpO1xuICAgICAgICBjb25zdCB2ID0gdGhpcy5zY2FsZVgoX3YsIGstX3YubGVuZ3RoKTtcblxuICAgICAgICBjb25zdCBuID0gdi5sZW5ndGgtMTtcbiAgICAgICAgbGV0IG0gPSB1Lmxlbmd0aC0xO1xuXG4gICAgICAgIGNvbnN0IHMgPSB0aGlzLl9yZWNpcHJvY2FsKHYsIGtiaXRzKTtcbiAgICAgICAgbGV0IHQ7XG4gICAgICAgIGlmIChtPjIqbikge1xuICAgICAgICAgICAgdCA9IHRoaXMuc3ViKHRoaXMuc2NhbGVYKFt0aGlzLkYub25lXSwgMipuKSwgdGhpcy5tdWwocywgdikpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHEgPSBbXTtcbiAgICAgICAgbGV0IHJlbSA9IHU7XG4gICAgICAgIGxldCB1cywgdXQ7XG4gICAgICAgIGxldCBmaW5pc2ggPSBmYWxzZTtcblxuICAgICAgICB3aGlsZSAoIWZpbmlzaCkge1xuICAgICAgICAgICAgdXMgPSB0aGlzLm11bChyZW0sIHMpO1xuICAgICAgICAgICAgcSA9IHRoaXMuYWRkKHEsIHRoaXMuc2NhbGVYKHVzLCAtMipuKSk7XG5cbiAgICAgICAgICAgIGlmICggbSA+IDIqbiApIHtcbiAgICAgICAgICAgICAgICB1dCA9IHRoaXMubXVsKHJlbSwgdCk7XG4gICAgICAgICAgICAgICAgcmVtID0gdGhpcy5zY2FsZVgodXQsIC0yKm4pO1xuICAgICAgICAgICAgICAgIG0gPSByZW0ubGVuZ3RoLTE7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGZpbmlzaCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcTtcbiAgICB9XG5cblxuICAgIC8vIHJldHVybnMgdGhlIGl0aCBudGgtcm9vdCBvZiBvbmVcbiAgICBvbmVSb290KG4sIGkpIHtcbiAgICAgICAgbGV0IG5iaXRzID0gbG9nMiQyKG4tMSkrMTtcbiAgICAgICAgbGV0IHJlcyA9IHRoaXMuRi5vbmU7XG4gICAgICAgIGxldCByID0gaTtcblxuICAgICAgICBpZihpPj1uKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJHaXZlbiAnaScgc2hvdWxkIGJlIGxvd2VyIHRoYW4gJ24nXCIpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKDE8PG5iaXRzICE9PSBuKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludGVybmFsIGVycmxyOiAke259IHNob3VsZCBlcXVhbCAkezE8PG5iaXRzfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgd2hpbGUgKHI+MCkge1xuICAgICAgICAgICAgaWYgKHIgJiAxID09IDEpIHtcbiAgICAgICAgICAgICAgICByZXMgPSB0aGlzLkYubXVsKHJlcywgdGhpcy53W25iaXRzXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByID0gciA+PiAxO1xuICAgICAgICAgICAgbmJpdHMgLS07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICBjb21wdXRlVmFuaXNoaW5nUG9saW5vbWlhbChiaXRzLCB0KSB7XG4gICAgICAgIGNvbnN0IG0gPSAxIDw8IGJpdHM7XG4gICAgICAgIHJldHVybiB0aGlzLkYuc3ViKHRoaXMuRi5wb3codCwgbSksIHRoaXMuRi5vbmUpO1xuICAgIH1cblxuICAgIGV2YWx1YXRlTGFncmFuZ2VQb2x5bm9taWFscyhiaXRzLCB0KSB7XG4gICAgICAgIGNvbnN0IG09IDEgPDwgYml0cztcbiAgICAgICAgY29uc3QgdG0gPSB0aGlzLkYucG93KHQsIG0pO1xuICAgICAgICBjb25zdCB1PSBuZXcgQXJyYXkobSkuZmlsbCh0aGlzLkYuemVybyk7XG4gICAgICAgIHRoaXMuX3NldFJvb3RzKGJpdHMpO1xuICAgICAgICBjb25zdCBvbWVnYSA9IHRoaXMud1tiaXRzXTtcblxuICAgICAgICBpZiAodGhpcy5GLmVxKHRtLCB0aGlzLkYub25lKSkge1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5GLmVxKHRoaXMucm9vdHNbYml0c11bMF0sdCkpIHsgLy8gaS5lLiwgdCBlcXVhbHMgb21lZ2FeaVxuICAgICAgICAgICAgICAgICAgICB1W2ldID0gdGhpcy5GLm9uZTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgeiA9IHRoaXMuRi5zdWIodG0sIHRoaXMuRi5vbmUpO1xuICAgICAgICAvLyAgICAgICAgbGV0IGwgPSB0aGlzLkYubXVsKHosICB0aGlzLkYucG93KHRoaXMuRi50d29pbnYsIG0pKTtcbiAgICAgICAgbGV0IGwgPSB0aGlzLkYubXVsKHosICB0aGlzLkYuaW52KHRoaXMuRi5lKG0pKSk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbTsgaSsrKSB7XG4gICAgICAgICAgICB1W2ldID0gdGhpcy5GLm11bChsLCB0aGlzLkYuaW52KHRoaXMuRi5zdWIodCx0aGlzLnJvb3RzW2JpdHNdW2ldKSkpO1xuICAgICAgICAgICAgbCA9IHRoaXMuRi5tdWwobCwgb21lZ2EpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHU7XG4gICAgfVxuXG4gICAgbG9nMihWKSB7XG4gICAgICAgIHJldHVybiBsb2cyJDIoVik7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBsb2cyJDIoIFYgKVxue1xuICAgIHJldHVybiggKCAoIFYgJiAweEZGRkYwMDAwICkgIT09IDAgPyAoIFYgJj0gMHhGRkZGMDAwMCwgMTYgKSA6IDAgKSB8ICggKCBWICYgMHhGRjAwRkYwMCApICE9PSAwID8gKCBWICY9IDB4RkYwMEZGMDAsIDggKSA6IDAgKSB8ICggKCBWICYgMHhGMEYwRjBGMCApICE9PSAwID8gKCBWICY9IDB4RjBGMEYwRjAsIDQgKSA6IDAgKSB8ICggKCBWICYgMHhDQ0NDQ0NDQyApICE9PSAwID8gKCBWICY9IDB4Q0NDQ0NDQ0MsIDIgKSA6IDAgKSB8ICggKCBWICYgMHhBQUFBQUFBQSApICE9PSAwICkgKTtcbn1cblxuXG5mdW5jdGlvbiBfX2ZmdCQxKFBGLCBwYWxsLCBiaXRzLCBvZmZzZXQsIHN0ZXApIHtcblxuICAgIGNvbnN0IG4gPSAxIDw8IGJpdHM7XG4gICAgaWYgKG49PTEpIHtcbiAgICAgICAgcmV0dXJuIFsgcGFsbFtvZmZzZXRdIF07XG4gICAgfSBlbHNlIGlmIChuPT0yKSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBQRi5GLmFkZChwYWxsW29mZnNldF0sIHBhbGxbb2Zmc2V0ICsgc3RlcF0pLFxuICAgICAgICAgICAgUEYuRi5zdWIocGFsbFtvZmZzZXRdLCBwYWxsW29mZnNldCArIHN0ZXBdKV07XG4gICAgfVxuXG4gICAgY29uc3QgbmRpdjIgPSBuID4+IDE7XG4gICAgY29uc3QgcDEgPSBfX2ZmdCQxKFBGLCBwYWxsLCBiaXRzLTEsIG9mZnNldCwgc3RlcCoyKTtcbiAgICBjb25zdCBwMiA9IF9fZmZ0JDEoUEYsIHBhbGwsIGJpdHMtMSwgb2Zmc2V0K3N0ZXAsIHN0ZXAqMik7XG5cbiAgICBjb25zdCBvdXQgPSBuZXcgQXJyYXkobik7XG5cbiAgICBmb3IgKGxldCBpPTA7IGk8bmRpdjI7IGkrKykge1xuICAgICAgICBvdXRbaV0gPSBQRi5GLmFkZChwMVtpXSwgUEYuRi5tdWwoUEYucm9vdHNbYml0c11baV0sIHAyW2ldKSk7XG4gICAgICAgIG91dFtpK25kaXYyXSA9IFBGLkYuc3ViKHAxW2ldLCBQRi5GLm11bChQRi5yb290c1tiaXRzXVtpXSwgcDJbaV0pKTtcbiAgICB9XG5cbiAgICByZXR1cm4gb3V0O1xufVxuXG5cbmZ1bmN0aW9uIF9fZmZ0MihQRiwgcGFsbCwgYml0cykge1xuXG4gICAgY29uc3QgbiA9IDEgPDwgYml0cztcbiAgICBpZiAobj09MSkge1xuICAgICAgICByZXR1cm4gWyBwYWxsWzBdIF07XG4gICAgfVxuXG4gICAgY29uc3QgbmRpdjIgPSBuID4+IDE7XG4gICAgY29uc3QgcDEgPSBfX2ZmdDIoUEYsIHBhbGwuc2xpY2UoMCwgbmRpdjIpLCBiaXRzLTEpO1xuICAgIGNvbnN0IHAyID0gX19mZnQyKFBGLCBwYWxsLnNsaWNlKG5kaXYyKSwgYml0cy0xKTtcblxuICAgIGNvbnN0IG91dCA9IG5ldyBBcnJheShuKTtcblxuICAgIGZvciAobGV0IGk9MDsgaTxuZGl2MjsgaSsrKSB7XG4gICAgICAgIG91dFtpXSA9IFBGLkYuYWRkKHAxW2ldLCBQRi5GLm11bChQRi5yb290c1tiaXRzXVtpXSwgcDJbaV0pKTtcbiAgICAgICAgb3V0W2krbmRpdjJdID0gUEYuRi5zdWIocDFbaV0sIFBGLkYubXVsKFBGLnJvb3RzW2JpdHNdW2ldLCBwMltpXSkpO1xuICAgIH1cblxuICAgIHJldHVybiBvdXQ7XG59XG5cbmNvbnN0IF9yZXZUYWJsZSQxID0gW107XG5mb3IgKGxldCBpPTA7IGk8MjU2OyBpKyspIHtcbiAgICBfcmV2VGFibGUkMVtpXSA9IF9yZXZTbG93JDEoaSwgOCk7XG59XG5cbmZ1bmN0aW9uIF9yZXZTbG93JDEoaWR4LCBiaXRzKSB7XG4gICAgbGV0IHJlcyA9MDtcbiAgICBsZXQgYSA9IGlkeDtcbiAgICBmb3IgKGxldCBpPTA7IGk8Yml0czsgaSsrKSB7XG4gICAgICAgIHJlcyA8PD0gMTtcbiAgICAgICAgcmVzID0gcmVzIHwgKGEgJjEpO1xuICAgICAgICBhID4+PTE7XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5cbmZ1bmN0aW9uIHJldihpZHgsIGJpdHMpIHtcbiAgICByZXR1cm4gKFxuICAgICAgICBfcmV2VGFibGUkMVtpZHggPj4+IDI0XSB8XG4gICAgICAgIChfcmV2VGFibGUkMVsoaWR4ID4+PiAxNikgJiAweEZGXSA8PCA4KSB8XG4gICAgICAgIChfcmV2VGFibGUkMVsoaWR4ID4+PiA4KSAmIDB4RkZdIDw8IDE2KSB8XG4gICAgICAgIChfcmV2VGFibGUkMVtpZHggJiAweEZGXSA8PCAyNClcbiAgICApID4+PiAoMzItYml0cyk7XG59XG5cbmZ1bmN0aW9uIF9fYml0UmV2ZXJzZShwLCBiaXRzKSB7XG4gICAgZm9yIChsZXQgaz0wOyBrPHAubGVuZ3RoOyBrKyspIHtcbiAgICAgICAgY29uc3QgciA9IHJldihrLCBiaXRzKTtcbiAgICAgICAgaWYgKHI+aykge1xuICAgICAgICAgICAgY29uc3QgdG1wPSBwW2tdO1xuICAgICAgICAgICAgcFtrXSA9IHBbcl07XG4gICAgICAgICAgICBwW3JdID0gdG1wO1xuICAgICAgICB9XG4gICAgfVxuXG59XG5cbi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMGtpbXMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya2pzLlxuXG4gICAgc25hcmtqcyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuICAgIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGVcbiAgICBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbilcbiAgICBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJranMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3JcbiAgICBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoXG4gICAgc25hcmtqcy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cblxuXG5mdW5jdGlvbiBtdWxTY2FsYXIoRiwgYmFzZSwgZSkge1xuICAgIGxldCByZXM7XG5cbiAgICBpZiAoaXNaZXJvKGUpKSByZXR1cm4gRi56ZXJvO1xuXG4gICAgY29uc3QgbiA9IG5hZihlKTtcblxuICAgIGlmIChuW24ubGVuZ3RoLTFdID09IDEpIHtcbiAgICAgICAgcmVzID0gYmFzZTtcbiAgICB9IGVsc2UgaWYgKG5bbi5sZW5ndGgtMV0gPT0gLTEpIHtcbiAgICAgICAgcmVzID0gRi5uZWcoYmFzZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaW52bGF1ZCBOQUZcIik7XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaT1uLmxlbmd0aC0yOyBpPj0wOyBpLS0pIHtcblxuICAgICAgICByZXMgPSBGLmRvdWJsZShyZXMpO1xuXG4gICAgICAgIGlmIChuW2ldID09IDEpIHtcbiAgICAgICAgICAgIHJlcyA9IEYuYWRkKHJlcywgYmFzZSk7XG4gICAgICAgIH0gZWxzZSBpZiAobltpXSA9PSAtMSkge1xuICAgICAgICAgICAgcmVzID0gRi5zdWIocmVzLCBiYXNlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cblxuLypcbmV4cG9ydHMubXVsU2NhbGFyID0gKEYsIGJhc2UsIGUpID0+e1xuICAgIGxldCByZXMgPSBGLnplcm87XG4gICAgbGV0IHJlbSA9IGJpZ0ludChlKTtcbiAgICBsZXQgZXhwID0gYmFzZTtcblxuICAgIHdoaWxlICghIHJlbS5lcShiaWdJbnQuemVybykpIHtcbiAgICAgICAgaWYgKHJlbS5hbmQoYmlnSW50Lm9uZSkuZXEoYmlnSW50Lm9uZSkpIHtcbiAgICAgICAgICAgIHJlcyA9IEYuYWRkKHJlcywgZXhwKTtcbiAgICAgICAgfVxuICAgICAgICBleHAgPSBGLmRvdWJsZShleHApO1xuICAgICAgICByZW0gPSByZW0uc2hpZnRSaWdodCgxKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzO1xufTtcbiovXG5cblxuZnVuY3Rpb24gZXhwKEYsIGJhc2UsIGUpIHtcblxuICAgIGlmIChpc1plcm8oZSkpIHJldHVybiBGLm9uZTtcblxuICAgIGNvbnN0IG4gPSBiaXRzKGUpO1xuXG4gICAgaWYgKG4ubGVuZ3RoPT0wKSByZXR1cm4gRi5vbmU7XG5cbiAgICBsZXQgcmVzID0gYmFzZTtcblxuICAgIGZvciAobGV0IGk9bi5sZW5ndGgtMjsgaT49MDsgaS0tKSB7XG5cbiAgICAgICAgcmVzID0gRi5zcXVhcmUocmVzKTtcblxuICAgICAgICBpZiAobltpXSkge1xuICAgICAgICAgICAgcmVzID0gRi5tdWwocmVzLCBiYXNlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbi8vIENoZWNrIGhlcmU6IGh0dHBzOi8vZXByaW50LmlhY3Iub3JnLzIwMTIvNjg1LnBkZlxuXG5mdW5jdGlvbiBidWlsZFNxcnQgKEYpIHtcbiAgICBpZiAoKEYubSAlIDIpID09IDEpIHtcbiAgICAgICAgaWYgKGVxKG1vZChGLnAsIDQpLCAxICkpIHtcbiAgICAgICAgICAgIGlmIChlcShtb2QoRi5wLCA4KSwgMSApKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVxKG1vZChGLnAsIDE2KSwgMSApKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFsZzdfbXVsbGVyKEYpO1xuICAgICAgICAgICAgICAgICAgICBhbGc1X3RvbmVsbGlTaGFua3MoRik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChlcShtb2QoRi5wLCAxNiksIDkgKSkge1xuICAgICAgICAgICAgICAgICAgICBhbGc0X2tvbmcoRik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmllbGQgd2l0aG90IHNxcnRcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmIChlcShtb2QoRi5wLCA4KSwgNSApKSB7XG4gICAgICAgICAgICAgICAgYWxnM19hdGtpbihGKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmllbGQgd2l0aG90IHNxcnRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZXEobW9kKEYucCwgNCksIDMgKSkge1xuICAgICAgICAgICAgYWxnMl9zaGFua3MoRik7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBwbTJtb2Q0ID0gbW9kKHBvdyhGLnAsIEYubS8yKSwgNCk7XG4gICAgICAgIGlmIChwbTJtb2Q0ID09IDEpIHtcbiAgICAgICAgICAgIGFsZzEwX2FkaihGKTtcbiAgICAgICAgfSBlbHNlIGlmIChwbTJtb2Q0ID09IDMpIHtcbiAgICAgICAgICAgIGFsZzlfYWRqKEYpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWxnOF9jb21wbGV4KEYpO1xuICAgICAgICB9XG5cbiAgICB9XG59XG5cblxuZnVuY3Rpb24gYWxnNV90b25lbGxpU2hhbmtzKEYpIHtcbiAgICBGLnNxcnRfcSA9IHBvdyhGLnAsIEYubSk7XG5cbiAgICBGLnNxcnRfcyA9IDA7XG4gICAgRi5zcXJ0X3QgPSBzdWIoRi5zcXJ0X3EsIDEpO1xuXG4gICAgd2hpbGUgKCFpc09kZChGLnNxcnRfdCkpIHtcbiAgICAgICAgRi5zcXJ0X3MgPSBGLnNxcnRfcyArIDE7XG4gICAgICAgIEYuc3FydF90ID0gZGl2KEYuc3FydF90LCAyKTtcbiAgICB9XG5cbiAgICBsZXQgYzAgPSBGLm9uZTtcblxuICAgIHdoaWxlIChGLmVxKGMwLCBGLm9uZSkpIHtcbiAgICAgICAgY29uc3QgYyA9IEYucmFuZG9tKCk7XG4gICAgICAgIEYuc3FydF96ID0gRi5wb3coYywgRi5zcXJ0X3QpO1xuICAgICAgICBjMCA9IEYucG93KEYuc3FydF96LCAyICoqIChGLnNxcnRfcy0xKSApO1xuICAgIH1cblxuICAgIEYuc3FydF90bTFkMiA9IGRpdihzdWIoRi5zcXJ0X3QsIDEpLDIpO1xuXG4gICAgRi5zcXJ0ID0gZnVuY3Rpb24oYSkge1xuICAgICAgICBjb25zdCBGPXRoaXM7XG4gICAgICAgIGlmIChGLmlzWmVybyhhKSkgcmV0dXJuIEYuemVybztcbiAgICAgICAgbGV0IHcgPSBGLnBvdyhhLCBGLnNxcnRfdG0xZDIpO1xuICAgICAgICBjb25zdCBhMCA9IEYucG93KCBGLm11bChGLnNxdWFyZSh3KSwgYSksIDIgKiogKEYuc3FydF9zLTEpICk7XG4gICAgICAgIGlmIChGLmVxKGEwLCBGLm5lZ29uZSkpIHJldHVybiBudWxsO1xuXG4gICAgICAgIGxldCB2ID0gRi5zcXJ0X3M7XG4gICAgICAgIGxldCB4ID0gRi5tdWwoYSwgdyk7XG4gICAgICAgIGxldCBiID0gRi5tdWwoeCwgdyk7XG4gICAgICAgIGxldCB6ID0gRi5zcXJ0X3o7XG4gICAgICAgIHdoaWxlICghRi5lcShiLCBGLm9uZSkpIHtcbiAgICAgICAgICAgIGxldCBiMmsgPSBGLnNxdWFyZShiKTtcbiAgICAgICAgICAgIGxldCBrPTE7XG4gICAgICAgICAgICB3aGlsZSAoIUYuZXEoYjJrLCBGLm9uZSkpIHtcbiAgICAgICAgICAgICAgICBiMmsgPSBGLnNxdWFyZShiMmspO1xuICAgICAgICAgICAgICAgIGsrKztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdyA9IHo7XG4gICAgICAgICAgICBmb3IgKGxldCBpPTA7IGk8di1rLTE7IGkrKykge1xuICAgICAgICAgICAgICAgIHcgPSBGLnNxdWFyZSh3KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHogPSBGLnNxdWFyZSh3KTtcbiAgICAgICAgICAgIGIgPSBGLm11bChiLCB6KTtcbiAgICAgICAgICAgIHggPSBGLm11bCh4LCB3KTtcbiAgICAgICAgICAgIHYgPSBrO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBGLmdlcSh4LCBGLnplcm8pID8geCA6IEYubmVnKHgpO1xuICAgIH07XG59XG5cbmZ1bmN0aW9uIGFsZzRfa29uZyhGKSB7XG4gICAgRi5zcXJ0ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlNxcnQgYWxnIDQgbm90IGltcGxlbWVudGVkXCIpO1xuICAgIH07XG59XG5cbmZ1bmN0aW9uIGFsZzNfYXRraW4oRikge1xuICAgIEYuc3FydCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJTcXJ0IGFsZyAzIG5vdCBpbXBsZW1lbnRlZFwiKTtcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBhbGcyX3NoYW5rcyhGKSB7XG5cbiAgICBGLnNxcnRfcSA9IHBvdyhGLnAsIEYubSk7XG4gICAgRi5zcXJ0X2UxID0gZGl2KCBzdWIoRi5zcXJ0X3EsIDMpICwgNCk7XG5cbiAgICBGLnNxcnQgPSBmdW5jdGlvbihhKSB7XG4gICAgICAgIGlmICh0aGlzLmlzWmVybyhhKSkgcmV0dXJuIHRoaXMuemVybztcblxuICAgICAgICAvLyBUZXN0IHRoYXQgaGF2ZSBzb2x1dGlvblxuICAgICAgICBjb25zdCBhMSA9IHRoaXMucG93KGEsIHRoaXMuc3FydF9lMSk7XG5cbiAgICAgICAgY29uc3QgYTAgPSB0aGlzLm11bCh0aGlzLnNxdWFyZShhMSksIGEpO1xuXG4gICAgICAgIGlmICggdGhpcy5lcShhMCwgdGhpcy5uZWdvbmUpICkgcmV0dXJuIG51bGw7XG5cbiAgICAgICAgY29uc3QgeCA9IHRoaXMubXVsKGExLCBhKTtcblxuICAgICAgICByZXR1cm4gRi5nZXEoeCwgRi56ZXJvKSA/IHggOiBGLm5lZyh4KTtcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBhbGcxMF9hZGooRikge1xuICAgIEYuc3FydCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJTcXJ0IGFsZyAxMCBub3QgaW1wbGVtZW50ZWRcIik7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gYWxnOV9hZGooRikge1xuICAgIEYuc3FydF9xID0gcG93KEYucCwgRi5tLzIpO1xuICAgIEYuc3FydF9lMzQgPSBkaXYoIHN1YihGLnNxcnRfcSwgMykgLCA0KTtcbiAgICBGLnNxcnRfZTEyID0gZGl2KCBzdWIoRi5zcXJ0X3EsIDEpICwgMik7XG5cbiAgICBGLmZyb2Jlbml1cyA9IGZ1bmN0aW9uKG4sIHgpIHtcbiAgICAgICAgaWYgKChuJTIpID09IDEpIHtcbiAgICAgICAgICAgIHJldHVybiBGLmNvbmp1Z2F0ZSh4KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB4O1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIEYuc3FydCA9IGZ1bmN0aW9uKGEpIHtcbiAgICAgICAgY29uc3QgRiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGExID0gRi5wb3coYSwgRi5zcXJ0X2UzNCk7XG4gICAgICAgIGNvbnN0IGFsZmEgPSBGLm11bChGLnNxdWFyZShhMSksIGEpO1xuICAgICAgICBjb25zdCBhMCA9IEYubXVsKEYuZnJvYmVuaXVzKDEsIGFsZmEpLCBhbGZhKTtcbiAgICAgICAgaWYgKEYuZXEoYTAsIEYubmVnb25lKSkgcmV0dXJuIG51bGw7XG4gICAgICAgIGNvbnN0IHgwID0gRi5tdWwoYTEsIGEpO1xuICAgICAgICBsZXQgeDtcbiAgICAgICAgaWYgKEYuZXEoYWxmYSwgRi5uZWdvbmUpKSB7XG4gICAgICAgICAgICB4ID0gRi5tdWwoeDAsIFtGLkYuemVybywgRi5GLm9uZV0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgYiA9IEYucG93KEYuYWRkKEYub25lLCBhbGZhKSwgRi5zcXJ0X2UxMik7XG4gICAgICAgICAgICB4ID0gRi5tdWwoYiwgeDApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBGLmdlcSh4LCBGLnplcm8pID8geCA6IEYubmVnKHgpO1xuICAgIH07XG59XG5cblxuZnVuY3Rpb24gYWxnOF9jb21wbGV4KEYpIHtcbiAgICBGLnNxcnQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU3FydCBhbGcgOCBub3QgaW1wbGVtZW50ZWRcIik7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gcXVhcnRlclJvdW5kKHN0LCBhLCBiLCBjLCBkKSB7XG5cbiAgICBzdFthXSA9IChzdFthXSArIHN0W2JdKSA+Pj4gMDtcbiAgICBzdFtkXSA9IChzdFtkXSBeIHN0W2FdKSA+Pj4gMDtcbiAgICBzdFtkXSA9ICgoc3RbZF0gPDwgMTYpIHwgKChzdFtkXT4+PjE2KSAmIDB4RkZGRikpID4+PiAwO1xuXG4gICAgc3RbY10gPSAoc3RbY10gKyBzdFtkXSkgPj4+IDA7XG4gICAgc3RbYl0gPSAoc3RbYl0gXiBzdFtjXSkgPj4+IDA7XG4gICAgc3RbYl0gPSAoKHN0W2JdIDw8IDEyKSB8ICgoc3RbYl0+Pj4yMCkgJiAweEZGRikpID4+PiAwO1xuXG4gICAgc3RbYV0gPSAoc3RbYV0gKyBzdFtiXSkgPj4+IDA7XG4gICAgc3RbZF0gPSAoc3RbZF0gXiBzdFthXSkgPj4+IDA7XG4gICAgc3RbZF0gPSAoKHN0W2RdIDw8IDgpIHwgKChzdFtkXT4+PjI0KSAmIDB4RkYpKSA+Pj4gMDtcblxuICAgIHN0W2NdID0gKHN0W2NdICsgc3RbZF0pID4+PiAwO1xuICAgIHN0W2JdID0gKHN0W2JdIF4gc3RbY10pID4+PiAwO1xuICAgIHN0W2JdID0gKChzdFtiXSA8PCA3KSB8ICgoc3RbYl0+Pj4yNSkgJiAweDdGKSkgPj4+IDA7XG59XG5cbmZ1bmN0aW9uIGRvdWJsZVJvdW5kKHN0KSB7XG4gICAgcXVhcnRlclJvdW5kKHN0LCAwLCA0LCA4LDEyKTtcbiAgICBxdWFydGVyUm91bmQoc3QsIDEsIDUsIDksMTMpO1xuICAgIHF1YXJ0ZXJSb3VuZChzdCwgMiwgNiwxMCwxNCk7XG4gICAgcXVhcnRlclJvdW5kKHN0LCAzLCA3LDExLDE1KTtcblxuICAgIHF1YXJ0ZXJSb3VuZChzdCwgMCwgNSwxMCwxNSk7XG4gICAgcXVhcnRlclJvdW5kKHN0LCAxLCA2LDExLDEyKTtcbiAgICBxdWFydGVyUm91bmQoc3QsIDIsIDcsIDgsMTMpO1xuICAgIHF1YXJ0ZXJSb3VuZChzdCwgMywgNCwgOSwxNCk7XG59XG5cbmNsYXNzIENoYUNoYSB7XG5cbiAgICBjb25zdHJ1Y3RvcihzZWVkKSB7XG4gICAgICAgIHNlZWQgPSBzZWVkIHx8IFswLDAsMCwwLDAsMCwwLDBdO1xuICAgICAgICB0aGlzLnN0YXRlID0gW1xuICAgICAgICAgICAgMHg2MTcwNzg2NSxcbiAgICAgICAgICAgIDB4MzMyMDY0NkUsXG4gICAgICAgICAgICAweDc5NjIyRDMyLFxuICAgICAgICAgICAgMHg2QjIwNjU3NCxcbiAgICAgICAgICAgIHNlZWRbMF0sXG4gICAgICAgICAgICBzZWVkWzFdLFxuICAgICAgICAgICAgc2VlZFsyXSxcbiAgICAgICAgICAgIHNlZWRbM10sXG4gICAgICAgICAgICBzZWVkWzRdLFxuICAgICAgICAgICAgc2VlZFs1XSxcbiAgICAgICAgICAgIHNlZWRbNl0sXG4gICAgICAgICAgICBzZWVkWzddLFxuICAgICAgICAgICAgMCxcbiAgICAgICAgICAgIDAsXG4gICAgICAgICAgICAwLFxuICAgICAgICAgICAgMFxuICAgICAgICBdO1xuICAgICAgICB0aGlzLmlkeCA9IDE2O1xuICAgICAgICB0aGlzLmJ1ZmYgPSBuZXcgQXJyYXkoMTYpO1xuICAgIH1cblxuICAgIG5leHRVMzIoKSB7XG4gICAgICAgIGlmICh0aGlzLmlkeCA9PSAxNikgdGhpcy51cGRhdGUoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuYnVmZlt0aGlzLmlkeCsrXTtcbiAgICB9XG5cbiAgICBuZXh0VTY0KCkge1xuICAgICAgICByZXR1cm4gYWRkKG11bCh0aGlzLm5leHRVMzIoKSwgMHgxMDAwMDAwMDApLCB0aGlzLm5leHRVMzIoKSk7XG4gICAgfVxuXG4gICAgbmV4dEJvb2woKSB7XG4gICAgICAgIHJldHVybiAodGhpcy5uZXh0VTMyKCkgJiAxKSA9PSAxO1xuICAgIH1cblxuICAgIHVwZGF0ZSgpIHtcbiAgICAgICAgLy8gQ29weSB0aGUgc3RhdGVcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPDE2OyBpKyspIHRoaXMuYnVmZltpXSA9IHRoaXMuc3RhdGVbaV07XG5cbiAgICAgICAgLy8gQXBwbHkgdGhlIHJvdW5kc1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8MTA7IGkrKykgZG91YmxlUm91bmQodGhpcy5idWZmKTtcblxuICAgICAgICAvLyBBZGQgdG8gdGhlIGluaXRpYWxcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPDE2OyBpKyspIHRoaXMuYnVmZltpXSA9ICh0aGlzLmJ1ZmZbaV0gKyB0aGlzLnN0YXRlW2ldKSA+Pj4gMDtcblxuICAgICAgICB0aGlzLmlkeCA9IDA7XG5cbiAgICAgICAgdGhpcy5zdGF0ZVsxMl0gPSAodGhpcy5zdGF0ZVsxMl0gKyAxKSA+Pj4gMDtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGVbMTJdICE9IDApIHJldHVybjtcbiAgICAgICAgdGhpcy5zdGF0ZVsxM10gPSAodGhpcy5zdGF0ZVsxM10gKyAxKSA+Pj4gMDtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGVbMTNdICE9IDApIHJldHVybjtcbiAgICAgICAgdGhpcy5zdGF0ZVsxNF0gPSAodGhpcy5zdGF0ZVsxNF0gKyAxKSA+Pj4gMDtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGVbMTRdICE9IDApIHJldHVybjtcbiAgICAgICAgdGhpcy5zdGF0ZVsxNV0gPSAodGhpcy5zdGF0ZVsxNV0gKyAxKSA+Pj4gMDtcbiAgICB9XG59XG5cbnZhciBvcyA9IHt9O1xuXG5mdW5jdGlvbiBnZXRSYW5kb21CeXRlcyhuKSB7XG4gICAgbGV0IGFycmF5ID0gbmV3IFVpbnQ4QXJyYXkobik7XG4gICAgLy8gRmVhdHVyZS1kZXRlY3QgcmF0aGVyIHRoYW4gcmVseSBvbiBgdHJ1ZWAgKHVuZGVmaW5lZCB1bmRlclxuICAgIC8vIFZpdGUvZXNidWlsZC9TRVMgLT4gUmVmZXJlbmNlRXJyb3IpLiBQcmVmZXIgTm9kZSBjcnlwdG8gKG5vIHBlci1jYWxsIHNpemVcbiAgICAvLyBsaW1pdCk7IGZhbGwgYmFjayB0byBXZWIgQ3J5cHRvIGNodW5rZWQgdG8gaXRzIDY1NTM2LWJ5dGUgY2FwLlxuICAgIGlmIChvcyAmJiBvcy5yYW5kb21GaWxsU3luYykgeyAvLyBOb2RlXG4gICAgICAgIG9zLnJhbmRvbUZpbGxTeW5jKGFycmF5KTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBnbG9iYWxUaGlzLmNyeXB0byAhPT0gXCJ1bmRlZmluZWRcIiAmJiBnbG9iYWxUaGlzLmNyeXB0by5nZXRSYW5kb21WYWx1ZXMpIHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpICs9IDY1NTM2KSB7XG4gICAgICAgICAgICBnbG9iYWxUaGlzLmNyeXB0by5nZXRSYW5kb21WYWx1ZXMoYXJyYXkuc3ViYXJyYXkoaSwgTWF0aC5taW4oaSArIDY1NTM2LCBuKSkpO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHsgLy8gaW5zZWN1cmUgbGFzdCByZXNvcnRcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPG47IGkrKykge1xuICAgICAgICAgICAgYXJyYXlbaV0gPSAoTWF0aC5yYW5kb20oKSo0Mjk0OTY3Mjk2KT4+PjA7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGFycmF5O1xufVxuXG5mdW5jdGlvbiBnZXRSYW5kb21TZWVkKCkge1xuICAgIGNvbnN0IGFyciA9IGdldFJhbmRvbUJ5dGVzKDMyKTtcbiAgICBjb25zdCBhcnJWID0gbmV3IFVpbnQzMkFycmF5KGFyci5idWZmZXIpO1xuICAgIGNvbnN0IHNlZWQgPSBbXTtcbiAgICBmb3IgKGxldCBpPTA7IGk8ODsgaSsrKSB7XG4gICAgICAgIHNlZWQucHVzaChhcnJWW2ldKTtcbiAgICB9XG4gICAgcmV0dXJuIHNlZWQ7XG59XG5cbmxldCB0aHJlYWRSbmcgPSBudWxsO1xuXG5mdW5jdGlvbiBnZXRUaHJlYWRSbmcoKSB7XG4gICAgaWYgKHRocmVhZFJuZykgcmV0dXJuIHRocmVhZFJuZztcbiAgICB0aHJlYWRSbmcgPSBuZXcgQ2hhQ2hhKGdldFJhbmRvbVNlZWQoKSk7XG4gICAgcmV0dXJuIHRocmVhZFJuZztcbn1cblxuLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwa2ltcyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJranMuXG5cbiAgICBzbmFya2pzIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4gICAgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZVxuICAgIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKVxuICAgIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtqcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvclxuICAgIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGhcbiAgICBzbmFya2pzLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuLypcbiAgICBUaGlzIGxpYnJhcnkgZG9lcyBvcGVyYXRpb25zIG9uIHBvbHlub21pYWxzIHdpdGggY29lZmZpY2llbnRzIGluIGEgZmllbGQgRi5cblxuICAgIEEgcG9seW5vbWlhbCBQKHgpID0gcDAgKyBwMSAqIHggKyBwMiAqIHheMiArIC4uLiArIHBuICogeF5uICBpcyByZXByZXNlbnRlZFxuICAgIGJ5IHRoZSBhcnJheSBbIHAwLCBwMSwgcDIsIC4uLiAsIHBuIF0uXG4gKi9cblxuY2xhc3MgRkZUIHtcbiAgICBjb25zdHJ1Y3RvciAoRywgRiwgb3BNdWxHRikge1xuICAgICAgICB0aGlzLkYgPSBGO1xuICAgICAgICB0aGlzLkcgPSBHO1xuICAgICAgICB0aGlzLm9wTXVsR0YgPSBvcE11bEdGO1xuXG4gICAgICAgIGxldCByZW0gPSBGLnNxcnRfdCB8fCBGLnQ7XG4gICAgICAgIGxldCBzID0gRi5zcXJ0X3MgfHwgRi5zO1xuXG4gICAgICAgIGxldCBucXIgPSBGLm9uZTtcbiAgICAgICAgd2hpbGUgKEYuZXEoRi5wb3cobnFyLCBGLmhhbGYpLCBGLm9uZSkpIG5xciA9IEYuYWRkKG5xciwgRi5vbmUpO1xuXG4gICAgICAgIHRoaXMudyA9IG5ldyBBcnJheShzKzEpO1xuICAgICAgICB0aGlzLndpID0gbmV3IEFycmF5KHMrMSk7XG4gICAgICAgIHRoaXMud1tzXSA9IHRoaXMuRi5wb3cobnFyLCByZW0pO1xuICAgICAgICB0aGlzLndpW3NdID0gdGhpcy5GLmludih0aGlzLndbc10pO1xuXG4gICAgICAgIGxldCBuPXMtMTtcbiAgICAgICAgd2hpbGUgKG4+PTApIHtcbiAgICAgICAgICAgIHRoaXMud1tuXSA9IHRoaXMuRi5zcXVhcmUodGhpcy53W24rMV0pO1xuICAgICAgICAgICAgdGhpcy53aVtuXSA9IHRoaXMuRi5zcXVhcmUodGhpcy53aVtuKzFdKTtcbiAgICAgICAgICAgIG4tLTtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgdGhpcy5yb290cyA9IFtdO1xuICAgICAgICAvKlxuICAgICAgICBmb3IgKGxldCBpPTA7IGk8MTY7IGkrKykge1xuICAgICAgICAgICAgbGV0IHIgPSB0aGlzLkYub25lO1xuICAgICAgICAgICAgbiA9IDEgPDwgaTtcbiAgICAgICAgICAgIGNvbnN0IHJvb3RzaSA9IG5ldyBBcnJheShuKTtcbiAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxuOyBqKyspIHtcbiAgICAgICAgICAgICAgICByb290c2lbal0gPSByO1xuICAgICAgICAgICAgICAgIHIgPSB0aGlzLkYubXVsKHIsIHRoaXMud1tpXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMucm9vdHMucHVzaChyb290c2kpO1xuICAgICAgICB9XG4gICAgICAgICovXG4gICAgICAgIHRoaXMuX3NldFJvb3RzKE1hdGgubWluKHMsIDE1KSk7XG4gICAgfVxuXG4gICAgX3NldFJvb3RzKG4pIHtcbiAgICAgICAgZm9yIChsZXQgaT1uOyAoaT49MCkgJiYgKCF0aGlzLnJvb3RzW2ldKTsgaS0tKSB7XG4gICAgICAgICAgICBsZXQgciA9IHRoaXMuRi5vbmU7XG4gICAgICAgICAgICBjb25zdCBucm9vdHMgPSAxIDw8IGk7XG4gICAgICAgICAgICBjb25zdCByb290c2kgPSBuZXcgQXJyYXkobnJvb3RzKTtcbiAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxucm9vdHM7IGorKykge1xuICAgICAgICAgICAgICAgIHJvb3RzaVtqXSA9IHI7XG4gICAgICAgICAgICAgICAgciA9IHRoaXMuRi5tdWwociwgdGhpcy53W2ldKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5yb290c1tpXSA9IHJvb3RzaTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZmdChwKSB7XG4gICAgICAgIGlmIChwLmxlbmd0aCA8PSAxKSByZXR1cm4gcDtcbiAgICAgICAgY29uc3QgYml0cyA9IGxvZzIkMShwLmxlbmd0aC0xKSsxO1xuICAgICAgICB0aGlzLl9zZXRSb290cyhiaXRzKTtcblxuICAgICAgICBjb25zdCBtID0gMSA8PCBiaXRzO1xuICAgICAgICBpZiAocC5sZW5ndGggIT0gbSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU2l6ZSBtdXN0IGJlIG11bHRpcGxlIG9mIDJcIik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcmVzID0gX19mZnQodGhpcywgcCwgYml0cywgMCwgMSk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgaWZmdChwKSB7XG5cbiAgICAgICAgaWYgKHAubGVuZ3RoIDw9IDEpIHJldHVybiBwO1xuICAgICAgICBjb25zdCBiaXRzID0gbG9nMiQxKHAubGVuZ3RoLTEpKzE7XG4gICAgICAgIHRoaXMuX3NldFJvb3RzKGJpdHMpO1xuICAgICAgICBjb25zdCBtID0gMSA8PCBiaXRzO1xuICAgICAgICBpZiAocC5sZW5ndGggIT0gbSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU2l6ZSBtdXN0IGJlIG11bHRpcGxlIG9mIDJcIik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcmVzID0gIF9fZmZ0KHRoaXMsIHAsIGJpdHMsIDAsIDEpO1xuICAgICAgICBjb25zdCB0d29pbnZtID0gdGhpcy5GLmludiggdGhpcy5GLm11bFNjYWxhcih0aGlzLkYub25lLCBtKSApO1xuICAgICAgICBjb25zdCByZXNuID0gbmV3IEFycmF5KG0pO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8bTsgaSsrKSB7XG4gICAgICAgICAgICByZXNuW2ldID0gdGhpcy5vcE11bEdGKHJlc1sobS1pKSVtXSwgdHdvaW52bSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzbjtcbiAgICB9XG5cblxufVxuXG5mdW5jdGlvbiBsb2cyJDEoIFYgKVxue1xuICAgIHJldHVybiggKCAoIFYgJiAweEZGRkYwMDAwICkgIT09IDAgPyAoIFYgJj0gMHhGRkZGMDAwMCwgMTYgKSA6IDAgKSB8ICggKCBWICYgMHhGRjAwRkYwMCApICE9PSAwID8gKCBWICY9IDB4RkYwMEZGMDAsIDggKSA6IDAgKSB8ICggKCBWICYgMHhGMEYwRjBGMCApICE9PSAwID8gKCBWICY9IDB4RjBGMEYwRjAsIDQgKSA6IDAgKSB8ICggKCBWICYgMHhDQ0NDQ0NDQyApICE9PSAwID8gKCBWICY9IDB4Q0NDQ0NDQ0MsIDIgKSA6IDAgKSB8ICggKCBWICYgMHhBQUFBQUFBQSApICE9PSAwICkgKTtcbn1cblxuXG5mdW5jdGlvbiBfX2ZmdChQRiwgcGFsbCwgYml0cywgb2Zmc2V0LCBzdGVwKSB7XG5cbiAgICBjb25zdCBuID0gMSA8PCBiaXRzO1xuICAgIGlmIChuPT0xKSB7XG4gICAgICAgIHJldHVybiBbIHBhbGxbb2Zmc2V0XSBdO1xuICAgIH0gZWxzZSBpZiAobj09Mikge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgUEYuRy5hZGQocGFsbFtvZmZzZXRdLCBwYWxsW29mZnNldCArIHN0ZXBdKSxcbiAgICAgICAgICAgIFBGLkcuc3ViKHBhbGxbb2Zmc2V0XSwgcGFsbFtvZmZzZXQgKyBzdGVwXSldO1xuICAgIH1cblxuICAgIGNvbnN0IG5kaXYyID0gbiA+PiAxO1xuICAgIGNvbnN0IHAxID0gX19mZnQoUEYsIHBhbGwsIGJpdHMtMSwgb2Zmc2V0LCBzdGVwKjIpO1xuICAgIGNvbnN0IHAyID0gX19mZnQoUEYsIHBhbGwsIGJpdHMtMSwgb2Zmc2V0K3N0ZXAsIHN0ZXAqMik7XG5cbiAgICBjb25zdCBvdXQgPSBuZXcgQXJyYXkobik7XG5cbiAgICBmb3IgKGxldCBpPTA7IGk8bmRpdjI7IGkrKykge1xuICAgICAgICBvdXRbaV0gPSBQRi5HLmFkZChwMVtpXSwgUEYub3BNdWxHRihwMltpXSwgUEYucm9vdHNbYml0c11baV0pKTtcbiAgICAgICAgb3V0W2krbmRpdjJdID0gUEYuRy5zdWIocDFbaV0sIFBGLm9wTXVsR0YocDJbaV0sIFBGLnJvb3RzW2JpdHNdW2ldKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG91dDtcbn1cblxuY2xhc3MgWnFGaWVsZCB7XG4gICAgY29uc3RydWN0b3IocCkge1xuICAgICAgICB0aGlzLnR5cGU9XCJGMVwiO1xuICAgICAgICB0aGlzLm9uZSA9IEJpZ0ludCgxKTtcbiAgICAgICAgdGhpcy56ZXJvID0gQmlnSW50KDApO1xuICAgICAgICB0aGlzLnAgPSBCaWdJbnQocCk7XG4gICAgICAgIHRoaXMubSA9IDE7XG4gICAgICAgIHRoaXMubmVnb25lID0gdGhpcy5wLXRoaXMub25lO1xuICAgICAgICB0aGlzLnR3byA9IEJpZ0ludCgyKTtcbiAgICAgICAgdGhpcy5oYWxmID0gdGhpcy5wID4+IHRoaXMub25lO1xuICAgICAgICB0aGlzLmJpdExlbmd0aCA9IGJpdExlbmd0aCh0aGlzLnApO1xuICAgICAgICB0aGlzLm1hc2sgPSAodGhpcy5vbmUgPDwgQmlnSW50KHRoaXMuYml0TGVuZ3RoKSkgLSB0aGlzLm9uZTtcblxuICAgICAgICB0aGlzLm42NCA9IE1hdGguZmxvb3IoKHRoaXMuYml0TGVuZ3RoIC0gMSkgLyA2NCkrMTtcbiAgICAgICAgdGhpcy5uMzIgPSB0aGlzLm42NCoyO1xuICAgICAgICB0aGlzLm44ID0gdGhpcy5uNjQqODtcbiAgICAgICAgdGhpcy5SID0gdGhpcy5lKHRoaXMub25lIDw8IEJpZ0ludCh0aGlzLm42NCo2NCkpO1xuICAgICAgICB0aGlzLlJpID0gdGhpcy5pbnYodGhpcy5SKTtcblxuICAgICAgICBjb25zdCBlID0gdGhpcy5uZWdvbmUgPj4gdGhpcy5vbmU7XG4gICAgICAgIHRoaXMubnFyID0gdGhpcy50d287XG4gICAgICAgIGxldCByID0gdGhpcy5wb3codGhpcy5ucXIsIGUpO1xuICAgICAgICB3aGlsZSAoIXRoaXMuZXEociwgdGhpcy5uZWdvbmUpKSB7XG4gICAgICAgICAgICB0aGlzLm5xciA9IHRoaXMubnFyICsgdGhpcy5vbmU7XG4gICAgICAgICAgICByID0gdGhpcy5wb3codGhpcy5ucXIsIGUpO1xuICAgICAgICB9XG5cblxuICAgICAgICB0aGlzLnMgPSAwO1xuICAgICAgICB0aGlzLnQgPSB0aGlzLm5lZ29uZTtcblxuICAgICAgICB3aGlsZSAoKHRoaXMudCAmIHRoaXMub25lKSA9PSB0aGlzLnplcm8pIHtcbiAgICAgICAgICAgIHRoaXMucyA9IHRoaXMucyArIDE7XG4gICAgICAgICAgICB0aGlzLnQgPSB0aGlzLnQgPj4gdGhpcy5vbmU7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm5xcl90b190ID0gdGhpcy5wb3codGhpcy5ucXIsIHRoaXMudCk7XG5cbiAgICAgICAgYnVpbGRTcXJ0KHRoaXMpO1xuXG4gICAgICAgIHRoaXMuRkZUID0gbmV3IEZGVCh0aGlzLCB0aGlzLCB0aGlzLm11bC5iaW5kKHRoaXMpKTtcblxuICAgICAgICB0aGlzLmZmdCA9IHRoaXMuRkZULmZmdC5iaW5kKHRoaXMuRkZUKTtcbiAgICAgICAgdGhpcy5pZmZ0ID0gdGhpcy5GRlQuaWZmdC5iaW5kKHRoaXMuRkZUKTtcbiAgICAgICAgdGhpcy53ID0gdGhpcy5GRlQudztcbiAgICAgICAgdGhpcy53aSA9IHRoaXMuRkZULndpOyBcbiAgICBcbiAgICAgICAgdGhpcy5zaGlmdCA9IHRoaXMuc3F1YXJlKHRoaXMubnFyKTtcbiAgICAgICAgdGhpcy5rID0gdGhpcy5leHAodGhpcy5ucXIsIDIqKnRoaXMucyk7XG4gICAgfVxuXG4gICAgZShhLGIpIHtcbiAgICAgICAgbGV0IHJlcztcbiAgICAgICAgaWYgKCFiKSB7XG4gICAgICAgICAgICByZXMgPSBCaWdJbnQoYSk7XG4gICAgICAgIH0gZWxzZSBpZiAoYj09MTYpIHtcbiAgICAgICAgICAgIHJlcyA9IEJpZ0ludChcIjB4XCIrYSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlcyA8IDApIHtcbiAgICAgICAgICAgIGxldCBucmVzID0gLXJlcztcbiAgICAgICAgICAgIGlmIChucmVzID49IHRoaXMucCkgbnJlcyA9IG5yZXMgJSB0aGlzLnA7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wIC0gbnJlcztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiAocmVzPj0gdGhpcy5wKSA/IHJlcyV0aGlzLnAgOiByZXM7XG4gICAgICAgIH1cblxuICAgIH1cblxuICAgIGFkZChhLCBiKSB7XG4gICAgICAgIGNvbnN0IHJlcyA9IGEgKyBiO1xuICAgICAgICByZXR1cm4gcmVzID49IHRoaXMucCA/IHJlcy10aGlzLnAgOiByZXM7XG4gICAgfVxuXG4gICAgc3ViKGEsIGIpIHtcbiAgICAgICAgcmV0dXJuIChhID49IGIpID8gYS1iIDogdGhpcy5wLWIrYTtcbiAgICB9XG5cbiAgICBuZWcoYSkge1xuICAgICAgICByZXR1cm4gYSA/IHRoaXMucC1hIDogYTtcbiAgICB9XG5cbiAgICBtdWwoYSwgYikge1xuICAgICAgICByZXR1cm4gKGEqYikldGhpcy5wO1xuICAgIH1cblxuICAgIG11bFNjYWxhcihiYXNlLCBzKSB7XG4gICAgICAgIHJldHVybiAoYmFzZSAqIHRoaXMuZShzKSkgJSB0aGlzLnA7XG4gICAgfVxuXG4gICAgc3F1YXJlKGEpIHtcbiAgICAgICAgcmV0dXJuIChhKmEpICUgdGhpcy5wO1xuICAgIH1cblxuICAgIGVxKGEsIGIpIHtcbiAgICAgICAgcmV0dXJuIGE9PWI7XG4gICAgfVxuXG4gICAgbmVxKGEsIGIpIHtcbiAgICAgICAgcmV0dXJuIGEhPWI7XG4gICAgfVxuXG4gICAgbHQoYSwgYikge1xuICAgICAgICBjb25zdCBhYSA9IChhID4gdGhpcy5oYWxmKSA/IGEgLSB0aGlzLnAgOiBhO1xuICAgICAgICBjb25zdCBiYiA9IChiID4gdGhpcy5oYWxmKSA/IGIgLSB0aGlzLnAgOiBiO1xuICAgICAgICByZXR1cm4gYWEgPCBiYjtcbiAgICB9XG5cbiAgICBndChhLCBiKSB7XG4gICAgICAgIGNvbnN0IGFhID0gKGEgPiB0aGlzLmhhbGYpID8gYSAtIHRoaXMucCA6IGE7XG4gICAgICAgIGNvbnN0IGJiID0gKGIgPiB0aGlzLmhhbGYpID8gYiAtIHRoaXMucCA6IGI7XG4gICAgICAgIHJldHVybiBhYSA+IGJiO1xuICAgIH1cblxuICAgIGxlcShhLCBiKSB7XG4gICAgICAgIGNvbnN0IGFhID0gKGEgPiB0aGlzLmhhbGYpID8gYSAtIHRoaXMucCA6IGE7XG4gICAgICAgIGNvbnN0IGJiID0gKGIgPiB0aGlzLmhhbGYpID8gYiAtIHRoaXMucCA6IGI7XG4gICAgICAgIHJldHVybiBhYSA8PSBiYjtcbiAgICB9XG5cbiAgICBnZXEoYSwgYikge1xuICAgICAgICBjb25zdCBhYSA9IChhID4gdGhpcy5oYWxmKSA/IGEgLSB0aGlzLnAgOiBhO1xuICAgICAgICBjb25zdCBiYiA9IChiID4gdGhpcy5oYWxmKSA/IGIgLSB0aGlzLnAgOiBiO1xuICAgICAgICByZXR1cm4gYWEgPj0gYmI7XG4gICAgfVxuXG4gICAgZGl2KGEsIGIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubXVsKGEsIHRoaXMuaW52KGIpKTtcbiAgICB9XG5cbiAgICBpZGl2KGEsIGIpIHtcbiAgICAgICAgaWYgKCFiKSB0aHJvdyBuZXcgRXJyb3IoXCJEaXZpc2lvbiBieSB6ZXJvXCIpO1xuICAgICAgICByZXR1cm4gYSAvIGI7XG4gICAgfVxuXG4gICAgaW52KGEpIHtcbiAgICAgICAgaWYgKCFhKSB0aHJvdyBuZXcgRXJyb3IoXCJEaXZpc2lvbiBieSB6ZXJvXCIpO1xuXG4gICAgICAgIGxldCB0ID0gdGhpcy56ZXJvO1xuICAgICAgICBsZXQgciA9IHRoaXMucDtcbiAgICAgICAgbGV0IG5ld3QgPSB0aGlzLm9uZTtcbiAgICAgICAgbGV0IG5ld3IgPSBhICUgdGhpcy5wO1xuICAgICAgICB3aGlsZSAobmV3cikge1xuICAgICAgICAgICAgbGV0IHEgPSByL25ld3I7XG4gICAgICAgICAgICBbdCwgbmV3dF0gPSBbbmV3dCwgdC1xKm5ld3RdO1xuICAgICAgICAgICAgW3IsIG5ld3JdID0gW25ld3IsIHItcSpuZXdyXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodDx0aGlzLnplcm8pIHQgKz0gdGhpcy5wO1xuICAgICAgICByZXR1cm4gdDtcbiAgICB9XG5cbiAgICBtb2QoYSwgYikge1xuICAgICAgICByZXR1cm4gYSAlIGI7XG4gICAgfVxuXG4gICAgcG93KGIsIGUpIHtcbiAgICAgICAgcmV0dXJuIGV4cCh0aGlzLCBiLCBlKTtcbiAgICB9XG5cbiAgICBleHAoYiwgZSkge1xuICAgICAgICByZXR1cm4gZXhwKHRoaXMsIGIsIGUpO1xuICAgIH1cblxuICAgIGJhbmQoYSwgYikge1xuICAgICAgICBjb25zdCByZXMgPSAgKChhICYgYikgJiB0aGlzLm1hc2spO1xuICAgICAgICByZXR1cm4gcmVzID49IHRoaXMucCA/IHJlcy10aGlzLnAgOiByZXM7XG4gICAgfVxuXG4gICAgYm9yKGEsIGIpIHtcbiAgICAgICAgY29uc3QgcmVzID0gICgoYSB8IGIpICYgdGhpcy5tYXNrKTtcbiAgICAgICAgcmV0dXJuIHJlcyA+PSB0aGlzLnAgPyByZXMtdGhpcy5wIDogcmVzO1xuICAgIH1cblxuICAgIGJ4b3IoYSwgYikge1xuICAgICAgICBjb25zdCByZXMgPSAgKChhIF4gYikgJiB0aGlzLm1hc2spO1xuICAgICAgICByZXR1cm4gcmVzID49IHRoaXMucCA/IHJlcy10aGlzLnAgOiByZXM7XG4gICAgfVxuXG4gICAgYm5vdChhKSB7XG4gICAgICAgIGNvbnN0IHJlcyA9IGEgXiB0aGlzLm1hc2s7XG4gICAgICAgIHJldHVybiByZXMgPj0gdGhpcy5wID8gcmVzLXRoaXMucCA6IHJlcztcbiAgICB9XG5cbiAgICBzaGwoYSwgYikge1xuICAgICAgICBpZiAoTnVtYmVyKGIpIDwgdGhpcy5iaXRMZW5ndGgpIHtcbiAgICAgICAgICAgIGNvbnN0IHJlcyA9IChhIDw8IGIpICYgdGhpcy5tYXNrO1xuICAgICAgICAgICAgcmV0dXJuIHJlcyA+PSB0aGlzLnAgPyByZXMtdGhpcy5wIDogcmVzO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgbmIgPSB0aGlzLnAgLSBiO1xuICAgICAgICAgICAgaWYgKE51bWJlcihuYikgPCB0aGlzLmJpdExlbmd0aCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBhID4+IG5iO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy56ZXJvO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgc2hyKGEsIGIpIHtcbiAgICAgICAgaWYgKE51bWJlcihiKSA8IHRoaXMuYml0TGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gYSA+PiBiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgbmIgPSB0aGlzLnAgLSBiO1xuICAgICAgICAgICAgaWYgKE51bWJlcihuYikgPCB0aGlzLmJpdExlbmd0aCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlcyA9IChhIDw8IG5iKSAmIHRoaXMubWFzaztcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzID49IHRoaXMucCA/IHJlcy10aGlzLnAgOiByZXM7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgbGFuZChhLCBiKSB7XG4gICAgICAgIHJldHVybiAoYSAmJiBiKSA/IHRoaXMub25lIDogdGhpcy56ZXJvO1xuICAgIH1cblxuICAgIGxvcihhLCBiKSB7XG4gICAgICAgIHJldHVybiAoYSB8fCBiKSA/IHRoaXMub25lIDogdGhpcy56ZXJvO1xuICAgIH1cblxuICAgIGxub3QoYSkge1xuICAgICAgICByZXR1cm4gKGEpID8gdGhpcy56ZXJvIDogdGhpcy5vbmU7XG4gICAgfVxuXG4gICAgc3FydF9vbGQobikge1xuXG4gICAgICAgIGlmIChuID09IHRoaXMuemVybykgcmV0dXJuIHRoaXMuemVybztcblxuICAgICAgICAvLyBUZXN0IHRoYXQgaGF2ZSBzb2x1dGlvblxuICAgICAgICBjb25zdCByZXMgPSB0aGlzLnBvdyhuLCB0aGlzLm5lZ29uZSA+PiB0aGlzLm9uZSk7XG4gICAgICAgIGlmICggcmVzICE9IHRoaXMub25lICkgcmV0dXJuIG51bGw7XG5cbiAgICAgICAgbGV0IG0gPSB0aGlzLnM7XG4gICAgICAgIGxldCBjID0gdGhpcy5ucXJfdG9fdDtcbiAgICAgICAgbGV0IHQgPSB0aGlzLnBvdyhuLCB0aGlzLnQpO1xuICAgICAgICBsZXQgciA9IHRoaXMucG93KG4sIHRoaXMuYWRkKHRoaXMudCwgdGhpcy5vbmUpID4+IHRoaXMub25lICk7XG5cbiAgICAgICAgd2hpbGUgKCB0ICE9IHRoaXMub25lICkge1xuICAgICAgICAgICAgbGV0IHNxID0gdGhpcy5zcXVhcmUodCk7XG4gICAgICAgICAgICBsZXQgaSA9IDE7XG4gICAgICAgICAgICB3aGlsZSAoc3EgIT0gdGhpcy5vbmUgKSB7XG4gICAgICAgICAgICAgICAgaSsrO1xuICAgICAgICAgICAgICAgIHNxID0gdGhpcy5zcXVhcmUoc3EpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBiID0gYyBeIG0taS0xXG4gICAgICAgICAgICBsZXQgYiA9IGM7XG4gICAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8IG0taS0xOyBqICsrKSBiID0gdGhpcy5zcXVhcmUoYik7XG5cbiAgICAgICAgICAgIG0gPSBpO1xuICAgICAgICAgICAgYyA9IHRoaXMuc3F1YXJlKGIpO1xuICAgICAgICAgICAgdCA9IHRoaXMubXVsKHQsIGMpO1xuICAgICAgICAgICAgciA9IHRoaXMubXVsKHIsIGIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHIgPiAodGhpcy5wID4+IHRoaXMub25lKSkge1xuICAgICAgICAgICAgciA9IHRoaXMubmVnKHIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHI7XG4gICAgfVxuXG4gICAgbm9ybWFsaXplKGEsIGIpIHtcbiAgICAgICAgYSA9IEJpZ0ludChhLGIpO1xuICAgICAgICBpZiAoYSA8IDApIHtcbiAgICAgICAgICAgIGxldCBuYSA9IC1hO1xuICAgICAgICAgICAgaWYgKG5hID49IHRoaXMucCkgbmEgPSBuYSAlIHRoaXMucDtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnAgLSBuYTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiAoYT49IHRoaXMucCkgPyBhJXRoaXMucCA6IGE7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByYW5kb20oKSB7XG4gICAgICAgIGNvbnN0IG5CeXRlcyA9ICh0aGlzLmJpdExlbmd0aCoyIC8gOCk7XG4gICAgICAgIGxldCByZXMgPXRoaXMuemVybztcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPG5CeXRlczsgaSsrKSB7XG4gICAgICAgICAgICByZXMgPSAocmVzIDw8IEJpZ0ludCg4KSkgKyBCaWdJbnQoZ2V0UmFuZG9tQnl0ZXMoMSlbMF0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXMgJSB0aGlzLnA7XG4gICAgfVxuXG4gICAgdG9TdHJpbmcoYSwgYmFzZSkge1xuICAgICAgICBiYXNlID0gYmFzZSB8fCAxMDtcbiAgICAgICAgbGV0IHZzO1xuICAgICAgICBpZiAoKGEgPiB0aGlzLmhhbGYpJiYoYmFzZSA9PSAxMCkpIHtcbiAgICAgICAgICAgIGNvbnN0IHYgPSB0aGlzLnAtYTtcbiAgICAgICAgICAgIHZzID0gXCItXCIrdi50b1N0cmluZyhiYXNlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHZzID0gYS50b1N0cmluZyhiYXNlKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdnM7XG4gICAgfVxuXG4gICAgaXNaZXJvKGEpIHtcbiAgICAgICAgcmV0dXJuIGEgPT0gdGhpcy56ZXJvO1xuICAgIH1cblxuICAgIGZyb21Sbmcocm5nKSB7XG4gICAgICAgIGxldCB2O1xuICAgICAgICBkbyB7XG4gICAgICAgICAgICB2PXRoaXMuemVybztcbiAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaTx0aGlzLm42NDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdiArPSBybmcubmV4dFU2NCgpIDw8IEJpZ0ludCg2NCAqaSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2ICY9IHRoaXMubWFzaztcbiAgICAgICAgfSB3aGlsZSAodiA+PSB0aGlzLnApO1xuICAgICAgICB2ID0gKHYgKiB0aGlzLlJpKSAlIHRoaXMucDsgICAvLyBDb252ZXJ0IGZyb20gbW9udGdvbWVyeVxuICAgICAgICByZXR1cm4gdjtcbiAgICB9XG5cbiAgICBmZnQoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5GRlQuZmZ0KGEpO1xuICAgIH1cblxuICAgIGlmZnQoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5GRlQuaWZmdChhKTtcbiAgICB9XG5cbiAgICAvLyBSZXR1cm5zIGEgYnVmZmVyIHdpdGggTGl0dGxlIEVuZGlhbiBSZXByZXNlbnRhdGlvblxuICAgIHRvUnByTEUoYnVmZiwgbywgZSkge1xuICAgICAgICB0b1JwckxFKGJ1ZmYsIG8sIGUsIHRoaXMubjY0KjgpO1xuICAgIH1cblxuICAgIC8vIFJldHVybnMgYSBidWZmZXIgd2l0aCBCaWcgRW5kaWFuIFJlcHJlc2VudGF0aW9uXG4gICAgdG9ScHJCRShidWZmLCBvLCBlKSB7XG4gICAgICAgIHRvUnByQkUoYnVmZiwgbywgZSwgdGhpcy5uNjQqOCk7XG4gICAgfVxuXG4gICAgLy8gUmV0dXJucyBhIGJ1ZmZlciB3aXRoIEJpZyBFbmRpYW4gTW9udGdvbWVyeSBSZXByZXNlbnRhdGlvblxuICAgIHRvUnByQkVNKGJ1ZmYsIG8sIGUpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudG9ScHJCRShidWZmLCBvLCB0aGlzLm11bCh0aGlzLlIsIGUpKTtcbiAgICB9XG5cbiAgICB0b1JwckxFTShidWZmLCBvLCBlKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnRvUnByTEUoYnVmZiwgbywgdGhpcy5tdWwodGhpcy5SLCBlKSk7XG4gICAgfVxuXG5cbiAgICAvLyBQYXNlcyBhIGJ1ZmZlciB3aXRoIExpdHRsZSBFbmRpYW4gUmVwcmVzZW50YXRpb25cbiAgICBmcm9tUnByTEUoYnVmZiwgbykge1xuICAgICAgICByZXR1cm4gZnJvbVJwckxFKGJ1ZmYsIG8sIHRoaXMubjgpO1xuICAgIH1cblxuICAgIC8vIFBhc2VzIGEgYnVmZmVyIHdpdGggQmlnIEVuZGlhbiBSZXByZXNlbnRhdGlvblxuICAgIGZyb21ScHJCRShidWZmLCBvKSB7XG4gICAgICAgIHJldHVybiBmcm9tUnByQkUoYnVmZiwgbywgdGhpcy5uOCk7XG4gICAgfVxuXG4gICAgZnJvbVJwckxFTShidWZmLCBvKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm11bCh0aGlzLmZyb21ScHJMRShidWZmLCBvKSwgdGhpcy5SaSk7XG4gICAgfVxuXG4gICAgZnJvbVJwckJFTShidWZmLCBvKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm11bCh0aGlzLmZyb21ScHJCRShidWZmLCBvKSwgdGhpcy5SaSk7XG4gICAgfVxuXG4gICAgdG9PYmplY3QoYSkge1xuICAgICAgICByZXR1cm4gYTtcbiAgICB9XG59XG5cbi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMGtpbXMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya2pzLlxuXG4gICAgc25hcmtqcyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuICAgIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGVcbiAgICBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbilcbiAgICBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJranMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3JcbiAgICBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoXG4gICAgc25hcmtqcy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cblxuY2xhc3MgRjJGaWVsZCB7XG4gICAgY29uc3RydWN0b3IoRiwgbm9uUmVzaWR1ZSkge1xuICAgICAgICB0aGlzLnR5cGU9XCJGMlwiO1xuICAgICAgICB0aGlzLkYgPSBGO1xuICAgICAgICB0aGlzLnplcm8gPSBbdGhpcy5GLnplcm8sIHRoaXMuRi56ZXJvXTtcbiAgICAgICAgdGhpcy5vbmUgPSBbdGhpcy5GLm9uZSwgdGhpcy5GLnplcm9dO1xuICAgICAgICB0aGlzLm5lZ29uZSA9IHRoaXMubmVnKHRoaXMub25lKTtcbiAgICAgICAgdGhpcy5ub25SZXNpZHVlID0gbm9uUmVzaWR1ZTtcbiAgICAgICAgdGhpcy5tID0gRi5tKjI7XG4gICAgICAgIHRoaXMucCA9IEYucDtcbiAgICAgICAgdGhpcy5uNjQgPSBGLm42NCoyO1xuICAgICAgICB0aGlzLm4zMiA9IHRoaXMubjY0KjI7XG4gICAgICAgIHRoaXMubjggPSB0aGlzLm42NCo4O1xuXG4gICAgICAgIGJ1aWxkU3FydCh0aGlzKTtcbiAgICB9XG5cbiAgICBfbXVsQnlOb25SZXNpZHVlKGEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuRi5tdWwodGhpcy5ub25SZXNpZHVlLCBhKTtcbiAgICB9XG5cbiAgICBjb3B5KGEpIHtcbiAgICAgICAgcmV0dXJuIFt0aGlzLkYuY29weShhWzBdKSwgdGhpcy5GLmNvcHkoYVsxXSldO1xuICAgIH1cblxuICAgIGFkZChhLCBiKSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICB0aGlzLkYuYWRkKGFbMF0sIGJbMF0pLFxuICAgICAgICAgICAgdGhpcy5GLmFkZChhWzFdLCBiWzFdKVxuICAgICAgICBdO1xuICAgIH1cblxuICAgIGRvdWJsZShhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFkZChhLGEpO1xuICAgIH1cblxuICAgIHN1YihhLCBiKSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICB0aGlzLkYuc3ViKGFbMF0sIGJbMF0pLFxuICAgICAgICAgICAgdGhpcy5GLnN1YihhWzFdLCBiWzFdKVxuICAgICAgICBdO1xuICAgIH1cblxuICAgIG5lZyhhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN1Yih0aGlzLnplcm8sIGEpO1xuICAgIH1cblxuICAgIGNvbmp1Z2F0ZShhKSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBhWzBdLFxuICAgICAgICAgICAgdGhpcy5GLm5lZyhhWzFdKVxuICAgICAgICBdO1xuICAgIH1cblxuICAgIG11bChhLCBiKSB7XG4gICAgICAgIGNvbnN0IGFBID0gdGhpcy5GLm11bChhWzBdICwgYlswXSk7XG4gICAgICAgIGNvbnN0IGJCID0gdGhpcy5GLm11bChhWzFdICwgYlsxXSk7XG5cbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIHRoaXMuRi5hZGQoIGFBICwgdGhpcy5fbXVsQnlOb25SZXNpZHVlKGJCKSksXG4gICAgICAgICAgICB0aGlzLkYuc3ViKFxuICAgICAgICAgICAgICAgIHRoaXMuRi5tdWwoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuRi5hZGQoYVswXSwgYVsxXSksXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuRi5hZGQoYlswXSwgYlsxXSkpLFxuICAgICAgICAgICAgICAgIHRoaXMuRi5hZGQoYUEsIGJCKSldO1xuICAgIH1cblxuICAgIGludihhKSB7XG4gICAgICAgIGNvbnN0IHQwID0gdGhpcy5GLnNxdWFyZShhWzBdKTtcbiAgICAgICAgY29uc3QgdDEgPSB0aGlzLkYuc3F1YXJlKGFbMV0pO1xuICAgICAgICBjb25zdCB0MiA9IHRoaXMuRi5zdWIodDAsIHRoaXMuX211bEJ5Tm9uUmVzaWR1ZSh0MSkpO1xuICAgICAgICBjb25zdCB0MyA9IHRoaXMuRi5pbnYodDIpO1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgdGhpcy5GLm11bChhWzBdLCB0MyksXG4gICAgICAgICAgICB0aGlzLkYubmVnKHRoaXMuRi5tdWwoIGFbMV0sIHQzKSkgXTtcbiAgICB9XG5cbiAgICBkaXYoYSwgYikge1xuICAgICAgICByZXR1cm4gdGhpcy5tdWwoYSwgdGhpcy5pbnYoYikpO1xuICAgIH1cblxuICAgIHNxdWFyZShhKSB7XG4gICAgICAgIGNvbnN0IGFiID0gdGhpcy5GLm11bChhWzBdICwgYVsxXSk7XG5cbiAgICAgICAgLypcbiAgICAgICAgW1xuICAgICAgICAgICAgKGEgKyBiKSAqIChhICsgbm9uX3Jlc2lkdWUgKiBiKSAtIGFiIC0gbm9uX3Jlc2lkdWUgKiBhYixcbiAgICAgICAgICAgIGFiICsgYWJcbiAgICAgICAgXTtcbiAgICAgICAgKi9cblxuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgdGhpcy5GLnN1YihcbiAgICAgICAgICAgICAgICB0aGlzLkYubXVsKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLkYuYWRkKGFbMF0sIGFbMV0pICxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5GLmFkZChcbiAgICAgICAgICAgICAgICAgICAgICAgIGFbMF0gLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fbXVsQnlOb25SZXNpZHVlKGFbMV0pKSksXG4gICAgICAgICAgICAgICAgdGhpcy5GLmFkZChcbiAgICAgICAgICAgICAgICAgICAgYWIsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX211bEJ5Tm9uUmVzaWR1ZShhYikpKSxcbiAgICAgICAgICAgIHRoaXMuRi5hZGQoYWIsIGFiKVxuICAgICAgICBdO1xuICAgIH1cblxuICAgIGlzWmVybyhhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLkYuaXNaZXJvKGFbMF0pICYmIHRoaXMuRi5pc1plcm8oYVsxXSk7XG4gICAgfVxuXG4gICAgZXEoYSwgYikge1xuICAgICAgICByZXR1cm4gdGhpcy5GLmVxKGFbMF0sIGJbMF0pICYmIHRoaXMuRi5lcShhWzFdLCBiWzFdKTtcbiAgICB9XG5cbiAgICBtdWxTY2FsYXIoYmFzZSwgZSkge1xuICAgICAgICByZXR1cm4gbXVsU2NhbGFyKHRoaXMsIGJhc2UsIGUpO1xuICAgIH1cblxuICAgIHBvdyhiYXNlLCBlKSB7XG4gICAgICAgIHJldHVybiBleHAodGhpcywgYmFzZSwgZSk7XG4gICAgfVxuXG4gICAgZXhwKGJhc2UsIGUpIHtcbiAgICAgICAgcmV0dXJuIGV4cCh0aGlzLCBiYXNlLCBlKTtcbiAgICB9XG5cbiAgICB0b1N0cmluZyhhKSB7XG4gICAgICAgIHJldHVybiBgWyAke3RoaXMuRi50b1N0cmluZyhhWzBdKX0gLCAke3RoaXMuRi50b1N0cmluZyhhWzFdKX0gXWA7XG4gICAgfVxuXG4gICAgZnJvbVJuZyhybmcpIHtcbiAgICAgICAgY29uc3QgYzAgPSB0aGlzLkYuZnJvbVJuZyhybmcpO1xuICAgICAgICBjb25zdCBjMSA9IHRoaXMuRi5mcm9tUm5nKHJuZyk7XG4gICAgICAgIHJldHVybiBbYzAsIGMxXTtcbiAgICB9XG5cbiAgICBndChhLCBiKSB7XG4gICAgICAgIGlmICh0aGlzLkYuZ3QoYVswXSwgYlswXSkpIHJldHVybiB0cnVlO1xuICAgICAgICBpZiAodGhpcy5GLmd0KGJbMF0sIGFbMF0pKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIGlmICh0aGlzLkYuZ3QoYVsxXSwgYlsxXSkpIHJldHVybiB0cnVlO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgZ2VxKGEsIGIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ3QoYSwgYikgfHwgdGhpcy5lcShhLCBiKTtcbiAgICB9XG5cbiAgICBsdChhLCBiKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5nZXEoYSxiKTtcbiAgICB9XG5cbiAgICBsZXEoYSwgYikge1xuICAgICAgICByZXR1cm4gIXRoaXMuZ3QoYSxiKTtcbiAgICB9XG5cbiAgICBuZXEoYSwgYikge1xuICAgICAgICByZXR1cm4gIXRoaXMuZXEoYSxiKTtcbiAgICB9XG5cbiAgICByYW5kb20oKSB7XG4gICAgICAgIHJldHVybiBbdGhpcy5GLnJhbmRvbSgpLCB0aGlzLkYucmFuZG9tKCldO1xuICAgIH1cblxuXG4gICAgdG9ScHJMRShidWZmLCBvLCBlKSB7XG4gICAgICAgIHRoaXMuRi50b1JwckxFKGJ1ZmYsIG8sIGVbMF0pO1xuICAgICAgICB0aGlzLkYudG9ScHJMRShidWZmLCBvK3RoaXMuRi5uOCwgZVsxXSk7XG4gICAgfVxuXG4gICAgdG9ScHJCRShidWZmLCBvLCBlKSB7XG4gICAgICAgIHRoaXMuRi50b1JwckJFKGJ1ZmYsIG8sIGVbMV0pO1xuICAgICAgICB0aGlzLkYudG9ScHJCRShidWZmLCBvK3RoaXMuRi5uOCwgZVswXSk7XG4gICAgfVxuXG4gICAgdG9ScHJMRU0oYnVmZiwgbywgZSkge1xuICAgICAgICB0aGlzLkYudG9ScHJMRU0oYnVmZiwgbywgZVswXSk7XG4gICAgICAgIHRoaXMuRi50b1JwckxFTShidWZmLCBvK3RoaXMuRi5uOCwgZVsxXSk7XG4gICAgfVxuXG5cbiAgICB0b1JwckJFTShidWZmLCBvLCBlKSB7XG4gICAgICAgIHRoaXMuRi50b1JwckJFTShidWZmLCBvLCBlWzFdKTtcbiAgICAgICAgdGhpcy5GLnRvUnByQkVNKGJ1ZmYsIG8rdGhpcy5GLm44LCBlWzBdKTtcbiAgICB9XG5cbiAgICBmcm9tUnByTEUoYnVmZiwgbykge1xuICAgICAgICBvID0gbyB8fCAwO1xuICAgICAgICBjb25zdCBjMCA9IHRoaXMuRi5mcm9tUnByTEUoYnVmZiwgbyk7XG4gICAgICAgIGNvbnN0IGMxID0gdGhpcy5GLmZyb21ScHJMRShidWZmLCBvK3RoaXMuRi5uOCk7XG4gICAgICAgIHJldHVybiBbYzAsIGMxXTtcbiAgICB9XG5cbiAgICBmcm9tUnByQkUoYnVmZiwgbykge1xuICAgICAgICBvID0gbyB8fCAwO1xuICAgICAgICBjb25zdCBjMSA9IHRoaXMuRi5mcm9tUnByQkUoYnVmZiwgbyk7XG4gICAgICAgIGNvbnN0IGMwID0gdGhpcy5GLmZyb21ScHJCRShidWZmLCBvK3RoaXMuRi5uOCk7XG4gICAgICAgIHJldHVybiBbYzAsIGMxXTtcbiAgICB9XG5cbiAgICBmcm9tUnByTEVNKGJ1ZmYsIG8pIHtcbiAgICAgICAgbyA9IG8gfHwgMDtcbiAgICAgICAgY29uc3QgYzAgPSB0aGlzLkYuZnJvbVJwckxFTShidWZmLCBvKTtcbiAgICAgICAgY29uc3QgYzEgPSB0aGlzLkYuZnJvbVJwckxFTShidWZmLCBvK3RoaXMuRi5uOCk7XG4gICAgICAgIHJldHVybiBbYzAsIGMxXTtcbiAgICB9XG5cbiAgICBmcm9tUnByQkVNKGJ1ZmYsIG8pIHtcbiAgICAgICAgbyA9IG8gfHwgMDtcbiAgICAgICAgY29uc3QgYzEgPSB0aGlzLkYuZnJvbVJwckJFTShidWZmLCBvKTtcbiAgICAgICAgY29uc3QgYzAgPSB0aGlzLkYuZnJvbVJwckJFTShidWZmLCBvK3RoaXMuRi5uOCk7XG4gICAgICAgIHJldHVybiBbYzAsIGMxXTtcbiAgICB9XG5cbiAgICB0b09iamVjdChhKSB7XG4gICAgICAgIHJldHVybiBhO1xuICAgIH1cblxufVxuXG4vKlxuICAgIENvcHlyaWdodCAyMDE4IDBraW1zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5cbmNsYXNzIEYzRmllbGQge1xuICAgIGNvbnN0cnVjdG9yKEYsIG5vblJlc2lkdWUpIHtcbiAgICAgICAgdGhpcy50eXBlPVwiRjNcIjtcbiAgICAgICAgdGhpcy5GID0gRjtcbiAgICAgICAgdGhpcy56ZXJvID0gW3RoaXMuRi56ZXJvLCB0aGlzLkYuemVybywgdGhpcy5GLnplcm9dO1xuICAgICAgICB0aGlzLm9uZSA9IFt0aGlzLkYub25lLCB0aGlzLkYuemVybywgdGhpcy5GLnplcm9dO1xuICAgICAgICB0aGlzLm5lZ29uZSA9IHRoaXMubmVnKHRoaXMub25lKTtcbiAgICAgICAgdGhpcy5ub25SZXNpZHVlID0gbm9uUmVzaWR1ZTtcbiAgICAgICAgdGhpcy5tID0gRi5tKjM7XG4gICAgICAgIHRoaXMucCA9IEYucDtcbiAgICAgICAgdGhpcy5uNjQgPSBGLm42NCozO1xuICAgICAgICB0aGlzLm4zMiA9IHRoaXMubjY0KjI7XG4gICAgICAgIHRoaXMubjggPSB0aGlzLm42NCo4O1xuICAgIH1cblxuICAgIF9tdWxCeU5vblJlc2lkdWUoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5GLm11bCh0aGlzLm5vblJlc2lkdWUsIGEpO1xuICAgIH1cblxuICAgIGNvcHkoYSkge1xuICAgICAgICByZXR1cm4gW3RoaXMuRi5jb3B5KGFbMF0pLCB0aGlzLkYuY29weShhWzFdKSwgdGhpcy5GLmNvcHkoYVsyXSldO1xuICAgIH1cblxuICAgIGFkZChhLCBiKSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICB0aGlzLkYuYWRkKGFbMF0sIGJbMF0pLFxuICAgICAgICAgICAgdGhpcy5GLmFkZChhWzFdLCBiWzFdKSxcbiAgICAgICAgICAgIHRoaXMuRi5hZGQoYVsyXSwgYlsyXSlcbiAgICAgICAgXTtcbiAgICB9XG5cbiAgICBkb3VibGUoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5hZGQoYSxhKTtcbiAgICB9XG5cbiAgICBzdWIoYSwgYikge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgdGhpcy5GLnN1YihhWzBdLCBiWzBdKSxcbiAgICAgICAgICAgIHRoaXMuRi5zdWIoYVsxXSwgYlsxXSksXG4gICAgICAgICAgICB0aGlzLkYuc3ViKGFbMl0sIGJbMl0pXG4gICAgICAgIF07XG4gICAgfVxuXG4gICAgbmVnKGEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3ViKHRoaXMuemVybywgYSk7XG4gICAgfVxuXG4gICAgbXVsKGEsIGIpIHtcblxuICAgICAgICBjb25zdCBhQSA9IHRoaXMuRi5tdWwoYVswXSAsIGJbMF0pO1xuICAgICAgICBjb25zdCBiQiA9IHRoaXMuRi5tdWwoYVsxXSAsIGJbMV0pO1xuICAgICAgICBjb25zdCBjQyA9IHRoaXMuRi5tdWwoYVsyXSAsIGJbMl0pO1xuXG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICB0aGlzLkYuYWRkKFxuICAgICAgICAgICAgICAgIGFBLFxuICAgICAgICAgICAgICAgIHRoaXMuX211bEJ5Tm9uUmVzaWR1ZShcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5GLnN1YihcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuRi5tdWwoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5GLmFkZChhWzFdLCBhWzJdKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLkYuYWRkKGJbMV0sIGJbMl0pKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuRi5hZGQoYkIsIGNDKSkpKSwgICAgLy8gYUEgKyBub25fcmVzaWR1ZSooKGIrYykqKEIrQyktYkItY0MpLFxuXG4gICAgICAgICAgICB0aGlzLkYuYWRkKFxuICAgICAgICAgICAgICAgIHRoaXMuRi5zdWIoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuRi5tdWwoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLkYuYWRkKGFbMF0sIGFbMV0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5GLmFkZChiWzBdLCBiWzFdKSksXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuRi5hZGQoYUEsIGJCKSksXG4gICAgICAgICAgICAgICAgdGhpcy5fbXVsQnlOb25SZXNpZHVlKCBjQykpLCAgIC8vIChhK2IpKihBK0IpLWFBLWJCK25vbl9yZXNpZHVlKmNDXG5cbiAgICAgICAgICAgIHRoaXMuRi5hZGQoXG4gICAgICAgICAgICAgICAgdGhpcy5GLnN1YihcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5GLm11bChcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuRi5hZGQoYVswXSwgYVsyXSksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLkYuYWRkKGJbMF0sIGJbMl0pKSxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5GLmFkZChhQSwgY0MpKSxcbiAgICAgICAgICAgICAgICBiQildOyAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIChhK2MpKihBK0MpLWFBK2JCLWNDKVxuICAgIH1cblxuICAgIGludihhKSB7XG4gICAgICAgIGNvbnN0IHQwID0gdGhpcy5GLnNxdWFyZShhWzBdKTsgICAgICAgICAgICAgLy8gdDAgPSBhXjIgO1xuICAgICAgICBjb25zdCB0MSA9IHRoaXMuRi5zcXVhcmUoYVsxXSk7ICAgICAgICAgICAgIC8vIHQxID0gYl4yIDtcbiAgICAgICAgY29uc3QgdDIgPSB0aGlzLkYuc3F1YXJlKGFbMl0pOyAgICAgICAgICAgICAvLyB0MiA9IGNeMjtcbiAgICAgICAgY29uc3QgdDMgPSB0aGlzLkYubXVsKGFbMF0sYVsxXSk7ICAgICAgICAgICAvLyB0MyA9IGFiXG4gICAgICAgIGNvbnN0IHQ0ID0gdGhpcy5GLm11bChhWzBdLGFbMl0pOyAgICAgICAgICAgLy8gdDQgPSBhY1xuICAgICAgICBjb25zdCB0NSA9IHRoaXMuRi5tdWwoYVsxXSxhWzJdKTsgICAgICAgICAgIC8vIHQ1ID0gYmM7XG4gICAgICAgIC8vIGMwID0gdDAgLSBub25fcmVzaWR1ZSAqIHQ1O1xuICAgICAgICBjb25zdCBjMCA9IHRoaXMuRi5zdWIodDAsIHRoaXMuX211bEJ5Tm9uUmVzaWR1ZSh0NSkpO1xuICAgICAgICAvLyBjMSA9IG5vbl9yZXNpZHVlICogdDIgLSB0MztcbiAgICAgICAgY29uc3QgYzEgPSB0aGlzLkYuc3ViKHRoaXMuX211bEJ5Tm9uUmVzaWR1ZSh0MiksIHQzKTtcbiAgICAgICAgY29uc3QgYzIgPSB0aGlzLkYuc3ViKHQxLCB0NCk7ICAgICAgICAgICAgICAvLyBjMiA9IHQxLXQ0XG5cbiAgICAgICAgLy8gdDYgPSAoYSAqIGMwICsgbm9uX3Jlc2lkdWUgKiAoYyAqIGMxICsgYiAqIGMyKSkuaW52KCk7XG4gICAgICAgIGNvbnN0IHQ2ID1cbiAgICAgICAgICAgIHRoaXMuRi5pbnYoXG4gICAgICAgICAgICAgICAgdGhpcy5GLmFkZChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5GLm11bChhWzBdLCBjMCksXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX211bEJ5Tm9uUmVzaWR1ZShcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuRi5hZGQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5GLm11bChhWzJdLCBjMSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5GLm11bChhWzFdLCBjMikpKSkpO1xuXG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICB0aGlzLkYubXVsKHQ2LCBjMCksICAgICAgICAgLy8gdDYqYzBcbiAgICAgICAgICAgIHRoaXMuRi5tdWwodDYsIGMxKSwgICAgICAgICAvLyB0NipjMVxuICAgICAgICAgICAgdGhpcy5GLm11bCh0NiwgYzIpXTsgICAgICAgIC8vIHQ2KmMyXG4gICAgfVxuXG4gICAgZGl2KGEsIGIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubXVsKGEsIHRoaXMuaW52KGIpKTtcbiAgICB9XG5cbiAgICBzcXVhcmUoYSkge1xuICAgICAgICBjb25zdCBzMCA9IHRoaXMuRi5zcXVhcmUoYVswXSk7ICAgICAgICAgICAgICAgICAgIC8vIHMwID0gYV4yXG4gICAgICAgIGNvbnN0IGFiID0gdGhpcy5GLm11bChhWzBdLCBhWzFdKTsgICAgICAgICAgICAgICAgLy8gYWIgPSBhKmJcbiAgICAgICAgY29uc3QgczEgPSB0aGlzLkYuYWRkKGFiLCBhYik7ICAgICAgICAgICAgICAgICAgICAvLyBzMSA9IDJhYjtcbiAgICAgICAgY29uc3QgczIgPSB0aGlzLkYuc3F1YXJlKFxuICAgICAgICAgICAgdGhpcy5GLmFkZCh0aGlzLkYuc3ViKGFbMF0sYVsxXSksIGFbMl0pKTsgICAgIC8vIHMyID0gKGEgLSBiICsgYyleMjtcbiAgICAgICAgY29uc3QgYmMgPSB0aGlzLkYubXVsKGFbMV0sYVsyXSk7ICAgICAgICAgICAgICAgICAvLyBiYyA9IGIqY1xuICAgICAgICBjb25zdCBzMyA9IHRoaXMuRi5hZGQoYmMsIGJjKTsgICAgICAgICAgICAgICAgICAgIC8vIHMzID0gMipiY1xuICAgICAgICBjb25zdCBzNCA9IHRoaXMuRi5zcXVhcmUoYVsyXSk7ICAgICAgICAgICAgICAgICAgIC8vIHM0ID0gY14yXG5cblxuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgdGhpcy5GLmFkZChcbiAgICAgICAgICAgICAgICBzMCxcbiAgICAgICAgICAgICAgICB0aGlzLl9tdWxCeU5vblJlc2lkdWUoczMpKSwgICAgICAgICAgIC8vIHMwICsgbm9uX3Jlc2lkdWUgKiBzMyxcbiAgICAgICAgICAgIHRoaXMuRi5hZGQoXG4gICAgICAgICAgICAgICAgczEsXG4gICAgICAgICAgICAgICAgdGhpcy5fbXVsQnlOb25SZXNpZHVlKHM0KSksICAgICAgICAgICAvLyBzMSArIG5vbl9yZXNpZHVlICogczQsXG4gICAgICAgICAgICB0aGlzLkYuc3ViKFxuICAgICAgICAgICAgICAgIHRoaXMuRi5hZGQoIHRoaXMuRi5hZGQoczEsIHMyKSAsIHMzICksXG4gICAgICAgICAgICAgICAgdGhpcy5GLmFkZChzMCwgczQpKV07ICAgICAgICAgICAgICAgICAgICAgIC8vIHMxICsgczIgKyBzMyAtIHMwIC0gczRcbiAgICB9XG5cbiAgICBpc1plcm8oYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5GLmlzWmVybyhhWzBdKSAmJiB0aGlzLkYuaXNaZXJvKGFbMV0pICYmIHRoaXMuRi5pc1plcm8oYVsyXSk7XG4gICAgfVxuXG4gICAgZXEoYSwgYikge1xuICAgICAgICByZXR1cm4gdGhpcy5GLmVxKGFbMF0sIGJbMF0pICYmIHRoaXMuRi5lcShhWzFdLCBiWzFdKSAmJiB0aGlzLkYuZXEoYVsyXSwgYlsyXSk7XG4gICAgfVxuXG4gICAgYWZmaW5lKGEpIHtcbiAgICAgICAgcmV0dXJuIFt0aGlzLkYuYWZmaW5lKGFbMF0pLCB0aGlzLkYuYWZmaW5lKGFbMV0pLCB0aGlzLkYuYWZmaW5lKGFbMl0pXTtcbiAgICB9XG5cbiAgICBtdWxTY2FsYXIoYmFzZSwgZSkge1xuICAgICAgICByZXR1cm4gbXVsU2NhbGFyKHRoaXMsIGJhc2UsIGUpO1xuICAgIH1cblxuICAgIHBvdyhiYXNlLCBlKSB7XG4gICAgICAgIHJldHVybiBleHAodGhpcywgYmFzZSwgZSk7XG4gICAgfVxuXG4gICAgZXhwKGJhc2UsIGUpIHtcbiAgICAgICAgcmV0dXJuIGV4cCh0aGlzLCBiYXNlLCBlKTtcbiAgICB9XG5cbiAgICB0b1N0cmluZyhhKSB7XG4gICAgICAgIHJldHVybiBgWyAke3RoaXMuRi50b1N0cmluZyhhWzBdKX0gLCAke3RoaXMuRi50b1N0cmluZyhhWzFdKX0sICR7dGhpcy5GLnRvU3RyaW5nKGFbMl0pfSBdYDtcbiAgICB9XG5cbiAgICBmcm9tUm5nKHJuZykge1xuICAgICAgICBjb25zdCBjMCA9IHRoaXMuRi5mcm9tUm5nKHJuZyk7XG4gICAgICAgIGNvbnN0IGMxID0gdGhpcy5GLmZyb21Sbmcocm5nKTtcbiAgICAgICAgY29uc3QgYzIgPSB0aGlzLkYuZnJvbVJuZyhybmcpO1xuICAgICAgICByZXR1cm4gW2MwLCBjMSwgYzJdO1xuICAgIH1cblxuICAgIGd0KGEsIGIpIHtcbiAgICAgICAgaWYgKHRoaXMuRi5ndChhWzBdLCBiWzBdKSkgcmV0dXJuIHRydWU7XG4gICAgICAgIGlmICh0aGlzLkYuZ3QoYlswXSwgYVswXSkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgaWYgKHRoaXMuRi5ndChhWzFdLCBiWzFdKSkgcmV0dXJuIHRydWU7XG4gICAgICAgIGlmICh0aGlzLkYuZ3QoYlsxXSwgYVsxXSkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgaWYgKHRoaXMuRi5ndChhWzJdLCBiWzJdKSkgcmV0dXJuIHRydWU7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cblxuICAgIGdlcShhLCBiKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmd0KGEsIGIpIHx8IHRoaXMuZXEoYSwgYik7XG4gICAgfVxuXG4gICAgbHQoYSwgYikge1xuICAgICAgICByZXR1cm4gIXRoaXMuZ2VxKGEsYik7XG4gICAgfVxuXG4gICAgbGVxKGEsIGIpIHtcbiAgICAgICAgcmV0dXJuICF0aGlzLmd0KGEsYik7XG4gICAgfVxuXG4gICAgbmVxKGEsIGIpIHtcbiAgICAgICAgcmV0dXJuICF0aGlzLmVxKGEsYik7XG4gICAgfVxuXG4gICAgcmFuZG9tKCkge1xuICAgICAgICByZXR1cm4gW3RoaXMuRi5yYW5kb20oKSwgdGhpcy5GLnJhbmRvbSgpLCB0aGlzLkYucmFuZG9tKCldO1xuICAgIH1cblxuXG4gICAgdG9ScHJMRShidWZmLCBvLCBlKSB7XG4gICAgICAgIHRoaXMuRi50b1JwckxFKGJ1ZmYsIG8sIGVbMF0pO1xuICAgICAgICB0aGlzLkYudG9ScHJMRShidWZmLCBvK3RoaXMuRi5uOCwgZVsxXSk7XG4gICAgICAgIHRoaXMuRi50b1JwckxFKGJ1ZmYsIG8rdGhpcy5GLm44KjIsIGVbMl0pO1xuICAgIH1cblxuICAgIHRvUnByQkUoYnVmZiwgbywgZSkge1xuICAgICAgICB0aGlzLkYudG9ScHJCRShidWZmLCBvLCBlWzJdKTtcbiAgICAgICAgdGhpcy5GLnRvUnByQkUoYnVmZiwgbyt0aGlzLkYubjgsIGVbMV0pO1xuICAgICAgICB0aGlzLkYudG9ScHJCRShidWZmLCBvK3RoaXMuRi5uOCoyLCBlWzBdKTtcbiAgICB9XG5cbiAgICB0b1JwckxFTShidWZmLCBvLCBlKSB7XG4gICAgICAgIHRoaXMuRi50b1JwckxFTShidWZmLCBvLCBlWzBdKTtcbiAgICAgICAgdGhpcy5GLnRvUnByTEVNKGJ1ZmYsIG8rdGhpcy5GLm44LCBlWzFdKTtcbiAgICAgICAgdGhpcy5GLnRvUnByTEVNKGJ1ZmYsIG8rdGhpcy5GLm44KjIsIGVbMl0pO1xuICAgIH1cblxuXG4gICAgdG9ScHJCRU0oYnVmZiwgbywgZSkge1xuICAgICAgICB0aGlzLkYudG9ScHJCRU0oYnVmZiwgbywgZVsyXSk7XG4gICAgICAgIHRoaXMuRi50b1JwckJFTShidWZmLCBvK3RoaXMuRi5uOCwgZVsxXSk7XG4gICAgICAgIHRoaXMuRi50b1JwckJFTShidWZmLCBvK3RoaXMuRi5uOCoyLCBlWzBdKTtcbiAgICB9XG5cbiAgICBmcm9tUnByTEUoYnVmZiwgbykge1xuICAgICAgICBvID0gbyB8fCAwO1xuICAgICAgICBjb25zdCBjMCA9IHRoaXMuRi5mcm9tUnByTEUoYnVmZiwgbyk7XG4gICAgICAgIGNvbnN0IGMxID0gdGhpcy5GLmZyb21ScHJMRShidWZmLCBvK3RoaXMubjgpO1xuICAgICAgICBjb25zdCBjMiA9IHRoaXMuRi5mcm9tUnByTEUoYnVmZiwgbyt0aGlzLm44KjIpO1xuICAgICAgICByZXR1cm4gW2MwLCBjMSwgYzJdO1xuICAgIH1cblxuICAgIGZyb21ScHJCRShidWZmLCBvKSB7XG4gICAgICAgIG8gPSBvIHx8IDA7XG4gICAgICAgIGNvbnN0IGMyID0gdGhpcy5GLmZyb21ScHJCRShidWZmLCBvKTtcbiAgICAgICAgY29uc3QgYzEgPSB0aGlzLkYuZnJvbVJwckJFKGJ1ZmYsIG8rdGhpcy5uOCk7XG4gICAgICAgIGNvbnN0IGMwID0gdGhpcy5GLmZyb21ScHJCRShidWZmLCBvK3RoaXMubjgqMik7XG4gICAgICAgIHJldHVybiBbYzAsIGMxLCBjMl07XG4gICAgfVxuXG4gICAgZnJvbVJwckxFTShidWZmLCBvKSB7XG4gICAgICAgIG8gPSBvIHx8IDA7XG4gICAgICAgIGNvbnN0IGMwID0gdGhpcy5GLmZyb21ScHJMRU0oYnVmZiwgbyk7XG4gICAgICAgIGNvbnN0IGMxID0gdGhpcy5GLmZyb21ScHJMRU0oYnVmZiwgbyt0aGlzLm44KTtcbiAgICAgICAgY29uc3QgYzIgPSB0aGlzLkYuZnJvbVJwckxFTShidWZmLCBvK3RoaXMubjgqMik7XG4gICAgICAgIHJldHVybiBbYzAsIGMxLCBjMl07XG4gICAgfVxuXG4gICAgZnJvbVJwckJFTShidWZmLCBvKSB7XG4gICAgICAgIG8gPSBvIHx8IDA7XG4gICAgICAgIGNvbnN0IGMyID0gdGhpcy5GLmZyb21ScHJCRU0oYnVmZiwgbyk7XG4gICAgICAgIGNvbnN0IGMxID0gdGhpcy5GLmZyb21ScHJCRU0oYnVmZiwgbyt0aGlzLm44KTtcbiAgICAgICAgY29uc3QgYzAgPSB0aGlzLkYuZnJvbVJwckJFTShidWZmLCBvK3RoaXMubjgqMik7XG4gICAgICAgIHJldHVybiBbYzAsIGMxLCBjMl07XG4gICAgfVxuXG4gICAgdG9PYmplY3QoYSkge1xuICAgICAgICByZXR1cm4gYTtcbiAgICB9XG59XG5cbi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMGtpbXMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya2pzLlxuXG4gICAgc25hcmtqcyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuICAgIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGVcbiAgICBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbilcbiAgICBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJranMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3JcbiAgICBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoXG4gICAgc25hcmtqcy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cblxuXG5mdW5jdGlvbiBpc0dyZWF0ZXN0KEYsIGEpIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShhKSkge1xuICAgICAgICBmb3IgKGxldCBpPWEubGVuZ3RoLTE7IGk+PTA7IGktLSkge1xuICAgICAgICAgICAgaWYgKCFGLkYuaXNaZXJvKGFbaV0pKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGlzR3JlYXRlc3QoRi5GLCBhW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBuYSA9IEYubmVnKGEpO1xuICAgICAgICByZXR1cm4gZ3QoYSwgbmEpO1xuICAgIH1cbn1cblxuXG5jbGFzcyBFQyB7XG5cbiAgICBjb25zdHJ1Y3RvcihGLCBnKSB7XG4gICAgICAgIHRoaXMuRiA9IEY7XG4gICAgICAgIHRoaXMuZyA9IGc7XG4gICAgICAgIGlmICh0aGlzLmcubGVuZ3RoID09IDIpIHRoaXMuZ1syXSA9IHRoaXMuRi5vbmU7XG4gICAgICAgIHRoaXMuemVybyA9IFt0aGlzLkYuemVybywgdGhpcy5GLm9uZSwgdGhpcy5GLnplcm9dO1xuICAgIH1cblxuICAgIGFkZChwMSwgcDIpIHtcblxuICAgICAgICBjb25zdCBGID0gdGhpcy5GO1xuXG4gICAgICAgIGlmICh0aGlzLmVxKHAxLCB0aGlzLnplcm8pKSByZXR1cm4gcDI7XG4gICAgICAgIGlmICh0aGlzLmVxKHAyLCB0aGlzLnplcm8pKSByZXR1cm4gcDE7XG5cbiAgICAgICAgY29uc3QgcmVzID0gbmV3IEFycmF5KDMpO1xuXG4gICAgICAgIGNvbnN0IFoxWjEgPSBGLnNxdWFyZSggcDFbMl0gKTtcbiAgICAgICAgY29uc3QgWjJaMiA9IEYuc3F1YXJlKCBwMlsyXSApO1xuXG4gICAgICAgIGNvbnN0IFUxID0gRi5tdWwoIHAxWzBdICwgWjJaMiApOyAgICAgLy8gVTEgPSBYMSAgKiBaMloyXG4gICAgICAgIGNvbnN0IFUyID0gRi5tdWwoIHAyWzBdICwgWjFaMSApOyAgICAgLy8gVTIgPSBYMiAgKiBaMVoxXG5cbiAgICAgICAgY29uc3QgWjFfY3ViZWQgPSBGLm11bCggcDFbMl0gLCBaMVoxKTtcbiAgICAgICAgY29uc3QgWjJfY3ViZWQgPSBGLm11bCggcDJbMl0gLCBaMloyKTtcblxuICAgICAgICBjb25zdCBTMSA9IEYubXVsKCBwMVsxXSAsIFoyX2N1YmVkKTsgIC8vIFMxID0gWTEgKiBaMiAqIFoyWjJcbiAgICAgICAgY29uc3QgUzIgPSBGLm11bCggcDJbMV0gLCBaMV9jdWJlZCk7ICAvLyBTMiA9IFkyICogWjEgKiBaMVoxXG5cbiAgICAgICAgaWYgKEYuZXEoVTEsVTIpICYmIEYuZXEoUzEsUzIpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kb3VibGUocDEpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgSCA9IEYuc3ViKCBVMiAsIFUxICk7ICAgICAgICAgICAgICAgICAgICAvLyBIID0gVTItVTFcblxuICAgICAgICBjb25zdCBTMl9taW51c19TMSA9IEYuc3ViKCBTMiAsIFMxICk7XG5cbiAgICAgICAgY29uc3QgSSA9IEYuc3F1YXJlKCBGLmFkZChILEgpICk7ICAgICAgICAgLy8gSSA9ICgyICogSCleMlxuICAgICAgICBjb25zdCBKID0gRi5tdWwoIEggLCBJICk7ICAgICAgICAgICAgICAgICAgICAgIC8vIEogPSBIICogSVxuXG4gICAgICAgIGNvbnN0IHIgPSBGLmFkZCggUzJfbWludXNfUzEgLCBTMl9taW51c19TMSApOyAgLy8gciA9IDIgKiAoUzItUzEpXG4gICAgICAgIGNvbnN0IFYgPSBGLm11bCggVTEgLCBJICk7ICAgICAgICAgICAgICAgICAgICAgLy8gViA9IFUxICogSVxuXG4gICAgICAgIHJlc1swXSA9XG4gICAgICAgICAgICBGLnN1YihcbiAgICAgICAgICAgICAgICBGLnN1YiggRi5zcXVhcmUocikgLCBKICksXG4gICAgICAgICAgICAgICAgRi5hZGQoIFYgLCBWICkpOyAgICAgICAgICAgICAgICAgICAgICAgLy8gWDMgPSByXjIgLSBKIC0gMiAqIFZcblxuICAgICAgICBjb25zdCBTMV9KID0gRi5tdWwoIFMxICwgSiApO1xuXG4gICAgICAgIHJlc1sxXSA9XG4gICAgICAgICAgICBGLnN1YihcbiAgICAgICAgICAgICAgICBGLm11bCggciAsIEYuc3ViKFYscmVzWzBdKSksXG4gICAgICAgICAgICAgICAgRi5hZGQoIFMxX0osUzFfSiApKTsgICAgICAgICAgICAgICAgICAgLy8gWTMgPSByICogKFYtWDMpLTIgUzEgSlxuXG4gICAgICAgIHJlc1syXSA9XG4gICAgICAgICAgICBGLm11bChcbiAgICAgICAgICAgICAgICBILFxuICAgICAgICAgICAgICAgIEYuc3ViKFxuICAgICAgICAgICAgICAgICAgICBGLnNxdWFyZSggRi5hZGQocDFbMl0scDJbMl0pICksXG4gICAgICAgICAgICAgICAgICAgIEYuYWRkKCBaMVoxICwgWjJaMiApKSk7ICAgICAgICAgICAgLy8gWjMgPSAoKFoxK1oyKV4yLVoxWjEtWjJaMikgKiBIXG5cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICBuZWcocCkge1xuICAgICAgICByZXR1cm4gW3BbMF0sIHRoaXMuRi5uZWcocFsxXSksIHBbMl1dO1xuICAgIH1cblxuICAgIHN1YihhLCBiKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFkZChhLCB0aGlzLm5lZyhiKSk7XG4gICAgfVxuXG4gICAgZG91YmxlKHApIHtcbiAgICAgICAgY29uc3QgRiA9IHRoaXMuRjtcblxuICAgICAgICBjb25zdCByZXMgPSBuZXcgQXJyYXkoMyk7XG5cbiAgICAgICAgaWYgKHRoaXMuZXEocCwgdGhpcy56ZXJvKSkgcmV0dXJuIHA7XG5cbiAgICAgICAgY29uc3QgQSA9IEYuc3F1YXJlKCBwWzBdICk7ICAgICAgICAgICAgICAgICAgICAvLyBBID0gWDFeMlxuICAgICAgICBjb25zdCBCID0gRi5zcXVhcmUoIHBbMV0gKTsgICAgICAgICAgICAgICAgICAgIC8vIEIgPSBZMV4yXG4gICAgICAgIGNvbnN0IEMgPSBGLnNxdWFyZSggQiApOyAgICAgICAgICAgICAgICAgICAgICAgLy8gQyA9IEJeMlxuXG4gICAgICAgIGxldCBEID1cbiAgICAgICAgICAgIEYuc3ViKFxuICAgICAgICAgICAgICAgIEYuc3F1YXJlKCBGLmFkZChwWzBdICwgQiApKSxcbiAgICAgICAgICAgICAgICBGLmFkZCggQSAsIEMpKTtcbiAgICAgICAgRCA9IEYuYWRkKEQsRCk7ICAgICAgICAgICAgICAgICAgICAvLyBEID0gMiAqICgoWDEgKyBCKV4yIC0gQSAtIEMpXG5cbiAgICAgICAgY29uc3QgRSA9IEYuYWRkKCBGLmFkZChBLEEpLCBBKTsgICAgICAgICAgLy8gRSA9IDMgKiBBXG4gICAgICAgIGNvbnN0IEZGID1GLnNxdWFyZSggRSApOyAgICAgICAgICAgICAgICAgICAgICAgLy8gRiA9IEVeMlxuXG4gICAgICAgIHJlc1swXSA9IEYuc3ViKCBGRiAsIEYuYWRkKEQsRCkgKTsgICAgICAgICAvLyBYMyA9IEYgLSAyIERcblxuICAgICAgICBsZXQgZWlnaHRDID0gRi5hZGQoIEMgLCBDICk7XG4gICAgICAgIGVpZ2h0QyA9IEYuYWRkKCBlaWdodEMgLCBlaWdodEMgKTtcbiAgICAgICAgZWlnaHRDID0gRi5hZGQoIGVpZ2h0QyAsIGVpZ2h0QyApO1xuXG4gICAgICAgIHJlc1sxXSA9XG4gICAgICAgICAgICBGLnN1YihcbiAgICAgICAgICAgICAgICBGLm11bChcbiAgICAgICAgICAgICAgICAgICAgRSxcbiAgICAgICAgICAgICAgICAgICAgRi5zdWIoIEQsIHJlc1swXSApKSxcbiAgICAgICAgICAgICAgICBlaWdodEMpOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFkzID0gRSAqIChEIC0gWDMpIC0gOCAqIENcblxuICAgICAgICBjb25zdCBZMVoxID0gRi5tdWwoIHBbMV0gLCBwWzJdICk7XG4gICAgICAgIHJlc1syXSA9IEYuYWRkKCBZMVoxICwgWTFaMSApOyAgICAgICAgICAgICAgICAgLy8gWjMgPSAyICogWTEgKiBaMVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgdGltZXNTY2FsYXIoYmFzZSwgZSkge1xuICAgICAgICByZXR1cm4gbXVsU2NhbGFyKHRoaXMsIGJhc2UsIGUpO1xuICAgIH1cblxuICAgIG11bFNjYWxhcihiYXNlLCBlKSB7XG4gICAgICAgIHJldHVybiBtdWxTY2FsYXIodGhpcywgYmFzZSwgZSk7XG4gICAgfVxuXG4gICAgYWZmaW5lKHApIHtcbiAgICAgICAgY29uc3QgRiA9IHRoaXMuRjtcbiAgICAgICAgaWYgKHRoaXMuaXNaZXJvKHApKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy56ZXJvO1xuICAgICAgICB9IGVsc2UgaWYgKEYuZXEocFsyXSwgRi5vbmUpKSB7XG4gICAgICAgICAgICByZXR1cm4gcDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IFpfaW52ID0gRi5pbnYocFsyXSk7XG4gICAgICAgICAgICBjb25zdCBaMl9pbnYgPSBGLnNxdWFyZShaX2ludik7XG4gICAgICAgICAgICBjb25zdCBaM19pbnYgPSBGLm11bChaMl9pbnYsIFpfaW52KTtcblxuICAgICAgICAgICAgY29uc3QgcmVzID0gbmV3IEFycmF5KDMpO1xuICAgICAgICAgICAgcmVzWzBdID0gRi5tdWwocFswXSxaMl9pbnYpO1xuICAgICAgICAgICAgcmVzWzFdID0gRi5tdWwocFsxXSxaM19pbnYpO1xuICAgICAgICAgICAgcmVzWzJdID0gRi5vbmU7XG5cbiAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBtdWx0aUFmZmluZShhcnIpIHtcbiAgICAgICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKGFycik7XG4gICAgICAgIGNvbnN0IEYgPSB0aGlzLkY7XG4gICAgICAgIGNvbnN0IGFjY011bCA9IG5ldyBBcnJheShrZXlzLmxlbmd0aCsxKTtcbiAgICAgICAgYWNjTXVsWzBdID0gRi5vbmU7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoRi5lcShhcnJba2V5c1tpXV1bMl0sIEYuemVybykpIHtcbiAgICAgICAgICAgICAgICBhY2NNdWxbaSsxXSA9IGFjY011bFtpXTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYWNjTXVsW2krMV0gPSBGLm11bChhY2NNdWxbaV0sIGFycltrZXlzW2ldXVsyXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBhY2NNdWxba2V5cy5sZW5ndGhdID0gRi5pbnYoYWNjTXVsW2tleXMubGVuZ3RoXSk7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IGtleXMubGVuZ3RoLTE7IGk+PTA7IGktLSkge1xuICAgICAgICAgICAgaWYgKEYuZXEoYXJyW2tleXNbaV1dWzJdLCBGLnplcm8pKSB7XG4gICAgICAgICAgICAgICAgYWNjTXVsW2ldID0gYWNjTXVsW2krMV07XG4gICAgICAgICAgICAgICAgYXJyW2tleXNbaV1dID0gdGhpcy56ZXJvO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zdCBaX2ludiA9IEYubXVsKGFjY011bFtpXSwgYWNjTXVsW2krMV0pO1xuICAgICAgICAgICAgICAgIGFjY011bFtpXSA9IEYubXVsKGFycltrZXlzW2ldXVsyXSwgYWNjTXVsW2krMV0pO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgWjJfaW52ID0gRi5zcXVhcmUoWl9pbnYpO1xuICAgICAgICAgICAgICAgIGNvbnN0IFozX2ludiA9IEYubXVsKFoyX2ludiwgWl9pbnYpO1xuXG4gICAgICAgICAgICAgICAgYXJyW2tleXNbaV1dWzBdID0gRi5tdWwoYXJyW2tleXNbaV1dWzBdLFoyX2ludik7XG4gICAgICAgICAgICAgICAgYXJyW2tleXNbaV1dWzFdID0gRi5tdWwoYXJyW2tleXNbaV1dWzFdLFozX2ludik7XG4gICAgICAgICAgICAgICAgYXJyW2tleXNbaV1dWzJdID0gRi5vbmU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgIH1cblxuICAgIGVxKHAxLCBwMikge1xuICAgICAgICBjb25zdCBGID0gdGhpcy5GO1xuXG4gICAgICAgIGlmICh0aGlzLkYuZXEocDFbMl0sIHRoaXMuRi56ZXJvKSkgcmV0dXJuIHRoaXMuRi5lcShwMlsyXSwgdGhpcy5GLnplcm8pO1xuICAgICAgICBpZiAodGhpcy5GLmVxKHAyWzJdLCB0aGlzLkYuemVybykpIHJldHVybiBmYWxzZTtcblxuICAgICAgICBjb25zdCBaMVoxID0gRi5zcXVhcmUoIHAxWzJdICk7XG4gICAgICAgIGNvbnN0IFoyWjIgPSBGLnNxdWFyZSggcDJbMl0gKTtcblxuICAgICAgICBjb25zdCBVMSA9IEYubXVsKCBwMVswXSAsIFoyWjIgKTtcbiAgICAgICAgY29uc3QgVTIgPSBGLm11bCggcDJbMF0gLCBaMVoxICk7XG5cbiAgICAgICAgY29uc3QgWjFfY3ViZWQgPSBGLm11bCggcDFbMl0gLCBaMVoxKTtcbiAgICAgICAgY29uc3QgWjJfY3ViZWQgPSBGLm11bCggcDJbMl0gLCBaMloyKTtcblxuICAgICAgICBjb25zdCBTMSA9IEYubXVsKCBwMVsxXSAsIFoyX2N1YmVkKTtcbiAgICAgICAgY29uc3QgUzIgPSBGLm11bCggcDJbMV0gLCBaMV9jdWJlZCk7XG5cbiAgICAgICAgcmV0dXJuIChGLmVxKFUxLFUyKSAmJiBGLmVxKFMxLFMyKSk7XG4gICAgfVxuXG4gICAgaXNaZXJvKHApIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuRi5pc1plcm8ocFsyXSk7XG4gICAgfVxuXG4gICAgdG9TdHJpbmcocCkge1xuICAgICAgICBjb25zdCBjcCA9IHRoaXMuYWZmaW5lKHApO1xuICAgICAgICByZXR1cm4gYFsgJHt0aGlzLkYudG9TdHJpbmcoY3BbMF0pfSAsICR7dGhpcy5GLnRvU3RyaW5nKGNwWzFdKX0gXWA7XG4gICAgfVxuXG4gICAgZnJvbVJuZyhybmcpIHtcbiAgICAgICAgY29uc3QgRiA9IHRoaXMuRjtcbiAgICAgICAgbGV0IFAgPSBbXTtcbiAgICAgICAgbGV0IGdyZWF0ZXN0O1xuICAgICAgICBkbyB7XG4gICAgICAgICAgICBQWzBdID0gRi5mcm9tUm5nKHJuZyk7XG4gICAgICAgICAgICBncmVhdGVzdCA9IHJuZy5uZXh0Qm9vbCgpO1xuICAgICAgICAgICAgY29uc3QgeDNiID0gRi5hZGQoRi5tdWwoRi5zcXVhcmUoUFswXSksIFBbMF0pLCB0aGlzLmIpO1xuICAgICAgICAgICAgUFsxXSA9IEYuc3FydCh4M2IpO1xuICAgICAgICB9IHdoaWxlICgoUFsxXSA9PSBudWxsKXx8KEYuaXNaZXJvW1BdKSk7XG5cbiAgICAgICAgY29uc3QgcyA9IGlzR3JlYXRlc3QoRiwgUFsxXSk7XG4gICAgICAgIGlmIChncmVhdGVzdCBeIHMpIFBbMV0gPSBGLm5lZyhQWzFdKTtcbiAgICAgICAgUFsyXSA9IEYub25lO1xuXG4gICAgICAgIGlmICh0aGlzLmNvZmFjdG9yKSB7XG4gICAgICAgICAgICBQID0gdGhpcy5tdWxTY2FsYXIoUCwgdGhpcy5jb2ZhY3Rvcik7XG4gICAgICAgIH1cblxuICAgICAgICBQID0gdGhpcy5hZmZpbmUoUCk7XG5cbiAgICAgICAgcmV0dXJuIFA7XG5cbiAgICB9XG5cbiAgICB0b1JwckxFKGJ1ZmYsIG8sIHApIHtcbiAgICAgICAgcCA9IHRoaXMuYWZmaW5lKHApO1xuICAgICAgICBpZiAodGhpcy5pc1plcm8ocCkpIHtcbiAgICAgICAgICAgIGNvbnN0IEJ1ZmZWID0gbmV3IFVpbnQ4QXJyYXkoYnVmZiwgbywgdGhpcy5GLm44KjIpO1xuICAgICAgICAgICAgQnVmZlYuZmlsbCgwKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLkYudG9ScHJMRShidWZmLCBvLCBwWzBdKTtcbiAgICAgICAgdGhpcy5GLnRvUnByTEUoYnVmZiwgbyt0aGlzLkYubjgsIHBbMV0pO1xuICAgIH1cblxuICAgIHRvUnByQkUoYnVmZiwgbywgcCkge1xuICAgICAgICBwID0gdGhpcy5hZmZpbmUocCk7XG4gICAgICAgIGlmICh0aGlzLmlzWmVybyhwKSkge1xuICAgICAgICAgICAgY29uc3QgQnVmZlYgPSBuZXcgVWludDhBcnJheShidWZmLCBvLCB0aGlzLkYubjgqMik7XG4gICAgICAgICAgICBCdWZmVi5maWxsKDApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuRi50b1JwckJFKGJ1ZmYsIG8sIHBbMF0pO1xuICAgICAgICB0aGlzLkYudG9ScHJCRShidWZmLCBvK3RoaXMuRi5uOCwgcFsxXSk7XG4gICAgfVxuXG4gICAgdG9ScHJMRU0oYnVmZiwgbywgcCkge1xuICAgICAgICBwID0gdGhpcy5hZmZpbmUocCk7XG4gICAgICAgIGlmICh0aGlzLmlzWmVybyhwKSkge1xuICAgICAgICAgICAgY29uc3QgQnVmZlYgPSBuZXcgVWludDhBcnJheShidWZmLCBvLCB0aGlzLkYubjgqMik7XG4gICAgICAgICAgICBCdWZmVi5maWxsKDApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuRi50b1JwckxFTShidWZmLCBvLCBwWzBdKTtcbiAgICAgICAgdGhpcy5GLnRvUnByTEVNKGJ1ZmYsIG8rdGhpcy5GLm44LCBwWzFdKTtcbiAgICB9XG5cbiAgICB0b1JwckxFSk0oYnVmZiwgbywgcCkge1xuICAgICAgICBwID0gdGhpcy5hZmZpbmUocCk7XG4gICAgICAgIGlmICh0aGlzLmlzWmVybyhwKSkge1xuICAgICAgICAgICAgY29uc3QgQnVmZlYgPSBuZXcgVWludDhBcnJheShidWZmLCBvLCB0aGlzLkYubjgqMik7XG4gICAgICAgICAgICBCdWZmVi5maWxsKDApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuRi50b1JwckxFTShidWZmLCBvLCBwWzBdKTtcbiAgICAgICAgdGhpcy5GLnRvUnByTEVNKGJ1ZmYsIG8rdGhpcy5GLm44LCBwWzFdKTtcbiAgICAgICAgdGhpcy5GLnRvUnByTEVNKGJ1ZmYsIG8rMip0aGlzLkYubjgsIHBbMl0pO1xuICAgIH1cblxuXG4gICAgdG9ScHJCRU0oYnVmZiwgbywgcCkge1xuICAgICAgICBwID0gdGhpcy5hZmZpbmUocCk7XG4gICAgICAgIGlmICh0aGlzLmlzWmVybyhwKSkge1xuICAgICAgICAgICAgY29uc3QgQnVmZlYgPSBuZXcgVWludDhBcnJheShidWZmLCBvLCB0aGlzLkYubjgqMik7XG4gICAgICAgICAgICBCdWZmVi5maWxsKDApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuRi50b1JwckJFTShidWZmLCBvLCBwWzBdKTtcbiAgICAgICAgdGhpcy5GLnRvUnByQkVNKGJ1ZmYsIG8rdGhpcy5GLm44LCBwWzFdKTtcbiAgICB9XG5cbiAgICBmcm9tUnByTEUoYnVmZiwgbykge1xuICAgICAgICBvID0gbyB8fCAwO1xuICAgICAgICBjb25zdCB4ID0gdGhpcy5GLmZyb21ScHJMRShidWZmLCBvKTtcbiAgICAgICAgY29uc3QgeSA9IHRoaXMuRi5mcm9tUnByTEUoYnVmZiwgbyt0aGlzLkYubjgpO1xuICAgICAgICBpZiAodGhpcy5GLmlzWmVybyh4KSAmJiB0aGlzLkYuaXNaZXJvKHkpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy56ZXJvO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbeCwgeSwgdGhpcy5GLm9uZV07XG4gICAgfVxuXG4gICAgZnJvbVJwckJFKGJ1ZmYsIG8pIHtcbiAgICAgICAgbyA9IG8gfHwgMDtcbiAgICAgICAgY29uc3QgeCA9IHRoaXMuRi5mcm9tUnByQkUoYnVmZiwgbyk7XG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLkYuZnJvbVJwckJFKGJ1ZmYsIG8rdGhpcy5GLm44KTtcbiAgICAgICAgaWYgKHRoaXMuRi5pc1plcm8oeCkgJiYgdGhpcy5GLmlzWmVybyh5KSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuemVybztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW3gsIHksIHRoaXMuRi5vbmVdO1xuICAgIH1cblxuICAgIGZyb21ScHJMRU0oYnVmZiwgbykge1xuICAgICAgICBvID0gbyB8fCAwO1xuICAgICAgICBjb25zdCB4ID0gdGhpcy5GLmZyb21ScHJMRU0oYnVmZiwgbyk7XG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLkYuZnJvbVJwckxFTShidWZmLCBvK3RoaXMuRi5uOCk7XG4gICAgICAgIGlmICh0aGlzLkYuaXNaZXJvKHgpICYmIHRoaXMuRi5pc1plcm8oeSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnplcm87XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFt4LCB5LCB0aGlzLkYub25lXTtcbiAgICB9XG5cbiAgICBmcm9tUnByTEVKTShidWZmLCBvKSB7XG4gICAgICAgIG8gPSBvIHx8IDA7XG4gICAgICAgIGNvbnN0IHggPSB0aGlzLkYuZnJvbVJwckxFTShidWZmLCBvKTtcbiAgICAgICAgY29uc3QgeSA9IHRoaXMuRi5mcm9tUnByTEVNKGJ1ZmYsIG8rdGhpcy5GLm44KTtcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuRi5mcm9tUnByTEVNKGJ1ZmYsIG8rdGhpcy5GLm44KjIpO1xuICAgICAgICBpZiAodGhpcy5GLmlzWmVybyh4KSAmJiB0aGlzLkYuaXNaZXJvKHkpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy56ZXJvO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbeCwgeSwgel07XG4gICAgfVxuXG4gICAgZnJvbVJwckJFTShidWZmLCBvKSB7XG4gICAgICAgIG8gPSBvIHx8IDA7XG4gICAgICAgIGNvbnN0IHggPSB0aGlzLkYuZnJvbVJwckJFTShidWZmLCBvKTtcbiAgICAgICAgY29uc3QgeSA9IHRoaXMuRi5mcm9tUnByQkVNKGJ1ZmYsIG8rdGhpcy5GLm44KTtcbiAgICAgICAgaWYgKHRoaXMuRi5pc1plcm8oeCkgJiYgdGhpcy5GLmlzWmVybyh5KSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuemVybztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW3gsIHksIHRoaXMuRi5vbmVdO1xuICAgIH1cblxuICAgIGZyb21ScHJDb21wcmVzc2VkKGJ1ZmYsIG8pIHtcbiAgICAgICAgY29uc3QgRiA9IHRoaXMuRjtcbiAgICAgICAgY29uc3QgdiA9IG5ldyBVaW50OEFycmF5KGJ1ZmYuYnVmZmVyLCBvLCBGLm44KTtcbiAgICAgICAgaWYgKHZbMF0gJiAweDQwKSByZXR1cm4gdGhpcy56ZXJvO1xuICAgICAgICBjb25zdCBQID0gbmV3IEFycmF5KDMpO1xuXG4gICAgICAgIGNvbnN0IGdyZWF0ZXN0ID0gKCh2WzBdICYgMHg4MCkgIT0gMCk7XG4gICAgICAgIHZbMF0gPSB2WzBdICYgMHg3RjtcbiAgICAgICAgUFswXSA9IEYuZnJvbVJwckJFKGJ1ZmYsIG8pO1xuICAgICAgICBpZiAoZ3JlYXRlc3QpIHZbMF0gPSB2WzBdIHwgMHg4MDsgIC8vIHNldCBiYWNrIGFnYWluIHRoZSBvbGQgdmFsdWVcblxuICAgICAgICBjb25zdCB4M2IgPSBGLmFkZChGLm11bChGLnNxdWFyZShQWzBdKSwgUFswXSksIHRoaXMuYik7XG4gICAgICAgIFBbMV0gPSBGLnNxcnQoeDNiKTtcblxuICAgICAgICBpZiAoUFsxXSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBQb2ludCFcIik7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzID0gaXNHcmVhdGVzdChGLCBQWzFdKTtcbiAgICAgICAgaWYgKGdyZWF0ZXN0IF4gcykgUFsxXSA9IEYubmVnKFBbMV0pO1xuICAgICAgICBQWzJdID0gRi5vbmU7XG5cbiAgICAgICAgcmV0dXJuIFA7XG4gICAgfVxuXG4gICAgdG9ScHJDb21wcmVzc2VkKGJ1ZmYsIG8sIHApIHtcbiAgICAgICAgcCA9IHRoaXMuYWZmaW5lKHApO1xuICAgICAgICBjb25zdCB2ID0gbmV3IFVpbnQ4QXJyYXkoYnVmZi5idWZmZXIsIG8sIHRoaXMuRi5uOCk7XG4gICAgICAgIGlmICh0aGlzLmlzWmVybyhwKSkge1xuICAgICAgICAgICAgdi5maWxsKDApO1xuICAgICAgICAgICAgdlswXSA9IDB4NDA7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5GLnRvUnByQkUoYnVmZiwgbywgcFswXSk7XG5cbiAgICAgICAgaWYgKGlzR3JlYXRlc3QodGhpcy5GLCBwWzFdKSkge1xuICAgICAgICAgICAgdlswXSA9IHZbMF0gfCAweDgwO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICBmcm9tUnByVW5jb21wcmVzc2VkKGJ1ZmYsIG8pIHtcbiAgICAgICAgaWYgKGJ1ZmZbMF0gJiAweDQwKSByZXR1cm4gdGhpcy56ZXJvO1xuXG4gICAgICAgIHJldHVybiB0aGlzLmZyb21ScHJCRShidWZmLCBvKTtcbiAgICB9XG5cbiAgICB0b1JwclVuY29tcHJlc3NlZChidWZmLCBvLCBwKSB7XG4gICAgICAgIHRoaXMudG9ScHJCRShidWZmLCBvLCBwKTtcblxuICAgICAgICBpZiAodGhpcy5pc1plcm8ocCkpIHtcbiAgICAgICAgICAgIGJ1ZmZbb10gPSBidWZmW29dIHwgMHg0MDtcbiAgICAgICAgfVxuICAgIH1cblxuXG59XG5cbmZ1bmN0aW9uIHN0cmluZ2lmeUJpZ0ludHMobykge1xuICAgIGlmICh0eXBlb2YgbyA9PSBcImJpZ2ludFwiIHx8IG8uZXEgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gby50b1N0cmluZygxMCk7XG4gICAgfSBlbHNlIGlmIChvIGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgICByZXR1cm4gZnJvbVJwckxFKG8sIDApO1xuICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShvKSkge1xuICAgICAgICByZXR1cm4gby5tYXAoc3RyaW5naWZ5QmlnSW50cyk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgbyA9PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIGNvbnN0IHJlcyA9IHt9O1xuICAgICAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMobyk7XG4gICAgICAgIGtleXMuZm9yRWFjaCgoaykgPT4ge1xuICAgICAgICAgICAgcmVzW2tdID0gc3RyaW5naWZ5QmlnSW50cyhvW2tdKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIG87XG4gICAgfVxufVxuXG5mdW5jdGlvbiB1bnN0cmluZ2lmeUJpZ0ludHMobykge1xuICAgIGlmICh0eXBlb2YgbyA9PSBcInN0cmluZ1wiICYmIC9eWzAtOV0rJC8udGVzdChvKSkge1xuICAgICAgICByZXR1cm4gQmlnSW50KG8pO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIG8gPT0gXCJzdHJpbmdcIiAmJiAvXjB4WzAtOWEtZkEtRl0rJC8udGVzdChvKSkge1xuICAgICAgICByZXR1cm4gQmlnSW50KG8pO1xuICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShvKSkge1xuICAgICAgICByZXR1cm4gby5tYXAodW5zdHJpbmdpZnlCaWdJbnRzKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBvID09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgaWYgKG8gPT09IG51bGwpIHJldHVybiBudWxsO1xuICAgICAgICBjb25zdCByZXMgPSB7fTtcbiAgICAgICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKG8pO1xuICAgICAgICBrZXlzLmZvckVhY2goKGspID0+IHtcbiAgICAgICAgICAgIHJlc1trXSA9IHVuc3RyaW5naWZ5QmlnSW50cyhvW2tdKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIG87XG4gICAgfVxufVxuXG5mdW5jdGlvbiBiZUJ1ZmYyaW50KGJ1ZmYpIHtcbiAgICBsZXQgcmVzID0gQmlnSW50KDApO1xuICAgIGxldCBpID0gYnVmZi5sZW5ndGg7XG4gICAgbGV0IG9mZnNldCA9IDA7XG4gICAgY29uc3QgYnVmZlYgPSBuZXcgRGF0YVZpZXcoYnVmZi5idWZmZXIsIGJ1ZmYuYnl0ZU9mZnNldCwgYnVmZi5ieXRlTGVuZ3RoKTtcbiAgICB3aGlsZSAoaSA+IDApIHtcbiAgICAgICAgaWYgKGkgPj0gNCkge1xuICAgICAgICAgICAgaSAtPSA0O1xuICAgICAgICAgICAgcmVzICs9IEJpZ0ludChidWZmVi5nZXRVaW50MzIoaSkpIDw8IEJpZ0ludChvZmZzZXQgKiA4KTtcbiAgICAgICAgICAgIG9mZnNldCArPSA0O1xuICAgICAgICB9IGVsc2UgaWYgKGkgPj0gMikge1xuICAgICAgICAgICAgaSAtPSAyO1xuICAgICAgICAgICAgcmVzICs9IEJpZ0ludChidWZmVi5nZXRVaW50MTYoaSkpIDw8IEJpZ0ludChvZmZzZXQgKiA4KTtcbiAgICAgICAgICAgIG9mZnNldCArPSAyO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaSAtPSAxO1xuICAgICAgICAgICAgcmVzICs9IEJpZ0ludChidWZmVi5nZXRVaW50OChpKSkgPDwgQmlnSW50KG9mZnNldCAqIDgpO1xuICAgICAgICAgICAgb2Zmc2V0ICs9IDE7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlcztcbn1cblxuZnVuY3Rpb24gYmVJbnQyQnVmZihuLCBsZW4pIHtcbiAgICBsZXQgciA9IG47XG4gICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KGxlbik7XG4gICAgY29uc3QgYnVmZlYgPSBuZXcgRGF0YVZpZXcoYnVmZi5idWZmZXIpO1xuICAgIGxldCBvID0gbGVuO1xuICAgIHdoaWxlIChvID4gMCkge1xuICAgICAgICBpZiAobyAtIDQgPj0gMCkge1xuICAgICAgICAgICAgbyAtPSA0O1xuICAgICAgICAgICAgYnVmZlYuc2V0VWludDMyKG8sIE51bWJlcihyICYgQmlnSW50KDB4ZmZmZmZmZmYpKSk7XG4gICAgICAgICAgICByID0gciA+PiBCaWdJbnQoMzIpO1xuICAgICAgICB9IGVsc2UgaWYgKG8gLSAyID49IDApIHtcbiAgICAgICAgICAgIG8gLT0gMjtcbiAgICAgICAgICAgIGJ1ZmZWLnNldFVpbnQxNihvLCBOdW1iZXIociAmIEJpZ0ludCgweGZmZmYpKSk7XG4gICAgICAgICAgICByID0gciA+PiBCaWdJbnQoMTYpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbyAtPSAxO1xuICAgICAgICAgICAgYnVmZlYuc2V0VWludDgobywgTnVtYmVyKHIgJiBCaWdJbnQoMHhmZikpKTtcbiAgICAgICAgICAgIHIgPSByID4+IEJpZ0ludCg4KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAocikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJOdW1iZXIgZG9lcyBub3QgZml0IGluIHRoaXMgbGVuZ3RoXCIpO1xuICAgIH1cbiAgICByZXR1cm4gYnVmZjtcbn1cblxuZnVuY3Rpb24gbGVCdWZmMmludChidWZmKSB7XG4gICAgbGV0IHJlcyA9IEJpZ0ludCgwKTtcbiAgICBsZXQgaSA9IDA7XG4gICAgY29uc3QgYnVmZlYgPSBuZXcgRGF0YVZpZXcoYnVmZi5idWZmZXIsIGJ1ZmYuYnl0ZU9mZnNldCwgYnVmZi5ieXRlTGVuZ3RoKTtcbiAgICB3aGlsZSAoaSA8IGJ1ZmYubGVuZ3RoKSB7XG4gICAgICAgIGlmIChpICsgNCA8PSBidWZmLmxlbmd0aCkge1xuICAgICAgICAgICAgcmVzICs9IEJpZ0ludChidWZmVi5nZXRVaW50MzIoaSwgdHJ1ZSkpIDw8IEJpZ0ludChpICogOCk7XG4gICAgICAgICAgICBpICs9IDQ7XG4gICAgICAgIH0gZWxzZSBpZiAoaSArIDIgPD0gYnVmZi5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJlcyArPSBCaWdJbnQoYnVmZlYuZ2V0VWludDE2KGksIHRydWUpKSA8PCBCaWdJbnQoaSAqIDgpO1xuICAgICAgICAgICAgaSArPSAyO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzICs9IEJpZ0ludChidWZmVi5nZXRVaW50OChpLCB0cnVlKSkgPDwgQmlnSW50KGkgKiA4KTtcbiAgICAgICAgICAgIGkgKz0gMTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzO1xufVxuXG5mdW5jdGlvbiBsZUludDJCdWZmKG4sIGxlbikge1xuICAgIGxldCByID0gbjtcbiAgICBpZiAodHlwZW9mIGxlbiA9PT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICBsZW4gPSBNYXRoLmZsb29yKChiaXRMZW5ndGgobikgLSAxKSAvIDgpICsgMTtcbiAgICAgICAgaWYgKGxlbiA9PSAwKSBsZW4gPSAxO1xuICAgIH1cbiAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkobGVuKTtcbiAgICBjb25zdCBidWZmViA9IG5ldyBEYXRhVmlldyhidWZmLmJ1ZmZlcik7XG4gICAgbGV0IG8gPSAwO1xuICAgIHdoaWxlIChvIDwgbGVuKSB7XG4gICAgICAgIGlmIChvICsgNCA8PSBsZW4pIHtcbiAgICAgICAgICAgIGJ1ZmZWLnNldFVpbnQzMihvLCBOdW1iZXIociAmIEJpZ0ludCgweGZmZmZmZmZmKSksIHRydWUpO1xuICAgICAgICAgICAgbyArPSA0O1xuICAgICAgICAgICAgciA9IHIgPj4gQmlnSW50KDMyKTtcbiAgICAgICAgfSBlbHNlIGlmIChvICsgMiA8PSBsZW4pIHtcbiAgICAgICAgICAgIGJ1ZmZWLnNldFVpbnQxNihvLCBOdW1iZXIociAmIEJpZ0ludCgweGZmZmYpKSwgdHJ1ZSk7XG4gICAgICAgICAgICBvICs9IDI7XG4gICAgICAgICAgICByID0gciA+PiBCaWdJbnQoMTYpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYnVmZlYuc2V0VWludDgobywgTnVtYmVyKHIgJiBCaWdJbnQoMHhmZikpLCB0cnVlKTtcbiAgICAgICAgICAgIG8gKz0gMTtcbiAgICAgICAgICAgIHIgPSByID4+IEJpZ0ludCg4KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAocikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJOdW1iZXIgZG9lcyBub3QgZml0IGluIHRoaXMgbGVuZ3RoXCIpO1xuICAgIH1cbiAgICByZXR1cm4gYnVmZjtcbn1cblxuZnVuY3Rpb24gc3RyaW5naWZ5RkVsZW1lbnRzKEYsIG8pIHtcbiAgICBpZiAodHlwZW9mIG8gPT0gXCJiaWdpbnRcIiB8fCBvLmVxICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIG8udG9TdHJpbmcoMTApO1xuICAgIH0gZWxzZSBpZiAobyBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHtcbiAgICAgICAgcmV0dXJuIEYudG9TdHJpbmcoRi5lKG8pKTtcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkobykpIHtcbiAgICAgICAgcmV0dXJuIG8ubWFwKHN0cmluZ2lmeUZFbGVtZW50cy5iaW5kKHRoaXMsIEYpKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBvID09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgY29uc3QgcmVzID0ge307XG4gICAgICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhvKTtcbiAgICAgICAga2V5cy5mb3JFYWNoKChrKSA9PiB7XG4gICAgICAgICAgICByZXNba10gPSBzdHJpbmdpZnlGRWxlbWVudHMoRiwgb1trXSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBvO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gdW5zdHJpbmdpZnlGRWxlbWVudHMoRiwgbykge1xuICAgIGlmICh0eXBlb2YgbyA9PSBcInN0cmluZ1wiICYmIC9eWzAtOV0rJC8udGVzdChvKSkge1xuICAgICAgICByZXR1cm4gRi5lKG8pO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIG8gPT0gXCJzdHJpbmdcIiAmJiAvXjB4WzAtOWEtZkEtRl0rJC8udGVzdChvKSkge1xuICAgICAgICByZXR1cm4gRi5lKG8pO1xuICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShvKSkge1xuICAgICAgICByZXR1cm4gby5tYXAodW5zdHJpbmdpZnlGRWxlbWVudHMuYmluZCh0aGlzLCBGKSk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgbyA9PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIGlmIChvID09PSBudWxsKSByZXR1cm4gbnVsbDtcbiAgICAgICAgY29uc3QgcmVzID0ge307XG4gICAgICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhvKTtcbiAgICAgICAga2V5cy5mb3JFYWNoKChrKSA9PiB7XG4gICAgICAgICAgICByZXNba10gPSB1bnN0cmluZ2lmeUZFbGVtZW50cyhGLCBvW2tdKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIG87XG4gICAgfVxufVxuXG5jb25zdCBfcmV2VGFibGUgPSBbXTtcbmZvciAobGV0IGkgPSAwOyBpIDwgMjU2OyBpKyspIHtcbiAgICBfcmV2VGFibGVbaV0gPSBfcmV2U2xvdyhpLCA4KTtcbn1cblxuZnVuY3Rpb24gX3JldlNsb3coaWR4LCBiaXRzKSB7XG4gICAgbGV0IHJlcyA9IDA7XG4gICAgbGV0IGEgPSBpZHg7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBiaXRzOyBpKyspIHtcbiAgICAgICAgcmVzIDw8PSAxO1xuICAgICAgICByZXMgPSByZXMgfCAoYSAmIDEpO1xuICAgICAgICBhID4+PSAxO1xuICAgIH1cbiAgICByZXR1cm4gcmVzO1xufVxuXG5mdW5jdGlvbiBiaXRSZXZlcnNlKGlkeCwgYml0cykge1xuICAgIHJldHVybiAoXG4gICAgICAgIChfcmV2VGFibGVbaWR4ID4+PiAyNF0gfFxuICAgICAgICAoX3JldlRhYmxlWyhpZHggPj4+IDE2KSAmIDB4ZmZdIDw8IDgpIHxcbiAgICAgICAgKF9yZXZUYWJsZVsoaWR4ID4+PiA4KSAmIDB4ZmZdIDw8IDE2KSB8XG4gICAgICAgIChfcmV2VGFibGVbaWR4ICYgMHhmZl0gPDwgMjQpKSA+Pj5cbiAgICAgICAgKDMyIC0gYml0cylcbiAgICApO1xufVxuXG5mdW5jdGlvbiBsb2cyKFYpIHtcbiAgICByZXR1cm4gKFxuICAgICAgICAoKFYgJiAweGZmZmYwMDAwKSAhPT0gMCA/ICgoViAmPSAweGZmZmYwMDAwKSwgMTYpIDogMCkgfFxuICAgICAgICAoKFYgJiAweGZmMDBmZjAwKSAhPT0gMCA/ICgoViAmPSAweGZmMDBmZjAwKSwgOCkgOiAwKSB8XG4gICAgICAgICgoViAmIDB4ZjBmMGYwZjApICE9PSAwID8gKChWICY9IDB4ZjBmMGYwZjApLCA0KSA6IDApIHxcbiAgICAgICAgKChWICYgMHhjY2NjY2NjYykgIT09IDAgPyAoKFYgJj0gMHhjY2NjY2NjYyksIDIpIDogMCkgfFxuICAgICAgICAoKFYgJiAweGFhYWFhYWFhKSAhPT0gMClcbiAgICApO1xufVxuXG5mdW5jdGlvbiBidWZmUmV2ZXJzZUJpdHMoYnVmZiwgZVNpemUpIHtcbiAgICBjb25zdCBuID0gYnVmZi5ieXRlTGVuZ3RoIC8gZVNpemU7XG4gICAgY29uc3QgYml0cyA9IGxvZzIobik7XG4gICAgaWYgKG4gIT0gMSA8PCBiaXRzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgbnVtYmVyIG9mIHBvaW50ZXJzXCIpO1xuICAgIH1cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgICAgICBjb25zdCByID0gYml0UmV2ZXJzZShpLCBiaXRzKTtcbiAgICAgICAgaWYgKGkgPiByKSB7XG4gICAgICAgICAgICBjb25zdCB0bXAgPSBidWZmLnNsaWNlKGkgKiBlU2l6ZSwgKGkgKyAxKSAqIGVTaXplKTtcbiAgICAgICAgICAgIGJ1ZmYuc2V0KGJ1ZmYuc2xpY2UociAqIGVTaXplLCAociArIDEpICogZVNpemUpLCBpICogZVNpemUpO1xuICAgICAgICAgICAgYnVmZi5zZXQodG1wLCByICogZVNpemUpO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5mdW5jdGlvbiBhcnJheTJidWZmZXIoYXJyLCBzRykge1xuICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShzRyAqIGFyci5sZW5ndGgpO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnIubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgYnVmZi5zZXQoYXJyW2ldLCBpICogc0cpO1xuICAgIH1cblxuICAgIHJldHVybiBidWZmO1xufVxuXG5mdW5jdGlvbiBidWZmZXIyYXJyYXkoYnVmZiwgc0cpIHtcbiAgICBjb25zdCBuID0gYnVmZi5ieXRlTGVuZ3RoIC8gc0c7XG4gICAgY29uc3QgYXJyID0gbmV3IEFycmF5KG4pO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgICAgIGFycltpXSA9IGJ1ZmYuc2xpY2UoaSAqIHNHLCBpICogc0cgKyBzRyk7XG4gICAgfVxuICAgIHJldHVybiBhcnI7XG59XG5cbnZhciBfdXRpbHMgPSAvKiNfX1BVUkVfXyovT2JqZWN0LmZyZWV6ZSh7XG4gICAgX19wcm90b19fOiBudWxsLFxuICAgIGFycmF5MmJ1ZmZlcjogYXJyYXkyYnVmZmVyLFxuICAgIGJlQnVmZjJpbnQ6IGJlQnVmZjJpbnQsXG4gICAgYmVJbnQyQnVmZjogYmVJbnQyQnVmZixcbiAgICBiaXRSZXZlcnNlOiBiaXRSZXZlcnNlLFxuICAgIGJ1ZmZSZXZlcnNlQml0czogYnVmZlJldmVyc2VCaXRzLFxuICAgIGJ1ZmZlcjJhcnJheTogYnVmZmVyMmFycmF5LFxuICAgIGxlQnVmZjJpbnQ6IGxlQnVmZjJpbnQsXG4gICAgbGVJbnQyQnVmZjogbGVJbnQyQnVmZixcbiAgICBsb2cyOiBsb2cyLFxuICAgIHN0cmluZ2lmeUJpZ0ludHM6IHN0cmluZ2lmeUJpZ0ludHMsXG4gICAgc3RyaW5naWZ5RkVsZW1lbnRzOiBzdHJpbmdpZnlGRWxlbWVudHMsXG4gICAgdW5zdHJpbmdpZnlCaWdJbnRzOiB1bnN0cmluZ2lmeUJpZ0ludHMsXG4gICAgdW5zdHJpbmdpZnlGRWxlbWVudHM6IHVuc3RyaW5naWZ5RkVsZW1lbnRzXG59KTtcblxuLy8gMSBHaUIgcGFnZSBzaXplOiBhIGRlbGliZXJhdGVseSBjb25zZXJ2YXRpdmUsIGZyYWdtZW50YXRpb24tZnJpZW5kbHkgcGFnZSAtLSBub3Rcbi8vIHRoZSBlbmdpbmUncyBtYXggc2luZ2xlLWJ1ZmZlciBsZW5ndGggKH44IEdpQispLCB3aGljaCB3b3VsZCBkZWZlYXQgcGFnaW5nIGFuZFxuLy8gcmlzayBPT00gb24gdGhlIG11bHRpLUdpQiBHMS9HMiBidWZmZXJzIGxhcmdlIGNpcmN1aXRzIHByb2R1Y2UuXG5jb25zdCBQQUdFX1NJWkUgPSAxIDw8IDMwO1xuXG5jbGFzcyBCaWdCdWZmZXIge1xuXG4gICAgY29uc3RydWN0b3Ioc2l6ZSkge1xuICAgICAgICB0aGlzLmJ1ZmZlcnMgPSBbXTtcbiAgICAgICAgdGhpcy5ieXRlTGVuZ3RoID0gc2l6ZTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHNpemU7IGkrPSBQQUdFX1NJWkUpIHtcbiAgICAgICAgICAgIGNvbnN0IG4gPSBNYXRoLm1pbihzaXplLWksIFBBR0VfU0laRSk7XG4gICAgICAgICAgICB0aGlzLmJ1ZmZlcnMucHVzaChuZXcgVWludDhBcnJheShuKSk7XG4gICAgICAgIH1cblxuICAgIH1cblxuICAgIHNsaWNlKGZyLCB0bykge1xuICAgICAgICBpZiAoIHRvID09PSB1bmRlZmluZWQgKSB0byA9IHRoaXMuYnl0ZUxlbmd0aDtcbiAgICAgICAgaWYgKCBmciA9PT0gdW5kZWZpbmVkICkgZnIgPSAwO1xuICAgICAgICBjb25zdCBsZW4gPSB0by1mcjtcblxuICAgICAgICBjb25zdCBmaXJzdFBhZ2UgPSBNYXRoLmZsb29yKGZyIC8gUEFHRV9TSVpFKTtcbiAgICAgICAgY29uc3QgbGFzdFBhZ2UgPSBNYXRoLmZsb29yKChmcitsZW4tMSkgLyBQQUdFX1NJWkUpO1xuXG4gICAgICAgIGlmICgoZmlyc3RQYWdlID09IGxhc3RQYWdlKXx8KGxlbj09MCkpXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5idWZmZXJzW2ZpcnN0UGFnZV0uc2xpY2UoZnIlUEFHRV9TSVpFLCBmciVQQUdFX1NJWkUgKyBsZW4pO1xuXG4gICAgICAgIGxldCBidWZmO1xuXG4gICAgICAgIGxldCBwID0gZmlyc3RQYWdlO1xuICAgICAgICBsZXQgbyA9IGZyICUgUEFHRV9TSVpFO1xuICAgICAgICAvLyBSZW1haW5pbmcgYnl0ZXMgdG8gcmVhZFxuICAgICAgICBsZXQgciA9IGxlbjtcbiAgICAgICAgd2hpbGUgKHI+MCkge1xuICAgICAgICAgICAgLy8gYnl0ZXMgdG8gY29weSBmcm9tIHRoaXMgcGFnZVxuICAgICAgICAgICAgY29uc3QgbCA9IChvK3IgPiBQQUdFX1NJWkUpID8gKFBBR0VfU0laRSAtbykgOiByO1xuICAgICAgICAgICAgY29uc3Qgc3JjVmlldyA9IG5ldyBVaW50OEFycmF5KHRoaXMuYnVmZmVyc1twXS5idWZmZXIsIHRoaXMuYnVmZmVyc1twXS5ieXRlT2Zmc2V0K28sIGwpO1xuICAgICAgICAgICAgaWYgKGwgPT0gbGVuKSByZXR1cm4gc3JjVmlldy5zbGljZSgpO1xuICAgICAgICAgICAgaWYgKCFidWZmKSB7XG4gICAgICAgICAgICAgICAgaWYgKGxlbiA8PSBQQUdFX1NJWkUpIHtcbiAgICAgICAgICAgICAgICAgICAgYnVmZiA9IG5ldyBVaW50OEFycmF5KGxlbik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgYnVmZiA9IG5ldyBCaWdCdWZmZXIobGVuKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBidWZmLnNldChzcmNWaWV3LCBsZW4tcik7XG4gICAgICAgICAgICByID0gci1sO1xuICAgICAgICAgICAgcCArKztcbiAgICAgICAgICAgIG8gPSAwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgfVxuXG4gICAgc2V0KGJ1ZmYsIG9mZnNldCkge1xuICAgICAgICBpZiAob2Zmc2V0ID09PSB1bmRlZmluZWQpIG9mZnNldCA9IDA7XG5cbiAgICAgICAgY29uc3QgbGVuID0gYnVmZi5ieXRlTGVuZ3RoO1xuXG4gICAgICAgIGlmIChsZW49PTApIHJldHVybjtcblxuICAgICAgICBjb25zdCBmaXJzdFBhZ2UgPSBNYXRoLmZsb29yKG9mZnNldCAvIFBBR0VfU0laRSk7XG4gICAgICAgIGNvbnN0IGxhc3RQYWdlID0gTWF0aC5mbG9vcigob2Zmc2V0K2xlbi0xKSAvIFBBR0VfU0laRSk7XG5cbiAgICAgICAgaWYgKGZpcnN0UGFnZSA9PSBsYXN0UGFnZSkge1xuICAgICAgICAgICAgaWYgKChidWZmIGluc3RhbmNlb2YgQmlnQnVmZmVyKSYmKGJ1ZmYuYnVmZmVycy5sZW5ndGg9PTEpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYnVmZmVyc1tmaXJzdFBhZ2VdLnNldChidWZmLmJ1ZmZlcnNbMF0sIG9mZnNldCAlIFBBR0VfU0laRSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmJ1ZmZlcnNbZmlyc3RQYWdlXS5zZXQoYnVmZiwgb2Zmc2V0ICUgUEFHRV9TSVpFKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9XG5cblxuICAgICAgICBsZXQgcCA9IGZpcnN0UGFnZTtcbiAgICAgICAgbGV0IG8gPSBvZmZzZXQgJSBQQUdFX1NJWkU7XG4gICAgICAgIGxldCByID0gbGVuO1xuICAgICAgICB3aGlsZSAocj4wKSB7XG4gICAgICAgICAgICBjb25zdCBsID0gKG8rciA+IFBBR0VfU0laRSkgPyAoUEFHRV9TSVpFIC1vKSA6IHI7XG4gICAgICAgICAgICBjb25zdCBzcmNWaWV3ID0gYnVmZi5zbGljZSggbGVuIC1yLCBsZW4gLXIrbCk7XG4gICAgICAgICAgICBjb25zdCBkc3RWaWV3ID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5idWZmZXJzW3BdLmJ1ZmZlciwgdGhpcy5idWZmZXJzW3BdLmJ5dGVPZmZzZXQgKyBvLCBsKTtcbiAgICAgICAgICAgIGRzdFZpZXcuc2V0KHNyY1ZpZXcpO1xuICAgICAgICAgICAgciA9IHItbDtcbiAgICAgICAgICAgIHAgKys7XG4gICAgICAgICAgICBvID0gMDtcbiAgICAgICAgfVxuXG4gICAgfVxufVxuXG5mdW5jdGlvbiBidWlsZEJhdGNoQ29udmVydCh0bSwgZm5OYW1lLCBzSW4sIHNPdXQpIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gYmF0Y2hDb252ZXJ0KGJ1ZmZJbikge1xuICAgICAgICBjb25zdCBuUG9pbnRzID0gTWF0aC5mbG9vcihidWZmSW4uYnl0ZUxlbmd0aCAvIHNJbik7XG4gICAgICAgIGlmICggblBvaW50cyAqIHNJbiAhPT0gYnVmZkluLmJ5dGVMZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgYnVmZmVyIHNpemVcIik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcG9pbnRzUGVyQ2h1bmsgPSBNYXRoLmZsb29yKG5Qb2ludHMvdG0uY29uY3VycmVuY3kpO1xuICAgICAgICBjb25zdCBvcFByb21pc2VzID0gW107XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTx0bS5jb25jdXJyZW5jeTsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgbjtcbiAgICAgICAgICAgIGlmIChpPCB0bS5jb25jdXJyZW5jeS0xKSB7XG4gICAgICAgICAgICAgICAgbiA9IHBvaW50c1BlckNodW5rO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuID0gblBvaW50cyAtIGkqcG9pbnRzUGVyQ2h1bms7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobj09MCkgY29udGludWU7XG5cbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZDaHVuayA9IGJ1ZmZJbi5zbGljZShpKnBvaW50c1BlckNodW5rKnNJbiwgaSpwb2ludHNQZXJDaHVuaypzSW4gKyBuKnNJbik7XG4gICAgICAgICAgICBjb25zdCB0YXNrID0gW1xuICAgICAgICAgICAgICAgIHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAwLCBidWZmOmJ1ZmZDaHVua30sXG4gICAgICAgICAgICAgICAge2NtZDogXCJBTExPQ1wiLCB2YXI6IDEsIGxlbjpzT3V0ICogbn0sXG4gICAgICAgICAgICAgICAge2NtZDogXCJDQUxMXCIsIGZuTmFtZTogZm5OYW1lLCBwYXJhbXM6IFtcbiAgICAgICAgICAgICAgICAgICAge3ZhcjogMH0sXG4gICAgICAgICAgICAgICAgICAgIHt2YWw6IG59LFxuICAgICAgICAgICAgICAgICAgICB7dmFyOiAxfVxuICAgICAgICAgICAgICAgIF19LFxuICAgICAgICAgICAgICAgIHtjbWQ6IFwiR0VUXCIsIG91dDogMCwgdmFyOiAxLCBsZW46c091dCAqIG59LFxuICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIG9wUHJvbWlzZXMucHVzaChcbiAgICAgICAgICAgICAgICB0bS5xdWV1ZUFjdGlvbih0YXNrLCBbYnVmZkNodW5rLmJ1ZmZlcl0pXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5hbGwob3BQcm9taXNlcyk7XG5cbiAgICAgICAgbGV0IGZ1bGxCdWZmT3V0O1xuICAgICAgICBpZiAoYnVmZkluIGluc3RhbmNlb2YgQmlnQnVmZmVyKSB7XG4gICAgICAgICAgICBmdWxsQnVmZk91dCA9IG5ldyBCaWdCdWZmZXIoblBvaW50cypzT3V0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGZ1bGxCdWZmT3V0ID0gbmV3IFVpbnQ4QXJyYXkoblBvaW50cypzT3V0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBwID0wO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8cmVzdWx0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBmdWxsQnVmZk91dC5zZXQocmVzdWx0W2ldWzBdLCBwKTtcbiAgICAgICAgICAgIHArPXJlc3VsdFtpXVswXS5ieXRlTGVuZ3RoO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZ1bGxCdWZmT3V0O1xuICAgIH07XG59XG5cbmNsYXNzIFdhc21GaWVsZDEge1xuXG4gICAgY29uc3RydWN0b3IodG0sIHByZWZpeCwgbjgsIHApIHtcbiAgICAgICAgdGhpcy50bSA9IHRtO1xuICAgICAgICB0aGlzLnByZWZpeCA9IHByZWZpeDtcblxuICAgICAgICB0aGlzLnAgPSBwO1xuICAgICAgICB0aGlzLm44ID0gbjg7XG4gICAgICAgIHRoaXMudHlwZSA9IFwiRjFcIjtcbiAgICAgICAgdGhpcy5tID0gMTtcblxuICAgICAgICB0aGlzLmhhbGYgPSBzaGlmdFJpZ2h0KHAsIG9uZSk7XG4gICAgICAgIHRoaXMuYml0TGVuZ3RoID0gYml0TGVuZ3RoKHApO1xuICAgICAgICB0aGlzLm1hc2sgPSBzdWIoc2hpZnRMZWZ0KG9uZSwgdGhpcy5iaXRMZW5ndGgpLCBvbmUpO1xuXG4gICAgICAgIHRoaXMucE9wMSA9IHRtLmFsbG9jKG44KTtcbiAgICAgICAgdGhpcy5wT3AyID0gdG0uYWxsb2MobjgpO1xuICAgICAgICB0aGlzLnBPcDMgPSB0bS5hbGxvYyhuOCk7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1twcmVmaXggKyBcIl96ZXJvXCJdKHRoaXMucE9wMSk7XG4gICAgICAgIHRoaXMuemVybyA9IHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDEsIHRoaXMubjgpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbcHJlZml4ICsgXCJfb25lXCJdKHRoaXMucE9wMSk7XG4gICAgICAgIHRoaXMub25lID0gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMSwgdGhpcy5uOCk7XG5cbiAgICAgICAgdGhpcy5uZWdvbmUgPSB0aGlzLm5lZyh0aGlzLm9uZSk7XG4gICAgICAgIHRoaXMudHdvID0gdGhpcy5hZGQodGhpcy5vbmUsIHRoaXMub25lKTtcblxuICAgICAgICB0aGlzLm42NCA9IE1hdGguZmxvb3IobjgvOCk7XG4gICAgICAgIHRoaXMubjMyID0gTWF0aC5mbG9vcihuOC80KTtcblxuICAgICAgICBpZih0aGlzLm42NCo4ICE9IHRoaXMubjgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIm44IG11c3QgYmUgYSBtdWx0aXBsZSBvZiA4XCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5oYWxmID0gc2hpZnRSaWdodCh0aGlzLnAsIG9uZSk7XG4gICAgICAgIHRoaXMubnFyID0gdGhpcy50d287XG4gICAgICAgIGxldCByID0gdGhpcy5leHAodGhpcy5ucXIsIHRoaXMuaGFsZik7XG4gICAgICAgIHdoaWxlICghdGhpcy5lcShyLCB0aGlzLm5lZ29uZSkpIHtcbiAgICAgICAgICAgIHRoaXMubnFyID0gdGhpcy5hZGQodGhpcy5ucXIsIHRoaXMub25lKTtcbiAgICAgICAgICAgIHIgPSB0aGlzLmV4cCh0aGlzLm5xciwgdGhpcy5oYWxmKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2hpZnQgPSB0aGlzLm11bCh0aGlzLm5xciwgdGhpcy5ucXIpO1xuICAgICAgICB0aGlzLnNoaWZ0SW52ID0gdGhpcy5pbnYodGhpcy5zaGlmdCk7XG5cbiAgICAgICAgdGhpcy5zID0gMDtcbiAgICAgICAgbGV0IHQgPSBzdWIodGhpcy5wLCBvbmUpO1xuXG4gICAgICAgIHdoaWxlICggIWlzT2RkKHQpICkge1xuICAgICAgICAgICAgdGhpcy5zID0gdGhpcy5zICsgMTtcbiAgICAgICAgICAgIHQgPSBzaGlmdFJpZ2h0KHQsIG9uZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLncgPSBbXTtcbiAgICAgICAgdGhpcy53W3RoaXMuc10gPSB0aGlzLmV4cCh0aGlzLm5xciwgdCk7XG5cbiAgICAgICAgZm9yIChsZXQgaT0gdGhpcy5zLTE7IGk+PTA7IGktLSkge1xuICAgICAgICAgICAgdGhpcy53W2ldID0gdGhpcy5zcXVhcmUodGhpcy53W2krMV0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLmVxKHRoaXMud1swXSwgdGhpcy5vbmUpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJFcnJvciBjYWxjdWxhdGluZyByb290cyBvZiB1bml0eVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuYmF0Y2hUb01vbnRnb21lcnkgPSBidWlsZEJhdGNoQ29udmVydCh0bSwgcHJlZml4ICsgXCJfYmF0Y2hUb01vbnRnb21lcnlcIiwgdGhpcy5uOCwgdGhpcy5uOCk7XG4gICAgICAgIHRoaXMuYmF0Y2hGcm9tTW9udGdvbWVyeSA9IGJ1aWxkQmF0Y2hDb252ZXJ0KHRtLCBwcmVmaXggKyBcIl9iYXRjaEZyb21Nb250Z29tZXJ5XCIsIHRoaXMubjgsIHRoaXMubjgpO1xuICAgIH1cblxuXG4gICAgb3AyKG9wTmFtZSwgYSwgYikge1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AxLCBhKTtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMiwgYik7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIG9wTmFtZV0odGhpcy5wT3AxLCB0aGlzLnBPcDIsIHRoaXMucE9wMyk7XG4gICAgICAgIHJldHVybiB0aGlzLnRtLmdldEJ1ZmYodGhpcy5wT3AzLCB0aGlzLm44KTtcbiAgICB9XG5cbiAgICBvcDJCb29sKG9wTmFtZSwgYSwgYikge1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AxLCBhKTtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMiwgYik7XG4gICAgICAgIHJldHVybiAhIXRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIG9wTmFtZV0odGhpcy5wT3AxLCB0aGlzLnBPcDIpO1xuICAgIH1cblxuICAgIG9wMShvcE5hbWUsIGEpIHtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMSwgYSk7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIG9wTmFtZV0odGhpcy5wT3AxLCB0aGlzLnBPcDMpO1xuICAgICAgICByZXR1cm4gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMywgdGhpcy5uOCk7XG4gICAgfVxuXG4gICAgb3AxQm9vbChvcE5hbWUsIGEpIHtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMSwgYSk7XG4gICAgICAgIHJldHVybiAhIXRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIG9wTmFtZV0odGhpcy5wT3AxLCB0aGlzLnBPcDMpO1xuICAgIH1cblxuICAgIGFkZChhLGIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AyKFwiX2FkZFwiLCBhLCBiKTtcbiAgICB9XG5cblxuICAgIGVxKGEsYikge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDJCb29sKFwiX2VxXCIsIGEsIGIpO1xuICAgIH1cblxuICAgIGlzWmVybyhhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMUJvb2woXCJfaXNaZXJvXCIsIGEpO1xuICAgIH1cblxuICAgIHN1YihhLGIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AyKFwiX3N1YlwiLCBhLCBiKTtcbiAgICB9XG5cbiAgICBuZWcoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDEoXCJfbmVnXCIsIGEpO1xuICAgIH1cblxuICAgIGludihhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMShcIl9pbnZlcnNlXCIsIGEpO1xuICAgIH1cblxuICAgIHRvTW9udGdvbWVyeShhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMShcIl90b01vbnRnb21lcnlcIiwgYSk7XG4gICAgfVxuXG4gICAgZnJvbU1vbnRnb21lcnkoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDEoXCJfZnJvbU1vbnRnb21lcnlcIiwgYSk7XG4gICAgfVxuXG4gICAgbXVsKGEsYikge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDIoXCJfbXVsXCIsIGEsIGIpO1xuICAgIH1cblxuICAgIGRpdihhLCBiKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AyLCBiKTtcbiAgICAgICAgdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMucHJlZml4ICsgXCJfaW52ZXJzZVwiXSh0aGlzLnBPcDIsIHRoaXMucE9wMik7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIFwiX211bFwiXSh0aGlzLnBPcDEsIHRoaXMucE9wMiwgdGhpcy5wT3AzKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDMsIHRoaXMubjgpO1xuICAgIH1cblxuICAgIHNxdWFyZShhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMShcIl9zcXVhcmVcIiwgYSk7XG4gICAgfVxuXG4gICAgaXNTcXVhcmUoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDFCb29sKFwiX2lzU3F1YXJlXCIsIGEpO1xuICAgIH1cblxuICAgIHNxcnQoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDEoXCJfc3FydFwiLCBhKTtcbiAgICB9XG5cbiAgICBleHAoYSwgYikge1xuICAgICAgICBpZiAoIShiIGluc3RhbmNlb2YgVWludDhBcnJheSkpIHtcbiAgICAgICAgICAgIGIgPSB0b0xFQnVmZihlKGIpKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AxLCBhKTtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMiwgYik7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIFwiX2V4cFwiXSh0aGlzLnBPcDEsIHRoaXMucE9wMiwgYi5ieXRlTGVuZ3RoLCB0aGlzLnBPcDMpO1xuICAgICAgICByZXR1cm4gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMywgdGhpcy5uOCk7XG4gICAgfVxuXG4gICAgaXNOZWdhdGl2ZShhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMUJvb2woXCJfaXNOZWdhdGl2ZVwiLCBhKTtcbiAgICB9XG5cbiAgICBlKGEsIGIpIHtcbiAgICAgICAgaWYgKGEgaW5zdGFuY2VvZiBVaW50OEFycmF5KSByZXR1cm4gYTtcbiAgICAgICAgbGV0IHJhID0gZShhLCBiKTtcbiAgICAgICAgaWYgKGlzTmVnYXRpdmUocmEpKSB7XG4gICAgICAgICAgICByYSA9IG5lZyhyYSk7XG4gICAgICAgICAgICBpZiAoZ3QocmEsIHRoaXMucCkpIHtcbiAgICAgICAgICAgICAgICByYSA9IG1vZChyYSwgdGhpcy5wKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJhID0gc3ViKHRoaXMucCwgcmEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGd0KHJhLCB0aGlzLnApKSB7XG4gICAgICAgICAgICAgICAgcmEgPSBtb2QocmEsIHRoaXMucCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYnVmZiA9IGxlSW50MkJ1ZmYocmEsIHRoaXMubjgpO1xuICAgICAgICByZXR1cm4gdGhpcy50b01vbnRnb21lcnkoYnVmZik7XG4gICAgfVxuXG4gICAgdG9TdHJpbmcoYSwgcmFkaXgpIHtcbiAgICAgICAgY29uc3QgYW4gPSB0aGlzLmZyb21Nb250Z29tZXJ5KGEpO1xuICAgICAgICBjb25zdCBzID0gZnJvbVJwckxFKGFuLCAwKTtcbiAgICAgICAgcmV0dXJuIHRvU3RyaW5nKHMsIHJhZGl4KTtcbiAgICB9XG5cbiAgICBmcm9tUm5nKHJuZykge1xuICAgICAgICBsZXQgdjtcbiAgICAgICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KHRoaXMubjgpO1xuICAgICAgICBkbyB7XG4gICAgICAgICAgICB2ID0gemVybztcbiAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaTx0aGlzLm42NDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdiA9IGFkZCh2LCAgc2hpZnRMZWZ0KHJuZy5uZXh0VTY0KCksIDY0KmkpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHYgPSBiYW5kKHYsIHRoaXMubWFzayk7XG4gICAgICAgIH0gd2hpbGUgKGdlcSh2LCB0aGlzLnApKTtcbiAgICAgICAgdG9ScHJMRShidWZmLCAwLCB2LCB0aGlzLm44KTtcbiAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgfVxuXG4gICAgcmFuZG9tKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5mcm9tUm5nKGdldFRocmVhZFJuZygpKTtcbiAgICB9XG5cbiAgICB0b09iamVjdChhKSB7XG4gICAgICAgIGNvbnN0IGFuID0gdGhpcy5mcm9tTW9udGdvbWVyeShhKTtcbiAgICAgICAgcmV0dXJuIGZyb21ScHJMRShhbiwgMCk7XG4gICAgfVxuXG4gICAgZnJvbU9iamVjdChhKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheSh0aGlzLm44KTtcbiAgICAgICAgdG9ScHJMRShidWZmLCAwLCBhLCB0aGlzLm44KTtcbiAgICAgICAgcmV0dXJuIHRoaXMudG9Nb250Z29tZXJ5KGJ1ZmYpO1xuICAgIH1cblxuICAgIHRvUnByTEUoYnVmZiwgb2Zmc2V0LCBhKSB7XG4gICAgICAgIGJ1ZmYuc2V0KHRoaXMuZnJvbU1vbnRnb21lcnkoYSksIG9mZnNldCk7XG4gICAgfVxuXG4gICAgdG9ScHJCRShidWZmLCBvZmZzZXQsIGEpIHtcbiAgICAgICAgY29uc3QgYnVmZjIgPSB0aGlzLmZyb21Nb250Z29tZXJ5KGEpO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8dGhpcy5uOC8yOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGF1eCA9IGJ1ZmYyW2ldO1xuICAgICAgICAgICAgYnVmZjJbaV0gPSBidWZmMlt0aGlzLm44LTEtaV07XG4gICAgICAgICAgICBidWZmMlt0aGlzLm44LTEtaV0gPSBhdXg7XG4gICAgICAgIH1cbiAgICAgICAgYnVmZi5zZXQoYnVmZjIsIG9mZnNldCk7XG4gICAgfVxuXG4gICAgZnJvbVJwckxFKGJ1ZmYsIG9mZnNldCkge1xuICAgICAgICBvZmZzZXQgPSBvZmZzZXQgfHwgMDtcbiAgICAgICAgY29uc3QgcmVzID0gYnVmZi5zbGljZShvZmZzZXQsIG9mZnNldCArIHRoaXMubjgpO1xuICAgICAgICByZXR1cm4gdGhpcy50b01vbnRnb21lcnkocmVzKTtcbiAgICB9XG5cbiAgICBhc3luYyBiYXRjaEludmVyc2UoYnVmZkluKSB7XG4gICAgICAgIGxldCByZXR1cm5BcnJheSA9IGZhbHNlO1xuICAgICAgICBjb25zdCBzSW4gPSB0aGlzLm44O1xuICAgICAgICBjb25zdCBzT3V0ID0gdGhpcy5uODtcblxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShidWZmSW4pKSB7XG4gICAgICAgICAgICBidWZmSW4gPSBhcnJheTJidWZmZXIoYnVmZkluLCBzSW4gKTtcbiAgICAgICAgICAgIHJldHVybkFycmF5ID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGJ1ZmZJbiA9IGJ1ZmZJbi5zbGljZSgwLCBidWZmSW4uYnl0ZUxlbmd0aCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBuUG9pbnRzID0gTWF0aC5mbG9vcihidWZmSW4uYnl0ZUxlbmd0aCAvIHNJbik7XG4gICAgICAgIGlmICggblBvaW50cyAqIHNJbiAhPT0gYnVmZkluLmJ5dGVMZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgYnVmZmVyIHNpemVcIik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcG9pbnRzUGVyQ2h1bmsgPSBNYXRoLmZsb29yKG5Qb2ludHMvdGhpcy50bS5jb25jdXJyZW5jeSk7XG4gICAgICAgIGNvbnN0IG9wUHJvbWlzZXMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHRoaXMudG0uY29uY3VycmVuY3k7IGkrKykge1xuICAgICAgICAgICAgbGV0IG47XG4gICAgICAgICAgICBpZiAoaTwgdGhpcy50bS5jb25jdXJyZW5jeS0xKSB7XG4gICAgICAgICAgICAgICAgbiA9IHBvaW50c1BlckNodW5rO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuID0gblBvaW50cyAtIGkqcG9pbnRzUGVyQ2h1bms7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobj09MCkgY29udGludWU7XG5cbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZDaHVuayA9IGJ1ZmZJbi5zbGljZShpKnBvaW50c1BlckNodW5rKnNJbiwgaSpwb2ludHNQZXJDaHVuaypzSW4gKyBuKnNJbik7XG4gICAgICAgICAgICBjb25zdCB0YXNrID0gW1xuICAgICAgICAgICAgICAgIHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAwLCBidWZmOmJ1ZmZDaHVua30sXG4gICAgICAgICAgICAgICAge2NtZDogXCJBTExPQ1wiLCB2YXI6IDEsIGxlbjpzT3V0ICogbn0sXG4gICAgICAgICAgICAgICAge2NtZDogXCJDQUxMXCIsIGZuTmFtZTogdGhpcy5wcmVmaXggKyBcIl9iYXRjaEludmVyc2VcIiwgcGFyYW1zOiBbXG4gICAgICAgICAgICAgICAgICAgIHt2YXI6IDB9LFxuICAgICAgICAgICAgICAgICAgICB7dmFsOiBzSW59LFxuICAgICAgICAgICAgICAgICAgICB7dmFsOiBufSxcbiAgICAgICAgICAgICAgICAgICAge3ZhcjogMX0sXG4gICAgICAgICAgICAgICAgICAgIHt2YWw6IHNPdXR9LFxuICAgICAgICAgICAgICAgIF19LFxuICAgICAgICAgICAgICAgIHtjbWQ6IFwiR0VUXCIsIG91dDogMCwgdmFyOiAxLCBsZW46c091dCAqIG59LFxuICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIG9wUHJvbWlzZXMucHVzaChcbiAgICAgICAgICAgICAgICB0aGlzLnRtLnF1ZXVlQWN0aW9uKHRhc2ssIFtidWZmQ2h1bmsuYnVmZmVyXSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBQcm9taXNlLmFsbChvcFByb21pc2VzKTtcblxuICAgICAgICBsZXQgZnVsbEJ1ZmZPdXQ7XG4gICAgICAgIGlmIChidWZmSW4gaW5zdGFuY2VvZiBCaWdCdWZmZXIpIHtcbiAgICAgICAgICAgIGZ1bGxCdWZmT3V0ID0gbmV3IEJpZ0J1ZmZlcihuUG9pbnRzKnNPdXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZnVsbEJ1ZmZPdXQgPSBuZXcgVWludDhBcnJheShuUG9pbnRzKnNPdXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHAgPTA7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxyZXN1bHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGZ1bGxCdWZmT3V0LnNldChyZXN1bHRbaV1bMF0sIHApO1xuICAgICAgICAgICAgcCs9cmVzdWx0W2ldWzBdLmJ5dGVMZW5ndGg7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocmV0dXJuQXJyYXkpIHtcbiAgICAgICAgICAgIHJldHVybiBidWZmZXIyYXJyYXkoZnVsbEJ1ZmZPdXQsIHNPdXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bGxCdWZmT3V0O1xuICAgICAgICB9XG5cbiAgICB9XG5cbn1cblxuY2xhc3MgV2FzbUZpZWxkMiB7XG5cbiAgICBjb25zdHJ1Y3Rvcih0bSwgcHJlZml4LCBGKSB7XG4gICAgICAgIHRoaXMudG0gPSB0bTtcbiAgICAgICAgdGhpcy5wcmVmaXggPSBwcmVmaXg7XG5cbiAgICAgICAgdGhpcy5GID0gRjtcbiAgICAgICAgdGhpcy50eXBlID0gXCJGMlwiO1xuICAgICAgICB0aGlzLm0gPSBGLm0gKiAyO1xuICAgICAgICB0aGlzLm44ID0gdGhpcy5GLm44KjI7XG4gICAgICAgIHRoaXMubjMyID0gdGhpcy5GLm4zMioyO1xuICAgICAgICB0aGlzLm42NCA9IHRoaXMuRi5uNjQqMjtcblxuICAgICAgICB0aGlzLnBPcDEgPSB0bS5hbGxvYyhGLm44KjIpO1xuICAgICAgICB0aGlzLnBPcDIgPSB0bS5hbGxvYyhGLm44KjIpO1xuICAgICAgICB0aGlzLnBPcDMgPSB0bS5hbGxvYyhGLm44KjIpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbcHJlZml4ICsgXCJfemVyb1wiXSh0aGlzLnBPcDEpO1xuICAgICAgICB0aGlzLnplcm8gPSB0bS5nZXRCdWZmKHRoaXMucE9wMSwgdGhpcy5uOCk7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1twcmVmaXggKyBcIl9vbmVcIl0odGhpcy5wT3AxKTtcbiAgICAgICAgdGhpcy5vbmUgPSB0bS5nZXRCdWZmKHRoaXMucE9wMSwgdGhpcy5uOCk7XG5cbiAgICAgICAgdGhpcy5uZWdvbmUgPSB0aGlzLm5lZyh0aGlzLm9uZSk7XG4gICAgICAgIHRoaXMudHdvID0gdGhpcy5hZGQodGhpcy5vbmUsIHRoaXMub25lKTtcblxuICAgIH1cblxuICAgIG9wMihvcE5hbWUsIGEsIGIpIHtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMSwgYSk7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDIsIGIpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AyLCB0aGlzLnBPcDMpO1xuICAgICAgICByZXR1cm4gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMywgdGhpcy5uOCk7XG4gICAgfVxuXG4gICAgb3AyQm9vbChvcE5hbWUsIGEsIGIpIHtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMSwgYSk7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDIsIGIpO1xuICAgICAgICByZXR1cm4gISF0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AyKTtcbiAgICB9XG5cbiAgICBvcDEob3BOYW1lLCBhKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AzKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDMsIHRoaXMubjgpO1xuICAgIH1cblxuICAgIG9wMUJvb2wob3BOYW1lLCBhKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICByZXR1cm4gISF0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AzKTtcbiAgICB9XG5cbiAgICBhZGQoYSxiKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMihcIl9hZGRcIiwgYSwgYik7XG4gICAgfVxuXG4gICAgZXEoYSxiKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMkJvb2woXCJfZXFcIiwgYSwgYik7XG4gICAgfVxuXG4gICAgaXNaZXJvKGEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AxQm9vbChcIl9pc1plcm9cIiwgYSk7XG4gICAgfVxuXG4gICAgc3ViKGEsYikge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDIoXCJfc3ViXCIsIGEsIGIpO1xuICAgIH1cblxuICAgIG5lZyhhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMShcIl9uZWdcIiwgYSk7XG4gICAgfVxuXG4gICAgaW52KGEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AxKFwiX2ludmVyc2VcIiwgYSk7XG4gICAgfVxuXG4gICAgaXNOZWdhdGl2ZShhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMUJvb2woXCJfaXNOZWdhdGl2ZVwiLCBhKTtcbiAgICB9XG5cbiAgICB0b01vbnRnb21lcnkoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDEoXCJfdG9Nb250Z29tZXJ5XCIsIGEpO1xuICAgIH1cblxuICAgIGZyb21Nb250Z29tZXJ5KGEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AxKFwiX2Zyb21Nb250Z29tZXJ5XCIsIGEpO1xuICAgIH1cblxuICAgIG11bChhLGIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AyKFwiX211bFwiLCBhLCBiKTtcbiAgICB9XG5cbiAgICBtdWwxKGEsYikge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDIoXCJfbXVsMVwiLCBhLCBiKTtcbiAgICB9XG5cbiAgICBkaXYoYSwgYikge1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AxLCBhKTtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMiwgYik7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIFwiX2ludmVyc2VcIl0odGhpcy5wT3AyLCB0aGlzLnBPcDIpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBcIl9tdWxcIl0odGhpcy5wT3AxLCB0aGlzLnBPcDIsIHRoaXMucE9wMyk7XG4gICAgICAgIHJldHVybiB0aGlzLnRtLmdldEJ1ZmYodGhpcy5wT3AzLCB0aGlzLm44KTtcbiAgICB9XG5cbiAgICBzcXVhcmUoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDEoXCJfc3F1YXJlXCIsIGEpO1xuICAgIH1cblxuICAgIGlzU3F1YXJlKGEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AxQm9vbChcIl9pc1NxdWFyZVwiLCBhKTtcbiAgICB9XG5cbiAgICBzcXJ0KGEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AxKFwiX3NxcnRcIiwgYSk7XG4gICAgfVxuXG4gICAgZXhwKGEsIGIpIHtcbiAgICAgICAgaWYgKCEoYiBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpKSB7XG4gICAgICAgICAgICBiID0gdG9MRUJ1ZmYoZShiKSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMSwgYSk7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDIsIGIpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBcIl9leHBcIl0odGhpcy5wT3AxLCB0aGlzLnBPcDIsIGIuYnl0ZUxlbmd0aCwgdGhpcy5wT3AzKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDMsIHRoaXMubjgpO1xuICAgIH1cblxuICAgIGUoYSwgYikge1xuICAgICAgICBpZiAoYSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHJldHVybiBhO1xuICAgICAgICBpZiAoKEFycmF5LmlzQXJyYXkoYSkpICYmIChhLmxlbmd0aCA9PSAyKSkge1xuICAgICAgICAgICAgY29uc3QgYzEgPSB0aGlzLkYuZShhWzBdLCBiKTtcbiAgICAgICAgICAgIGNvbnN0IGMyID0gdGhpcy5GLmUoYVsxXSwgYik7XG4gICAgICAgICAgICBjb25zdCByZXMgPSBuZXcgVWludDhBcnJheSh0aGlzLkYubjgqMik7XG4gICAgICAgICAgICByZXMuc2V0KGMxKTtcbiAgICAgICAgICAgIHJlcy5zZXQoYzIsIHRoaXMuRi5uOCoyKTtcbiAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIEYyXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdG9TdHJpbmcoYSwgcmFkaXgpIHtcbiAgICAgICAgY29uc3QgczEgPSB0aGlzLkYudG9TdHJpbmcoYS5zbGljZSgwLCB0aGlzLkYubjgpLCByYWRpeCk7XG4gICAgICAgIGNvbnN0IHMyID0gdGhpcy5GLnRvU3RyaW5nKGEuc2xpY2UodGhpcy5GLm44KSwgcmFkaXgpO1xuICAgICAgICByZXR1cm4gYFske3MxfSwgJHtzMn1dYDtcbiAgICB9XG5cbiAgICBmcm9tUm5nKHJuZykge1xuICAgICAgICBjb25zdCBjMSA9IHRoaXMuRi5mcm9tUm5nKHJuZyk7XG4gICAgICAgIGNvbnN0IGMyID0gdGhpcy5GLmZyb21Sbmcocm5nKTtcbiAgICAgICAgY29uc3QgcmVzID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5GLm44KjIpO1xuICAgICAgICByZXMuc2V0KGMxKTtcbiAgICAgICAgcmVzLnNldChjMiwgdGhpcy5GLm44KTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICByYW5kb20oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZyb21SbmcoZ2V0VGhyZWFkUm5nKCkpO1xuICAgIH1cblxuICAgIHRvT2JqZWN0KGEpIHtcbiAgICAgICAgY29uc3QgYzEgPSB0aGlzLkYudG9PYmplY3QoYS5zbGljZSgwLCB0aGlzLkYubjgpKTtcbiAgICAgICAgY29uc3QgYzIgPSB0aGlzLkYudG9PYmplY3QoYS5zbGljZSh0aGlzLkYubjgsIHRoaXMuRi5uOCoyKSk7XG4gICAgICAgIHJldHVybiBbYzEsIGMyXTtcbiAgICB9XG5cbiAgICBmcm9tT2JqZWN0KGEpIHtcbiAgICAgICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KHRoaXMuRi5uOCoyKTtcbiAgICAgICAgY29uc3QgYjEgPSB0aGlzLkYuZnJvbU9iamVjdChhWzBdKTtcbiAgICAgICAgY29uc3QgYjIgPSB0aGlzLkYuZnJvbU9iamVjdChhWzFdKTtcbiAgICAgICAgYnVmZi5zZXQoYjEpO1xuICAgICAgICBidWZmLnNldChiMiwgdGhpcy5GLm44KTtcbiAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgfVxuXG4gICAgYzEoYSkge1xuICAgICAgICByZXR1cm4gYS5zbGljZSgwLCB0aGlzLkYubjgpO1xuICAgIH1cblxuICAgIGMyKGEpIHtcbiAgICAgICAgcmV0dXJuIGEuc2xpY2UodGhpcy5GLm44KTtcbiAgICB9XG5cbn1cblxuY2xhc3MgV2FzbUZpZWxkMyB7XG5cbiAgICBjb25zdHJ1Y3Rvcih0bSwgcHJlZml4LCBGKSB7XG4gICAgICAgIHRoaXMudG0gPSB0bTtcbiAgICAgICAgdGhpcy5wcmVmaXggPSBwcmVmaXg7XG5cbiAgICAgICAgdGhpcy5GID0gRjtcbiAgICAgICAgdGhpcy50eXBlID0gXCJGM1wiO1xuICAgICAgICB0aGlzLm0gPSBGLm0gKiAzO1xuICAgICAgICB0aGlzLm44ID0gdGhpcy5GLm44KjM7XG4gICAgICAgIHRoaXMubjMyID0gdGhpcy5GLm4zMiozO1xuICAgICAgICB0aGlzLm42NCA9IHRoaXMuRi5uNjQqMztcblxuICAgICAgICB0aGlzLnBPcDEgPSB0bS5hbGxvYyhGLm44KjMpO1xuICAgICAgICB0aGlzLnBPcDIgPSB0bS5hbGxvYyhGLm44KjMpO1xuICAgICAgICB0aGlzLnBPcDMgPSB0bS5hbGxvYyhGLm44KjMpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbcHJlZml4ICsgXCJfemVyb1wiXSh0aGlzLnBPcDEpO1xuICAgICAgICB0aGlzLnplcm8gPSB0bS5nZXRCdWZmKHRoaXMucE9wMSwgdGhpcy5uOCk7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1twcmVmaXggKyBcIl9vbmVcIl0odGhpcy5wT3AxKTtcbiAgICAgICAgdGhpcy5vbmUgPSB0bS5nZXRCdWZmKHRoaXMucE9wMSwgdGhpcy5uOCk7XG5cbiAgICAgICAgdGhpcy5uZWdvbmUgPSB0aGlzLm5lZyh0aGlzLm9uZSk7XG4gICAgICAgIHRoaXMudHdvID0gdGhpcy5hZGQodGhpcy5vbmUsIHRoaXMub25lKTtcblxuICAgIH1cblxuICAgIG9wMihvcE5hbWUsIGEsIGIpIHtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMSwgYSk7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDIsIGIpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AyLCB0aGlzLnBPcDMpO1xuICAgICAgICByZXR1cm4gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMywgdGhpcy5uOCk7XG4gICAgfVxuXG4gICAgb3AyQm9vbChvcE5hbWUsIGEsIGIpIHtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMSwgYSk7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDIsIGIpO1xuICAgICAgICByZXR1cm4gISF0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AyKTtcbiAgICB9XG5cbiAgICBvcDEob3BOYW1lLCBhKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AzKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDMsIHRoaXMubjgpO1xuICAgIH1cblxuICAgIG9wMUJvb2wob3BOYW1lLCBhKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICByZXR1cm4gISF0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AzKTtcbiAgICB9XG5cblxuICAgIGVxKGEsYikge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDJCb29sKFwiX2VxXCIsIGEsIGIpO1xuICAgIH1cblxuICAgIGlzWmVybyhhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMUJvb2woXCJfaXNaZXJvXCIsIGEpO1xuICAgIH1cblxuICAgIGFkZChhLGIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AyKFwiX2FkZFwiLCBhLCBiKTtcbiAgICB9XG5cbiAgICBzdWIoYSxiKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMihcIl9zdWJcIiwgYSwgYik7XG4gICAgfVxuXG4gICAgbmVnKGEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AxKFwiX25lZ1wiLCBhKTtcbiAgICB9XG5cbiAgICBpbnYoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDEoXCJfaW52ZXJzZVwiLCBhKTtcbiAgICB9XG5cbiAgICBpc05lZ2F0aXZlKGEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3AxQm9vbChcIl9pc05lZ2F0aXZlXCIsIGEpO1xuICAgIH1cblxuICAgIHRvTW9udGdvbWVyeShhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMShcIl90b01vbnRnb21lcnlcIiwgYSk7XG4gICAgfVxuXG4gICAgZnJvbU1vbnRnb21lcnkoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDEoXCJfZnJvbU1vbnRnb21lcnlcIiwgYSk7XG4gICAgfVxuXG4gICAgbXVsKGEsYikge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDIoXCJfbXVsXCIsIGEsIGIpO1xuICAgIH1cblxuICAgIGRpdihhLCBiKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AyLCBiKTtcbiAgICAgICAgdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMucHJlZml4ICsgXCJfaW52ZXJzZVwiXSh0aGlzLnBPcDIsIHRoaXMucE9wMik7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIFwiX211bFwiXSh0aGlzLnBPcDEsIHRoaXMucE9wMiwgdGhpcy5wT3AzKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDMsIHRoaXMubjgpO1xuICAgIH1cblxuICAgIHNxdWFyZShhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wMShcIl9zcXVhcmVcIiwgYSk7XG4gICAgfVxuXG4gICAgaXNTcXVhcmUoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDFCb29sKFwiX2lzU3F1YXJlXCIsIGEpO1xuICAgIH1cblxuICAgIHNxcnQoYSkge1xuICAgICAgICByZXR1cm4gdGhpcy5vcDEoXCJfc3FydFwiLCBhKTtcbiAgICB9XG5cbiAgICBleHAoYSwgYikge1xuICAgICAgICBpZiAoIShiIGluc3RhbmNlb2YgVWludDhBcnJheSkpIHtcbiAgICAgICAgICAgIGIgPSB0b0xFQnVmZihlKGIpKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AxLCBhKTtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMiwgYik7XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIFwiX2V4cFwiXSh0aGlzLnBPcDEsIHRoaXMucE9wMiwgYi5ieXRlTGVuZ3RoLCB0aGlzLnBPcDMpO1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRCdWZmKHRoaXMucE9wMywgdGhpcy5uOCk7XG4gICAgfVxuXG4gICAgZShhLCBiKSB7XG4gICAgICAgIGlmIChhIGluc3RhbmNlb2YgVWludDhBcnJheSkgcmV0dXJuIGE7XG4gICAgICAgIGlmICgoQXJyYXkuaXNBcnJheShhKSkgJiYgKGEubGVuZ3RoID09IDMpKSB7XG4gICAgICAgICAgICBjb25zdCBjMSA9IHRoaXMuRi5lKGFbMF0sIGIpO1xuICAgICAgICAgICAgY29uc3QgYzIgPSB0aGlzLkYuZShhWzFdLCBiKTtcbiAgICAgICAgICAgIGNvbnN0IGMzID0gdGhpcy5GLmUoYVsyXSwgYik7XG4gICAgICAgICAgICBjb25zdCByZXMgPSBuZXcgVWludDhBcnJheSh0aGlzLkYubjgqMyk7XG4gICAgICAgICAgICByZXMuc2V0KGMxKTtcbiAgICAgICAgICAgIHJlcy5zZXQoYzIsIHRoaXMuRi5uOCk7XG4gICAgICAgICAgICByZXMuc2V0KGMzLCB0aGlzLkYubjgqMik7XG4gICAgICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaW52YWxpZCBGM1wiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRvU3RyaW5nKGEsIHJhZGl4KSB7XG4gICAgICAgIGNvbnN0IHMxID0gdGhpcy5GLnRvU3RyaW5nKGEuc2xpY2UoMCwgdGhpcy5GLm44KSwgcmFkaXgpO1xuICAgICAgICBjb25zdCBzMiA9IHRoaXMuRi50b1N0cmluZyhhLnNsaWNlKHRoaXMuRi5uOCwgdGhpcy5GLm44KjIpLCByYWRpeCk7XG4gICAgICAgIGNvbnN0IHMzID0gdGhpcy5GLnRvU3RyaW5nKGEuc2xpY2UodGhpcy5GLm44KjIpLCByYWRpeCk7XG4gICAgICAgIHJldHVybiBgWyR7czF9LCAke3MyfSwgJHtzM31dYDtcbiAgICB9XG5cbiAgICBmcm9tUm5nKHJuZykge1xuICAgICAgICBjb25zdCBjMSA9IHRoaXMuRi5mcm9tUm5nKHJuZyk7XG4gICAgICAgIGNvbnN0IGMyID0gdGhpcy5GLmZyb21Sbmcocm5nKTtcbiAgICAgICAgY29uc3QgYzMgPSB0aGlzLkYuZnJvbVJuZyhybmcpO1xuICAgICAgICBjb25zdCByZXMgPSBuZXcgVWludDhBcnJheSh0aGlzLkYubjgqMyk7XG4gICAgICAgIHJlcy5zZXQoYzEpO1xuICAgICAgICByZXMuc2V0KGMyLCB0aGlzLkYubjgpO1xuICAgICAgICByZXMuc2V0KGMzLCB0aGlzLkYubjgqMik7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgcmFuZG9tKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5mcm9tUm5nKGdldFRocmVhZFJuZygpKTtcbiAgICB9XG5cbiAgICB0b09iamVjdChhKSB7XG4gICAgICAgIGNvbnN0IGMxID0gdGhpcy5GLnRvT2JqZWN0KGEuc2xpY2UoMCwgdGhpcy5GLm44KSk7XG4gICAgICAgIGNvbnN0IGMyID0gdGhpcy5GLnRvT2JqZWN0KGEuc2xpY2UodGhpcy5GLm44LCB0aGlzLkYubjgqMikpO1xuICAgICAgICBjb25zdCBjMyA9IHRoaXMuRi50b09iamVjdChhLnNsaWNlKHRoaXMuRi5uOCoyLCB0aGlzLkYubjgqMykpO1xuICAgICAgICByZXR1cm4gW2MxLCBjMiwgYzNdO1xuICAgIH1cblxuICAgIGZyb21PYmplY3QoYSkge1xuICAgICAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5GLm44KjMpO1xuICAgICAgICBjb25zdCBiMSA9IHRoaXMuRi5mcm9tT2JqZWN0KGFbMF0pO1xuICAgICAgICBjb25zdCBiMiA9IHRoaXMuRi5mcm9tT2JqZWN0KGFbMV0pO1xuICAgICAgICBjb25zdCBiMyA9IHRoaXMuRi5mcm9tT2JqZWN0KGFbMl0pO1xuICAgICAgICBidWZmLnNldChiMSk7XG4gICAgICAgIGJ1ZmYuc2V0KGIyLCB0aGlzLkYubjgpO1xuICAgICAgICBidWZmLnNldChiMywgdGhpcy5GLm44KjIpO1xuICAgICAgICByZXR1cm4gYnVmZjtcbiAgICB9XG5cbiAgICBjMShhKSB7XG4gICAgICAgIHJldHVybiBhLnNsaWNlKDAsIHRoaXMuRi5uOCk7XG4gICAgfVxuXG4gICAgYzIoYSkge1xuICAgICAgICByZXR1cm4gYS5zbGljZSh0aGlzLkYubjgsIHRoaXMuRi5uOCoyKTtcbiAgICB9XG5cbiAgICBjMyhhKSB7XG4gICAgICAgIHJldHVybiBhLnNsaWNlKHRoaXMuRi5uOCoyKTtcbiAgICB9XG5cbn1cblxuY2xhc3MgV2FzbUN1cnZlIHtcblxuICAgIGNvbnN0cnVjdG9yKHRtLCBwcmVmaXgsIEYsIHBHZW4sIHBHYiwgY29mYWN0b3IpIHtcbiAgICAgICAgdGhpcy50bSA9IHRtO1xuICAgICAgICB0aGlzLnByZWZpeCA9IHByZWZpeDtcbiAgICAgICAgdGhpcy5GID0gRjtcblxuICAgICAgICB0aGlzLnBPcDEgPSB0bS5hbGxvYyhGLm44KjMpO1xuICAgICAgICB0aGlzLnBPcDIgPSB0bS5hbGxvYyhGLm44KjMpO1xuICAgICAgICB0aGlzLnBPcDMgPSB0bS5hbGxvYyhGLm44KjMpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbcHJlZml4ICsgXCJfemVyb1wiXSh0aGlzLnBPcDEpO1xuICAgICAgICB0aGlzLnplcm8gPSB0aGlzLnRtLmdldEJ1ZmYodGhpcy5wT3AxLCBGLm44KjMpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbcHJlZml4ICsgXCJfemVyb0FmZmluZVwiXSh0aGlzLnBPcDEpO1xuICAgICAgICB0aGlzLnplcm9BZmZpbmUgPSB0aGlzLnRtLmdldEJ1ZmYodGhpcy5wT3AxLCBGLm44KjIpO1xuICAgICAgICB0aGlzLm9uZSA9IHRoaXMudG0uZ2V0QnVmZihwR2VuLCBGLm44KjMpO1xuICAgICAgICB0aGlzLmcgPSB0aGlzLm9uZTtcbiAgICAgICAgdGhpcy5vbmVBZmZpbmUgPSB0aGlzLnRtLmdldEJ1ZmYocEdlbiwgRi5uOCoyKTtcbiAgICAgICAgdGhpcy5nQWZmaW5lID0gdGhpcy5vbmVBZmZpbmU7XG4gICAgICAgIHRoaXMuYiA9IHRoaXMudG0uZ2V0QnVmZihwR2IsIEYubjgpO1xuXG4gICAgICAgIGlmIChjb2ZhY3Rvcikge1xuICAgICAgICAgICAgdGhpcy5jb2ZhY3RvciA9IHRvTEVCdWZmKGNvZmFjdG9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubmVnb25lID0gdGhpcy5uZWcodGhpcy5vbmUpO1xuICAgICAgICB0aGlzLnR3byA9IHRoaXMuYWRkKHRoaXMub25lLCB0aGlzLm9uZSk7XG5cbiAgICAgICAgdGhpcy5iYXRjaExFTXRvQyA9IGJ1aWxkQmF0Y2hDb252ZXJ0KHRtLCBwcmVmaXggKyBcIl9iYXRjaExFTXRvQ1wiLCBGLm44KjIsIEYubjgpO1xuICAgICAgICB0aGlzLmJhdGNoTEVNdG9VID0gYnVpbGRCYXRjaENvbnZlcnQodG0sIHByZWZpeCArIFwiX2JhdGNoTEVNdG9VXCIsIEYubjgqMiwgRi5uOCoyKTtcbiAgICAgICAgdGhpcy5iYXRjaEN0b0xFTSA9IGJ1aWxkQmF0Y2hDb252ZXJ0KHRtLCBwcmVmaXggKyBcIl9iYXRjaEN0b0xFTVwiLCBGLm44LCBGLm44KjIpO1xuICAgICAgICB0aGlzLmJhdGNoVXRvTEVNID0gYnVpbGRCYXRjaENvbnZlcnQodG0sIHByZWZpeCArIFwiX2JhdGNoVXRvTEVNXCIsIEYubjgqMiwgRi5uOCoyKTtcbiAgICAgICAgdGhpcy5iYXRjaFRvSmFjb2JpYW4gPSBidWlsZEJhdGNoQ29udmVydCh0bSwgcHJlZml4ICsgXCJfYmF0Y2hUb0phY29iaWFuXCIsIEYubjgqMiwgRi5uOCozKTtcbiAgICAgICAgdGhpcy5iYXRjaFRvQWZmaW5lID0gYnVpbGRCYXRjaENvbnZlcnQodG0sIHByZWZpeCArIFwiX2JhdGNoVG9BZmZpbmVcIiwgRi5uOCozLCBGLm44KjIpO1xuICAgIH1cblxuICAgIG9wMihvcE5hbWUsIGEsIGIpIHtcbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMSwgYSk7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDIsIGIpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AyLCB0aGlzLnBPcDMpO1xuICAgICAgICByZXR1cm4gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMywgdGhpcy5GLm44KjMpO1xuICAgIH1cblxuICAgIG9wMmJvb2wob3BOYW1lLCBhLCBiKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AyLCBiKTtcbiAgICAgICAgcmV0dXJuICEhdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMucHJlZml4ICsgb3BOYW1lXSh0aGlzLnBPcDEsIHRoaXMucE9wMiwgdGhpcy5wT3AzKTtcbiAgICB9XG5cbiAgICBvcDEob3BOYW1lLCBhKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AzKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDMsIHRoaXMuRi5uOCozKTtcbiAgICB9XG5cbiAgICBvcDFBZmZpbmUob3BOYW1lLCBhKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBvcE5hbWVdKHRoaXMucE9wMSwgdGhpcy5wT3AzKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDMsIHRoaXMuRi5uOCoyKTtcbiAgICB9XG5cbiAgICBvcDFCb29sKG9wTmFtZSwgYSkge1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AxLCBhKTtcbiAgICAgICAgcmV0dXJuICEhdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMucHJlZml4ICsgb3BOYW1lXSh0aGlzLnBPcDEsIHRoaXMucE9wMyk7XG4gICAgfVxuXG4gICAgYWRkKGEsYikge1xuICAgICAgICBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCozKSB7XG4gICAgICAgICAgICBpZiAoYi5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCozKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMub3AyKFwiX2FkZFwiLCBhLCBiKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYi5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCoyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMub3AyKFwiX2FkZE1peGVkXCIsIGEsIGIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIHBvaW50IHNpemVcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCoyKSB7XG4gICAgICAgICAgICBpZiAoYi5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCozKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMub3AyKFwiX2FkZE1peGVkXCIsIGIsIGEpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChiLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vcDIoXCJfYWRkQWZmaW5lXCIsIGEsIGIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIHBvaW50IHNpemVcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIHBvaW50IHNpemVcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzdWIoYSxiKSB7XG4gICAgICAgIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjMpIHtcbiAgICAgICAgICAgIGlmIChiLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vcDIoXCJfc3ViXCIsIGEsIGIpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChiLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vcDIoXCJfc3ViTWl4ZWRcIiwgYSwgYik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImludmFsaWQgcG9pbnQgc2l6ZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgIGlmIChiLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vcDIoXCJfc3ViTWl4ZWRcIiwgYiwgYSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGIuYnl0ZUxlbmd0aCA9PSB0aGlzLkYubjgqMikge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm9wMihcIl9zdWJBZmZpbmVcIiwgYSwgYik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImludmFsaWQgcG9pbnQgc2l6ZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImludmFsaWQgcG9pbnQgc2l6ZVwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG5lZyhhKSB7XG4gICAgICAgIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjMpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm9wMShcIl9uZWdcIiwgYSk7XG4gICAgICAgIH0gZWxzZSBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCoyKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5vcDFBZmZpbmUoXCJfbmVnQWZmaW5lXCIsIGEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaW52YWxpZCBwb2ludCBzaXplXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZG91YmxlKGEpIHtcbiAgICAgICAgaWYgKGEuYnl0ZUxlbmd0aCA9PSB0aGlzLkYubjgqMykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMub3AxKFwiX2RvdWJsZVwiLCBhKTtcbiAgICAgICAgfSBlbHNlIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm9wMShcIl9kb3VibGVBZmZpbmVcIiwgYSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIHBvaW50IHNpemVcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpc1plcm8oYSkge1xuICAgICAgICBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCozKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5vcDFCb29sKFwiX2lzWmVyb1wiLCBhKTtcbiAgICAgICAgfSBlbHNlIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm9wMUJvb2woXCJfaXNaZXJvQWZmaW5lXCIsIGEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaW52YWxpZCBwb2ludCBzaXplXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdGltZXNTY2FsYXIoYSwgcykge1xuICAgICAgICBpZiAoIShzIGluc3RhbmNlb2YgVWludDhBcnJheSkpIHtcbiAgICAgICAgICAgIHMgPSB0b0xFQnVmZihlKHMpKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgZm5OYW1lO1xuICAgICAgICBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCozKSB7XG4gICAgICAgICAgICBmbk5hbWUgPSB0aGlzLnByZWZpeCArIFwiX3RpbWVzU2NhbGFyXCI7XG4gICAgICAgIH0gZWxzZSBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCoyKSB7XG4gICAgICAgICAgICBmbk5hbWUgPSB0aGlzLnByZWZpeCArIFwiX3RpbWVzU2NhbGFyQWZmaW5lXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIHBvaW50IHNpemVcIik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50bS5zZXRCdWZmKHRoaXMucE9wMSwgYSk7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDIsIHMpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbZm5OYW1lXSh0aGlzLnBPcDEsIHRoaXMucE9wMiwgcy5ieXRlTGVuZ3RoLCB0aGlzLnBPcDMpO1xuICAgICAgICByZXR1cm4gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMywgdGhpcy5GLm44KjMpO1xuICAgIH1cblxuICAgIHRpbWVzRnIoYSwgcykge1xuICAgICAgICBsZXQgZm5OYW1lO1xuICAgICAgICBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCozKSB7XG4gICAgICAgICAgICBmbk5hbWUgPSB0aGlzLnByZWZpeCArIFwiX3RpbWVzRnJcIjtcbiAgICAgICAgfSBlbHNlIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgIGZuTmFtZSA9IHRoaXMucHJlZml4ICsgXCJfdGltZXNGckFmZmluZVwiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaW52YWxpZCBwb2ludCBzaXplXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AyLCBzKTtcbiAgICAgICAgdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW2ZuTmFtZV0odGhpcy5wT3AxLCB0aGlzLnBPcDIsIHRoaXMucE9wMyk7XG4gICAgICAgIHJldHVybiB0aGlzLnRtLmdldEJ1ZmYodGhpcy5wT3AzLCB0aGlzLkYubjgqMyk7XG4gICAgfVxuXG4gICAgZXEoYSxiKSB7XG4gICAgICAgIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjMpIHtcbiAgICAgICAgICAgIGlmIChiLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vcDJib29sKFwiX2VxXCIsIGEsIGIpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChiLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vcDJib29sKFwiX2VxTWl4ZWRcIiwgYSwgYik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImludmFsaWQgcG9pbnQgc2l6ZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgIGlmIChiLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vcDJib29sKFwiX2VxTWl4ZWRcIiwgYiwgYSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGIuYnl0ZUxlbmd0aCA9PSB0aGlzLkYubjgqMikge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm9wMmJvb2woXCJfZXFBZmZpbmVcIiwgYSwgYik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImludmFsaWQgcG9pbnQgc2l6ZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImludmFsaWQgcG9pbnQgc2l6ZVwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRvQWZmaW5lKGEpIHtcbiAgICAgICAgaWYgKGEuYnl0ZUxlbmd0aCA9PSB0aGlzLkYubjgqMykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMub3AxQWZmaW5lKFwiX3RvQWZmaW5lXCIsIGEpO1xuICAgICAgICB9IGVsc2UgaWYgKGEuYnl0ZUxlbmd0aCA9PSB0aGlzLkYubjgqMikge1xuICAgICAgICAgICAgcmV0dXJuIGE7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIHBvaW50IHNpemVcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0b0phY29iaWFuKGEpIHtcbiAgICAgICAgaWYgKGEuYnl0ZUxlbmd0aCA9PSB0aGlzLkYubjgqMykge1xuICAgICAgICAgICAgcmV0dXJuIGE7XG4gICAgICAgIH0gZWxzZSBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCoyKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5vcDEoXCJfdG9KYWNvYmlhblwiLCBhKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImludmFsaWQgcG9pbnQgc2l6ZVwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRvUnByVW5jb21wcmVzc2VkKGFyciwgb2Zmc2V0LCBhKSB7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCozKSB7XG4gICAgICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBcIl90b0FmZmluZVwiXSh0aGlzLnBPcDEsIHRoaXMucE9wMSk7XG4gICAgICAgIH0gZWxzZSBpZiAoYS5ieXRlTGVuZ3RoICE9IHRoaXMuRi5uOCoyKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIHBvaW50IHNpemVcIik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMucHJlZml4ICsgXCJfTEVNdG9VXCJdKHRoaXMucE9wMSwgdGhpcy5wT3AxKTtcbiAgICAgICAgY29uc3QgcmVzID0gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMSwgdGhpcy5GLm44KjIpO1xuICAgICAgICBhcnIuc2V0KHJlcywgb2Zmc2V0KTtcbiAgICB9XG5cbiAgICBmcm9tUnByVW5jb21wcmVzc2VkKGFyciwgb2Zmc2V0KSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBhcnIuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyB0aGlzLkYubjgqMik7XG4gICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGJ1ZmYpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5wcmVmaXggKyBcIl9VdG9MRU1cIl0odGhpcy5wT3AxLCB0aGlzLnBPcDEpO1xuICAgICAgICByZXR1cm4gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMSwgdGhpcy5GLm44KjIpO1xuICAgIH1cblxuICAgIHRvUnByQ29tcHJlc3NlZChhcnIsIG9mZnNldCwgYSkge1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AxLCBhKTtcbiAgICAgICAgaWYgKGEuYnl0ZUxlbmd0aCA9PSB0aGlzLkYubjgqMykge1xuICAgICAgICAgICAgdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMucHJlZml4ICsgXCJfdG9BZmZpbmVcIl0odGhpcy5wT3AxLCB0aGlzLnBPcDEpO1xuICAgICAgICB9IGVsc2UgaWYgKGEuYnl0ZUxlbmd0aCAhPSB0aGlzLkYubjgqMikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaW52YWxpZCBwb2ludCBzaXplXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudG0uaW5zdGFuY2UuZXhwb3J0c1t0aGlzLnByZWZpeCArIFwiX0xFTXRvQ1wiXSh0aGlzLnBPcDEsIHRoaXMucE9wMSk7XG4gICAgICAgIGNvbnN0IHJlcyA9IHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDEsIHRoaXMuRi5uOCk7XG4gICAgICAgIGFyci5zZXQocmVzLCBvZmZzZXQpO1xuICAgIH1cblxuICAgIGZyb21ScHJDb21wcmVzc2VkKGFyciwgb2Zmc2V0KSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBhcnIuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyB0aGlzLkYubjgpO1xuICAgICAgICB0aGlzLnRtLnNldEJ1ZmYodGhpcy5wT3AxLCBidWZmKTtcbiAgICAgICAgdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMucHJlZml4ICsgXCJfQ3RvTEVNXCJdKHRoaXMucE9wMSwgdGhpcy5wT3AyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMudG0uZ2V0QnVmZih0aGlzLnBPcDIsIHRoaXMuRi5uOCoyKTtcbiAgICB9XG5cbiAgICB0b1VuY29tcHJlc3NlZChhKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheSh0aGlzLkYubjgqMik7XG4gICAgICAgIHRoaXMudG9ScHJVbmNvbXByZXNzZWQoYnVmZiwgMCwgYSk7XG4gICAgICAgIHJldHVybiBidWZmO1xuICAgIH1cblxuICAgIHRvUnByTEVNKGFyciwgb2Zmc2V0LCBhKSB7XG4gICAgICAgIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgIGFyci5zZXQoYSwgb2Zmc2V0KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSBlbHNlIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjMpIHtcbiAgICAgICAgICAgIHRoaXMudG0uc2V0QnVmZih0aGlzLnBPcDEsIGEpO1xuICAgICAgICAgICAgdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMucHJlZml4ICsgXCJfdG9BZmZpbmVcIl0odGhpcy5wT3AxLCB0aGlzLnBPcDEpO1xuICAgICAgICAgICAgY29uc3QgcmVzID0gdGhpcy50bS5nZXRCdWZmKHRoaXMucE9wMSwgdGhpcy5GLm44KjIpO1xuICAgICAgICAgICAgYXJyLnNldChyZXMsIG9mZnNldCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIHBvaW50IHNpemVcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmcm9tUnByTEVNKGFyciwgb2Zmc2V0KSB7XG4gICAgICAgIG9mZnNldCA9IG9mZnNldCB8fCAwO1xuICAgICAgICByZXR1cm4gYXJyLnNsaWNlKG9mZnNldCwgb2Zmc2V0K3RoaXMuRi5uOCoyKTtcbiAgICB9XG5cbiAgICB0b1N0cmluZyhhLCByYWRpeCkge1xuICAgICAgICBpZiAoYS5ieXRlTGVuZ3RoID09IHRoaXMuRi5uOCozKSB7XG4gICAgICAgICAgICBjb25zdCB4ID0gdGhpcy5GLnRvU3RyaW5nKGEuc2xpY2UoMCwgdGhpcy5GLm44KSwgcmFkaXgpO1xuICAgICAgICAgICAgY29uc3QgeSA9IHRoaXMuRi50b1N0cmluZyhhLnNsaWNlKHRoaXMuRi5uOCwgdGhpcy5GLm44KjIpLCByYWRpeCk7XG4gICAgICAgICAgICBjb25zdCB6ID0gdGhpcy5GLnRvU3RyaW5nKGEuc2xpY2UodGhpcy5GLm44KjIpLCByYWRpeCk7XG4gICAgICAgICAgICByZXR1cm4gYFsgJHt4fSwgJHt5fSwgJHt6fSBdYDtcbiAgICAgICAgfSBlbHNlIGlmIChhLmJ5dGVMZW5ndGggPT0gdGhpcy5GLm44KjIpIHtcbiAgICAgICAgICAgIGNvbnN0IHggPSB0aGlzLkYudG9TdHJpbmcoYS5zbGljZSgwLCB0aGlzLkYubjgpLCByYWRpeCk7XG4gICAgICAgICAgICBjb25zdCB5ID0gdGhpcy5GLnRvU3RyaW5nKGEuc2xpY2UodGhpcy5GLm44KSwgcmFkaXgpO1xuICAgICAgICAgICAgcmV0dXJuIGBbICR7eH0sICR7eX0gXWA7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnZhbGlkIHBvaW50IHNpemVcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpc1ZhbGlkKGEpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNaZXJvKGEpKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgY29uc3QgRiA9IHRoaXMuRjtcbiAgICAgICAgY29uc3QgYWEgPSB0aGlzLnRvQWZmaW5lKGEpO1xuICAgICAgICBjb25zdCB4ID0gYWEuc2xpY2UoMCwgdGhpcy5GLm44KTtcbiAgICAgICAgY29uc3QgeSA9IGFhLnNsaWNlKHRoaXMuRi5uOCwgdGhpcy5GLm44KjIpO1xuICAgICAgICBjb25zdCB4M2IgPSBGLmFkZChGLm11bChGLnNxdWFyZSh4KSx4KSwgdGhpcy5iKTtcbiAgICAgICAgY29uc3QgeTIgPSBGLnNxdWFyZSh5KTtcbiAgICAgICAgcmV0dXJuIEYuZXEoeDNiLCB5Mik7XG4gICAgfVxuXG4gICAgZnJvbVJuZyhybmcpIHtcbiAgICAgICAgY29uc3QgRiA9IHRoaXMuRjtcbiAgICAgICAgbGV0IFAgPSBbXTtcbiAgICAgICAgbGV0IGdyZWF0ZXN0O1xuICAgICAgICBsZXQgeDNiO1xuICAgICAgICBkbyB7XG4gICAgICAgICAgICBQWzBdID0gRi5mcm9tUm5nKHJuZyk7XG4gICAgICAgICAgICBncmVhdGVzdCA9IHJuZy5uZXh0Qm9vbCgpO1xuICAgICAgICAgICAgeDNiID0gRi5hZGQoRi5tdWwoRi5zcXVhcmUoUFswXSksIFBbMF0pLCB0aGlzLmIpO1xuICAgICAgICB9IHdoaWxlICghRi5pc1NxdWFyZSh4M2IpKTtcblxuICAgICAgICBQWzFdID0gRi5zcXJ0KHgzYik7XG5cbiAgICAgICAgY29uc3QgcyA9IEYuaXNOZWdhdGl2ZShQWzFdKTtcbiAgICAgICAgaWYgKGdyZWF0ZXN0IF4gcykgUFsxXSA9IEYubmVnKFBbMV0pO1xuXG4gICAgICAgIGxldCBQYnVmZiA9IG5ldyBVaW50OEFycmF5KHRoaXMuRi5uOCoyKTtcbiAgICAgICAgUGJ1ZmYuc2V0KFBbMF0pO1xuICAgICAgICBQYnVmZi5zZXQoUFsxXSwgdGhpcy5GLm44KTtcblxuICAgICAgICBpZiAodGhpcy5jb2ZhY3Rvcikge1xuICAgICAgICAgICAgUGJ1ZmYgPSB0aGlzLnRpbWVzU2NhbGFyKFBidWZmLCB0aGlzLmNvZmFjdG9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBQYnVmZjtcbiAgICB9XG5cblxuXG4gICAgdG9PYmplY3QoYSkge1xuICAgICAgICBpZiAodGhpcy5pc1plcm8oYSkpIHtcbiAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgdGhpcy5GLnRvT2JqZWN0KHRoaXMuRi56ZXJvKSxcbiAgICAgICAgICAgICAgICB0aGlzLkYudG9PYmplY3QodGhpcy5GLm9uZSksXG4gICAgICAgICAgICAgICAgdGhpcy5GLnRvT2JqZWN0KHRoaXMuRi56ZXJvKSxcbiAgICAgICAgICAgIF07XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgeCA9IHRoaXMuRi50b09iamVjdChhLnNsaWNlKDAsIHRoaXMuRi5uOCkpO1xuICAgICAgICBjb25zdCB5ID0gdGhpcy5GLnRvT2JqZWN0KGEuc2xpY2UodGhpcy5GLm44LCB0aGlzLkYubjgqMikpO1xuICAgICAgICBsZXQgejtcbiAgICAgICAgaWYgKGEuYnl0ZUxlbmd0aCA9PSB0aGlzLkYubjgqMykge1xuICAgICAgICAgICAgeiA9IHRoaXMuRi50b09iamVjdChhLnNsaWNlKHRoaXMuRi5uOCoyLCB0aGlzLkYubjgqMykpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgeiA9IHRoaXMuRi50b09iamVjdCh0aGlzLkYub25lKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW3gsIHksIHpdO1xuICAgIH1cblxuICAgIGZyb21PYmplY3QoYSkge1xuICAgICAgICBjb25zdCB4ID0gdGhpcy5GLmZyb21PYmplY3QoYVswXSk7XG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLkYuZnJvbU9iamVjdChhWzFdKTtcbiAgICAgICAgbGV0IHo7XG4gICAgICAgIGlmIChhLmxlbmd0aD09Mykge1xuICAgICAgICAgICAgeiA9IHRoaXMuRi5mcm9tT2JqZWN0KGFbMl0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgeiA9IHRoaXMuRi5vbmU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuRi5pc1plcm8oeiwgdGhpcy5GLm9uZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnplcm9BZmZpbmU7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5GLmVxKHosIHRoaXMuRi5vbmUpKSB7XG4gICAgICAgICAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5GLm44KjIpO1xuICAgICAgICAgICAgYnVmZi5zZXQoeCk7XG4gICAgICAgICAgICBidWZmLnNldCh5LCB0aGlzLkYubjgpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5GLm44KjMpO1xuICAgICAgICAgICAgYnVmZi5zZXQoeCk7XG4gICAgICAgICAgICBidWZmLnNldCh5LCB0aGlzLkYubjgpO1xuICAgICAgICAgICAgYnVmZi5zZXQoeiwgdGhpcy5GLm44KjIpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBlKGEpIHtcbiAgICAgICAgaWYgKGEgaW5zdGFuY2VvZiBVaW50OEFycmF5KSByZXR1cm4gYTtcbiAgICAgICAgcmV0dXJuIHRoaXMuZnJvbU9iamVjdChhKTtcbiAgICB9XG5cbiAgICB4KGEpIHtcbiAgICAgICAgY29uc3QgdG1wID0gdGhpcy50b0FmZmluZShhKTtcbiAgICAgICAgcmV0dXJuIHRtcC5zbGljZSgwLCB0aGlzLkYubjgpO1xuICAgIH1cblxuICAgIHkoYSkge1xuICAgICAgICBjb25zdCB0bXAgPSB0aGlzLnRvQWZmaW5lKGEpO1xuICAgICAgICByZXR1cm4gdG1wLnNsaWNlKHRoaXMuRi5uOCk7XG4gICAgfVxuXG59XG5cbmZ1bmN0aW9uIHRocmVhZChzZWxmKSB7XG4gICAgY29uc3QgTUFYTUVNID0gMzI3Njc7XG4gICAgbGV0IGluc3RhbmNlO1xuICAgIGxldCBtZW1vcnk7XG4gICAgbGV0IGJhdGNoRm5zID0gbnVsbDsgICAvLyBiYXRjaC1hZmZpbmUgTVNNIGVudHJ5IHBvaW50cyAocGVyLWdyb3VwIHdyYXBwZXJzKVxuICAgIGxldCB0ZXJtaW5hdGlvblRpbWVyO1xuXG4gICAgYXN5bmMgZnVuY3Rpb24gaW5pdChkYXRhKSB7XG4gICAgICAgIGxldCB3YXNtTW9kdWxlO1xuICAgICAgICBpZiAoZGF0YS5jb2RlIGluc3RhbmNlb2YgV2ViQXNzZW1ibHkuTW9kdWxlKSB7XG4gICAgICAgICAgICB3YXNtTW9kdWxlID0gZGF0YS5jb2RlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgY29kZSA9IG5ldyBVaW50OEFycmF5KGRhdGEuY29kZSk7XG4gICAgICAgICAgICB3YXNtTW9kdWxlID0gYXdhaXQgV2ViQXNzZW1ibHkuY29tcGlsZShjb2RlKTtcbiAgICAgICAgfVxuICAgICAgICBtZW1vcnkgPSBuZXcgV2ViQXNzZW1ibHkuTWVtb3J5KHtpbml0aWFsOmRhdGEuaW5pdCwgbWF4aW11bTogTUFYTUVNfSk7XG5cbiAgICAgICAgaW5zdGFuY2UgPSBhd2FpdCBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZSh3YXNtTW9kdWxlLCB7XG4gICAgICAgICAgICBlbnY6IHtcbiAgICAgICAgICAgICAgICBcIm1lbW9yeVwiOiBtZW1vcnlcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gT3B0aW9uYWwgYmF0Y2gtYWZmaW5lIE1TTSBoZWxwZXIgbW9kdWxlLiBJdCBpcyBjdXJ2ZS1pbmRlcGVuZGVudDpcbiAgICAgICAgLy8gaXQgaW1wb3J0cyB0aGUgYmFzZS1maWVsZC9ncm91cCBvcHMgZnJvbSB0aGUgbWFpbiBpbnN0YW5jZSBhbmQgd29ya3NcbiAgICAgICAgLy8gb24gdGhlIHNhbWUgbWVtb3J5LCBzbyBvbmUgYmluYXJ5IHNlcnZlcyBHMSAoZjFtL2cxbSkgYW5kLCBvdmVyIHRoZVxuICAgICAgICAvLyBxdWFkcmF0aWMgZXh0ZW5zaW9uLCBHMiAoZjJtL2cybSkuIEluc3RhbnRpYXRlZCBvbmNlIHBlciBncm91cC5cbiAgICAgICAgaWYgKGRhdGEuYmF0Y2hDb2RlKSB7XG4gICAgICAgICAgICBsZXQgYmF0Y2hNb2R1bGU7XG4gICAgICAgICAgICBpZiAoZGF0YS5iYXRjaENvZGUgaW5zdGFuY2VvZiBXZWJBc3NlbWJseS5Nb2R1bGUpIHtcbiAgICAgICAgICAgICAgICBiYXRjaE1vZHVsZSA9IGRhdGEuYmF0Y2hDb2RlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBiYXRjaE1vZHVsZSA9IGF3YWl0IFdlYkFzc2VtYmx5LmNvbXBpbGUobmV3IFVpbnQ4QXJyYXkoZGF0YS5iYXRjaENvZGUpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGV4ID0gaW5zdGFuY2UuZXhwb3J0cztcbiAgICAgICAgICAgIGNvbnN0IG1rQmF0Y2ggPSBhc3luYyAoZiwgZywgY29uaikgPT4gKGF3YWl0IFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKGJhdGNoTW9kdWxlLCB7XG4gICAgICAgICAgICAgICAgZW52OiB7IFwibWVtb3J5XCI6IG1lbW9yeSB9LFxuICAgICAgICAgICAgICAgIGN1cnZlOiB7XG4gICAgICAgICAgICAgICAgICAgIGZfbXVsOiBleFtmICsgXCJfbXVsXCJdLCBmX3NxdWFyZTogZXhbZiArIFwiX3NxdWFyZVwiXSwgZl9hZGQ6IGV4W2YgKyBcIl9hZGRcIl0sXG4gICAgICAgICAgICAgICAgICAgIGZfc3ViOiBleFtmICsgXCJfc3ViXCJdLCBmX25lZzogZXhbZiArIFwiX25lZ1wiXSwgZl9pbnZlcnNlOiBleFtmICsgXCJfaW52ZXJzZVwiXSxcbiAgICAgICAgICAgICAgICAgICAgZl9pc1plcm86IGV4W2YgKyBcIl9pc1plcm9cIl0sIGZfY29uajogZXhbY29ual0sXG4gICAgICAgICAgICAgICAgICAgIGdfYWRkOiBleFtnICsgXCJfYWRkXCJdLCBnX2FkZE1peGVkOiBleFtnICsgXCJfYWRkTWl4ZWRcIl0sXG4gICAgICAgICAgICAgICAgICAgIGdfZG91YmxlOiBleFtnICsgXCJfZG91YmxlXCJdLCBnX3plcm86IGV4W2cgKyBcIl96ZXJvXCJdLCBnX2lzWmVybzogZXhbZyArIFwiX2lzWmVyb1wiXSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSkpLmV4cG9ydHM7XG4gICAgICAgICAgICBjb25zdCBuOGYgPSBkYXRhLm44ZjtcbiAgICAgICAgICAgIGJhdGNoRm5zID0ge307XG4gICAgICAgICAgICBpZiAoZXguZjFtX211bCAmJiBleC5nMW1fYWRkTWl4ZWQpIHtcbiAgICAgICAgICAgICAgICAvLyBmX2NvbmogaXMgb25seSB1c2VkIGJ5IHRoZSBHMiBHTFMgcGF0aDsgd2lyZSBhIGhhcm1sZXNzIGNvcHkgZm9yIEcxXG4gICAgICAgICAgICAgICAgY29uc3QgYiA9IGF3YWl0IG1rQmF0Y2goXCJmMW1cIiwgXCJnMW1cIiwgXCJmMW1fY29weVwiKTtcbiAgICAgICAgICAgICAgICAvLyBHTFYgcGF0aCAoYm4yNTQgRzEgZW5kb21vcnBoaXNtKSB3aGVuIHRoZSBjdXJ2ZSBhZHZlcnRpc2VzIGl0O1xuICAgICAgICAgICAgICAgIC8vIHRoZSB3YXNtIGZhbGxzIGJhY2sgaW50ZXJuYWxseSBmb3IgdW5leHBlY3RlZCBzaXplcy5cbiAgICAgICAgICAgICAgICBjb25zdCB1c2VHbHYgPSBkYXRhLmdsdiAmJiBiLm11bHRpZXhwQWZmaW5lR0xWO1xuICAgICAgICAgICAgICAgIGNvbnN0IGZuID0gdXNlR2x2ID8gYi5tdWx0aWV4cEFmZmluZUdMViA6IGIubXVsdGlleHBBZmZpbmU7XG4gICAgICAgICAgICAgICAgYmF0Y2hGbnNbXCJnMW1fbXVsdGlleHBBZmZpbmVCYXRjaFwiXSA9IChwQiwgcFMsIHNTLCBuLCBwcikgPT4gZm4ocEIsIHBTLCBzUywgbiwgcHIsIG44Zik7XG4gICAgICAgICAgICAgICAgLy8gTm9HbHYgdmFyaWFudCwgc2VsZWN0YWJsZSBwZXIgY2FsbCAoe2dsdjogXCJkaXNhYmxlZFwifSBvcHRpb24pXG4gICAgICAgICAgICAgICAgYmF0Y2hGbnNbXCJnMW1fbXVsdGlleHBBZmZpbmVCYXRjaE5vR2x2XCJdID0gKHBCLCBwUywgc1MsIG4sIHByKSA9PiBiLm11bHRpZXhwQWZmaW5lKHBCLCBwUywgc1MsIG4sIHByLCBuOGYpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGV4LmYybV9tdWwgJiYgZXguZzJtX2FkZE1peGVkKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYiA9IGF3YWl0IG1rQmF0Y2goXCJmMm1cIiwgXCJnMm1cIiwgXCJmMm1fY29uanVnYXRlXCIpO1xuICAgICAgICAgICAgICAgIC8vIEdMUyAoYm4yNTQgRzIgZW5kb21vcnBoaXNtKSB3aGVuIHRoZSBjdXJ2ZSBhZHZlcnRpc2VzIGl0OyB0aGVcbiAgICAgICAgICAgICAgICAvLyB3YXNtIGdhdGVzIGludGVybmFsbHkgb24gY2h1bmsgc2l6ZSBhbmQgZmFsbHMgYmFjayB0byBiYXRjaC5cbiAgICAgICAgICAgICAgICAvLyBUaGUgTm9HbHMgdmFyaWFudCBpcyBzZWxlY3RhYmxlIHBlciBjYWxsICh7Z2xzOmZhbHNlfSBvcHRpb24pLlxuICAgICAgICAgICAgICAgIGNvbnN0IHVzZUdscyA9IGRhdGEuZ2x2ICYmIGIubXVsdGlleHBBZmZpbmVHTFM7XG4gICAgICAgICAgICAgICAgY29uc3QgZm4yID0gdXNlR2xzID8gYi5tdWx0aWV4cEFmZmluZUdMUyA6IGIubXVsdGlleHBBZmZpbmU7XG4gICAgICAgICAgICAgICAgYmF0Y2hGbnNbXCJnMm1fbXVsdGlleHBBZmZpbmVCYXRjaFwiXSA9IChwQiwgcFMsIHNTLCBuLCBwcikgPT4gZm4yKHBCLCBwUywgc1MsIG4sIHByLCBuOGYgKiAyKTtcbiAgICAgICAgICAgICAgICBiYXRjaEZuc1tcImcybV9tdWx0aWV4cEFmZmluZUJhdGNoTm9HbHNcIl0gPSAocEIsIHBTLCBzUywgbiwgcHIpID0+IGIubXVsdGlleHBBZmZpbmUocEIsIHBTLCBzUywgbiwgcHIsIG44ZiAqIDIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG5cblxuICAgIC8vIFJldmVyc2UgdGhlIGxvdyBgYml0c2Agb2YgYSAzMi1iaXQgaW50ZWdlciAoTygxKSBiaXQtdHdpZGRsZSkuXG4gICAgZnVuY3Rpb24gcmV2MzIoeCkge1xuICAgICAgICB4ID0gKCh4ICYgMHg1NTU1NTU1NSkgPDwgMSkgfCAoKHggPj4+IDEpICYgMHg1NTU1NTU1NSk7XG4gICAgICAgIHggPSAoKHggJiAweDMzMzMzMzMzKSA8PCAyKSB8ICgoeCA+Pj4gMikgJiAweDMzMzMzMzMzKTtcbiAgICAgICAgeCA9ICgoeCAmIDB4MGYwZjBmMGYpIDw8IDQpIHwgKCh4ID4+PiA0KSAmIDB4MGYwZjBmMGYpO1xuICAgICAgICB4ID0gKCh4ICYgMHgwMGZmMDBmZikgPDwgOCkgfCAoKHggPj4+IDgpICYgMHgwMGZmMDBmZik7XG4gICAgICAgIHggPSAoeCA8PCAxNikgfCAoeCA+Pj4gMTYpO1xuICAgICAgICByZXR1cm4geCA+Pj4gMDtcbiAgICB9XG5cbiAgICAvLyBJbi1wbGFjZSBiaXQtcmV2ZXJzYWwgcGVybXV0YXRpb24gb2YgZml4ZWQtc2l6ZSAoc0luLWJ5dGUpIGVsZW1lbnRzLlxuICAgIC8vIFdvcmtzIGZvciBhbnkgZWxlbWVudCBzaXplLCBsaWtlIHRoZSBvbGQgcHVyZS1KUyBidWZmUmV2ZXJzZUJpdHMuIFdoZW5cbiAgICAvLyB0aGUgZWxlbWVudHMgYXJlIDQtYnl0ZSBhbGlnbmVkIGl0IHN3YXBzIFVpbnQzMkFycmF5IGxhbmVzIChubyBCaWdJbnRcbiAgICAvLyBib3hpbmcsIG5vIGFsbG9jYXRpb24pOyBvdGhlcndpc2UgaXQgZmFsbHMgYmFjayB0byBhIGJ5dGUtd2lzZSBzd2FwIHdpdGhcbiAgICAvLyBhIHNpbmdsZSByZXVzZWQgdGVtcCBidWZmZXIuIEVpdGhlciB3YXkgaXQgdG91Y2hlcyBubyBXQVNNIGxpbmVhciBtZW1vcnkuXG4gICAgZnVuY3Rpb24gcmV2ZXJzZUluUGxhY2UodTgsIHNJbiwgYml0cykge1xuICAgICAgICBjb25zdCBuID0gdTguYnl0ZUxlbmd0aCAvIHNJbjtcbiAgICAgICAgY29uc3Qgc2hpZnQgPSAzMiAtIGJpdHM7XG4gICAgICAgIGlmICgoKHNJbiAmIDMpID09PSAwKSAmJiAoKHU4LmJ5dGVPZmZzZXQgJiAzKSA9PT0gMCkpIHtcbiAgICAgICAgICAgIGNvbnN0IGxhbmVzID0gc0luID4+PiAyO1xuICAgICAgICAgICAgY29uc3QgdTMyID0gbmV3IFVpbnQzMkFycmF5KHU4LmJ1ZmZlciwgdTguYnl0ZU9mZnNldCwgdTguYnl0ZUxlbmd0aCA+Pj4gMik7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IHJpID0gcmV2MzIoaSkgPj4+IHNoaWZ0O1xuICAgICAgICAgICAgICAgIGlmIChpIDwgcmkpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGEgPSBpICogbGFuZXM7XG4gICAgICAgICAgICAgICAgICAgIGxldCBiID0gcmkgKiBsYW5lcztcbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgbCA9IDA7IGwgPCBsYW5lczsgbCsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB0ID0gdTMyW2EgKyBsXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHUzMlthICsgbF0gPSB1MzJbYiArIGxdO1xuICAgICAgICAgICAgICAgICAgICAgICAgdTMyW2IgKyBsXSA9IHQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCB0bXAgPSBuZXcgVWludDhBcnJheShzSW4pOyAgIC8vIG9uZSByZXVzZWQgdGVtcCwgbm90IG9uZSBwZXIgc3dhcFxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpKyspIHtcbiAgICAgICAgICAgICAgICBjb25zdCByaSA9IHJldjMyKGkpID4+PiBzaGlmdDtcbiAgICAgICAgICAgICAgICBpZiAoaSA8IHJpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGFvID0gaSAqIHNJbjtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYm8gPSByaSAqIHNJbjtcbiAgICAgICAgICAgICAgICAgICAgdG1wLnNldCh1OC5zdWJhcnJheShhbywgYW8gKyBzSW4pKTtcbiAgICAgICAgICAgICAgICAgICAgdTguY29weVdpdGhpbihhbywgYm8sIGJvICsgc0luKTtcbiAgICAgICAgICAgICAgICAgICAgdTguc2V0KHRtcCwgYm8pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFsbG9jKGxlbmd0aCkge1xuICAgICAgICBjb25zdCB1MzIgPSBuZXcgVWludDMyQXJyYXkobWVtb3J5LmJ1ZmZlciwgMCwgMSk7XG4gICAgICAgIHdoaWxlICh1MzJbMF0gJiAzKSB1MzJbMF0rKzsgIC8vIFJldHVybiBhbHdheXMgYWxpZ25lZCBwb2ludGVyc1xuICAgICAgICBjb25zdCByZXMgPSB1MzJbMF07XG4gICAgICAgIHUzMlswXSArPSBsZW5ndGg7XG4gICAgICAgIGlmICh1MzJbMF0gKyBsZW5ndGggPiBtZW1vcnkuYnVmZmVyLmJ5dGVMZW5ndGgpIHtcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRQYWdlcyA9IG1lbW9yeS5idWZmZXIuYnl0ZUxlbmd0aCAvIDB4MTAwMDA7XG4gICAgICAgICAgICBsZXQgcmVxdWlyZWRQYWdlcyA9IE1hdGguZmxvb3IoKHUzMlswXSArIGxlbmd0aCkgLyAweDEwMDAwKSsxO1xuICAgICAgICAgICAgaWYgKHJlcXVpcmVkUGFnZXM+TUFYTUVNKSByZXF1aXJlZFBhZ2VzPU1BWE1FTTtcbiAgICAgICAgICAgIG1lbW9yeS5ncm93KHJlcXVpcmVkUGFnZXMtY3VycmVudFBhZ2VzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFsbG9jQnVmZmVyKGJ1ZmZlcikge1xuICAgICAgICBjb25zdCBwID0gYWxsb2MoYnVmZmVyLmJ5dGVMZW5ndGgpO1xuICAgICAgICBzZXRCdWZmZXIocCwgYnVmZmVyKTtcbiAgICAgICAgcmV0dXJuIHA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0QnVmZmVyKHBvaW50ZXIsIGxlbmd0aCkge1xuICAgICAgICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkobWVtb3J5LmJ1ZmZlciwgcG9pbnRlciwgbGVuZ3RoKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzZXRCdWZmZXIocG9pbnRlciwgYnVmZmVyKSB7XG4gICAgICAgIGNvbnN0IHU4ID0gbmV3IFVpbnQ4QXJyYXkobWVtb3J5LmJ1ZmZlcik7XG4gICAgICAgIHU4LnNldChuZXcgVWludDhBcnJheShidWZmZXIpLCBwb2ludGVyKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBydW5UYXNrKHRhc2spIHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRlcm1pbmF0aW9uVGltZXIpO1xuICAgICAgICBpZiAodGFza1swXS5jbWQgPT09IFwiSU5JVFwiKSB7XG4gICAgICAgICAgICByZXR1cm4gaW5pdCh0YXNrWzBdKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjdHggPSB7XG4gICAgICAgICAgICB2YXJzOiBbXSxcbiAgICAgICAgICAgIG91dDogW11cbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgdTMyYSA9IG5ldyBVaW50MzJBcnJheShtZW1vcnkuYnVmZmVyLCAwLCAxKTtcbiAgICAgICAgY29uc3Qgb2xkQWxsb2MgPSB1MzJhWzBdO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8dGFzay5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgc3dpdGNoICh0YXNrW2ldLmNtZCkge1xuICAgICAgICAgICAgY2FzZSBcIlJFVkVSU0VcIjoge1xuICAgICAgICAgICAgICAgIC8vIFJldmVyc2UgdGhlIHRyYW5zZmVycmVkIGJ1ZmZlciBpbiBwbGFjZSBhbmQgaGFuZCBpdCBzdHJhaWdodFxuICAgICAgICAgICAgICAgIC8vIGJhY2suIE5vIFNoYXJlZEFycmF5QnVmZmVyIGFuZCBubyBXQVNNIG1lbW9yeTogdGhlIGJ1ZmZlciBpc1xuICAgICAgICAgICAgICAgIC8vIHRyYW5zZmVycmVkIGluIGFuZCBvdXQgKHplcm8gY29weSkgYW5kIHJldmVyc2VkIHdoZXJlIGl0IGxpZXMuXG4gICAgICAgICAgICAgICAgY29uc3QgdCA9IHRhc2tbaV07XG4gICAgICAgICAgICAgICAgcmV2ZXJzZUluUGxhY2UodC5zcmMsIHQuc0luLCB0LmJpdHMpO1xuICAgICAgICAgICAgICAgIGN0eC5vdXRbMF0gPSB0LnNyYztcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgXCJBTExPQ1NFVFwiOlxuICAgICAgICAgICAgICAgIGN0eC52YXJzW3Rhc2tbaV0udmFyXSA9IGFsbG9jQnVmZmVyKHRhc2tbaV0uYnVmZik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiQUxMT0NcIjpcbiAgICAgICAgICAgICAgICBjdHgudmFyc1t0YXNrW2ldLnZhcl0gPSBhbGxvYyh0YXNrW2ldLmxlbik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiU0VUXCI6XG4gICAgICAgICAgICAgICAgc2V0QnVmZmVyKGN0eC52YXJzW3Rhc2tbaV0udmFyXSwgdGFza1tpXS5idWZmKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJDQUxMXCI6IHtcbiAgICAgICAgICAgICAgICBjb25zdCBwYXJhbXMgPSBbXTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8dGFza1tpXS5wYXJhbXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcCA9IHRhc2tbaV0ucGFyYW1zW2pdO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHAudmFyICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMucHVzaChjdHgudmFyc1twLnZhcl0gKyAocC5vZmZzZXQgfHwgMCkpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiBwLnZhbCAhPSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMucHVzaChwLnZhbCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBmbmFtZSA9IHRhc2tbaV0uZm5OYW1lO1xuICAgICAgICAgICAgICAgICAgICBsZXQgZm4gPSBiYXRjaEZucyA/IGJhdGNoRm5zW2ZuYW1lXSA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFmbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZm4gPSBpbnN0YW5jZS5leHBvcnRzW2ZuYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGdyYWNlZnVsIGZhbGxiYWNrOiBcIi4uLkJhdGNoW05vR2xzfE5vR2x2XVwiIC0+IHBsYWluXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpbi1tb2R1bGUgdmFyaWFudCB3aGVuIHRoZSBiYXRjaCBtb2R1bGUgaXMgdW5hdmFpbGFibGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIChzYW1lIDUtYXJnIHNpZ25hdHVyZSlcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZm4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBiYXNlID0gZm5hbWUucmVwbGFjZSgvQmF0Y2goTm9HbHN8Tm9HbHYpPyQvLCBcIlwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbiA9IGluc3RhbmNlLmV4cG9ydHNbYmFzZV07XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZm4oLi4ucGFyYW1zKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFwiR0VUXCI6XG4gICAgICAgICAgICAgICAgY3R4Lm91dFt0YXNrW2ldLm91dF0gPSBnZXRCdWZmZXIoY3R4LnZhcnNbdGFza1tpXS52YXJdLCB0YXNrW2ldLmxlbikuc2xpY2UoKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBjbWRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdTMyYiA9IG5ldyBVaW50MzJBcnJheShtZW1vcnkuYnVmZmVyLCAwLCAxKTtcbiAgICAgICAgdTMyYlswXSA9IG9sZEFsbG9jO1xuXG4gICAgICAgIHJldHVybiBjdHgub3V0O1xuICAgIH1cblxuICAgIHJldHVybiBydW5UYXNrO1xufVxuXG4vKlxuICAgIENvcHlyaWdodCAyMDE5IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygd2FzbXNuYXJrIChXZWIgQXNzZW1ibHkgemtTbmFyayBQcm92ZXIpLlxuXG4gICAgd2FzbXNuYXJrIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgd2FzbXNuYXJrIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHdhc21zbmFyay4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbi8vIGNvbnN0IE1FTV9TSVpFID0gMTAwMDsgIC8vIE1lbW9yeSBzaXplIGluIDY0SyBQYWtlcyAoNTEyTWIpXG5jb25zdCBNRU1fU0laRSA9IDI1OyAgLy8gTWVtb3J5IHNpemUgaW4gNjRLIFBha2VzICgxNjAwS2IpXG5cbi8vIFJvYnVzdCBOb2RlIGRldGVjdGlvbiB0aGF0IG5ldmVyIHRocm93cyAodW5saWtlIGB0cnVlYCwgd2hpY2ggaXMgYVxuLy8gd2VicGFjay1pc20gYW5kIGlzIHVuZGVmaW5lZCB1bmRlciBWaXRlL2VzYnVpbGQvU0VTKS5cbmNvbnN0IGlzTm9kZSA9IHR5cGVvZiBwcm9jZXNzICE9PSBcInVuZGVmaW5lZFwiICYmIHByb2Nlc3MudmVyc2lvbnMgIT0gbnVsbCAmJiBwcm9jZXNzLnZlcnNpb25zLm5vZGUgIT0gbnVsbDtcblxuY2xhc3MgRGVmZXJyZWQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KT0+IHtcbiAgICAgICAgICAgIHRoaXMucmVqZWN0ID0gcmVqZWN0O1xuICAgICAgICAgICAgdGhpcy5yZXNvbHZlID0gcmVzb2x2ZTtcbiAgICAgICAgfSk7XG4gICAgfVxufVxuXG4vLyBXb3JrZXJTbG90IGhvbGRzIHRoZSBuYXRpdmUgV29ya2VyIGFuZCBhbGwgcGVyLXdvcmtlciBzdGF0ZS5cbi8vIEVhY2ggY2FsbCB0byBzdGFydFdvcmtlcigpIGNyZWF0ZXMgYSBmcmVzaCBXb3JrZXJTbG90IGluc3RhbmNlLlxuLy8gTWVzc2FnZSBoYW5kbGVycyBjbG9zZSBvdmVyIHRoZSBzbG90IHJlZmVyZW5jZSBzbyB0aGF0IHN0YWxlIG1lc3NhZ2VzXG4vLyBmcm9tIGEgcmVwbGFjZWQgd29ya2VyIGFyZSBkZXRlY3RlZCBieSBhIHNpbXBsZSBpZGVudGl0eSBjaGVja1xuLy8gKHRtLnBvb2xbaV0gIT09IHNsb3QpLlxuY2xhc3MgV29ya2VyU2xvdCB7XG4gICAgY29uc3RydWN0b3Iod29ya2VyKSB7XG4gICAgICAgIHRoaXMud29ya2VyICAgICAgPSB3b3JrZXI7IC8vIG5hdGl2ZSBXb3JrZXIgdGhyZWFkXG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pbml0aWFsaXppbmc9IGZhbHNlO1xuICAgICAgICB0aGlzLndvcmtpbmcgICAgID0gZmFsc2U7XG4gICAgICAgIHRoaXMucGVuZGluZ0RlZmVycmVkID0gbnVsbDtcbiAgICAgICAgdGhpcy5vbk1zZyAgID0gbnVsbDsgLy8gc3RvcmVkIHNvIHJlbW92ZUV2ZW50TGlzdGVuZXIgY2FuIGJlIGNhbGxlZCBvbiB0ZXJtaW5hdGlvblxuICAgICAgICB0aGlzLm9uRXJyb3IgPSBudWxsO1xuICAgIH1cbn1cblxuLy8gQ29tcHV0ZWQgbGF6aWx5IG9uIGZpcnN0IHdvcmtlciBjcmVhdGlvbiwgTk9UIGF0IG1vZHVsZSBsb2FkOiBhIFNFU1xuLy8gaGFyZGVuZWQgcmVhbG0gKHdoaWNoIHJ1bnMgc2luZ2xlLXRocmVhZGVkKSBoYXMgbm8gQmxvYi9idG9hL1VSTC5jcmVhdGVPYmplY3RVUkwsIGFuZFxuLy8gdG91Y2hpbmcgdGhlbSBhdCBpbXBvcnQgdGltZSB3b3VsZCB0aHJvdyBiZWZvcmUgYSBjdXJ2ZSBjb3VsZCBldmVuIGJlIGJ1aWx0LlxubGV0IHdvcmtlclNvdXJjZTtcbmZ1bmN0aW9uIGdldFdvcmtlclNvdXJjZSgpIHtcbiAgICBpZiAod29ya2VyU291cmNlICE9PSB1bmRlZmluZWQpIHJldHVybiB3b3JrZXJTb3VyY2U7XG4gICAgY29uc3QgdGhyZWFkU3RyID0gYCgke1wiZnVuY3Rpb24gdGhyZWFkKHNlbGYpIHtcXG4gICAgY29uc3QgTUFYTUVNID0gMzI3Njc7XFxuICAgIGxldCBpbnN0YW5jZTtcXG4gICAgbGV0IG1lbW9yeTtcXG4gICAgbGV0IGJhdGNoRm5zID0gbnVsbDsgICAvLyBiYXRjaC1hZmZpbmUgTVNNIGVudHJ5IHBvaW50cyAocGVyLWdyb3VwIHdyYXBwZXJzKVxcbiAgICBsZXQgdGVybWluYXRpb25UaW1lb3V0ID0gMTUwMDsgLy8gbWlsbGlzZWNvbmRzXFxuICAgIGxldCB0ZXJtaW5hdGlvblRpbWVyO1xcblxcbiAgICBpZiAoc2VsZikge1xcbiAgICAgICAgc2VsZi5vbm1lc3NhZ2UgPSBmdW5jdGlvbihlKSB7XFxuICAgICAgICAgICAgbGV0IGRhdGE7XFxuICAgICAgICAgICAgaWYgKGUuZGF0YSkge1xcbiAgICAgICAgICAgICAgICBkYXRhID0gZS5kYXRhO1xcbiAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgIGRhdGEgPSBlO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICB0cnkge1xcbiAgICAgICAgICAgICAgICBpZiAoZGF0YVswXS5jbWQgPT09IFxcXCJJTklUXFxcIikge1xcbiAgICAgICAgICAgICAgICAgICAgaW5pdChkYXRhWzBdKS50aGVuKGZ1bmN0aW9uKCkge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYucG9zdE1lc3NhZ2Uoe3N0YXR1czogXFxcImluaXRpYWxpemVkXFxcIn0pO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFN0YXJ0IGlkbGUgdGltZXIgb25seSBhZnRlciBpbml0IGNvbXBsZXRlcyBzbyBpdCBuZXZlclxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZpcmVzIGR1cmluZyBhc3luYyBXQVNNIGNvbXBpbGF0aW9uLlxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjaGVkdWxlVGVybWluYXRpb24oKTtcXG4gICAgICAgICAgICAgICAgICAgIH0pO1xcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOyAvLyBza2lwIHRoZSBzY2hlZHVsZVRlcm1pbmF0aW9uKCkgY2FsbCBhdCB0aGUgYm90dG9tXFxuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZGF0YVswXS5jbWQgPT09IFxcXCJURVJNSU5BVEVcXFwiKSB7XFxuICAgICAgICAgICAgICAgICAgICB0ZXJtaW5hdGUoKTtcXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgICAgIGxldCB0ZXJtaW5hdGVBZnRlclRhc2sgPSBmYWxzZTtcXG4gICAgICAgICAgICAgICAgICAgIGlmIChkYXRhW2RhdGEubGVuZ3RoLTFdLmNtZCA9PT0gXFxcIlRFUk1JTkFURVxcXCIpIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXJtaW5hdGVBZnRlclRhc2sgPSB0cnVlO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEucG9wKCk7XFxuICAgICAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgICAgICAgICBjb25zdCByZXMgPSBydW5UYXNrKGRhdGEpO1xcbiAgICAgICAgICAgICAgICAgICAgbGV0IHRyYW5zZmVycyA9IFtdO1xcbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpPHJlcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXNbaV0gaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZmVycy5wdXNoKHJlc1tpXS5idWZmZXIpO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgICAgIHNlbGYucG9zdE1lc3NhZ2UocmVzLCB0cmFuc2ZlcnMpO1xcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRlcm1pbmF0ZUFmdGVyVGFzaykge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIHRlcm1pbmF0ZSgpO1xcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XFxuICAgICAgICAgICAgICAgIC8vIENhdGNoIGFueSBlcnJvciBhbmQgc2VuZCBpdCBiYWNrIHRvIG1haW4gdGhyZWFkXFxuICAgICAgICAgICAgICAgIHNlbGYucG9zdE1lc3NhZ2Uoe2Vycm9yOiBlcnIubWVzc2FnZX0pO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgICAgICBzY2hlZHVsZVRlcm1pbmF0aW9uKCk7XFxuICAgICAgICB9O1xcbiAgICB9XFxuXFxuICAgIGFzeW5jIGZ1bmN0aW9uIGluaXQoZGF0YSkge1xcbiAgICAgICAgbGV0IHdhc21Nb2R1bGU7XFxuICAgICAgICBpZiAoZGF0YS5jb2RlIGluc3RhbmNlb2YgV2ViQXNzZW1ibHkuTW9kdWxlKSB7XFxuICAgICAgICAgICAgd2FzbU1vZHVsZSA9IGRhdGEuY29kZTtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgY29uc3QgY29kZSA9IG5ldyBVaW50OEFycmF5KGRhdGEuY29kZSk7XFxuICAgICAgICAgICAgd2FzbU1vZHVsZSA9IGF3YWl0IFdlYkFzc2VtYmx5LmNvbXBpbGUoY29kZSk7XFxuICAgICAgICB9XFxuICAgICAgICBtZW1vcnkgPSBuZXcgV2ViQXNzZW1ibHkuTWVtb3J5KHtpbml0aWFsOmRhdGEuaW5pdCwgbWF4aW11bTogTUFYTUVNfSk7XFxuXFxuICAgICAgICBpbnN0YW5jZSA9IGF3YWl0IFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKHdhc21Nb2R1bGUsIHtcXG4gICAgICAgICAgICBlbnY6IHtcXG4gICAgICAgICAgICAgICAgXFxcIm1lbW9yeVxcXCI6IG1lbW9yeVxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH0pO1xcblxcbiAgICAgICAgLy8gT3B0aW9uYWwgYmF0Y2gtYWZmaW5lIE1TTSBoZWxwZXIgbW9kdWxlLiBJdCBpcyBjdXJ2ZS1pbmRlcGVuZGVudDpcXG4gICAgICAgIC8vIGl0IGltcG9ydHMgdGhlIGJhc2UtZmllbGQvZ3JvdXAgb3BzIGZyb20gdGhlIG1haW4gaW5zdGFuY2UgYW5kIHdvcmtzXFxuICAgICAgICAvLyBvbiB0aGUgc2FtZSBtZW1vcnksIHNvIG9uZSBiaW5hcnkgc2VydmVzIEcxIChmMW0vZzFtKSBhbmQsIG92ZXIgdGhlXFxuICAgICAgICAvLyBxdWFkcmF0aWMgZXh0ZW5zaW9uLCBHMiAoZjJtL2cybSkuIEluc3RhbnRpYXRlZCBvbmNlIHBlciBncm91cC5cXG4gICAgICAgIGlmIChkYXRhLmJhdGNoQ29kZSkge1xcbiAgICAgICAgICAgIGxldCBiYXRjaE1vZHVsZTtcXG4gICAgICAgICAgICBpZiAoZGF0YS5iYXRjaENvZGUgaW5zdGFuY2VvZiBXZWJBc3NlbWJseS5Nb2R1bGUpIHtcXG4gICAgICAgICAgICAgICAgYmF0Y2hNb2R1bGUgPSBkYXRhLmJhdGNoQ29kZTtcXG4gICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICBiYXRjaE1vZHVsZSA9IGF3YWl0IFdlYkFzc2VtYmx5LmNvbXBpbGUobmV3IFVpbnQ4QXJyYXkoZGF0YS5iYXRjaENvZGUpKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICAgICAgY29uc3QgZXggPSBpbnN0YW5jZS5leHBvcnRzO1xcbiAgICAgICAgICAgIGNvbnN0IG1rQmF0Y2ggPSBhc3luYyAoZiwgZywgY29uaikgPT4gKGF3YWl0IFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKGJhdGNoTW9kdWxlLCB7XFxuICAgICAgICAgICAgICAgIGVudjogeyBcXFwibWVtb3J5XFxcIjogbWVtb3J5IH0sXFxuICAgICAgICAgICAgICAgIGN1cnZlOiB7XFxuICAgICAgICAgICAgICAgICAgICBmX211bDogZXhbZiArIFxcXCJfbXVsXFxcIl0sIGZfc3F1YXJlOiBleFtmICsgXFxcIl9zcXVhcmVcXFwiXSwgZl9hZGQ6IGV4W2YgKyBcXFwiX2FkZFxcXCJdLFxcbiAgICAgICAgICAgICAgICAgICAgZl9zdWI6IGV4W2YgKyBcXFwiX3N1YlxcXCJdLCBmX25lZzogZXhbZiArIFxcXCJfbmVnXFxcIl0sIGZfaW52ZXJzZTogZXhbZiArIFxcXCJfaW52ZXJzZVxcXCJdLFxcbiAgICAgICAgICAgICAgICAgICAgZl9pc1plcm86IGV4W2YgKyBcXFwiX2lzWmVyb1xcXCJdLCBmX2Nvbmo6IGV4W2NvbmpdLFxcbiAgICAgICAgICAgICAgICAgICAgZ19hZGQ6IGV4W2cgKyBcXFwiX2FkZFxcXCJdLCBnX2FkZE1peGVkOiBleFtnICsgXFxcIl9hZGRNaXhlZFxcXCJdLFxcbiAgICAgICAgICAgICAgICAgICAgZ19kb3VibGU6IGV4W2cgKyBcXFwiX2RvdWJsZVxcXCJdLCBnX3plcm86IGV4W2cgKyBcXFwiX3plcm9cXFwiXSwgZ19pc1plcm86IGV4W2cgKyBcXFwiX2lzWmVyb1xcXCJdLFxcbiAgICAgICAgICAgICAgICB9LFxcbiAgICAgICAgICAgIH0pKS5leHBvcnRzO1xcbiAgICAgICAgICAgIGNvbnN0IG44ZiA9IGRhdGEubjhmO1xcbiAgICAgICAgICAgIGJhdGNoRm5zID0ge307XFxuICAgICAgICAgICAgaWYgKGV4LmYxbV9tdWwgJiYgZXguZzFtX2FkZE1peGVkKSB7XFxuICAgICAgICAgICAgICAgIC8vIGZfY29uaiBpcyBvbmx5IHVzZWQgYnkgdGhlIEcyIEdMUyBwYXRoOyB3aXJlIGEgaGFybWxlc3MgY29weSBmb3IgRzFcXG4gICAgICAgICAgICAgICAgY29uc3QgYiA9IGF3YWl0IG1rQmF0Y2goXFxcImYxbVxcXCIsIFxcXCJnMW1cXFwiLCBcXFwiZjFtX2NvcHlcXFwiKTtcXG4gICAgICAgICAgICAgICAgLy8gR0xWIHBhdGggKGJuMjU0IEcxIGVuZG9tb3JwaGlzbSkgd2hlbiB0aGUgY3VydmUgYWR2ZXJ0aXNlcyBpdDtcXG4gICAgICAgICAgICAgICAgLy8gdGhlIHdhc20gZmFsbHMgYmFjayBpbnRlcm5hbGx5IGZvciB1bmV4cGVjdGVkIHNpemVzLlxcbiAgICAgICAgICAgICAgICBjb25zdCB1c2VHbHYgPSBkYXRhLmdsdiAmJiBiLm11bHRpZXhwQWZmaW5lR0xWO1xcbiAgICAgICAgICAgICAgICBjb25zdCBmbiA9IHVzZUdsdiA/IGIubXVsdGlleHBBZmZpbmVHTFYgOiBiLm11bHRpZXhwQWZmaW5lO1xcbiAgICAgICAgICAgICAgICBiYXRjaEZuc1tcXFwiZzFtX211bHRpZXhwQWZmaW5lQmF0Y2hcXFwiXSA9IChwQiwgcFMsIHNTLCBuLCBwcikgPT4gZm4ocEIsIHBTLCBzUywgbiwgcHIsIG44Zik7XFxuICAgICAgICAgICAgICAgIC8vIE5vR2x2IHZhcmlhbnQsIHNlbGVjdGFibGUgcGVyIGNhbGwgKHtnbHY6IFxcXCJkaXNhYmxlZFxcXCJ9IG9wdGlvbilcXG4gICAgICAgICAgICAgICAgYmF0Y2hGbnNbXFxcImcxbV9tdWx0aWV4cEFmZmluZUJhdGNoTm9HbHZcXFwiXSA9IChwQiwgcFMsIHNTLCBuLCBwcikgPT4gYi5tdWx0aWV4cEFmZmluZShwQiwgcFMsIHNTLCBuLCBwciwgbjhmKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICAgICAgaWYgKGV4LmYybV9tdWwgJiYgZXguZzJtX2FkZE1peGVkKSB7XFxuICAgICAgICAgICAgICAgIGNvbnN0IGIgPSBhd2FpdCBta0JhdGNoKFxcXCJmMm1cXFwiLCBcXFwiZzJtXFxcIiwgXFxcImYybV9jb25qdWdhdGVcXFwiKTtcXG4gICAgICAgICAgICAgICAgLy8gR0xTIChibjI1NCBHMiBlbmRvbW9ycGhpc20pIHdoZW4gdGhlIGN1cnZlIGFkdmVydGlzZXMgaXQ7IHRoZVxcbiAgICAgICAgICAgICAgICAvLyB3YXNtIGdhdGVzIGludGVybmFsbHkgb24gY2h1bmsgc2l6ZSBhbmQgZmFsbHMgYmFjayB0byBiYXRjaC5cXG4gICAgICAgICAgICAgICAgLy8gVGhlIE5vR2xzIHZhcmlhbnQgaXMgc2VsZWN0YWJsZSBwZXIgY2FsbCAoe2dsczpmYWxzZX0gb3B0aW9uKS5cXG4gICAgICAgICAgICAgICAgY29uc3QgdXNlR2xzID0gZGF0YS5nbHYgJiYgYi5tdWx0aWV4cEFmZmluZUdMUztcXG4gICAgICAgICAgICAgICAgY29uc3QgZm4yID0gdXNlR2xzID8gYi5tdWx0aWV4cEFmZmluZUdMUyA6IGIubXVsdGlleHBBZmZpbmU7XFxuICAgICAgICAgICAgICAgIGJhdGNoRm5zW1xcXCJnMm1fbXVsdGlleHBBZmZpbmVCYXRjaFxcXCJdID0gKHBCLCBwUywgc1MsIG4sIHByKSA9PiBmbjIocEIsIHBTLCBzUywgbiwgcHIsIG44ZiAqIDIpO1xcbiAgICAgICAgICAgICAgICBiYXRjaEZuc1tcXFwiZzJtX211bHRpZXhwQWZmaW5lQmF0Y2hOb0dsc1xcXCJdID0gKHBCLCBwUywgc1MsIG4sIHByKSA9PiBiLm11bHRpZXhwQWZmaW5lKHBCLCBwUywgc1MsIG4sIHByLCBuOGYgKiAyKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICBpZiAoZGF0YS50ZXJtaW5hdGlvblRpbWVvdXQpIHtcXG4gICAgICAgICAgICB0ZXJtaW5hdGlvblRpbWVvdXQgPSBkYXRhLnRlcm1pbmF0aW9uVGltZW91dDtcXG4gICAgICAgIH1cXG4gICAgfVxcblxcblxcblxcbiAgICAvLyBSZXZlcnNlIHRoZSBsb3cgYGJpdHNgIG9mIGEgMzItYml0IGludGVnZXIgKE8oMSkgYml0LXR3aWRkbGUpLlxcbiAgICBmdW5jdGlvbiByZXYzMih4KSB7XFxuICAgICAgICB4ID0gKCh4ICYgMHg1NTU1NTU1NSkgPDwgMSkgfCAoKHggPj4+IDEpICYgMHg1NTU1NTU1NSk7XFxuICAgICAgICB4ID0gKCh4ICYgMHgzMzMzMzMzMykgPDwgMikgfCAoKHggPj4+IDIpICYgMHgzMzMzMzMzMyk7XFxuICAgICAgICB4ID0gKCh4ICYgMHgwZjBmMGYwZikgPDwgNCkgfCAoKHggPj4+IDQpICYgMHgwZjBmMGYwZik7XFxuICAgICAgICB4ID0gKCh4ICYgMHgwMGZmMDBmZikgPDwgOCkgfCAoKHggPj4+IDgpICYgMHgwMGZmMDBmZik7XFxuICAgICAgICB4ID0gKHggPDwgMTYpIHwgKHggPj4+IDE2KTtcXG4gICAgICAgIHJldHVybiB4ID4+PiAwO1xcbiAgICB9XFxuXFxuICAgIC8vIEluLXBsYWNlIGJpdC1yZXZlcnNhbCBwZXJtdXRhdGlvbiBvZiBmaXhlZC1zaXplIChzSW4tYnl0ZSkgZWxlbWVudHMuXFxuICAgIC8vIFdvcmtzIGZvciBhbnkgZWxlbWVudCBzaXplLCBsaWtlIHRoZSBvbGQgcHVyZS1KUyBidWZmUmV2ZXJzZUJpdHMuIFdoZW5cXG4gICAgLy8gdGhlIGVsZW1lbnRzIGFyZSA0LWJ5dGUgYWxpZ25lZCBpdCBzd2FwcyBVaW50MzJBcnJheSBsYW5lcyAobm8gQmlnSW50XFxuICAgIC8vIGJveGluZywgbm8gYWxsb2NhdGlvbik7IG90aGVyd2lzZSBpdCBmYWxscyBiYWNrIHRvIGEgYnl0ZS13aXNlIHN3YXAgd2l0aFxcbiAgICAvLyBhIHNpbmdsZSByZXVzZWQgdGVtcCBidWZmZXIuIEVpdGhlciB3YXkgaXQgdG91Y2hlcyBubyBXQVNNIGxpbmVhciBtZW1vcnkuXFxuICAgIGZ1bmN0aW9uIHJldmVyc2VJblBsYWNlKHU4LCBzSW4sIGJpdHMpIHtcXG4gICAgICAgIGNvbnN0IG4gPSB1OC5ieXRlTGVuZ3RoIC8gc0luO1xcbiAgICAgICAgY29uc3Qgc2hpZnQgPSAzMiAtIGJpdHM7XFxuICAgICAgICBpZiAoKChzSW4gJiAzKSA9PT0gMCkgJiYgKCh1OC5ieXRlT2Zmc2V0ICYgMykgPT09IDApKSB7XFxuICAgICAgICAgICAgY29uc3QgbGFuZXMgPSBzSW4gPj4+IDI7XFxuICAgICAgICAgICAgY29uc3QgdTMyID0gbmV3IFVpbnQzMkFycmF5KHU4LmJ1ZmZlciwgdTguYnl0ZU9mZnNldCwgdTguYnl0ZUxlbmd0aCA+Pj4gMik7XFxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpKyspIHtcXG4gICAgICAgICAgICAgICAgY29uc3QgcmkgPSByZXYzMihpKSA+Pj4gc2hpZnQ7XFxuICAgICAgICAgICAgICAgIGlmIChpIDwgcmkpIHtcXG4gICAgICAgICAgICAgICAgICAgIGxldCBhID0gaSAqIGxhbmVzO1xcbiAgICAgICAgICAgICAgICAgICAgbGV0IGIgPSByaSAqIGxhbmVzO1xcbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgbCA9IDA7IGwgPCBsYW5lczsgbCsrKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdCA9IHUzMlthICsgbF07XFxuICAgICAgICAgICAgICAgICAgICAgICAgdTMyW2EgKyBsXSA9IHUzMltiICsgbF07XFxuICAgICAgICAgICAgICAgICAgICAgICAgdTMyW2IgKyBsXSA9IHQ7XFxuICAgICAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICB9XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIGNvbnN0IHRtcCA9IG5ldyBVaW50OEFycmF5KHNJbik7ICAgLy8gb25lIHJldXNlZCB0ZW1wLCBub3Qgb25lIHBlciBzd2FwXFxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpKyspIHtcXG4gICAgICAgICAgICAgICAgY29uc3QgcmkgPSByZXYzMihpKSA+Pj4gc2hpZnQ7XFxuICAgICAgICAgICAgICAgIGlmIChpIDwgcmkpIHtcXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGFvID0gaSAqIHNJbjtcXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGJvID0gcmkgKiBzSW47XFxuICAgICAgICAgICAgICAgICAgICB0bXAuc2V0KHU4LnN1YmFycmF5KGFvLCBhbyArIHNJbikpO1xcbiAgICAgICAgICAgICAgICAgICAgdTguY29weVdpdGhpbihhbywgYm8sIGJvICsgc0luKTtcXG4gICAgICAgICAgICAgICAgICAgIHU4LnNldCh0bXAsIGJvKTtcXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG4gICAgfVxcblxcbiAgICBmdW5jdGlvbiBhbGxvYyhsZW5ndGgpIHtcXG4gICAgICAgIGNvbnN0IHUzMiA9IG5ldyBVaW50MzJBcnJheShtZW1vcnkuYnVmZmVyLCAwLCAxKTtcXG4gICAgICAgIHdoaWxlICh1MzJbMF0gJiAzKSB1MzJbMF0rKzsgIC8vIFJldHVybiBhbHdheXMgYWxpZ25lZCBwb2ludGVyc1xcbiAgICAgICAgY29uc3QgcmVzID0gdTMyWzBdO1xcbiAgICAgICAgdTMyWzBdICs9IGxlbmd0aDtcXG4gICAgICAgIGlmICh1MzJbMF0gKyBsZW5ndGggPiBtZW1vcnkuYnVmZmVyLmJ5dGVMZW5ndGgpIHtcXG4gICAgICAgICAgICBjb25zdCBjdXJyZW50UGFnZXMgPSBtZW1vcnkuYnVmZmVyLmJ5dGVMZW5ndGggLyAweDEwMDAwO1xcbiAgICAgICAgICAgIGxldCByZXF1aXJlZFBhZ2VzID0gTWF0aC5mbG9vcigodTMyWzBdICsgbGVuZ3RoKSAvIDB4MTAwMDApKzE7XFxuICAgICAgICAgICAgaWYgKHJlcXVpcmVkUGFnZXM+TUFYTUVNKSByZXF1aXJlZFBhZ2VzPU1BWE1FTTtcXG4gICAgICAgICAgICBtZW1vcnkuZ3JvdyhyZXF1aXJlZFBhZ2VzLWN1cnJlbnRQYWdlcyk7XFxuICAgICAgICB9XFxuICAgICAgICByZXR1cm4gcmVzO1xcbiAgICB9XFxuXFxuICAgIGZ1bmN0aW9uIGFsbG9jQnVmZmVyKGJ1ZmZlcikge1xcbiAgICAgICAgY29uc3QgcCA9IGFsbG9jKGJ1ZmZlci5ieXRlTGVuZ3RoKTtcXG4gICAgICAgIHNldEJ1ZmZlcihwLCBidWZmZXIpO1xcbiAgICAgICAgcmV0dXJuIHA7XFxuICAgIH1cXG5cXG4gICAgZnVuY3Rpb24gZ2V0QnVmZmVyKHBvaW50ZXIsIGxlbmd0aCkge1xcbiAgICAgICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KG1lbW9yeS5idWZmZXIsIHBvaW50ZXIsIGxlbmd0aCk7XFxuICAgIH1cXG5cXG4gICAgZnVuY3Rpb24gc2V0QnVmZmVyKHBvaW50ZXIsIGJ1ZmZlcikge1xcbiAgICAgICAgY29uc3QgdTggPSBuZXcgVWludDhBcnJheShtZW1vcnkuYnVmZmVyKTtcXG4gICAgICAgIHU4LnNldChuZXcgVWludDhBcnJheShidWZmZXIpLCBwb2ludGVyKTtcXG4gICAgfVxcblxcbiAgICBmdW5jdGlvbiBydW5UYXNrKHRhc2spIHtcXG4gICAgICAgIGNsZWFyVGltZW91dCh0ZXJtaW5hdGlvblRpbWVyKTtcXG4gICAgICAgIGlmICh0YXNrWzBdLmNtZCA9PT0gXFxcIklOSVRcXFwiKSB7XFxuICAgICAgICAgICAgcmV0dXJuIGluaXQodGFza1swXSk7XFxuICAgICAgICB9XFxuICAgICAgICBjb25zdCBjdHggPSB7XFxuICAgICAgICAgICAgdmFyczogW10sXFxuICAgICAgICAgICAgb3V0OiBbXVxcbiAgICAgICAgfTtcXG4gICAgICAgIGNvbnN0IHUzMmEgPSBuZXcgVWludDMyQXJyYXkobWVtb3J5LmJ1ZmZlciwgMCwgMSk7XFxuICAgICAgICBjb25zdCBvbGRBbGxvYyA9IHUzMmFbMF07XFxuICAgICAgICBmb3IgKGxldCBpPTA7IGk8dGFzay5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHN3aXRjaCAodGFza1tpXS5jbWQpIHtcXG4gICAgICAgICAgICBjYXNlIFxcXCJSRVZFUlNFXFxcIjoge1xcbiAgICAgICAgICAgICAgICAvLyBSZXZlcnNlIHRoZSB0cmFuc2ZlcnJlZCBidWZmZXIgaW4gcGxhY2UgYW5kIGhhbmQgaXQgc3RyYWlnaHRcXG4gICAgICAgICAgICAgICAgLy8gYmFjay4gTm8gU2hhcmVkQXJyYXlCdWZmZXIgYW5kIG5vIFdBU00gbWVtb3J5OiB0aGUgYnVmZmVyIGlzXFxuICAgICAgICAgICAgICAgIC8vIHRyYW5zZmVycmVkIGluIGFuZCBvdXQgKHplcm8gY29weSkgYW5kIHJldmVyc2VkIHdoZXJlIGl0IGxpZXMuXFxuICAgICAgICAgICAgICAgIGNvbnN0IHQgPSB0YXNrW2ldO1xcbiAgICAgICAgICAgICAgICByZXZlcnNlSW5QbGFjZSh0LnNyYywgdC5zSW4sIHQuYml0cyk7XFxuICAgICAgICAgICAgICAgIGN0eC5vdXRbMF0gPSB0LnNyYztcXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIGNhc2UgXFxcIkFMTE9DU0VUXFxcIjpcXG4gICAgICAgICAgICAgICAgY3R4LnZhcnNbdGFza1tpXS52YXJdID0gYWxsb2NCdWZmZXIodGFza1tpXS5idWZmKTtcXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgY2FzZSBcXFwiQUxMT0NcXFwiOlxcbiAgICAgICAgICAgICAgICBjdHgudmFyc1t0YXNrW2ldLnZhcl0gPSBhbGxvYyh0YXNrW2ldLmxlbik7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgIGNhc2UgXFxcIlNFVFxcXCI6XFxuICAgICAgICAgICAgICAgIHNldEJ1ZmZlcihjdHgudmFyc1t0YXNrW2ldLnZhcl0sIHRhc2tbaV0uYnVmZik7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgIGNhc2UgXFxcIkNBTExcXFwiOiB7XFxuICAgICAgICAgICAgICAgIGNvbnN0IHBhcmFtcyA9IFtdO1xcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8dGFza1tpXS5wYXJhbXMubGVuZ3RoOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHAgPSB0YXNrW2ldLnBhcmFtc1tqXTtcXG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcC52YXIgIT09IFxcXCJ1bmRlZmluZWRcXFwiKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLnB1c2goY3R4LnZhcnNbcC52YXJdICsgKHAub2Zmc2V0IHx8IDApKTtcXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHAudmFsICE9IFxcXCJ1bmRlZmluZWRcXFwiKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLnB1c2gocC52YWwpO1xcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgICAgIHtcXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZuYW1lID0gdGFza1tpXS5mbk5hbWU7XFxuICAgICAgICAgICAgICAgICAgICBsZXQgZm4gPSBiYXRjaEZucyA/IGJhdGNoRm5zW2ZuYW1lXSA6IHVuZGVmaW5lZDtcXG4gICAgICAgICAgICAgICAgICAgIGlmICghZm4pIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICBmbiA9IGluc3RhbmNlLmV4cG9ydHNbZm5hbWVdO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGdyYWNlZnVsIGZhbGxiYWNrOiBcXFwiLi4uQmF0Y2hbTm9HbHN8Tm9HbHZdXFxcIiAtPiBwbGFpblxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGluLW1vZHVsZSB2YXJpYW50IHdoZW4gdGhlIGJhdGNoIG1vZHVsZSBpcyB1bmF2YWlsYWJsZVxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIChzYW1lIDUtYXJnIHNpZ25hdHVyZSlcXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWZuKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGJhc2UgPSBmbmFtZS5yZXBsYWNlKC9CYXRjaChOb0dsc3xOb0dsdik/JC8sIFxcXCJcXFwiKTtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm4gPSBpbnN0YW5jZS5leHBvcnRzW2Jhc2VdO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgICAgIGZuKC4uLnBhcmFtcyk7XFxuICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIGNhc2UgXFxcIkdFVFxcXCI6XFxuICAgICAgICAgICAgICAgIGN0eC5vdXRbdGFza1tpXS5vdXRdID0gZ2V0QnVmZmVyKGN0eC52YXJzW3Rhc2tbaV0udmFyXSwgdGFza1tpXS5sZW4pLnNsaWNlKCk7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgIGRlZmF1bHQ6XFxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcXFwiSW52YWxpZCBjbWRcXFwiKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgICAgICBjb25zdCB1MzJiID0gbmV3IFVpbnQzMkFycmF5KG1lbW9yeS5idWZmZXIsIDAsIDEpO1xcbiAgICAgICAgdTMyYlswXSA9IG9sZEFsbG9jO1xcblxcbiAgICAgICAgcmV0dXJuIGN0eC5vdXQ7XFxuICAgIH1cXG5cXG4gICAgZnVuY3Rpb24gc2NoZWR1bGVUZXJtaW5hdGlvbigpIHtcXG4gICAgICAgIGNsZWFyVGltZW91dCh0ZXJtaW5hdGlvblRpbWVyKTtcXG4gICAgICAgIGlmICh0ZXJtaW5hdGlvblRpbWVvdXQgPiAwKSB7XFxuICAgICAgICAgICAgdGVybWluYXRpb25UaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xcbiAgICAgICAgICAgICAgICAvLyAyLXBoYXNlIHRlcm1pbmF0aW9uOiBub3RpZnkgbWFpbiB0aHJlYWQgZmlyc3Q7IGNsb3NlIG9ubHkgYWZ0ZXJcXG4gICAgICAgICAgICAgICAgLy8gaXQgYWNrcyB3aXRoIFRFUk1JTkFURS4gVGhpcyBwcmV2ZW50cyB0aGUgcmFjZSB3aGVyZSB0aGUgbWFpblxcbiAgICAgICAgICAgICAgICAvLyB0aHJlYWQgZGlzcGF0Y2hlcyBhIHRhc2sgdG8gYSB3b3JrZXIgdGhhdCBoYXMgYWxyZWFkeSBjbG9zZWQuXFxuICAgICAgICAgICAgICAgIGlmIChzZWxmKSBzZWxmLnBvc3RNZXNzYWdlKHtzdGF0dXM6IFxcXCJ3YW50X3RvX3Rlcm1pbmF0ZVxcXCJ9KTtcXG4gICAgICAgICAgICB9LCB0ZXJtaW5hdGlvblRpbWVvdXQpO1xcbiAgICAgICAgfVxcbiAgICB9XFxuXFxuICAgIGZ1bmN0aW9uIHRlcm1pbmF0ZSgpIHtcXG4gICAgICAgIGNsZWFyVGltZW91dCh0ZXJtaW5hdGlvblRpbWVyKTtcXG4gICAgICAgIGlmIChzZWxmKSB7XFxuICAgICAgICAgICAgc2VsZi5wb3N0TWVzc2FnZSh7c3RhdHVzOiBcXFwidGVybWluYXRlZFxcXCJ9KTtcXG4gICAgICAgICAgICBzZWxmLmNsb3NlKCk7XFxuICAgICAgICB9XFxuICAgIH1cXG5cXG4gICAgcmV0dXJuIHJ1blRhc2s7XFxufVwifSkoc2VsZilgO1xuICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgd29ya2VyU291cmNlID0gXCJkYXRhOmFwcGxpY2F0aW9uL2phdmFzY3JpcHQ7YmFzZTY0LFwiICsgQnVmZmVyLmZyb20odGhyZWFkU3RyKS50b1N0cmluZyhcImJhc2U2NFwiKTtcbiAgICB9IGVsc2UgaWYgKGdsb2JhbFRoaXM/LkJsb2IgJiYgZ2xvYmFsVGhpcy5VUkwgJiYgZ2xvYmFsVGhpcy5VUkwuY3JlYXRlT2JqZWN0VVJMKSB7XG4gICAgICAgIGNvbnN0IHRocmVhZEJ5dGVzID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHRocmVhZFN0cik7XG4gICAgICAgIGNvbnN0IHdvcmtlckJsb2IgPSBuZXcgQmxvYihbdGhyZWFkQnl0ZXNdLCB7IHR5cGU6IFwiYXBwbGljYXRpb24vamF2YXNjcmlwdFwiIH0pO1xuICAgICAgICB3b3JrZXJTb3VyY2UgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKHdvcmtlckJsb2IpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHdvcmtlclNvdXJjZSA9IFwiZGF0YTphcHBsaWNhdGlvbi9qYXZhc2NyaXB0O2Jhc2U2NCxcIiArIGdsb2JhbFRoaXMuYnRvYSh0aHJlYWRTdHIpO1xuICAgIH1cbiAgICByZXR1cm4gd29ya2VyU291cmNlO1xufVxuXG5cblxuYXN5bmMgZnVuY3Rpb24gYnVpbGRUaHJlYWRNYW5hZ2VyKHdhc20sIHNpbmdsZVRocmVhZCkge1xuICAgIGNvbnN0IHRtID0gbmV3IFRocmVhZE1hbmFnZXIoKTtcblxuICAgIHRtLm1lbW9yeSA9IG5ldyBXZWJBc3NlbWJseS5NZW1vcnkoe2luaXRpYWw6TUVNX1NJWkV9KTtcbiAgICB0bS51OCA9IG5ldyBVaW50OEFycmF5KHRtLm1lbW9yeS5idWZmZXIpO1xuICAgIHRtLnUzMiA9IG5ldyBVaW50MzJBcnJheSh0bS5tZW1vcnkuYnVmZmVyKTtcblxuICAgIGNvbnN0IHdhc21Nb2R1bGUgPSBhd2FpdCBXZWJBc3NlbWJseS5jb21waWxlKHdhc20uY29kZSk7XG5cbiAgICB0bS5pbnN0YW5jZSA9IGF3YWl0IFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKHdhc21Nb2R1bGUsIHtcbiAgICAgICAgZW52OiB7XG4gICAgICAgICAgICBcIm1lbW9yeVwiOiB0bS5tZW1vcnlcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gRm9yY2Ugc2luZ2xlLXRocmVhZCB3aGVuIG5vIFdvcmtlciBpcyBhdmFpbGFibGUuIENvdmVycyBTRVMgaGFyZGVuZWQgcmVhbG1zXG4gICAgLy8gKG5vIFdvcmtlciwgZnJvemVuIGdsb2JhbHMpIGFuZCBvbGQvbGltaXRlZCBicm93c2VycywgcmVnYXJkbGVzcyBvZiB3aGF0XG4gICAgLy8gdGhlIGNhbGxlciByZXF1ZXN0ZWQgLS0gdGhlIHdvcmtlciBwYXRoIChhbmQgZ2V0V29ya2VyU291cmNlJ3NcbiAgICAvLyBCbG9iL2J0b2EpIHdvdWxkIG90aGVyd2lzZSBmYWlsLiBOb2RlIHVzZXMgdGhlIHdlYi13b3JrZXIgaW1wb3J0LCBzbyBpdFxuICAgIC8vIGtlZXBzIG11bHRpLXRocmVhZGluZy5cbiAgICBpZighaXNOb2RlICYmICFnbG9iYWxUaGlzPy5Xb3JrZXIpIHtcbiAgICAgICAgc2luZ2xlVGhyZWFkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB0bS5zaW5nbGVUaHJlYWQgPSBzaW5nbGVUaHJlYWQ7XG4gICAgdG0uaW5pdGFsUEZyZWUgPSB0bS51MzJbMF07ICAgLy8gU2F2ZSB0aGUgUG9pbnRlciB0byBmcmVlIHNwYWNlLlxuICAgIHRtLnBxID0gd2FzbS5wcTtcbiAgICB0bS5wciA9IHdhc20ucHI7XG4gICAgdG0ucEcxZ2VuID0gd2FzbS5wRzFnZW47XG4gICAgdG0ucEcxemVybyA9IHdhc20ucEcxemVybztcbiAgICB0bS5wRzJnZW4gPSB3YXNtLnBHMmdlbjtcbiAgICB0bS5wRzJ6ZXJvID0gd2FzbS5wRzJ6ZXJvO1xuICAgIHRtLnBPbmVUID0gd2FzbS5wT25lVDtcblxuICAgIHRtLmNvZGUgPSB3YXNtLmNvZGU7XG4gICAgdG0ud2FzbU1vZHVsZSA9IHdhc21Nb2R1bGU7XG4gICAgLy8gQmF0Y2gtYWZmaW5lIE1TTSBoZWxwZXIgbW9kdWxlIChvcHRpb25hbCk6IGNvbXBpbGVkIG9uY2UsIHNoaXBwZWQgdG8gZXZlcnlcbiAgICAvLyB3b3JrZXIgYWxvbmdzaWRlIHRoZSBtYWluIG1vZHVsZS4gbjhmID0gYmFzZS1maWVsZCBlbGVtZW50IHNpemUgaW4gYnl0ZXMuXG4gICAgdG0uYmF0Y2hDb2RlID0gd2FzbS5iYXRjaENvZGU7XG4gICAgdG0uYmF0Y2hXYXNtTW9kdWxlID0gd2FzbS5iYXRjaENvZGUgPyBhd2FpdCBXZWJBc3NlbWJseS5jb21waWxlKHdhc20uYmF0Y2hDb2RlKSA6IHVuZGVmaW5lZDtcbiAgICB0bS5uOGYgPSB3YXNtLm44cTtcbiAgICB0bS5nbHYgPSAhIXdhc20uZ2x2O1xuXG4gICAgaWYgKHNpbmdsZVRocmVhZCkge1xuICAgICAgICB0bS50YXNrTWFuYWdlciA9IHRocmVhZCgpO1xuICAgICAgICBhd2FpdCB0bS50YXNrTWFuYWdlcihbe1xuICAgICAgICAgICAgY21kOiBcIklOSVRcIixcbiAgICAgICAgICAgIGluaXQ6IE1FTV9TSVpFLFxuICAgICAgICAgICAgY29kZTogdG0uY29kZS5zbGljZSgpLFxuICAgICAgICAgICAgYmF0Y2hDb2RlOiB0bS5iYXRjaENvZGUgPyB0bS5iYXRjaENvZGUuc2xpY2UoKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIG44ZjogdG0ubjhmLFxuICAgICAgICAgICAgZ2x2OiB0bS5nbHZcbiAgICAgICAgfV0pO1xuICAgICAgICB0bS5jb25jdXJyZW5jeSAgPSAxO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHBvb2xbaV0gaXMgdGhlIGFjdGl2ZSBXb3JrZXJTbG90IGF0IHNsb3QgaSwgb3IgbnVsbCBpZiB0aGUgc2xvdCBpcyBlbXB0eS5cbiAgICAgICAgdG0ucG9vbCA9IFtdO1xuXG4gICAgICAgIGxldCBjb25jdXJyZW5jeSA9IDI7XG4gICAgICAgIGlmICh0eXBlb2YgbmF2aWdhdG9yID09PSBcIm9iamVjdFwiICYmIG5hdmlnYXRvci5oYXJkd2FyZUNvbmN1cnJlbmN5KSB7XG4gICAgICAgICAgICBjb25jdXJyZW5jeSA9IG5hdmlnYXRvci5oYXJkd2FyZUNvbmN1cnJlbmN5O1xuICAgICAgICB9IGVsc2UgaWYgKG9zICYmIG9zLmNwdXMpIHtcbiAgICAgICAgICAgIGNvbmN1cnJlbmN5ID0gb3MuY3B1cygpLmxlbmd0aDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKGNvbmN1cnJlbmN5ID09PSAwKXtcbiAgICAgICAgICAgIGNvbmN1cnJlbmN5ID0gMjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIExpbWl0IHRvIDY0IHRocmVhZHMgZm9yIG1lbW9yeSByZWFzb25zLlxuICAgICAgICBpZiAoY29uY3VycmVuY3k+NjQpIGNvbmN1cnJlbmN5PTY0O1xuICAgICAgICB0bS5jb25jdXJyZW5jeSA9IGNvbmN1cnJlbmN5O1xuICAgIH1cbiAgICByZXR1cm4gdG07XG59XG5cbmNsYXNzIFRocmVhZE1hbmFnZXIge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLmFjdGlvblF1ZXVlID0gW107XG4gICAgICAgIHRoaXMub2xkUEZyZWUgPSAwO1xuICAgIH1cblxuICAgIC8vIEJ1aWxkIHRoZSBtZXNzYWdlIGhhbmRsZXIgZm9yIGEgc3BlY2lmaWMgV29ya2VyU2xvdC5cbiAgICAvLyBBbGwgc3RhdGUgcmVhZHMvd3JpdGVzIGdvIHRocm91Z2ggYHNsb3RgOyB0aGUgc3RhbGUgY2hlY2tcbiAgICAvLyBgdG0ucG9vbFtzbG90SW5kZXhdICE9PSBzbG90YCBkaXNjYXJkcyBtZXNzYWdlcyBmcm9tIHJlcGxhY2VkIHdvcmtlcnMuXG4gICAgX21ha2VPbk1zZyhzbG90SW5kZXgsIHNsb3QpIHtcbiAgICAgICAgY29uc3QgdG0gPSB0aGlzO1xuICAgICAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgY29uc3QgZGF0YSA9IChlICYmIGUuZGF0YSkgPyBlLmRhdGEgOiBlO1xuXG4gICAgICAgICAgICAvLyBTdGFsZSBjaGVjazogaWYgcG9vbFtzbG90SW5kZXhdIG5vIGxvbmdlciBwb2ludHMgdG8gdGhpcyBzbG90LFxuICAgICAgICAgICAgLy8gdGhlIG1lc3NhZ2UgaXMgZnJvbSBhIHdvcmtlciB0aGF0IHdhcyBhbHJlYWR5IHJlcGxhY2VkLlxuICAgICAgICAgICAgaWYgKHRtLnBvb2xbc2xvdEluZGV4XSAhPT0gc2xvdCkge1xuICAgICAgICAgICAgICAgIGlmIChkYXRhLnN0YXR1cyA9PT0gXCJ0ZXJtaW5hdGVkXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQnJlYWsgdGhlIHJlZmVyZW5jZSBjeWNsZSBzbyB0aGUgc2xvdCBhbmQgaXRzIFdBU00gbWVtb3J5XG4gICAgICAgICAgICAgICAgICAgIC8vIGNhbiBiZSBjb2xsZWN0ZWQgaW1tZWRpYXRlbHkgcmF0aGVyIHRoYW4gd2FpdGluZyBmb3IgR0MuXG4gICAgICAgICAgICAgICAgICAgIHNsb3Qud29ya2VyLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIHNsb3Qub25Nc2cpO1xuICAgICAgICAgICAgICAgICAgICBzbG90Lndvcmtlci5yZW1vdmVFdmVudExpc3RlbmVyKFwiZXJyb3JcIiwgICBzbG90Lm9uRXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghZGF0YS5zdGF0dXMgJiYgc2xvdC53b3JraW5nKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFN0YWxlIHRhc2sgcmVzdWx0OiB0aGUgc2xvdCB3YXMgcmVwbGFjZWQgKHdhbnRfdG9fdGVybWluYXRlIHJhY2VkXG4gICAgICAgICAgICAgICAgICAgIC8vIHdpdGggYSB0YXNrIGRpc3BhdGNoIOKAlCBwb29sW2ldIHdhcyBudWxsZWQgYmVmb3JlIHRoZSByZXN1bHQgY2FtZVxuICAgICAgICAgICAgICAgICAgICAvLyBiYWNrKS4gVGhlIHJlc3VsdCBpcyBzdGlsbCB2YWxpZDsgcmVzb2x2ZSBzbyB0aGUgY2FsbGVyIGRvZXNuJ3QgaGFuZy5cbiAgICAgICAgICAgICAgICAgICAgc2xvdC53b3JraW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIHNsb3QucGVuZGluZ0RlZmVycmVkLnJlc29sdmUoZGF0YSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGF3YWl0IHRtLnByb2Nlc3NXb3JrcygpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGRhdGEuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBzbG90LndvcmtpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBzbG90LnBlbmRpbmdEZWZlcnJlZC5yZWplY3QobmV3IEVycm9yKFwiV29ya2VyIGVycm9yOiBcIiArIGRhdGEuZXJyb3IpKTtcbiAgICAgICAgICAgICAgICBpZiAoc2xvdC5pbml0aWFsaXppbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgc2xvdC5pbml0aWFsaXppbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgdG0ucG9vbFtzbG90SW5kZXhdID0gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiV29ya2VyIGVycm9yOiBcIiArIGRhdGEuZXJyb3IpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoZGF0YS5zdGF0dXMpIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0YS5zdGF0dXMgPT09IFwiaW5pdGlhbGl6ZWRcIikge1xuICAgICAgICAgICAgICAgICAgICBzbG90LmluaXRpYWxpemluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICBzbG90LmluaXRpYWxpemVkICA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGRhdGEuc3RhdHVzID09PSBcIndhbnRfdG9fdGVybWluYXRlXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gMi1waGFzZSB0ZXJtaW5hdGlvbjogdGhlIHdvcmtlciBpcyBpZGxlIGFuZCBhc2tpbmcgdG8gY2xvc2UuXG4gICAgICAgICAgICAgICAgICAgIC8vIFJlbGVhc2UgdGhlIHNsb3QgaW1tZWRpYXRlbHkgc28gcHJvY2Vzc1dvcmtzIGNhbiBmaWxsIGl0IHdpdGggYVxuICAgICAgICAgICAgICAgICAgICAvLyBmcmVzaCB3b3JrZXIgaWYgdGhlIHF1ZXVlIG5lZWRzIG9uZS4gIFRoZSBURVJNSU5BVEUgYWNrIGlzIHNlbnRcbiAgICAgICAgICAgICAgICAgICAgLy8gdG8gdGhlIG9sZCB3b3JrZXIgc28gaXQgY2FuIGNsb3NlIGNsZWFubHk7IGl0cyBsYXRlciBcInRlcm1pbmF0ZWRcIlxuICAgICAgICAgICAgICAgICAgICAvLyBtZXNzYWdlIHdpbGwgYmUgc3RhbGUgKHBvb2xbc2xvdEluZGV4XSAhPT0gc2xvdCkgYW5kIGlnbm9yZWQuXG4gICAgICAgICAgICAgICAgICAgIHRtLnBvb2xbc2xvdEluZGV4XSA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHNsb3Qud29ya2VyLnBvc3RNZXNzYWdlKFt7Y21kOiBcIlRFUk1JTkFURVwifV0pO1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0bS5wcm9jZXNzV29ya3MoKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChkYXRhLnN0YXR1cyA9PT0gXCJ0ZXJtaW5hdGVkXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gV29ya2VyIGhhcyBmdWxseSBjbG9zZWQuICBGb3IgdGhlIDItcGhhc2UgcGF0aCB0aGUgc2xvdCB3YXNcbiAgICAgICAgICAgICAgICAgICAgLy8gYWxyZWFkeSBudWxsZWQgaW4gd2FudF90b190ZXJtaW5hdGUsIHNvIHRoaXMgbWVzc2FnZSBhcnJpdmVzXG4gICAgICAgICAgICAgICAgICAgIC8vIHN0YWxlIGFuZCBpcyBoYW5kbGVkIGFib3ZlLiAgRm9yIGEgZGlyZWN0IFRFUk1JTkFURVxuICAgICAgICAgICAgICAgICAgICAvLyAodG0udGVybWluYXRlKCkgYXQgcHJvb2YgZW5kKSB3ZSBjbGVhbiB1cCBoZXJlLlxuICAgICAgICAgICAgICAgICAgICBzbG90Lndvcmtlci5yZW1vdmVFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCBzbG90Lm9uTXNnKTtcbiAgICAgICAgICAgICAgICAgICAgc2xvdC53b3JrZXIucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImVycm9yXCIsICAgc2xvdC5vbkVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgdG0ucG9vbFtzbG90SW5kZXhdID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNsb3Qud29ya2luZykge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2FmZXR5IG5ldDogcmVqZWN0IHRoZSBwZW5kaW5nIGRlZmVycmVkIHNvIHRoZSBjYWxsZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN1cmZhY2VzIGFuIGVycm9yIGluc3RlYWQgb2YgaGFuZ2luZy5cbiAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QucGVuZGluZ0RlZmVycmVkLnJlamVjdChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcgRXJyb3IoYFdvcmtlciBhdCBzbG90ICR7c2xvdEluZGV4fSB0ZXJtaW5hdGVkIHVuZXhwZWN0ZWRseSB3aGlsZSBwcm9jZXNzaW5nIHRhc2tgKVxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNsb3Qud29ya2luZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gZmFsbCB0aHJvdWdoIGZvciBcImluaXRpYWxpemVkXCIgc28gdGhlIElOSVQgZGVmZXJyZWQgaXMgcmVzb2x2ZWQgYmVsb3dcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2xvdC53b3JraW5nID0gZmFsc2U7XG4gICAgICAgICAgICBzbG90LnBlbmRpbmdEZWZlcnJlZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgYXdhaXQgdG0ucHJvY2Vzc1dvcmtzKCk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgX21ha2VPbkVycm9yKHNsb3RJbmRleCwgc2xvdCkge1xuICAgICAgICBjb25zdCB0bSA9IHRoaXM7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbihlKSB7XG4gICAgICAgICAgICBpZiAodG0ucG9vbFtzbG90SW5kZXhdID09PSBzbG90KSB7XG4gICAgICAgICAgICAgICAgc2xvdC53b3JraW5nICAgICA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHNsb3QuaW5pdGlhbGl6ZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBpZiAoc2xvdC5wZW5kaW5nRGVmZXJyZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgc2xvdC5wZW5kaW5nRGVmZXJyZWQucmVqZWN0KG5ldyBFcnJvcihcIldvcmtlciBlcnJvcjogXCIgKyBlLm1lc3NhZ2UpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJXb3JrZXIgZXJyb3I6IFwiICsgZS5tZXNzYWdlKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBzdGFydFdvcmtlcihzbG90SW5kZXgpIHtcbiAgICAgICAgY29uc3QgbmF0aXZlV29ya2VyID0gbmV3IFdvcmtlcihnZXRXb3JrZXJTb3VyY2UoKSk7XG4gICAgICAgIGNvbnN0IHNsb3QgPSBuZXcgV29ya2VyU2xvdChuYXRpdmVXb3JrZXIpO1xuICAgICAgICB0aGlzLnBvb2xbc2xvdEluZGV4XSA9IHNsb3Q7XG5cbiAgICAgICAgc2xvdC5vbk1zZyAgID0gdGhpcy5fbWFrZU9uTXNnKHNsb3RJbmRleCwgc2xvdCk7XG4gICAgICAgIHNsb3Qub25FcnJvciA9IHRoaXMuX21ha2VPbkVycm9yKHNsb3RJbmRleCwgc2xvdCk7XG4gICAgICAgIG5hdGl2ZVdvcmtlci5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCBzbG90Lm9uTXNnKTtcbiAgICAgICAgbmF0aXZlV29ya2VyLmFkZEV2ZW50TGlzdGVuZXIoXCJlcnJvclwiLCAgIHNsb3Qub25FcnJvcik7XG5cbiAgICAgICAgc2xvdC5pbml0aWFsaXppbmcgPSB0cnVlO1xuXG4gICAgICAgIC8vIHBvc3RBY3Rpb24gc2V0cyBzbG90LndvcmtpbmcgPSB0cnVlIHN5bmNocm9ub3VzbHkgYmVmb3JlIGFueSBhd2FpdCxcbiAgICAgICAgLy8gc28gcHJvY2Vzc1dvcmtzIHdpbGwgbm90IGF0dGVtcHQgdG8gc3RhcnQgdGhpcyBzbG90IGFnYWluLlxuICAgICAgICB0aGlzLnBvc3RBY3Rpb24oc2xvdEluZGV4LCBbe1xuICAgICAgICAgICAgY21kOiAgXCJJTklUXCIsXG4gICAgICAgICAgICBpbml0OiBNRU1fU0laRSxcbiAgICAgICAgICAgIGNvZGU6IHRoaXMud2FzbU1vZHVsZSxcbiAgICAgICAgICAgIGJhdGNoQ29kZTogdGhpcy5iYXRjaFdhc21Nb2R1bGUsXG4gICAgICAgICAgICBuOGY6IHRoaXMubjhmLFxuICAgICAgICAgICAgZ2x2OiB0aGlzLmdsdixcbiAgICAgICAgfV0pLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgc2xvdC5pbml0aWFsaXplZCA9IHRydWU7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHN0YXJ0U3luY09wKCkge1xuICAgICAgICBpZiAodGhpcy5vbGRQRnJlZSAhPT0gMCkgdGhyb3cgbmV3IEVycm9yKFwiU3luYyBvcGVyYXRpb24gaW4gcHJvZ3Jlc3NcIik7XG4gICAgICAgIHRoaXMub2xkUEZyZWUgPSB0aGlzLnUzMlswXTtcbiAgICB9XG5cbiAgICBlbmRTeW5jT3AoKSB7XG4gICAgICAgIGlmICh0aGlzLm9sZFBGcmVlID09PSAwKSB0aHJvdyBuZXcgRXJyb3IoXCJObyBzeW5jIG9wZXJhdGlvbiBpbiBwcm9ncmVzc1wiKTtcbiAgICAgICAgdGhpcy51MzJbMF0gPSB0aGlzLm9sZFBGcmVlO1xuICAgICAgICB0aGlzLm9sZFBGcmVlID0gMDtcbiAgICB9XG5cbiAgICBhc3luYyBwb3N0QWN0aW9uKHNsb3RJbmRleCwgZSwgdHJhbnNmZXJzLCBfZGVmZXJyZWQpIHtcbiAgICAgICAgY29uc3Qgc2xvdCA9IHRoaXMucG9vbFtzbG90SW5kZXhdO1xuICAgICAgICBpZiAoIXNsb3QgfHwgc2xvdC53b3JraW5nKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJQb3N0aW5nIGEgam9iIHRvIGEgd29ya2luZyB3b3JrZXJcIik7XG4gICAgICAgIH1cbiAgICAgICAgc2xvdC53b3JraW5nID0gdHJ1ZTtcbiAgICAgICAgc2xvdC5wZW5kaW5nRGVmZXJyZWQgPSBfZGVmZXJyZWQgPyBfZGVmZXJyZWQgOiBuZXcgRGVmZXJyZWQoKTtcbiAgICAgICAgYXdhaXQgc2xvdC53b3JrZXIucG9zdE1lc3NhZ2UoZSwgdHJhbnNmZXJzKTtcbiAgICAgICAgcmV0dXJuIHNsb3QucGVuZGluZ0RlZmVycmVkLnByb21pc2U7XG4gICAgfVxuXG4gICAgYXN5bmMgcHJvY2Vzc1dvcmtzKCkge1xuICAgICAgICAvLyBEaXNwYXRjaCBxdWV1ZWQgdGFza3MgdG8gcmVhZHkgd29ya2Vycy5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmNvbmN1cnJlbmN5ICYmIHRoaXMuYWN0aW9uUXVldWUubGVuZ3RoID4gMDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBzbG90ID0gdGhpcy5wb29sW2ldO1xuICAgICAgICAgICAgaWYgKHNsb3QgJiYgc2xvdC5pbml0aWFsaXplZCAmJiAhc2xvdC53b3JraW5nKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgd29yayA9IHRoaXMuYWN0aW9uUXVldWUuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBvc3RBY3Rpb24oaSwgd29yay5kYXRhLCB3b3JrLnRyYW5zZmVycywgd29yay5kZWZlcnJlZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTdGFydCBuZXcgd29ya2VycyBmb3Igc2xvdHMgdGhhdCBuZWVkIHRoZW0uXG4gICAgICAgIGlmICh0aGlzLmFjdGlvblF1ZXVlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGxldCBpbml0aWFsaXppbmdDb3VudCA9IDA7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuY29uY3VycmVuY3k7IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IHNsb3QgPSB0aGlzLnBvb2xbaV07XG4gICAgICAgICAgICAgICAgaWYgKHNsb3QpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNsb3QuaW5pdGlhbGl6aW5nKSBpbml0aWFsaXppbmdDb3VudCsrO1xuICAgICAgICAgICAgICAgICAgICAvLyBzbG90IGV4aXN0czogc2tpcCB3aGV0aGVyIGluaXRpYWxpemVkLCBpbml0aWFsaXppbmcsIG9yIHdvcmtpbmdcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIHNsb3QgaXMgbnVsbDogdGhpcyBzbG90IGlzIGF2YWlsYWJsZSB0byBob3N0IGEgbmV3IHdvcmtlclxuICAgICAgICAgICAgICAgIGlmIChpbml0aWFsaXppbmdDb3VudCA+PSB0aGlzLmFjdGlvblF1ZXVlLmxlbmd0aCkgYnJlYWs7XG4gICAgICAgICAgICAgICAgaW5pdGlhbGl6aW5nQ291bnQrKztcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXJ0V29ya2VyKGkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgcXVldWVBY3Rpb24oYWN0aW9uRGF0YSwgdHJhbnNmZXJzKSB7XG4gICAgICAgIGNvbnN0IGQgPSBuZXcgRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAodGhpcy5zaW5nbGVUaHJlYWQpIHtcbiAgICAgICAgICAgIGNvbnN0IHJlcyA9IHRoaXMudGFza01hbmFnZXIoYWN0aW9uRGF0YSk7XG4gICAgICAgICAgICBkLnJlc29sdmUocmVzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYWN0aW9uUXVldWUucHVzaCh7XG4gICAgICAgICAgICAgICAgZGF0YTogICAgICBhY3Rpb25EYXRhLFxuICAgICAgICAgICAgICAgIHRyYW5zZmVyczogdHJhbnNmZXJzLFxuICAgICAgICAgICAgICAgIGRlZmVycmVkOiAgZFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnByb2Nlc3NXb3JrcygpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkLnByb21pc2U7XG4gICAgfVxuXG4gICAgcmVzZXRNZW1vcnkoKSB7XG4gICAgICAgIHRoaXMudTMyWzBdID0gdGhpcy5pbml0YWxQRnJlZTtcbiAgICB9XG5cbiAgICBhbGxvY0J1ZmYoYnVmZikge1xuICAgICAgICBjb25zdCBwb2ludGVyID0gdGhpcy5hbGxvYyhidWZmLmJ5dGVMZW5ndGgpO1xuICAgICAgICB0aGlzLnNldEJ1ZmYocG9pbnRlciwgYnVmZik7XG4gICAgICAgIHJldHVybiBwb2ludGVyO1xuICAgIH1cblxuICAgIGdldEJ1ZmYocG9pbnRlciwgbGVuZ3RoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnU4LnNsaWNlKHBvaW50ZXIsIHBvaW50ZXIgKyBsZW5ndGgpO1xuICAgIH1cblxuICAgIHNldEJ1ZmYocG9pbnRlciwgYnVmZmVyKSB7XG4gICAgICAgIHRoaXMudTguc2V0KG5ldyBVaW50OEFycmF5KGJ1ZmZlciksIHBvaW50ZXIpO1xuICAgIH1cblxuICAgIGFsbG9jKGxlbmd0aCkge1xuICAgICAgICB3aGlsZSAodGhpcy51MzJbMF0gJiAzKSB0aGlzLnUzMlswXSsrOyAgLy8gUmV0dXJuIGFsd2F5cyBhbGlnbmVkIHBvaW50ZXJzXG4gICAgICAgIGNvbnN0IHJlcyA9IHRoaXMudTMyWzBdO1xuICAgICAgICB0aGlzLnUzMlswXSArPSBsZW5ndGg7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgYXN5bmMgdGVybWluYXRlKCkge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMucG9vbC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKHRoaXMucG9vbFtpXSkge1xuICAgICAgICAgICAgICAgIHRoaXMucG9vbFtpXS53b3JrZXIucG9zdE1lc3NhZ2UoW3tjbWQ6IFwiVEVSTUlOQVRFXCJ9XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbn1cblxuZnVuY3Rpb24gYnVpbGRCYXRjaEFwcGx5S2V5KGN1cnZlLCBncm91cE5hbWUpIHtcbiAgICBjb25zdCBHID0gY3VydmVbZ3JvdXBOYW1lXTtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgIGNvbnN0IHRtID0gY3VydmUudG07XG5cbiAgICBjdXJ2ZVtncm91cE5hbWVdLmJhdGNoQXBwbHlLZXkgPSBhc3luYyBmdW5jdGlvbihidWZmLCBmaXJzdCwgaW5jLCBpblR5cGUsIG91dFR5cGUpIHtcbiAgICAgICAgaW5UeXBlID0gaW5UeXBlIHx8IFwiYWZmaW5lXCI7XG4gICAgICAgIG91dFR5cGUgPSBvdXRUeXBlIHx8IFwiYWZmaW5lXCI7XG4gICAgICAgIGxldCBmbk5hbWUsIGZuQWZmaW5lO1xuICAgICAgICBsZXQgc0dpbiwgc0dtaWQsIHNHb3V0O1xuICAgICAgICBpZiAoZ3JvdXBOYW1lID09IFwiRzFcIikge1xuICAgICAgICAgICAgaWYgKGluVHlwZSA9PSBcImphY29iaWFuXCIpIHtcbiAgICAgICAgICAgICAgICBzR2luID0gRy5GLm44KjM7XG4gICAgICAgICAgICAgICAgZm5OYW1lID0gXCJnMW1fYmF0Y2hBcHBseUtleVwiO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzR2luID0gRy5GLm44KjI7XG4gICAgICAgICAgICAgICAgZm5OYW1lID0gXCJnMW1fYmF0Y2hBcHBseUtleU1peGVkXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzR21pZCA9IEcuRi5uOCozO1xuICAgICAgICAgICAgaWYgKG91dFR5cGUgPT0gXCJqYWNvYmlhblwiKSB7XG4gICAgICAgICAgICAgICAgc0dvdXQgPSBHLkYubjgqMztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZm5BZmZpbmUgPSBcImcxbV9iYXRjaFRvQWZmaW5lXCI7XG4gICAgICAgICAgICAgICAgc0dvdXQgPSBHLkYubjgqMjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChncm91cE5hbWUgPT0gXCJHMlwiKSB7XG4gICAgICAgICAgICBpZiAoaW5UeXBlID09IFwiamFjb2JpYW5cIikge1xuICAgICAgICAgICAgICAgIHNHaW4gPSBHLkYubjgqMztcbiAgICAgICAgICAgICAgICBmbk5hbWUgPSBcImcybV9iYXRjaEFwcGx5S2V5XCI7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNHaW4gPSBHLkYubjgqMjtcbiAgICAgICAgICAgICAgICBmbk5hbWUgPSBcImcybV9iYXRjaEFwcGx5S2V5TWl4ZWRcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNHbWlkID0gRy5GLm44KjM7XG4gICAgICAgICAgICBpZiAob3V0VHlwZSA9PSBcImphY29iaWFuXCIpIHtcbiAgICAgICAgICAgICAgICBzR291dCA9IEcuRi5uOCozO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmbkFmZmluZSA9IFwiZzJtX2JhdGNoVG9BZmZpbmVcIjtcbiAgICAgICAgICAgICAgICBzR291dCA9IEcuRi5uOCoyO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGdyb3VwTmFtZSA9PSBcIkZyXCIpIHtcbiAgICAgICAgICAgIGZuTmFtZSA9IFwiZnJtX2JhdGNoQXBwbHlLZXlcIjtcbiAgICAgICAgICAgIHNHaW4gPSBHLm44O1xuICAgICAgICAgICAgc0dtaWQgPSBHLm44O1xuICAgICAgICAgICAgc0dvdXQgPSBHLm44O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBncm91cDogXCIgKyBncm91cE5hbWUpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG5Qb2ludHMgPSBNYXRoLmZsb29yKGJ1ZmYuYnl0ZUxlbmd0aCAvIHNHaW4pO1xuICAgICAgICBjb25zdCBwb2ludHNQZXJDaHVuayA9IE1hdGguZmxvb3IoblBvaW50cy90bS5jb25jdXJyZW5jeSk7XG4gICAgICAgIGNvbnN0IG9wUHJvbWlzZXMgPSBbXTtcbiAgICAgICAgaW5jID0gRnIuZShpbmMpO1xuICAgICAgICBsZXQgdCA9IEZyLmUoZmlyc3QpO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8dG0uY29uY3VycmVuY3k7IGkrKykge1xuICAgICAgICAgICAgbGV0IG47XG4gICAgICAgICAgICBpZiAoaTwgdG0uY29uY3VycmVuY3ktMSkge1xuICAgICAgICAgICAgICAgIG4gPSBwb2ludHNQZXJDaHVuaztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbiA9IG5Qb2ludHMgLSBpKnBvaW50c1BlckNodW5rO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG49PTApIGNvbnRpbnVlO1xuXG4gICAgICAgICAgICBjb25zdCB0YXNrID0gW107XG5cbiAgICAgICAgICAgIGNvbnN0IGIgPSBidWZmLnNsaWNlKGkqcG9pbnRzUGVyQ2h1bmsqc0dpbiwgaSpwb2ludHNQZXJDaHVuaypzR2luICsgbipzR2luKTtcblxuICAgICAgICAgICAgdGFzay5wdXNoKHtcbiAgICAgICAgICAgICAgICBjbWQ6IFwiQUxMT0NTRVRcIixcbiAgICAgICAgICAgICAgICB2YXI6IDAsXG4gICAgICAgICAgICAgICAgYnVmZjogYlxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDEsIGJ1ZmY6IHR9KTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMiwgYnVmZjogaW5jfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1wiLCB2YXI6IDMsIGxlbjogbipNYXRoLm1heChzR21pZCwgc0dvdXQpfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe1xuICAgICAgICAgICAgICAgIGNtZDogXCJDQUxMXCIsXG4gICAgICAgICAgICAgICAgZm5OYW1lOiBmbk5hbWUsXG4gICAgICAgICAgICAgICAgcGFyYW1zOiBbXG4gICAgICAgICAgICAgICAgICAgIHt2YXI6IDB9LFxuICAgICAgICAgICAgICAgICAgICB7dmFsOiBufSxcbiAgICAgICAgICAgICAgICAgICAge3ZhcjogMX0sXG4gICAgICAgICAgICAgICAgICAgIHt2YXI6IDJ9LFxuICAgICAgICAgICAgICAgICAgICB7dmFyOjN9XG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAoZm5BZmZpbmUpIHtcbiAgICAgICAgICAgICAgICB0YXNrLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBjbWQ6IFwiQ0FMTFwiLFxuICAgICAgICAgICAgICAgICAgICBmbk5hbWU6IGZuQWZmaW5lLFxuICAgICAgICAgICAgICAgICAgICBwYXJhbXM6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgIHt2YXI6IDN9LFxuICAgICAgICAgICAgICAgICAgICAgICAge3ZhbDogbn0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFyOiAzfSxcbiAgICAgICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDogMCwgdmFyOiAzLCBsZW46IG4qc0dvdXR9KTtcblxuICAgICAgICAgICAgb3BQcm9taXNlcy5wdXNoKHRtLnF1ZXVlQWN0aW9uKHRhc2ssIFtiLmJ1ZmZlcl0pKTtcbiAgICAgICAgICAgIHQgPSBGci5tdWwodCwgRnIuZXhwKGluYywgbikpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5hbGwob3BQcm9taXNlcyk7XG5cbiAgICAgICAgbGV0IG91dEJ1ZmY7XG4gICAgICAgIGlmIChidWZmIGluc3RhbmNlb2YgQmlnQnVmZmVyKSB7XG4gICAgICAgICAgICBvdXRCdWZmID0gbmV3IEJpZ0J1ZmZlcihuUG9pbnRzKnNHb3V0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG91dEJ1ZmYgPSBuZXcgVWludDhBcnJheShuUG9pbnRzKnNHb3V0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBwPTA7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxyZXN1bHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIG91dEJ1ZmYuc2V0KHJlc3VsdFtpXVswXSwgcCk7XG4gICAgICAgICAgICBwICs9IHJlc3VsdFtpXVswXS5ieXRlTGVuZ3RoO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG91dEJ1ZmY7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gYnVpbGRQYWlyaW5nKGN1cnZlKSB7XG4gICAgY29uc3QgdG0gPSBjdXJ2ZS50bTtcbiAgICBjdXJ2ZS5wYWlyaW5nID0gZnVuY3Rpb24gcGFpcmluZyhhLCBiKSB7XG5cbiAgICAgICAgdG0uc3RhcnRTeW5jT3AoKTtcbiAgICAgICAgY29uc3QgcEEgPSB0bS5hbGxvY0J1ZmYoY3VydmUuRzEudG9KYWNvYmlhbihhKSk7XG4gICAgICAgIGNvbnN0IHBCID0gdG0uYWxsb2NCdWZmKGN1cnZlLkcyLnRvSmFjb2JpYW4oYikpO1xuICAgICAgICBjb25zdCBwUmVzID0gdG0uYWxsb2MoY3VydmUuR3QubjgpO1xuICAgICAgICB0bS5pbnN0YW5jZS5leHBvcnRzW2N1cnZlLm5hbWUgKyBcIl9wYWlyaW5nXCJdKHBBLCBwQiwgcFJlcyk7XG5cbiAgICAgICAgY29uc3QgcmVzID0gdG0uZ2V0QnVmZihwUmVzLCBjdXJ2ZS5HdC5uOCk7XG5cbiAgICAgICAgdG0uZW5kU3luY09wKCk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfTtcblxuICAgIGN1cnZlLnBhaXJpbmdFcSA9IGFzeW5jIGZ1bmN0aW9uIHBhaXJpbmdFcSgpIHtcbiAgICAgICAgbGV0ICBidWZmQ3Q7XG4gICAgICAgIGxldCBuRXFzO1xuICAgICAgICBpZiAoKGFyZ3VtZW50cy5sZW5ndGggJSAyKSA9PSAxKSB7XG4gICAgICAgICAgICBidWZmQ3QgPSBhcmd1bWVudHNbYXJndW1lbnRzLmxlbmd0aC0xXTtcbiAgICAgICAgICAgIG5FcXMgPSAoYXJndW1lbnRzLmxlbmd0aCAtMSkgLzI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBidWZmQ3QgPSBjdXJ2ZS5HdC5vbmU7XG4gICAgICAgICAgICBuRXFzID0gYXJndW1lbnRzLmxlbmd0aCAvMjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG9wUHJvbWlzZXMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPG5FcXM7IGkrKykge1xuXG4gICAgICAgICAgICBjb25zdCB0YXNrID0gW107XG5cbiAgICAgICAgICAgIGNvbnN0IGcxQnVmZiA9IGN1cnZlLkcxLnRvSmFjb2JpYW4oYXJndW1lbnRzW2kqMl0pO1xuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAwLCBidWZmOiBnMUJ1ZmZ9KTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DXCIsIHZhcjogMSwgbGVuOiBjdXJ2ZS5wcmVQU2l6ZX0pO1xuXG4gICAgICAgICAgICBjb25zdCBnMkJ1ZmYgPSBjdXJ2ZS5HMi50b0phY29iaWFuKGFyZ3VtZW50c1tpKjIgKzFdKTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMiwgYnVmZjogZzJCdWZmfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1wiLCB2YXI6IDMsIGxlbjogY3VydmUucHJlUVNpemV9KTtcblxuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NcIiwgdmFyOiA0LCBsZW46IGN1cnZlLkd0Lm44fSk7XG5cbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkNBTExcIiwgZm5OYW1lOiBjdXJ2ZS5uYW1lICsgXCJfcHJlcGFyZUcxXCIsIHBhcmFtczogW1xuICAgICAgICAgICAgICAgIHt2YXI6IDB9LFxuICAgICAgICAgICAgICAgIHt2YXI6IDF9XG4gICAgICAgICAgICBdfSk7XG5cbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkNBTExcIiwgZm5OYW1lOiBjdXJ2ZS5uYW1lICsgXCJfcHJlcGFyZUcyXCIsIHBhcmFtczogW1xuICAgICAgICAgICAgICAgIHt2YXI6IDJ9LFxuICAgICAgICAgICAgICAgIHt2YXI6IDN9XG4gICAgICAgICAgICBdfSk7XG5cbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkNBTExcIiwgZm5OYW1lOiBjdXJ2ZS5uYW1lICsgXCJfbWlsbGVyTG9vcFwiLCBwYXJhbXM6IFtcbiAgICAgICAgICAgICAgICB7dmFyOiAxfSxcbiAgICAgICAgICAgICAgICB7dmFyOiAzfSxcbiAgICAgICAgICAgICAgICB7dmFyOiA0fVxuICAgICAgICAgICAgXX0pO1xuXG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJHRVRcIiwgb3V0OiAwLCB2YXI6IDQsIGxlbjogY3VydmUuR3Qubjh9KTtcblxuICAgICAgICAgICAgLy8gRG8gTk9UIHRyYW5zZmVyIGcxQnVmZi9nMkJ1ZmY6IHRvSmFjb2JpYW4oKSByZXR1cm5zIGl0cyBhcmd1bWVudFxuICAgICAgICAgICAgLy8gdW5yZXBsYWNlZCB3aGVuIHRoZSBwb2ludCBpcyBhbHJlYWR5IGluIGphY29iaWFuIGZvcm0sIHNvIHRoZXNlIG1heVxuICAgICAgICAgICAgLy8gYWxpYXMgY2FsbGVyLW93bmVkIGJ1ZmZlcnMgKGUuZy4gY3VydmUuRzEuZyAvIGN1cnZlLkcyLmcpLlxuICAgICAgICAgICAgLy8gVHJhbnNmZXJyaW5nIHdvdWxkIGRldGFjaCB0aGVtIG9uIHRoZSBtYWluIHRocmVhZC4gVGhleSBhcmUgc2luZ2xlXG4gICAgICAgICAgICAvLyBwb2ludHMsIHNvIHRoZSBzdHJ1Y3R1cmVkLWNsb25lIGNvcHkgaXMgbmVnbGlnaWJsZS5cbiAgICAgICAgICAgIG9wUHJvbWlzZXMucHVzaChcbiAgICAgICAgICAgICAgICB0bS5xdWV1ZUFjdGlvbih0YXNrKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5hbGwob3BQcm9taXNlcyk7XG5cbiAgICAgICAgdG0uc3RhcnRTeW5jT3AoKTtcbiAgICAgICAgY29uc3QgcFJlcyA9IHRtLmFsbG9jKGN1cnZlLkd0Lm44KTtcbiAgICAgICAgdG0uaW5zdGFuY2UuZXhwb3J0cy5mdG1fb25lKHBSZXMpO1xuXG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxyZXN1bHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IHBNUiA9IHRtLmFsbG9jQnVmZihyZXN1bHRbaV1bMF0pO1xuICAgICAgICAgICAgdG0uaW5zdGFuY2UuZXhwb3J0cy5mdG1fbXVsKHBSZXMsIHBNUiwgcFJlcyk7XG4gICAgICAgIH1cbiAgICAgICAgdG0uaW5zdGFuY2UuZXhwb3J0c1tjdXJ2ZS5uYW1lICsgXCJfZmluYWxFeHBvbmVudGlhdGlvblwiXShwUmVzLCBwUmVzKTtcblxuICAgICAgICBjb25zdCBwQ3QgPSB0bS5hbGxvY0J1ZmYoYnVmZkN0KTtcblxuICAgICAgICBjb25zdCByID0gISF0bS5pbnN0YW5jZS5leHBvcnRzLmZ0bV9lcShwUmVzLCBwQ3QpO1xuXG4gICAgICAgIHRtLmVuZFN5bmNPcCgpO1xuXG4gICAgICAgIHJldHVybiByO1xuICAgIH07XG5cbiAgICBjdXJ2ZS5wcmVwYXJlRzEgPSBmdW5jdGlvbihwKSB7XG4gICAgICAgIHRoaXMudG0uc3RhcnRTeW5jT3AoKTtcbiAgICAgICAgY29uc3QgcFAgPSB0aGlzLnRtLmFsbG9jQnVmZihwKTtcbiAgICAgICAgY29uc3QgcFByZXBQID0gdGhpcy50bS5hbGxvYyh0aGlzLnByZVBTaXplKTtcbiAgICAgICAgdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMubmFtZSArIFwiX3ByZXBhcmVHMVwiXShwUCwgcFByZXBQKTtcbiAgICAgICAgY29uc3QgcmVzID0gdGhpcy50bS5nZXRCdWZmKHBQcmVwUCwgdGhpcy5wcmVQU2l6ZSk7XG4gICAgICAgIHRoaXMudG0uZW5kU3luY09wKCk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfTtcblxuICAgIGN1cnZlLnByZXBhcmVHMiA9IGZ1bmN0aW9uKHEpIHtcbiAgICAgICAgdGhpcy50bS5zdGFydFN5bmNPcCgpO1xuICAgICAgICBjb25zdCBwUSA9IHRoaXMudG0uYWxsb2NCdWZmKHEpO1xuICAgICAgICBjb25zdCBwUHJlcFEgPSB0aGlzLnRtLmFsbG9jKHRoaXMucHJlUVNpemUpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5uYW1lICsgXCJfcHJlcGFyZUcyXCJdKHBRLCBwUHJlcFEpO1xuICAgICAgICBjb25zdCByZXMgPSB0aGlzLnRtLmdldEJ1ZmYocFByZXBRLCB0aGlzLnByZVFTaXplKTtcbiAgICAgICAgdGhpcy50bS5lbmRTeW5jT3AoKTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9O1xuXG4gICAgY3VydmUubWlsbGVyTG9vcCA9IGZ1bmN0aW9uKHByZVAsIHByZVEpIHtcbiAgICAgICAgdGhpcy50bS5zdGFydFN5bmNPcCgpO1xuICAgICAgICBjb25zdCBwUHJlUCA9IHRoaXMudG0uYWxsb2NCdWZmKHByZVApO1xuICAgICAgICBjb25zdCBwUHJlUSA9IHRoaXMudG0uYWxsb2NCdWZmKHByZVEpO1xuICAgICAgICBjb25zdCBwUmVzID0gdGhpcy50bS5hbGxvYyh0aGlzLkd0Lm44KTtcbiAgICAgICAgdGhpcy50bS5pbnN0YW5jZS5leHBvcnRzW3RoaXMubmFtZSArIFwiX21pbGxlckxvb3BcIl0ocFByZVAsIHBQcmVRLCBwUmVzKTtcbiAgICAgICAgY29uc3QgcmVzID0gdGhpcy50bS5nZXRCdWZmKHBSZXMsIHRoaXMuR3QubjgpO1xuICAgICAgICB0aGlzLnRtLmVuZFN5bmNPcCgpO1xuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH07XG5cbiAgICBjdXJ2ZS5maW5hbEV4cG9uZW50aWF0aW9uID0gZnVuY3Rpb24oYSkge1xuICAgICAgICB0aGlzLnRtLnN0YXJ0U3luY09wKCk7XG4gICAgICAgIGNvbnN0IHBBID0gdGhpcy50bS5hbGxvY0J1ZmYoYSk7XG4gICAgICAgIGNvbnN0IHBSZXMgPSB0aGlzLnRtLmFsbG9jKHRoaXMuR3QubjgpO1xuICAgICAgICB0aGlzLnRtLmluc3RhbmNlLmV4cG9ydHNbdGhpcy5uYW1lICsgXCJfZmluYWxFeHBvbmVudGlhdGlvblwiXShwQSwgcFJlcyk7XG4gICAgICAgIGNvbnN0IHJlcyA9IHRoaXMudG0uZ2V0QnVmZihwUmVzLCB0aGlzLkd0Lm44KTtcbiAgICAgICAgdGhpcy50bS5lbmRTeW5jT3AoKTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9O1xuXG59XG5cbmNvbnN0IHBUU2l6ZXMgPSBbXG4gICAgMSAsICAxLCAgMSwgIDEsICAgIDIsICAzLCAgNCwgIDUsXG4gICAgNiAsICA3LCAgNywgIDgsICAgIDksIDEwLCAxMSwgMTIsXG4gICAgMTMsIDEzLCAxNCwgMTUsICAgMTYsIDE2LCAxNywgMTcsXG4gICAgMTcsIDE3LCAxNywgMTcsICAgMTcsIDE3LCAxNywgMTdcbl07XG5cbmZ1bmN0aW9uIGJ1aWxkTXVsdGlleHAoY3VydmUsIGdyb3VwTmFtZSkge1xuICAgIGNvbnN0IEcgPSBjdXJ2ZVtncm91cE5hbWVdO1xuICAgIGNvbnN0IHRtID0gRy50bTtcblxuICAgIGNvbnN0IE1BWF9DSFVOS19TSVpFID0gMSA8PCAyMjtcbiAgICBjb25zdCBNSU5fQ0hVTktfU0laRSA9IDEgPDwgMTI7XG5cbiAgICAvLyBCeXRlIHNpemUgb2Ygb25lIGlucHV0IHBvaW50OiBhZmZpbmUgPSAyIGNvb3JkaW5hdGVzLCBqYWNvYmlhbiA9IDMuXG4gICAgZnVuY3Rpb24gcG9pbnRTaXplKGluVHlwZSkge1xuICAgICAgICByZXR1cm4gaW5UeXBlID09PSBcImFmZmluZVwiID8gRy5GLm44KjIgOiBHLkYubjgqMztcbiAgICB9XG5cbiAgICAvLyBCYXRjaC1hZmZpbmUgXCJhdXRvXCIgdGhyZXNob2xkOiB1c2UgdGhlIGJhdGNoIG1vZHVsZSB3aGVuIGEgY2h1bmsncyBiYXNlc1xuICAgIC8vIGZpdCBjb21mb3J0YWJseSBpbiBhIHBlci13b3JrZXIgc2hhcmUgb2YgdGhlIGxhc3QtbGV2ZWwgY2FjaGUuIE1lYXN1cmVkXG4gICAgLy8gKDIwIGNvcmVzLCBibjEyOCk6IGNsZWFyIHdpbiB1cCB0byB+MS0yIE1pQiBvZiBiYXNlcyBwZXIgY2h1bmsgKCsxMCUgb24gYVxuICAgIC8vIGZ1bGwgMl4xNiBwcm92ZSksIHBhcml0eSBidXQgZXh0cmEgc2NyYXRjaCBtZW1vcnkgYXQgfjYgTWlCIGNodW5rcyAtLVxuICAgIC8vIHVuZGVyIGZ1bGwgd29ya2VyIGNvbmN1cnJlbmN5IHRoZSBmaWxsIHBoYXNlIGlzIGJhbmR3aWR0aC1ib3VuZCwgc28gdGhlXG4gICAgLy8gZmV3ZXItbXVsdGlwbGljYXRpb25zIGFkdmFudGFnZSBvbmx5IG1hdGVyaWFsaXplcyB3aGlsZSB0aGUgcmFuZG9tLWFjY2Vzc1xuICAgIC8vIHNldCBzdGF5cyBjYWNoZS1yZXNpZGVudC5cbiAgICBjb25zdCBBVVRPX0JBVENIX01BWF9CQVNFU19CWVRFUyA9IDEgPDwgMjE7XG5cbiAgICAvLyBSZXNvbHZlIHRoZSBiYXRjaGluZyBtb2RlOiBcImF1dG9cIiAoZGVmYXVsdCkgfCBcImVuYWJsZWRcIiB8IFwiZGlzYWJsZWRcIi5cbiAgICAvLyBBY2NlcHRzIGJvb2xlYW5zIGFzIGFsaWFzZXMuXG4gICAgZnVuY3Rpb24gYmF0Y2hNb2RlT2Yob3B0aW9ucykge1xuICAgICAgICBjb25zdCBtID0gb3B0aW9ucyA/IG9wdGlvbnMuYmF0Y2ggOiB1bmRlZmluZWQ7XG4gICAgICAgIGlmIChtID09PSB0cnVlIHx8IG0gPT09IFwiZW5hYmxlZFwiKSByZXR1cm4gXCJlbmFibGVkXCI7XG4gICAgICAgIGlmIChtID09PSBmYWxzZSB8fCBtID09PSBcImRpc2FibGVkXCIpIHJldHVybiBcImRpc2FibGVkXCI7XG4gICAgICAgIHJldHVybiBcImF1dG9cIjtcbiAgICB9XG5cbiAgICAvLyBFbmRvbW9ycGhpc20gbW9kZSBmb3IgdGhpcyBncm91cDogXCJhdXRvXCIgKGRlZmF1bHQgLS0gdXNlIEdMVi9HTFMgd2hlbiB0aGVcbiAgICAvLyBjdXJ2ZSBhZHZlcnRpc2VzIGl0OyB0aGUgd2FzbSBzdGlsbCBnYXRlcyBpbnRlcm5hbGx5IG9uIHNpemVzKSBvclxuICAgIC8vIFwiZGlzYWJsZWRcIiAoZ2VuZXJpYyBiYXRjaCBhY2N1bXVsYXRpb24pLiBvcHRpb25zLmdsdiBnb3Zlcm5zIEcxLFxuICAgIC8vIG9wdGlvbnMuZ2xzIGdvdmVybnMgRzI7IGZhbHNlIGlzIGFjY2VwdGVkIGFzIGFuIGFsaWFzIGZvciBcImRpc2FibGVkXCIuXG4gICAgZnVuY3Rpb24gZW5kb09mKG9wdGlvbnMpIHtcbiAgICAgICAgY29uc3QgdiA9IG9wdGlvbnMgPyAoZ3JvdXBOYW1lID09PSBcIkcxXCIgPyBvcHRpb25zLmdsdiA6IG9wdGlvbnMuZ2xzKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKHYgPT09IGZhbHNlIHx8IHYgPT09IFwiZGlzYWJsZWRcIikgcmV0dXJuIFwiZGlzYWJsZWRcIjtcbiAgICAgICAgcmV0dXJuIFwiYXV0b1wiO1xuICAgIH1cblxuICAgIC8vIFdBU00gZXhwb3J0IG5hbWUgZm9yIHRoaXMgZ3JvdXAgKyBpbnB1dCByZXByZXNlbnRhdGlvbi4gQWZmaW5lIGlucHV0XG4gICAgLy8gcm91dGVzIHRvIHRoZSBiYXRjaC1hZmZpbmUgTVNNIG1vZHVsZSAoXCIuLi5CYXRjaFwiKSBkZXBlbmRpbmcgb24gdGhlXG4gICAgLy8gYmF0Y2hpbmcgbW9kZTsgdGhlIHdvcmtlciBmYWxscyBiYWNrIHRvIHRoZSBwbGFpbiBpbi1tb2R1bGUgdmFyaWFudFxuICAgIC8vIHdoZW4gdGhlIGJhdGNoIG1vZHVsZSBpcyBhYnNlbnQuXG4gICAgZnVuY3Rpb24gZm5OYW1lRm9yKGluVHlwZSwgYmFzZXNCeXRlcywgYmF0Y2hNb2RlLCBlbmRvTW9kZSkge1xuICAgICAgICBjb25zdCBnID0gZ3JvdXBOYW1lID09PSBcIkcxXCIgPyBcImcxbVwiIDogXCJnMm1cIjtcbiAgICAgICAgaWYgKGluVHlwZSAhPT0gXCJhZmZpbmVcIikgcmV0dXJuIGAke2d9X211bHRpZXhwYDtcbiAgICAgICAgY29uc3QgdXNlQmF0Y2ggPSBiYXRjaE1vZGUgPT09IFwiZW5hYmxlZFwiIHx8XG4gICAgICAgICAgICAoYmF0Y2hNb2RlID09PSBcImF1dG9cIiAmJiBiYXNlc0J5dGVzIDw9IEFVVE9fQkFUQ0hfTUFYX0JBU0VTX0JZVEVTKTtcbiAgICAgICAgaWYgKCF1c2VCYXRjaCkgcmV0dXJuIGAke2d9X211bHRpZXhwQWZmaW5lYDtcbiAgICAgICAgY29uc3Qgbm9FbmRvID0gZW5kb01vZGUgPT09IFwiZGlzYWJsZWRcIiA/IChncm91cE5hbWUgPT09IFwiRzFcIiA/IFwiTm9HbHZcIiA6IFwiTm9HbHNcIikgOiBcIlwiO1xuICAgICAgICByZXR1cm4gYCR7Z31fbXVsdGlleHBBZmZpbmVCYXRjaCR7bm9FbmRvfWA7XG4gICAgfVxuXG4gICAgLy8gUG9pbnRzIHBlciBjaHVuay4gbkNodW5rcyBpcyBkZXJpdmVkIGZyb20gdGhlIHNjYWxhciBiaXQtd2lkdGggYW5kIHJvdW5kZWQgdXBcbiAgICAvLyB0byBhIG11bHRpcGxlIG9mIHRoZSB3b3JrZXIgY291bnQgZm9yIGV2ZW4gbG9hZCBiYWxhbmNpbmcgKEcyIHBvaW50cyBhcmVcbiAgICAvLyBsYXJnZXIsIHNvIHdlIGhhbHZlIHRoZSBjaHVuayAvIGRvdWJsZSB0aGUgY291bnQpLiBDbGFtcGVkIHRvIGEgc2FuZSByYW5nZS5cbiAgICBmdW5jdGlvbiBjaHVua1NpemVGb3IoblBvaW50cywgc1NjYWxhcikge1xuICAgICAgICBjb25zdCBiaXRDaHVua1NpemUgPSBwVFNpemVzW2xvZzIoblBvaW50cyldO1xuICAgICAgICBsZXQgbkNodW5rcyA9IE1hdGguZmxvb3IoKHNTY2FsYXIqOCAtIDEpIC8gYml0Q2h1bmtTaXplKSArIDE7XG4gICAgICAgIGlmIChncm91cE5hbWUgPT09IFwiRzJcIikgbkNodW5rcyAqPSAyO1xuICAgICAgICBuQ2h1bmtzID0gKE1hdGguZmxvb3IoKG5DaHVua3MtMSkgLyB0bS5jb25jdXJyZW5jeSkgKyAxKSAqIHRtLmNvbmN1cnJlbmN5O1xuICAgICAgICBsZXQgY2h1bmtTaXplID0gTWF0aC5mbG9vcihuUG9pbnRzIC8gbkNodW5rcykgKyAxO1xuICAgICAgICBpZiAoY2h1bmtTaXplID4gTUFYX0NIVU5LX1NJWkUpIGNodW5rU2l6ZSA9IE1BWF9DSFVOS19TSVpFO1xuICAgICAgICBpZiAoY2h1bmtTaXplIDwgTUlOX0NIVU5LX1NJWkUpIGNodW5rU2l6ZSA9IE1JTl9DSFVOS19TSVpFO1xuICAgICAgICByZXR1cm4gY2h1bmtTaXplO1xuICAgIH1cblxuICAgIC8vIFJ1biB0aGUgbXVsdGlleHAgb2Ygb25lIGNodW5rIG9uIGEgd29ya2VyOyByZXR1cm5zIHRoZSBwYXJ0aWFsIHBvaW50LlxuICAgIGFzeW5jIGZ1bmN0aW9uIF9tdWx0aUV4cENodW5rKGJ1ZmZCYXNlcywgYnVmZlNjYWxhcnMsIGluVHlwZSwgYmF0Y2hNb2RlLCBlbmRvTW9kZSwgbG9nVGV4dCkge1xuICAgICAgICBpZiAoIShidWZmQmFzZXMgaW5zdGFuY2VvZiBVaW50OEFycmF5KSkgdGhyb3cgbmV3IEVycm9yKGAke2xvZ1RleHR9IF9tdWx0aUV4cENodW5rIGJ1ZmZCYXNlcyBpcyBub3QgVWludDhBcnJheWApO1xuICAgICAgICBpZiAoIShidWZmU2NhbGFycyBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpKSB0aHJvdyBuZXcgRXJyb3IoYCR7bG9nVGV4dH0gX211bHRpRXhwQ2h1bmsgYnVmZlNjYWxhcnMgaXMgbm90IFVpbnQ4QXJyYXlgKTtcbiAgICAgICAgY29uc3Qgc0dJbiA9IHBvaW50U2l6ZShpblR5cGUpO1xuICAgICAgICBjb25zdCBuUG9pbnRzID0gTWF0aC5mbG9vcihidWZmQmFzZXMuYnl0ZUxlbmd0aCAvIHNHSW4pO1xuICAgICAgICBpZiAoblBvaW50cyA9PT0gMCkgcmV0dXJuIEcuemVybztcbiAgICAgICAgY29uc3Qgc1NjYWxhciA9IE1hdGguZmxvb3IoYnVmZlNjYWxhcnMuYnl0ZUxlbmd0aCAvIG5Qb2ludHMpO1xuICAgICAgICBpZiAoc1NjYWxhciAqIG5Qb2ludHMgIT09IGJ1ZmZTY2FsYXJzLmJ5dGVMZW5ndGgpIHRocm93IG5ldyBFcnJvcihgJHtsb2dUZXh0fSBTY2FsYXIgc2l6ZSBkb2VzIG5vdCBtYXRjaGApO1xuXG4gICAgICAgIGNvbnN0IHRhc2sgPSBbXG4gICAgICAgICAgICB7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMCwgYnVmZjogYnVmZkJhc2VzfSxcbiAgICAgICAgICAgIHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAxLCBidWZmOiBidWZmU2NhbGFyc30sXG4gICAgICAgICAgICB7Y21kOiBcIkFMTE9DXCIsICAgIHZhcjogMiwgbGVuOiBHLkYubjgqM30sXG4gICAgICAgICAgICB7Y21kOiBcIkNBTExcIiwgZm5OYW1lOiBmbk5hbWVGb3IoaW5UeXBlLCBidWZmQmFzZXMuYnl0ZUxlbmd0aCwgYmF0Y2hNb2RlLCBlbmRvTW9kZSksIHBhcmFtczogW1xuICAgICAgICAgICAgICAgIHt2YXI6IDB9LCB7dmFyOiAxfSwge3ZhbDogc1NjYWxhcn0sIHt2YWw6IG5Qb2ludHN9LCB7dmFyOiAyfVxuICAgICAgICAgICAgXX0sXG4gICAgICAgICAgICB7Y21kOiBcIkdFVFwiLCBvdXQ6IDAsIHZhcjogMiwgbGVuOiBHLkYubjgqM30sXG4gICAgICAgIF07XG4gICAgICAgIC8vIHRyYW5zZmVyIHRoZSBjaHVuayBidWZmZXJzIHRvIHRoZSB3b3JrZXIgKHplcm8tY29weSk7IG9uZSBHRVQgLT4gb25lIHBvaW50XG4gICAgICAgIGNvbnN0IG91dCA9IGF3YWl0IHRtLnF1ZXVlQWN0aW9uKHRhc2ssIFtidWZmQmFzZXMuYnVmZmVyLCBidWZmU2NhbGFycy5idWZmZXJdKTtcbiAgICAgICAgcmV0dXJuIG91dFswXTtcbiAgICB9XG5cbiAgICAvLyBTaGFyZWQgZHJpdmVyLiBgZ2V0Q2h1bmsoYnl0ZU9mZnNldCwgYnl0ZUxlbmd0aClgIHN1cHBsaWVzIGVhY2ggYmFzZXMgY2h1bmsgLS1cbiAgICAvLyBhIHN5bmNocm9ub3VzIHNsaWNlIG9mIGFuIGluLW1lbW9yeSBidWZmZXIsIG9yIGFuIGFzeW5jIHN1Yi1yYW5nZSByZWFkLiBBdCBtb3N0XG4gICAgLy8gYG1heEluRmxpZ2h0YCBjaHVua3MgYXJlIHNvdXJjZWQgYXQgb25jZSAoSW5maW5pdHkgPSBkaXNwYXRjaCB0aGVtIGFsbCkuIFRoZVxuICAgIC8vIHBvaW50IHNldCBpcyBwYXJ0aXRpb25lZCBhY3Jvc3MgY2h1bmtzLCBzbyB0aGUgZnVsbCBtdWx0aWV4cCBpcyB0aGUgc3VtIG9mIHRoZVxuICAgIC8vIHBlci1jaHVuayBtdWx0aWV4cHMuXG4gICAgYXN5bmMgZnVuY3Rpb24gX211bHRpRXhwRGlzcGF0Y2goZ2V0Q2h1bmssIGJ1ZmZTY2FsYXJzLCBuUG9pbnRzLCBzR0luLCBzU2NhbGFyLCBpblR5cGUsIG1heEluRmxpZ2h0LCBiYXRjaE1vZGUsIGVuZG9Nb2RlLCBsb2dnZXIsIGxvZ1RleHQpIHtcbiAgICAgICAgaWYgKG5Qb2ludHMgPT09IDApIHJldHVybiBHLnplcm87XG4gICAgICAgIGNvbnN0IGNodW5rU2l6ZSA9IGNodW5rU2l6ZUZvcihuUG9pbnRzLCBzU2NhbGFyKTtcbiAgICAgICAgY29uc3QgaW5GbGlnaHQgPSBuZXcgU2V0KCk7XG4gICAgICAgIGNvbnN0IHBhcnRpYWxzID0gW107XG5cbiAgICAgICAgZm9yIChsZXQgb2ZmID0gMDsgb2ZmIDwgblBvaW50czsgb2ZmICs9IGNodW5rU2l6ZSkge1xuICAgICAgICAgICAgY29uc3QgbiA9IE1hdGgubWluKG5Qb2ludHMgLSBvZmYsIGNodW5rU2l6ZSk7XG4gICAgICAgICAgICBjb25zdCBhdCA9IG9mZjtcbiAgICAgICAgICAgIC8vIEJhY2twcmVzc3VyZTogYmxvY2sgdW50aWwgYSBzbG90IGZyZWVzIChQcm9taXNlLnJhY2UgYWxzbyBzdXJmYWNlcyBhXG4gICAgICAgICAgICAvLyBmYWlsZWQgY2h1bmsgcHJvbXB0bHkpLiBXaXRoIG1heEluRmxpZ2h0ID0gSW5maW5pdHkgdGhpcyBuZXZlciBibG9ja3MuXG4gICAgICAgICAgICB3aGlsZSAoaW5GbGlnaHQuc2l6ZSA+PSBtYXhJbkZsaWdodCkgYXdhaXQgUHJvbWlzZS5yYWNlKGluRmxpZ2h0KTtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgTXVsdGlleHAgc3RhcnQ6ICR7bG9nVGV4dH06ICR7YXR9LyR7blBvaW50c31gKTtcbiAgICAgICAgICAgIGNvbnN0IG9wID0gKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBiYXNlc0NodW5rID0gYXdhaXQgZ2V0Q2h1bmsoYXQqc0dJbiwgbipzR0luKTtcbiAgICAgICAgICAgICAgICBjb25zdCBzY2FsYXJzQ2h1bmsgPSBidWZmU2NhbGFycy5zbGljZShhdCpzU2NhbGFyLCAoYXQrbikqc1NjYWxhcik7XG4gICAgICAgICAgICAgICAgY29uc3QgciA9IGF3YWl0IF9tdWx0aUV4cENodW5rKGJhc2VzQ2h1bmssIHNjYWxhcnNDaHVuaywgaW5UeXBlLCBiYXRjaE1vZGUsIGVuZG9Nb2RlLCBsb2dUZXh0KTtcbiAgICAgICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYE11bHRpZXhwIGVuZDogJHtsb2dUZXh0fTogJHthdH0vJHtuUG9pbnRzfWApO1xuICAgICAgICAgICAgICAgIHJldHVybiByO1xuICAgICAgICAgICAgfSkoKTtcbiAgICAgICAgICAgIC8vIHNldHRsZS1laXRoZXItd2F5IGNsZWFudXAgc28gYSByZWplY3RlZCBjaHVuayBjYW4ndCB3ZWRnZSB0aGUgc2V0XG4gICAgICAgICAgICBjb25zdCBzbG90ID0gb3AuZmluYWxseSgoKSA9PiBpbkZsaWdodC5kZWxldGUoc2xvdCkpO1xuICAgICAgICAgICAgaW5GbGlnaHQuYWRkKHNsb3QpO1xuICAgICAgICAgICAgcGFydGlhbHMucHVzaChzbG90KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UuYWxsKHBhcnRpYWxzKTtcbiAgICAgICAgbGV0IHJlcyA9IEcuemVybztcbiAgICAgICAgZm9yIChsZXQgaSA9IHJlc3VsdC5sZW5ndGgtMTsgaSA+PSAwOyBpLS0pIHJlcyA9IEcuYWRkKHJlcywgcmVzdWx0W2ldKTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICAvLyBEZXJpdmUgblBvaW50cy9zU2NhbGFyIGFuZCB2YWxpZGF0ZSBiZWZvcmUgZGlzcGF0Y2hpbmcuXG4gICAgZnVuY3Rpb24gZ2VvbWV0cnkodG90YWxCYXNlc0J5dGVzLCBidWZmU2NhbGFycywgaW5UeXBlKSB7XG4gICAgICAgIGNvbnN0IHNHSW4gPSBwb2ludFNpemUoaW5UeXBlKTtcbiAgICAgICAgY29uc3QgblBvaW50cyA9IE1hdGguZmxvb3IodG90YWxCYXNlc0J5dGVzIC8gc0dJbik7XG4gICAgICAgIGxldCBzU2NhbGFyID0gMDtcbiAgICAgICAgaWYgKG5Qb2ludHMgPiAwKSB7XG4gICAgICAgICAgICBzU2NhbGFyID0gTWF0aC5mbG9vcihidWZmU2NhbGFycy5ieXRlTGVuZ3RoIC8gblBvaW50cyk7XG4gICAgICAgICAgICBpZiAoc1NjYWxhciAqIG5Qb2ludHMgIT09IGJ1ZmZTY2FsYXJzLmJ5dGVMZW5ndGgpIHRocm93IG5ldyBFcnJvcihcIlNjYWxhciBzaXplIGRvZXMgbm90IG1hdGNoXCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IHNHSW4sIG5Qb2ludHMsIHNTY2FsYXIgfTtcbiAgICB9XG5cbiAgICAvLyBtdWx0aWV4cCBvdmVyIGFuIGluLW1lbW9yeSBiYXNlcyBidWZmZXIgKHNsaWNlZCBwZXIgY2h1bmssIGFsbCBkaXNwYXRjaGVkIGF0IG9uY2UpLlxuICAgIGFzeW5jIGZ1bmN0aW9uIF9tdWx0aUV4cChidWZmQmFzZXMsIGJ1ZmZTY2FsYXJzLCBpblR5cGUsIGJhdGNoTW9kZSwgZW5kb01vZGUsIGxvZ2dlciwgbG9nVGV4dCkge1xuICAgICAgICBjb25zdCB7IHNHSW4sIG5Qb2ludHMsIHNTY2FsYXIgfSA9IGdlb21ldHJ5KGJ1ZmZCYXNlcy5ieXRlTGVuZ3RoLCBidWZmU2NhbGFycywgaW5UeXBlKTtcbiAgICAgICAgY29uc3QgZ2V0Q2h1bmsgPSAob2ZmLCBsZW4pID0+IGJ1ZmZCYXNlcy5zbGljZShvZmYsIG9mZiArIGxlbik7XG4gICAgICAgIHJldHVybiBfbXVsdGlFeHBEaXNwYXRjaChnZXRDaHVuaywgYnVmZlNjYWxhcnMsIG5Qb2ludHMsIHNHSW4sIHNTY2FsYXIsIGluVHlwZSwgSW5maW5pdHksIGJhdGNoTW9kZSwgZW5kb01vZGUsIGxvZ2dlciwgbG9nVGV4dCk7XG4gICAgfVxuXG4gICAgRy5tdWx0aUV4cCA9IGFzeW5jIGZ1bmN0aW9uIG11bHRpRXhwKGJ1ZmZCYXNlcywgYnVmZlNjYWxhcnMsIGxvZ2dlciwgbG9nVGV4dCkge1xuICAgICAgICByZXR1cm4gX211bHRpRXhwKGJ1ZmZCYXNlcywgYnVmZlNjYWxhcnMsIFwiamFjb2JpYW5cIiwgXCJkaXNhYmxlZFwiLCBcImF1dG9cIiwgbG9nZ2VyLCBsb2dUZXh0KTtcbiAgICB9O1xuICAgIC8vIG9wdGlvbnMuYmF0Y2g6IFwiYXV0b1wiIChkZWZhdWx0KSB8IFwiZW5hYmxlZFwiIHwgXCJkaXNhYmxlZFwiIC0tIHNlZSBiYXRjaE1vZGVPZi5cbiAgICAvLyBvcHRpb25zLmdsdiAvIG9wdGlvbnMuZ2xzOiBcImF1dG9cIiAoZGVmYXVsdCkgfCBcImRpc2FibGVkXCIgLS0gc2VlIGVuZG9PZi5cbiAgICBHLm11bHRpRXhwQWZmaW5lID0gYXN5bmMgZnVuY3Rpb24gbXVsdGlFeHBBZmZpbmUoYnVmZkJhc2VzLCBidWZmU2NhbGFycywgbG9nZ2VyLCBsb2dUZXh0LCBvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBfbXVsdGlFeHAoYnVmZkJhc2VzLCBidWZmU2NhbGFycywgXCJhZmZpbmVcIiwgYmF0Y2hNb2RlT2Yob3B0aW9ucyksIGVuZG9PZihvcHRpb25zKSwgbG9nZ2VyLCBsb2dUZXh0KTtcbiAgICB9O1xuXG4gICAgLy8gU3RyZWFtaW5nIGFmZmluZSBtdWx0aWV4cDogYmFzZXMgYXJlIHByb2R1Y2VkIGNodW5rLWJ5LWNodW5rIGJ5IGBiYXNlc1JlYWRlcmBcbiAgICAvLyAoZS5nLiBhIGRpcmVjdCBzdWItcmFuZ2UgZmlsZSByZWFkKSBpbnN0ZWFkIG9mIGJlaW5nIHJlYWQgd2hvbGUgYW5kIHNsaWNlZCAtLVxuICAgIC8vIG5vIG1haW4tdGhyZWFkIHNsaWNlIGNvcHksIGFuZCB0aGUgZnVsbCBzZWN0aW9uIG5ldmVyIHNpdHMgaW4gUkFNIChyZWFkcyBhcmVcbiAgICAvLyBib3VuZGVkIHRvIGEgZmV3IGluLWZsaWdodCBjaHVua3MpLiBSZXN1bHQgaXMgaWRlbnRpY2FsIHRvIG11bHRpRXhwQWZmaW5lLlxuICAgIEcubXVsdGlFeHBBZmZpbmVDaHVua2VkID0gYXN5bmMgZnVuY3Rpb24gbXVsdGlFeHBBZmZpbmVDaHVua2VkKGJhc2VzUmVhZGVyLCB0b3RhbEJhc2VzQnl0ZXMsIGJ1ZmZTY2FsYXJzLCBsb2dnZXIsIGxvZ1RleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBiYXNlc1JlYWRlciAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7bG9nVGV4dCB8fCBcIm11bHRpRXhwQWZmaW5lQ2h1bmtlZFwifTogYmFzZXNSZWFkZXIgbXVzdCBiZSBhIGZ1bmN0aW9uIChieXRlT2Zmc2V0LCBieXRlTGVuZ3RoKSA9PiBQcm9taXNlPFVpbnQ4QXJyYXk+YCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgeyBzR0luLCBuUG9pbnRzLCBzU2NhbGFyIH0gPSBnZW9tZXRyeSh0b3RhbEJhc2VzQnl0ZXMsIGJ1ZmZTY2FsYXJzLCBcImFmZmluZVwiKTtcbiAgICAgICAgcmV0dXJuIF9tdWx0aUV4cERpc3BhdGNoKGJhc2VzUmVhZGVyLCBidWZmU2NhbGFycywgblBvaW50cywgc0dJbiwgc1NjYWxhciwgXCJhZmZpbmVcIiwgdG0uY29uY3VycmVuY3kgKyAyLCBiYXRjaE1vZGVPZihvcHRpb25zKSwgZW5kb09mKG9wdGlvbnMpLCBsb2dnZXIsIGxvZ1RleHQpO1xuICAgIH07XG59XG5cbmZ1bmN0aW9uIGJ1aWxkRkZUKGN1cnZlLCBncm91cE5hbWUpIHtcbiAgICBjb25zdCBHID0gY3VydmVbZ3JvdXBOYW1lXTtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgIGNvbnN0IHRtID0gRy50bTtcblxuICAgIC8vIEluLXBsYWNlIGJpdC1yZXZlcnNhbCBwZXJtdXRhdGlvbiBpbiBhIHdvcmtlci4gVGhlIGJ1ZmZlciBpcyB0cmFuc2ZlcnJlZFxuICAgIC8vIGluLCByZXZlcnNlZCB3aGVyZSBpdCBsaWVzIHZpYSBwbGFpbiB0eXBlZC1hcnJheSBsYW5lIHN3YXBzIChubyBXQVNNXG4gICAgLy8gbGluZWFyIG1lbW9yeSBncm93biwgbm90aGluZyBhbGxvY2F0ZWQpLCBhbmQgdHJhbnNmZXJyZWQgYmFjay4gQm90aFxuICAgIC8vIHRyYW5zZmVycyBhcmUgcG9pbnRlciBtb3Zlcywgc28gdGhpcyBpcyB6ZXJvLWNvcHkuIFRoZSBzd2FwIGlzXG4gICAgLy8gbWVtb3J5LWJhbmR3aWR0aCBib3VuZCwgc28gYSBzaW5nbGUgd29ya2VyIGlzIGFzIGZhc3QgYXMgc3BsaXR0aW5nIGFjcm9zc1xuICAgIC8vIG1hbnkg4oCUIHdoaWNoIGlzIHdoeSBubyBTaGFyZWRBcnJheUJ1ZmZlciBpcyBuZWVkZWQgKG9ubHkgY29uY3VycmVudFxuICAgIC8vIG11bHRpLXdvcmtlciBhY2Nlc3MgdG8gb25lIGJ1ZmZlciB3b3VsZCByZXF1aXJlIHRoYXQpLlxuICAgIGFzeW5jIGZ1bmN0aW9uIF9yZXZlcnNlUGVybXV0YXRpb24oYnVmZiwgc0luLCBiaXRzKSB7XG4gICAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IHRtLnF1ZXVlQWN0aW9uKFxuICAgICAgICAgICAgW3tjbWQ6IFwiUkVWRVJTRVwiLCBzcmM6IGJ1ZmYsIHNJbiwgYml0c31dLFxuICAgICAgICAgICAgW2J1ZmYuYnVmZmVyXSAgIC8vIHRyYW5zZmVyIGluOyByZXZlcnNlZCBpbiBwbGFjZSBhbmQgdHJhbnNmZXJyZWQgYmFja1xuICAgICAgICApO1xuICAgICAgICByZXR1cm4gcmVzWzBdO1xuICAgIH1cblxuICAgIC8vIGBjb25zdW1lYDogd2hlbiB0cnVlIHRoZSBjYWxsZXIgY2VkZXMgb3duZXJzaGlwIG9mIGBidWZmYCAtLSB3ZSBza2lwIHRoZVxuICAgIC8vIGRlZmVuc2l2ZSBmdWxsLWNvcHkgYmVsb3cgYW5kIHJldmVyc2UvdHJhbnNmZXIgdGhlIGNhbGxlcidzIGJ1ZmZlciBpbiBwbGFjZVxuICAgIC8vIChpdHMgYmFja2luZyBBcnJheUJ1ZmZlciBpcyBkZXRhY2hlZCBhcyBhIHJlc3VsdCkuIE9ubHkgcGFzcyBpdCB3aGVuIHRoZVxuICAgIC8vIGlucHV0IGlzIGRpc2NhcmRlZCByaWdodCBhZnRlciB0aGUgY2FsbCAoZS5nLiB0aGUgZ3JvdGgxNiBJRkZULT5hcHBseUtleS0+RkZUXG4gICAgLy8gcGlwZWxpbmUpLiBEZWZhdWx0IGZhbHNlIHByZXNlcnZlcyB0aGUgaW5wdXQuXG4gICAgYXN5bmMgZnVuY3Rpb24gX2ZmdChidWZmLCBpbnZlcnNlLCBpblR5cGUsIG91dFR5cGUsIGxvZ2dlciwgbG9nZ2VyVHh0LCBjb25zdW1lKSB7XG5cbiAgICAgICAgaW5UeXBlID0gaW5UeXBlIHx8IFwiYWZmaW5lXCI7XG4gICAgICAgIG91dFR5cGUgPSBvdXRUeXBlIHx8IFwiYWZmaW5lXCI7XG4gICAgICAgIGNvbnN0IE1BWF9CSVRTX1RIUkVBRCA9IDE0O1xuXG4gICAgICAgIGxldCBzSW4sIHNNaWQsIHNPdXQsIGZuSW4yTWlkLCBmbk1pZDJPdXQsIGZuRkZUTWl4LCBmbkZGVEpvaW4sIGZuRkZURmluYWw7XG4gICAgICAgIGlmIChncm91cE5hbWUgPT0gXCJHMVwiKSB7XG4gICAgICAgICAgICBpZiAoaW5UeXBlID09IFwiYWZmaW5lXCIpIHtcbiAgICAgICAgICAgICAgICBzSW4gPSBHLkYubjgqMjtcbiAgICAgICAgICAgICAgICBmbkluMk1pZCA9IFwiZzFtX2JhdGNoVG9KYWNvYmlhblwiO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzSW4gPSBHLkYubjgqMztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNNaWQgPSBHLkYubjgqMztcbiAgICAgICAgICAgIGlmIChpbnZlcnNlKSB7XG4gICAgICAgICAgICAgICAgZm5GRlRGaW5hbCA9IFwiZzFtX2ZmdEZpbmFsXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmbkZGVEpvaW4gPSBcImcxbV9mZnRKb2luXCI7XG4gICAgICAgICAgICBmbkZGVE1peCA9IFwiZzFtX2ZmdE1peFwiO1xuXG4gICAgICAgICAgICBpZiAob3V0VHlwZSA9PSBcImFmZmluZVwiKSB7XG4gICAgICAgICAgICAgICAgc091dCA9IEcuRi5uOCoyO1xuICAgICAgICAgICAgICAgIGZuTWlkMk91dCA9IFwiZzFtX2JhdGNoVG9BZmZpbmVcIjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc091dCA9IEcuRi5uOCozO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH0gZWxzZSBpZiAoZ3JvdXBOYW1lID09IFwiRzJcIikge1xuICAgICAgICAgICAgaWYgKGluVHlwZSA9PSBcImFmZmluZVwiKSB7XG4gICAgICAgICAgICAgICAgc0luID0gRy5GLm44KjI7XG4gICAgICAgICAgICAgICAgZm5JbjJNaWQgPSBcImcybV9iYXRjaFRvSmFjb2JpYW5cIjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc0luID0gRy5GLm44KjM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzTWlkID0gRy5GLm44KjM7XG4gICAgICAgICAgICBpZiAoaW52ZXJzZSkge1xuICAgICAgICAgICAgICAgIGZuRkZURmluYWwgPSBcImcybV9mZnRGaW5hbFwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm5GRlRKb2luID0gXCJnMm1fZmZ0Sm9pblwiO1xuICAgICAgICAgICAgZm5GRlRNaXggPSBcImcybV9mZnRNaXhcIjtcbiAgICAgICAgICAgIGlmIChvdXRUeXBlID09IFwiYWZmaW5lXCIpIHtcbiAgICAgICAgICAgICAgICBzT3V0ID0gRy5GLm44KjI7XG4gICAgICAgICAgICAgICAgZm5NaWQyT3V0ID0gXCJnMm1fYmF0Y2hUb0FmZmluZVwiO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzT3V0ID0gRy5GLm44KjM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZ3JvdXBOYW1lID09IFwiRnJcIikge1xuICAgICAgICAgICAgc0luID0gRy5uODtcbiAgICAgICAgICAgIHNNaWQgPSBHLm44O1xuICAgICAgICAgICAgc091dCA9IEcubjg7XG4gICAgICAgICAgICBpZiAoaW52ZXJzZSkge1xuICAgICAgICAgICAgICAgIGZuRkZURmluYWwgPSBcImZybV9mZnRGaW5hbFwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm5GRlRNaXggPSBcImZybV9mZnRNaXhcIjtcbiAgICAgICAgICAgIGZuRkZUSm9pbiA9IFwiZnJtX2ZmdEpvaW5cIjtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgbGV0IHJldHVybkFycmF5ID0gZmFsc2U7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGJ1ZmYpKSB7XG4gICAgICAgICAgICBidWZmID0gYXJyYXkyYnVmZmVyKGJ1ZmYsIHNJbik7XG4gICAgICAgICAgICByZXR1cm5BcnJheSA9IHRydWU7XG4gICAgICAgIH0gZWxzZSBpZiAoIWNvbnN1bWUgfHwgIUFycmF5QnVmZmVyLmlzVmlldyhidWZmKSkge1xuICAgICAgICAgICAgLy8gRGVmZW5zaXZlIGNvcHk6IHRoZSBiaXQtcmV2ZXJzYWwgcnVucyBpbiBwbGFjZSBhbmQgY2h1bmtzIGFyZVxuICAgICAgICAgICAgLy8gdHJhbnNmZXJyZWQsIHNvIHdpdGhvdXQgY29uc3VtZSB3ZSBtdXN0IG5vdCB0b3VjaCB0aGUgY2FsbGVyJ3MgYnVmZmVyLlxuICAgICAgICAgICAgLy8gSXQgYWxzbyBmbGF0dGVucyBhIEJpZ0J1ZmZlciAobm8gc2luZ2xlIC5idWZmZXIgdG8gdHJhbnNmZXIpIHRvIGFcbiAgICAgICAgICAgIC8vIFVpbnQ4QXJyYXksIHNvIGNvbnN1bWUgY2FuIG9ubHkgYmUgaG9ub3VyZWQgZm9yIGFuIEFycmF5QnVmZmVyIHZpZXcuXG4gICAgICAgICAgICBidWZmID0gYnVmZi5zbGljZSgwLCBidWZmLmJ5dGVMZW5ndGgpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgblBvaW50cyA9IGJ1ZmYuYnl0ZUxlbmd0aCAvIHNJbjtcbiAgICAgICAgY29uc3QgYml0cyA9IGxvZzIoblBvaW50cyk7XG5cbiAgICAgICAgaWYgICgoMSA8PCBiaXRzKSAhPSBuUG9pbnRzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJmZnQgbXVzdCBiZSBtdWx0aXBsZSBvZiAyXCIgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChiaXRzID09IEZyLnMgKzEpIHtcbiAgICAgICAgICAgIGxldCBidWZmT3V0O1xuXG4gICAgICAgICAgICBpZiAoaW52ZXJzZSkge1xuICAgICAgICAgICAgICAgIGJ1ZmZPdXQgPSAgYXdhaXQgX2ZmdEV4dEludihidWZmLCBpblR5cGUsIG91dFR5cGUsIGxvZ2dlciwgbG9nZ2VyVHh0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYnVmZk91dCA9ICBhd2FpdCBfZmZ0RXh0KGJ1ZmYsIGluVHlwZSwgb3V0VHlwZSwgbG9nZ2VyLCBsb2dnZXJUeHQpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAocmV0dXJuQXJyYXkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYnVmZmVyMmFycmF5KGJ1ZmZPdXQsIHNPdXQpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYnVmZk91dDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBpbnY7XG4gICAgICAgIGlmIChpbnZlcnNlKSB7XG4gICAgICAgICAgICBpbnYgPSBGci5pbnYoRnIuZShuUG9pbnRzKSk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgYnVmZk91dDtcblxuICAgICAgICAvLyBCaXQtcmV2ZXJzYWwgcGVybXV0YXRpb24uIExpa2UgdGhlIG9sZCBwdXJlLUpTIGJ1ZmZSZXZlcnNlQml0cywgdGhpcyBpc1xuICAgICAgICAvLyBqdXN0IGEgcGVybXV0YXRpb24gb2YgZml4ZWQtc2l6ZSAoc0luLWJ5dGUpIGVsZW1lbnRzIGFuZCB3b3JrcyBmb3IgYW55XG4gICAgICAgIC8vIGVsZW1lbnQgc2l6ZSwgc28gaXQgY292ZXJzIEZyLCBHMSBhbmQgRzIgYWxpa2UuIFJldmVyc2VkIGluIHBsYWNlIGluIGFcbiAgICAgICAgLy8gd29ya2VyIHZpYSB0eXBlZC1hcnJheSBzd2FwcyDigJQgbm8gV0FTTSBsaW5lYXIgbWVtb3J5IGdyb3duLCBub3RoaW5nXG4gICAgICAgIC8vIGFsbG9jYXRlZC4gKFRoZSBwcmV2aW91cyBXQVNNIF9fcmV2ZXJzZVBlcm11dGF0aW9uIHN3YXBwZWQgbjhnLXNpemVkXG4gICAgICAgIC8vIGVsZW1lbnRzIHJhdGhlciB0aGFuIHNJbi1zaXplZCBvbmVzLCB3aGljaCB3YXMgd3Jvbmcgd2hlbmV2ZXJcbiAgICAgICAgLy8gc0luICE9IG44ZywgZS5nLiBhZmZpbmUtaW5wdXQgRzEvRzIgRkZUcy4pXG4gICAgICAgIGJ1ZmYgPSBhd2FpdCBfcmV2ZXJzZVBlcm11dGF0aW9uKGJ1ZmYsIHNJbiwgYml0cyk7XG5cbiAgICAgICAgbGV0IGNodW5rcztcbiAgICAgICAgbGV0IHBvaW50c0luQ2h1bmsgPSBNYXRoLm1pbigxIDw8IE1BWF9CSVRTX1RIUkVBRCwgblBvaW50cyk7XG4gICAgICAgIGxldCBuQ2h1bmtzID0gblBvaW50cyAvIHBvaW50c0luQ2h1bms7XG5cbiAgICAgICAgd2hpbGUgKChuQ2h1bmtzIDwgdG0uY29uY3VycmVuY3kpJiYocG9pbnRzSW5DaHVuaz49MTYpKSB7XG4gICAgICAgICAgICBuQ2h1bmtzICo9IDI7XG4gICAgICAgICAgICBwb2ludHNJbkNodW5rIC89IDI7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBsMkNodW5rID0gbG9nMihwb2ludHNJbkNodW5rKTtcblxuICAgICAgICBjb25zdCBwcm9taXNlcyA9IFtdO1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYCR7bG9nZ2VyVHh0fTogZmZ0ICR7Yml0c30gbWl4IHN0YXJ0OiAke25DaHVua3N9YCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpPCBuQ2h1bmtzOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IHRhc2sgPSBbXTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DXCIsIHZhcjogMCwgbGVuOiBzTWlkKnBvaW50c0luQ2h1bmt9KTtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZDaHVuayA9IGJ1ZmYuc2xpY2UoIChwb2ludHNJbkNodW5rICogaSkqc0luLCAocG9pbnRzSW5DaHVuayAqIChpKzEpKSpzSW4pO1xuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiU0VUXCIsIHZhcjogMCwgYnVmZjogYnVmZkNodW5rfSk7XG4gICAgICAgICAgICBpZiAoZm5JbjJNaWQpIHtcbiAgICAgICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJDQUxMXCIsIGZuTmFtZTpmbkluMk1pZCwgcGFyYW1zOiBbe3ZhcjowfSwge3ZhbDogcG9pbnRzSW5DaHVua30sIHt2YXI6IDB9XX0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChsZXQgaj0xOyBqPD1sMkNodW5rO2orKykge1xuICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkNBTExcIiwgZm5OYW1lOmZuRkZUTWl4LCBwYXJhbXM6IFt7dmFyOjB9LCB7dmFsOiBwb2ludHNJbkNodW5rfSwge3ZhbDogan1dfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChsMkNodW5rPT1iaXRzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGZuRkZURmluYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAxLCBidWZmOiBpbnZ9KTtcbiAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IGZuRkZURmluYWwsICBwYXJhbXM6W1xuICAgICAgICAgICAgICAgICAgICAgICAge3ZhcjogMH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFsOiBwb2ludHNJbkNodW5rfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHt2YXI6IDF9LFxuICAgICAgICAgICAgICAgICAgICBdfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChmbk1pZDJPdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6Zm5NaWQyT3V0LCBwYXJhbXM6IFt7dmFyOjB9LCB7dmFsOiBwb2ludHNJbkNodW5rfSwge3ZhcjogMH1dfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkdFVFwiLCBvdXQ6IDAsIHZhcjogMCwgbGVuOiBwb2ludHNJbkNodW5rKnNPdXR9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDowLCB2YXI6IDAsIGxlbjogc01pZCpwb2ludHNJbkNodW5rfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBwcm9taXNlcy5wdXNoKHRtLnF1ZXVlQWN0aW9uKHRhc2ssIFtidWZmQ2h1bmsuYnVmZmVyXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgY2h1bmtzID0gYXdhaXQgUHJvbWlzZS5hbGwocHJvbWlzZXMpO1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYCR7bG9nZ2VyVHh0fTogZmZ0ICR7Yml0c30gbWl4IGVuZDogJHtuQ2h1bmtzfWApO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaTwgbkNodW5rczsgaSsrKSBjaHVua3NbaV0gPSBjaHVua3NbaV1bMF07XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IGwyQ2h1bmsrMTsgICBpPD1iaXRzOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgJHtsb2dnZXJUeHR9OiBmZnQgJHtiaXRzfSBqb2luOiAke2l9LyR7Yml0c31gKTtcbiAgICAgICAgICAgIGNvbnN0IG5Hcm91cHMgPSAxIDw8IChiaXRzIC0gaSk7XG4gICAgICAgICAgICBjb25zdCBuQ2h1bmtzUGVyR3JvdXAgPSBuQ2h1bmtzIC8gbkdyb3VwcztcbiAgICAgICAgICAgIGNvbnN0IG9wUHJvbWlzZXMgPSBbXTtcbiAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxuR3JvdXBzOyBqKyspIHtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBrPTA7IGsgPG5DaHVua3NQZXJHcm91cC8yOyBrKyspIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZmlyc3QgPSBGci5leHAoIEZyLndbaV0sIGsqcG9pbnRzSW5DaHVuayk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGluYyA9IEZyLndbaV07XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG8xID0gaipuQ2h1bmtzUGVyR3JvdXAgKyBrO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBvMiA9IGoqbkNodW5rc1Blckdyb3VwICsgayArIG5DaHVua3NQZXJHcm91cC8yO1xuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRhc2sgPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAwLCBidWZmOiBjaHVua3NbbzFdfSk7XG4gICAgICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMSwgYnVmZjogY2h1bmtzW28yXX0pO1xuICAgICAgICAgICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDIsIGJ1ZmY6IGZpcnN0fSk7XG4gICAgICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMywgYnVmZjogaW5jfSk7XG4gICAgICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkNBTExcIiwgZm5OYW1lOiBmbkZGVEpvaW4sICBwYXJhbXM6W1xuICAgICAgICAgICAgICAgICAgICAgICAge3ZhcjogMH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFyOiAxfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHt2YWw6IHBvaW50c0luQ2h1bmt9LFxuICAgICAgICAgICAgICAgICAgICAgICAge3ZhcjogMn0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFyOiAzfVxuICAgICAgICAgICAgICAgICAgICBdfSk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpPT1iaXRzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZm5GRlRGaW5hbCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogNCwgYnVmZjogaW52fSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IGZuRkZURmluYWwsICBwYXJhbXM6W1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7dmFyOiAwfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3ZhbDogcG9pbnRzSW5DaHVua30sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt2YXI6IDR9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF19KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJDQUxMXCIsIGZuTmFtZTogZm5GRlRGaW5hbCwgIHBhcmFtczpbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt2YXI6IDF9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7dmFsOiBwb2ludHNJbkNodW5rfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3ZhcjogNH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXX0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGZuTWlkMk91dCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkNBTExcIiwgZm5OYW1lOmZuTWlkMk91dCwgcGFyYW1zOiBbe3ZhcjowfSwge3ZhbDogcG9pbnRzSW5DaHVua30sIHt2YXI6IDB9XX0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkNBTExcIiwgZm5OYW1lOmZuTWlkMk91dCwgcGFyYW1zOiBbe3ZhcjoxfSwge3ZhbDogcG9pbnRzSW5DaHVua30sIHt2YXI6IDF9XX0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDogMCwgdmFyOiAwLCBsZW46IHBvaW50c0luQ2h1bmsqc091dH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDogMSwgdmFyOiAxLCBsZW46IHBvaW50c0luQ2h1bmsqc091dH0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDogMCwgdmFyOiAwLCBsZW46IHBvaW50c0luQ2h1bmsqc01pZH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDogMSwgdmFyOiAxLCBsZW46IHBvaW50c0luQ2h1bmsqc01pZH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIG9wUHJvbWlzZXMucHVzaCh0bS5xdWV1ZUFjdGlvbih0YXNrLCBbY2h1bmtzW28xXS5idWZmZXIsIGNodW5rc1tvMl0uYnVmZmVyLCBmaXJzdC5idWZmZXIgXSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgUHJvbWlzZS5hbGwob3BQcm9taXNlcyk7XG4gICAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8bkdyb3VwczsgaisrKSB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaz0wOyBrIDxuQ2h1bmtzUGVyR3JvdXAvMjsgaysrKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG8xID0gaipuQ2h1bmtzUGVyR3JvdXAgKyBrO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBvMiA9IGoqbkNodW5rc1Blckdyb3VwICsgayArIG5DaHVua3NQZXJHcm91cC8yO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCByZXNDaHVuayA9IHJlcy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgICAgICBjaHVua3NbbzFdID0gcmVzQ2h1bmtbMF07XG4gICAgICAgICAgICAgICAgICAgIGNodW5rc1tvMl0gPSByZXNDaHVua1sxXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYnVmZiBpbnN0YW5jZW9mIEJpZ0J1ZmZlcikge1xuICAgICAgICAgICAgYnVmZk91dCA9IG5ldyBCaWdCdWZmZXIoblBvaW50cypzT3V0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGJ1ZmZPdXQgPSBuZXcgVWludDhBcnJheShuUG9pbnRzKnNPdXQpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChpbnZlcnNlKSB7XG4gICAgICAgICAgICBidWZmT3V0LnNldChjaHVua3NbMF0uc2xpY2UoKHBvaW50c0luQ2h1bmstMSkqc091dCkpO1xuICAgICAgICAgICAgbGV0IHA9IHNPdXQ7XG4gICAgICAgICAgICBmb3IgKGxldCBpPW5DaHVua3MtMTsgaT4wOyBpLS0pIHtcbiAgICAgICAgICAgICAgICBidWZmT3V0LnNldChjaHVua3NbaV0sIHApO1xuICAgICAgICAgICAgICAgIHAgKz0gcG9pbnRzSW5DaHVuaypzT3V0O1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBjaHVua3NbaV07ICAvLyBMaWJlcmF0ZSBtZW1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJ1ZmZPdXQuc2V0KGNodW5rc1swXS5zbGljZSgwLCAocG9pbnRzSW5DaHVuay0xKSpzT3V0KSwgcCk7XG4gICAgICAgICAgICBkZWxldGUgY2h1bmtzWzBdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpPG5DaHVua3M7IGkrKykge1xuICAgICAgICAgICAgICAgIGJ1ZmZPdXQuc2V0KGNodW5rc1tpXSwgcG9pbnRzSW5DaHVuaypzT3V0KmkpO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBjaHVua3NbaV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocmV0dXJuQXJyYXkpIHtcbiAgICAgICAgICAgIHJldHVybiBidWZmZXIyYXJyYXkoYnVmZk91dCwgc091dCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gYnVmZk91dDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIF9mZnRFeHQoYnVmZiwgaW5UeXBlLCBvdXRUeXBlLCBsb2dnZXIsIGxvZ2dlclR4dCkge1xuICAgICAgICBsZXQgYjEsIGIyO1xuICAgICAgICBiMSA9IGJ1ZmYuc2xpY2UoIDAgLCBidWZmLmJ5dGVMZW5ndGgvMik7XG4gICAgICAgIGIyID0gYnVmZi5zbGljZSggYnVmZi5ieXRlTGVuZ3RoLzIsIGJ1ZmYuYnl0ZUxlbmd0aCk7XG5cbiAgICAgICAgY29uc3QgcHJvbWlzZXMgPSBbXTtcblxuICAgICAgICBbYjEsIGIyXSA9IGF3YWl0IF9mZnRKb2luRXh0KGIxLCBiMiwgXCJmZnRKb2luRXh0XCIsIEZyLm9uZSwgRnIuc2hpZnQsIGluVHlwZSwgXCJqYWNvYmlhblwiLCBsb2dnZXIsIGxvZ2dlclR4dCk7XG5cbiAgICAgICAgcHJvbWlzZXMucHVzaCggX2ZmdChiMSwgZmFsc2UsIFwiamFjb2JpYW5cIiwgb3V0VHlwZSwgbG9nZ2VyLCBsb2dnZXJUeHQpKTtcbiAgICAgICAgcHJvbWlzZXMucHVzaCggX2ZmdChiMiwgZmFsc2UsIFwiamFjb2JpYW5cIiwgb3V0VHlwZSwgbG9nZ2VyLCBsb2dnZXJUeHQpKTtcblxuICAgICAgICBjb25zdCByZXMxID0gYXdhaXQgUHJvbWlzZS5hbGwocHJvbWlzZXMpO1xuXG4gICAgICAgIGxldCBidWZmT3V0O1xuICAgICAgICBpZiAocmVzMVswXS5ieXRlTGVuZ3RoID4gKDE8PDI4KSkge1xuICAgICAgICAgICAgYnVmZk91dCA9IG5ldyBCaWdCdWZmZXIocmVzMVswXS5ieXRlTGVuZ3RoKjIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYnVmZk91dCA9IG5ldyBVaW50OEFycmF5KHJlczFbMF0uYnl0ZUxlbmd0aCoyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGJ1ZmZPdXQuc2V0KHJlczFbMF0pO1xuICAgICAgICBidWZmT3V0LnNldChyZXMxWzFdLCByZXMxWzBdLmJ5dGVMZW5ndGgpO1xuXG4gICAgICAgIHJldHVybiBidWZmT3V0O1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIF9mZnRFeHRJbnYoYnVmZiwgaW5UeXBlLCBvdXRUeXBlLCBsb2dnZXIsIGxvZ2dlclR4dCkge1xuICAgICAgICBsZXQgYjEsIGIyO1xuICAgICAgICBiMSA9IGJ1ZmYuc2xpY2UoIDAgLCBidWZmLmJ5dGVMZW5ndGgvMik7XG4gICAgICAgIGIyID0gYnVmZi5zbGljZSggYnVmZi5ieXRlTGVuZ3RoLzIsIGJ1ZmYuYnl0ZUxlbmd0aCk7XG5cbiAgICAgICAgY29uc3QgcHJvbWlzZXMgPSBbXTtcblxuICAgICAgICBwcm9taXNlcy5wdXNoKCBfZmZ0KGIxLCB0cnVlLCBpblR5cGUsIFwiamFjb2JpYW5cIiwgbG9nZ2VyLCBsb2dnZXJUeHQpKTtcbiAgICAgICAgcHJvbWlzZXMucHVzaCggX2ZmdChiMiwgdHJ1ZSwgaW5UeXBlLCBcImphY29iaWFuXCIsIGxvZ2dlciwgbG9nZ2VyVHh0KSk7XG5cbiAgICAgICAgW2IxLCBiMl0gPSBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcyk7XG5cbiAgICAgICAgY29uc3QgcmVzMSA9IGF3YWl0IF9mZnRKb2luRXh0KGIxLCBiMiwgXCJmZnRKb2luRXh0SW52XCIsIEZyLm9uZSwgRnIuc2hpZnRJbnYsIFwiamFjb2JpYW5cIiwgb3V0VHlwZSwgbG9nZ2VyLCBsb2dnZXJUeHQpO1xuXG4gICAgICAgIGxldCBidWZmT3V0O1xuICAgICAgICBpZiAocmVzMVswXS5ieXRlTGVuZ3RoID4gKDE8PDI4KSkge1xuICAgICAgICAgICAgYnVmZk91dCA9IG5ldyBCaWdCdWZmZXIocmVzMVswXS5ieXRlTGVuZ3RoKjIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYnVmZk91dCA9IG5ldyBVaW50OEFycmF5KHJlczFbMF0uYnl0ZUxlbmd0aCoyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGJ1ZmZPdXQuc2V0KHJlczFbMF0pO1xuICAgICAgICBidWZmT3V0LnNldChyZXMxWzFdLCByZXMxWzBdLmJ5dGVMZW5ndGgpO1xuXG4gICAgICAgIHJldHVybiBidWZmT3V0O1xuICAgIH1cblxuXG4gICAgYXN5bmMgZnVuY3Rpb24gX2ZmdEpvaW5FeHQoYnVmZjEsIGJ1ZmYyLCBmbiwgZmlyc3QsIGluYywgaW5UeXBlLCBvdXRUeXBlLCBsb2dnZXIsIGxvZ2dlclR4dCkge1xuICAgICAgICBjb25zdCBNQVhfQ0hVTktfU0laRSA9IDE8PDE2O1xuICAgICAgICBjb25zdCBNSU5fQ0hVTktfU0laRSA9IDE8PDQ7XG5cbiAgICAgICAgbGV0IGZuTmFtZTtcbiAgICAgICAgbGV0IGZuSW4yTWlkLCBmbk1pZDJPdXQ7XG4gICAgICAgIGxldCBzT3V0LCBzSW4sIHNNaWQ7XG5cbiAgICAgICAgaWYgKGdyb3VwTmFtZSA9PSBcIkcxXCIpIHtcbiAgICAgICAgICAgIGlmIChpblR5cGUgPT0gXCJhZmZpbmVcIikge1xuICAgICAgICAgICAgICAgIHNJbiA9IEcuRi5uOCoyO1xuICAgICAgICAgICAgICAgIGZuSW4yTWlkID0gXCJnMW1fYmF0Y2hUb0phY29iaWFuXCI7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNJbiA9IEcuRi5uOCozO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc01pZCA9IEcuRi5uOCozO1xuICAgICAgICAgICAgZm5OYW1lID0gXCJnMW1fXCIrZm47XG4gICAgICAgICAgICBpZiAob3V0VHlwZSA9PSBcImFmZmluZVwiKSB7XG4gICAgICAgICAgICAgICAgZm5NaWQyT3V0ID0gXCJnMW1fYmF0Y2hUb0FmZmluZVwiO1xuICAgICAgICAgICAgICAgIHNPdXQgPSBHLkYubjgqMjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc091dCA9IEcuRi5uOCozO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGdyb3VwTmFtZSA9PSBcIkcyXCIpIHtcbiAgICAgICAgICAgIGlmIChpblR5cGUgPT0gXCJhZmZpbmVcIikge1xuICAgICAgICAgICAgICAgIHNJbiA9IEcuRi5uOCoyO1xuICAgICAgICAgICAgICAgIGZuSW4yTWlkID0gXCJnMm1fYmF0Y2hUb0phY29iaWFuXCI7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNJbiA9IEcuRi5uOCozO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm5OYW1lID0gXCJnMm1fXCIrZm47XG4gICAgICAgICAgICBzTWlkID0gRy5GLm44KjM7XG4gICAgICAgICAgICBpZiAob3V0VHlwZSA9PSBcImFmZmluZVwiKSB7XG4gICAgICAgICAgICAgICAgZm5NaWQyT3V0ID0gXCJnMm1fYmF0Y2hUb0FmZmluZVwiO1xuICAgICAgICAgICAgICAgIHNPdXQgPSBHLkYubjgqMjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc091dCA9IEcuRi5uOCozO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGdyb3VwTmFtZSA9PSBcIkZyXCIpIHtcbiAgICAgICAgICAgIHNJbiA9IEZyLm44O1xuICAgICAgICAgICAgc091dCA9IEZyLm44O1xuICAgICAgICAgICAgc01pZCA9IEZyLm44O1xuICAgICAgICAgICAgZm5OYW1lID0gXCJmcm1fXCIgKyBmbjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgZ3JvdXBcIik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYnVmZjEuYnl0ZUxlbmd0aCAhPSBidWZmMi5ieXRlTGVuZ3RoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGJ1ZmZlciBzaXplXCIpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG5Qb2ludHMgPSBNYXRoLmZsb29yKGJ1ZmYxLmJ5dGVMZW5ndGggLyBzSW4pO1xuICAgICAgICBpZiAoblBvaW50cyAhPSAxIDw8IGxvZzIoblBvaW50cykpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgbnVtYmVyIG9mIHBvaW50c1wiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBjaHVua1NpemUgPSBNYXRoLmZsb29yKG5Qb2ludHMgL3RtLmNvbmN1cnJlbmN5KTtcbiAgICAgICAgaWYgKGNodW5rU2l6ZSA8IE1JTl9DSFVOS19TSVpFKSBjaHVua1NpemUgPSBNSU5fQ0hVTktfU0laRTtcbiAgICAgICAgaWYgKGNodW5rU2l6ZSA+IE1BWF9DSFVOS19TSVpFKSBjaHVua1NpemUgPSBNQVhfQ0hVTktfU0laRTtcblxuICAgICAgICBjb25zdCBvcFByb21pc2VzID0gW107XG5cbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPG5Qb2ludHM7IGkgKz0gY2h1bmtTaXplKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYCR7bG9nZ2VyVHh0fTogZmZ0Sm9pbkV4dCBTdGFydDogJHtpfS8ke25Qb2ludHN9YCk7XG4gICAgICAgICAgICBjb25zdCBuPSBNYXRoLm1pbihuUG9pbnRzIC0gaSwgY2h1bmtTaXplKTtcblxuICAgICAgICAgICAgY29uc3QgZmlyc3RDaHVuayA9IEZyLm11bChmaXJzdCwgRnIuZXhwKCBpbmMsIGkpKTtcbiAgICAgICAgICAgIGNvbnN0IHRhc2sgPSBbXTtcblxuICAgICAgICAgICAgY29uc3QgYjEgPSBidWZmMS5zbGljZShpKnNJbiwgKGkrbikqc0luKTtcbiAgICAgICAgICAgIGNvbnN0IGIyID0gYnVmZjIuc2xpY2UoaSpzSW4sIChpK24pKnNJbik7XG5cbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DXCIsIHZhcjogMCwgbGVuOiBzTWlkKm59KTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIlNFVFwiLCB2YXI6IDAsIGJ1ZmY6IGIxfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1wiLCB2YXI6IDEsIGxlbjogc01pZCpufSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJTRVRcIiwgdmFyOiAxLCBidWZmOiBiMn0pO1xuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAyLCBidWZmOiBmaXJzdENodW5rfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDMsIGJ1ZmY6IGluY30pO1xuICAgICAgICAgICAgaWYgKGZuSW4yTWlkKSB7XG4gICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6Zm5JbjJNaWQsIHBhcmFtczogW3t2YXI6MH0sIHt2YWw6IG59LCB7dmFyOiAwfV19KTtcbiAgICAgICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJDQUxMXCIsIGZuTmFtZTpmbkluMk1pZCwgcGFyYW1zOiBbe3ZhcjoxfSwge3ZhbDogbn0sIHt2YXI6IDF9XX0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IGZuTmFtZSwgcGFyYW1zOiBbXG4gICAgICAgICAgICAgICAge3ZhcjogMH0sXG4gICAgICAgICAgICAgICAge3ZhcjogMX0sXG4gICAgICAgICAgICAgICAge3ZhbDogbn0sXG4gICAgICAgICAgICAgICAge3ZhcjogMn0sXG4gICAgICAgICAgICAgICAge3ZhcjogM30sXG4gICAgICAgICAgICAgICAge3ZhbDogRnIuc30sXG4gICAgICAgICAgICBdfSk7XG4gICAgICAgICAgICBpZiAoZm5NaWQyT3V0KSB7XG4gICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6Zm5NaWQyT3V0LCBwYXJhbXM6IFt7dmFyOjB9LCB7dmFsOiBufSwge3ZhcjogMH1dfSk7XG4gICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6Zm5NaWQyT3V0LCBwYXJhbXM6IFt7dmFyOjF9LCB7dmFsOiBufSwge3ZhcjogMX1dfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJHRVRcIiwgb3V0OiAwLCB2YXI6IDAsIGxlbjogbipzT3V0fSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJHRVRcIiwgb3V0OiAxLCB2YXI6IDEsIGxlbjogbipzT3V0fSk7XG4gICAgICAgICAgICBvcFByb21pc2VzLnB1c2goXG4gICAgICAgICAgICAgICAgdG0ucXVldWVBY3Rpb24odGFzaywgW2IxLmJ1ZmZlciwgYjIuYnVmZmVyLCBmaXJzdENodW5rLmJ1ZmZlcl0pLnRoZW4oKHIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGAke2xvZ2dlclR4dH06IGZmdEpvaW5FeHQgRW5kOiAke2l9LyR7blBvaW50c31gKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHI7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBQcm9taXNlLmFsbChvcFByb21pc2VzKTtcblxuICAgICAgICBsZXQgZnVsbEJ1ZmZPdXQxO1xuICAgICAgICBsZXQgZnVsbEJ1ZmZPdXQyO1xuICAgICAgICBpZiAoblBvaW50cyAqIHNPdXQgPiAxPDwyOCkge1xuICAgICAgICAgICAgZnVsbEJ1ZmZPdXQxID0gbmV3IEJpZ0J1ZmZlcihuUG9pbnRzKnNPdXQpO1xuICAgICAgICAgICAgZnVsbEJ1ZmZPdXQyID0gbmV3IEJpZ0J1ZmZlcihuUG9pbnRzKnNPdXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZnVsbEJ1ZmZPdXQxID0gbmV3IFVpbnQ4QXJyYXkoblBvaW50cypzT3V0KTtcbiAgICAgICAgICAgIGZ1bGxCdWZmT3V0MiA9IG5ldyBVaW50OEFycmF5KG5Qb2ludHMqc091dCk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgcCA9MDtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHJlc3VsdC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgZnVsbEJ1ZmZPdXQxLnNldChyZXN1bHRbaV1bMF0sIHApO1xuICAgICAgICAgICAgZnVsbEJ1ZmZPdXQyLnNldChyZXN1bHRbaV1bMV0sIHApO1xuICAgICAgICAgICAgcCs9cmVzdWx0W2ldWzBdLmJ5dGVMZW5ndGg7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gW2Z1bGxCdWZmT3V0MSwgZnVsbEJ1ZmZPdXQyXTtcbiAgICB9XG5cblxuICAgIEcuZmZ0ID0gYXN5bmMgZnVuY3Rpb24oYnVmZiwgaW5UeXBlLCBvdXRUeXBlLCBsb2dnZXIsIGxvZ2dlclR4dCwgY29uc3VtZSkge1xuICAgICAgICByZXR1cm4gYXdhaXQgX2ZmdChidWZmLCBmYWxzZSwgaW5UeXBlLCBvdXRUeXBlLCBsb2dnZXIsIGxvZ2dlclR4dCwgY29uc3VtZSk7XG4gICAgfTtcblxuICAgIEcuaWZmdCA9IGFzeW5jIGZ1bmN0aW9uKGJ1ZmYsIGluVHlwZSwgb3V0VHlwZSwgbG9nZ2VyLCBsb2dnZXJUeHQsIGNvbnN1bWUpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IF9mZnQoYnVmZiwgdHJ1ZSwgaW5UeXBlLCBvdXRUeXBlLCBsb2dnZXIsIGxvZ2dlclR4dCwgY29uc3VtZSk7XG4gICAgfTtcblxuICAgIEcubGFncmFuZ2VFdmFsdWF0aW9ucyA9IGFzeW5jIGZ1bmN0aW9uIChidWZmLCBpblR5cGUsIG91dFR5cGUsIGxvZ2dlciwgbG9nZ2VyVHh0KSB7XG4gICAgICAgIGluVHlwZSA9IGluVHlwZSB8fCBcImFmZmluZVwiO1xuICAgICAgICBvdXRUeXBlID0gb3V0VHlwZSB8fCBcImFmZmluZVwiO1xuXG4gICAgICAgIGxldCBzSW47XG4gICAgICAgIGlmIChncm91cE5hbWUgPT0gXCJHMVwiKSB7XG4gICAgICAgICAgICBpZiAoaW5UeXBlID09IFwiYWZmaW5lXCIpIHtcbiAgICAgICAgICAgICAgICBzSW4gPSBHLkYubjgqMjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc0luID0gRy5GLm44KjM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZ3JvdXBOYW1lID09IFwiRzJcIikge1xuICAgICAgICAgICAgaWYgKGluVHlwZSA9PSBcImFmZmluZVwiKSB7XG4gICAgICAgICAgICAgICAgc0luID0gRy5GLm44KjI7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNJbiA9IEcuRi5uOCozO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGdyb3VwTmFtZSA9PSBcIkZyXCIpIHtcbiAgICAgICAgICAgIHNJbiA9IEZyLm44O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBncm91cFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG5Qb2ludHMgPSBidWZmLmJ5dGVMZW5ndGggL3NJbjtcbiAgICAgICAgY29uc3QgYml0cyA9IGxvZzIoblBvaW50cyk7XG5cbiAgICAgICAgaWYgKCgyICoqIGJpdHMpKnNJbiAhPSBidWZmLmJ5dGVMZW5ndGgpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcImxhZ3JhbmdlRXZhbHVhdGlvbnMgaWludmFsaWQgaW5wdXQgc2l6ZVwiKTtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImxhZ3JhbmdlRXZhbHVhdGlvbnMgaW52YWxpZCBJbnB1dCBzaXplXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGJpdHMgPD0gRnIucykge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IEcuaWZmdChidWZmLCBpblR5cGUsIG91dFR5cGUsIGxvZ2dlciwgbG9nZ2VyVHh0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChiaXRzID4gRnIucysxKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJsYWdyYW5nZUV2YWx1YXRpb25zIGlucHV0IHRvbyBiaWdcIik7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJsYWdyYW5nZUV2YWx1YXRpb25zIGlucHV0IHRvbyBiaWdcIik7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgdDAgPSBidWZmLnNsaWNlKDAsIGJ1ZmYuYnl0ZUxlbmd0aC8yKTtcbiAgICAgICAgbGV0IHQxID0gYnVmZi5zbGljZShidWZmLmJ5dGVMZW5ndGgvMiwgYnVmZi5ieXRlTGVuZ3RoKTtcblxuXG4gICAgICAgIGNvbnN0IHNoaWZ0VG9TbWFsbE0gPSBGci5leHAoRnIuc2hpZnQsIG5Qb2ludHMvMik7XG4gICAgICAgIGNvbnN0IHNDb25zdCA9IEZyLmludiggRnIuc3ViKEZyLm9uZSwgc2hpZnRUb1NtYWxsTSkpO1xuXG4gICAgICAgIFt0MCwgdDFdID0gYXdhaXQgX2ZmdEpvaW5FeHQodDAsIHQxLCBcInByZXBhcmVMYWdyYW5nZUV2YWx1YXRpb25cIiwgc0NvbnN0LCBGci5zaGlmdEludiwgaW5UeXBlLCBcImphY29iaWFuXCIsIGxvZ2dlciwgbG9nZ2VyVHh0ICsgXCIgcHJlcFwiKTtcblxuICAgICAgICBjb25zdCBwcm9taXNlcyA9IFtdO1xuXG4gICAgICAgIHByb21pc2VzLnB1c2goIF9mZnQodDAsIHRydWUsIFwiamFjb2JpYW5cIiwgb3V0VHlwZSwgbG9nZ2VyLCBsb2dnZXJUeHQgKyBcIiB0MFwiKSk7XG4gICAgICAgIHByb21pc2VzLnB1c2goIF9mZnQodDEsIHRydWUsIFwiamFjb2JpYW5cIiwgb3V0VHlwZSwgbG9nZ2VyLCBsb2dnZXJUeHQgKyBcIiB0MVwiKSk7XG5cbiAgICAgICAgW3QwLCB0MV0gPSBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcyk7XG5cbiAgICAgICAgbGV0IGJ1ZmZPdXQ7XG4gICAgICAgIGlmICh0MC5ieXRlTGVuZ3RoID4gKDE8PDI4KSkge1xuICAgICAgICAgICAgYnVmZk91dCA9IG5ldyBCaWdCdWZmZXIodDAuYnl0ZUxlbmd0aCoyKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGJ1ZmZPdXQgPSBuZXcgVWludDhBcnJheSh0MC5ieXRlTGVuZ3RoKjIpO1xuICAgICAgICB9XG5cbiAgICAgICAgYnVmZk91dC5zZXQodDApO1xuICAgICAgICBidWZmT3V0LnNldCh0MSwgdDAuYnl0ZUxlbmd0aCk7XG5cbiAgICAgICAgcmV0dXJuIGJ1ZmZPdXQ7XG4gICAgfTtcblxuICAgIEcuZmZ0TWl4ID0gYXN5bmMgZnVuY3Rpb24gZmZ0TWl4KGJ1ZmYpIHtcbiAgICAgICAgY29uc3Qgc0cgPSBHLkYubjgqMztcbiAgICAgICAgbGV0IGZuTmFtZSwgZm5GRlRKb2luO1xuICAgICAgICBpZiAoZ3JvdXBOYW1lID09IFwiRzFcIikge1xuICAgICAgICAgICAgZm5OYW1lID0gXCJnMW1fZmZ0TWl4XCI7XG4gICAgICAgICAgICBmbkZGVEpvaW4gPSBcImcxbV9mZnRKb2luXCI7XG4gICAgICAgIH0gZWxzZSBpZiAoZ3JvdXBOYW1lID09IFwiRzJcIikge1xuICAgICAgICAgICAgZm5OYW1lID0gXCJnMm1fZmZ0TWl4XCI7XG4gICAgICAgICAgICBmbkZGVEpvaW4gPSBcImcybV9mZnRKb2luXCI7XG4gICAgICAgIH0gZWxzZSBpZiAoZ3JvdXBOYW1lID09IFwiRnJcIikge1xuICAgICAgICAgICAgZm5OYW1lID0gXCJmcm1fZmZ0TWl4XCI7XG4gICAgICAgICAgICBmbkZGVEpvaW4gPSBcImZybV9mZnRKb2luXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGdyb3VwXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgblBvaW50cyA9IE1hdGguZmxvb3IoYnVmZi5ieXRlTGVuZ3RoIC8gc0cpO1xuICAgICAgICBjb25zdCBwb3dlciA9IGxvZzIoblBvaW50cyk7XG5cbiAgICAgICAgbGV0IG5DaHVua3MgPSAxIDw8IGxvZzIodG0uY29uY3VycmVuY3kpO1xuXG4gICAgICAgIGlmIChuUG9pbnRzIDw9IG5DaHVua3MqMikgbkNodW5rcyA9IDE7XG5cbiAgICAgICAgY29uc3QgcG9pbnRzUGVyQ2h1bmsgPSBuUG9pbnRzIC8gbkNodW5rcztcblxuICAgICAgICBjb25zdCBwb3dlckNodW5rID0gbG9nMihwb2ludHNQZXJDaHVuayk7XG5cbiAgICAgICAgY29uc3Qgb3BQcm9taXNlcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8bkNodW5rczsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCB0YXNrID0gW107XG4gICAgICAgICAgICBjb25zdCBiID0gYnVmZi5zbGljZSgoaSogcG9pbnRzUGVyQ2h1bmspKnNHLCAoKGkrMSkqIHBvaW50c1BlckNodW5rKSpzRyk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDAsIGJ1ZmY6IGJ9KTtcbiAgICAgICAgICAgIGZvciAobGV0IGo9MTsgajw9cG93ZXJDaHVuazsgaisrKSB7XG4gICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IGZuTmFtZSwgcGFyYW1zOiBbXG4gICAgICAgICAgICAgICAgICAgIHt2YXI6IDB9LFxuICAgICAgICAgICAgICAgICAgICB7dmFsOiBwb2ludHNQZXJDaHVua30sXG4gICAgICAgICAgICAgICAgICAgIHt2YWw6IGp9XG4gICAgICAgICAgICAgICAgXX0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDogMCwgdmFyOiAwLCBsZW46IHBvaW50c1BlckNodW5rKnNHfSk7XG4gICAgICAgICAgICBvcFByb21pc2VzLnB1c2goXG4gICAgICAgICAgICAgICAgdG0ucXVldWVBY3Rpb24odGFzaywgW2IuYnVmZmVyXSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBQcm9taXNlLmFsbChvcFByb21pc2VzKTtcblxuICAgICAgICBjb25zdCBjaHVua3MgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHJlc3VsdC5sZW5ndGg7IGkrKykgY2h1bmtzW2ldID0gcmVzdWx0W2ldWzBdO1xuXG5cbiAgICAgICAgZm9yIChsZXQgaSA9IHBvd2VyQ2h1bmsrMTsgaTw9cG93ZXI7IGkrKykge1xuICAgICAgICAgICAgY29uc3Qgbkdyb3VwcyA9IDEgPDwgKHBvd2VyIC0gaSk7XG4gICAgICAgICAgICBjb25zdCBuQ2h1bmtzUGVyR3JvdXAgPSBuQ2h1bmtzIC8gbkdyb3VwcztcbiAgICAgICAgICAgIGNvbnN0IG9wUHJvbWlzZXMgPSBbXTtcbiAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxuR3JvdXBzOyBqKyspIHtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBrPTA7IGsgPG5DaHVua3NQZXJHcm91cC8yOyBrKyspIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZmlyc3QgPSBGci5leHAoIEZyLndbaV0sIGsqcG9pbnRzUGVyQ2h1bmspO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBpbmMgPSBGci53W2ldO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBvMSA9IGoqbkNodW5rc1Blckdyb3VwICsgaztcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbzIgPSBqKm5DaHVua3NQZXJHcm91cCArIGsgKyBuQ2h1bmtzUGVyR3JvdXAvMjtcblxuICAgICAgICAgICAgICAgICAgICBjb25zdCB0YXNrID0gW107XG4gICAgICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMCwgYnVmZjogY2h1bmtzW28xXX0pO1xuICAgICAgICAgICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDEsIGJ1ZmY6IGNodW5rc1tvMl19KTtcbiAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAyLCBidWZmOiBmaXJzdH0pO1xuICAgICAgICAgICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDMsIGJ1ZmY6IGluY30pO1xuICAgICAgICAgICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJDQUxMXCIsIGZuTmFtZTogZm5GRlRKb2luLCAgcGFyYW1zOltcbiAgICAgICAgICAgICAgICAgICAgICAgIHt2YXI6IDB9LFxuICAgICAgICAgICAgICAgICAgICAgICAge3ZhcjogMX0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFsOiBwb2ludHNQZXJDaHVua30sXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFyOiAyfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHt2YXI6IDN9XG4gICAgICAgICAgICAgICAgICAgIF19KTtcbiAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDogMCwgdmFyOiAwLCBsZW46IHBvaW50c1BlckNodW5rKnNHfSk7XG4gICAgICAgICAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkdFVFwiLCBvdXQ6IDEsIHZhcjogMSwgbGVuOiBwb2ludHNQZXJDaHVuaypzR30pO1xuICAgICAgICAgICAgICAgICAgICBvcFByb21pc2VzLnB1c2godG0ucXVldWVBY3Rpb24odGFzaywgW2NodW5rc1tvMV0uYnVmZmVyLCBjaHVua3NbbzJdLmJ1ZmZlciwgZmlyc3QuYnVmZmVyXSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgUHJvbWlzZS5hbGwob3BQcm9taXNlcyk7XG4gICAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8bkdyb3VwczsgaisrKSB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaz0wOyBrIDxuQ2h1bmtzUGVyR3JvdXAvMjsgaysrKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG8xID0gaipuQ2h1bmtzUGVyR3JvdXAgKyBrO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBvMiA9IGoqbkNodW5rc1Blckdyb3VwICsgayArIG5DaHVua3NQZXJHcm91cC8yO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCByZXNDaHVuayA9IHJlcy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgICAgICBjaHVua3NbbzFdID0gcmVzQ2h1bmtbMF07XG4gICAgICAgICAgICAgICAgICAgIGNodW5rc1tvMl0gPSByZXNDaHVua1sxXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgZnVsbEJ1ZmZPdXQ7XG4gICAgICAgIGlmIChidWZmIGluc3RhbmNlb2YgQmlnQnVmZmVyKSB7XG4gICAgICAgICAgICBmdWxsQnVmZk91dCA9IG5ldyBCaWdCdWZmZXIoblBvaW50cypzRyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmdWxsQnVmZk91dCA9IG5ldyBVaW50OEFycmF5KG5Qb2ludHMqc0cpO1xuICAgICAgICB9XG4gICAgICAgIGxldCBwID0wO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8bkNodW5rczsgaSsrKSB7XG4gICAgICAgICAgICBmdWxsQnVmZk91dC5zZXQoY2h1bmtzW2ldLCBwKTtcbiAgICAgICAgICAgIHArPWNodW5rc1tpXS5ieXRlTGVuZ3RoO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZ1bGxCdWZmT3V0O1xuICAgIH07XG5cbiAgICBHLmZmdEpvaW4gPSBhc3luYyBmdW5jdGlvbiBmZnRKb2luKGJ1ZmYxLCBidWZmMiwgZmlyc3QsIGluYykge1xuICAgICAgICBjb25zdCBzRyA9IEcuRi5uOCozO1xuICAgICAgICBsZXQgZm5OYW1lO1xuICAgICAgICBpZiAoZ3JvdXBOYW1lID09IFwiRzFcIikge1xuICAgICAgICAgICAgZm5OYW1lID0gXCJnMW1fZmZ0Sm9pblwiO1xuICAgICAgICB9IGVsc2UgaWYgKGdyb3VwTmFtZSA9PSBcIkcyXCIpIHtcbiAgICAgICAgICAgIGZuTmFtZSA9IFwiZzJtX2ZmdEpvaW5cIjtcbiAgICAgICAgfSBlbHNlIGlmIChncm91cE5hbWUgPT0gXCJGclwiKSB7XG4gICAgICAgICAgICBmbk5hbWUgPSBcImZybV9mZnRKb2luXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGdyb3VwXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGJ1ZmYxLmJ5dGVMZW5ndGggIT0gYnVmZjIuYnl0ZUxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBidWZmZXIgc2l6ZVwiKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBuUG9pbnRzID0gTWF0aC5mbG9vcihidWZmMS5ieXRlTGVuZ3RoIC8gc0cpO1xuICAgICAgICBpZiAoblBvaW50cyAhPSAxIDw8IGxvZzIoblBvaW50cykpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgbnVtYmVyIG9mIHBvaW50c1wiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBuQ2h1bmtzID0gMSA8PCBsb2cyKHRtLmNvbmN1cnJlbmN5KTtcbiAgICAgICAgaWYgKG5Qb2ludHMgPD0gbkNodW5rcyoyKSBuQ2h1bmtzID0gMTtcblxuICAgICAgICBjb25zdCBwb2ludHNQZXJDaHVuayA9IG5Qb2ludHMgLyBuQ2h1bmtzO1xuXG5cbiAgICAgICAgY29uc3Qgb3BQcm9taXNlcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8bkNodW5rczsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCB0YXNrID0gW107XG5cbiAgICAgICAgICAgIGNvbnN0IGZpcnN0Q2h1bmsgPSBGci5tdWwoZmlyc3QsIEZyLmV4cChpbmMsIGkqcG9pbnRzUGVyQ2h1bmspKTtcbiAgICAgICAgICAgIGNvbnN0IGIxID0gYnVmZjEuc2xpY2UoKGkqIHBvaW50c1BlckNodW5rKSpzRywgKChpKzEpKiBwb2ludHNQZXJDaHVuaykqc0cpO1xuICAgICAgICAgICAgY29uc3QgYjIgPSBidWZmMi5zbGljZSgoaSogcG9pbnRzUGVyQ2h1bmspKnNHLCAoKGkrMSkqIHBvaW50c1BlckNodW5rKSpzRyk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDAsIGJ1ZmY6IGIxfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDEsIGJ1ZmY6IGIyfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDIsIGJ1ZmY6IGZpcnN0Q2h1bmt9KTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMywgYnVmZjogaW5jfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJDQUxMXCIsIGZuTmFtZTogZm5OYW1lLCBwYXJhbXM6IFtcbiAgICAgICAgICAgICAgICB7dmFyOiAwfSxcbiAgICAgICAgICAgICAgICB7dmFyOiAxfSxcbiAgICAgICAgICAgICAgICB7dmFsOiBwb2ludHNQZXJDaHVua30sXG4gICAgICAgICAgICAgICAge3ZhcjogMn0sXG4gICAgICAgICAgICAgICAge3ZhcjogM31cbiAgICAgICAgICAgIF19KTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkdFVFwiLCBvdXQ6IDAsIHZhcjogMCwgbGVuOiBwb2ludHNQZXJDaHVuaypzR30pO1xuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDogMSwgdmFyOiAxLCBsZW46IHBvaW50c1BlckNodW5rKnNHfSk7XG4gICAgICAgICAgICBvcFByb21pc2VzLnB1c2goXG4gICAgICAgICAgICAgICAgdG0ucXVldWVBY3Rpb24odGFzaywgW2IxLmJ1ZmZlciwgYjIuYnVmZmVyLCBmaXJzdENodW5rLmJ1ZmZlcl0pXG4gICAgICAgICAgICApO1xuXG4gICAgICAgIH1cblxuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UuYWxsKG9wUHJvbWlzZXMpO1xuXG4gICAgICAgIGxldCBmdWxsQnVmZk91dDE7XG4gICAgICAgIGxldCBmdWxsQnVmZk91dDI7XG4gICAgICAgIGlmIChidWZmMSBpbnN0YW5jZW9mIEJpZ0J1ZmZlcikge1xuICAgICAgICAgICAgZnVsbEJ1ZmZPdXQxID0gbmV3IEJpZ0J1ZmZlcihuUG9pbnRzKnNHKTtcbiAgICAgICAgICAgIGZ1bGxCdWZmT3V0MiA9IG5ldyBCaWdCdWZmZXIoblBvaW50cypzRyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmdWxsQnVmZk91dDEgPSBuZXcgVWludDhBcnJheShuUG9pbnRzKnNHKTtcbiAgICAgICAgICAgIGZ1bGxCdWZmT3V0MiA9IG5ldyBVaW50OEFycmF5KG5Qb2ludHMqc0cpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHAgPTA7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxyZXN1bHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGZ1bGxCdWZmT3V0MS5zZXQocmVzdWx0W2ldWzBdLCBwKTtcbiAgICAgICAgICAgIGZ1bGxCdWZmT3V0Mi5zZXQocmVzdWx0W2ldWzFdLCBwKTtcbiAgICAgICAgICAgIHArPXJlc3VsdFtpXVswXS5ieXRlTGVuZ3RoO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIFtmdWxsQnVmZk91dDEsIGZ1bGxCdWZmT3V0Ml07XG4gICAgfTtcblxuXG5cbiAgICBHLmZmdEZpbmFsID0gIGFzeW5jIGZ1bmN0aW9uIGZmdEZpbmFsKGJ1ZmYsIGZhY3Rvcikge1xuICAgICAgICBjb25zdCBzRyA9IEcuRi5uOCozO1xuICAgICAgICBjb25zdCBzR291dCA9IEcuRi5uOCoyO1xuICAgICAgICBsZXQgZm5OYW1lLCBmblRvQWZmaW5lO1xuICAgICAgICBpZiAoZ3JvdXBOYW1lID09IFwiRzFcIikge1xuICAgICAgICAgICAgZm5OYW1lID0gXCJnMW1fZmZ0RmluYWxcIjtcbiAgICAgICAgICAgIGZuVG9BZmZpbmUgPSBcImcxbV9iYXRjaFRvQWZmaW5lXCI7XG4gICAgICAgIH0gZWxzZSBpZiAoZ3JvdXBOYW1lID09IFwiRzJcIikge1xuICAgICAgICAgICAgZm5OYW1lID0gXCJnMm1fZmZ0RmluYWxcIjtcbiAgICAgICAgICAgIGZuVG9BZmZpbmUgPSBcImcybV9iYXRjaFRvQWZmaW5lXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGdyb3VwXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgblBvaW50cyA9IE1hdGguZmxvb3IoYnVmZi5ieXRlTGVuZ3RoIC8gc0cpO1xuICAgICAgICBpZiAoblBvaW50cyAhPSAxIDw8IGxvZzIoblBvaW50cykpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgbnVtYmVyIG9mIHBvaW50c1wiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHBvaW50c1BlckNodW5rID0gTWF0aC5mbG9vcihuUG9pbnRzIC8gdG0uY29uY3VycmVuY3kpO1xuXG4gICAgICAgIGNvbnN0IG9wUHJvbWlzZXMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHRtLmNvbmN1cnJlbmN5OyBpKyspIHtcbiAgICAgICAgICAgIGxldCBuO1xuICAgICAgICAgICAgaWYgKGk8IHRtLmNvbmN1cnJlbmN5LTEpIHtcbiAgICAgICAgICAgICAgICBuID0gcG9pbnRzUGVyQ2h1bms7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG4gPSBuUG9pbnRzIC0gaSpwb2ludHNQZXJDaHVuaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChuPT0wKSBjb250aW51ZTtcbiAgICAgICAgICAgIGNvbnN0IHRhc2sgPSBbXTtcbiAgICAgICAgICAgIGNvbnN0IGIgPSBidWZmLnNsaWNlKChpKiBwb2ludHNQZXJDaHVuaykqc0csIChpKnBvaW50c1BlckNodW5rK24pKnNHKTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMCwgYnVmZjogYn0pO1xuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAxLCBidWZmOiBmYWN0b3J9KTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkNBTExcIiwgZm5OYW1lOiBmbk5hbWUsIHBhcmFtczogW1xuICAgICAgICAgICAgICAgIHt2YXI6IDB9LFxuICAgICAgICAgICAgICAgIHt2YWw6IG59LFxuICAgICAgICAgICAgICAgIHt2YXI6IDF9LFxuICAgICAgICAgICAgXX0pO1xuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IGZuVG9BZmZpbmUsIHBhcmFtczogW1xuICAgICAgICAgICAgICAgIHt2YXI6IDB9LFxuICAgICAgICAgICAgICAgIHt2YWw6IG59LFxuICAgICAgICAgICAgICAgIHt2YXI6IDB9LFxuICAgICAgICAgICAgXX0pO1xuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiR0VUXCIsIG91dDogMCwgdmFyOiAwLCBsZW46IG4qc0dvdXR9KTtcbiAgICAgICAgICAgIG9wUHJvbWlzZXMucHVzaChcbiAgICAgICAgICAgICAgICB0bS5xdWV1ZUFjdGlvbih0YXNrLCBbYi5idWZmZXJdKVxuICAgICAgICAgICAgKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5hbGwob3BQcm9taXNlcyk7XG5cbiAgICAgICAgbGV0IGZ1bGxCdWZmT3V0O1xuICAgICAgICBpZiAoYnVmZiBpbnN0YW5jZW9mIEJpZ0J1ZmZlcikge1xuICAgICAgICAgICAgZnVsbEJ1ZmZPdXQgPSBuZXcgQmlnQnVmZmVyKG5Qb2ludHMqc0dvdXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZnVsbEJ1ZmZPdXQgPSBuZXcgVWludDhBcnJheShuUG9pbnRzKnNHb3V0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBwID0wO1xuICAgICAgICBmb3IgKGxldCBpPXJlc3VsdC5sZW5ndGgtMTsgaT49MDsgaS0tKSB7XG4gICAgICAgICAgICBmdWxsQnVmZk91dC5zZXQocmVzdWx0W2ldWzBdLCBwKTtcbiAgICAgICAgICAgIHArPXJlc3VsdFtpXVswXS5ieXRlTGVuZ3RoO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZ1bGxCdWZmT3V0O1xuICAgIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGJ1aWxkRW5naW5lKHBhcmFtcykge1xuXG4gICAgY29uc3QgdG0gPSBhd2FpdCBidWlsZFRocmVhZE1hbmFnZXIocGFyYW1zLndhc20sIHBhcmFtcy5zaW5nbGVUaHJlYWQpO1xuXG5cbiAgICBjb25zdCBjdXJ2ZSA9IHt9O1xuXG4gICAgY3VydmUucSA9IGUocGFyYW1zLndhc20ucS50b1N0cmluZygpKTtcbiAgICBjdXJ2ZS5yID0gZShwYXJhbXMud2FzbS5yLnRvU3RyaW5nKCkpO1xuICAgIGN1cnZlLm5hbWUgPSBwYXJhbXMubmFtZTtcbiAgICBjdXJ2ZS50bSA9IHRtO1xuICAgIGN1cnZlLnByZVBTaXplID0gcGFyYW1zLndhc20ucHJlUFNpemU7XG4gICAgY3VydmUucHJlUVNpemUgPSBwYXJhbXMud2FzbS5wcmVRU2l6ZTtcbiAgICBjdXJ2ZS5GciA9IG5ldyBXYXNtRmllbGQxKHRtLCBcImZybVwiLCBwYXJhbXMubjhyLCBwYXJhbXMucik7XG4gICAgY3VydmUuRjEgPSBuZXcgV2FzbUZpZWxkMSh0bSwgXCJmMW1cIiwgcGFyYW1zLm44cSwgcGFyYW1zLnEpO1xuICAgIGN1cnZlLkYyID0gbmV3IFdhc21GaWVsZDIodG0sIFwiZjJtXCIsIGN1cnZlLkYxKTtcbiAgICBjdXJ2ZS5HMSA9IG5ldyBXYXNtQ3VydmUodG0sIFwiZzFtXCIsIGN1cnZlLkYxLCBwYXJhbXMud2FzbS5wRzFnZW4sIHBhcmFtcy53YXNtLnBHMWIsIHBhcmFtcy5jb2ZhY3RvckcxKTtcbiAgICBjdXJ2ZS5HMiA9IG5ldyBXYXNtQ3VydmUodG0sIFwiZzJtXCIsIGN1cnZlLkYyLCBwYXJhbXMud2FzbS5wRzJnZW4sIHBhcmFtcy53YXNtLnBHMmIsIHBhcmFtcy5jb2ZhY3RvckcyKTtcbiAgICBjdXJ2ZS5GNiA9IG5ldyBXYXNtRmllbGQzKHRtLCBcImY2bVwiLCBjdXJ2ZS5GMik7XG4gICAgY3VydmUuRjEyID0gbmV3IFdhc21GaWVsZDIodG0sIFwiZnRtXCIsIGN1cnZlLkY2KTtcblxuICAgIGN1cnZlLkd0ID0gY3VydmUuRjEyO1xuXG4gICAgYnVpbGRCYXRjaEFwcGx5S2V5KGN1cnZlLCBcIkcxXCIpO1xuICAgIGJ1aWxkQmF0Y2hBcHBseUtleShjdXJ2ZSwgXCJHMlwiKTtcbiAgICBidWlsZEJhdGNoQXBwbHlLZXkoY3VydmUsIFwiRnJcIik7XG5cbiAgICBidWlsZE11bHRpZXhwKGN1cnZlLCBcIkcxXCIpO1xuICAgIGJ1aWxkTXVsdGlleHAoY3VydmUsIFwiRzJcIik7XG5cbiAgICBidWlsZEZGVChjdXJ2ZSwgXCJHMVwiKTtcbiAgICBidWlsZEZGVChjdXJ2ZSwgXCJHMlwiKTtcbiAgICBidWlsZEZGVChjdXJ2ZSwgXCJGclwiKTtcblxuICAgIGJ1aWxkUGFpcmluZyhjdXJ2ZSk7XG5cbiAgICBjdXJ2ZS5hcnJheTJidWZmZXIgPSBmdW5jdGlvbihhcnIsIHNHKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShzRyphcnIubGVuZ3RoKTtcblxuICAgICAgICBmb3IgKGxldCBpPTA7IGk8YXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBidWZmLnNldChhcnJbaV0sIGkqc0cpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgfTtcblxuICAgIGN1cnZlLmJ1ZmZlcjJhcnJheSA9IGZ1bmN0aW9uKGJ1ZmYgLCBzRykge1xuICAgICAgICBjb25zdCBuPSBidWZmLmJ5dGVMZW5ndGggLyBzRztcbiAgICAgICAgY29uc3QgYXJyID0gbmV3IEFycmF5KG4pO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8bjsgaSsrKSB7XG4gICAgICAgICAgICBhcnJbaV0gPSBidWZmLnNsaWNlKGkqc0csIGkqc0crc0cpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhcnI7XG4gICAgfTtcblxuICAgIHJldHVybiBjdXJ2ZTtcbn1cblxuLy8gQVVUTy1HRU5FUkFURUQgZnJvbSB3YXNtY3VydmVzL2J1aWxkL2JuMTI4X3dhc20uanMg4oCUIGRvIG5vdCBlZGl0LlxuLy8gUmVnZW5lcmF0ZSB3aXRoOiBucG0gcnVuIGdlbi13YXNtXG4vLyAnY29kZScgaXMgYmFzZTY0IG9mIHRoZSB3YXNtLW9wdCAtTzIgb3B0aW1pemVkIHdhc207IHRoZSByZXN0IGFyZVxuLy8gcG9pbnRlciBvZmZzZXRzIC8gZmllbGQgbW9kdWxpLlxuY29uc3QgY29kZSQyID0gXCJBR0Z6YlFFQUFBQUJpZ0VRWUFKL2Z3QmdBMzkvZndCZ0FYOEJmMkFFZjM5L2Z3QmdCWDkvZjM5L0FHQUJmd0JnQW45L0FYOWdCbjkvZjM5L2Z3QmdDSDkvZjM5L2YzOS9BR0FEZjM5L0FYOWdCSDkvZjM4QmYyQUtmMzkvZjM5L2YzOS9md0JnQlg5L2YzOS9BWDlnQjM5L2YzOS9mMzhCZjJBSmYzOS9mMzkvZjM5L0FYOWdDMzkvZjM5L2YzOS9mMzkvQVg4Q0R3RURaVzUyQm0xbGJXOXllUUlBR1FPZEFwc0NBQVVDQlFZR0NRa0JBQUFEQVFJQkFRQUFBUUFBQUFBQ0FnQUZBUU1FQVFFREFBSUNBUUVBQUFFQUFBQUFBZ0lBQlFFREJBRUJBd0FDQVFBQUFnSUNCUVVBQUFBR0JnWUFBQUVCQVFBQUFRRUJBQUFBQUFBQ0FnRUFBUUFBQUFBQkFRRUJBUW9IQ0FRSUJBTURBQU1DQUFBRUJ3Y0JBUWNBQXdzRUF3SUZBQUVCQUFFQkFBQURBZ0lFQXdBQ0FnSUZCUUFBQUFZR0JnQUFBUUVCQUFBQkFRRUFBQUFBQUFJQ0FRQUFBQUFBQVFFQkFRRUlCQWdFQXdNQkFBTUFBQVFIQndFQkJ3RUFBd0FBQkFjSEFRRUhBUUVFQkFRRUJBQUNBZ1VGQUFFQUFRRUFBZ1lBQXdJRUF3QUNBZ1VGQUFFQkFBRUJBQUFBQUFZQUF3SUNCQU1BQWdBQUFBQURBd0VBQUFBQUFBQUFBQUFBQUFBQUFBa01EUTRQQVFleEphc0NDR2x1ZEY5amIzQjVBQUFJYVc1MFgzcGxjbThBQVFkcGJuUmZiMjVsQUFNS2FXNTBYMmx6V21WeWJ3QUNCbWx1ZEY5bGNRQUVCMmx1ZEY5bmRHVUFCUWRwYm5SZllXUmtBQVlIYVc1MFgzTjFZZ0FIQjJsdWRGOXRkV3dBQ0FwcGJuUmZjM0YxWVhKbEFBa05hVzUwWDNOeGRXRnlaVTlzWkFBS0IybHVkRjlrYVhZQUN3NXBiblJmYVc1MlpYSnpaVTF2WkFBTUNHWXhiVjlqYjNCNUFBQUlaakZ0WDNwbGNtOEFBUXBtTVcxZmFYTmFaWEp2QUFJR1pqRnRYMlZ4QUFRSFpqRnRYMkZrWkFBT0IyWXhiVjl6ZFdJQUR3ZG1NVzFmYm1WbkFCQU9aakZ0WDJselRtVm5ZWFJwZG1VQUZ3bG1NVzFmYVhOUGJtVUFEUWhtTVcxZmMybG5iZ0FZQzJZeGJWOXRVbVZrZFdOMEFCRUhaakZ0WDIxMWJBQVNDbVl4YlY5emNYVmhjbVVBRXcxbU1XMWZjM0YxWVhKbFQyeGtBQlFTWmpGdFgyWnliMjFOYjI1MFoyOXRaWEo1QUJZUVpqRnRYM1J2VFc5dWRHZHZiV1Z5ZVFBVkMyWXhiVjlwYm5abGNuTmxBQmtIWmpGdFgyOXVaUUFhQ0dZeGJWOXNiMkZrQUJzUFpqRnRYM1JwYldWelUyTmhiR0Z5QUJ3SFpqRnRYMlY0Y0FBZ0VHWXhiVjlpWVhSamFFbHVkbVZ5YzJVQUhRaG1NVzFmYzNGeWRBQWhER1l4YlY5cGMxTnhkV0Z5WlFBaUZXWXhiVjlpWVhSamFGUnZUVzl1ZEdkdmJXVnllUUFlRjJZeGJWOWlZWFJqYUVaeWIyMU5iMjUwWjI5dFpYSjVBQjhJWm5KdFgyTnZjSGtBQUFobWNtMWZlbVZ5YndBQkNtWnliVjlwYzFwbGNtOEFBZ1ptY20xZlpYRUFCQWRtY20xZllXUmtBQ1FIWm5KdFgzTjFZZ0FsQjJaeWJWOXVaV2NBSmc1bWNtMWZhWE5PWldkaGRHbDJaUUF0Q1daeWJWOXBjMDl1WlFBakNHWnliVjl6YVdkdUFDNExabkp0WDIxU1pXUjFZM1FBSndkbWNtMWZiWFZzQUNnS1puSnRYM054ZFdGeVpRQXBEV1p5YlY5emNYVmhjbVZQYkdRQUtoSm1jbTFmWm5KdmJVMXZiblJuYjIxbGNua0FMQkJtY20xZmRHOU5iMjUwWjI5dFpYSjVBQ3NMWm5KdFgybHVkbVZ5YzJVQUx3ZG1jbTFmYjI1bEFEQUlabkp0WDJ4dllXUUFNUTltY20xZmRHbHRaWE5UWTJGc1lYSUFNZ2RtY20xZlpYaHdBRFlRWm5KdFgySmhkR05vU1c1MlpYSnpaUUF6Q0daeWJWOXpjWEowQURjTVpuSnRYMmx6VTNGMVlYSmxBRGdWWm5KdFgySmhkR05vVkc5TmIyNTBaMjl0WlhKNUFEUVhabkp0WDJKaGRHTm9Sbkp2YlUxdmJuUm5iMjFsY25rQU5RWm1jbDloWkdRQUpBWm1jbDl6ZFdJQUpRWm1jbDl1WldjQUpnWm1jbDl0ZFd3QU9RbG1jbDl6Y1hWaGNtVUFPZ3BtY2w5cGJuWmxjbk5sQURzTlpuSmZhWE5PWldkaGRHbDJaUUE4QjJaeVgyTnZjSGtBQUFkbWNsOTZaWEp2QUFFR1puSmZiMjVsQURBSlpuSmZhWE5hWlhKdkFBSUZabkpmWlhFQUJBeG5NVzFmYlhWc2RHbGxlSEFBWnhKbk1XMWZiWFZzZEdsbGVIQmZZMmgxYm1zQVpoSm5NVzFmYlhWc2RHbGxlSEJCWm1acGJtVUFhUmhuTVcxZmJYVnNkR2xsZUhCQlptWnBibVZmWTJoMWJtc0FhQXBuTVcxZmFYTmFaWEp2QUQ0UVp6RnRYMmx6V21WeWIwRm1abWx1WlFBOUJtY3hiVjlsY1FCR0MyY3hiVjlsY1UxcGVHVmtBRVVNWnpGdFgyVnhRV1ptYVc1bEFFUUlaekZ0WDJOdmNIa0FRZzVuTVcxZlkyOXdlVUZtWm1sdVpRQkJDR2N4YlY5NlpYSnZBRUFPWnpGdFgzcGxjbTlCWm1acGJtVUFQd3BuTVcxZlpHOTFZbXhsQUVnUVp6RnRYMlJ2ZFdKc1pVRm1abWx1WlFCSEIyY3hiVjloWkdRQVN3eG5NVzFmWVdSa1RXbDRaV1FBU2cxbk1XMWZZV1JrUVdabWFXNWxBRWtIWnpGdFgyNWxad0JORFdjeGJWOXVaV2RCWm1acGJtVUFUQWRuTVcxZmMzVmlBRkFNWnpGdFgzTjFZazFwZUdWa0FFOE5aekZ0WDNOMVlrRm1abWx1WlFCT0VtY3hiVjltY205dFRXOXVkR2R2YldWeWVRQlNHR2N4YlY5bWNtOXRUVzl1ZEdkdmJXVnllVUZtWm1sdVpRQlJFR2N4YlY5MGIwMXZiblJuYjIxbGNua0FWQlpuTVcxZmRHOU5iMjUwWjI5dFpYSjVRV1ptYVc1bEFGTVBaekZ0WDNScGJXVnpVMk5oYkdGeUFHb1ZaekZ0WDNScGJXVnpVMk5oYkdGeVFXWm1hVzVsQUdzTlp6RnRYMjV2Y20xaGJHbDZaUUJaQ21jeGJWOU1SVTEwYjFVQVd3cG5NVzFmVEVWTmRHOURBRndLWnpGdFgxVjBiMHhGVFFCZENtY3hiVjlEZEc5TVJVMEFYZzluTVcxZlltRjBZMmhNUlUxMGIxVUFYdzluTVcxZlltRjBZMmhNUlUxMGIwTUFZQTluTVcxZlltRjBZMmhWZEc5TVJVMEFZUTluTVcxZlltRjBZMmhEZEc5TVJVMEFZZ3huTVcxZmRHOUJabVpwYm1VQVZRNW5NVzFmZEc5S1lXTnZZbWxoYmdCREVXY3hiVjlpWVhSamFGUnZRV1ptYVc1bEFGZ1RaekZ0WDJKaGRHTm9WRzlLWVdOdlltbGhiZ0JqQzJjeGJWOXBia04xY25abEFGY1JaekZ0WDJsdVEzVnlkbVZCWm1acGJtVUFWaGRtY20xZlgzSmxkbVZ5YzJWUVpYSnRkWFJoZEdsdmJnQnNCMlp5YlY5bVpuUUFid2htY20xZmFXWm1kQUJ3Q21aeWJWOXlZWGRtWm5RQWJRdG1jbTFmWm1aMFNtOXBiZ0J4RG1aeWJWOW1ablJLYjJsdVJYaDBBSElSWm5KdFgyWm1kRXB2YVc1RmVIUkpibllBY3dwbWNtMWZabVowVFdsNEFIUU1abkp0WDJabWRFWnBibUZzQUhVZFpuSnRYM0J5WlhCaGNtVk1ZV2R5WVc1blpVVjJZV3gxWVhScGIyNEFkZ2h3YjJ4ZmVtVnlid0IzRDNCdmJGOWpiMjV6ZEhKMVkzUk1Rd0I0REhGaGNGOWlkV2xzWkVGQ1F3QjVDM0ZoY0Y5cWIybHVRVUpEQUhvTWNXRndYMkpoZEdOb1FXUmtBSHNLWmpKdFgybHpXbVZ5YndBOUNXWXliVjlwYzA5dVpRQjhDR1l5YlY5NlpYSnZBRDhIWmpKdFgyOXVaUUI5Q0dZeWJWOWpiM0I1QUg0SFpqSnRYMjExYkFCL0NHWXliVjl0ZFd3eEFJQUJDbVl5YlY5emNYVmhjbVVBZ1FFSFpqSnRYMkZrWkFDQ0FRZG1NbTFmYzNWaUFJTUJCMll5YlY5dVpXY0FoQUVJWmpKdFgzTnBaMjRBaHdFTlpqSnRYMk52Ym1wMVoyRjBaUUJNRW1ZeWJWOW1jbTl0VFc5dWRHZHZiV1Z5ZVFCUkVHWXliVjkwYjAxdmJuUm5iMjFsY25rQVV3Wm1NbTFmWlhFQVJBdG1NbTFmYVc1MlpYSnpaUUNGQVFkbU1tMWZaWGh3QUlvQkQyWXliVjkwYVcxbGMxTmpZV3hoY2dDR0FSQm1NbTFmWW1GMFkyaEpiblpsY25ObEFJa0JDR1l5YlY5emNYSjBBSXNCREdZeWJWOXBjMU54ZFdGeVpRQ01BUTVtTW0xZmFYTk9aV2RoZEdsMlpRQ0lBUXhuTW0xZmJYVnNkR2xsZUhBQXRBRVNaekp0WDIxMWJIUnBaWGh3WDJOb2RXNXJBTE1CRW1jeWJWOXRkV3gwYVdWNGNFRm1abWx1WlFDMkFSaG5NbTFmYlhWc2RHbGxlSEJCWm1acGJtVmZZMmgxYm1zQXRRRUtaekp0WDJseldtVnlid0NPQVJCbk1tMWZhWE5hWlhKdlFXWm1hVzVsQUkwQkJtY3liVjlsY1FDV0FRdG5NbTFmWlhGTmFYaGxaQUNWQVF4bk1tMWZaWEZCWm1acGJtVUFsQUVJWnpKdFgyTnZjSGtBa2dFT1p6SnRYMk52Y0hsQlptWnBibVVBa1FFSVp6SnRYM3BsY204QWtBRU9aekp0WDNwbGNtOUJabVpwYm1VQWp3RUtaekp0WDJSdmRXSnNaUUNZQVJCbk1tMWZaRzkxWW14bFFXWm1hVzVsQUpjQkIyY3liVjloWkdRQW13RU1aekp0WDJGa1pFMXBlR1ZrQUpvQkRXY3liVjloWkdSQlptWnBibVVBbVFFSFp6SnRYMjVsWndDZEFRMW5NbTFmYm1WblFXWm1hVzVsQUp3QkIyY3liVjl6ZFdJQW9BRU1aekp0WDNOMVlrMXBlR1ZrQUo4QkRXY3liVjl6ZFdKQlptWnBibVVBbmdFU1p6SnRYMlp5YjIxTmIyNTBaMjl0WlhKNUFLSUJHR2N5YlY5bWNtOXRUVzl1ZEdkdmJXVnllVUZtWm1sdVpRQ2hBUkJuTW0xZmRHOU5iMjUwWjI5dFpYSjVBS1FCRm1jeWJWOTBiMDF2Ym5SbmIyMWxjbmxCWm1acGJtVUFvd0VQWnpKdFgzUnBiV1Z6VTJOaGJHRnlBTGNCRldjeWJWOTBhVzFsYzFOallXeGhja0ZtWm1sdVpRQzRBUTFuTW0xZmJtOXliV0ZzYVhwbEFLa0JDbWN5YlY5TVJVMTBiMVVBcWdFS1p6SnRYMHhGVFhSdlF3Q3JBUXBuTW0xZlZYUnZURVZOQUt3QkNtY3liVjlEZEc5TVJVMEFyUUVQWnpKdFgySmhkR05vVEVWTmRHOVZBSzRCRDJjeWJWOWlZWFJqYUV4RlRYUnZRd0N2QVE5bk1tMWZZbUYwWTJoVmRHOU1SVTBBc0FFUFp6SnRYMkpoZEdOb1EzUnZURVZOQUxFQkRHY3liVjkwYjBGbVptbHVaUUNsQVE1bk1tMWZkRzlLWVdOdlltbGhiZ0NUQVJGbk1tMWZZbUYwWTJoVWIwRm1abWx1WlFDb0FSTm5NbTFmWW1GMFkyaFViMHBoWTI5aWFXRnVBTElCQzJjeWJWOXBia04xY25abEFLY0JFV2N5YlY5cGJrTjFjblpsUVdabWFXNWxBS1lCQzJjeGJWOTBhVzFsYzBaeUFMa0JGMmN4YlY5ZmNtVjJaWEp6WlZCbGNtMTFkR0YwYVc5dUFMb0JCMmN4YlY5bVpuUUF2QUVJWnpGdFgybG1ablFBdlFFS1p6RnRYM0poZDJabWRBQzdBUXRuTVcxZlptWjBTbTlwYmdDK0FRNW5NVzFmWm1aMFNtOXBia1Y0ZEFDL0FSRm5NVzFmWm1aMFNtOXBia1Y0ZEVsdWRnREFBUXBuTVcxZlptWjBUV2w0QU1FQkRHY3hiVjltWm5SR2FXNWhiQURDQVIxbk1XMWZjSEpsY0dGeVpVeGhaM0poYm1kbFJYWmhiSFZoZEdsdmJnRERBUXRuTW0xZmRHbHRaWE5HY2dERUFSZG5NbTFmWDNKbGRtVnljMlZRWlhKdGRYUmhkR2x2YmdERkFRZG5NbTFmWm1aMEFNY0JDR2N5YlY5cFptWjBBTWdCQ21jeWJWOXlZWGRtWm5RQXhnRUxaekp0WDJabWRFcHZhVzRBeVFFT1p6SnRYMlptZEVwdmFXNUZlSFFBeWdFUlp6SnRYMlptZEVwdmFXNUZlSFJKYm5ZQXl3RUtaekp0WDJabWRFMXBlQURNQVF4bk1tMWZabVowUm1sdVlXd0F6UUVkWnpKdFgzQnlaWEJoY21WTVlXZHlZVzVuWlVWMllXeDFZWFJwYjI0QXpnRVJaekZ0WDNScGJXVnpSbkpCWm1acGJtVUF6d0VSWnpKdFgzUnBiV1Z6Um5KQlptWnBibVVBMEFFUlpuSnRYMkpoZEdOb1FYQndiSGxMWlhrQTBRRVJaekZ0WDJKaGRHTm9RWEJ3YkhsTFpYa0EwZ0VXWnpGdFgySmhkR05vUVhCd2JIbExaWGxOYVhobFpBRFRBUkZuTW0xZlltRjBZMmhCY0hCc2VVdGxlUURVQVJabk1tMWZZbUYwWTJoQmNIQnNlVXRsZVUxcGVHVmtBTlVCQ21ZMmJWOXBjMXBsY204QTF3RUpaalp0WDJselQyNWxBTmdCQ0dZMmJWOTZaWEp2QU5rQkIyWTJiVjl2Ym1VQTJnRUlaalp0WDJOdmNIa0Eyd0VIWmpadFgyMTFiQURjQVFwbU5tMWZjM0YxWVhKbEFOMEJCMlkyYlY5aFpHUUEzZ0VIWmpadFgzTjFZZ0RmQVFkbU5tMWZibVZuQU9BQkNHWTJiVjl6YVdkdUFPRUJFbVkyYlY5bWNtOXRUVzl1ZEdkdmJXVnllUUNpQVJCbU5tMWZkRzlOYjI1MFoyOXRaWEo1QUtRQkJtWTJiVjlsY1FEaUFRdG1ObTFmYVc1MlpYSnpaUURqQVFkbU5tMWZaWGh3QU9jQkQyWTJiVjkwYVcxbGMxTmpZV3hoY2dEa0FSQm1ObTFmWW1GMFkyaEpiblpsY25ObEFPWUJEbVkyYlY5cGMwNWxaMkYwYVhabEFPVUJDbVowYlY5cGMxcGxjbThBNlFFSlpuUnRYMmx6VDI1bEFPb0JDR1owYlY5NlpYSnZBT3NCQjJaMGJWOXZibVVBN0FFSVpuUnRYMk52Y0hrQTdRRUhablJ0WDIxMWJBRHVBUWhtZEcxZmJYVnNNUUR2QVFwbWRHMWZjM0YxWVhKbEFQQUJCMlowYlY5aFpHUUE4UUVIWm5SdFgzTjFZZ0R5QVFkbWRHMWZibVZuQVBNQkNHWjBiVjl6YVdkdUFQb0JEV1owYlY5amIyNXFkV2RoZEdVQTlBRVNablJ0WDJaeWIyMU5iMjUwWjI5dFpYSjVBUFlCRUdaMGJWOTBiMDF2Ym5SbmIyMWxjbmtBOVFFR1puUnRYMlZ4QVBjQkMyWjBiVjlwYm5abGNuTmxBUGdCQjJaMGJWOWxlSEFBL1FFUFpuUnRYM1JwYldWelUyTmhiR0Z5QVBrQkVHWjBiVjlpWVhSamFFbHVkbVZ5YzJVQS9BRUlablJ0WDNOeGNuUUEvZ0VNWm5SdFgybHpVM0YxWVhKbEFQOEJEbVowYlY5cGMwNWxaMkYwYVhabEFQc0JGR0p1TVRJNFgxOW1jbTlpWlc1cGRYTk5ZWEF3QUljQ0ZHSnVNVEk0WDE5bWNtOWlaVzVwZFhOTllYQXhBSWdDRkdKdU1USTRYMTltY205aVpXNXBkWE5OWVhBeUFJa0NGR0p1TVRJNFgxOW1jbTlpWlc1cGRYTk5ZWEF6QUlvQ0ZHSnVNVEk0WDE5bWNtOWlaVzVwZFhOTllYQTBBSXNDRkdKdU1USTRYMTltY205aVpXNXBkWE5OWVhBMUFJd0NGR0p1TVRJNFgxOW1jbTlpWlc1cGRYTk5ZWEEyQUkwQ0ZHSnVNVEk0WDE5bWNtOWlaVzVwZFhOTllYQTNBSTRDRkdKdU1USTRYMTltY205aVpXNXBkWE5OWVhBNEFJOENGR0p1TVRJNFgxOW1jbTlpWlc1cGRYTk5ZWEE1QUpBQ0VHSnVNVEk0WDNCaGFYSnBibWRGY1RFQWxRSVFZbTR4TWpoZmNHRnBjbWx1WjBWeE1nQ1dBaEJpYmpFeU9GOXdZV2x5YVc1blJYRXpBSmNDRUdKdU1USTRYM0JoYVhKcGJtZEZjVFFBbUFJUVltNHhNamhmY0dGcGNtbHVaMFZ4TlFDWkFnMWliakV5T0Y5d1lXbHlhVzVuQUpvQ0QySnVNVEk0WDNCeVpYQmhjbVZITVFDQkFnOWliakV5T0Y5d2NtVndZWEpsUnpJQWd3SVFZbTR4TWpoZmJXbHNiR1Z5VEc5dmNBQ0dBaGxpYmpFeU9GOW1hVzVoYkVWNGNHOXVaVzUwYVdGMGFXOXVBSlFDSEdKdU1USTRYMlpwYm1Gc1JYaHdiMjVsYm5ScFlYUnBiMjVQYkdRQWtRSVBZbTR4TWpoZlgyMTFiRUo1TURJMEFJUUNFbUp1TVRJNFgxOXRkV3hDZVRBeU5FOXNaQUNGQWhkaWJqRXlPRjlmWTNsamJHOTBiMjFwWTFOeGRXRnlaUUNTQWhkaWJqRXlPRjlmWTNsamJHOTBiMjFwWTBWNGNGOTNNQUNUQWdyZXJBT2JBaW9BSUFFZ0FDa0RBRGNEQUNBQklBQXBBd2czQXdnZ0FTQUFLUU1RTndNUUlBRWdBQ2tER0RjREdBc2VBQ0FBUWdBM0F3QWdBRUlBTndNSUlBQkNBRGNERUNBQVFnQTNBeGdMTEFBZ0FDa0RHRkFFZmlBQUtRTVFVQVIrSUFBcEF3aFFCSDRnQUNrREFBVkNBUXNGUWdFTEJVSUJDMUFMSGdBZ0FFSUJOd01BSUFCQ0FEY0RDQ0FBUWdBM0F4QWdBRUlBTndNWUMwQUFJQUFwQXhnZ0FTa0RHRkVFZnlBQUtRTVFJQUVwQXhCUkJIOGdBQ2tEQ0NBQktRTUlVUVIvSUFBcEF3QWdBU2tEQUZFRlFRQUxCVUVBQ3dWQkFBc0xjd0FnQUNrREdDQUJLUU1ZVkFSL1FRQUZJQUFwQXhnZ0FTa0RHRllFZjBFQkJTQUFLUU1RSUFFcEF4QlVCSDlCQUFVZ0FDa0RFQ0FCS1FNUVZnUi9RUUVGSUFBcEF3Z2dBU2tEQ0ZRRWYwRUFCU0FBS1FNSUlBRXBBd2hXQkg5QkFRVWdBQ2tEQUNBQktRTUFXZ3NMQ3dzTEN3dkVBUUVCZmlBQ0lBQTFBZ0FnQVRVQ0FId2lBejRDQUNBQ0lBQTFBZ1FnQVRVQ0JId2dBMElnaUh3aUF6NENCQ0FDSUFBMUFnZ2dBVFVDQ0h3Z0EwSWdpSHdpQXo0Q0NDQUNJQUExQWd3Z0FUVUNESHdnQTBJZ2lId2lBejRDRENBQ0lBQTFBaEFnQVRVQ0VId2dBMElnaUh3aUF6NENFQ0FDSUFBMUFoUWdBVFVDRkh3Z0EwSWdpSHdpQXo0Q0ZDQUNJQUExQWhnZ0FUVUNHSHdnQTBJZ2lId2lBejRDR0NBQ0lBQTFBaHdnQVRVQ0hId2dBMElnaUh3aUF6NENIQ0FEUWlDSXB3djhBUUVCZmlBQ0lBQTFBZ0FnQVRVQ0FIMGlBMEwvLy8vL0Q0TStBZ0FnQWlBQU5RSUVJQUUxQWdSOUlBTkNJSWQ4SWdOQy8vLy8vdytEUGdJRUlBSWdBRFVDQ0NBQk5RSUlmU0FEUWlDSGZDSURRdi8vLy84UGd6NENDQ0FDSUFBMUFnd2dBVFVDREgwZ0EwSWdoM3dpQTBMLy8vLy9ENE0rQWd3Z0FpQUFOUUlRSUFFMUFoQjlJQU5DSUlkOElnTkMvLy8vL3crRFBnSVFJQUlnQURVQ0ZDQUJOUUlVZlNBRFFpQ0hmQ0lEUXYvLy8vOFBnejRDRkNBQ0lBQTFBaGdnQVRVQ0dIMGdBMElnaDN3aUEwTC8vLy8vRDRNK0FoZ2dBaUFBTlFJY0lBRTFBaHg5SUFOQ0lJZDhJZ05DLy8vLy93K0RQZ0ljSUFOQ0lJZW5DK1lPQVJGK0lBUWdBRFVDQUNJRklBRTFBZ0FpQm40Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0FpQURQZ0lBSUFSQ0lJZ2hBeUFESUFVZ0FUVUNCQ0lIZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBQTFBZ1FpQ0NBR2ZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QUNJQVErQWdRZ0EwSWdpQ0VFSUFRZ0JTQUJOUUlJSWdsK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdCeUFJZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBQTFBZ2dpQ2lBR2ZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUNJQU0rQWdnZ0JFSWdpQ0VESUFNZ0JTQUJOUUlNSWd0K0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdDQ0FKZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBY2dDbjRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBQU5RSU1JZ3dnQm40Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0FpQUVQZ0lNSUFOQ0lJZ2hCQ0FFSUFVZ0FUVUNFQ0lOZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBZ2dDMzRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBSklBcCtJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnQnlBTWZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQUExQWhBaURpQUdmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FDSUFNK0FoQWdCRUlnaUNFRElBTWdCU0FCTlFJVUlnOStJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nQ0NBTmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQW9nQzM0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QUpJQXgrSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0J5QU9maUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFBMUFoUWlFQ0FHZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBQ0lBUStBaFFnQTBJZ2lDRUVJQVFnQlNBQk5RSVlJaEYrSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0NDQVBmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUFvZ0RYNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FMSUF4K0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdDU0FPZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBY2dFSDRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBQU5RSVlJaElnQm40Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0FpQURQZ0lZSUFSQ0lJZ2hBeUFESUFVZ0FUVUNIQ0lUZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBZ2dFWDRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBS0lBOStJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nRENBTmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQXNnRG40Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QUpJQkIrSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0J5QVNmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFBMUFod2lCU0FHZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBQ0lBUStBaHdnQTBJZ2lDRUVJQVFnQ0NBVGZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQW9nRVg0Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0JDQU1JQTkrSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0RTQU9maUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUFzZ0VINGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FKSUJKK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdCU0FIZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBQ0lBTStBaUFnQkVJZ2lDRURJQU1nQ2lBVGZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQXdnRVg0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QU9JQTkrSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0RTQVFmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFzZ0VuNGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBeUFGSUFsK0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBSWdCRDRDSkNBRFFpQ0lJUVFnQkNBTUlCTitJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnRGlBUmZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQThnRUg0Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0JDQU5JQkorSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0JTQUxmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FDSUFNK0FpZ2dCRUlnaUNFRElBTWdEaUFUZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElCQWdFWDRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBUElCSitJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nQlNBTmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QUNJQVErQWl3Z0EwSWdpQ0VFSUFRZ0VDQVRmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUJFZ0VuNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FGSUE5K0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBSWdBejRDTUNBRVFpQ0lJUU1nQXlBU0lCTitJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nQlNBUmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QUNJQVErQWpRZ0EwSWdpQ0VFSUFRZ0JTQVRmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FDSUFNK0FqZ2dBaUFFUGdJOEM4NE5BUXgrSUFNZ0FEVUNBQ0lHSUFaK0lBSkMvLy8vL3crRGZDSUNRaUNJZkNFRElBRWdBajRDQUNBRElnUkNJSWdoQlNBQU5RSUVJZ2NnQm40aUFrSWdpRUlCaGlBQ1F2Ly8vLzhQZzBJQmhpSUNRaUNJZkNFRElBTWdBa0wvLy8vL0Q0TWdCRUwvLy8vL0Q0TjhJZ0pDSUloOElBVjhJUU1nQVNBQ1BnSUVJQU1pQkVJZ2lDRUZJQUExQWdnaUNDQUdmaUlDUWlDSVFnR0dJQUpDLy8vLy93K0RRZ0dHSWdKQ0lJaDhJUU1nQXlBSElBZCtJQUpDLy8vLy93K0RmQ0lDUWlDSWZDRURJQU1nQWtMLy8vLy9ENE1nQkVMLy8vLy9ENE44SWdKQ0lJaDhJQVY4SVFNZ0FTQUNQZ0lJSUFNaUJFSWdpQ0VGSUFBMUFnd2lDU0FHZmlJQ1FpQ0lJUU1nQXlBSElBaCtJQUpDLy8vLy93K0RmQ0lDUWlDSWZFSUJoaUFDUXYvLy8vOFBnMElCaGlJQ1FpQ0lmQ0VESUFNZ0FrTC8vLy8vRDRNZ0JFTC8vLy8vRDROOElnSkNJSWg4SUFWOElRTWdBU0FDUGdJTUlBTWlCRUlnaUNFRklBQTFBaEFpQ2lBR2ZpSUNRaUNJSVFNZ0F5QUhJQWwrSUFKQy8vLy8vdytEZkNJQ1FpQ0lmRUlCaGlBQ1F2Ly8vLzhQZzBJQmhpSUNRaUNJZkNFRElBTWdDQ0FJZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHdoQXlBRElBSkMvLy8vL3crRElBUkMvLy8vL3crRGZDSUNRaUNJZkNBRmZDRURJQUVnQWo0Q0VDQURJZ1JDSUlnaEJTQUFOUUlVSWdzZ0JuNGlBa0lnaUNFRElBTWdCeUFLZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHdoQXlBRElBZ2dDWDRnQWtMLy8vLy9ENE44SWdKQ0lJaDhRZ0dHSUFKQy8vLy8vdytEUWdHR0lnSkNJSWg4SVFNZ0F5QUNRdi8vLy84UGd5QUVRdi8vLy84UGczd2lBa0lnaUh3Z0JYd2hBeUFCSUFJK0FoUWdBeUlFUWlDSUlRVWdBRFVDR0NJTUlBWitJZ0pDSUlnaEF5QURJQWNnQzM0Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUlJQXArSUFKQy8vLy8vdytEZkNJQ1FpQ0lmRUlCaGlBQ1F2Ly8vLzhQZzBJQmhpSUNRaUNJZkNFRElBTWdDU0FKZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHdoQXlBRElBSkMvLy8vL3crRElBUkMvLy8vL3crRGZDSUNRaUNJZkNBRmZDRURJQUVnQWo0Q0dDQURJZ1JDSUlnaEJTQUFOUUljSWcwZ0JuNGlBa0lnaUNFRElBTWdCeUFNZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHdoQXlBRElBZ2dDMzRnQWtMLy8vLy9ENE44SWdKQ0lJaDhJUU1nQXlBSklBcCtJQUpDLy8vLy93K0RmQ0lDUWlDSWZFSUJoaUFDUXYvLy8vOFBnMElCaGlJQ1FpQ0lmQ0VESUFNZ0FrTC8vLy8vRDRNZ0JFTC8vLy8vRDROOElnSkNJSWg4SUFWOElRTWdBU0FDUGdJY0lBTWlCRUlnaUNFRklBY2dEWDRpQWtJZ2lDRURJQU1nQ0NBTWZpQUNRdi8vLy84UGczd2lBa0lnaUh3aEF5QURJQWtnQzM0Z0FrTC8vLy8vRDROOElnSkNJSWg4UWdHR0lBSkMvLy8vL3crRFFnR0dJZ0pDSUloOElRTWdBeUFLSUFwK0lBSkMvLy8vL3crRGZDSUNRaUNJZkNFRElBTWdBa0wvLy8vL0Q0TWdCRUwvLy8vL0Q0TjhJZ0pDSUloOElBVjhJUU1nQVNBQ1BnSWdJQU1pQkVJZ2lDRUZJQWdnRFg0aUFrSWdpQ0VESUFNZ0NTQU1maUFDUXYvLy8vOFBnM3dpQWtJZ2lId2hBeUFESUFvZ0MzNGdBa0wvLy8vL0Q0TjhJZ0pDSUloOFFnR0dJQUpDLy8vLy93K0RRZ0dHSWdKQ0lJaDhJUU1nQXlBQ1F2Ly8vLzhQZ3lBRVF2Ly8vLzhQZzN3aUFrSWdpSHdnQlh3aEF5QUJJQUkrQWlRZ0F5SUVRaUNJSVFVZ0NTQU5maUlDUWlDSUlRTWdBeUFLSUF4K0lBSkMvLy8vL3crRGZDSUNRaUNJZkVJQmhpQUNRdi8vLy84UGcwSUJoaUlDUWlDSWZDRURJQU1nQ3lBTGZpQUNRdi8vLy84UGczd2lBa0lnaUh3aEF5QURJQUpDLy8vLy93K0RJQVJDLy8vLy93K0RmQ0lDUWlDSWZDQUZmQ0VESUFFZ0FqNENLQ0FESWdSQ0lJZ2hCU0FLSUExK0lnSkNJSWdoQXlBRElBc2dESDRnQWtMLy8vLy9ENE44SWdKQ0lJaDhRZ0dHSUFKQy8vLy8vdytEUWdHR0lnSkNJSWg4SVFNZ0F5QUNRdi8vLy84UGd5QUVRdi8vLy84UGczd2lBa0lnaUh3Z0JYd2hBeUFCSUFJK0Fpd2dBeUlFUWlDSUlRVWdDeUFOZmlJQ1FpQ0lRZ0dHSUFKQy8vLy8vdytEUWdHR0lnSkNJSWg4SVFNZ0F5QU1JQXgrSUFKQy8vLy8vdytEZkNJQ1FpQ0lmQ0VESUFNZ0FrTC8vLy8vRDRNZ0JFTC8vLy8vRDROOElnSkNJSWg4SUFWOElRTWdBU0FDUGdJd0lBTWlCRUlnaUNFRklBd2dEWDRpQWtJZ2lFSUJoaUFDUXYvLy8vOFBnMElCaGlJQ1FpQ0lmQ0VESUFNZ0FrTC8vLy8vRDRNZ0JFTC8vLy8vRDROOElnSkNJSWg4SUFWOElRTWdBU0FDUGdJMElBTWlCRUlnaUNFRlFnQWhBa0lBSVFNZ0F5QU5JQTErSUFKQy8vLy8vdytEZkNJQ1FpQ0lmQ0VESUFNZ0FrTC8vLy8vRDRNZ0JFTC8vLy8vRDROOElnSkNJSWg4SUFWOElRTWdBU0FDUGdJNElBRWdBejRDUEFzS0FDQUFJQUFnQVJBSUMrUURBZ04rQVg4Z0FDQURRZWdBSUFNYklnTVFBQ0FCUVNnUUFDQUNRY2dBSUFJYklnY1FBVUdJQVJBQlFSOGhBRUVmSVFFRFFDQUJRU2hxTFFBQUlBRkJBMFp5UlFSQUlBRkJBV3NoQVF3QkN3c2dBVUVsYWpVQUFFSUJmQ0lHUWdGUkJFQkNBRUlBZ0JvTEEwQUNRQU5BSUFBZ0Eyb3RBQUFnQUVFSFJuSkZCRUFnQUVFQmF5RUFEQUVMQ3lBQUlBTnFRUWRyS1FBQUlBYUFJUVFnQUNBQmEwRUVheUVDQTBBZ0JFS0FnSUNBY0lOUUlBSkJBRTV4UlFSQUlBUkNDSWdoQkNBQ1FRRnFJUUlNQVFzTElBUlFCRUFnQTBFb0VBVkZEUUZDQVNFRVFRQWhBZ3RCcUFGQktEVUFBQ0FFZmlJRlBnQUFRYXdCUVN3MUFBQWdCSDRnQlVJZ2lId2lCVDRBQUVHd0FVRXdOUUFBSUFSK0lBVkNJSWg4SWdVK0FBQkJ0QUZCTkRVQUFDQUVmaUFGUWlDSWZDSUZQZ0FBUWJnQlFUZzFBQUFnQkg0Z0JVSWdpSHdpQlQ0QUFFRzhBVUU4TlFBQUlBUitJQVZDSUloOElnVStBQUJCd0FGQndBQTFBQUFnQkg0Z0JVSWdpSHdpQlQ0QUFFSEVBVUhFQURVQUFDQUVmaUFGUWlDSWZENEFBQ0FEUWFnQklBSnJJQU1RQnhvZ0FpQUhhaUlDSUFJMUFBQWdCSHdpQkQ0QUFDQUVRaUNJSVFRRFFDQUVRZ0JTQkVBZ0FrRUVhaUlDTlFBQUlBUjhJUVFnQWlBRVBnQUFJQVJDSUlnaEJBd0JDd3NNQVFzTEM0NENBUXAvUWNnQklRTkJ5QUVRQVVIb0FTRUlJQUZCNkFFUUFFR0lBaUVKUVlnQ0VBTkJxQUloQmlBQVFhZ0NFQUJCeUFJaEMwSG9BaUVLUWNnRElRUURRQ0FHRUFKRkJFQWdDQ0FHSUFzZ0NoQUxJQXNnQ1VHSUF4QUlJQWNFZnlBRkJIOUJpQU1nQXhBRkJIOUJpQU1nQXlBRUVBY2FRUUFGSUFOQmlBTWdCQkFIR2tFQkN3VkJpQU1nQXlBRUVBWWFRUUVMQlNBRkJIOUJpQU1nQXlBRUVBWWFRUUFGSUFOQmlBTVFCUVIvSUFOQmlBTWdCQkFIR2tFQUJVR0lBeUFESUFRUUJ4cEJBUXNMQ3lFTUlBTWhBQ0FKSVFNZ0JDRUpJQUFoQkNBRklRY2dEQ0VGSUFnaEFDQUdJUWdnQ2lFR0lBQWhDZ3dCQ3dzZ0J3UkFJQUVnQXlBQ0VBY2FCU0FESUFJUUFBc0xDUUFnQUVHb0JCQUVDeXdBSUFBZ0FTQUNFQVlFUUNBQ1FlZ0RJQUlRQnhvRklBSkI2QU1RQlFSQUlBSkI2QU1nQWhBSEdnc0xDeGNBSUFBZ0FTQUNFQWNFUUNBQ1FlZ0RJQUlRQmhvTEN3c0FRY2dFSUFBZ0FSQVBDN1lQQVFOK0lBQWdBRFVDQUVLSng1bWtEaUlFSUFBMUFnQitRdi8vLy84UGd5SURRZWdETlFJQWZud2lBajRDQUNBQUlBQTFBZ1FnQWtJZ2lIeEI3QU0xQWdBZ0EzNThJZ0krQWdRZ0FDQUFOUUlJSUFKQ0lJaDhRZkFETlFJQUlBTitmQ0lDUGdJSUlBQWdBRFVDRENBQ1FpQ0lmRUgwQXpVQ0FDQURmbndpQWo0Q0RDQUFJQUExQWhBZ0FrSWdpSHhCK0FNMUFnQWdBMzU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UWZ3RE5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVHQUJEVUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QmhBUTFBZ0FnQTM1OElnSStBaHhCaUFZZ0FrSWdpRDRDQUNBQUlBQTFBZ1FnQURVQ0JDQUVma0wvLy8vL0Q0TWlBMEhvQXpVQ0FINThJZ0krQWdRZ0FDQUFOUUlJSUFKQ0lJaDhRZXdETlFJQUlBTitmQ0lDUGdJSUlBQWdBRFVDRENBQ1FpQ0lmRUh3QXpVQ0FDQURmbndpQWo0Q0RDQUFJQUExQWhBZ0FrSWdpSHhCOUFNMUFnQWdBMzU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UWZnRE5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVIOEF6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QmdBUTFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFZUUVOUUlBSUFOK2ZDSUNQZ0lnUVl3R0lBSkNJSWcrQWdBZ0FDQUFOUUlJSUFBMUFnZ2dCSDVDLy8vLy93K0RJZ05CNkFNMUFnQitmQ0lDUGdJSUlBQWdBRFVDRENBQ1FpQ0lmRUhzQXpVQ0FDQURmbndpQWo0Q0RDQUFJQUExQWhBZ0FrSWdpSHhCOEFNMUFnQWdBMzU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UWZRRE5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVINEF6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4Qi9BTTFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFZQUVOUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFR0VCRFVDQUNBRGZud2lBajRDSkVHUUJpQUNRaUNJUGdJQUlBQWdBRFVDRENBQU5RSU1JQVIrUXYvLy8vOFBneUlEUWVnRE5RSUFmbndpQWo0Q0RDQUFJQUExQWhBZ0FrSWdpSHhCN0FNMUFnQWdBMzU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UWZBRE5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVIMEF6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QitBTTFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFmd0ROUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFR0FCRFVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEJoQVExQWdBZ0EzNThJZ0krQWloQmxBWWdBa0lnaUQ0Q0FDQUFJQUExQWhBZ0FEVUNFQ0FFZmtMLy8vLy9ENE1pQTBIb0F6VUNBSDU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UWV3RE5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVId0F6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QjlBTTFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFmZ0ROUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFSDhBelVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEJnQVExQWdBZ0EzNThJZ0krQWlnZ0FDQUFOUUlzSUFKQ0lJaDhRWVFFTlFJQUlBTitmQ0lDUGdJc1FaZ0dJQUpDSUlnK0FnQWdBQ0FBTlFJVUlBQTFBaFFnQkg1Qy8vLy8vdytESWdOQjZBTTFBZ0IrZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVIc0F6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QjhBTTFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFmUUROUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFSDRBelVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEIvQU0xQWdBZ0EzNThJZ0krQWlnZ0FDQUFOUUlzSUFKQ0lJaDhRWUFFTlFJQUlBTitmQ0lDUGdJc0lBQWdBRFVDTUNBQ1FpQ0lmRUdFQkRVQ0FDQURmbndpQWo0Q01FR2NCaUFDUWlDSVBnSUFJQUFnQURVQ0dDQUFOUUlZSUFSK1F2Ly8vLzhQZ3lJRFFlZ0ROUUlBZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QjdBTTFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFmQUROUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFSDBBelVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEIrQU0xQWdBZ0EzNThJZ0krQWlnZ0FDQUFOUUlzSUFKQ0lJaDhRZndETlFJQUlBTitmQ0lDUGdJc0lBQWdBRFVDTUNBQ1FpQ0lmRUdBQkRVQ0FDQURmbndpQWo0Q01DQUFJQUExQWpRZ0FrSWdpSHhCaEFRMUFnQWdBMzU4SWdJK0FqUkJvQVlnQWtJZ2lENENBQ0FBSUFBMUFod2dBRFVDSENBRWZrTC8vLy8vRDRNaUEwSG9BelVDQUg1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFld0ROUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFSHdBelVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEI5QU0xQWdBZ0EzNThJZ0krQWlnZ0FDQUFOUUlzSUFKQ0lJaDhRZmdETlFJQUlBTitmQ0lDUGdJc0lBQWdBRFVDTUNBQ1FpQ0lmRUg4QXpVQ0FDQURmbndpQWo0Q01DQUFJQUExQWpRZ0FrSWdpSHhCZ0FRMUFnQWdBMzU4SWdJK0FqUWdBQ0FBTlFJNElBSkNJSWg4UVlRRU5RSUFJQU4rZkNJQ1BnSTRRYVFHSUFKQ0lJZytBZ0JCaUFZZ0FFRWdhaUFCRUE0THdCd0JFMzRnQlNBQk5RSUFJZ1FnQURVQ0FDSU9mbndpQTBMLy8vLy9ENE1oQlNBR0lBQTFBZ1FpRHlBRWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUhJQUExQWdnaUVDQUVmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCeUFJSUFBMUFnd2lFU0FFZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ0NBSklBQTFBaEFpRWlBRWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUtJQUExQWhRaUV5QUVmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDaUFMSUFBMUFoZ2lGQ0FFZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ3lBTUlBQTFBaHdpRlNBRWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERDQURRaUNJSVEwZ0JTQUZRb25IbWFRT2ZrTC8vLy8vRDRNaUJFTEgrdlBERFg1OFFpQ0lJQVlnQkVLV21JTGhBMzU4ZkNJRFF2Ly8vLzhQZ3lFRklBY2dCRUtObGNmREJuNThJQU5DSUloOElnTkMvLy8vL3crRElRWWdDQ0FFUXBIVmhid0pmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCeUFKSUFSQzNiQ0ZqQWgrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVJSUFvZ0JFSzJpOEhDQzM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFrZ0N5QUVRcW5BeG9rT2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaENpQU1JQVJDOHB5Umd3TitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUxJQTBnQTBJZ2lId2hEQ0FGSUE0Z0FUVUNCQ0lFZm53aUEwTC8vLy8vRDRNaEJTQUdJQVFnRDM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFZZ0J5QUVJQkIrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFnZ0JDQVJmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDQ0FKSUFRZ0VuNThJQU5DSUloOElnTkMvLy8vL3crRElRa2dDaUFFSUJOK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFS0lBc2dCQ0FVZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ3lBTUlBUWdGWDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXdnQTBJZ2lDRU5JQVVnQlVLSng1bWtEbjVDLy8vLy93K0RJZ1JDeC9yend3MStmRUlnaUNBR0lBUkNscGlDNFFOK2ZId2lBMEwvLy8vL0Q0TWhCU0FISUFSQ2paWEh3d1orZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVHSUFnZ0JFS1IxWVc4Q1g1OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NTQUVRdDJ3aFl3SWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENDQUtJQVJDdG92QndndCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUpJQXNnQkVLcHdNYUpEbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUW9nRENBRVF2S2NrWU1EZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ3lBTklBTkNJSWg4SVF3Z0JTQU9JQUUxQWdnaUJINThJZ05DLy8vLy93K0RJUVVnQmlBRUlBOStmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUdJQWNnQkNBUWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJ5QUlJQVFnRVg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NTQUVJQkorZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVKSUFvZ0JDQVRmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDaUFMSUFRZ0ZINThJQU5DSUloOElnTkMvLy8vL3crRElRc2dEQ0FFSUJWK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTUlBTkNJSWdoRFNBRklBVkNpY2VacEE1K1F2Ly8vLzhQZ3lJRVFzZjY4OE1OZm54Q0lJZ2dCaUFFUXBhWWd1RURmbng4SWdOQy8vLy8vdytESVFVZ0J5QUVRbzJWeDhNR2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUlJQVJDa2RXRnZBbCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUhJQWtnQkVMZHNJV01DSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWdnQ2lBRVFyYUx3Y0lMZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ1NBTElBUkNxY0RHaVE1K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFS0lBd2dCRUx5bkpHREEzNThJQU5DSUloOElnTkMvLy8vL3crRElRc2dEU0FEUWlDSWZDRU1JQVVnRGlBQk5RSU1JZ1IrZkNJRFF2Ly8vLzhQZ3lFRklBWWdCQ0FQZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQmlBSElBUWdFSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWNnQ0NBRUlCRitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUlJQWtnQkNBU2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUtJQVFnRTM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFvZ0N5QUVJQlIrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVMSUF3Z0JDQVZmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEQ0FEUWlDSUlRMGdCU0FGUW9uSG1hUU9ma0wvLy8vL0Q0TWlCRUxIK3ZQRERYNThRaUNJSUFZZ0JFS1dtSUxoQTM1OGZDSURRdi8vLy84UGd5RUZJQWNnQkVLTmxjZkRCbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUVlnQ0NBRVFwSFZoYndKZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQnlBSklBUkMzYkNGakFoK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSUlBb2dCRUsyaThIQ0MzNThJQU5DSUloOElnTkMvLy8vL3crRElRa2dDeUFFUXFuQXhva09mbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDaUFNSUFSQzhweVJnd04rZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVMSUEwZ0EwSWdpSHdoRENBRklBNGdBVFVDRUNJRWZud2lBMEwvLy8vL0Q0TWhCU0FHSUFRZ0QzNThJQU5DSUloOElnTkMvLy8vL3crRElRWWdCeUFFSUJCK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSElBZ2dCQ0FSZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ0NBSklBUWdFbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWtnQ2lBRUlCTitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUtJQXNnQkNBVWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEN5QU1JQVFnRlg1OElBTkNJSWg4SWdOQy8vLy8vdytESVF3Z0EwSWdpQ0VOSUFVZ0JVS0p4NW1rRG41Qy8vLy8vdytESWdSQ3gvcnp3dzErZkVJZ2lDQUdJQVJDbHBpQzRRTitmSHdpQTBMLy8vLy9ENE1oQlNBSElBUkNqWlhId3daK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFR0lBZ2dCRUtSMVlXOENYNThJQU5DSUloOElnTkMvLy8vL3crRElRY2dDU0FFUXQyd2hZd0lmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDQ0FLSUFSQ3RvdkJ3Z3QrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVKSUFzZ0JFS3B3TWFKRG41OElBTkNJSWg4SWdOQy8vLy8vdytESVFvZ0RDQUVRdktja1lNRGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEN5QU5JQU5DSUloOElRd2dCU0FPSUFFMUFoUWlCSDU4SWdOQy8vLy8vdytESVFVZ0JpQUVJQTkrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVHSUFjZ0JDQVFmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCeUFJSUFRZ0VYNThJQU5DSUloOElnTkMvLy8vL3crRElRZ2dDU0FFSUJKK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSklBb2dCQ0FUZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ2lBTElBUWdGSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRENBRUlCVitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RU1JQU5DSUlnaERTQUZJQVZDaWNlWnBBNStRdi8vLy84UGd5SUVRc2Y2ODhNTmZueENJSWdnQmlBRVFwYVlndUVEZm54OElnTkMvLy8vL3crRElRVWdCeUFFUW8yVng4TUdmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFJSUFSQ2tkV0Z2QWwrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFrZ0JFTGRzSVdNQ0g1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NpQUVRcmFMd2NJTGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUxJQVJDcWNER2lRNStmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUtJQXdnQkVMeW5KR0RBMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRFNBRFFpQ0lmQ0VNSUFVZ0RpQUJOUUlZSWdSK2ZDSURRdi8vLy84UGd5RUZJQVlnQkNBUGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUhJQVFnRUg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NDQUVJQkYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVJSUFrZ0JDQVNmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FLSUFRZ0UzNThJQU5DSUloOElnTkMvLy8vL3crRElRb2dDeUFFSUJSK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTElBd2dCQ0FWZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRENBRFFpQ0lJUTBnQlNBRlFvbkhtYVFPZmtMLy8vLy9ENE1pQkVMSCt2UEREWDU4UWlDSUlBWWdCRUtXbUlMaEEzNThmQ0lEUXYvLy8vOFBneUVGSUFjZ0JFS05sY2ZEQm41OElBTkNJSWg4SWdOQy8vLy8vdytESVFZZ0NDQUVRcEhWaGJ3SmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJ5QUpJQVJDM2JDRmpBaCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUlJQW9nQkVLMmk4SENDMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWtnQ3lBRVFxbkF4b2tPZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ2lBTUlBUkM4cHlSZ3dOK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTElBMGdBMElnaUh3aERDQUZJQTRnQVRVQ0hDSUVmbndpQTBMLy8vLy9ENE1oQlNBR0lBUWdEMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUVlnQnlBRUlCQitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUhJQWdnQkNBUmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENDQUpJQVFnRW41OElBTkNJSWg4SWdOQy8vLy8vdytESVFrZ0NpQUVJQk4rZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVLSUFzZ0JDQVVmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDeUFNSUFRZ0ZYNThJQU5DSUloOElnTkMvLy8vL3crRElRd2dBMElnaUNFTklBSWdCU0FGUW9uSG1hUU9ma0wvLy8vL0Q0TWlCRUxIK3ZQRERYNThRaUNJSUFZZ0JFS1dtSUxoQTM1OGZDSURRdi8vLy84UGd6NENBQ0FDSUFjZ0JFS05sY2ZEQm41OElBTkNJSWg4SWdOQy8vLy8vdytEUGdJRUlBSWdDQ0FFUXBIVmhid0pmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TStBZ2dnQWlBSklBUkMzYkNGakFoK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3o0Q0RDQUNJQW9nQkVLMmk4SENDMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RQZ0lRSUFJZ0N5QUVRcW5BeG9rT2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNK0FoUWdBaUFNSUFSQzhweVJnd04rZkNBRFFpQ0lmQ0lEUXYvLy8vOFBnejRDR0NBQ0lBMGdBMElnaUh3K0Fod2dBa0hvQXhBRkJFQWdBa0hvQXlBQ0VBY2FDd3ZvSFFFVGZpQUlJQUExQWdBaURTQU5mbndpQWtMLy8vLy9ENE1oQ0NBTUlBQTFBZ1FpRHlBTmZpSURRdi8vLy84UGcwSUJobndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhEQ0FEUWlDSVFnR0dJQUpDSUloOElBc2dBRFVDQ0NJUUlBMStJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEN5QURRaUNJUWdHR0lBSkNJSWg4SUFvZ0FEVUNEQ0lSSUExK0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQ2lBRFFpQ0lRZ0dHSUFKQ0lJaDhJQWtnQURVQ0VDSVNJQTErSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhDU0FEUWlDSVFnR0dJQUpDSUloOElBY2dBRFVDRkNJVElBMStJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJ5QURRaUNJUWdHR0lBSkNJSWg4SUFZZ0FEVUNHQ0lVSUExK0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQmlBRFFpQ0lRZ0dHSUFKQ0lJaDhJQVFnRFNBQU5RSWNJZzErSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhCQ0FGSUFOQ0lJaENBWVlnQWtJZ2lIeDhJZ0pDLy8vLy93K0RJUVVnRGlBQ1FpQ0lmQ0VPSUFnZ0NFS0p4NW1rRG41Qy8vLy8vdytESWdOQ3gvcnp3dzErZkVJZ2lDQU1JQU5DbHBpQzRRTitmSHdpQWtMLy8vLy9ENE1oQ0NBTElBTkNqWlhId3daK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFTUlBb2dBMEtSMVlXOENYNThJQUpDSUloOElnSkMvLy8vL3crRElRc2dDU0FEUXQyd2hZd0lmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhDaUFISUFOQ3RvdkJ3Z3QrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVKSUFZZ0EwS3B3TWFKRG41OElBSkNJSWg4SWdKQy8vLy8vdytESVFjZ0JDQURRdktja1lNRGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEJpQUZJQUpDSUloOElnSkMvLy8vL3crRElRUWdEaUFDUWlDSWZDRUZJQXdnRHlBUGZud2lBa0wvLy8vL0Q0TWhEQ0FMSUE4Z0VINGlBMEwvLy8vL0Q0TkNBWVo4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQTBJZ2lFSUJoaUFDUWlDSWZDQUtJQThnRVg0aUEwTC8vLy8vRDROQ0FZWjhmQ0lDUXYvLy8vOFBneUVLSUFOQ0lJaENBWVlnQWtJZ2lId2dDU0FQSUJKK0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQ1NBRFFpQ0lRZ0dHSUFKQ0lJaDhJQWNnRHlBVGZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFjZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FHSUE4Z0ZINGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFR0lBTkNJSWhDQVlZZ0FrSWdpSHdnQkNBTklBOStJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJDQUZJQU5DSUloQ0FZWWdBa0lnaUh4OElnSkMvLy8vL3crRElRVWdBa0lnaUNFT0lBZ2dDRUtKeDVta0RuNUMvLy8vL3crRElnTkN4L3J6d3cxK2ZFSWdpQ0FNSUFOQ2xwaUM0UU4rZkh3aUFrTC8vLy8vRDRNaENDQUxJQU5DalpYSHd3WitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU1JQW9nQTBLUjFZVzhDWDU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQ1NBRFF0MndoWXdJZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ2lBSElBTkN0b3ZCd2d0K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSklBWWdBMEtwd01hSkRuNThJQUpDSUloOElnSkMvLy8vL3crRElRY2dCQ0FEUXZLY2tZTURmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCaUFGSUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVFnRGlBQ1FpQ0lmQ0VGSUFzZ0VDQVFmbndpQWtMLy8vLy9ENE1oQ3lBS0lCQWdFWDRpQTBMLy8vLy9ENE5DQVlaOElBSkNJSWg4SWdKQy8vLy8vdytESVFvZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FKSUJBZ0VuNGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFSklBTkNJSWhDQVlZZ0FrSWdpSHdnQnlBUUlCTitJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJ5QURRaUNJUWdHR0lBSkNJSWg4SUFZZ0VDQVVmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRWWdBMElnaUVJQmhpQUNRaUNJZkNBRUlBMGdFSDRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUVJQVVnQTBJZ2lFSUJoaUFDUWlDSWZId2lBa0wvLy8vL0Q0TWhCU0FDUWlDSUlRNGdDQ0FJUW9uSG1hUU9ma0wvLy8vL0Q0TWlBMExIK3ZQRERYNThRaUNJSUF3Z0EwS1dtSUxoQTM1OGZDSUNRdi8vLy84UGd5RUlJQXNnQTBLTmxjZkRCbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXdnQ2lBRFFwSFZoYndKZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ3lBSklBTkMzYkNGakFoK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFS0lBY2dBMEsyaThIQ0MzNThJQUpDSUloOElnSkMvLy8vL3crRElRa2dCaUFEUXFuQXhva09mbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCeUFFSUFOQzhweVJnd04rZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVHSUFVZ0FrSWdpSHdpQWtMLy8vLy9ENE1oQkNBT0lBSkNJSWg4SVFVZ0NpQVJJQkYrZkNJQ1F2Ly8vLzhQZ3lFS0lBa2dFU0FTZmlJRFF2Ly8vLzhQZzBJQmhud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENTQURRaUNJUWdHR0lBSkNJSWg4SUFjZ0VTQVRmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRY2dBMElnaUVJQmhpQUNRaUNJZkNBR0lCRWdGSDRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUdJQU5DSUloQ0FZWWdBa0lnaUh3Z0JDQU5JQkYrSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhCQ0FGSUFOQ0lJaENBWVlnQWtJZ2lIeDhJZ0pDLy8vLy93K0RJUVVnQWtJZ2lDRU9JQWdnQ0VLSng1bWtEbjVDLy8vLy93K0RJZ05DeC9yend3MStmRUlnaUNBTUlBTkNscGlDNFFOK2ZId2lBa0wvLy8vL0Q0TWhDQ0FMSUFOQ2paWEh3d1orZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVNSUFvZ0EwS1IxWVc4Q1g1OElBSkNJSWg4SWdKQy8vLy8vdytESVFzZ0NTQURRdDJ3aFl3SWZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENpQUhJQU5DdG92QndndCtmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUpJQVlnQTBLcHdNYUpEbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUWNnQkNBRFF2S2NrWU1EZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQmlBRklBSkNJSWg4SWdKQy8vLy8vdytESVFRZ0RpQUNRaUNJZkNFRklBa2dFaUFTZm53aUFrTC8vLy8vRDRNaENTQUhJQklnRTM0aUEwTC8vLy8vRDROQ0FZWjhJQUpDSUloOElnSkMvLy8vL3crRElRY2dBMElnaUVJQmhpQUNRaUNJZkNBR0lCSWdGSDRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUdJQU5DSUloQ0FZWWdBa0lnaUh3Z0JDQU5JQkorSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhCQ0FGSUFOQ0lJaENBWVlnQWtJZ2lIeDhJZ0pDLy8vLy93K0RJUVVnQWtJZ2lDRU9JQWdnQ0VLSng1bWtEbjVDLy8vLy93K0RJZ05DeC9yend3MStmRUlnaUNBTUlBTkNscGlDNFFOK2ZId2lBa0wvLy8vL0Q0TWhDQ0FMSUFOQ2paWEh3d1orZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVNSUFvZ0EwS1IxWVc4Q1g1OElBSkNJSWg4SWdKQy8vLy8vdytESVFzZ0NTQURRdDJ3aFl3SWZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENpQUhJQU5DdG92QndndCtmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUpJQVlnQTBLcHdNYUpEbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUWNnQkNBRFF2S2NrWU1EZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQmlBRklBSkNJSWg4SWdKQy8vLy8vdytESVFRZ0RpQUNRaUNJZkNFRklBY2dFeUFUZm53aUFrTC8vLy8vRDRNaEJ5QUdJQk1nRkg0aUEwTC8vLy8vRDROQ0FZWjhJQUpDSUloOElnSkMvLy8vL3crRElRWWdBMElnaUVJQmhpQUNRaUNJZkNBRUlBMGdFMzRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUVJQVVnQTBJZ2lFSUJoaUFDUWlDSWZId2lBa0wvLy8vL0Q0TWhCU0FDUWlDSUlRNGdDQ0FJUW9uSG1hUU9ma0wvLy8vL0Q0TWlBMExIK3ZQRERYNThRaUNJSUF3Z0EwS1dtSUxoQTM1OGZDSUNRdi8vLy84UGd5RUlJQXNnQTBLTmxjZkRCbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXdnQ2lBRFFwSFZoYndKZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ3lBSklBTkMzYkNGakFoK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFS0lBY2dBMEsyaThIQ0MzNThJQUpDSUloOElnSkMvLy8vL3crRElRa2dCaUFEUXFuQXhva09mbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCeUFFSUFOQzhweVJnd04rZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVHSUFVZ0FrSWdpSHdpQWtMLy8vLy9ENE1oQkNBT0lBSkNJSWg4SVFVZ0JpQVVJQlIrZkNJQ1F2Ly8vLzhQZ3lFR0lBUWdEU0FVZmlJRFF2Ly8vLzhQZzBJQmhud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEJDQUZJQU5DSUloQ0FZWWdBa0lnaUh4OElnSkMvLy8vL3crRElRVWdBa0lnaUNFT0lBZ2dDRUtKeDVta0RuNUMvLy8vL3crRElnTkN4L3J6d3cxK2ZFSWdpQ0FNSUFOQ2xwaUM0UU4rZkh3aUFrTC8vLy8vRDRNaENDQUxJQU5DalpYSHd3WitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU1JQW9nQTBLUjFZVzhDWDU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQ1NBRFF0MndoWXdJZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ2lBSElBTkN0b3ZCd2d0K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSklBWWdBMEtwd01hSkRuNThJQUpDSUloOElnSkMvLy8vL3crRElRY2dCQ0FEUXZLY2tZTURmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCaUFGSUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVFnRGlBQ1FpQ0lmQ0VGSUFRZ0RTQU5mbndpQWtMLy8vLy9ENE1oQkNBRklBSkNJSWg4SWdKQy8vLy8vdytESVFVZ0FrSWdpQ0VPSUFFZ0NDQUlRb25IbWFRT2ZrTC8vLy8vRDRNaUEwTEgrdlBERFg1OFFpQ0lJQXdnQTBLV21JTGhBMzU4ZkNJQ1F2Ly8vLzhQZ3o0Q0FDQUJJQXNnQTBLTmxjZkRCbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RQZ0lFSUFFZ0NpQURRcEhWaGJ3SmZud2dBa0lnaUh3aUFrTC8vLy8vRDRNK0FnZ2dBU0FKSUFOQzNiQ0ZqQWgrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBnejRDRENBQklBY2dBMEsyaThIQ0MzNThJQUpDSUloOElnSkMvLy8vL3crRFBnSVFJQUVnQmlBRFFxbkF4b2tPZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE0rQWhRZ0FTQUVJQU5DOHB5Umd3TitmQ0FDUWlDSWZDSUNRdi8vLy84UGd6NENHQ0FCSUFVZ0FrSWdpSHdpQWtMLy8vLy9ENE0rQWh3Z0RpQUNRaUNJZktjRVFDQUJRZWdESUFFUUJ4b0ZJQUZCNkFNUUJRUkFJQUZCNkFNZ0FSQUhHZ3NMQ3dvQUlBQWdBQ0FCRUJJTEN3QWdBRUdJQkNBQkVCSUxGUUFnQUVHSUNoQUFRYWdLRUFGQmlBb2dBUkFSQ3hFQUlBQkJ5QW9RRmtISUNrR0lCUkFGQ3lNQUlBQVFBZ1JBUVFBUEN5QUFRZWdLRUJaQjZBcEJpQVVRQlFSQVFYOFBDMEVCQ3hjQUlBQWdBUkFXSUFGQjZBTWdBUkFNSUFFZ0FSQVZDd2tBUWFnRUlBQVFBQXU4QVFFQ2Z5QUNFQUZCSUNFREEwQWdBU0FEVHdSQUlBTkJJRVlFUUVHSUN4QWFCVUdJQzBHSUJFR0lDeEFTQ3lBQVFZZ0xRYWdMRUJJZ0FrR29DeUFDRUE0Z0FFRWdhaUVBSUFOQklHb2hBd3dCQ3dzZ0FVRWZjU0lFUlFSQUR3dEJxQXNRQVVFQUlRRURRQ0FCSUFSR1JRUkFJQUVnQUMwQUFEb0FxQXNnQUVFQmFpRUFJQUZCQVdvaEFRd0JDd3NnQTBFZ1JnUkFRWWdMRUJvRlFZZ0xRWWdFUVlnTEVCSUxRYWdMUVlnTFFhZ0xFQklnQWtHb0N5QUNFQTRMSEFBZ0FTQUNRY2dMRUJ0QnlBdEJ5QXNRRlNBQVFjZ0xJQU1RRWd2aEFRRUNmMEVBUVFBb0FnQWlCU0FDUVFGcVFRVjBhallDQUNBRkVCb2dCVUVnYWlFRkEwQWdBaUFHUndSQUlBQVFBZ1JBSUFWQklHc2dCUkFBQlNBQUlBVkJJR3NnQlJBU0N5QUFJQUZxSVFBZ0JVRWdhaUVGSUFaQkFXb2hCZ3dCQ3dzZ0FDQUJheUVBSUFNZ0FrRUJheUFFYkdvaEFpQUZRU0JySWdVZ0JSQVpBMEFnQmdSQUlBQVFBZ1JBSUFVZ0JVRWdheEFBSUFJUUFRVWdCVUVnYTBIb0N4QUFJQVVnQUNBRlFTQnJFQklnQlVIb0N5QUNFQklMSUFBZ0FXc2hBQ0FDSUFScklRSWdCVUVnYXlFRklBWkJBV3NoQmd3QkN3dEJBQ0FGTmdJQUN5MEJBWDhEUUNBQklBTkdSUVJBSUFBZ0FoQVZJQUJCSUdvaEFDQUNRU0JxSVFJZ0EwRUJhaUVEREFFTEN3c3RBUUYvQTBBZ0FTQURSa1VFUUNBQUlBSVFGaUFBUVNCcUlRQWdBa0VnYWlFQ0lBTkJBV29oQXd3QkN3c0xsd0lBSUFKRkJFQWdBeEFhRHdzZ0FFR0lEQkFBSUFNUUdnTkFJQUpCQVdzaUFpQUJhaTBBQUNFQUlBTWdBeEFUSUFCQmdBRlBCRUFnQTBHSURDQURFQklnQUVHQUFXc2hBQXNnQXlBREVCTWdBRUhBQUU4RVFDQURRWWdNSUFNUUVpQUFRVUJxSVFBTElBTWdBeEFUSUFCQklFOEVRQ0FEUVlnTUlBTVFFaUFBUVNCcklRQUxJQU1nQXhBVElBQkJFRThFUUNBRFFZZ01JQU1RRWlBQVFSQnJJUUFMSUFNZ0F4QVRJQUJCQ0U4RVFDQURRWWdNSUFNUUVpQUFRUWhySVFBTElBTWdBeEFUSUFCQkJFOEVRQ0FEUVlnTUlBTVFFaUFBUVFScklRQUxJQU1nQXhBVElBQkJBazhFUUNBRFFZZ01JQU1RRWlBQVFRSnJJUUFMSUFNZ0F4QVRJQUFFUUNBRFFZZ01JQU1RRWdzZ0FnMEFDd3ZWQVFFQmZ5QUFFQUlFUUNBQkVBRVBDMEVCSVFKQnlBVkJxQXdRQUNBQVFhZ0ZRU0JCeUF3UUlDQUFRZWdGUVNCQjZBd1FJQU5BUWNnTVFhZ0VFQVJGQkVCQnlBeEJpQTBRRTBFQklRQURRRUdJRFVHb0JCQUVSUVJBUVlnTlFZZ05FQk1nQUVFQmFpRUFEQUVMQzBHb0RFR29EUkFBSUFJZ0FHdEJBV3NoQWdOQUlBSUVRRUdvRFVHb0RSQVRJQUpCQVdzaEFnd0JDd3NnQUNFQ1FhZ05RYWdNRUJOQnlBeEJxQXhCeUF3UUVrSG9ERUdvRFVIb0RCQVNEQUVMQzBIb0RCQVhCRUJCNkF3Z0FSQVFCVUhvRENBQkVBQUxDeUFBSUFBUUFnUkFRUUVQQ3lBQVFlZ0VRU0JCeUEwUUlFSElEVUdvQkJBRUN3a0FJQUJCcUE0UUJBc3NBQ0FBSUFFZ0FoQUdCRUFnQWtIb0RTQUNFQWNhQlNBQ1FlZ05FQVVFUUNBQ1FlZ05JQUlRQnhvTEN3c1hBQ0FBSUFFZ0FoQUhCRUFnQWtIb0RTQUNFQVlhQ3dzTEFFSElEaUFBSUFFUUpRdTJEd0VEZmlBQUlBQTFBZ0JDLy8vLy93NGlCQ0FBTlFJQWZrTC8vLy8vRDRNaUEwSG9EVFVDQUg1OElnSStBZ0FnQUNBQU5RSUVJQUpDSUloOFFld05OUUlBSUFOK2ZDSUNQZ0lFSUFBZ0FEVUNDQ0FDUWlDSWZFSHdEVFVDQUNBRGZud2lBajRDQ0NBQUlBQTFBZ3dnQWtJZ2lIeEI5QTAxQWdBZ0EzNThJZ0krQWd3Z0FDQUFOUUlRSUFKQ0lJaDhRZmdOTlFJQUlBTitmQ0lDUGdJUUlBQWdBRFVDRkNBQ1FpQ0lmRUg4RFRVQ0FDQURmbndpQWo0Q0ZDQUFJQUExQWhnZ0FrSWdpSHhCZ0E0MUFnQWdBMzU4SWdJK0FoZ2dBQ0FBTlFJY0lBSkNJSWg4UVlRT05RSUFJQU4rZkNJQ1BnSWNRWWdRSUFKQ0lJZytBZ0FnQUNBQU5RSUVJQUExQWdRZ0JINUMvLy8vL3crRElnTkI2QTAxQWdCK2ZDSUNQZ0lFSUFBZ0FEVUNDQ0FDUWlDSWZFSHNEVFVDQUNBRGZud2lBajRDQ0NBQUlBQTFBZ3dnQWtJZ2lIeEI4QTAxQWdBZ0EzNThJZ0krQWd3Z0FDQUFOUUlRSUFKQ0lJaDhRZlFOTlFJQUlBTitmQ0lDUGdJUUlBQWdBRFVDRkNBQ1FpQ0lmRUg0RFRVQ0FDQURmbndpQWo0Q0ZDQUFJQUExQWhnZ0FrSWdpSHhCL0EwMUFnQWdBMzU4SWdJK0FoZ2dBQ0FBTlFJY0lBSkNJSWg4UVlBT05RSUFJQU4rZkNJQ1BnSWNJQUFnQURVQ0lDQUNRaUNJZkVHRURqVUNBQ0FEZm53aUFqNENJRUdNRUNBQ1FpQ0lQZ0lBSUFBZ0FEVUNDQ0FBTlFJSUlBUitRdi8vLy84UGd5SURRZWdOTlFJQWZud2lBajRDQ0NBQUlBQTFBZ3dnQWtJZ2lIeEI3QTAxQWdBZ0EzNThJZ0krQWd3Z0FDQUFOUUlRSUFKQ0lJaDhRZkFOTlFJQUlBTitmQ0lDUGdJUUlBQWdBRFVDRkNBQ1FpQ0lmRUgwRFRVQ0FDQURmbndpQWo0Q0ZDQUFJQUExQWhnZ0FrSWdpSHhCK0EwMUFnQWdBMzU4SWdJK0FoZ2dBQ0FBTlFJY0lBSkNJSWg4UWZ3Tk5RSUFJQU4rZkNJQ1BnSWNJQUFnQURVQ0lDQUNRaUNJZkVHQURqVUNBQ0FEZm53aUFqNENJQ0FBSUFBMUFpUWdBa0lnaUh4QmhBNDFBZ0FnQTM1OElnSStBaVJCa0JBZ0FrSWdpRDRDQUNBQUlBQTFBZ3dnQURVQ0RDQUVma0wvLy8vL0Q0TWlBMEhvRFRVQ0FINThJZ0krQWd3Z0FDQUFOUUlRSUFKQ0lJaDhRZXdOTlFJQUlBTitmQ0lDUGdJUUlBQWdBRFVDRkNBQ1FpQ0lmRUh3RFRVQ0FDQURmbndpQWo0Q0ZDQUFJQUExQWhnZ0FrSWdpSHhCOUEwMUFnQWdBMzU4SWdJK0FoZ2dBQ0FBTlFJY0lBSkNJSWg4UWZnTk5RSUFJQU4rZkNJQ1BnSWNJQUFnQURVQ0lDQUNRaUNJZkVIOERUVUNBQ0FEZm53aUFqNENJQ0FBSUFBMUFpUWdBa0lnaUh4QmdBNDFBZ0FnQTM1OElnSStBaVFnQUNBQU5RSW9JQUpDSUloOFFZUU9OUUlBSUFOK2ZDSUNQZ0lvUVpRUUlBSkNJSWcrQWdBZ0FDQUFOUUlRSUFBMUFoQWdCSDVDLy8vLy93K0RJZ05CNkEwMUFnQitmQ0lDUGdJUUlBQWdBRFVDRkNBQ1FpQ0lmRUhzRFRVQ0FDQURmbndpQWo0Q0ZDQUFJQUExQWhnZ0FrSWdpSHhCOEEwMUFnQWdBMzU4SWdJK0FoZ2dBQ0FBTlFJY0lBSkNJSWg4UWZRTk5RSUFJQU4rZkNJQ1BnSWNJQUFnQURVQ0lDQUNRaUNJZkVINERUVUNBQ0FEZm53aUFqNENJQ0FBSUFBMUFpUWdBa0lnaUh4Qi9BMDFBZ0FnQTM1OElnSStBaVFnQUNBQU5RSW9JQUpDSUloOFFZQU9OUUlBSUFOK2ZDSUNQZ0lvSUFBZ0FEVUNMQ0FDUWlDSWZFR0VEalVDQUNBRGZud2lBajRDTEVHWUVDQUNRaUNJUGdJQUlBQWdBRFVDRkNBQU5RSVVJQVIrUXYvLy8vOFBneUlEUWVnTk5RSUFmbndpQWo0Q0ZDQUFJQUExQWhnZ0FrSWdpSHhCN0EwMUFnQWdBMzU4SWdJK0FoZ2dBQ0FBTlFJY0lBSkNJSWg4UWZBTk5RSUFJQU4rZkNJQ1BnSWNJQUFnQURVQ0lDQUNRaUNJZkVIMERUVUNBQ0FEZm53aUFqNENJQ0FBSUFBMUFpUWdBa0lnaUh4QitBMDFBZ0FnQTM1OElnSStBaVFnQUNBQU5RSW9JQUpDSUloOFFmd05OUUlBSUFOK2ZDSUNQZ0lvSUFBZ0FEVUNMQ0FDUWlDSWZFR0FEalVDQUNBRGZud2lBajRDTENBQUlBQTFBakFnQWtJZ2lIeEJoQTQxQWdBZ0EzNThJZ0krQWpCQm5CQWdBa0lnaUQ0Q0FDQUFJQUExQWhnZ0FEVUNHQ0FFZmtMLy8vLy9ENE1pQTBIb0RUVUNBSDU4SWdJK0FoZ2dBQ0FBTlFJY0lBSkNJSWg4UWV3Tk5RSUFJQU4rZkNJQ1BnSWNJQUFnQURVQ0lDQUNRaUNJZkVId0RUVUNBQ0FEZm53aUFqNENJQ0FBSUFBMUFpUWdBa0lnaUh4QjlBMDFBZ0FnQTM1OElnSStBaVFnQUNBQU5RSW9JQUpDSUloOFFmZ05OUUlBSUFOK2ZDSUNQZ0lvSUFBZ0FEVUNMQ0FDUWlDSWZFSDhEVFVDQUNBRGZud2lBajRDTENBQUlBQTFBakFnQWtJZ2lIeEJnQTQxQWdBZ0EzNThJZ0krQWpBZ0FDQUFOUUkwSUFKQ0lJaDhRWVFPTlFJQUlBTitmQ0lDUGdJMFFhQVFJQUpDSUlnK0FnQWdBQ0FBTlFJY0lBQTFBaHdnQkg1Qy8vLy8vdytESWdOQjZBMDFBZ0IrZkNJQ1BnSWNJQUFnQURVQ0lDQUNRaUNJZkVIc0RUVUNBQ0FEZm53aUFqNENJQ0FBSUFBMUFpUWdBa0lnaUh4QjhBMDFBZ0FnQTM1OElnSStBaVFnQUNBQU5RSW9JQUpDSUloOFFmUU5OUUlBSUFOK2ZDSUNQZ0lvSUFBZ0FEVUNMQ0FDUWlDSWZFSDREVFVDQUNBRGZud2lBajRDTENBQUlBQTFBakFnQWtJZ2lIeEIvQTAxQWdBZ0EzNThJZ0krQWpBZ0FDQUFOUUkwSUFKQ0lJaDhRWUFPTlFJQUlBTitmQ0lDUGdJMElBQWdBRFVDT0NBQ1FpQ0lmRUdFRGpVQ0FDQURmbndpQWo0Q09FR2tFQ0FDUWlDSVBnSUFRWWdRSUFCQklHb2dBUkFrQzhBY0FSTitJQVVnQVRVQ0FDSUVJQUExQWdBaURuNThJZ05DLy8vLy93K0RJUVVnQmlBQU5RSUVJZzhnQkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFZZ0J5QUFOUUlJSWhBZ0JINThJQU5DSUloOElnTkMvLy8vL3crRElRY2dDQ0FBTlFJTUloRWdCSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWdnQ1NBQU5RSVFJaElnQkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFrZ0NpQUFOUUlVSWhNZ0JINThJQU5DSUloOElnTkMvLy8vL3crRElRb2dDeUFBTlFJWUloUWdCSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRENBQU5RSWNJaFVnQkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVF3Z0EwSWdpQ0VOSUFVZ0JVTC8vLy8vRG41Qy8vLy8vdytESWdSQ2dZQ0FnQTkrZkVJZ2lDQUdJQVJDayt1SG53UitmSHdpQTBMLy8vLy9ENE1oQlNBSElBUkNrZUhselFkK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFR0lBZ2dCRUxJME0vQkFuNThJQU5DSUloOElnTkMvLy8vL3crRElRY2dDU0FFUXQyd2hZd0lmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDQ0FLSUFSQ3RvdkJ3Z3QrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVKSUFzZ0JFS3B3TWFKRG41OElBTkNJSWg4SWdOQy8vLy8vdytESVFvZ0RDQUVRdktja1lNRGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEN5QU5JQU5DSUloOElRd2dCU0FPSUFFMUFnUWlCSDU4SWdOQy8vLy8vdytESVFVZ0JpQUVJQTkrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVHSUFjZ0JDQVFmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCeUFJSUFRZ0VYNThJQU5DSUloOElnTkMvLy8vL3crRElRZ2dDU0FFSUJKK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSklBb2dCQ0FUZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ2lBTElBUWdGSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRENBRUlCVitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RU1JQU5DSUlnaERTQUZJQVZDLy8vLy93NStRdi8vLy84UGd5SUVRb0dBZ0lBUGZueENJSWdnQmlBRVFwUHJoNThFZm54OElnTkMvLy8vL3crRElRVWdCeUFFUXBIaDVjMEhmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFJSUFSQ3lORFB3UUorZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFrZ0JFTGRzSVdNQ0g1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NpQUVRcmFMd2NJTGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUxJQVJDcWNER2lRNStmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUtJQXdnQkVMeW5KR0RBMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRFNBRFFpQ0lmQ0VNSUFVZ0RpQUJOUUlJSWdSK2ZDSURRdi8vLy84UGd5RUZJQVlnQkNBUGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUhJQVFnRUg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NDQUVJQkYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVJSUFrZ0JDQVNmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FLSUFRZ0UzNThJQU5DSUloOElnTkMvLy8vL3crRElRb2dDeUFFSUJSK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTElBd2dCQ0FWZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRENBRFFpQ0lJUTBnQlNBRlF2Ly8vLzhPZmtMLy8vLy9ENE1pQkVLQmdJQ0FEMzU4UWlDSUlBWWdCRUtUNjRlZkJINThmQ0lEUXYvLy8vOFBneUVGSUFjZ0JFS1I0ZVhOQjM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFZZ0NDQUVRc2pRejhFQ2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJ5QUpJQVJDM2JDRmpBaCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUlJQW9nQkVLMmk4SENDMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWtnQ3lBRVFxbkF4b2tPZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ2lBTUlBUkM4cHlSZ3dOK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTElBMGdBMElnaUh3aERDQUZJQTRnQVRVQ0RDSUVmbndpQTBMLy8vLy9ENE1oQlNBR0lBUWdEMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUVlnQnlBRUlCQitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUhJQWdnQkNBUmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENDQUpJQVFnRW41OElBTkNJSWg4SWdOQy8vLy8vdytESVFrZ0NpQUVJQk4rZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVLSUFzZ0JDQVVmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDeUFNSUFRZ0ZYNThJQU5DSUloOElnTkMvLy8vL3crRElRd2dBMElnaUNFTklBVWdCVUwvLy8vL0RuNUMvLy8vL3crRElnUkNnWUNBZ0E5K2ZFSWdpQ0FHSUFSQ2srdUhud1IrZkh3aUEwTC8vLy8vRDRNaEJTQUhJQVJDa2VIbHpRZCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUdJQWdnQkVMSTBNL0JBbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWNnQ1NBRVF0MndoWXdJZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ0NBS0lBUkN0b3ZCd2d0K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSklBc2dCRUtwd01hSkRuNThJQU5DSUloOElnTkMvLy8vL3crRElRb2dEQ0FFUXZLY2tZTURmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDeUFOSUFOQ0lJaDhJUXdnQlNBT0lBRTFBaEFpQkg1OElnTkMvLy8vL3crRElRVWdCaUFFSUE5K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFR0lBY2dCQ0FRZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQnlBSUlBUWdFWDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWdnQ1NBRUlCSitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUpJQW9nQkNBVGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENpQUxJQVFnRkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFzZ0RDQUVJQlYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVNSUFOQ0lJZ2hEU0FGSUFWQy8vLy8vdzUrUXYvLy8vOFBneUlFUW9HQWdJQVBmbnhDSUlnZ0JpQUVRcFByaDU4RWZueDhJZ05DLy8vLy93K0RJUVVnQnlBRVFwSGg1YzBIZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQmlBSUlBUkN5TkRQd1FKK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSElBa2dCRUxkc0lXTUNINThJQU5DSUloOElnTkMvLy8vL3crRElRZ2dDaUFFUXJhTHdjSUxmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FMSUFSQ3FjREdpUTUrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVLSUF3Z0JFTHluSkdEQTM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFzZ0RTQURRaUNJZkNFTUlBVWdEaUFCTlFJVUlnUitmQ0lEUXYvLy8vOFBneUVGSUFZZ0JDQVBmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFISUFRZ0VINThJQU5DSUloOElnTkMvLy8vL3crRElRY2dDQ0FFSUJGK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSUlBa2dCQ0FTZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ1NBS0lBUWdFMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUW9nQ3lBRUlCUitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUxJQXdnQkNBVmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERDQURRaUNJSVEwZ0JTQUZRdi8vLy84T2ZrTC8vLy8vRDRNaUJFS0JnSUNBRDM1OFFpQ0lJQVlnQkVLVDY0ZWZCSDU4ZkNJRFF2Ly8vLzhQZ3lFRklBY2dCRUtSNGVYTkIzNThJQU5DSUloOElnTkMvLy8vL3crRElRWWdDQ0FFUXNqUXo4RUNmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCeUFKSUFSQzNiQ0ZqQWgrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVJSUFvZ0JFSzJpOEhDQzM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFrZ0N5QUVRcW5BeG9rT2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaENpQU1JQVJDOHB5Umd3TitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUxJQTBnQTBJZ2lId2hEQ0FGSUE0Z0FUVUNHQ0lFZm53aUEwTC8vLy8vRDRNaEJTQUdJQVFnRDM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFZZ0J5QUVJQkIrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFnZ0JDQVJmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDQ0FKSUFRZ0VuNThJQU5DSUloOElnTkMvLy8vL3crRElRa2dDaUFFSUJOK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFS0lBc2dCQ0FVZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ3lBTUlBUWdGWDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXdnQTBJZ2lDRU5JQVVnQlVMLy8vLy9EbjVDLy8vLy93K0RJZ1JDZ1lDQWdBOStmRUlnaUNBR0lBUkNrK3VIbndSK2ZId2lBMEwvLy8vL0Q0TWhCU0FISUFSQ2tlSGx6UWQrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVHSUFnZ0JFTEkwTS9CQW41OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NTQUVRdDJ3aFl3SWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENDQUtJQVJDdG92QndndCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUpJQXNnQkVLcHdNYUpEbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUW9nRENBRVF2S2NrWU1EZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ3lBTklBTkNJSWg4SVF3Z0JTQU9JQUUxQWh3aUJINThJZ05DLy8vLy93K0RJUVVnQmlBRUlBOStmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUdJQWNnQkNBUWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJ5QUlJQVFnRVg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NTQUVJQkorZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVKSUFvZ0JDQVRmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDaUFMSUFRZ0ZINThJQU5DSUloOElnTkMvLy8vL3crRElRc2dEQ0FFSUJWK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTUlBTkNJSWdoRFNBQ0lBVWdCVUwvLy8vL0RuNUMvLy8vL3crRElnUkNnWUNBZ0E5K2ZFSWdpQ0FHSUFSQ2srdUhud1IrZkh3aUEwTC8vLy8vRDRNK0FnQWdBaUFISUFSQ2tlSGx6UWQrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBnejRDQkNBQ0lBZ2dCRUxJME0vQkFuNThJQU5DSUloOElnTkMvLy8vL3crRFBnSUlJQUlnQ1NBRVF0MndoWXdJZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE0rQWd3Z0FpQUtJQVJDdG92QndndCtmQ0FEUWlDSWZDSURRdi8vLy84UGd6NENFQ0FDSUFzZ0JFS3B3TWFKRG41OElBTkNJSWg4SWdOQy8vLy8vdytEUGdJVUlBSWdEQ0FFUXZLY2tZTURmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TStBaGdnQWlBTklBTkNJSWg4UGdJY0lBSkI2QTBRQlFSQUlBSkI2QTBnQWhBSEdnc0w2QjBCRTM0Z0NDQUFOUUlBSWcwZ0RYNThJZ0pDLy8vLy93K0RJUWdnRENBQU5RSUVJZzhnRFg0aUEwTC8vLy8vRDROQ0FZWjhJQUpDSUloOElnSkMvLy8vL3crRElRd2dBMElnaUVJQmhpQUNRaUNJZkNBTElBQTFBZ2dpRUNBTmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFzZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FLSUFBMUFnd2lFU0FOZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUW9nQTBJZ2lFSUJoaUFDUWlDSWZDQUpJQUExQWhBaUVpQU5maUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRa2dBMElnaUVJQmhpQUNRaUNJZkNBSElBQTFBaFFpRXlBTmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFjZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FHSUFBMUFoZ2lGQ0FOZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUVlnQTBJZ2lFSUJoaUFDUWlDSWZDQUVJQTBnQURVQ0hDSU5maUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRUWdCU0FEUWlDSVFnR0dJQUpDSUloOGZDSUNRdi8vLy84UGd5RUZJQTRnQWtJZ2lId2hEaUFJSUFoQy8vLy8vdzUrUXYvLy8vOFBneUlEUW9HQWdJQVBmbnhDSUlnZ0RDQURRcFByaDU4RWZueDhJZ0pDLy8vLy93K0RJUWdnQ3lBRFFwSGg1YzBIZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oRENBS0lBTkN5TkRQd1FKK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFTElBa2dBMExkc0lXTUNINThJQUpDSUloOElnSkMvLy8vL3crRElRb2dCeUFEUXJhTHdjSUxmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhDU0FHSUFOQ3FjREdpUTUrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVISUFRZ0EwTHluSkdEQTM1OElBSkNJSWg4SWdKQy8vLy8vdytESVFZZ0JTQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFRUlBNGdBa0lnaUh3aEJTQU1JQThnRDM1OElnSkMvLy8vL3crRElRd2dDeUFQSUJCK0lnTkMvLy8vL3crRFFnR0dmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUxJQU5DSUloQ0FZWWdBa0lnaUh3Z0NpQVBJQkYrSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhDaUFEUWlDSVFnR0dJQUpDSUloOElBa2dEeUFTZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUWtnQTBJZ2lFSUJoaUFDUWlDSWZDQUhJQThnRTM0aUEwTC8vLy8vRDROQ0FZWjhmQ0lDUXYvLy8vOFBneUVISUFOQ0lJaENBWVlnQWtJZ2lId2dCaUFQSUJSK0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQmlBRFFpQ0lRZ0dHSUFKQ0lJaDhJQVFnRFNBUGZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFRZ0JTQURRaUNJUWdHR0lBSkNJSWg4ZkNJQ1F2Ly8vLzhQZ3lFRklBSkNJSWdoRGlBSUlBaEMvLy8vL3c1K1F2Ly8vLzhQZ3lJRFFvR0FnSUFQZm54Q0lJZ2dEQ0FEUXBQcmg1OEVmbng4SWdKQy8vLy8vdytESVFnZ0N5QURRcEhoNWMwSGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaERDQUtJQU5DeU5EUHdRSitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUxJQWtnQTBMZHNJV01DSDU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUW9nQnlBRFFyYUx3Y0lMZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ1NBR0lBTkNxY0RHaVE1K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSElBUWdBMEx5bkpHREEzNThJQUpDSUloOElnSkMvLy8vL3crRElRWWdCU0FDUWlDSWZDSUNRdi8vLy84UGd5RUVJQTRnQWtJZ2lId2hCU0FMSUJBZ0VINThJZ0pDLy8vLy93K0RJUXNnQ2lBUUlCRitJZ05DLy8vLy93K0RRZ0dHZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVLSUFOQ0lJaENBWVlnQWtJZ2lId2dDU0FRSUJKK0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQ1NBRFFpQ0lRZ0dHSUFKQ0lJaDhJQWNnRUNBVGZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFjZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FHSUJBZ0ZINGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFR0lBTkNJSWhDQVlZZ0FrSWdpSHdnQkNBTklCQitJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJDQUZJQU5DSUloQ0FZWWdBa0lnaUh4OElnSkMvLy8vL3crRElRVWdBa0lnaUNFT0lBZ2dDRUwvLy8vL0RuNUMvLy8vL3crRElnTkNnWUNBZ0E5K2ZFSWdpQ0FNSUFOQ2srdUhud1IrZkh3aUFrTC8vLy8vRDRNaENDQUxJQU5Da2VIbHpRZCtmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU1JQW9nQTBMSTBNL0JBbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQ1NBRFF0MndoWXdJZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ2lBSElBTkN0b3ZCd2d0K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSklBWWdBMEtwd01hSkRuNThJQUpDSUloOElnSkMvLy8vL3crRElRY2dCQ0FEUXZLY2tZTURmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCaUFGSUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVFnRGlBQ1FpQ0lmQ0VGSUFvZ0VTQVJmbndpQWtMLy8vLy9ENE1oQ2lBSklCRWdFbjRpQTBMLy8vLy9ENE5DQVlaOElBSkNJSWg4SWdKQy8vLy8vdytESVFrZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FISUJFZ0UzNGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFSElBTkNJSWhDQVlZZ0FrSWdpSHdnQmlBUklCUitJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJpQURRaUNJUWdHR0lBSkNJSWg4SUFRZ0RTQVJmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRUWdCU0FEUWlDSVFnR0dJQUpDSUloOGZDSUNRdi8vLy84UGd5RUZJQUpDSUlnaERpQUlJQWhDLy8vLy93NStRdi8vLy84UGd5SURRb0dBZ0lBUGZueENJSWdnRENBRFFwUHJoNThFZm54OElnSkMvLy8vL3crRElRZ2dDeUFEUXBIaDVjMEhmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhEQ0FLSUFOQ3lORFB3UUorZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVMSUFrZ0EwTGRzSVdNQ0g1OElBSkNJSWg4SWdKQy8vLy8vdytESVFvZ0J5QURRcmFMd2NJTGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENTQUdJQU5DcWNER2lRNStmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUhJQVFnQTBMeW5KR0RBMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVlnQlNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVFSUE0Z0FrSWdpSHdoQlNBSklCSWdFbjU4SWdKQy8vLy8vdytESVFrZ0J5QVNJQk4rSWdOQy8vLy8vdytEUWdHR2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSElBTkNJSWhDQVlZZ0FrSWdpSHdnQmlBU0lCUitJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJpQURRaUNJUWdHR0lBSkNJSWg4SUFRZ0RTQVNmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRUWdCU0FEUWlDSVFnR0dJQUpDSUloOGZDSUNRdi8vLy84UGd5RUZJQUpDSUlnaERpQUlJQWhDLy8vLy93NStRdi8vLy84UGd5SURRb0dBZ0lBUGZueENJSWdnRENBRFFwUHJoNThFZm54OElnSkMvLy8vL3crRElRZ2dDeUFEUXBIaDVjMEhmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhEQ0FLSUFOQ3lORFB3UUorZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVMSUFrZ0EwTGRzSVdNQ0g1OElBSkNJSWg4SWdKQy8vLy8vdytESVFvZ0J5QURRcmFMd2NJTGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENTQUdJQU5DcWNER2lRNStmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUhJQVFnQTBMeW5KR0RBMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVlnQlNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVFSUE0Z0FrSWdpSHdoQlNBSElCTWdFMzU4SWdKQy8vLy8vdytESVFjZ0JpQVRJQlIrSWdOQy8vLy8vdytEUWdHR2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFR0lBTkNJSWhDQVlZZ0FrSWdpSHdnQkNBTklCTitJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJDQUZJQU5DSUloQ0FZWWdBa0lnaUh4OElnSkMvLy8vL3crRElRVWdBa0lnaUNFT0lBZ2dDRUwvLy8vL0RuNUMvLy8vL3crRElnTkNnWUNBZ0E5K2ZFSWdpQ0FNSUFOQ2srdUhud1IrZkh3aUFrTC8vLy8vRDRNaENDQUxJQU5Da2VIbHpRZCtmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU1JQW9nQTBMSTBNL0JBbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQ1NBRFF0MndoWXdJZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ2lBSElBTkN0b3ZCd2d0K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSklBWWdBMEtwd01hSkRuNThJQUpDSUloOElnSkMvLy8vL3crRElRY2dCQ0FEUXZLY2tZTURmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCaUFGSUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVFnRGlBQ1FpQ0lmQ0VGSUFZZ0ZDQVVmbndpQWtMLy8vLy9ENE1oQmlBRUlBMGdGSDRpQTBMLy8vLy9ENE5DQVlaOElBSkNJSWg4SWdKQy8vLy8vdytESVFRZ0JTQURRaUNJUWdHR0lBSkNJSWg4ZkNJQ1F2Ly8vLzhQZ3lFRklBSkNJSWdoRGlBSUlBaEMvLy8vL3c1K1F2Ly8vLzhQZ3lJRFFvR0FnSUFQZm54Q0lJZ2dEQ0FEUXBQcmg1OEVmbng4SWdKQy8vLy8vdytESVFnZ0N5QURRcEhoNWMwSGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaERDQUtJQU5DeU5EUHdRSitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUxJQWtnQTBMZHNJV01DSDU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUW9nQnlBRFFyYUx3Y0lMZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ1NBR0lBTkNxY0RHaVE1K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSElBUWdBMEx5bkpHREEzNThJQUpDSUloOElnSkMvLy8vL3crRElRWWdCU0FDUWlDSWZDSUNRdi8vLy84UGd5RUVJQTRnQWtJZ2lId2hCU0FFSUEwZ0RYNThJZ0pDLy8vLy93K0RJUVFnQlNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVGSUFKQ0lJZ2hEaUFCSUFnZ0NFTC8vLy8vRG41Qy8vLy8vdytESWdOQ2dZQ0FnQTkrZkVJZ2lDQU1JQU5Dayt1SG53UitmSHdpQWtMLy8vLy9ENE0rQWdBZ0FTQUxJQU5Da2VIbHpRZCtmQ0FDUWlDSWZDSUNRdi8vLy84UGd6NENCQ0FCSUFvZ0EwTEkwTS9CQW41OElBSkNJSWg4SWdKQy8vLy8vdytEUGdJSUlBRWdDU0FEUXQyd2hZd0lmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TStBZ3dnQVNBSElBTkN0b3ZCd2d0K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3o0Q0VDQUJJQVlnQTBLcHdNYUpEbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RQZ0lVSUFFZ0JDQURRdktja1lNRGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNK0FoZ2dBU0FGSUFKQ0lJaDhJZ0pDLy8vLy93K0RQZ0ljSUE0Z0FrSWdpSHluQkVBZ0FVSG9EU0FCRUFjYUJTQUJRZWdORUFVRVFDQUJRZWdOSUFFUUJ4b0xDd3NLQUNBQUlBQWdBUkFvQ3dzQUlBQkJpQTRnQVJBb0N4VUFJQUJCaUJRUUFFR29GQkFCUVlnVUlBRVFKd3NSQUNBQVFjZ1VFQ3hCeUJSQmlBOFFCUXNqQUNBQUVBSUVRRUVBRHdzZ0FFSG9GQkFzUWVnVVFZZ1BFQVVFUUVGL0R3dEJBUXNYQUNBQUlBRVFMQ0FCUWVnTklBRVFEQ0FCSUFFUUt3c0pBRUdvRGlBQUVBQUx2QUVCQW44Z0FoQUJRU0FoQXdOQUlBRWdBMDhFUUNBRFFTQkdCRUJCaUJVUU1BVkJpQlZCaUE1QmlCVVFLQXNnQUVHSUZVR29GUkFvSUFKQnFCVWdBaEFrSUFCQklHb2hBQ0FEUVNCcUlRTU1BUXNMSUFGQkgzRWlCRVVFUUE4TFFhZ1ZFQUZCQUNFQkEwQWdBU0FFUmtVRVFDQUJJQUF0QUFBNkFLZ1ZJQUJCQVdvaEFDQUJRUUZxSVFFTUFRc0xJQU5CSUVZRVFFR0lGUkF3QlVHSUZVR0lEa0dJRlJBb0MwR29GVUdJRlVHb0ZSQW9JQUpCcUJVZ0FoQWtDeHdBSUFFZ0FrSElGUkF4UWNnVlFjZ1ZFQ3NnQUVISUZTQURFQ2dMNFFFQkFuOUJBRUVBS0FJQUlnVWdBa0VCYWtFRmRHbzJBZ0FnQlJBd0lBVkJJR29oQlFOQUlBSWdCa2NFUUNBQUVBSUVRQ0FGUVNCcklBVVFBQVVnQUNBRlFTQnJJQVVRS0FzZ0FDQUJhaUVBSUFWQklHb2hCU0FHUVFGcUlRWU1BUXNMSUFBZ0FXc2hBQ0FESUFKQkFXc2dCR3hxSVFJZ0JVRWdheUlGSUFVUUx3TkFJQVlFUUNBQUVBSUVRQ0FGSUFWQklHc1FBQ0FDRUFFRklBVkJJR3RCNkJVUUFDQUZJQUFnQlVFZ2F4QW9JQVZCNkJVZ0FoQW9DeUFBSUFGcklRQWdBaUFFYXlFQ0lBVkJJR3NoQlNBR1FRRnJJUVlNQVFzTFFRQWdCVFlDQUFzdEFRRi9BMEFnQVNBRFJrVUVRQ0FBSUFJUUt5QUFRU0JxSVFBZ0FrRWdhaUVDSUFOQkFXb2hBd3dCQ3dzTExRRUJmd05BSUFFZ0EwWkZCRUFnQUNBQ0VDd2dBRUVnYWlFQUlBSkJJR29oQWlBRFFRRnFJUU1NQVFzTEM1Y0NBQ0FDUlFSQUlBTVFNQThMSUFCQmlCWVFBQ0FERURBRFFDQUNRUUZySWdJZ0FXb3RBQUFoQUNBRElBTVFLU0FBUVlBQlR3UkFJQU5CaUJZZ0F4QW9JQUJCZ0FGcklRQUxJQU1nQXhBcElBQkJ3QUJQQkVBZ0EwR0lGaUFERUNnZ0FFRkFhaUVBQ3lBRElBTVFLU0FBUVNCUEJFQWdBMEdJRmlBREVDZ2dBRUVnYXlFQUN5QURJQU1RS1NBQVFSQlBCRUFnQTBHSUZpQURFQ2dnQUVFUWF5RUFDeUFESUFNUUtTQUFRUWhQQkVBZ0EwR0lGaUFERUNnZ0FFRUlheUVBQ3lBRElBTVFLU0FBUVFSUEJFQWdBMEdJRmlBREVDZ2dBRUVFYXlFQUN5QURJQU1RS1NBQVFRSlBCRUFnQTBHSUZpQURFQ2dnQUVFQ2F5RUFDeUFESUFNUUtTQUFCRUFnQTBHSUZpQURFQ2dMSUFJTkFBc0wxUUVCQVg4Z0FCQUNCRUFnQVJBQkR3dEJIQ0VDUWNnUFFhZ1dFQUFnQUVHb0QwRWdRY2dXRURZZ0FFSG9EMEVnUWVnV0VEWURRRUhJRmtHb0RoQUVSUVJBUWNnV1FZZ1hFQ2xCQVNFQUEwQkJpQmRCcUE0UUJFVUVRRUdJRjBHSUZ4QXBJQUJCQVdvaEFBd0JDd3RCcUJaQnFCY1FBQ0FDSUFCclFRRnJJUUlEUUNBQ0JFQkJxQmRCcUJjUUtTQUNRUUZySVFJTUFRc0xJQUFoQWtHb0YwR29GaEFwUWNnV1FhZ1dRY2dXRUNoQjZCWkJxQmRCNkJZUUtBd0JDd3RCNkJZUUxRUkFRZWdXSUFFUUpnVkI2QllnQVJBQUN3c2dBQ0FBRUFJRVFFRUJEd3NnQUVIb0RrRWdRY2dYRURaQnlCZEJxQTRRQkFzVkFDQUFJQUZCNkJjUUtFSG9GMEdJRGlBQ0VDZ0xDZ0FnQUNBQUlBRVFPUXNMQUNBQVFlZ05JQUVRREFzSkFDQUFRWWdQRUFVTERnQWdBQkFDSUFCQklHb1FBbkVMQ1FBZ0FFRkFheEFDQ3cwQUlBQVFBU0FBUVNCcUVBRUxGQUFnQUJBQklBQkJJR29RR2lBQVFVQnJFQUVMVWdBZ0FTQUFLUU1BTndNQUlBRWdBQ2tEQ0RjRENDQUJJQUFwQXhBM0F4QWdBU0FBS1FNWU53TVlJQUVnQUNrRElEY0RJQ0FCSUFBcEF5ZzNBeWdnQVNBQUtRTXdOd013SUFFZ0FDa0RPRGNET0F0NkFDQUJJQUFwQXdBM0F3QWdBU0FBS1FNSU53TUlJQUVnQUNrREVEY0RFQ0FCSUFBcEF4ZzNBeGdnQVNBQUtRTWdOd01nSUFFZ0FDa0RLRGNES0NBQklBQXBBekEzQXpBZ0FTQUFLUU00TndNNElBRWdBQ2tEUURjRFFDQUJJQUFwQTBnM0EwZ2dBU0FBS1FOUU53TlFJQUVnQUNrRFdEY0RXQXNuQUNBQUVEMEVRQ0FCRUVBRklBRkJRR3NRR2lBQVFTQnFJQUZCSUdvUUFDQUFJQUVRQUFzTEZRQWdBQ0FCRUFRZ0FFRWdhaUFCUVNCcUVBUnhDM0VCQVg4Z0FCQStCRUFnQVJBOUR3c2dBUkE5QkVCQkFBOExJQUJCUUdzaUFoQU5CRUFnQUNBQkVFUVBDeUFDUWFnWUVCTWdBVUdvR0VISUdCQVNJQUpCcUJoQjZCZ1FFaUFCUVNCcVFlZ1lRWWdaRUJJZ0FFSElHQkFFQkVBZ0FFRWdha0dJR1JBRUJFQkJBUThMQzBFQUM2c0JBUUovSUFBUVBnUkFJQUVRUGc4TElBRVFQZ1JBUVFBUEN5QUFRVUJySWdJUURRUkFJQUVnQUJCRkR3c2dBVUZBYXlJREVBMEVRQ0FBSUFFUVJROExJQUpCcUJrUUV5QURRY2daRUJNZ0FFSElHVUhvR1JBU0lBRkJxQmxCaUJvUUVpQUNRYWdaUWFnYUVCSWdBMEhJR1VISUdoQVNJQUJCSUdwQnlCcEI2Qm9RRWlBQlFTQnFRYWdhUVlnYkVCSkI2QmxCaUJvUUJBUkFRZWdhUVlnYkVBUUVRRUVCRHdzTFFRQUw1d0VBSUFBUVBRUkFJQUFnQVJCRER3c2dBRUdvR3hBVElBQkJJR3BCeUJzUUUwSElHMEhvR3hBVElBQkJ5QnRCaUJ3UURrR0lIRUdJSEJBVFFZZ2NRYWdiUVlnY0VBOUJpQnhCNkJ0QmlCd1FEMEdJSEVHSUhFR0lIQkFPUWFnYlFhZ2JRYWdjRUE1QnFCeEJxQnRCcUJ3UURpQUFRU0JxSUFCQklHb2dBVUZBYXhBT1FhZ2NJQUVRRXlBQlFZZ2NJQUVRRHlBQlFZZ2NJQUVRRDBIb0cwSG9HMEhJSEJBT1FjZ2NRY2djUWNnY0VBNUJ5QnhCeUJ4QnlCd1FEa0dJSENBQklBRkJJR29RRHlBQlFTQnFRYWdjSUFGQklHb1FFaUFCUVNCcVFjZ2NJQUZCSUdvUUR3dUZBZ0FnQUJBK0JFQWdBQ0FCRUVJUEN5QUFRVUJyRUEwRVFDQUFJQUVRUnc4TElBQkI2QndRRXlBQVFTQnFRWWdkRUJOQmlCMUJxQjBRRXlBQVFZZ2RRY2dkRUE1QnlCMUJ5QjBRRTBISUhVSG9IRUhJSFJBUFFjZ2RRYWdkUWNnZEVBOUJ5QjFCeUIxQnlCMFFEa0hvSEVIb0hFSG9IUkFPUWVnZFFlZ2NRZWdkRUE1QjZCMUJpQjRRRXlBQVFTQnFJQUJCUUd0QnFCNFFFa0hJSFVISUhTQUJFQTVCaUI0Z0FTQUJFQTlCcUIxQnFCMUJ5QjRRRGtISUhrSElIa0hJSGhBT1FjZ2VRY2dlUWNnZUVBNUJ5QjBnQVNBQlFTQnFFQThnQVVFZ2FrSG9IU0FCUVNCcUVCSWdBVUVnYWtISUhpQUJRU0JxRUE5QnFCNUJxQjRnQVVGQWF4QU9DNVlDQUNBQUVEMEVRQ0FCSUFJUVFTQUNRVUJyRUJvUEN5QUJFRDBFUUNBQUlBSVFRU0FDUVVCckVCb1BDeUFBSUFFUUJBUkFJQUJCSUdvZ0FVRWdhaEFFQkVBZ0FTQUNFRWNQQ3dzZ0FTQUFRZWdlRUE4Z0FVRWdhaUFBUVNCcVFhZ2ZFQTlCNkI1QmlCOFFFMEdJSDBHSUgwSElIeEFPUWNnZlFjZ2ZRY2dmRUE1QjZCNUJ5QjlCNkI4UUVrR29IMEdvSDBHSUlCQU9JQUJCeUI5QnlDQVFFa0dJSUVHb0lCQVRRY2dnUWNnZ1FlZ2dFQTVCcUNCQjZCOGdBaEFQSUFKQjZDQWdBaEFQSUFCQklHcEI2QjlCaUNFUUVrR0lJVUdJSVVHSUlSQU9RY2dnSUFJZ0FrRWdhaEFQSUFKQklHcEJpQ0FnQWtFZ2FoQVNJQUpCSUdwQmlDRWdBa0VnYWhBUFFlZ2VRZWdlSUFKQlFHc1FEZ3YxQWdFQmZ5QUFFRDRFUUNBQklBSVFRU0FDUVVCckVCb1BDeUFCRUQwRVFDQUFJQUlRUWc4TElBQkJRR3NpQXhBTkJFQWdBQ0FCSUFJUVNROExJQU5CcUNFUUV5QUJRYWdoUWNnaEVCSWdBMEdvSVVIb0lSQVNJQUZCSUdwQjZDRkJpQ0lRRWlBQVFjZ2hFQVFFUUNBQVFTQnFRWWdpRUFRRVFDQUJJQUlRUnc4TEMwSElJU0FBUWFnaUVBOUJpQ0lnQUVFZ2FrSG9JaEFQUWFnaVFjZ2lFQk5CeUNKQnlDSkJpQ01RRGtHSUkwR0lJMEdJSXhBT1FhZ2lRWWdqUWFnakVCSkI2Q0pCNkNKQnlDTVFEaUFBUVlnalFZZ2tFQkpCeUNOQjZDTVFFMEdJSkVHSUpFR29KQkFPUWVnalFhZ2pJQUlRRHlBQ1FhZ2tJQUlRRHlBQVFTQnFRYWdqUWNna0VCSkJ5Q1JCeUNSQnlDUVFEa0dJSkNBQ0lBSkJJR29RRHlBQ1FTQnFRY2dqSUFKQklHb1FFaUFDUVNCcVFjZ2tJQUpCSUdvUUR5QURRYWdpSUFKQlFHc1FEaUFDUVVCcklBSkJRR3NRRXlBQ1FVQnJRYWdoSUFKQlFHc1FEeUFDUVVCclFjZ2lJQUpCUUdzUUR3dXJBd0VDZnlBQUVENEVRQ0FCSUFJUVFnOExJQUVRUGdSQUlBQWdBaEJDRHdzZ0FFRkFheUlERUEwRVFDQUJJQUFnQWhCS0R3c2dBVUZBYXlJRUVBMEVRQ0FBSUFFZ0FoQktEd3NnQTBIb0pCQVRJQVJCaUNVUUV5QUFRWWdsUWFnbEVCSWdBVUhvSkVISUpSQVNJQU5CNkNSQjZDVVFFaUFFUVlnbFFZZ21FQklnQUVFZ2FrR0lKa0dvSmhBU0lBRkJJR3BCNkNWQnlDWVFFa0dvSlVISUpSQUVCRUJCcUNaQnlDWVFCQVJBSUFBZ0FoQklEd3NMUWNnbFFhZ2xRZWdtRUE5QnlDWkJxQ1pCaUNjUUQwSG9Ka0hvSmtHb0p4QU9RYWduUWFnbkVCTkI2Q1pCcUNkQnlDY1FFa0dJSjBHSUowSG9KeEFPUWFnbFFhZ25RYWdvRUJKQjZDZEJpQ2dRRTBHb0tFR29LRUhJS0JBT1FZZ29RY2duSUFJUUR5QUNRY2dvSUFJUUQwR29Ka0hJSjBIb0tCQVNRZWdvUWVnb1FlZ29FQTVCcUNnZ0FpQUNRU0JxRUE4Z0FrRWdha0hvSnlBQ1FTQnFFQklnQWtFZ2FrSG9LQ0FDUVNCcUVBOGdBeUFFSUFKQlFHc1FEaUFDUVVCcklBSkJRR3NRRXlBQ1FVQnJRZWdrSUFKQlFHc1FEeUFDUVVCclFZZ2xJQUpCUUdzUUR5QUNRVUJyUWVnbUlBSkJRR3NRRWdzVUFDQUFJQUVRQUNBQVFTQnFJQUZCSUdvUUVBc2dBQ0FBSUFFUUFDQUFRU0JxSUFGQklHb1FFQ0FBUVVCcklBRkJRR3NRQUFzU0FDQUJRWWdwRUV3Z0FFR0lLU0FDRUVrTEVnQWdBVUhvS1JCTUlBQkI2Q2tnQWhCS0N4SUFJQUZCeUNvUVRTQUFRY2dxSUFJUVN3c1VBQ0FBSUFFUUZpQUFRU0JxSUFGQklHb1FGZ3NnQUNBQUlBRVFGaUFBUVNCcUlBRkJJR29RRmlBQVFVQnJJQUZCUUdzUUZnc1VBQ0FBSUFFUUZTQUFRU0JxSUFGQklHb1FGUXNnQUNBQUlBRVFGU0FBUVNCcUlBRkJJR29RRlNBQVFVQnJJQUZCUUdzUUZRdEtBQ0FBRUQ0RVFDQUJFQUVnQVVFZ2FoQUJCU0FBUVVCclFhZ3JFQmxCcUN0QnlDc1FFMEdvSzBISUswSG9LeEFTSUFCQnlDc2dBUkFTSUFCQklHcEI2Q3NnQVVFZ2FoQVNDd3N3QUNBQVFTQnFRWWdzRUJNZ0FFR29MQkFUSUFCQnFDeEJxQ3dRRWtHb0xFR0lHRUdvTEJBT1FZZ3NRYWdzRUFRTERnQWdBRUhJTEJCVlFjZ3NFRllMbEFFQkEzOUJBRUVBS0FJQUlnUWdBVUVGZEdvMkFnQWdBRUZBYTBIZ0FDQUJJQVJCSUJBZElBUWhBd05BSUFFZ0JVY0VRQ0FERUFJRVFDQUNFQUVnQWtFZ2FoQUJCU0FESUFCQklHcEJpQzBRRWlBRElBTVFFeUFESUFBZ0FoQVNJQU5CaUMwZ0FrRWdhaEFTQ3lBQVFlQUFhaUVBSUFKQlFHc2hBaUFEUVNCcUlRTWdCVUVCYWlFRkRBRUxDMEVBSUFRMkFnQUxTZ0FnQUJBK0JFQWdBUkJBQlNBQVFVQnJRYWd0RUJsQnFDMUJ5QzBRRTBHb0xVSElMVUhvTFJBU0lBQkJ5QzBnQVJBU0lBQkJJR3BCNkMwZ0FVRWdhaEFTSUFGQlFHc1FHZ3NMTWdBZ0FTQUNha0VCYXlFQkEwQWdBU0FDU0VVRVFDQUJJQUF0QUFBNkFBQWdBVUVCYXlFQklBQkJBV29oQUF3QkN3c0xLZ0FnQUJBOUJFQWdBUkEvRHdzZ0FFR0lMaEJSUVlndVFTQWdBUkJhUWFndVFTQWdBVUVnYWhCYUMwRUFJQUFRUFFSQUlBRVFBU0FCUWNBQU9nQUFEd3NnQUVISUxoQVdRY2d1UVNBZ0FSQmFJQUJCSUdvUUdFRi9SZ1JBSUFFZ0FTMEFBRUdBQVhJNkFBQUxDeThBSUFBdEFBQkJ3QUJ4QkVBZ0FSQS9Ed3NnQUVFZ1FlZ3VFRm9nQUVFZ2FrRWdRWWd2RUZwQjZDNGdBUkJUQzY0QkFRSi9JQUF0QUFBaUFrSEFBSEVFUUNBQkVEOFBDeUFDUVlBQmNTRURJQUJCeUM4UUFFSElMeUFDUVQ5eE9nQUFRY2d2UVNCQnFDOFFXa0dvTHlBQkVCVWdBVUhJTHhBVElBRkJ5QzlCeUM4UUVrSElMMEdJR0VISUx4QU9RY2d2UWNndkVDRkJ5QzlCcUM4UUVFSElMeEFZUVg5R0JFQWdBd1JBUWNndklBRkJJR29RQUFWQnlDOGdBVUVnYWhBUUN3VWdBd1JBUWNndklBRkJJR29RRUFWQnlDOGdBVUVnYWhBQUN3c0xMUUVCZndOQUlBRWdBMFpGQkVBZ0FDQUNFRnNnQUVGQWF5RUFJQUpCUUdzaEFpQURRUUZxSVFNTUFRc0xDeTBCQVg4RFFDQUJJQU5HUlFSQUlBQWdBaEJjSUFCQlFHc2hBQ0FDUVNCcUlRSWdBMEVCYWlFRERBRUxDd3N0QVFGL0EwQWdBU0FEUmtVRVFDQUFJQUlRWFNBQVFVQnJJUUFnQWtGQWF5RUNJQU5CQVdvaEF3d0JDd3NMUndFQmZ5QUFJQUZCQVd0QkJYUnFJUUFnQWlBQlFRRnJRUVowYWlFQ0EwQWdBU0FEUmtVRVFDQUFJQUlRWGlBQVFTQnJJUUFnQWtGQWFpRUNJQU5CQVdvaEF3d0JDd3NMU1FFQmZ5QUFJQUZCQVd0QkJuUnFJUUFnQWlBQlFRRnJRZUFBYkdvaEFnTkFJQUVnQTBaRkJFQWdBQ0FDRUVNZ0FFRkFhaUVBSUFKQjRBQnJJUUlnQTBFQmFpRUREQUVMQ3dzMUFDQUJRUU4wSUFKcklnRWdBMGdFZjBFQklBRjBRUUZyQlVFQklBTjBRUUZyQ3lBQUlBSkJBM1pxS0FBQUlBSkJCM0YyY1F1SEFRRUZmMEVCSUFOQkFXdDBJUWdnQVVFRGRDRUpJQVJCQVdvaENnTkFJQUlnQjBaRkJFQkJBQ0VHUVFBaEJBTkFJQVFnQ2taRkJFQWdCU0FDSUFSc0lBZHFhaUFHT2dBQUlBZ2dCaUFESUFSc0lnWWdDVWdFZnlBQUlBRWdCaUFERUdRRlFRQUxha3doQmlBRVFRRnFJUVFNQVFzTElBQWdBV29oQUNBSFFRRnFJUWNNQVFzTEM4OENBUVovSUFSRkJFQWdCeEJBRHd0QkFTQUdkQ0VNSUFKQkEzUWhEU0FGSUFac0lRdEJBRUVBS0FJQUlnbEJBU0FHUVFGcmRDSUtRZUFBYkdvMkFnQURRQ0FJSUFwR1JRUkFJQWtnQ0VIZ0FHeHFFRUFnQ0VFQmFpRUlEQUVMQ3lBRElBUWdCV3hxSVFWQkFDRUlBMEFnQkNBSVJ3UkFJQXNnRFVnRWZ5QUJJQUlnQ3lBR0VHUUZRUUFMSVFNZ0F5QUZMUUFBYWlJRElBcE9CRUFnQXlBTWF5RURDeUFEUVFCS0JFQWdDU0FEUVFGclFlQUFiR29pQXlBQUlBTVFTd1VnQTBFQVNBUkFJQWxCZnlBRGEwSGdBR3hxSWdNZ0FDQURFRkFMQ3lBQklBSnFJUUVnQlVFQmFpRUZJQUJCNEFCcUlRQWdDRUVCYWlFSURBRUxDeUFKSUFwQkFXdEI0QUJzYWlJQUlBY1FRaUFBUWVndkVFSWdBRUhnQUdzaEFBTkFJQUFnQ1VsRkJFQkI2QzhnQUVIb0x4QkxJQWRCNkM4Z0J4QkxJQUJCNEFCcklRQU1BUXNMUVFBZ0NUWUNBQXUzQVFFRWZ5QUVFRUFnQTBVRVFBOExJQU5uTFFDb01TSUZRUUpKQkVCQkFpRUZDMEVBUVFBb0FnQWlCeUFDUVFOMFFRRnJJQVZ1UVFGcUlnWkJBV29nQTJ4cVFRTnFRWHh4TmdJQUlBRWdBaUFESUFVZ0JpQUhFR1VEUUNBR1FRQk9CRUFnQkJBK1JRUkFRUUFoQ0FOQUlBVWdDRVpGQkVBZ0JDQUVFRWdnQ0VFQmFpRUlEQUVMQ3dzZ0FDQUJJQUlnQnlBRElBWWdCVUhJTUJCbUlBUkJ5REFnQkJCTElBWkJBV3NoQmd3QkN3dEJBQ0FITmdJQUM4NENBUVovSUFSRkJFQWdCeEJBRHd0QkFTQUdkQ0VNSUFKQkEzUWhEU0FGSUFac0lRdEJBRUVBS0FJQUlnbEJBU0FHUVFGcmRDSUtRZUFBYkdvMkFnQURRQ0FJSUFwR1JRUkFJQWtnQ0VIZ0FHeHFFRUFnQ0VFQmFpRUlEQUVMQ3lBRElBUWdCV3hxSVFWQkFDRUlBMEFnQkNBSVJ3UkFJQXNnRFVnRWZ5QUJJQUlnQ3lBR0VHUUZRUUFMSVFNZ0F5QUZMUUFBYWlJRElBcE9CRUFnQXlBTWF5RURDeUFEUVFCS0JFQWdDU0FEUVFGclFlQUFiR29pQXlBQUlBTVFTZ1VnQTBFQVNBUkFJQWxCZnlBRGEwSGdBR3hxSWdNZ0FDQURFRThMQ3lBQklBSnFJUUVnQlVFQmFpRUZJQUJCUUdzaEFDQUlRUUZxSVFnTUFRc0xJQWtnQ2tFQmEwSGdBR3hxSWdBZ0J4QkNJQUJCeURFUVFpQUFRZUFBYXlFQUEwQWdBQ0FKU1VVRVFFSElNU0FBUWNneEVFc2dCMEhJTVNBSEVFc2dBRUhnQUdzaEFBd0JDd3RCQUNBSk5nSUFDN2NCQVFSL0lBUVFRQ0FEUlFSQUR3c2dBMmN0QUlneklnVkJBa2tFUUVFQ0lRVUxRUUJCQUNnQ0FDSUhJQUpCQTNSQkFXc2dCVzVCQVdvaUJrRUJhaUFEYkdwQkEycEJmSEUyQWdBZ0FTQUNJQU1nQlNBR0lBY1FaUU5BSUFaQkFFNEVRQ0FFRUQ1RkJFQkJBQ0VJQTBBZ0JTQUlSa1VFUUNBRUlBUVFTQ0FJUVFGcUlRZ01BUXNMQ3lBQUlBRWdBaUFISUFNZ0JpQUZRYWd5RUdnZ0JFR29NaUFFRUVzZ0JrRUJheUVHREFFTEMwRUFJQWMyQWdBTDdBTUJCbjhnQWtVRVFDQURFRUFQQzBFQUtBSUFJZ2doQkVFQUlBSkJBM1FpQ1NBSVFTQnFha0Y0Y1RZQ0FFRUJJUVlnQVNnQ0FFRUJjU0VGUVFBaEFnTkFJQVlnQ1VaRkJFQWdBU0FHUVFOMlFYeHhhaWdDQUNBR2RrRUJjU0VISUFVRWZ5QUhCSDhnQWdSL1FRQWhCU0FFUVFFNkFBQWdCRUVCYWlFRVFRRUZRUUFoQlNBRVFmOEJPZ0FBSUFSQkFXb2hCRUVCQ3dVZ0FnUi9RUUFoQlNBRVFmOEJPZ0FBSUFSQkFXb2hCRUVCQlVFQUlRVWdCRUVCT2dBQUlBUkJBV29oQkVFQUN3c0ZJQWNFZnlBQ0JIOUJBQ0VGSUFSQkFEb0FBQ0FFUVFGcUlRUkJBUVZCQVNFRklBUkJBRG9BQUNBRVFRRnFJUVJCQUFzRklBSUVmMEVCSVFVZ0JFRUFPZ0FBSUFSQkFXb2hCRUVBQlVFQUlRVWdCRUVBT2dBQUlBUkJBV29oQkVFQUN3c0xJUUlnQmtFQmFpRUdEQUVMQ3lBRkJIOGdBZ1IvSUFSQi93RTZBQUFnQkVFQmFpSUVRUUE2QUFBZ0JFRUJhaUlFUVFFNkFBQWdCRUVCYWdVZ0JFRUJPZ0FBSUFSQkFXb0xCU0FDQkg4Z0JFRUFPZ0FBSUFSQkFXb2lCRUVCT2dBQUlBUkJBV29GSUFRTEMwRUJheUVFSUFCQnFETVFRaUFERUVBRFFDQURJQU1RU0NBRUxRQUFJZ2NFUUNBSFFRRkdCRUFnQTBHb015QURFRXNGSUFOQnFETWdBeEJRQ3dzZ0JDQUlSa1VFUUNBRVFRRnJJUVFNQVFzTFFRQWdDRFlDQUF2c0F3RUdmeUFDUlFSQUlBTVFRQThMUVFBb0FnQWlDQ0VFUVFBZ0FrRURkQ0lKSUFoQklHcHFRWGh4TmdJQVFRRWhCaUFCS0FJQVFRRnhJUVZCQUNFQ0EwQWdCaUFKUmtVRVFDQUJJQVpCQTNaQmZIRnFLQUlBSUFaMlFRRnhJUWNnQlFSL0lBY0VmeUFDQkg5QkFDRUZJQVJCQVRvQUFDQUVRUUZxSVFSQkFRVkJBQ0VGSUFSQi93RTZBQUFnQkVFQmFpRUVRUUVMQlNBQ0JIOUJBQ0VGSUFSQi93RTZBQUFnQkVFQmFpRUVRUUVGUVFBaEJTQUVRUUU2QUFBZ0JFRUJhaUVFUVFBTEN3VWdCd1IvSUFJRWYwRUFJUVVnQkVFQU9nQUFJQVJCQVdvaEJFRUJCVUVCSVFVZ0JFRUFPZ0FBSUFSQkFXb2hCRUVBQ3dVZ0FnUi9RUUVoQlNBRVFRQTZBQUFnQkVFQmFpRUVRUUFGUVFBaEJTQUVRUUE2QUFBZ0JFRUJhaUVFUVFBTEN3c2hBaUFHUVFGcUlRWU1BUXNMSUFVRWZ5QUNCSDhnQkVIL0FUb0FBQ0FFUVFGcUlnUkJBRG9BQUNBRVFRRnFJZ1JCQVRvQUFDQUVRUUZxQlNBRVFRRTZBQUFnQkVFQmFnc0ZJQUlFZnlBRVFRQTZBQUFnQkVFQmFpSUVRUUU2QUFBZ0JFRUJhZ1VnQkFzTFFRRnJJUVFnQUVHSU5CQkJJQU1RUUFOQUlBTWdBeEJJSUFRdEFBQWlCd1JBSUFkQkFVWUVRQ0FEUVlnMElBTVFTZ1VnQTBHSU5DQURFRThMQ3lBRUlBaEdSUVJBSUFSQkFXc2hCQXdCQ3d0QkFDQUlOZ0lBQzRrQkFRUi9RUUVnQVhRaEJBTkFJQUlnQkVjRVFDQUNRZjhCY1MwQXlGRkJHSFFnQWtFSWRrSC9BWEV0QU1oUlFSQjBhaUFDUVJoMkxRRElVU0FDUVJCMlFmOEJjUzBBeUZGQkNIUnFhaUFCZHlJRElBSkxCRUFnQUNBQ1FRVjBhaUlGUWNqVEFCQUFJQUFnQTBFRmRHb2lBeUFGRUFCQnlOTUFJQU1RQUFzZ0FrRUJhaUVDREFFTEN3dUFBd0VKZnlBQUlBRVFiRUVCSUFGMElRcEJBU0VFQTBBZ0FTQUVUd1JBUVFFZ0JIUWhCeUFFUVFWMFFjZzBhaUVMUVFBaEJRTkFJQVVnQ2trRVFFR0kxQUFRTUNBSFFRRjJJUWhCQUNFR0EwQWdCaUFJU1FSQUlBQWdCU0FHYWtFRmRHb2lDU0FJUVFWMGFpSU1RWWpVQUVHbzFBQVFLQ0FKUWNqVUFCQUFRY2pVQUVHbzFBQWdDUkFrUWNqVUFFR28xQUFnREJBbFFZalVBQ0FMUVlqVUFCQW9JQVpCQVdvaEJnd0JDd3NnQlNBSGFpRUZEQUVMQ3lBRVFRRnFJUVFNQVFzTElBTVFJeUFDUlhGRkJFQkJBU0VGUVFFZ0FYUWlCMEVCZGlFR0EwQWdCU0FHU1FSQUlBQWdCVUVGZEdvaEJDQUFJQWNnQld0QkJYUnFJUUVnQWdSQUlBTVFJd1JBSUFSQjZOTUFFQUFnQVNBRUVBQkI2Tk1BSUFFUUFBVWdCRUhvMHdBUUFDQUJJQU1nQkJBb1FlalRBQ0FESUFFUUtBc0ZJQU1RSTBVRVFDQUVJQU1nQkJBb0lBRWdBeUFCRUNnTEN5QUZRUUZxSVFVTUFRc0xJQU1RSTBVRVFDQUFJQU1nQUJBb0lBQWdCa0VGZEdvaUFTQURJQUVRS0FzTEN6b0JBbjhnQUVFQmRpRUNBMEFnQWdSQUlBSkJBWFloQWlBQlFRRnFJUUVNQVFzTElBQkJBU0FCZEVjRVFBQUxJQUZCSEVzRVFBQUxJQUVMR2dBZ0FSQnVJUUZCNk5RQUVEQWdBQ0FCUVFCQjZOUUFFRzBMRndBZ0FDQUJFRzRpQUVFQklBQkJCWFJCNkR0cUVHMExiUUVDZnlBRFFZalZBQkFBUVFBaEF3TkFJQUlnQTBaRkJFQWdBU0FEUVFWMGFpSUZRWWpWQUVHbzFRQVFLQ0FBSUFOQkJYUnFJZ1pCeU5VQUVBQkJ5TlVBUWFqVkFDQUdFQ1JCeU5VQVFhalZBQ0FGRUNWQmlOVUFJQVJCaU5VQUVDZ2dBMEVCYWlFRERBRUxDd3Q1QVFKL0lBVkJCWFJCaU1NQWFpRUhJQU5CNk5VQUVBQkJBQ0VGQTBBZ0FpQUZSa1VFUUNBQUlBVkJCWFJxSWdZZ0FTQUZRUVYwYWlJRFFZaldBQkFrSUFNZ0J5QURFQ2dnQmlBRElBTVFKQ0FEUWVqVkFDQURFQ2hCaU5ZQUlBWVFBRUhvMVFBZ0JFSG8xUUFRS0NBRlFRRnFJUVVNQVFzTEM1RUJBUU4vSUFWQkJYUkJpTU1BYWlFSUlBVkJCWFJCcU1vQWFpRUhJQU5CcU5ZQUVBQkJBQ0VGQTBBZ0FpQUZSa1VFUUNBQklBVkJCWFJxSWdaQnFOWUFRY2pXQUJBb0lBQWdCVUVGZEdvaUEwSEkxZ0FnQmhBbElBWWdCeUFHRUNnZ0F5QUlJQU1RS0VISTFnQWdBeUFERUNVZ0F5QUhJQU1RS0VHbzFnQWdCRUdvMWdBUUtDQUZRUUZxSVFVTUFRc0xDNm9CQVFkL0lBRWdBblloQkVFQklBSjBJZ1ZCQVhZaUJrRUZkQ0VISUFKQkJYUkJ5RFJxSVFoQkFDRUJBMEFnQVNBRVJrVUVRRUhvMWdBUU1FRUFJUUlEUUNBQ0lBWkdSUVJBSUFBZ0FTQUZiQ0FDYWtFRmRHb2lBeUFIYWlJSlFlaldBRUdJMXdBUUtDQURRYWpYQUJBQVFhalhBRUdJMXdBZ0F4QWtRYWpYQUVHSTF3QWdDUkFsUWVqV0FDQUlRZWpXQUJBb0lBSkJBV29oQWd3QkN3c2dBVUVCYWlFQkRBRUxDd3RzQVFSL0lBRkJBWFloQkNBQlFRRnhCRUFnQUNBRVFRVjBhaUFDSUFBZ0JFRUZkR29RS0FzRFFDQURJQVJQUlFSQUlBQWdBVUVCYXlBRGEwRUZkR29pQlNBQ1FjalhBQkFvSUFBZ0EwRUZkR29pQmlBQ0lBVVFLRUhJMXdBZ0JoQUFJQU5CQVdvaEF3d0JDd3NMaXdFQkEzOGdCVUVGZEVHSXd3QnFJUWNnQlVFRmRFR295Z0JxSVFnZ0EwSG8xd0FRQUVFQUlRTURRQ0FDSUFOR1JRUkFJQUFnQTBFRmRHb2lCaUFIUVlqWUFCQW9JQUVnQTBFRmRHb2lCVUdJMkFCQmlOZ0FFQ1VnQmlBRklBVVFKVUdJMkFBZ0NDQUdFQ2dnQlVIbzF3QWdCUkFvUWVqWEFDQUVRZWpYQUJBb0lBTkJBV29oQXd3QkN3c0xKUUFnQUNBQlFRVjBhaUVCQTBBZ0FDQUJSa1VFUUNBQUVBRWdBRUVnYWlFQURBRUxDd3QwQVFSL0EwQWdBaUFFUmtVRVFDQUFLQUlBSVFjZ0FFRUVhaUVBUVFBaEJRTkFJQVVnQjBaRkJFQWdBeUFBS0FJQVFRVjBhaUVHSUFFZ0FFRUVhaUlBUWFqWUFCQW9RYWpZQUNBR0lBWVFKQ0FBUVNCcUlRQWdCVUVCYWlFRkRBRUxDeUFCUVNCcUlRRWdCRUVCYWlFRURBRUxDd3VqQWdFRWZ5QUVJUXNnQXlJS0lBZEJCWFJxSVF3RFFDQUtJQXhHUlFSQUlBb1FBU0FMRUFFZ0NrRWdhaUVLSUF0QklHb2hDd3dCQ3dzZ0FDQUJRU3hzYWlFTUEwQWdBQ0FNUndSQUlBQW9BZ2dpQVNBSUlBbHFUeUFCSUFoSmNnUkFJQUJCTEdvaEFBd0NDeUFBS0FJQUlnb0VRQ0FLUVFGR0JFQWdCQ0VOQlNBQVFTeHFJUUFMQlNBRElRMExJQUFvQWdRaUNpQUdJQWRxVHlBR0lBcExjZ1JBSUFCQkxHb2hBQXdDQlNBQ0lBRWdDR3RCQlhScUlBQkJER3BCeU5nQUVDZ2dEU0FLSUFaclFRVjBhaUlOUWNqWUFDQU5FQ1FnQUVFc2FpRUFEQUlMQUFzTElBUWhDeUFGSVFBZ0F5SUtJQWRCQlhScUlRd0RRQ0FLSUF4R1JRUkFJQW9nQ3lBQUVDZ2dDa0VnYWlFS0lBdEJJR29oQ3lBQVFTQnFJUUFNQVFzTEMwb0FJQUFnQTBFRmRHb2hBd05BSUFBZ0EwWkZCRUFnQUNBQlFlallBQkFvUWVqWUFDQUNJQVFRSlNBQVFTQnFJUUFnQVVFZ2FpRUJJQUpCSUdvaEFpQUVRU0JxSVFRTUFRc0xDemNBSUFBZ0FrRUZkR29oQWdOQUlBQWdBa1pGQkVBZ0FDQUJJQU1RSkNBQVFTQnFJUUFnQVVFZ2FpRUJJQU5CSUdvaEF3d0JDd3NMRGdBZ0FCQU5JQUJCSUdvUUFuRUxEUUFnQUJBYUlBQkJJR29RQVFzVUFDQUFJQUVRQUNBQVFTQnFJQUZCSUdvUUFBdDFBQ0FBSUFGQmlOa0FFQklnQUVFZ2FpQUJRU0JxUWFqWkFCQVNJQUFnQUVFZ2FrSEkyUUFRRGlBQklBRkJJR3BCNk5rQUVBNUJ5TmtBUWVqWkFFSEkyUUFRRWtHbzJRQWdBaEFRUVlqWkFDQUNJQUlRRGtHSTJRQkJxTmtBSUFKQklHb1FEa0hJMlFBZ0FrRWdhaUFDUVNCcUVBOExHQUFnQUNBQklBSVFFaUFBUVNCcUlBRWdBa0VnYWhBU0MzQUFJQUFnQUVFZ2FrR0kyZ0FRRWlBQUlBQkJJR3BCcU5vQUVBNGdBRUVnYWtISTJnQVFFQ0FBUWNqYUFFSEkyZ0FRRGtHSTJnQkI2Tm9BRUJCQjZOb0FRWWphQUVIbzJnQVFEa0dvMmdCQnlOb0FJQUVRRWlBQlFlamFBQ0FCRUE5QmlOb0FRWWphQUNBQlFTQnFFQTRMR3dBZ0FDQUJJQUlRRGlBQVFTQnFJQUZCSUdvZ0FrRWdhaEFPQ3hzQUlBQWdBU0FDRUE4Z0FFRWdhaUFCUVNCcUlBSkJJR29RRHdzVUFDQUFJQUVRRUNBQVFTQnFJQUZCSUdvUUVBdGRBQ0FBUVlqYkFCQVRJQUJCSUdwQnFOc0FFQk5CcU5zQVFjamJBQkFRUVlqYkFFSEkyd0JCeU5zQUVBOUJ5TnNBUWVqYkFCQVpJQUJCNk5zQUlBRVFFaUFBUVNCcVFlamJBQ0FCUVNCcUVCSWdBVUVnYWlBQlFTQnFFQkFMSEFBZ0FDQUJJQUlnQXhBY0lBQkJJR29nQVNBQ0lBTkJJR29RSEFzWEFRRi9JQUJCSUdvUUdDSUJCRUFnQVE4TElBQVFHQXNZQUNBQVFTQnFFQUlFUUNBQUVCY1BDeUFBUVNCcUVCY0w1QUVCQW45QkFFRUFLQUlBSWdVZ0FrRUJha0VHZEdvMkFnQWdCUkI5SUFWQlFHc2hCUU5BSUFJZ0JrY0VRQ0FBRUQwRVFDQUZRVUJxSUFVUWZnVWdBQ0FGUVVCcUlBVVFmd3NnQUNBQmFpRUFJQVZCUUdzaEJTQUdRUUZxSVFZTUFRc0xJQUFnQVdzaEFDQURJQUpCQVdzZ0JHeHFJUUlnQlVGQWFpSUZJQVVRaFFFRFFDQUdCRUFnQUJBOUJFQWdCU0FGUVVCcUVINGdBaEEvQlNBRlFVQnFRWWpjQUJCK0lBVWdBQ0FGUVVCcUVIOGdCVUdJM0FBZ0FoQi9DeUFBSUFGcklRQWdBaUFFYXlFQ0lBVkJRR29oQlNBR1FRRnJJUVlNQVFzTFFRQWdCVFlDQUF1b0FnQWdBa1VFUUNBREVIMFBDeUFBUWNqY0FCQitJQU1RZlFOQUlBSkJBV3NpQWlBQmFpMEFBQ0VBSUFNZ0F4Q0JBU0FBUVlBQlR3UkFJQU5CeU53QUlBTVFmeUFBUVlBQmF5RUFDeUFESUFNUWdRRWdBRUhBQUU4RVFDQURRY2pjQUNBREVIOGdBRUZBYWlFQUN5QURJQU1RZ1FFZ0FFRWdUd1JBSUFOQnlOd0FJQU1RZnlBQVFTQnJJUUFMSUFNZ0F4Q0JBU0FBUVJCUEJFQWdBMEhJM0FBZ0F4Qi9JQUJCRUdzaEFBc2dBeUFERUlFQklBQkJDRThFUUNBRFFjamNBQ0FERUg4Z0FFRUlheUVBQ3lBRElBTVFnUUVnQUVFRVR3UkFJQU5CeU53QUlBTVFmeUFBUVFScklRQUxJQU1nQXhDQkFTQUFRUUpQQkVBZ0EwSEkzQUFnQXhCL0lBQkJBbXNoQUFzZ0F5QURFSUVCSUFBRVFDQURRY2pjQUNBREVIOExJQUlOQUFzTHd3RUFRWWpmQUJCOVFZamZBRUdJM3dBUWhBRWdBRUdJM1FCQklFSEkzUUFRaWdGQnlOMEFRWWplQUJDQkFTQUFRWWplQUVHSTNnQVFmMEdJM2dCQnlONEFFRXhCeU40QVFZamVBRUhJM2dBUWYwSEkzZ0JCaU44QUVFUUVRQUFMUWNqZEFDQUFRY2pmQUJCL1FZamVBRUdJM3dBUVJBUkFRWWpmQUJBQlFhamZBQkFhUVlqZkFFSEkzd0FnQVJCL0JVR0k0QUFRZlVHSTRBQkJpTjRBUVlqZ0FCQ0NBVUdJNEFCQnFOMEFRU0JCaU9BQUVJb0JRWWpnQUVISTN3QWdBUkIvQ3d0akFFR280Z0FRZlVHbzRnQkJxT0lBRUlRQklBQkJ5T0FBUVNCQjZPQUFFSW9CUWVqZ0FFR280UUFRZ1FFZ0FFR280UUJCcU9FQUVIOUJxT0VBUWVqaEFCQk1RZWpoQUVHbzRRQkI2T0VBRUg5QjZPRUFRYWppQUJCRUJFQkJBQThMUVFFTERnQWdBQkE5SUFCQlFHc1FQWEVMQ2dBZ0FFR0FBV29RUFFzTkFDQUFFRDhnQUVGQWF4QS9DeFVBSUFBUVB5QUFRVUJyRUgwZ0FFR0FBV29RUHd1aUFRQWdBU0FBS1FNQU53TUFJQUVnQUNrRENEY0RDQ0FCSUFBcEF4QTNBeEFnQVNBQUtRTVlOd01ZSUFFZ0FDa0RJRGNESUNBQklBQXBBeWczQXlnZ0FTQUFLUU13TndNd0lBRWdBQ2tET0RjRE9DQUJJQUFwQTBBM0EwQWdBU0FBS1FOSU53TklJQUVnQUNrRFVEY0RVQ0FCSUFBcEExZzNBMWdnQVNBQUtRTmdOd05nSUFFZ0FDa0RhRGNEYUNBQklBQXBBM0EzQTNBZ0FTQUFLUU40TndONEM0SUNBQ0FCSUFBcEF3QTNBd0FnQVNBQUtRTUlOd01JSUFFZ0FDa0RFRGNERUNBQklBQXBBeGczQXhnZ0FTQUFLUU1nTndNZ0lBRWdBQ2tES0RjREtDQUJJQUFwQXpBM0F6QWdBU0FBS1FNNE53TTRJQUVnQUNrRFFEY0RRQ0FCSUFBcEEwZzNBMGdnQVNBQUtRTlFOd05RSUFFZ0FDa0RXRGNEV0NBQklBQXBBMkEzQTJBZ0FTQUFLUU5vTndOb0lBRWdBQ2tEY0RjRGNDQUJJQUFwQTNnM0EzZ2dBU0FBS1FPQUFUY0RnQUVnQVNBQUtRT0lBVGNEaUFFZ0FTQUFLUU9RQVRjRGtBRWdBU0FBS1FPWUFUY0RtQUVnQVNBQUtRT2dBVGNEb0FFZ0FTQUFLUU9vQVRjRHFBRWdBU0FBS1FPd0FUY0RzQUVnQVNBQUtRTzRBVGNEdUFFTEtnQWdBQkNOQVFSQUlBRVFrQUVGSUFGQmdBRnFFSDBnQUVGQWF5QUJRVUJyRUg0Z0FDQUJFSDRMQ3hVQUlBQWdBUkJFSUFCQlFHc2dBVUZBYXhCRWNRdUFBUUVCZnlBQUVJNEJCRUFnQVJDTkFROExJQUVRalFFRVFFRUFEd3NnQUVHQUFXb2lBaEI4QkVBZ0FDQUJFSlFCRHdzZ0FrR280d0FRZ1FFZ0FVR280d0JCNk9NQUVIOGdBa0dvNHdCQnFPUUFFSDhnQVVGQWEwR281QUJCNk9RQUVIOGdBRUhvNHdBUVJBUkFJQUJCUUd0QjZPUUFFRVFFUUVFQkR3c0xRUUFMeGdFQkFuOGdBQkNPQVFSQUlBRVFqZ0VQQ3lBQkVJNEJCRUJCQUE4TElBQkJnQUZxSWdJUWZBUkFJQUVnQUJDVkFROExJQUZCZ0FGcUlnTVFmQVJBSUFBZ0FSQ1ZBUThMSUFKQnFPVUFFSUVCSUFOQjZPVUFFSUVCSUFCQjZPVUFRYWptQUJCL0lBRkJxT1VBUWVqbUFCQi9JQUpCcU9VQVFham5BQkIvSUFOQjZPVUFRZWpuQUJCL0lBQkJRR3RCNk9jQVFham9BQkIvSUFGQlFHdEJxT2NBUWVqb0FCQi9RYWptQUVIbzVnQVFSQVJBUWFqb0FFSG82QUFRUkFSQVFRRVBDd3RCQUF1akFnQWdBQkNOQVFSQUlBQWdBUkNUQVE4TElBQkJxT2tBRUlFQklBQkJRR3RCNk9rQUVJRUJRZWpwQUVHbzZnQVFnUUVnQUVIbzZRQkI2T29BRUlJQlFlanFBRUhvNmdBUWdRRkI2T29BUWFqcEFFSG82Z0FRZ3dGQjZPb0FRYWpxQUVIbzZnQVFnd0ZCNk9vQVFlanFBRUhvNmdBUWdnRkJxT2tBUWFqcEFFR282d0FRZ2dGQnFPc0FRYWpwQUVHbzZ3QVFnZ0VnQUVGQWF5QUFRVUJySUFGQmdBRnFFSUlCUWFqckFDQUJFSUVCSUFGQjZPb0FJQUVRZ3dFZ0FVSG82Z0FnQVJDREFVR282Z0JCcU9vQVFlanJBQkNDQVVIbzZ3QkI2T3NBUWVqckFCQ0NBVUhvNndCQjZPc0FRZWpyQUJDQ0FVSG82Z0FnQVNBQlFVQnJFSU1CSUFGQlFHdEJxT3NBSUFGQlFHc1FmeUFCUVVCclFlanJBQ0FCUVVCckVJTUJDOGtDQUNBQUVJNEJCRUFnQUNBQkVKSUJEd3NnQUVHQUFXb1FmQVJBSUFBZ0FSQ1hBUThMSUFCQnFPd0FFSUVCSUFCQlFHdEI2T3dBRUlFQlFlanNBRUdvN1FBUWdRRWdBRUhvN0FCQjZPMEFFSUlCUWVqdEFFSG83UUFRZ1FGQjZPMEFRYWpzQUVIbzdRQVFnd0ZCNk8wQVFhanRBRUhvN1FBUWd3RkI2TzBBUWVqdEFFSG83UUFRZ2dGQnFPd0FRYWpzQUVHbzdnQVFnZ0ZCcU80QVFhanNBRUdvN2dBUWdnRkJxTzRBUWVqdUFCQ0JBU0FBUVVCcklBQkJnQUZxUWFqdkFCQi9RZWp0QUVIbzdRQWdBUkNDQVVIbzdnQWdBU0FCRUlNQlFhanRBRUdvN1FCQjZPOEFFSUlCUWVqdkFFSG83d0JCNk84QUVJSUJRZWp2QUVIbzd3QkI2TzhBRUlJQlFlanRBQ0FCSUFGQlFHc1Fnd0VnQVVGQWEwR283Z0FnQVVGQWF4Qi9JQUZCUUd0QjZPOEFJQUZCUUdzUWd3RkJxTzhBUWFqdkFDQUJRWUFCYWhDQ0FRdlFBZ0FnQUJDTkFRUkFJQUVnQWhDUkFTQUNRWUFCYWhCOUR3c2dBUkNOQVFSQUlBQWdBaENSQVNBQ1FZQUJhaEI5RHdzZ0FDQUJFRVFFUUNBQVFVQnJJQUZCUUdzUVJBUkFJQUVnQWhDWEFROExDeUFCSUFCQnFQQUFFSU1CSUFGQlFHc2dBRUZBYTBHbzhRQVFnd0ZCcVBBQVFlandBQkNCQVVIbzhBQkI2UEFBUWVqeEFCQ0NBVUhvOFFCQjZQRUFRZWp4QUJDQ0FVR284QUJCNlBFQVFhanlBQkIvUWFqeEFFR284UUJCNlBJQUVJSUJJQUJCNlBFQVFlanpBQkIvUWVqeUFFR284d0FRZ1FGQjZQTUFRZWp6QUVHbzlBQVFnZ0ZCcVBNQVFhanlBQ0FDRUlNQklBSkJxUFFBSUFJUWd3RWdBRUZBYTBHbzhnQkI2UFFBRUg5QjZQUUFRZWowQUVIbzlBQVFnZ0ZCNlBNQUlBSWdBa0ZBYXhDREFTQUNRVUJyUWVqeUFDQUNRVUJyRUg4Z0FrRkFhMEhvOUFBZ0FrRkFheENEQVVHbzhBQkJxUEFBSUFKQmdBRnFFSUlCQzhZREFRRi9JQUFRamdFRVFDQUJJQUlRa1FFZ0FrR0FBV29RZlE4TElBRVFqUUVFUUNBQUlBSVFrZ0VQQ3lBQVFZQUJhaUlERUh3RVFDQUFJQUVnQWhDWkFROExJQU5CcVBVQUVJRUJJQUZCcVBVQVFlajFBQkIvSUFOQnFQVUFRYWoyQUJCL0lBRkJRR3RCcVBZQVFlajJBQkIvSUFCQjZQVUFFRVFFUUNBQVFVQnJRZWoyQUJCRUJFQWdBU0FDRUpjQkR3c0xRZWoxQUNBQVFhajNBQkNEQVVIbzlnQWdBRUZBYTBHbytBQVFnd0ZCcVBjQVFlajNBQkNCQVVIbzl3QkI2UGNBUWVqNEFCQ0NBVUhvK0FCQjZQZ0FRZWo0QUJDQ0FVR285d0JCNlBnQVFhajVBQkIvUWFqNEFFR28rQUJCNlBrQUVJSUJJQUJCNlBnQVFlajZBQkIvUWVqNUFFR28rZ0FRZ1FGQjZQb0FRZWo2QUVHbyt3QVFnZ0ZCcVBvQVFhajVBQ0FDRUlNQklBSkJxUHNBSUFJUWd3RWdBRUZBYTBHbytRQkI2UHNBRUg5QjZQc0FRZWo3QUVIbyt3QVFnZ0ZCNlBvQUlBSWdBa0ZBYXhDREFTQUNRVUJyUWVqNUFDQUNRVUJyRUg4Z0FrRkFhMEhvK3dBZ0FrRkFheENEQVNBRFFhajNBQ0FDUVlBQmFoQ0NBU0FDUVlBQmFpQUNRWUFCYWhDQkFTQUNRWUFCYWtHbzlRQWdBa0dBQVdvUWd3RWdBa0dBQVdwQjZQY0FJQUpCZ0FGcUVJTUJDNGtFQVFKL0lBQVFqZ0VFUUNBQklBSVFrZ0VQQ3lBQkVJNEJCRUFnQUNBQ0VKSUJEd3NnQUVHQUFXb2lBeEI4QkVBZ0FTQUFJQUlRbWdFUEN5QUJRWUFCYWlJRUVId0VRQ0FBSUFFZ0FoQ2FBUThMSUFOQnFQd0FFSUVCSUFSQjZQd0FFSUVCSUFCQjZQd0FRYWo5QUJCL0lBRkJxUHdBUWVqOUFCQi9JQU5CcVB3QVFhaitBQkIvSUFSQjZQd0FRZWorQUJCL0lBQkJRR3RCNlA0QVFhai9BQkIvSUFGQlFHdEJxUDRBUWVqL0FCQi9RYWo5QUVIby9RQVFSQVJBUWFqL0FFSG8vd0FRUkFSQUlBQWdBaENZQVE4TEMwSG8vUUJCcVAwQVFhaUFBUkNEQVVIby93QkJxUDhBUWVpQUFSQ0RBVUdvZ0FGQnFJQUJRYWlCQVJDQ0FVR29nUUZCcUlFQkVJRUJRYWlBQVVHb2dRRkI2SUVCRUg5QjZJQUJRZWlBQVVHb2dnRVFnZ0ZCcVAwQVFhaUJBVUdvZ3dFUWYwR29nZ0ZCNklJQkVJRUJRYWlEQVVHb2d3RkI2SU1CRUlJQlFlaUNBVUhvZ1FFZ0FoQ0RBU0FDUWVpREFTQUNFSU1CUWFqL0FFSG9nUUZCcUlRQkVIOUJxSVFCUWFpRUFVR29oQUVRZ2dGQnFJTUJJQUlnQWtGQWF4Q0RBU0FDUVVCclFhaUNBU0FDUVVCckVIOGdBa0ZBYTBHb2hBRWdBa0ZBYXhDREFTQURJQVFnQWtHQUFXb1FnZ0VnQWtHQUFXb2dBa0dBQVdvUWdRRWdBa0dBQVdwQnFQd0FJQUpCZ0FGcUVJTUJJQUpCZ0FGcVFlajhBQ0FDUVlBQmFoQ0RBU0FDUVlBQmFrR29nQUVnQWtHQUFXb1Fmd3NWQUNBQUlBRVFmaUFBUVVCcklBRkJRR3NRaEFFTEl3QWdBQ0FCRUg0Z0FFRkFheUFCUVVCckVJUUJJQUJCZ0FGcUlBRkJnQUZxRUg0TEZnQWdBVUhvaEFFUW5BRWdBRUhvaEFFZ0FoQ1pBUXNXQUNBQlFhaUdBUkNjQVNBQVFhaUdBU0FDRUpvQkN4WUFJQUZCNkljQkVKMEJJQUJCNkljQklBSVFtd0VMRkFBZ0FDQUJFRkVnQUVGQWF5QUJRVUJyRUZFTElnQWdBQ0FCRUZFZ0FFRkFheUFCUVVCckVGRWdBRUdBQVdvZ0FVR0FBV29RVVFzVUFDQUFJQUVRVXlBQVFVQnJJQUZCUUdzUVV3c2lBQ0FBSUFFUVV5QUFRVUJySUFGQlFHc1FVeUFBUVlBQmFpQUJRWUFCYWhCVEMxWUFJQUFRamdFRVFDQUJFRDhnQVVGQWF4QS9CU0FBUVlBQmFrR29pUUVRaFFGQnFJa0JRZWlKQVJDQkFVR29pUUZCNklrQlFhaUtBUkIvSUFCQjZJa0JJQUVRZnlBQVFVQnJRYWlLQVNBQlFVQnJFSDhMQ3p3QUlBQkJRR3RCNklvQkVJRUJJQUJCcUlzQkVJRUJJQUJCcUlzQlFhaUxBUkIvUWFpTEFVSG80Z0JCcUlzQkVJSUJRZWlLQVVHb2l3RVFSQXNTQUNBQVFlaUxBUkNsQVVIb2l3RVFwZ0VMbXdFQkEzOUJBRUVBS0FJQUlnUWdBVUVHZEdvMkFnQWdBRUdBQVdwQndBRWdBU0FFUWNBQUVJa0JJQVFoQXdOQUlBRWdCVWNFUUNBREVEMEVRQ0FDRUQ4Z0FrRkFheEEvQlNBRElBQkJRR3RCNkl3QkVIOGdBeUFERUlFQklBTWdBQ0FDRUg4Z0EwSG9qQUVnQWtGQWF4Qi9DeUFBUWNBQmFpRUFJQUpCZ0FGcUlRSWdBMEZBYXlFRElBVkJBV29oQlF3QkN3dEJBQ0FFTmdJQUMxZ0FJQUFRamdFRVFDQUJFSkFCQlNBQVFZQUJha0dvalFFUWhRRkJxSTBCUWVpTkFSQ0JBVUdvalFGQjZJMEJRYWlPQVJCL0lBQkI2STBCSUFFUWZ5QUFRVUJyUWFpT0FTQUJRVUJyRUg4Z0FVR0FBV29RZlFzTE1nQWdBQkNOQVFSQUlBRVFqd0VQQ3lBQVFlaU9BUkNoQVVIb2pnRkJ3QUFnQVJCYVFhaVBBVUhBQUNBQlFVQnJFRm9MUmdBZ0FCQ05BUVJBSUFFUVB5QUJRY0FBT2dBQUR3c2dBRUhvandFUVVVSG9qd0ZCd0FBZ0FSQmFJQUJCUUdzUWh3RkJmMFlFUUNBQklBRXRBQUJCZ0FGeU9nQUFDd3MyQUNBQUxRQUFRY0FBY1FSQUlBRVFqd0VQQ3lBQVFjQUFRYWlRQVJCYUlBQkJRR3RCd0FCQjZKQUJFRnBCcUpBQklBRVFvd0VMeXdFQkFuOGdBQzBBQUNJQ1FjQUFjUVJBSUFFUWp3RVBDeUFDUVlBQmNTRURJQUJCNkpFQkVINUI2SkVCSUFKQlAzRTZBQUJCNkpFQlFjQUFRYWlSQVJCYVFhaVJBU0FCRUZNZ0FVSG9rUUVRZ1FFZ0FVSG9rUUZCNkpFQkVIOUI2SkVCUWVqaUFFSG9rUUVRZ2dGQjZKRUJRZWlSQVJDTEFVSG9rUUZCcUpFQkVJUUJRZWlSQVJDSEFVRi9SZ1JBSUFNRVFFSG9rUUVnQVVGQWF4QitCVUhva1FFZ0FVRkFheENFQVFzRklBTUVRRUhva1FFZ0FVRkFheENFQVFWQjZKRUJJQUZCUUdzUWZnc0xDekFCQVg4RFFDQUJJQU5HUlFSQUlBQWdBaENxQVNBQVFZQUJhaUVBSUFKQmdBRnFJUUlnQTBFQmFpRUREQUVMQ3dzdkFRRi9BMEFnQVNBRFJrVUVRQ0FBSUFJUXF3RWdBRUdBQVdvaEFDQUNRVUJySVFJZ0EwRUJhaUVEREFFTEN3c3dBUUYvQTBBZ0FTQURSa1VFUUNBQUlBSVFyQUVnQUVHQUFXb2hBQ0FDUVlBQmFpRUNJQU5CQVdvaEF3d0JDd3NMU1FFQmZ5QUFJQUZCQVd0QkJuUnFJUUFnQWlBQlFRRnJRUWQwYWlFQ0EwQWdBU0FEUmtVRVFDQUFJQUlRclFFZ0FFRkFhaUVBSUFKQmdBRnJJUUlnQTBFQmFpRUREQUVMQ3d0TEFRRi9JQUFnQVVFQmEwRUhkR29oQUNBQ0lBRkJBV3RCd0FGc2FpRUNBMEFnQVNBRFJrVUVRQ0FBSUFJUWt3RWdBRUdBQVdzaEFDQUNRY0FCYXlFQ0lBTkJBV29oQXd3QkN3c0wyd0lCQm44Z0JFVUVRQ0FIRUpBQkR3dEJBU0FHZENFTUlBSkJBM1FoRFNBRklBWnNJUXRCQUVFQUtBSUFJZ2xCQVNBR1FRRnJkQ0lLUWNBQmJHbzJBZ0FEUUNBSUlBcEdSUVJBSUFrZ0NFSEFBV3hxRUpBQklBaEJBV29oQ0F3QkN3c2dBeUFFSUFWc2FpRUZRUUFoQ0FOQUlBUWdDRWNFUUNBTElBMUlCSDhnQVNBQ0lBc2dCaEJrQlVFQUN5RURJQU1nQlMwQUFHb2lBeUFLVGdSQUlBTWdER3NoQXdzZ0EwRUFTZ1JBSUFrZ0EwRUJhMEhBQVd4cUlnTWdBQ0FERUpzQkJTQURRUUJJQkVBZ0NVRi9JQU5yUWNBQmJHb2lBeUFBSUFNUW9BRUxDeUFCSUFKcUlRRWdCVUVCYWlFRklBQkJ3QUZxSVFBZ0NFRUJhaUVJREFFTEN5QUpJQXBCQVd0QndBRnNhaUlBSUFjUWtnRWdBRUdva2dFUWtnRWdBRUhBQVdzaEFBTkFJQUFnQ1VsRkJFQkJxSklCSUFCQnFKSUJFSnNCSUFkQnFKSUJJQWNRbXdFZ0FFSEFBV3NoQUF3QkN3dEJBQ0FKTmdJQUM3OEJBUVIvSUFRUWtBRWdBMFVFUUE4TElBTm5MUUNvbFFFaUJVRUNTUVJBUVFJaEJRdEJBRUVBS0FJQUlnY2dBa0VEZEVFQmF5QUZia0VCYWlJR1FRRnFJQU5zYWtFRGFrRjhjVFlDQUNBQklBSWdBeUFGSUFZZ0J4QmxBMEFnQmtFQVRnUkFJQVFRamdGRkJFQkJBQ0VJQTBBZ0JTQUlSa1VFUUNBRUlBUVFtQUVnQ0VFQmFpRUlEQUVMQ3dzZ0FDQUJJQUlnQnlBRElBWWdCVUhva3dFUXN3RWdCRUhva3dFZ0JCQ2JBU0FHUVFGcklRWU1BUXNMUVFBZ0J6WUNBQXZiQWdFR2Z5QUVSUVJBSUFjUWtBRVBDMEVCSUFaMElRd2dBa0VEZENFTklBVWdCbXdoQzBFQVFRQW9BZ0FpQ1VFQklBWkJBV3QwSWdwQndBRnNhallDQUFOQUlBZ2dDa1pGQkVBZ0NTQUlRY0FCYkdvUWtBRWdDRUVCYWlFSURBRUxDeUFESUFRZ0JXeHFJUVZCQUNFSUEwQWdCQ0FJUndSQUlBc2dEVWdFZnlBQklBSWdDeUFHRUdRRlFRQUxJUU1nQXlBRkxRQUFhaUlESUFwT0JFQWdBeUFNYXlFREN5QURRUUJLQkVBZ0NTQURRUUZyUWNBQmJHb2lBeUFBSUFNUW1nRUZJQU5CQUVnRVFDQUpRWDhnQTJ0QndBRnNhaUlESUFBZ0F4Q2ZBUXNMSUFFZ0Ftb2hBU0FGUVFGcUlRVWdBRUdBQVdvaEFDQUlRUUZxSVFnTUFRc0xJQWtnQ2tFQmEwSEFBV3hxSWdBZ0J4Q1NBU0FBUWNpVkFSQ1NBU0FBUWNBQmF5RUFBMEFnQUNBSlNVVUVRRUhJbFFFZ0FFSElsUUVRbXdFZ0IwSElsUUVnQnhDYkFTQUFRY0FCYXlFQURBRUxDMEVBSUFrMkFnQUx2d0VCQkg4Z0JCQ1FBU0FEUlFSQUR3c2dBMmN0QU1pWUFTSUZRUUpKQkVCQkFpRUZDMEVBUVFBb0FnQWlCeUFDUVFOMFFRRnJJQVZ1UVFGcUlnWkJBV29nQTJ4cVFRTnFRWHh4TmdJQUlBRWdBaUFESUFVZ0JpQUhFR1VEUUNBR1FRQk9CRUFnQkJDT0FVVUVRRUVBSVFnRFFDQUZJQWhHUlFSQUlBUWdCQkNZQVNBSVFRRnFJUWdNQVFzTEN5QUFJQUVnQWlBSElBTWdCaUFGUVlpWEFSQzFBU0FFUVlpWEFTQUVFSnNCSUFaQkFXc2hCZ3dCQ3d0QkFDQUhOZ0lBQy9VREFRWi9JQUpGQkVBZ0F4Q1FBUThMUVFBb0FnQWlDQ0VFUVFBZ0FrRURkQ0lKSUFoQklHcHFRWGh4TmdJQVFRRWhCaUFCS0FJQVFRRnhJUVZCQUNFQ0EwQWdCaUFKUmtVRVFDQUJJQVpCQTNaQmZIRnFLQUlBSUFaMlFRRnhJUWNnQlFSL0lBY0VmeUFDQkg5QkFDRUZJQVJCQVRvQUFDQUVRUUZxSVFSQkFRVkJBQ0VGSUFSQi93RTZBQUFnQkVFQmFpRUVRUUVMQlNBQ0JIOUJBQ0VGSUFSQi93RTZBQUFnQkVFQmFpRUVRUUVGUVFBaEJTQUVRUUU2QUFBZ0JFRUJhaUVFUVFBTEN3VWdCd1IvSUFJRWYwRUFJUVVnQkVFQU9nQUFJQVJCQVdvaEJFRUJCVUVCSVFVZ0JFRUFPZ0FBSUFSQkFXb2hCRUVBQ3dVZ0FnUi9RUUVoQlNBRVFRQTZBQUFnQkVFQmFpRUVRUUFGUVFBaEJTQUVRUUE2QUFBZ0JFRUJhaUVFUVFBTEN3c2hBaUFHUVFGcUlRWU1BUXNMSUFVRWZ5QUNCSDhnQkVIL0FUb0FBQ0FFUVFGcUlnUkJBRG9BQUNBRVFRRnFJZ1JCQVRvQUFDQUVRUUZxQlNBRVFRRTZBQUFnQkVFQmFnc0ZJQUlFZnlBRVFRQTZBQUFnQkVFQmFpSUVRUUU2QUFBZ0JFRUJhZ1VnQkFzTFFRRnJJUVFnQUVIb21BRVFrZ0VnQXhDUUFRTkFJQU1nQXhDWUFTQUVMUUFBSWdjRVFDQUhRUUZHQkVBZ0EwSG9tQUVnQXhDYkFRVWdBMEhvbUFFZ0F4Q2dBUXNMSUFRZ0NFWkZCRUFnQkVFQmF5RUVEQUVMQzBFQUlBZzJBZ0FMOVFNQkJuOGdBa1VFUUNBREVKQUJEd3RCQUNnQ0FDSUlJUVJCQUNBQ1FRTjBJZ2tnQ0VFZ2FtcEJlSEUyQWdCQkFTRUdJQUVvQWdCQkFYRWhCVUVBSVFJRFFDQUdJQWxHUlFSQUlBRWdCa0VEZGtGOGNXb29BZ0FnQm5aQkFYRWhCeUFGQkg4Z0J3Ui9JQUlFZjBFQUlRVWdCRUVCT2dBQUlBUkJBV29oQkVFQkJVRUFJUVVnQkVIL0FUb0FBQ0FFUVFGcUlRUkJBUXNGSUFJRWYwRUFJUVVnQkVIL0FUb0FBQ0FFUVFGcUlRUkJBUVZCQUNFRklBUkJBVG9BQUNBRVFRRnFJUVJCQUFzTEJTQUhCSDhnQWdSL1FRQWhCU0FFUVFBNkFBQWdCRUVCYWlFRVFRRUZRUUVoQlNBRVFRQTZBQUFnQkVFQmFpRUVRUUFMQlNBQ0JIOUJBU0VGSUFSQkFEb0FBQ0FFUVFGcUlRUkJBQVZCQUNFRklBUkJBRG9BQUNBRVFRRnFJUVJCQUFzTEN5RUNJQVpCQVdvaEJnd0JDd3NnQlFSL0lBSUVmeUFFUWY4Qk9nQUFJQVJCQVdvaUJFRUFPZ0FBSUFSQkFXb2lCRUVCT2dBQUlBUkJBV29GSUFSQkFUb0FBQ0FFUVFGcUN3VWdBZ1IvSUFSQkFEb0FBQ0FFUVFGcUlnUkJBVG9BQUNBRVFRRnFCU0FFQ3d0QkFXc2hCQ0FBUWFpYUFSQ1JBU0FERUpBQkEwQWdBeUFERUpnQklBUXRBQUFpQndSQUlBZEJBVVlFUUNBRFFhaWFBU0FERUpvQkJTQURRYWlhQVNBREVKOEJDd3NnQkNBSVJrVUVRQ0FFUVFGcklRUU1BUXNMUVFBZ0NEWUNBQXNXQUNBQlFhaWJBUkFzSUFCQnFKc0JRU0FnQWhCcUM0OEJBUVIvUVFFZ0FYUWhCQU5BSUFJZ0JFY0VRQ0FDUWY4QmNTMEF5TGdCUVJoMElBSkJDSFpCL3dGeExRREl1QUZCRUhScUlBSkJHSFl0QU1pNEFTQUNRUkIyUWY4QmNTMEF5TGdCUVFoMGFtb2dBWGNpQXlBQ1N3UkFJQUFnQWtIZ0FHeHFJZ1ZCeUxvQkVFSWdBQ0FEUWVBQWJHb2lBeUFGRUVKQnlMb0JJQU1RUWdzZ0FrRUJhaUVDREFFTEN3dU9Bd0VKZnlBQUlBRVF1Z0ZCQVNBQmRDRUtRUUVoQkFOQUlBRWdCRThFUUVFQklBUjBJUWNnQkVFRmRFSEltd0ZxSVF0QkFDRUZBMEFnQlNBS1NRUkFRWWk4QVJBd0lBZEJBWFloQ0VFQUlRWURRQ0FHSUFoSkJFQWdBQ0FGSUFacVFlQUFiR29pQ1NBSVFlQUFiR29pREVHSXZBRkJxTHdCRUxrQklBbEJpTDBCRUVKQmlMMEJRYWk4QVNBSkVFdEJpTDBCUWFpOEFTQU1FRkJCaUx3QklBdEJpTHdCRUNnZ0JrRUJhaUVHREFFTEN5QUZJQWRxSVFVTUFRc0xJQVJCQVdvaEJBd0JDd3NnQXhBaklBSkZjVVVFUUVFQklRVkJBU0FCZENJSFFRRjJJUVlEUUNBRklBWkpCRUFnQUNBRlFlQUFiR29oQkNBQUlBY2dCV3RCNEFCc2FpRUJJQUlFUUNBREVDTUVRQ0FFUWFpN0FSQkNJQUVnQkJCQ1FhaTdBU0FCRUVJRklBUkJxTHNCRUVJZ0FTQURJQVFRdVFGQnFMc0JJQU1nQVJDNUFRc0ZJQU1RSTBVRVFDQUVJQU1nQkJDNUFTQUJJQU1nQVJDNUFRc0xJQVZCQVdvaEJRd0JDd3NnQXhBalJRUkFJQUFnQXlBQUVMa0JJQUFnQmtIZ0FHeHFJZ0VnQXlBQkVMa0JDd3NMR3dBZ0FSQnVJUUZCNkwwQkVEQWdBQ0FCUVFCQjZMMEJFTHNCQ3hrQUlBQWdBUkJ1SWdCQkFTQUFRUVYwUWVpaUFXb1F1d0VMY0FFQ2Z5QURRWWkrQVJBQVFRQWhBd05BSUFJZ0EwWkZCRUFnQVNBRFFlQUFiR29pQlVHSXZnRkJxTDRCRUxrQklBQWdBMEhnQUd4cUlnWkJpTDhCRUVKQmlMOEJRYWkrQVNBR0VFdEJpTDhCUWFpK0FTQUZFRkJCaUw0QklBUkJpTDRCRUNnZ0EwRUJhaUVEREFFTEN3dDlBUUovSUFWQkJYUkJpS29CYWlFSElBTkI2TDhCRUFCQkFDRUZBMEFnQWlBRlJrVUVRQ0FBSUFWQjRBQnNhaUlHSUFFZ0JVSGdBR3hxSWdOQmlNQUJFRXNnQXlBSElBTVF1UUVnQmlBRElBTVFTeUFEUWVpL0FTQURFTGtCUVlqQUFTQUdFRUpCNkw4QklBUkI2TDhCRUNnZ0JVRUJhaUVGREFFTEN3dVhBUUVEZnlBRlFRVjBRWWlxQVdvaENDQUZRUVYwUWFpeEFXb2hCeUFEUWVqQUFSQUFRUUFoQlFOQUlBSWdCVVpGQkVBZ0FTQUZRZUFBYkdvaUJrSG93QUZCaU1FQkVMa0JJQUFnQlVIZ0FHeHFJZ05CaU1FQklBWVFVQ0FHSUFjZ0JoQzVBU0FESUFnZ0F4QzVBVUdJd1FFZ0F5QURFRkFnQXlBSElBTVF1UUZCNk1BQklBUkI2TUFCRUNnZ0JVRUJhaUVGREFFTEN3dXVBUUVIZnlBQklBSjJJUVJCQVNBQ2RDSUZRUUYySWdaQjRBQnNJUWNnQWtFRmRFSEltd0ZxSVFoQkFDRUJBMEFnQVNBRVJrVUVRRUhvd1FFUU1FRUFJUUlEUUNBQ0lBWkdSUVJBSUFBZ0FTQUZiQ0FDYWtIZ0FHeHFJZ01nQjJvaUNVSG93UUZCaU1JQkVMa0JJQU5CNk1JQkVFSkI2TUlCUVlqQ0FTQURFRXRCNk1JQlFZakNBU0FKRUZCQjZNRUJJQWhCNk1FQkVDZ2dBa0VCYWlFQ0RBRUxDeUFCUVFGcUlRRU1BUXNMQzNNQkJIOGdBVUVCZGlFRUlBRkJBWEVFUUNBQUlBUkI0QUJzYWlBQ0lBQWdCRUhnQUd4cUVMa0JDd05BSUFNZ0JFOUZCRUFnQUNBQlFRRnJJQU5yUWVBQWJHb2lCU0FDUWNqREFSQzVBU0FBSUFOQjRBQnNhaUlHSUFJZ0JSQzVBVUhJd3dFZ0JoQkNJQU5CQVdvaEF3d0JDd3NMa0FFQkEzOGdCVUVGZEVHSXFnRnFJUWNnQlVFRmRFR29zUUZxSVFnZ0EwR294QUVRQUVFQUlRTURRQ0FDSUFOR1JRUkFJQUFnQTBIZ0FHeHFJZ1lnQjBISXhBRVF1UUVnQVNBRFFlQUFiR29pQlVISXhBRkJ5TVFCRUZBZ0JpQUZJQVVRVUVISXhBRWdDQ0FHRUxrQklBVkJxTVFCSUFVUXVRRkJxTVFCSUFSQnFNUUJFQ2dnQTBFQmFpRUREQUVMQ3dzWEFDQUJRYWpGQVJBc0lBQkJxTVVCUVNBZ0FoQzNBUXVTQVFFRWYwRUJJQUYwSVFRRFFDQUNJQVJIQkVBZ0FrSC9BWEV0QU1qaUFVRVlkQ0FDUVFoMlFmOEJjUzBBeU9JQlFSQjBhaUFDUVJoMkxRREk0Z0VnQWtFUWRrSC9BWEV0QU1qaUFVRUlkR3BxSUFGM0lnTWdBa3NFUUNBQUlBSkJ3QUZzYWlJRlFjamtBUkNTQVNBQUlBTkJ3QUZzYWlJRElBVVFrZ0ZCeU9RQklBTVFrZ0VMSUFKQkFXb2hBZ3dCQ3dzTGxRTUJDWDhnQUNBQkVNVUJRUUVnQVhRaENrRUJJUVFEUUNBQklBUlBCRUJCQVNBRWRDRUhJQVJCQlhSQnlNVUJhaUVMUVFBaEJRTkFJQVVnQ2trRVFFSEk1d0VRTUNBSFFRRjJJUWhCQUNFR0EwQWdCaUFJU1FSQUlBQWdCU0FHYWtIQUFXeHFJZ2tnQ0VIQUFXeHFJZ3hCeU9jQlFlam5BUkRFQVNBSlFhanBBUkNTQVVHbzZRRkI2T2NCSUFrUW13RkJxT2tCUWVqbkFTQU1FS0FCUWNqbkFTQUxRY2puQVJBb0lBWkJBV29oQmd3QkN3c2dCU0FIYWlFRkRBRUxDeUFFUVFGcUlRUU1BUXNMSUFNUUl5QUNSWEZGQkVCQkFTRUZRUUVnQVhRaUIwRUJkaUVHQTBBZ0JTQUdTUVJBSUFBZ0JVSEFBV3hxSVFRZ0FDQUhJQVZyUWNBQmJHb2hBU0FDQkVBZ0F4QWpCRUFnQkVHSTVnRVFrZ0VnQVNBRUVKSUJRWWptQVNBQkVKSUJCU0FFUVlqbUFSQ1NBU0FCSUFNZ0JCREVBVUdJNWdFZ0F5QUJFTVFCQ3dVZ0F4QWpSUVJBSUFRZ0F5QUVFTVFCSUFFZ0F5QUJFTVFCQ3dzZ0JVRUJhaUVGREFFTEN5QURFQ05GQkVBZ0FDQURJQUFReEFFZ0FDQUdRY0FCYkdvaUFTQURJQUVReEFFTEN3c2JBQ0FCRUc0aEFVSG82Z0VRTUNBQUlBRkJBRUhvNmdFUXhnRUxHUUFnQUNBQkVHNGlBRUVCSUFCQkJYUkI2TXdCYWhER0FRdHpBUUovSUFOQmlPc0JFQUJCQUNFREEwQWdBaUFEUmtVRVFDQUJJQU5Cd0FGc2FpSUZRWWpyQVVHbzZ3RVF4QUVnQUNBRFFjQUJiR29pQmtIbzdBRVFrZ0ZCNk93QlFhanJBU0FHRUpzQlFlanNBVUdvNndFZ0JSQ2dBVUdJNndFZ0JFR0k2d0VRS0NBRFFRRnFJUU1NQVFzTEM0QUJBUUovSUFWQkJYUkJpTlFCYWlFSElBTkJxTzRCRUFCQkFDRUZBMEFnQWlBRlJrVUVRQ0FBSUFWQndBRnNhaUlHSUFFZ0JVSEFBV3hxSWdOQnlPNEJFSnNCSUFNZ0J5QURFTVFCSUFZZ0F5QURFSnNCSUFOQnFPNEJJQU1ReEFGQnlPNEJJQVlRa2dGQnFPNEJJQVJCcU80QkVDZ2dCVUVCYWlFRkRBRUxDd3VaQVFFRGZ5QUZRUVYwUVlqVUFXb2hDQ0FGUVFWMFFhamJBV29oQnlBRFFZandBUkFBUVFBaEJRTkFJQUlnQlVaRkJFQWdBU0FGUWNBQmJHb2lCa0dJOEFGQnFQQUJFTVFCSUFBZ0JVSEFBV3hxSWdOQnFQQUJJQVlRb0FFZ0JpQUhJQVlReEFFZ0F5QUlJQU1ReEFGQnFQQUJJQU1nQXhDZ0FTQURJQWNnQXhERUFVR0k4QUVnQkVHSThBRVFLQ0FGUVFGcUlRVU1BUXNMQzdFQkFRZC9JQUVnQW5ZaEJFRUJJQUowSWdWQkFYWWlCa0hBQVd3aEJ5QUNRUVYwUWNqRkFXb2hDRUVBSVFFRFFDQUJJQVJHUlFSQVFlanhBUkF3UVFBaEFnTkFJQUlnQmtaRkJFQWdBQ0FCSUFWc0lBSnFRY0FCYkdvaUF5QUhhaUlKUWVqeEFVR0k4Z0VReEFFZ0EwSEk4d0VRa2dGQnlQTUJRWWp5QVNBREVKc0JRY2p6QVVHSThnRWdDUkNnQVVIbzhRRWdDRUhvOFFFUUtDQUNRUUZxSVFJTUFRc0xJQUZCQVdvaEFRd0JDd3NMZEFFRWZ5QUJRUUYySVFRZ0FVRUJjUVJBSUFBZ0JFSEFBV3hxSUFJZ0FDQUVRY0FCYkdvUXhBRUxBMEFnQXlBRVQwVUVRQ0FBSUFGQkFXc2dBMnRCd0FGc2FpSUZJQUpCaVBVQkVNUUJJQUFnQTBIQUFXeHFJZ1lnQWlBRkVNUUJRWWoxQVNBR0VKSUJJQU5CQVdvaEF3d0JDd3NMa2dFQkEzOGdCVUVGZEVHSTFBRnFJUWNnQlVFRmRFR28yd0ZxSVFnZ0EwSEk5Z0VRQUVFQUlRTURRQ0FDSUFOR1JRUkFJQUFnQTBIQUFXeHFJZ1lnQjBIbzlnRVF4QUVnQVNBRFFjQUJiR29pQlVIbzlnRkI2UFlCRUtBQklBWWdCU0FGRUtBQlFlajJBU0FJSUFZUXhBRWdCVUhJOWdFZ0JSREVBVUhJOWdFZ0JFSEk5Z0VRS0NBRFFRRnFJUU1NQVFzTEN4WUFJQUZCcVBnQkVDd2dBRUdvK0FGQklDQUNFR3NMRndBZ0FVSEkrQUVRTENBQVFjajRBVUVnSUFJUXVBRUxSd0FnQWtIbytBRVFBRUVBSVFJRFFDQUJJQUpHUlFSQUlBQkI2UGdCSUFRUUtDQUFRU0JxSVFBZ0JFRWdhaUVFUWVqNEFTQURRZWo0QVJBb0lBSkJBV29oQWd3QkN3c0xTZ0FnQWtHSStRRVFBRUVBSVFJRFFDQUJJQUpHUlFSQUlBQkJpUGtCSUFRUXVRRWdBRUhnQUdvaEFDQUVRZUFBYWlFRVFZajVBU0FEUVlqNUFSQW9JQUpCQVdvaEFnd0JDd3NMU1FBZ0FrR28rUUVRQUVFQUlRSURRQ0FCSUFKR1JRUkFJQUJCcVBrQklBUVF6d0VnQUVGQWF5RUFJQVJCNEFCcUlRUkJxUGtCSUFOQnFQa0JFQ2dnQWtFQmFpRUNEQUVMQ3d0S0FDQUNRY2o1QVJBQVFRQWhBZ05BSUFFZ0FrWkZCRUFnQUVISStRRWdCQkRFQVNBQVFjQUJhaUVBSUFSQndBRnFJUVJCeVBrQklBTkJ5UGtCRUNnZ0FrRUJhaUVDREFFTEN3dEtBQ0FDUWVqNUFSQUFRUUFoQWdOQUlBRWdBa1pGQkVBZ0FFSG8rUUVnQkJEUUFTQUFRWUFCYWlFQUlBUkJ3QUZxSVFSQjZQa0JJQU5CNlBrQkVDZ2dBa0VCYWlFQ0RBRUxDd3NNQUVISWdRSWdBQ0FCRUg4TEZ3QWdBQkE5SUFCQlFHc1FQWEVnQUVHQUFXb1FQWEVMRndBZ0FCQjhJQUJCUUdzUVBYRWdBRUdBQVdvUVBYRUxGUUFnQUJBL0lBQkJRR3NRUHlBQVFZQUJhaEEvQ3hVQUlBQVFmU0FBUVVCckVEOGdBRUdBQVdvUVB3c2lBQ0FBSUFFUWZpQUFRVUJySUFGQlFHc1FmaUFBUVlBQmFpQUJRWUFCYWhCK0M5UUNBQ0FBSUFGQmlJTUNFSDhnQUVGQWF5QUJRVUJyUWNpREFoQi9JQUJCZ0FGcUlBRkJnQUZxUVlpRUFoQi9JQUFnQUVGQWEwSEloQUlRZ2dFZ0FTQUJRVUJyUVlpRkFoQ0NBU0FBSUFCQmdBRnFRY2lGQWhDQ0FTQUJJQUZCZ0FGcVFZaUdBaENDQVNBQVFVQnJJQUJCZ0FGcVFjaUdBaENDQVNBQlFVQnJJQUZCZ0FGcVFZaUhBaENDQVVHSWd3SkJ5SU1DUWNpSEFoQ0NBVUdJZ3dKQmlJUUNRWWlJQWhDQ0FVSElnd0pCaUlRQ1FjaUlBaENDQVVISWhnSkJpSWNDSUFJUWZ5QUNRY2lJQWlBQ0VJTUJJQUlnQWhEV0FVR0lnd0lnQWlBQ0VJSUJRY2lFQWtHSWhRSWdBa0ZBYXhCL0lBSkJRR3RCeUljQ0lBSkJRR3NRZ3dGQmlJUUNRWWlKQWhEV0FTQUNRVUJyUVlpSkFpQUNRVUJyRUlJQlFjaUZBa0dJaGdJZ0FrR0FBV29RZnlBQ1FZQUJha0dJaUFJZ0FrR0FBV29RZ3dFZ0FrR0FBV3BCeUlNQ0lBSkJnQUZxRUlJQkMva0JBQ0FBUWNpSkFoQ0JBU0FBSUFCQlFHdEJpSW9DRUg5QmlJb0NRWWlLQWtISWlnSVFnZ0VnQUNBQVFVQnJRWWlMQWhDREFVR0lpd0lnQUVHQUFXcEJpSXNDRUlJQlFZaUxBa0dJaXdJUWdRRWdBRUZBYXlBQVFZQUJha0hJaXdJUWYwSElpd0pCeUlzQ1FZaU1BaENDQVNBQVFZQUJha0hJakFJUWdRRkJpSXdDSUFFUTFnRkJ5SWtDSUFFZ0FSQ0NBVUhJakFJZ0FVRkFheERXQVVISWlnSWdBVUZBYXlBQlFVQnJFSUlCUWNpSkFrSElqQUlnQVVHQUFXb1FnZ0ZCaUl3Q0lBRkJnQUZxSUFGQmdBRnFFSU1CUVlpTEFpQUJRWUFCYWlBQlFZQUJhaENDQVVISWlnSWdBVUdBQVdvZ0FVR0FBV29RZ2dFTE1nQWdBQ0FCSUFJUWdnRWdBRUZBYXlBQlFVQnJJQUpCUUdzUWdnRWdBRUdBQVdvZ0FVR0FBV29nQWtHQUFXb1FnZ0VMTWdBZ0FDQUJJQUlRZ3dFZ0FFRkFheUFCUVVCcklBSkJRR3NRZ3dFZ0FFR0FBV29nQVVHQUFXb2dBa0dBQVdvUWd3RUxKUUFnQUNBQkVJUUJJQUJCUUdzZ0FVRkFheENFQVNBQVFZQUJhaUFCUVlBQmFoQ0VBUXNxQVFGL0lBQkJnQUZxRUljQklnRUVRQ0FCRHdzZ0FFRkFheENIQVNJQkJFQWdBUThMSUFBUWh3RUxKQUFnQUNBQkVFUWdBRUZBYXlBQlFVQnJFRVJ4SUFCQmdBRnFJQUZCZ0FGcUVFUnhDNTBDQUNBQVFZaU5BaENCQVNBQVFVQnJRY2lOQWhDQkFTQUFRWUFCYWtHSWpnSVFnUUVnQUNBQVFVQnJRY2lPQWhCL0lBQWdBRUdBQVdwQmlJOENFSDhnQUVGQWF5QUFRWUFCYWtISWp3SVFmMEhJandKQmlKQUNFTllCUVlpTkFrR0lrQUpCaUpBQ0VJTUJRWWlPQWtISWtBSVExZ0ZCeUpBQ1FjaU9Ba0hJa0FJUWd3RkJ5STBDUVlpUEFrR0lrUUlRZ3dFZ0FFR0FBV3BCeUpBQ1FjaVJBaEIvSUFCQlFHdEJpSkVDUVlpU0FoQi9RY2lSQWtHSWtnSkJ5SkVDRUlJQlFjaVJBa0hJa1FJUTFnRWdBRUdJa0FKQmlKSUNFSDlCaUpJQ1FjaVJBa0hJa1FJUWdnRkJ5SkVDUWNpUkFoQ0ZBVUhJa1FKQmlKQUNJQUVRZjBISWtRSkJ5SkFDSUFGQlFHc1FmMEhJa1FKQmlKRUNJQUZCZ0FGcUVIOExNUUFnQUNBQklBSWdBeENHQVNBQVFVQnJJQUVnQWlBRFFVQnJFSVlCSUFCQmdBRnFJQUVnQWlBRFFZQUJhaENHQVFzcEFDQUFRWUFCYWhBOUJFQWdBQ0FBUVVCcklBQkJRR3NRUFJzUWlBRVBDeUFBUVlBQmFoQ0lBUXY0QVFFQ2YwRUFRUUFvQWdBaUJTQUNRUUZxUWNBQmJHbzJBZ0FnQlJEYUFTQUZRY0FCYWlFRkEwQWdBaUFHUndSQUlBQVExd0VFUUNBRlFjQUJheUFGRU5zQkJTQUFJQVZCd0FGcklBVVEzQUVMSUFBZ0FXb2hBQ0FGUWNBQmFpRUZJQVpCQVdvaEJnd0JDd3NnQUNBQmF5RUFJQU1nQWtFQmF5QUViR29oQWlBRlFjQUJheUlGSUFVUTR3RURRQ0FHQkVBZ0FCRFhBUVJBSUFVZ0JVSEFBV3NRMndFZ0FoRFpBUVVnQlVIQUFXdEJ5SklDRU5zQklBVWdBQ0FGUWNBQmF4RGNBU0FGUWNpU0FpQUNFTndCQ3lBQUlBRnJJUUFnQWlBRWF5RUNJQVZCd0FGcklRVWdCa0VCYXlFR0RBRUxDMEVBSUFVMkFnQUxzd0lBSUFKRkJFQWdBeERhQVE4TElBQkJpSlFDRU5zQklBTVEyZ0VEUUNBQ1FRRnJJZ0lnQVdvdEFBQWhBQ0FESUFNUTNRRWdBRUdBQVU4RVFDQURRWWlVQWlBREVOd0JJQUJCZ0FGcklRQUxJQU1nQXhEZEFTQUFRY0FBVHdSQUlBTkJpSlFDSUFNUTNBRWdBRUZBYWlFQUN5QURJQU1RM1FFZ0FFRWdUd1JBSUFOQmlKUUNJQU1RM0FFZ0FFRWdheUVBQ3lBRElBTVEzUUVnQUVFUVR3UkFJQU5CaUpRQ0lBTVEzQUVnQUVFUWF5RUFDeUFESUFNUTNRRWdBRUVJVHdSQUlBTkJpSlFDSUFNUTNBRWdBRUVJYXlFQUN5QURJQU1RM1FFZ0FFRUVUd1JBSUFOQmlKUUNJQU1RM0FFZ0FFRUVheUVBQ3lBRElBTVEzUUVnQUVFQ1R3UkFJQU5CaUpRQ0lBTVEzQUVnQUVFQ2F5RUFDeUFESUFNUTNRRWdBQVJBSUFOQmlKUUNJQU1RM0FFTElBSU5BQXNMSmdCQnlJRUNJQUJCZ0FGcUlBRVFmeUFBSUFGQlFHc1FmaUFBUVVCcklBRkJnQUZxRUg0TEVRQWdBQkRYQVNBQVFjQUJhaERYQVhFTEVRQWdBQkRZQVNBQVFjQUJhaERYQVhFTEVBQWdBQkRaQVNBQVFjQUJhaERaQVFzUUFDQUFFTm9CSUFCQndBRnFFTmtCQ3hnQUlBQWdBUkRiQVNBQVFjQUJhaUFCUWNBQmFoRGJBUXVGQVFBZ0FDQUJRY2lWQWhEY0FTQUFRY0FCYWlBQlFjQUJha0dJbHdJUTNBRWdBQ0FBUWNBQmFrSEltQUlRM2dFZ0FTQUJRY0FCYWtHSW1nSVEzZ0ZCeUpnQ1FZaWFBa0hJbUFJUTNBRkJpSmNDSUFJUTZBRkJ5SlVDSUFJZ0FoRGVBVUhJbFFKQmlKY0NJQUpCd0FGcUVONEJRY2lZQWlBQ1FjQUJhaUFDUWNBQmFoRGZBUXNjQUNBQUlBRWdBaERjQVNBQVFjQUJhaUFCSUFKQndBRnFFTndCQzMwQUlBQWdBRUhBQVdwQnlKc0NFTndCSUFBZ0FFSEFBV3BCaUowQ0VONEJJQUJCd0FGcVFjaWVBaERvQVNBQVFjaWVBa0hJbmdJUTNnRkJ5SnNDUVlpZ0FoRG9BVUdJb0FKQnlKc0NRWWlnQWhEZUFVR0luUUpCeUo0Q0lBRVEzQUVnQVVHSW9BSWdBUkRmQVVISW13SkJ5SnNDSUFGQndBRnFFTjRCQ3lBQUlBQWdBU0FDRU40QklBQkJ3QUZxSUFGQndBRnFJQUpCd0FGcUVONEJDeUFBSUFBZ0FTQUNFTjhCSUFCQndBRnFJQUZCd0FGcUlBSkJ3QUZxRU44QkN4Z0FJQUFnQVJEZ0FTQUFRY0FCYWlBQlFjQUJhaERnQVFzWUFDQUFJQUVRMndFZ0FFSEFBV29nQVVIQUFXb1E0QUVMR0FBZ0FDQUJFS1FCSUFCQndBRnFJQUZCd0FGcUVLUUJDeGdBSUFBZ0FSQ2lBU0FBUWNBQmFpQUJRY0FCYWhDaUFRc1pBQ0FBSUFFUTRnRWdBRUhBQVdvZ0FVSEFBV29RNGdGeEMyb0FJQUJCeUtFQ0VOMEJJQUJCd0FGcVFZaWpBaERkQVVHSW93SkJ5S1FDRU9nQlFjaWhBa0hJcEFKQnlLUUNFTjhCUWNpa0FrR0lwZ0lRNHdFZ0FFR0lwZ0lnQVJEY0FTQUFRY0FCYWtHSXBnSWdBVUhBQVdvUTNBRWdBVUhBQVdvZ0FVSEFBV29RNEFFTElBQWdBQ0FCSUFJZ0F4RGtBU0FBUWNBQmFpQUJJQUlnQTBIQUFXb1E1QUVMR2dFQmZ5QUFRY0FCYWhEaEFTSUJCRUFnQVE4TElBQVE0UUVMSFFBZ0FFSEFBV29RMXdFRVFDQUFFT1VCRHdzZ0FFSEFBV29RNVFFTCtBRUJBbjlCQUVFQUtBSUFJZ1VnQWtFQmFrR0FBMnhxTmdJQUlBVVE3QUVnQlVHQUEyb2hCUU5BSUFJZ0JrY0VRQ0FBRU9rQkJFQWdCVUdBQTJzZ0JSRHRBUVVnQUNBRlFZQURheUFGRU80QkN5QUFJQUZxSVFBZ0JVR0FBMm9oQlNBR1FRRnFJUVlNQVFzTElBQWdBV3NoQUNBRElBSkJBV3NnQkd4cUlRSWdCVUdBQTJzaUJTQUZFUGdCQTBBZ0JnUkFJQUFRNlFFRVFDQUZJQVZCZ0FOckVPMEJJQUlRNndFRklBVkJnQU5yUWNpbkFoRHRBU0FGSUFBZ0JVR0FBMnNRN2dFZ0JVSElwd0lnQWhEdUFRc2dBQ0FCYXlFQUlBSWdCR3NoQWlBRlFZQURheUVGSUFaQkFXc2hCZ3dCQ3d0QkFDQUZOZ0lBQzdNQ0FDQUNSUVJBSUFNUTdBRVBDeUFBUWNpcUFoRHRBU0FERU93QkEwQWdBa0VCYXlJQ0lBRnFMUUFBSVFBZ0F5QURFUEFCSUFCQmdBRlBCRUFnQTBISXFnSWdBeER1QVNBQVFZQUJheUVBQ3lBRElBTVE4QUVnQUVIQUFFOEVRQ0FEUWNpcUFpQURFTzRCSUFCQlFHb2hBQXNnQXlBREVQQUJJQUJCSUU4RVFDQURRY2lxQWlBREVPNEJJQUJCSUdzaEFBc2dBeUFERVBBQklBQkJFRThFUUNBRFFjaXFBaUFERU80QklBQkJFR3NoQUFzZ0F5QURFUEFCSUFCQkNFOEVRQ0FEUWNpcUFpQURFTzRCSUFCQkNHc2hBQXNnQXlBREVQQUJJQUJCQkU4RVFDQURRY2lxQWlBREVPNEJJQUJCQkdzaEFBc2dBeUFERVBBQklBQkJBazhFUUNBRFFjaXFBaUFERU80QklBQkJBbXNoQUFzZ0F5QURFUEFCSUFBRVFDQURRY2lxQWlBREVPNEJDeUFDRFFBTEM5RUJBRUhJdVFJUTdBRkJ5TGtDUWNpNUFoRHpBU0FBUWNpdEFrSEFBVUhJc0FJUS9RRkJ5TEFDUWNpekFoRHdBU0FBUWNpekFrSElzd0lRN2dGQnlMTUNRY2kyQWhEMEFVSEl0Z0pCeUxNQ1FjaTJBaER1QVVISXRnSkJ5TGtDRVBjQkJFQUFDMEhJc0FJZ0FFSEl2QUlRN2dGQnlMTUNRY2k1QWhEM0FRUkFRY2k1QWhEWkFVR0l1d0lRMmdGQnlMa0NRY2k4QWlBQkVPNEJCVUhJdndJUTdBRkJ5TDhDUWNpekFrSEl2d0lROFFGQnlMOENRWWl2QWtIQUFVSEl2d0lRL1FGQnlMOENRY2k4QWlBQkVPNEJDd3RwQUVHSXpRSVE3QUZCaU0wQ1FZak5BaER6QVNBQVFjakNBa0hBQVVHSXhBSVEvUUZCaU1RQ1FZakhBaER3QVNBQVFZakhBa0dJeHdJUTdnRkJpTWNDUVlqS0FoRDBBVUdJeWdKQmlNY0NRWWpLQWhEdUFVR0l5Z0pCaU0wQ0VQY0JCRUJCQUE4TFFRRUx3QUlBSUFCQmtQZ0RJQUZCUUdzUWYwR1E5d01nQVVGQWF5QUJRVUJyRUlNQklBQkJRR3RCa1BnRFFkRHNBeEIvUWREM0EwSFE3QU5CME93REVJTUJJQUZCUUd0QmtPMERFSUVCUWREc0EwSFE3UU1RZ1FFZ0FVRkFhMEdRN1FOQmtPNERFSDlCa1BjRFFaRHRBMEhRN2dNUWYwSFE3Z05CME80RFFkRHZBeENDQVVHUStBTkIwTzBEUVpEdkF4Qi9RWkR1QTBHUTd3TkJrTzhERUlJQlFaRHZBMEhRN3dOQmtPOERFSU1CSUFGQlFHdEJrTzhEUVpEM0F4Qi9RWkR1QTBIUTl3TkIwUGNERUg5QjBPNERRWkR2QTBIUTd3TVFnd0ZCME93RFFkRHZBMEhRN3dNUWYwSFE3d05CMFBjRFFkRDNBeENEQVVHUStBTkJrTzREUVpENEF4Qi9JQUZCUUdzZ0FFRkFhMEhRN3dNUWYwSFE3QU1nQUNBQkVIOGdBVUhRN3dNZ0FSQ0RBU0FCUWNpQkFpQUJFSDlCME93RElBRkJnQUZxRUlRQkN3Z0FJQUFnQVJCWkN6d0FJQUFnQVJCTVFaRDJBeUFCSUFFUWZ5QUFRVUJySUFGQlFHc1FURUhROWdNZ0FVRkFheUFCUVVCckVIOGdBRUdBQVdvZ0FVR0FBV29RVEF1c0JBRUJmeUFBSUFFUXFRRWdBVUdROXdNUWZpQUJRVUJyUWREM0F4QitRWkQ0QXhCOUlBRkJ3QUZxSVFCQlB5RUNBMEJCMFBjRFFZaUNBa0dROEFNUWYwR1E5d05Ca1BBRFFaRHdBeEIvUWREM0EwSFE4QU1RZ1FGQmtQZ0RRWkR4QXhDQkFVR1E4UU5Ca1BFRFFkRHhBeENDQVVIUThRTkJrUEVEUWREeEF4Q0NBVUhJZ2dKQjBQRURRWkR5QXhCL1FaRHlBMEdROGdOQjBQSURFSUlCUVpEeUEwSFE4Z05CMFBJREVJSUJRZER3QTBIUThnTkJrUE1ERUlJQlFaRHpBMEdJZ2dKQmtQTURFSDlCMFBBRFFaRHhBMEhROVFNUWdnRkIwUGNEUVpENEEwSFE4d01RZ2dGQjBQTURRZER6QXhDQkFVSFE4d05CMFBVRFFkRHpBeENEQVVHUThnTkIwUEFEUVpEMEF4Q0RBVUdROXdOQjBQUURFSUVCUVpEeUEwR1E5UU1RZ1FGQjBQQURRZER5QTBIUTlRTVFnd0ZCa1BBRFFkRDFBMEdROXdNUWYwR1E5UU5Ca1BVRFFkRDFBeENDQVVHUTlRTkIwUFVEUWREMUF4Q0NBVUdROHdOQjBQY0RFSUVCUWREM0EwSFE5UU5CMFBjREVJTUJRZER3QTBIUTh3TkJrUGdERUg5QnlJRUNRWkQwQXlBQUVIOUIwUE1ESUFCQlFHc1FoQUZCMFBRRFFkRDBBeUFBUVlBQmFoQ0NBVUhROUFNZ0FFR0FBV29nQUVHQUFXb1FnZ0VnQUVIQUFXb2hBQ0FDTEFDSTBBSUVRQ0FCSUFBUWdBSWdBRUhBQVdvaEFBc2dBZ1JBSUFKQkFXc2hBZ3dCQ3dzZ0FVSFErQU1RZ2dKQjBQZ0RRWkQ2QXhDQ0FrSFErZ05CMFBvREVJUUJRZEQ0QXlBQUVJQUNRWkQ2QXlBQVFjQUJhaENBQWd1YkJRQWdBeUFBUWREK0F4Qi9JQU5CZ0FGcUlBSkJrUDhERUg4Z0EwR0FBbW9nQVVIUS93TVFmeUFESUFOQmdBSnFRZEQ4QXhDQ0FTQURJQU5CZ0FGcVFaRDhBeENDQVNBRFFVQnJJQU5Cd0FGcVFaRDlBeENDQVVHUS9RTWdBMEhBQW1wQmtQMERFSUlCSUFOQlFHc2dBa0dRZ0FRUWYwR1FnQVJCMFA4RFFkRDlBeENDQVVISWdRSkIwUDBEUVpEK0F4Qi9RWkQrQTBIUS9nTWdBeENDQVNBRFFjQUNhaUFCUWREOUF4Qi9RWkNBQkVIUS9RTkJrSUFFRUlJQlFkRDlBMEdRL3dOQjBQMERFSUlCUWNpQkFrSFEvUU5Ca1A0REVIOGdBMEZBYXlBQVFkRDlBeEIvUVpDQUJFSFEvUU5Ca0lBRUVJSUJRWkQrQTBIUS9RTWdBMEZBYXhDQ0FTQUFJQUpCMFBzREVJSUJRWkQ4QTBIUSt3TkIwUDBERUg5QjBQNERRWkQvQTBIUWdBUVFnZ0ZCMFAwRFFkQ0FCRUhRL1FNUWd3RWdBMEhBQVdvZ0FVR1EvZ01RZjBHUWdBUkJrUDREUVpDQUJCQ0NBU0FEUVlBQmFpQURRWUFDYWtIUSt3TVFnZ0ZCMFAwRFFaRCtBeUFEUVlBQmFoQ0NBU0FDSUFGQmtQd0RFSUlCUVpEOEEwSFErd05CMFAwREVIOUJrUDhEUWREL0EwSFFnQVFRZ2dGQjBQMERRZENBQkVIUS9RTVFnd0ZCeUlFQ1FkRDlBMEdRL2dNUWZ5QURRY0FCYWlBQVFkRDlBeEIvUVpDQUJFSFEvUU5Ca0lBRUVJSUJRWkQrQTBIUS9RTWdBMEhBQVdvUWdnRWdBMEhBQW1vZ0FrSFEvUU1RZjBHUWdBUkIwUDBEUVpDQUJCQ0NBVUhJZ1FKQjBQMERRWkQrQXhCL0lBQWdBVUhRK3dNUWdnRkIwUHdEUWREN0EwSFEvUU1RZjBIUS9nTkIwUDhEUWRDQUJCQ0NBVUhRL1FOQjBJQUVRZEQ5QXhDREFVR1EvZ05CMFAwRElBTkJnQUpxRUlJQklBQWdBa0hRK3dNUWdnRkIwUHNESUFGQjBQc0RFSUlCUVpEOUEwSFErd05CMFAwREVIOUIwUDBEUVpDQUJDQURRY0FDYWhDREFRczNBQ0FBUVpDQkJCQitRZENCQkJBL0lBSkJrSUlFRUg1QjBJSUVFRDhnQVVHUWd3UVFma0hRZ3dRUVAwR1FnUVFnQXlBREVPNEJDNGtDQVFGL0lBSVE3QUVnQVVIQUFXb2hBVUUvSVFNRFFDQUNJQUlROEFFZ0FVRkFheUFBUVNCcVFaQ0VCQkNBQVNBQlFZQUJhaUFBUWRDRUJCQ0FBU0FCUVpDRUJFSFFoQVFnQWhDRUFpQUJRY0FCYWlFQklBTXNBSWpRQWdSQUlBRkJRR3NnQUVFZ2FrR1FoQVFRZ0FFZ0FVR0FBV29nQUVIUWhBUVFnQUVnQVVHUWhBUkIwSVFFSUFJUWhBSWdBVUhBQVdvaEFRc2dBd1JBSUFOQkFXc2hBd3dCQ3dzZ0FVRkFheUFBUVNCcVFaQ0VCQkNBQVNBQlFZQUJhaUFBUWRDRUJCQ0FBU0FCUVpDRUJFSFFoQVFnQWhDRUFpQUJRY0FCYWlJQlFVQnJJQUJCSUdwQmtJUUVFSUFCSUFGQmdBRnFJQUJCMElRRUVJQUJJQUZCa0lRRVFkQ0VCQ0FDRUlRQ0MyUUFJQUJCa0lVRUlBRVFmeUFBUVVCclFkQ0ZCQ0FCUVVCckVIOGdBRUdBQVdwQmtJWUVJQUZCZ0FGcUVIOGdBRUhBQVdwQjBJWUVJQUZCd0FGcUVIOGdBRUdBQW1wQmtJY0VJQUZCZ0FKcUVIOGdBRUhBQW1wQjBJY0VJQUZCd0FKcUVIOExnQUlBSUFBZ0FSQUFJQUJCSUdvZ0FVRWdhaEFRSUFGQmtJZ0VJQUVRZnlBQVFVQnJJQUZCUUdzUUFDQUFRZUFBYWlBQlFlQUFhaEFRSUFGQlFHdEIwSWdFSUFGQlFHc1FmeUFBUVlBQmFpQUJRWUFCYWhBQUlBQkJvQUZxSUFGQm9BRnFFQkFnQVVHQUFXcEJrSWtFSUFGQmdBRnFFSDhnQUVIQUFXb2dBVUhBQVdvUUFDQUFRZUFCYWlBQlFlQUJhaEFRSUFGQndBRnFRZENKQkNBQlFjQUJhaEIvSUFCQmdBSnFJQUZCZ0FKcUVBQWdBRUdnQW1vZ0FVR2dBbW9RRUNBQlFZQUNha0dRaWdRZ0FVR0FBbW9RZnlBQVFjQUNhaUFCUWNBQ2FoQUFJQUJCNEFKcUlBRkI0QUpxRUJBZ0FVSEFBbXBCMElvRUlBRkJ3QUpxRUg4TFpBQWdBRUdRaXdRZ0FSQi9JQUJCUUd0QjBJc0VJQUZCUUdzUWZ5QUFRWUFCYWtHUWpBUWdBVUdBQVdvUWZ5QUFRY0FCYWtIUWpBUWdBVUhBQVdvUWZ5QUFRWUFDYWtHUWpRUWdBVUdBQW1vUWZ5QUFRY0FDYWtIUWpRUWdBVUhBQW1vUWZ3dUFBZ0FnQUNBQkVBQWdBRUVnYWlBQlFTQnFFQkFnQVVHUWpnUWdBUkIvSUFCQlFHc2dBVUZBYXhBQUlBQkI0QUJxSUFGQjRBQnFFQkFnQVVGQWEwSFFqZ1FnQVVGQWF4Qi9JQUJCZ0FGcUlBRkJnQUZxRUFBZ0FFR2dBV29nQVVHZ0FXb1FFQ0FCUVlBQmFrR1Fqd1FnQVVHQUFXb1FmeUFBUWNBQmFpQUJRY0FCYWhBQUlBQkI0QUZxSUFGQjRBRnFFQkFnQVVIQUFXcEIwSThFSUFGQndBRnFFSDhnQUVHQUFtb2dBVUdBQW1vUUFDQUFRYUFDYWlBQlFhQUNhaEFRSUFGQmdBSnFRWkNRQkNBQlFZQUNhaEIvSUFCQndBSnFJQUZCd0FKcUVBQWdBRUhnQW1vZ0FVSGdBbW9RRUNBQlFjQUNha0hRa0FRZ0FVSEFBbW9RZnd0a0FDQUFRWkNSQkNBQkVIOGdBRUZBYTBIUWtRUWdBVUZBYXhCL0lBQkJnQUZxUVpDU0JDQUJRWUFCYWhCL0lBQkJ3QUZxUWRDU0JDQUJRY0FCYWhCL0lBQkJnQUpxUVpDVEJDQUJRWUFDYWhCL0lBQkJ3QUpxUWRDVEJDQUJRY0FDYWhCL0M0QUNBQ0FBSUFFUUFDQUFRU0JxSUFGQklHb1FFQ0FCUVpDVUJDQUJFSDhnQUVGQWF5QUJRVUJyRUFBZ0FFSGdBR29nQVVIZ0FHb1FFQ0FCUVVCclFkQ1VCQ0FCUVVCckVIOGdBRUdBQVdvZ0FVR0FBV29RQUNBQVFhQUJhaUFCUWFBQmFoQVFJQUZCZ0FGcVFaQ1ZCQ0FCUVlBQmFoQi9JQUJCd0FGcUlBRkJ3QUZxRUFBZ0FFSGdBV29nQVVIZ0FXb1FFQ0FCUWNBQmFrSFFsUVFnQVVIQUFXb1FmeUFBUVlBQ2FpQUJRWUFDYWhBQUlBQkJvQUpxSUFGQm9BSnFFQkFnQVVHQUFtcEJrSllFSUFGQmdBSnFFSDhnQUVIQUFtb2dBVUhBQW1vUUFDQUFRZUFDYWlBQlFlQUNhaEFRSUFGQndBSnFRZENXQkNBQlFjQUNhaEIvQzJRQUlBQkJrSmNFSUFFUWZ5QUFRVUJyUWRDWEJDQUJRVUJyRUg4Z0FFR0FBV3BCa0pnRUlBRkJnQUZxRUg4Z0FFSEFBV3BCMEpnRUlBRkJ3QUZxRUg4Z0FFR0FBbXBCa0prRUlBRkJnQUpxRUg4Z0FFSEFBbXBCMEprRUlBRkJ3QUpxRUg4TGdBSUFJQUFnQVJBQUlBQkJJR29nQVVFZ2FoQVFJQUZCa0pvRUlBRVFmeUFBUVVCcklBRkJRR3NRQUNBQVFlQUFhaUFCUWVBQWFoQVFJQUZCUUd0QjBKb0VJQUZCUUdzUWZ5QUFRWUFCYWlBQlFZQUJhaEFBSUFCQm9BRnFJQUZCb0FGcUVCQWdBVUdBQVdwQmtKc0VJQUZCZ0FGcUVIOGdBRUhBQVdvZ0FVSEFBV29RQUNBQVFlQUJhaUFCUWVBQmFoQVFJQUZCd0FGcVFkQ2JCQ0FCUWNBQmFoQi9JQUJCZ0FKcUlBRkJnQUpxRUFBZ0FFR2dBbW9nQVVHZ0Ftb1FFQ0FCUVlBQ2FrR1FuQVFnQVVHQUFtb1FmeUFBUWNBQ2FpQUJRY0FDYWhBQUlBQkI0QUpxSUFGQjRBSnFFQkFnQVVIQUFtcEIwSndFSUFGQndBSnFFSDhMWkFBZ0FFR1FuUVFnQVJCL0lBQkJRR3RCMEowRUlBRkJRR3NRZnlBQVFZQUJha0dRbmdRZ0FVR0FBV29RZnlBQVFjQUJha0hRbmdRZ0FVSEFBV29RZnlBQVFZQUNha0dRbndRZ0FVR0FBbW9RZnlBQVFjQUNha0hRbndRZ0FVSEFBbW9RZnd1QUFnQWdBQ0FCRUFBZ0FFRWdhaUFCUVNCcUVCQWdBVUdRb0FRZ0FSQi9JQUJCUUdzZ0FVRkFheEFBSUFCQjRBQnFJQUZCNEFCcUVCQWdBVUZBYTBIUW9BUWdBVUZBYXhCL0lBQkJnQUZxSUFGQmdBRnFFQUFnQUVHZ0FXb2dBVUdnQVdvUUVDQUJRWUFCYWtHUW9RUWdBVUdBQVdvUWZ5QUFRY0FCYWlBQlFjQUJhaEFBSUFCQjRBRnFJQUZCNEFGcUVCQWdBVUhBQVdwQjBLRUVJQUZCd0FGcUVIOGdBRUdBQW1vZ0FVR0FBbW9RQUNBQVFhQUNhaUFCUWFBQ2FoQVFJQUZCZ0FKcVFaQ2lCQ0FCUVlBQ2FoQi9JQUJCd0FKcUlBRkJ3QUpxRUFBZ0FFSGdBbW9nQVVIZ0Ftb1FFQ0FCUWNBQ2FrSFFvZ1FnQVVIQUFtb1Fmd3NRQUNBQVFaQ2pCRUhnQWlBQkVQMEJDKzBGQUNBQUlBQkJnQUpxUWZDMEJCQi9JQUJCZ0FKcVFjaUJBa0h3c1FRUWZ5QUFRZkN4QkVId3NRUVFnZ0VnQUNBQVFZQUNha0d3dFFRUWdnRkJzTFVFUWZDeEJFSHdzUVFRZjBISWdRSkI4TFFFUWJDMUJCQi9RZkMwQkVHd3RRUkJzTFVFRUlJQlFmQ3hCRUd3dFFSQjhMRUVFSU1CUWZDMEJFSHd0QVJCc0xJRUVJSUJJQUJCd0FGcUlBQkJnQUZxUWZDMEJCQi9JQUJCZ0FGcVFjaUJBa0h3c2dRUWZ5QUFRY0FCYWtId3NnUkI4TElFRUlJQklBQkJ3QUZxSUFCQmdBRnFRYkMxQkJDQ0FVR3d0UVJCOExJRVFmQ3lCQkIvUWNpQkFrSHd0QVJCc0xVRUVIOUI4TFFFUWJDMUJFR3d0UVFRZ2dGQjhMSUVRYkMxQkVId3NnUVFnd0ZCOExRRVFmQzBCRUd3c3dRUWdnRWdBRUZBYXlBQVFjQUNha0h3dEFRUWZ5QUFRY0FDYWtISWdRSkI4TE1FRUg4Z0FFRkFhMEh3c3dSQjhMTUVFSUlCSUFCQlFHc2dBRUhBQW1wQnNMVUVFSUlCUWJDMUJFSHdzd1JCOExNRUVIOUJ5SUVDUWZDMEJFR3d0UVFRZjBId3RBUkJzTFVFUWJDMUJCQ0NBVUh3c3dSQnNMVUVRZkN6QkJDREFVSHd0QVJCOExRRVFiQzBCQkNDQVVId3NRUWdBQ0FCRUlNQklBRWdBU0FCRUlJQlFmQ3hCQ0FCSUFFUWdnRkJzTElFSUFCQmdBSnFJQUZCZ0FKcUVJSUJJQUZCZ0FKcUlBRkJnQUpxSUFGQmdBSnFFSUlCUWJDeUJDQUJRWUFDYWlBQlFZQUNhaENDQVVHd3RBUkJ5SUVDUWJDMUJCQi9RYkMxQkNBQVFjQUJhaUFCUWNBQmFoQ0NBU0FCUWNBQmFpQUJRY0FCYWlBQlFjQUJhaENDQVVHd3RRUWdBVUhBQVdvZ0FVSEFBV29RZ2dGQjhMTUVJQUJCZ0FGcUlBRkJnQUZxRUlNQklBRkJnQUZxSUFGQmdBRnFJQUZCZ0FGcUVJSUJRZkN6QkNBQlFZQUJhaUFCUVlBQmFoQ0NBVUh3c2dRZ0FFRkFheUFCUVVCckVJTUJJQUZCUUdzZ0FVRkFheUFCUVVCckVJSUJRZkN5QkNBQlFVQnJJQUZCUUdzUWdnRkJzTE1FSUFCQndBSnFJQUZCd0FKcUVJSUJJQUZCd0FKcUlBRkJ3QUpxSUFGQndBSnFFSUlCUWJDekJDQUJRY0FDYWlBQlFjQUNhaENDQVF1QUFRRUNmeUFBUWJDMkJCRDBBU0FCRU93QlFhNjJCQ3dBQUNJREJFQWdBMEVCUmdSQUlBRWdBQ0FCRU80QkJTQUJRYkMyQkNBQkVPNEJDd3RCUFNFQ0EwQWdBU0FCRUpJQ0lBSXNBUEMxQkNJREJFQWdBMEVCUmdSQUlBRWdBQ0FCRU80QkJTQUJRYkMyQkNBQkVPNEJDd3NnQWdSQUlBSkJBV3NoQWd3QkN3c0xnd01BSUFCQjhLVUVFTnNCSUFCQndBRnFRYkNuQkJEZ0FTQUFRZkNvQkJENEFVSHdwUVJCOEtnRVFmQ3JCQkR1QVVId3F3UkI4SzRFRUlrQ1FmQ3JCRUh3cmdSQnNQZ0VFTzRCUWJENEJFR3d1UVFRa3dKQnNMa0VRYkM1QkJEMEFVR3d1UVJCc0x3RUVKSUNRYkM4QkVHd3Z3UVFrZ0pCc0w4RVFiQzhCRUd3d2dRUTdnRkJzTUlFUWJERkJCQ1RBa0d3eFFSQnNNVUVFUFFCUWJERkJFR3d5QVFRa2dKQnNNZ0VRYkRMQkJDVEFrR3d5d1JCc01zRUVQUUJRYkRDQkVHd3pnUVE5QUZCc01zRVFiRFJCQkQwQVVHdzBRUkJzTVVFUWJEVUJCRHVBVUd3MUFSQnNNNEVRYkRYQkJEdUFVR3cxd1JCc0x3RVFiRGFCQkR1QVVHdzF3UkJzTVVFUWJEZEJCRHVBVUd3M1FSQnNQZ0VRYkRnQkJEdUFVR3cyZ1JCc09NRUVJZ0NRYkRqQkVHdzRBUkJzT1lFRU80QlFiRFhCRUd3NlFRUWlRSkJzT2tFUWJEbUJFR3c3QVFRN2dGQnNQZ0VRYkR2QkJEMEFVR3c3d1JCc05vRVFiRHlCQkR1QVVHdzhnUkJzUFVFRUlvQ1FiRDFCRUd3N0FRZ0FSRHVBUXRNQUVHdyt3UVE3QUVnQUVIUTBBSVFXU0FCUVpEU0FoQ0RBa0hRMEFKQmtOSUNRYkQrQkJDR0FrR3crd1JCc1A0RVFiRDdCQkR1QVVHdyt3UkJzUHNFRUpRQ1FiRDdCQ0FDRVBjQkMzc0FRYkNCQlJEc0FTQUFRZERRQWhCWklBRkJrTklDRUlNQ1FkRFFBa0dRMGdKQnNJUUZFSVlDUWJDQkJVR3doQVZCc0lFRkVPNEJJQUpCME5BQ0VGa2dBMEdRMGdJUWd3SkIwTkFDUVpEU0FrR3doQVVRaGdKQnNJRUZRYkNFQlVHd2dRVVE3Z0ZCc0lFRlFiQ0JCUkNVQWtHd2dRVWdCQkQzQVF1cUFRQkJzSWNGRU93QklBQkIwTkFDRUZrZ0FVR1EwZ0lRZ3dKQjBOQUNRWkRTQWtHd2lnVVFoZ0pCc0ljRlFiQ0tCVUd3aHdVUTdnRWdBa0hRMEFJUVdTQURRWkRTQWhDREFrSFEwQUpCa05JQ1FiQ0tCUkNHQWtHd2h3VkJzSW9GUWJDSEJSRHVBU0FFUWREUUFoQlpJQVZCa05JQ0VJTUNRZERRQWtHUTBnSkJzSW9GRUlZQ1FiQ0hCVUd3aWdWQnNJY0ZFTzRCUWJDSEJVR3dod1VRbEFKQnNJY0ZJQVlROXdFTDJRRUFRYkNOQlJEc0FTQUFRZERRQWhCWklBRkJrTklDRUlNQ1FkRFFBa0dRMGdKQnNKQUZFSVlDUWJDTkJVR3drQVZCc0kwRkVPNEJJQUpCME5BQ0VGa2dBMEdRMGdJUWd3SkIwTkFDUVpEU0FrR3drQVVRaGdKQnNJMEZRYkNRQlVHd2pRVVE3Z0VnQkVIUTBBSVFXU0FGUVpEU0FoQ0RBa0hRMEFKQmtOSUNRYkNRQlJDR0FrR3dqUVZCc0pBRlFiQ05CUkR1QVNBR1FkRFFBaEJaSUFkQmtOSUNFSU1DUWREUUFrR1EwZ0pCc0pBRkVJWUNRYkNOQlVHd2tBVkJzSTBGRU80QlFiQ05CVUd3alFVUWxBSkJzSTBGSUFnUTl3RUxpQUlBUWJDVEJSRHNBU0FBUWREUUFoQlpJQUZCa05JQ0VJTUNRZERRQWtHUTBnSkJzSllGRUlZQ1FiQ1RCVUd3bGdWQnNKTUZFTzRCSUFKQjBOQUNFRmtnQTBHUTBnSVFnd0pCME5BQ1FaRFNBa0d3bGdVUWhnSkJzSk1GUWJDV0JVR3drd1VRN2dFZ0JFSFEwQUlRV1NBRlFaRFNBaENEQWtIUTBBSkJrTklDUWJDV0JSQ0dBa0d3a3dWQnNKWUZRYkNUQlJEdUFTQUdRZERRQWhCWklBZEJrTklDRUlNQ1FkRFFBa0dRMGdKQnNKWUZFSVlDUWJDVEJVR3dsZ1ZCc0pNRkVPNEJJQWhCME5BQ0VGa2dDVUdRMGdJUWd3SkIwTkFDUVpEU0FrR3dsZ1VRaGdKQnNKTUZRYkNXQlVHd2t3VVE3Z0ZCc0pNRlFiQ1RCUkNVQWtHd2t3VWdDaEQzQVFzckFDQUFRZERRQWhCWklBRkJrTklDRUlNQ1FkRFFBa0dRMGdKQnNKa0ZFSVlDUWJDWkJTQUNFSlFDQ3d1SW13RjRBRUVBQ3dRd1RnRUFBRUVJQ3lBQkFBRHdrL1hoUTVGd3VYbEk2RE1vWFZpQmdiWkZVTGdwb0RIaGNrNWtNQUJCNkFNTElFZjlmTmdXakNBOGpjcHhhSkZxZ1pkZFdJR0J0a1ZRdUNtZ01lRnlUbVF3QUVHSUJBc2dpZnFLVTF2OExQUDdBVVhVRVJubnRmWi9RUXIvSHF0SEh6VzR5bkdmMkFZQVFhZ0VDeUNkRFkvRmpVTmQwejBMeC9VbzYzZ0tMRVo1ZUcramJtWXYzd2Vhd1hjS0RnQkJ5QVFMSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhvQkFzZ28zNCtiQXRHRUo1RzVUaTBTTFhBeXk2c3dFRGJJaWpjRk5DWWNEa25NaGdBUVlnRkN5Q2tmajVzQzBZUW5rYmxPTFJJdGNETExxekFRTnNpS053VTBKaHdPU2N5R0FCQnFBVUxJS04rUG13TFJoQ2VSdVU0dEVpMXdNc3VyTUJBMnlJbzNCVFFtSEE1SnpJWUFFSElCUXNncXUvdEVvbEl3MmhQdjZweWFIOElqVEVTQ0FsSG91RlIrc0FwUjdIV1dTSUFRZWdGQ3lCU1B4KzJCU01JVDZOeUhGcWtXdUJsRjFaZ29HMFJGRzRLYUV5NG5CTVpEQUJCNkEwTElBRUFBUENUOWVGRGtYQzVlVWpvTXloZFdJR0J0a1ZRdUNtZ01lRnlUbVF3QUVHSURnc2dwMjBocmtYbXVCdmpXVnpqc1RyK1U0V0F1MU05ZzBtTXBVUk9mN0hRRmdJQVFhZ09DeUQ3Ly85UEhEU1dyQ25OWUorVmR2dzJMa1o1ZUcramJtWXYzd2Vhd1hjS0RnQkJ5QTRMSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhvRGdzZ0FBQUErTW42OEtGSXVOdzhKUFFabEM2c3dFRGJJaWpjRk5DWWNEa25NaGdBUVlnUEN5QUJBQUQ0eWZyd29VaTQzRHdrOUJtVUxxekFRTnNpS053VTBKaHdPU2N5R0FCQnFBOExJRDlaSHo0VUNaZWJoNFErZzlLRkZSaG9Xd1NGbXdJYUV5N25SQVlEQUFBQUFFSElEd3NnbkQzUmdGVnpibVBXLzBVa2RQTXJvdGdEc2g3QUtrVlc1L2xqS1pUdllCZ0FRZWdQQ3lDZ3JBOGZpb1RMelVOQ24wSHB3Z29NdEMyQ3drMEJqUW1YY3lLREFRQUFBQUJCaUJnTElOY29yVkNweWhkNnVTRlY0WHJCYWgrRTBtdHBUdXBMTTQ2ZEY4NUVaeDhxQUVHb01Rc2dFUkVSRVJFUkVSRVJFUkFRRHc0TkRRd0xDZ2tJQndjR0JRUURBZ0VCQVFFQVFZZ3pDeUFSRVJFUkVSRVJFUkVSRUJBUERnME5EQXNLQ1FnSEJ3WUZCQU1DQVFFQkFRQkJ5RFFMb0FmNy8vOVBIRFNXckNuTllKK1ZkdncyTGtaNWVHK2pibVl2M3dlYXdYY0tEZ1lBQUtCM3dVdVhaNk5ZMnJKeE4vRXVFZ2dKUjZMaFVmckFLVWV4MWxraWkrL2NucGM5ZFg4Z2tVZXhMQmMvWDI1c0NYUjVZckdOendqQk9UVjdOeXMvZksyMTRrcXQrTDZGeTRQL3htQXQ5eW1VWFN2OWR0bXAyWm8vNTN4QUpBT1BMM1I4ZmJiMHpHalFZOXd0RzJocVYvc2I3N3psalA0OHR0SlJLWHdXWkV4WHY3SDNGQ0x5ZlRIM0x5UDVLTTExcmJDb2hIWGxBMjBYM0ZuN2dTdS9ZWStCNVFPUWpzTCsrSnMwdjV1TVRsTUJQODN1M0ZNOHFpbmxhNWFRSnJGN2dTWXd4SGtLOEgxVG1Yek1zbnZlNWtFQzFTZkt0a3p3TWpZL3Mzb0F6RXFpZ3orNHI2SnVVMTFTMlZYeWtobmRoZ0lJWm5WZVNTVXR4YWF4ZXhqZUk2UWk1enRUbkExdTMzd1NuU3BrQmNDYVFFWjF2QTJDVUQyeWpVendBSVFSRENpMHMvUWVMQ3BlcnNMVWVzOFlaYVBGYkRzR3VJekEzMlc1eEVnanNzOVByb2toNTBnSFd2aU5QUHNEQ2dvdW0rbzFpazMvZHgyY3pTNk1xU2pUMit5ekwxTFVIYTN6VmRDVEtpSm82RlhWczJaOW5MNUcrSlJodVBhU0c5Wk9vSG0rM0V5Smh3ZlRSR3JlYkpWZndkdlhLN2FoV1U1dmdKb1E1T3NTdU9vRlRjZWdFN29XTWFzUlkxMEJMbHFncFl3c2tnTzEycFRqL3RjVnZnWlV1UDFiQmZkT2dQTHF6a0J4YTZkNnk0bitzbWhheWZ6SEJzVHhOUnhHSFROME9UbFo1N05IMFNRY0RaSTZPbTFEWC9kMFVSSTBvVmJWYXU0Qkg0SWJmTndFRXRpNEJkcEJqVEFHNWlveVNDeUpub1FuampVMWt0VXQxdnZLRHdTRUMzQUpMOFptSldDR3Y2QjJPaGd6OFZoUVYxbVBPZGswemRFNXppNXRCVFo2b3VhM281NEV2TnMrQlFQbTYrL1VuczQ2V3JRa2hGNTVpS2FRZzN3b0dwT05xbVhVTXRxY2o0QmhoZlpwSm9Xd3lPUkdxM3NrR2dMV2dZZG1PdzA4THpMMWtpSHFKNmZwajJYcGhCaXhhY0JUb0x3amhqcW1PZUVsOFBPUEV2SWE3N3h1SW82YllHdEEzNnZ4Ulo0OXU2ZlZWOUtOVTd5amduZ0RremdLQUpHZXdBUWtTRzZ5SlFCWng1RjFEUkcrWGpwNUp3S2txRXlwd2NPbVpBRXcwRS9ZYWIwaXh5d1dVczhtU2c1ZzZhZnpSZGQrY3Z0Y0ovdHBzcWRTRnVJSFhGZi8rZzVBeFpxUFMwbHpJMVUzcmVlQjdhdDVxamt1VFFpNDVjWWEvaUNLeVNLVW9xQ2RYSk5seW1MVWMvZUNSZFJ1U3JyaHRvSTZETUFVL0NobkFvbUFGR1JaaDBrRHdPUzFlRHBLZnJHbVV0MVBBRWtTNnVabDNSZEZLSnc5MFlCVmMyNWoxdjlGSkhUeks2TFlBN0lld0NwRlZ1ZjVZeW1VNzJBWUFFSG9Pd3VnQi92Ly8wOGNOSmFzS2MxZ241VjIvRFl1Um5sNGI2TnVaaS9mQjVyQmR3b08vdi8vSDlnVVBIamRIbzBNYnkrWXIwVlAvZnlTZEYrUHJMK2NQUnBqTngvLy8vOFBiQW9ldkc2UFJvYTNGOHpYb3FkK2ZrbTZyMGZXWDg0ZWpiR2JEd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQVFZakRBQXVnQjN6Ly96KzRYMzMvR1BWaFBLRTZQRVgzYjA0NTVRMmM5bnhxYWVMRGpFY01GdlAvbjRhWDhsc0pURGdMREVpcTBmYmNvSThidVZ2RE9hVWgxVy9vb2hEZ2QrRC9BYVpndkdxSmJhUFJ1RlZGdHBpYlpibWwxTjhsZjZnWC8rVGZLWCtUWFI1NDl2cDY2KzB0MjdHTDc3U2lNTlF3VUp3L3UzcVEzMUp6eVdrQzVmMEFPaFNRaDh5RGk3QnlhcXd0K3paazZnbit1VVk2MjU1ZHAxbGh2UlFDa0x5dlZnYmQ5U1hQQkNNcG5PVWZmMlpqMUVEYVhvbkxqUzRLMUFhSExnL1liOWVNZVQyR0VPWWw2dXpLU3I5VkR0aENZRkJvc1ZObnlWYkxCMHdnNzFNWEhTdXZyUUQxRjhYZnBXTkV6UjY4TTB2aWtGMi83eHBocCszYzV5RlZCUC9NMGxEWHIyTDdwemZRKzNERUlDNFI5NklZdlM3V01XV1h2UWFGRzN2aUxxYjMzVm9zeDFYbEwrdWs5M1ovN2ZMVHdtZUV1M2lFaERFTHpMRUo5WGlDeXhzWlp2TVVuZ2x6MkRWVHZOd0YyWGRhZ29QSmE0VmkzN0pzU1FLTHgrMURnQVRGNTZTMTNDQ1VCVDJ2WHE4bnlGVHdsVm5oWU5yTk5zOG5EaHhBbFArSldQZmVGN3M4dVJGZnVrRW01Q0ZJOUZXOThzUWJOY3Q0aFAwcTkxTmNTY0xjWDlOY1pmMUZPM3p5ckp1TFFjbkNQd0ZwOUlXb0xRaHFrUVRpTjl2THlvYVg4U3RiUVNSNzM1czNNVVl4S005YlpWb1kyaGFUbjBBcUhQbXVEZGV6dmZLVW1rWHloQ3huOFBZSkxLc2tOTFFPZTJWMWl6Zm14L3NoODh6SGJoWjdUMi9hYW5nQUU2Mzl2S1ZIc3FiWXltNTR0UFIvejNLUUVEQzA0SjdUQXIxNUE0alFlSlhlTWZmTGZoSTdTVGJ0dnJWanBQUkQ0V2FJS1FtQ1h1TWhGSTlZTEJoSXNzdnlROWdLbHZOTTR4Ynd1K1BEc0YrdjhkNFBDUkxhaHFhekRWSXVTZ2RHWExZVHZ6a0pRYzRPTUxxTzZBeXlkbHhSZUN4anFjZ1ZUaFg3SFA5N09rL0NXbStnWS9UQXJKWmtMMHU2ZHhTSzRwaVVKblp1VXpEcm9MOVBwK1dGREdIWE4vc0xGWGNqOERWR2R4bWdiV3M3cWpVT1lpc2hNR1FEbktpand4aDRyeUwwS085WXF2blp4cGc1eXFzNU5xbWczeXQzVW9CYmhYdEU1MFhNeU05MHBvYmhuSTNjUUJEbmN3SjZhajhyeWdFMkNTeUZ5QjFjcDE0MW5Xd2Q4K3k0VXY0ZExpUU11eFBSc3Vrbk9maXhXYVVEZC8vemVrYmcrbmUxMmtGcFQxd3FQdFFjeWhPeFNzbldMUXZwbVBXUFFSZitnNnQ4WjVHVVU4MURRY0NyaEU3K01IWUZkQ01WSUJPN0VPMkRtamVEQUdEZUR0M1BLaE94UWtRbEFkVXJTN3N4ZWlTNkdabFZzNHdHc2NqaTMzb2F4RENhaUdhL1dHUnZsM1ZieWIrbmtCL3dnaDZVd3d0Sk9vMmt3MVJYR3lRQVFhaktBQXVnQjFaVlZmVzNvNWFDQzBzbVVURHdkOFhvT2xaV0pObUtKWEVWSVpaTU5KZ1ZsMi81SnNKbzNnNVpaVVo1Mm1IVHVGYzl5R1dCZnZzZTA0Q3l5b3lmMUFCUUQ3b29BVmdDMkNhSHVlL0lZZVNlWGM4dFcwZ1A2bmVqaXg2Zk9yeEdLTTYzNVFmTEwrYkJMUlppZDJHSnUyYnVJK2hlNThJZFRFandIejBTS044Q3RmTE9idjh4YTBiVXhGNGtsYzF2RTA5dWs2VHMxWjBYTjBaTW1wY1FzaG9PZmZsQW1RakpKOFp0RVgrc3FRMmJud3BHQlRXTmxzNUVuUjdsUy95dEFUOGxJNSsxVkIrdUlxV241YWpNRlhFYkkxUC9rOEZhWUJuM2RqTlRVcEFCdEg4YWtLME1VRzZ1TUJXRDhuaWM5YU5WR3Q4MHVtMVE4SnhPMmFoM1N5MDhmLzNwQzdVN2ZqRjhUUWFUYnhiOXg1VmwvRnQ1UDdUSXNuSW9ZOXRKS0ZRSG1WbHZoN2dRZDIvdFlucnFpVkhQTUxDT0o2S0RxWUExeHpLaVh2NFl6Q2RMSmVvenlYdy9vdy9VaEtGYWJaeFFCNTI5VGhRRmhhdytnQTBBQ3gzRzVmcCt3dlM1L0RRVXpmMVpWT0paQkkyK0o4Q1dpYWI5cTh2RU1xek1HcThVWmxqQy94cENQbEF1bkxZTkFYVUR3QWlNT3hRMlM3Z244ZjZvRE5ZWGlTMWpuVGNJU2JKNnJ4SGZjMnRTR3Bxb1hBTTZOTEhjN25KN2FLRkpzUU56Kzhjam5zZTNqWEFObnY0c284MkxDUnVaZW1YVmtEeUlzY2RBMXZnQUJKRG5lQUhLM3o1ekJzd1g3K0N3Q3c3TTQvYlB2YzJpZTJvUndIWjlkVzh0YVh3bnZ6VVREYStjRWYvNkpQSXgrWDlRMHROSzBLeGlyNTFwUmZFQm13Rm9pYTRlSFQyUmNRTUVHUGNoTHhZREtDSWhDS0s5K002YkxRYSs0TFJDRUczSlQ3OS9OWnEvVU1BbVFuNzJJODRvbVo0QjJnZmpEYXVZSDlQYUdrY0R6U055dVlhSjlIUmtKeVpqZnZlQ3BENnN2RG1uZ2Mzc0h0bVhhVTErTVREYWdBeWUwMTdoRmFjdG1PZUphT3gyNFB0TTdValNTMUZERUdDTFZFU2tCKzVxWHp5NjFuZkRHYUlMZDZYNHZzcTRpYzIwbjJQd2ZaNkF5aHpQRWtVRmZ2WWRiaEIvUmRPeWZ4Tlc4V2F4dG9iTGk0OWFNME1waEw0TTYwa3BkaG8wQWVQRVNPMmdkeEoyRkNzbWdyT1VVY0hIQnQyWWs4ZnpxeHN2cG53M0hOYllIUUZOSUN0TUp1TlIrTXB3cjFOd0ppcWZTai85KytFUER5Q0VOL0VNcDVLcm9kYkY3YmNkdFFIK3B6WTVpbU5Hd29UMnlOMXRMektMQ21WSFN4S2Y4Vk9hc1pTYkE1K3lFYi80VmZzTzdQKzhkV2ZFRTdNS2VaV3JaZlA5S2RQci9pR1JzQktSTlkxMnFlV2szVlI4ZVdpVFVXdHQ0WEQvSDRGYkNpTWYxZTJDbjlHd1pwNVF3YVowRHpJTTdRazFzZFhUcldRWVlwd2VHK00rWnhVQVFjalJBQXVBQWdDQVFNQWdvR0RnRUpCUTBEQ3djUEFJaUVqSUtLaG82QmlZV05nNHVIajRCSVJFeENTa1pPUVVsRlRVTkxSMDlBeU1UTXdzckd6c0hKeGMzRHk4ZlB3Q2drTENJcUppNGhLU1V0SXlzbkx5Q29wS3lpcXFhdW9hbWxyYU9ycDYrZ2FHUnNZbXBtYm1GcFpXMWphMmR2WU9qazdPTHE1dTdoNmVYdDQrdm43K0FZRkJ3U0doWWVFUmtWSFJNYkZ4OFFtSlNja3BxV25wR1psWjJUbTVlZmtGaFVYRkphVmw1UldWVmRVMXRYWDFEWTFOelMydGJlMGRuVjNkUGIxOS9RT0RROE1qbzJQakU1TlQwek96Yy9NTGkwdkxLNnRyNnh1Ylc5czd1M3Y3QjRkSHh5ZW5aK2NYbDFmWE43ZDM5dytQVDg4dnIyL3ZINTlmM3orL2YvOEFRWWpkQUFzZ1VUOGZ0Z1VqQ0UramNoeGFwRnJnWlJkV1lLQnRFUlJ1Q21oTXVKd1RHUXdBUWFqZEFBc2dvMzQrYkF0R0VKNUc1VGkwU0xYQXl5NnN3RURiSWlqY0ZOQ1ljRGtuTWhnQVFjamdBQXNnVVQ4ZnRnVWpDRStqY2h4YXBGcmdaUmRXWUtCdEVSUnVDbWhNdUp3VEdRd0FRZWppQUF0QXFBSzRkK000K1R0ZFV6TTJKeHNMQW1CU2RVbnc3YmNtYmFpRVF6TEdGQ1ZuLzl6UnpPem5PRDROenBOOXMvQmxxZ0NzSXQzUVNkZE5qV2hLenJsQkFRQkJxSlVCQ3lBUkVSRVJFUkVSRVJFUkVCQVBEZzBOREFzS0NRZ0hCd1lGQkFNQ0FRRUJBUUJCeUpnQkN5QVJFUkVSRVJFUkVSRVJFQkFQRGcwTkRBc0tDUWdIQndZRkJBTUNBUUVCQVFCQnlKc0JDNkFIKy8vL1R4dzBscXdweldDZmxYYjhOaTVHZVhodm8yNW1MOThIbXNGM0NnNEdBQUNnZDhGTGwyZWpXTnF5Y1RmeExoSUlDVWVpNFZINndDbEhzZFpaSW92djNKNlhQWFYvSUpGSHNTd1hQMTl1YkFsMGVXS3hqYzhJd1RrMWV6Y3JQM3l0dGVKS3JmaStoY3VELzhaZ0xmY3BsRjByL1hiWnFkbWFQK2Q4UUNRRGp5OTBmSDIyOU14bzBHUGNMUnRvYWxmN0crKzg1WXorUExiU1VTbDhGbVJNVjcreDl4UWk4bjB4OXk4aitTak5kYTJ3cUlSMTVRTnRGOXhaKzRFcnYyR1BnZVVEa0k3Qy92aWJOTCtiakU1VEFUL043dHhUUEtvcDVXdVdrQ2F4ZTRFbU1NUjVDdkI5VTVsOHpMSjczdVpCQXRVbnlyWk04REkyUDdONkFNeEtvb00vdUsraWJsTmRVdGxWOHBJWjNZWUNDR1oxWGtrbExjV21zWHNZM2lPa0l1YzdVNXdOYnQ5OEVwMHFaQVhBbWtCR2Rid05nbEE5c28xTThBQ0VFUXdvdExQMEhpd3FYcTdDMUhyUEdHV2p4V3c3QnJpTXdOOWx1Y1JJSTdMUFQ2NkpJZWRJQjFyNGpUejdBd29LTHB2cU5ZcE4vM2Nkbk0wdWpLa28wOXZzc3k5UzFCMnQ4MVhRa3lvaWFPaFYxYk5tZlp5K1J2aVVZYmoya2h2V1RxQjV2dHhNaVljSDAwUnEzbXlWWDhIYjF5dTJvVmxPYjRDYUVPVHJFcmpxQlUzSG9CTzZGakdyRVdOZEFTNWFvS1dNTEpJRHRkcVU0LzdYRmI0R1ZMajlXd1gzVG9EeTZzNUFjV3VuZXN1Si9ySm9Xc244eHdiRThUVWNSaDB6ZERrNVdlZXpSOUVrSEEyU09qcHRRMS8zZEZFU05LRlcxV3J1QVIrQ0czemNCQkxZdUFYYVFZMHdCdVlxTWtnc2laNkVKNDQxTlpMVkxkYjd5ZzhFaEF0d0NTL0daaVZnaHIrZ2Rqb1lNL0ZZVUZkWmp6blpOTTNST2M0dWJRVTJlcUxtdDZPZUJMemJQZ1VENXV2djFKN09PbHEwSklSZWVZaW1rSU44S0JxVGphcGwxRExhbkkrQVlZWDJhU2FGc01qa1JxdDdKQm9DMW9HSFpqc05QQzh5OVpJaDZpZW42WTlsNllRWXNXbkFVNkM4STRZNnBqbmhKZkR6anhMeUd1KzhiaUtPbTJCclFOK3I4VVdlUGJ1bjFWZlNqVk84bzRKNEE1TTRDZ0NSbnNBRUpFaHVzaVVBV2NlUmRRMFJ2bDQ2ZVNjQ3BLaE1xY0hEcG1RQk1OQlAyR205SXNjc0ZsTFBKa29PWU9tbjgwWFhmbkw3WENmN2FiS25VaGJpQjF4WC8vb09RTVdhajB0SmN5TlZONjNuZ2UycmVhbzVMazBJdU9YR0d2NGdpc2tpbEtLZ25WeVRaY3BpMUhQM2drWFVia3E2NGJhQ09nekFGUHdvWndLSmdCUmtXWWRKQThEa3RYZzZTbjZ4cGxMZFR3QkpFdXJtWmQwWFJTaWNQZEdBVlhOdVk5Yi9SU1IwOHl1aTJBT3lIc0FxUlZibitXTXBsTzlnR0FCQjZLSUJDNkFIKy8vL1R4dzBscXdweldDZmxYYjhOaTVHZVhodm8yNW1MOThIbXNGM0NnNysvLzhmMkJROGVOMGVqUXh2TDVpdlJVLzkvSkowWDQrc3Y1dzlHbU0zSC8vLy93OXNDaDY4Ym85R2hyY1h6TmVpcDM1K1NicXZSOVpmemg2TnNac1BBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFCQmlLb0JDNkFIZlAvL1A3aGZmZjhZOVdFOG9UbzhSZmR2VGpubERaejJmR3BwNHNPTVJ3d1c4LytmaHBmeVd3bE1PQXNNU0tyUjl0eWdqeHU1VzhNNXBTSFZiK2lpRU9CMzRQOEJwbUM4YW9sdG85RzRWVVcybUp0bHVhWFUzeVYvcUJmLzVOOHBmNU5kSG5qMitucnI3UzNic1l2dnRLSXcxREJRbkQrN2VwRGZVblBKYVFMbC9RQTZGSkNIeklPTHNISnFyQzM3Tm1UcUNmNjVSanJibmwybldXRzlGQUtRdks5V0J0MzFKYzhFSXltYzVSOS9abVBVUU5wZWljdU5MZ3JVQm9jdUQ5aHYxNHg1UFlZUTVpWHE3TXBLdjFVTzJFSmdVR2l4VTJmSlZzc0hUQ0R2VXhjZEs2K3RBUFVYeGQrbFkwVE5Icnd6UytLUVhiL3ZHbUduN2R6bklWVUUvOHpTVU5ldll2dW5OOUQ3Y01RZ0xoSDNvaGk5THRZeFpaZTlCb1ViZStJdXB2ZmRXaXpIVmVVdjY2VDNkbi90OHRQQ1o0UzdlSVNFTVF2TXNRbjFlSUxMR3hsbTh4U2VDWFBZTlZPODNBWFpkMXFDZzhscmhXTGZzbXhKQW92SDdVT0FCTVhucExYY0lKUUZQYTllcnlmSVZQQ1ZXZUZnMnMwMnp5Y09IRUNVLzRsWTk5NFh1enk1RVYrNlFTYmtJVWowVmIzeXhCczF5M2lFL1NyM1UxeEp3dHhmMDF4bC9VVTdmUEtzbTR0QnljSS9BV24waGFndENHcVJCT0kzMjh2S2hwZnhLMXRCSkh2Zm16Y3hSakVvejF0bFdoamFGcE9mUUNvYythNE4xN085OHBTYVJmS0VMR2Z3OWdrc3F5UTB0QTU3WlhXTE4rYkgreUh6ek1kdUZudFBiOXBxZUFBVHJmMjhwVWV5cHRqS2JuaTA5SC9QY3BBUU1MVGdudE1DdlhrRGlOQjRsZDR4OTh0K0VqdEpOdTIrdFdPazlFUGhab2dwQ1lKZTR5RVVqMWdzR0VpeXkvSkQyQXFXODB6akZ2Qzc0OE93WDYveDNnOEpFdHFHcHJNTlVpNUtCMFpjdGhPL09RbEJ6ZzR3dW83b0RMSjJYRkY0TEdPcHlCVk9GZnNjLzNzNlQ4SmFiNkJqOU1Dc2xtUXZTN3AzRklyaW1KUW1kbTVUTU91Z3YwK241WVVNWWRjMyt3c1ZkeVB3TlVaM0dhQnRhenVxTlE1aUt5RXdaQU9jcUtQREdIaXZJdlFvNzFpcStkbkdtRG5LcXprMnFhRGZLM2RTZ0Z1RmUwVG5SY3pJejNTbWh1R2NqZHhBRU9kekFucHFQeXZLQVRZSkxJWElIVnluWGpXZGJCM3o3TGhTL2gwdUpBeTdFOUd5NlNjNStMRlpwUU4zLy9ONlJ1RDZkN1hhUVdsUFhDbysxQnpLRTdGS3lkWXRDK21ZOVk5QkYvNkRxM3hua1pSVHpVTkJ3S3VFVHY0d2RnVjBJeFVnRTdzUTdZT2FONE1BWU40TzNjOHFFN0ZDUkNVQjFTdEx1ekY2SkxvWm1WV3pqQWF4eU9MZmVockVNSnFJWnI5WVpHK1hkVnZKdjZlUUgvQ0NIcFREQzBrNmphVERWRmNiSkFCQnFMRUJDNkFIVmxWVjliZWpsb0lMU3laUk1QQjN4ZWc2VmxZazJZb2xjUlVobGt3MG1CV1hiL2ttd21qZURsbGxSbm5hWWRPNFZ6M0laWUYrK3g3VGdMTEtqSi9VQUZBUHVpZ0JXQUxZSm9lNTc4aGg1SjVkenkxYlNBL3FkNk9MSHA4NnZFWW96cmZsQjhzdjVzRXRGbUozWVltN1p1NGo2Rjdud2gxTVNQQWZQUklvM3dLMThzNXUvekZyUnRURVhpU1Z6VzhUVDI2VHBPelZuUmMzUmt5YWx4Q3lHZzU5K1VDWkNNa254bTBSZjZ5cERadWZDa1lGTlkyV3prU2RIdVZML0swQlB5VWpuN1ZVSDY0aXBhZmxxTXdWY1JzalUvK1R3VnBnR2ZkMk0xTlNrQUcwZnhxUXJReFFicTR3RllQeWVKejFvMVVhM3pTNmJWRHduRTdacUhkTExUeC8vZWtMdFR0K01YeE5CcE52RnYzSGxXWDhXM2svdE1peWNpaGoyMGtvVkFlWldXK0h1QkIzYisxaWV1cUpVYzh3c0k0bm9vT3BnRFhITXFKZS9oak1KMHNsNmpQSmZEK2pEOVNFb1ZwdG5GQUhuYjFPRkFXRnJENkFEUUFMSGNibCtuN0M5TG44TkJUTi9WbFU0bGtFamI0bndKYUpwdjJyeThReXJNd2FyeFJtV01ML0drSStVQzZjdGcwQmRRUEFDSXc3RkRaTHVDZngvcWdNMWhlSkxXT2ROd2hKc25xdkVkOXphMUlhbXFoY0F6bzBzZHp1Y250b29VbXhBM1A3eHlPZXg3ZU5jQTJlL2l5anpZc0pHNWw2WmRXUVBJaXh4MERXK0FBRWtPZDRBY3JmUG5NR3pCZnY0TEFMRHN6ajlzKzl6YUo3YWhIQWRuMTFieTFwZkNlL05STU5yNXdSLy9vazhqSDVmMURTMDByUXJHS3ZuV2xGOFFHYkFXaUpyaDRkUFpGeEF3UVk5eUV2RmdNb0lpRUlvcjM0enBzdEJyN2d0RUlRYmNsUHYzODFtcjlRd0NaQ2Z2WWp6aWlabmdIYUIrTU5xNWdmMDlvYVJ3UE5JM0s1aG9uMGRHUW5KbU4rOTRLa1BxeThPYWVCemV3ZTJaZHBUWDR4TU5xQURKN1RYdUVWcHkyWTU0bG83SGJnKzB6dFNOSkxVVU1RWUl0VVJLUUg3bXBmUExyV2Q4TVpvZ3QzcGZpK3lyaUp6YlNmWS9COW5vREtITThTUlFWKzloMXVFSDlGMDdKL0UxYnhackcyaHN1TGoxb3pReW1Fdmd6clNTbDJHalFCNDhSSTdhQjNFbllVS3lhQ3M1UlJ3Y2NHM1ppVHgvT3JHeSttZkRjYzF0Z2RBVTBnSzB3bTQxSDR5bkN2VTNBbUtwOUtQLzM3NFE4UElJUTM4UXlua3F1aDFzWHR0eDIxQWY2bk5qbUtZMGJDaFBiSTNXMHZNb3NLWlVkTEVwL3hVNXF4bEpzRG43SVJ2L2hWK3c3cy83eDFaOFFUc3dwNWxhdGw4LzBwMCt2K0laR3dFcEUxalhhcDVhVGRWSHg1YUpOUmEyM2hjUDhmZ1ZzS0l4L1Y3WUtmMGJCbW5sREJwblFQTWd6dENUV3gxZE90WkJoaW5CNGI0ejVuRlFCQnlMZ0JDNEFDQUlCQXdDQ2dZT0FRa0ZEUU1MQnc4QWlJU01nb3FHam9HSmhZMkRpNGVQZ0VoRVRFSktSazVCU1VWTlEwdEhUMERJeE16Q3lzYk93Y25GemNQTHg4L0FLQ1FzSWlvbUxpRXBKUzBqS3ljdklLaWtyS0txcHE2aHFhV3RvNnVucjZCb1pHeGlhbVp1WVdsbGJXTnJaMjlnNk9UczR1cm03dUhwNWUzajYrZnY0QmdVSEJJYUZoNFJHUlVkRXhzWEh4Q1lsSnlTbXBhZWtabVZuWk9ibDUrUVdGUmNVbHBXWGxGWlZWMVRXMWRmVU5qVTNOTGExdDdSMmRYZDA5dlgzOUE0TkR3eU9qWStNVGsxUFRNN056OHd1TFM4c3JxMnZyRzV0YjJ6dTdlL3NIaDBmSEo2ZG41eGVYVjljM3QzZjNENDlQenkrdmIrOGZuMS9mUDc5Ly93QkJ5TVVCQzZBSCsvLy9UeHcwbHF3cHpXQ2ZsWGI4Tmk1R2VYaHZvMjVtTDk4SG1zRjNDZzRHQUFDZ2Q4RkxsMmVqV05xeWNUZnhMaElJQ1VlaTRWSDZ3Q2xIc2RaWklvdnYzSjZYUFhWL0lKRkhzU3dYUDE5dWJBbDBlV0t4amM4SXdUazFlemNyUDN5dHRlSktyZmkraGN1RC84WmdMZmNwbEYwci9YYlpxZG1hUCtkOFFDUURqeTkwZkgyMjlNeG8wR1BjTFJ0b2FsZjdHKys4NVl6K1BMYlNVU2w4Rm1STVY3K3g5eFFpOG4weDl5OGorU2pOZGEyd3FJUjE1UU50Rjl4Wis0RXJ2MkdQZ2VVRGtJN0MvdmliTkwrYmpFNVRBVC9ON3R4VFBLb3A1V3VXa0NheGU0RW1NTVI1Q3ZCOVU1bDh6TEo3M3VaQkF0VW55clpNOERJMlA3TjZBTXhLb29NL3VLK2libE5kVXRsVjhwSVozWVlDQ0daMVhra2xMY1dtc1hzWTNpT2tJdWM3VTV3TmJ0OThFcDBxWkFYQW1rQkdkYndOZ2xBOXNvMU04QUNFRVF3b3RMUDBIaXdxWHE3QzFIclBHR1dqeFd3N0JyaU13TjlsdWNSSUk3TFBUNjZKSWVkSUIxcjRqVHo3QXdvS0xwdnFOWXBOLzNjZG5NMHVqS2tvMDl2c3N5OVMxQjJ0ODFYUWt5b2lhT2hWMWJObWZaeStSdmlVWWJqMmtodldUcUI1dnR4TWlZY0gwMFJxM215Vlg4SGIxeXUyb1ZsT2I0Q2FFT1RyRXJqcUJVM0hvQk82RmpHckVXTmRBUzVhb0tXTUxKSUR0ZHFVNC83WEZiNEdWTGo5V3dYM1RvRHk2czVBY1d1bmVzdUovckpvV3NuOHh3YkU4VFVjUmgwemREazVXZWV6UjlFa0hBMlNPanB0UTEvM2RGRVNOS0ZXMVdydUFSK0NHM3pjQkJMWXVBWGFRWTB3QnVZcU1rZ3NpWjZFSjQ0MU5aTFZMZGI3eWc4RWhBdHdDUy9HWmlWZ2hyK2dkam9ZTS9GWVVGZFpqem5aTk0zUk9jNHViUVUyZXFMbXQ2T2VCTHpiUGdVRDV1dnYxSjdPT2xxMEpJUmVlWWlta0lOOEtCcVRqYXBsMURMYW5JK0FZWVgyYVNhRnNNamtScXQ3SkJvQzFvR0haanNOUEM4eTlaSWg2aWVuNlk5bDZZUVlzV25BVTZDOEk0WTZwam5oSmZEemp4THlHdSs4YmlLT20yQnJRTityOFVXZVBidW4xVmZTalZPOG80SjRBNU00Q2dDUm5zQUVKRWh1c2lVQVdjZVJkUTBSdmw0NmVTY0NwS2hNcWNIRHBtUUJNTkJQMkdtOUlzY3NGbExQSmtvT1lPbW44MFhYZm5MN1hDZjdhYktuVWhiaUIxeFgvL29PUU1XYWowdEpjeU5WTjYzbmdlMnJlYW81TGswSXVPWEdHdjRnaXNraWxLS2duVnlUWmNwaTFIUDNna1hVYmtxNjRiYUNPZ3pBRlB3b1p3S0pnQlJrV1lkSkE4RGt0WGc2U242eHBsTGRUd0JKRXVybVpkMFhSU2ljUGRHQVZYTnVZOWIvUlNSMDh5dWkyQU95SHNBcVJWYm4rV01wbE85Z0dBQkI2TXdCQzZBSCsvLy9UeHcwbHF3cHpXQ2ZsWGI4Tmk1R2VYaHZvMjVtTDk4SG1zRjNDZzcrLy84ZjJCUThlTjBlalF4dkw1aXZSVS85L0pKMFg0K3N2NXc5R21NM0gvLy8vdzlzQ2g2OGJvOUdocmNYek5laXAzNStTYnF2UjlaZnpoNk5zWnNQQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQkJpTlFCQzZBSGZQLy9QN2hmZmY4WTlXRThvVG84UmZkdlRqbmxEWnoyZkdwcDRzT01Sd3dXOC8rZmhwZnlXd2xNT0FzTVNLclI5dHlnanh1NVc4TTVwU0hWYitpaUVPQjM0UDhCcG1DOGFvbHRvOUc0VlVXMm1KdGx1YVhVM3lWL3FCZi81TjhwZjVOZEhuajIrbnJyN1MzYnNZdnZ0S0l3MURCUW5EKzdlcERmVW5QSmFRTGwvUUE2RkpDSHpJT0xzSEpxckMzN05tVHFDZjY1UmpyYm5sMm5XV0c5RkFLUXZLOVdCdDMxSmM4RUl5bWM1UjkvWm1QVVFOcGVpY3VOTGdyVUJvY3VEOWh2MTR4NVBZWVE1aVhxN01wS3YxVU8yRUpnVUdpeFUyZkpWc3NIVENEdlV4Y2RLNit0QVBVWHhkK2xZMFROSHJ3elMrS1FYYi92R21Hbjdkem5JVlVFLzh6U1VOZXZZdnVuTjlEN2NNUWdMaEgzb2hpOUx0WXhaWmU5Qm9VYmUrSXVwdmZkV2l6SFZlVXY2NlQzZG4vdDh0UENaNFM3ZUlTRU1Rdk1zUW4xZUlMTEd4bG04eFNlQ1hQWU5WTzgzQVhaZDFxQ2c4bHJoV0xmc214SkFvdkg3VU9BQk1YbnBMWGNJSlFGUGE5ZXJ5ZklWUENWV2VGZzJzMDJ6eWNPSEVDVS80bFk5OTRYdXp5NUVWKzZRU2JrSVVqMFZiM3l4QnMxeTNpRS9TcjNVMXhKd3R4ZjAxeGwvVVU3ZlBLc200dEJ5Y0kvQVduMGhhZ3RDR3FSQk9JMzI4dktocGZ4SzF0QkpIdmZtemN4UmpFb3oxdGxXaGphRnBPZlFDb2MrYTROMTdPOThwU2FSZktFTEdmdzlna3NxeVEwdEE1N1pYV0xOK2JIK3lIenpNZHVGbnRQYjlwcWVBQVRyZjI4cFVleXB0aktibmkwOUgvUGNwQVFNTFRnbnRNQ3ZYa0RpTkI0bGQ0eDk4dCtFanRKTnUyK3RXT2s5RVBoWm9ncENZSmU0eUVVajFnc0dFaXl5L0pEMkFxVzgwempGdkM3NDhPd1g2L3gzZzhKRXRxR3ByTU5VaTVLQjBaY3RoTy9PUWxCemc0d3VvN29ETEoyWEZGNExHT3B5QlZPRmZzYy8zczZUOEphYjZCajlNQ3NsbVF2UzdwM0ZJcmltSlFtZG01VE1PdWd2MCtuNVlVTVlkYzMrd3NWZHlQd05VWjNHYUJ0YXp1cU5RNWlLeUV3WkFPY3FLUERHSGl2SXZRbzcxaXErZG5HbURuS3F6azJxYURmSzNkU2dGdUZlMFRuUmN6SXozU21odUdjamR4QUVPZHpBbnBxUHl2S0FUWUpMSVhJSFZ5blhqV2RiQjN6N0xoUy9oMHVKQXk3RTlHeTZTYzUrTEZacFFOMy8vTjZSdUQ2ZDdYYVFXbFBYQ28rMUJ6S0U3Rkt5ZFl0QyttWTlZOUJGLzZEcTN4bmtaUlR6VU5Cd0t1RVR2NHdkZ1YwSXhVZ0U3c1E3WU9hTjRNQVlONE8zYzhxRTdGQ1JDVUIxU3RMdXpGNkpMb1ptVld6akFheHlPTGZlaHJFTUpxSVpyOVlaRytYZFZ2SnY2ZVFIL0NDSHBUREMwazZqYVREVkZjYkpBQkJxTnNCQzZBSFZsVlY5YmVqbG9JTFN5WlJNUEIzeGVnNlZsWWsyWW9sY1JVaGxrdzBtQldYYi9rbXdtamVEbGxsUm5uYVlkTzRWejNJWllGKyt4N1RnTExLakovVUFGQVB1aWdCV0FMWUpvZTU3OGhoNUo1ZHp5MWJTQS9xZDZPTEhwODZ2RVlvenJmbEI4c3Y1c0V0Rm1KM1lZbTdadTRqNkY3bndoMU1TUEFmUFJJbzN3SzE4czV1L3pGclJ0VEVYaVNWelc4VFQyNlRwT3pWblJjM1JreWFseEN5R2c1OStVQ1pDTWtueG0wUmY2eXBEWnVmQ2tZRk5ZMld6a1NkSHVWTC9LMEJQeVVqbjdWVUg2NGlwYWZscU13VmNSc2pVLytUd1ZwZ0dmZDJNMU5Ta0FHMGZ4cVFyUXhRYnE0d0ZZUHllSnoxbzFVYTN6UzZiVkR3bkU3WnFIZExMVHgvL2VrTHRUdCtNWHhOQnBOdkZ2M0hsV1g4VzNrL3RNaXljaWhqMjBrb1ZBZVpXVytIdUJCM2IrMWlldXFKVWM4d3NJNG5vb09wZ0RYSE1xSmUvaGpNSjBzbDZqUEpmRCtqRDlTRW9WcHRuRkFIbmIxT0ZBV0ZyRDZBRFFBTEhjYmwrbjdDOUxuOE5CVE4vVmxVNGxrRWpiNG53SmFKcHYycnk4UXlyTXdhcnhSbVdNTC9Ha0krVUM2Y3RnMEJkUVBBQ0l3N0ZEWkx1Q2Z4L3FnTTFoZUpMV09kTndoSnNucXZFZDl6YTFJYW1xaGNBem8wc2R6dWNudG9vVW14QTNQN3h5T2V4N2VOY0EyZS9peWp6WXNKRzVsNlpkV1FQSWl4eDBEVytBQUVrT2Q0QWNyZlBuTUd6QmZ2NExBTERzemo5cys5emFKN2FoSEFkbjExYnkxcGZDZS9OUk1OcjV3Ui8vb2s4akg1ZjFEUzAwclFyR0t2bldsRjhRR2JBV2lKcmg0ZFBaRnhBd1FZOXlFdkZnTW9JaUVJb3IzNHpwc3RCcjdndEVJUWJjbFB2MzgxbXI5UXdDWkNmdllqemlpWm5nSGFCK01OcTVnZjA5b2FSd1BOSTNLNWhvbjBkR1FuSm1OKzk0S2tQcXk4T2FlQnpld2UyWmRwVFg0eE1OcUFESjdUWHVFVnB5Mlk1NGxvN0hiZyswenRTTkpMVVVNUVlJdFVSS1FIN21wZlBMcldkOE1ab2d0M3BmaSt5cmlKemJTZlkvQjlub0RLSE04U1JRVis5aDF1RUg5RjA3Si9FMWJ4WnJHMmhzdUxqMW96UXltRXZnenJTU2wyR2pRQjQ4Ukk3YUIzRW5ZVUt5YUNzNVJSd2NjRzNaaVR4L09yR3krbWZEY2MxdGdkQVUwZ0swd200MUg0eW5DdlUzQW1LcDlLUC8zNzRROFBJSVEzOFF5bmtxdWgxc1h0dHgyMUFmNm5Oam1LWTBiQ2hQYkkzVzB2TW9zS1pVZExFcC94VTVxeGxKc0RuN0lSdi9oVit3N3MvN3gxWjhRVHN3cDVsYXRsOC8wcDArditJWkd3RXBFMWpYYXA1YVRkVkh4NWFKTlJhMjNoY1A4ZmdWc0tJeC9WN1lLZjBiQm1ubERCcG5RUE1nenRDVFd4MWRPdFpCaGluQjRiNHo1bkZRQkJ5T0lCQzRBQ0FJQkF3Q0NnWU9BUWtGRFFNTEJ3OEFpSVNNZ29xR2pvR0poWTJEaTRlUGdFaEVURUpLUms1QlNVVk5RMHRIVDBESXhNekN5c2JPd2NuRnpjUEx4OC9BS0NRc0lpb21MaUVwSlMwakt5Y3ZJS2lrcktLcXBxNmhxYVd0bzZ1bnI2Qm9aR3hpYW1adVlXbGxiV05yWjI5ZzZPVHM0dXJtN3VIcDVlM2o2K2Z2NEJnVUhCSWFGaDRSR1JVZEV4c1hIeENZbEp5U21wYWVrWm1WblpPYmw1K1FXRlJjVWxwV1hsRlpWVjFUVzFkZlVOalUzTkxhMXQ3UjJkWGQwOXZYMzlBNE5Ed3lPalkrTVRrMVBUTTdOejh3dUxTOHNycTJ2ckc1dGIyenU3ZS9zSGgwZkhKNmRuNXhlWFY5YzN0M2YzRDQ5UHp5K3ZiKzhmbjEvZlA3OS8vd0JCaVBvQkMyQ2REWS9GalVOZDB6MEx4L1VvNjNnS0xFWjVlRytqYm1ZdjN3ZWF3WGNLRGpvYkhvc2JoN3FtZXhhTzYxSFc4UlJZalBMdzNrYmR6RjYrRHpTRDd4UWNuUTJQeFkxRFhkTTlDOGYxS090NENpeEdlWGh2bzI1bUw5OEhtc0YzQ2c0QVFlajZBUXRnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ2REWS9GalVOZDB6MEx4L1VvNjNnS0xFWjVlRytqYm1ZdjN3ZWF3WGNLRGdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhJK3dFTHdBRW1JTHdDMGJXRGpuSUJlMGsxR2V2YzN4cUJsMGNtdVBzN1VKYXZRVGhYR1VCaFRLaDljN1N2eE5nQ1dGcmRRMkNHTDZCUy9GRHBDV3Q3NmpxRDhQNFU5dWxyaUozNm5XRjRtNTcxbDlKLy92NTlHeU5pR3A3L0JrS2VydXQrL1NqdVZoakhWbHNKWkxzOGZUSWkrVmZjZGhBMU03NDErVldDWlAyVDVxQ2tEWjBOajhXTlExM1RQUXZIOVNqcmVBb3NSbmw0YjZOdVppL2ZCNXJCZHdvT0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUVlqOUFRdkFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNkRFkvRmpVTmQwejBMeC9VbzYzZ0tMRVo1ZUcramJtWXYzd2Vhd1hjS0RnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQnlQNEJDNEFEblEyUHhZMURYZE05QzhmMUtPdDRDaXhHZVhodm8yNW1MOThIbXNGM0NnNEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhJZ1FJTFFQZC9EVUhPUndiMkVkQWIwMDF2UFMvUnhrQTVmak5ES1ZlWTQ2Zm9tSlVkblEyUHhZMURYZE05QzhmMUtPdDRDaXhHZVhodm8yNW1MOThIbXNGM0NnNEFRWWlDQWd0QWNnVUdUOUxudm9mbGFod3YzU3I5MEVSUC9meVNkRitQckwrY1BScGpOeDhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJ5SUlDQzBDb0FyaDM0emo1TzExVE16WW5Hd3NDWUZKMVNmRHR0eVp0cUlSRE1zWVVKV2YvM05ITTdPYzRQZzNPazMyejhHV3FBS3dpM2RCSjEwMk5hRXJPdVVFQkFFSElyUUlMd0FFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRWWl2QWd2QUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCeU1JQ0M4QUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVHSTBBSUxRUUFBQUFFQUFRQUJBUUVBQVFFQkFBQUFBUUVBQVFFQkFBQUJBUUVCQVFBQkFRQUFBUUVCQUFBQUFBQUFBUUVCQUFFQUFBRUJBUUVBQVFBQkFRRUFBQUVCQUVHUTlnTUxRRENyWTBVUU8zZTFWR1NxcWNpUmZ6U1JDUzRrSjNFQWV1d1VnaEhZdkZZWlYwZXFvQjZmaEc1QmtmaUpiWHNjcWpySzRQck5FK2Uydyt1Q1RydFBhU1lBUWREMkF3dEFLYlkyS1F6ZHUrVEx1alBoWXZFd3UyWlRaUG0yMGFreDNmZ0FwYjV3TlNYSGQvNWY1SHpYb2R2UkpuZ1IvYThIYTl4K3V5ZTlGbTNNL3Q2RkFpQ0hMQUJCa0lVRUMwQ2REWS9GalVOZDB6MEx4L1VvNjNnS0xFWjVlRytqYm1ZdjN3ZWF3WGNLRGdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhRaFFRTFFKME5qOFdOUTEzVFBRdkg5U2pyZUFvc1JubDRiNk51WmkvZkI1ckJkd29PQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRWkNHQkF0QW5RMlB4WTFEWGRNOUM4ZjFLT3Q0Q2l4R2VYaHZvMjVtTDk4SG1zRjNDZzRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkIwSVlFQzBDZERZL0ZqVU5kMHowTHgvVW82M2dLTEVaNWVHK2pibVl2M3dlYXdYY0tEZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFR1Fod1FMUUowTmo4V05RMTNUUFF2SDlTanJlQW9zUm5sNGI2TnVaaS9mQjVyQmR3b09BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFkQ0hCQXRBblEyUHhZMURYZE05QzhmMUtPdDRDaXhHZVhodm8yNW1MOThIbXNGM0NnNEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQmtJZ0VDMENkRFkvRmpVTmQwejBMeC9VbzYzZ0tMRVo1ZUcramJtWXYzd2Vhd1hjS0RnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVIUWlBUUxRRENyWTBVUU8zZTFWR1NxcWNpUmZ6U1JDUzRrSjNFQWV1d1VnaEhZdkZZWlYwZXFvQjZmaEc1QmtmaUpiWHNjcWpySzRQck5FK2Uydyt1Q1RydFBhU1lBUVpDSkJBdEFrcjQ2aEgvWFlYUDdFVFFuMHl1N3Baa2pQa3N4SDVTYzdOT2Z1OTJjM3hWSnlkaExGZjNkWFdCYlJLU2xLY3RpdWRKOURBcUh2RGY5OEhFeG5RcURKQUJCMElrRUMwQUhTUlF6bHFhYnI0cTNyNGR6SFd2S2h5Q0s4Rjd0dlJGOE9oOGFkVTN6QW5JdFNVd2pyaUtpVytGZFZxUUNEOUFteWQ5VG92TXYzRkdWaWJNV1Y2Y1FBRUdRaWdRTFFDbTJOaWtNM2J2a3k3b3o0V0x4TUx0bVUyVDV0dEdwTWQzNEFLVytjRFVseDNmK1grUjgxNkhiMFNaNEVmMnZCMnZjZnJzbnZSWnR6UDdlaFFJZ2h5d0FRZENLQkF0QTV3OXBRUzlwY01rTFMya25JVFJBNHVoWnhJTnI1cjR5UVlpd0N1MjhxaEtwdjY1QUkxMUlEVmZNTDZzWU5Ca0Y5UkJKaWd1a3NOTmFrdEkxdGVzaEx3QkJrSXNFQzBDZERZL0ZqVU5kMHowTHgvVW82M2dLTEVaNWVHK2pibVl2M3dlYXdYY0tEZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFSFFpd1FMUUp3TDZCT095RkF6dVZaZTIzeFZ6bjFLVmhXMnVMUUJZT0FYQWdJWDVvSW1BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFaQ01CQXRBVmVHQzF4RU1rM0VqTTc3L2ZKUzdwa1FVZE5SRU16Q3FRMGxaSmcwL095d0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQjBJd0VDMER5Ry9vQUJZQ055bW1YczJnVTFzWHdHRVFOclhFU0lBN21WdGk2WlE4cEJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVHUWpRUUxRS3J2N1JLSlNNTm9UNytxY21oL0NJMHhFZ2dKUjZMaFVmckFLVWV4MWxraUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUWRDTkJBdEFxL0dVeElqRHp3alVjeE9ORkJXekdSTUNiTXY5a0U1WVNZZ3YzMXRvNFFrQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCa0k0RUMwQ2REWS9GalVOZDB6MEx4L1VvNjNnS0xFWjVlRytqYm1ZdjN3ZWF3WGNLRGdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhRamdRTFFLMXJyUmIzSXEvSnNtS21TaXA0RWJQMHgwamlaSy91R1lLZlErTjNQaWNnckpQTzkyQW93S3hNYTZkN2dkVXpPV2VFYkVTTEdPWnBWY3dYUkcwRFJnb0FRWkNQQkF0QTMySm5lNldUaWtUZjZ2MG85UzNXdjNyVW13N1E5VmpZV094Mk5FMDlzQWJSTnNtODlOb1pLNThwOUZaNlRxV2g4YTdlV3VEdU03V3lvTjJFSzRFTUZ3QkIwSThFQzBCOTJVWk9HQlpUTnA5dHlkU2VFdmNLdFFrUXlpK25uV1VqRGFLRGlXMFJDRGtabk1QM1N0K3hmNzl6aW9jQ256M2dDcStNa2lBaW02WlU4TzhWUldnbUFFR1FrQVFMUUI1SFJxOEtyMlJYd1E4K2h5NTVVTnoyQkIySS8zT21oa3luTUR5MDNTNExnSVYrZURJUFNacXgrRXJ3ZjIzUmovSjdBc2FPaURsTFhhRlNXM0F1M1FNQVFkQ1FCQXRBbjFYUGRTSkx2T0FQNWxUQlJiazR3bDU5bXBLbGdqbUFmcVBrOXkwRnpoV25tVGUvdmU4b0xYTUgxaG84ZmdtYlcxTktyeE5CTFpoallBWGprWW5oSkFCQmtKRUVDMENkRFkvRmpVTmQwejBMeC9VbzYzZ0tMRVo1ZUcramJtWXYzd2Vhd1hjS0RnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVIUWtRUUxRRlhoZ3RjUkRKTnhJek8rLzN5VXU2WkVGSFRVUkRNd3FrTkpXU1lOUHpzc0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUVpDU0JBdEFuQXZvRTQ3SVVETzVWbDdiZkZYT2ZVcFdGYmE0dEFGZzRCY0NBaGZtZ2lZQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCMEpJRUMwQ2NDK2dUanNoUU03bFdYdHQ4VmM1OVNsWVZ0cmkwQVdEZ0Z3SUNGK2FDSmdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUdRa3dRTFFKME5qOFdOUTEzVFBRdkg5U2pyZUFvc1JubDRiNk51WmkvZkI1ckJkd29PQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRZENUQkF0QVZlR0MxeEVNazNFak03Ny9mSlM3cGtRVWROUkVNekNxUTBsWkpnMC9PeXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJrSlFFQzBDZERZL0ZqVU5kMHowTHgvVW82M2dLTEVaNWVHK2pibVl2M3dlYXdYY0tEZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFSFFsQVFMUUxIajZGUW11aHI1RXM2UzNDL0xjVWMxMzR2ODRHcXgzT1NMbmMyVm9Vb25peCtCR0s1US9GeU1tRVBMTTRTeVN4bGl0Y01UWDlOUE9vaklMNzFKR1RBQVFaQ1ZCQXRBMXR2YTJQRWdOSVN5elQ4WXlSRHdNVWxncHllMU1HTkQ1TjhhOFVkMDFCTjArbGVvSTBCSjd4b1FxOVVDWFpJcUVDK21tNElWc0lPanJoTU1IUkU1SlFCQjBKVUVDMEIya0RJYmdtKzNoaFMyR1UwcjlZdEFMZW1GMmRDNTMxT24wb0pwRkNBZUJjZnJVbmZVbkx3UEpONFZOT1AvajIyNVFjODQ4Q3p5dmxTL1pqei83Y0FWQUVHUWxnUUxRQ20yTmlrTTNidmt5N296NFdMeE1MdG1VMlQ1dHRHcE1kMzRBS1crY0RVbHgzZitYK1I4MTZIYjBTWjRFZjJ2QjJ2Y2Zyc252Ulp0elA3ZWhRSWdoeXdBUWRDV0JBdEF1RVZtTlBQaFN4Y0VtK3VaSklYNDMzVWoxZzQ2bkhwTlBSczA3VUJJSXdORjF3VlhzUjRCWEtrRkdOaTB0SEV0eEpxQ3ByN2l6SHd5Ym1TT1Qrd2pKZ0JCa0pjRUMwQ2REWS9GalVOZDB6MEx4L1VvNjNnS0xFWjVlRytqYm1ZdjN3ZWF3WGNLRGdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhRbHdRTFFKME5qOFdOUTEzVFBRdkg5U2pyZUFvc1JubDRiNk51WmkvZkI1ckJkd29PQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRWkNZQkF0QW5RMlB4WTFEWGRNOUM4ZjFLT3Q0Q2l4R2VYaHZvMjVtTDk4SG1zRjNDZzRBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkIwSmdFQzBDcTcrMFNpVWpEYUUrL3FuSm9md2lOTVJJSUNVZWk0Vkg2d0NsSHNkWlpJZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFR1FtUVFMUUtydjdSS0pTTU5vVDcrcWNtaC9DSTB4RWdnSlI2TGhVZnJBS1VleDFsa2lBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFkQ1pCQXRBcXUvdEVvbEl3MmhQdjZweWFIOElqVEVTQ0FsSG91RlIrc0FwUjdIV1dTSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQmtKb0VDMENkRFkvRmpVTmQwejBMeC9VbzYzZ0tMRVo1ZUcramJtWXYzd2Vhd1hjS0RnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVIUW1nUUxRRENyWTBVUU8zZTFWR1NxcWNpUmZ6U1JDUzRrSjNFQWV1d1VnaEhZdkZZWlYwZXFvQjZmaEc1QmtmaUpiWHNjcWpySzRQck5FK2Uydyt1Q1RydFBhU1lBUVpDYkJBdEFrcjQ2aEgvWFlYUDdFVFFuMHl1N3Baa2pQa3N4SDVTYzdOT2Z1OTJjM3hWSnlkaExGZjNkWFdCYlJLU2xLY3RpdWRKOURBcUh2RGY5OEhFeG5RcURKQUJCMEpzRUMwQkF0R2lsZ09XRWpBSVR3dUFkVFJiTjFUZjNrRmRZa3FhdFpSTEgvUUJ4TGRYUE00enozZjJaTWVrVEV1MW5jc2MyajZFdEZGSWczTmNLcUMxYzk3d2ZBRUdRbkFRTFFCNUhScThLcjJSWHdROCtoeTU1VU56MkJCMkkvM09taGt5bk1EeTAzUzRMZ0lWK2VESVBTWnF4K0Vyd2YyM1JqL0o3QXNhT2lEbExYYUZTVzNBdTNRTUFRZENjQkF0QVlPMFRsK2Npc0hLQmZ3aEJjRFpCdFhUK3ZQMUtYNUdGNkJlQjFvV1J1UjJlUGM2WDh5N1lMamIrUWIxNE5taVNhRWM0OTZxaG4rVE9EVitydldKQ0FRQkJrSjBFQzBDZERZL0ZqVU5kMHowTHgvVW82M2dLTEVaNWVHK2pibVl2M3dlYXdYY0tEZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFSFFuUVFMUUp3TDZCT095RkF6dVZaZTIzeFZ6bjFLVmhXMnVMUUJZT0FYQWdJWDVvSW1BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFaQ2VCQXRBVmVHQzF4RU1rM0VqTTc3L2ZKUzdwa1FVZE5SRU16Q3FRMGxaSmcwL095d0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQjBKNEVDMEJWNFlMWEVReVRjU016dnY5OGxMdW1SQlIwMUVRek1LcERTVmttRFQ4N0xBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVHUW53UUxRSjBOajhXTlExM1RQUXZIOVNqcmVBb3NSbmw0YjZOdVppL2ZCNXJCZHdvT0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUWRDZkJBdEFuQXZvRTQ3SVVETzVWbDdiZkZYT2ZVcFdGYmE0dEFGZzRCY0NBaGZtZ2lZQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCa0tBRUMwQ2REWS9GalVOZDB6MEx4L1VvNjNnS0xFWjVlRytqYm1ZdjN3ZWF3WGNLRGdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhRb0FRTFFLMXJyUmIzSXEvSnNtS21TaXA0RWJQMHgwamlaSy91R1lLZlErTjNQaWNnckpQTzkyQW93S3hNYTZkN2dkVXpPV2VFYkVTTEdPWnBWY3dYUkcwRFJnb0FRWkNoQkF0QTMySm5lNldUaWtUZjZ2MG85UzNXdjNyVW13N1E5VmpZV094Mk5FMDlzQWJSTnNtODlOb1pLNThwOUZaNlRxV2g4YTdlV3VEdU03V3lvTjJFSzRFTUZ3QkIwS0VFQzBES0l6YUsvblhOQmU1Y3FKUHlWNHFNcUU1eHQ0YWVzbElHazQ5ZDZlQlNLQTdrNEJRZlFVR0tEUXYrM1FsbzRsbDlUZEwwSXlVdUhZTkxRZkZjQ2Z3SkFFR1FvZ1FMUUNtMk5pa00zYnZreTdvejRXTHhNTHRtVTJUNXR0R3BNZDM0QUtXK2NEVWx4M2YrWCtSODE2SGIwU1o0RWYydkIydmNmcnNudlJadHpQN2VoUUlnaHl3QVFkQ2lCQXRBcUtldFl2UkFaRnQ5NUJ5blM3RkkxZjdhNXU0UXd4WTRxL3hNNlVSSmxocWdZMFVaV1p6M0RockRtMDFWN0hmOEFRVTMwcUlFSXlER1B5eis0TVNDQ3dCQmtLTUVDK0FDSVBHR3ltUkxsb2FrSTBYbHQrK2tRTHRLNkpaNHFYK0RHTG15dWJZQ0VUYmFrbGJ6M29IZXdHREh3NmJveHdTK2Y3dHcxY241WnRkQkdGYURUWmN3d3FOcHZzTm9GcnBibEdKU0VNUVJPSDhjcDkzYWZlNjZLUUNwWFJTTk80Ry9MSm8vUXQrNkcyUmV6T3BFNnJRTHFIemovUlJJWm1YTjBwRUNXTGxrQTByZDhDWUlzZCtUN2lSSFVjV04yMEpyaFRjUEMwUFBFTHNXUW9CdlFFNUpRUHVxODZ3SDRjOVZoNjdyNElEc2lDQ2dONk1SMEQ1cWhKVlJPaDVLV3FSSUZnN0YzMmhGWnVYcnhBeE1LVUZxcTlySGFOSUMxdENDaXNRODdacEVhR2I4WFFHeUQ4MWlVTkd6M2JHb1FDbC9TR1FpS2pxMjlYZXVRK1JoRTNqdy9zakcxWWdPaDNmNXFtdG5INlprQTNtajNxM09MdWVIV0hBYm1xQmo1WGNUc3NQWUcrN3ZWQXozMkNUVld0SERQbDA2T0xKbVZQSGF3UDZVdTNNSzQrSGllejlmQVhFY2F2K3hhV08vUXkyRXZDQjlFTi9hL1NCd3lXMUxMd0FBQUFCQjhMVUVDejhCQUFBQS93QUFBQUFCQUFFQUFBQUFBUUFBQVFEL0FBRUFBUUFCQUFBQkFBQUFBUUQvQVA4QS93QUJBQUVBQVA4QUFRQUJBUDhBQUFFQUFRQUFBQUU9XCI7XG5jb25zdCBwcSQxID0gNDg4O1xuY29uc3QgcEcxZ2VuJDEgPSAzMjAwODtcbmNvbnN0IHBHMXplcm8kMSA9IDMyMTA0O1xuY29uc3QgcEcxYiQxID0gMzA4MDtcbmNvbnN0IHBHMmdlbiQxID0gMzIyMDA7XG5jb25zdCBwRzJ6ZXJvJDEgPSAzMjM5MjtcbmNvbnN0IHBHMmIkMSA9IDEyNjQ4O1xuY29uc3QgcE9uZVQkMSA9IDMyNTg0O1xuY29uc3QgcHJlUFNpemUkMSA9IDE5MjtcbmNvbnN0IHByZVFTaXplJDEgPSAxOTc3NjtcbmNvbnN0IHEkMSA9IFwiMjE4ODgyNDI4NzE4MzkyNzUyMjIyNDY0MDU3NDUyNTcyNzUwODg2OTYzMTExNTcyOTc4MjM2NjI2ODkwMzc4OTQ2NDUyMjYyMDg1ODNcIjtcbmNvbnN0IHIkMSA9IFwiMjE4ODgyNDI4NzE4MzkyNzUyMjIyNDY0MDU3NDUyNTcyNzUwODg1NDgzNjQ0MDA0MTYwMzQzNDM2OTgyMDQxODY1NzU4MDg0OTU2MTdcIjtcblxuLy8gQVVUTy1HRU5FUkFURUQgZnJvbSB3YXNtY3VydmVzL2J1aWxkL21zbV9iYXRjaC53YXNtIOKAlCBkbyBub3QgZWRpdC5cbi8vIFJlZ2VuZXJhdGUgd2l0aDogbnBtIHJ1biBnZW4td2FzbVxuLy8gQmF0Y2gtYWZmaW5lIE1TTSBtb2R1bGU7IGxpbmtzIGFnYWluc3QgdGhlIG1haW4gY3VydmUgbW9kdWxlIGF0IHJ1bnRpbWUuXG5jb25zdCBjb2RlJDEgPSBcIkFHRnpiUUVBQUFBQlNBcGdBWDhBWUFOL2YzOEFZQUovZndCZ0JuOS9mMzkvZndCZ0FYOEJmMkFLZjM5L2YzOS9mMzkvZndGL1lBaC9mMzkvZjM5L2Z3Ri9ZQUFBWUFOL2YzOEJmMkFDZjM4QmZ3TGNBUTRGWTNWeWRtVUZabDl0ZFd3QUFRVmpkWEoyWlFWbVgzTjFZZ0FCQldOMWNuWmxCbWRmZW1WeWJ3QUFCV04xY25abEJXWmZZV1JrQUFFRlkzVnlkbVVJWmw5cGMxcGxjbThBQkFWamRYSjJaUVptWDJOdmJtb0FBZ1ZqZFhKMlpRVm5YMkZrWkFBQkJXTjFjblpsQ0daZmMzRjFZWEpsQUFJRlkzVnlkbVVGWmw5dVpXY0FBZ1ZqZFhKMlpRaG5YMmx6V21WeWJ3QUVCV04xY25abENHZGZaRzkxWW14bEFBSUZZM1Z5ZG1VS1oxOWhaR1JOYVhobFpBQUJCV04xY25abENXWmZhVzUyWlhKelpRQUNBMlZ1ZGdadFpXMXZjbmtDQUJrREVBOERCQU1BQUFBQUJRWUFCd01EQ0FrR3F3RWlmd0ZCQUF0L0FVRUFDMzhCUVFBTGZ3RkJBQXQvQVVFQUMzOEJRUUFMZndGQkFBdC9BVUVBQzM4QlFRQUxmd0ZCQUF0L0FVRUFDMzhCUVFBTGZ3RkJBQXQvQVVFQUMzOEJRUUFMZndGQkFBdC9BVUVBQzM4QlFRQUxmd0ZCQUF0L0FVRUFDMzhCUVFBTGZ3RkJBQXQvQVVFQUMzOEJRUUFMZndGQkFBdC9BVUVBQzM4QlFRQUxmd0ZCQUF0L0FVRUFDMzhCUVFBTGZ3RkJBQXQvQVVFQUMzOEJRUUFMZndGQkFBc0hhUVlPYlhWc2RHbGxlSEJCWm1acGJtVUFEeEJuYkhORVpXTnZiWEJ2YzJWVVpYTjBBQnNSYlhWc2RHbGxlSEJCWm1acGJtVkhURk1BR1JCbmJIWkVaV052YlhCdmMyVlVaWE4wQUJvUmJYVnNkR2xsZUhCQlptWnBibVZIVEZZQUdBWnRaVzF2Y25rQ0FBcllWUS90QVFJRGZ3SitBMEFnQlNBR1NnUkFJQVFnQmtFQ2RHcEJBRFlDQUNBR1FRRnFJUVlNQVFzTEEwQWdBU0FIU2lBRklBZEtjUVJBSUFBZ0IwRUNkR28xQWdBaUNrSUFVZ1JBUWdBaENVRUFJUVlEUUNBRElBWktCRUFnQlNBR0lBZHFJZ2hLQkVBZ0JDQUlRUUowYWlJSU5RSUFJQW9nQWlBR1FRSjBhalVDQUg1OElBbDhJUWtnQ0NBSlBnSUFJQWxDSUlnaENTQUdRUUZxSVFZTUFnc0xDeUFHSUFkcUlRWURRQ0FGSUFaS0lBbENBRkp4QkVBZ0JDQUdRUUowYWlJSU5RSUFJQWw4SVFrZ0NDQUpQZ0lBSUFsQ0lJZ2hDU0FHUVFGcUlRWU1BUXNMQ3lBSFFRRnFJUWNNQVFzTEM2d0JBQ0FBWnlJQVFRbE5CRUJCRVE4TElBQkJDMDBFUUVFUUR3c2dBRUVNUmdSQVFROFBDeUFBUVExR0JFQkJEZzhMSUFCQkQwMEVRRUVORHdzZ0FFRVFSZ1JBUVF3UEN5QUFRUkZHQkVCQkN3OExJQUJCRWtZRVFFRUtEd3NnQUVFVFJnUkFRUWtQQ3lBQVFSUkdCRUJCQ0E4TElBQkJGazBFUUVFSER3c2dBRUVYUmdSQVFRWVBDeUFBUVJoR0JFQkJCUThMSUFCQkdVWUVRRUVFRHdzZ0FFRWFSZ1JBUVFNUEMwRUNDMHdBSUFRUUFpQURSUVJBRHdzZ0JTUUFJQU1rQmlBQ0pBY2dBa0VEZENRSUlBQWtDU0FCSkFvZ0F5UWZRUUFrSUVFQUpDRWdBeEFPSkFGQkFDZ0NBQ0VBSUFRUUVFRUFJQUEyQWdBTDh4Y0JFWDlCQVNNQlFRRnJkQ1FDUVFFakFYUWtBeU1DSkFRakNFRUJheU1CYlVFQ2FpUUZJd1lpQXlNRmJDRUNRUUFvQWdBaEFRTkFJQUZCQTNFRVFDQUJRUUZxSVFFTUFRc0xRUUFnQVNBQ2FpSUNOZ0lBUHdCQkVIUWlCQ0FDU1FSQUlBSWdCR3RCRUhaQkFXcEFBQm9MSUFFa0N5TUVJd0JCQVhSc0lRSkJBQ2dDQUNFQkEwQWdBVUVEY1FSQUlBRkJBV29oQVF3QkN3dEJBQ0FCSUFKcUlnSTJBZ0EvQUVFUWRDSUVJQUpKQkVBZ0FpQUVhMEVRZGtFQmFrQUFHZ3NnQVNRTUl3UWhBa0VBS0FJQUlRRURRQ0FCUVFOeEJFQWdBVUVCYWlFQkRBRUxDMEVBSUFFZ0Ftb2lBallDQUQ4QVFSQjBJZ1FnQWtrRVFDQUNJQVJyUVJCMlFRRnFRQUFhQ3lBQkpBMGdBMEVDZENFQ1FRQW9BZ0FoQVFOQUlBRkJBM0VFUUNBQlFRRnFJUUVNQVFzTFFRQWdBU0FDYWlJQ05nSUFQd0JCRUhRaUJDQUNTUVJBSUFJZ0JHdEJFSFpCQVdwQUFCb0xJQUVrRGlBRFFRTjBJUUpCQUNnQ0FDRUJBMEFnQVVFRGNRUkFJQUZCQVdvaEFRd0JDd3RCQUNBQklBSnFJZ0kyQWdBL0FFRVFkQ0lFSUFKSkJFQWdBaUFFYTBFUWRrRUJha0FBR2dzZ0FTUVBJd1JCQW5RaEFrRUFLQUlBSVFFRFFDQUJRUU54QkVBZ0FVRUJhaUVCREFFTEMwRUFJQUVnQW1vaUFqWUNBRDhBUVJCMElnUWdBa2tFUUNBQ0lBUnJRUkIyUVFGcVFBQWFDeUFCSkJBakJFRUNkQ0VDUVFBb0FnQWhBUU5BSUFGQkEzRUVRQ0FCUVFGcUlRRU1BUXNMUVFBZ0FTQUNhaUlDTmdJQVB3QkJFSFFpQkNBQ1NRUkFJQUlnQkd0QkVIWkJBV3BBQUJvTElBRWtFU0FEUVFGcVFRSjBJUUpCQUNnQ0FDRUJBMEFnQVVFRGNRUkFJQUZCQVdvaEFRd0JDd3RCQUNBQklBSnFJZ0kyQWdBL0FFRVFkQ0lFSUFKSkJFQWdBaUFFYTBFUWRrRUJha0FBR2dzZ0FTUVNJQU5CQVdwQkFuUWhBa0VBS0FJQUlRRURRQ0FCUVFOeEJFQWdBVUVCYWlFQkRBRUxDMEVBSUFFZ0Ftb2lBallDQUQ4QVFSQjBJZ1FnQWtrRVFDQUNJQVJyUVJCMlFRRnFRQUFhQ3lBQkpCTWdBMEVCYWtFQ2RDRURRUUFvQWdBaEFRTkFJQUZCQTNFRVFDQUJRUUZxSVFFTUFRc0xRUUFnQVNBRGFpSUROZ0lBUHdCQkVIUWlBaUFEU1FSQUlBTWdBbXRCRUhaQkFXcEFBQm9MSUFFa0ZFRUFLQUlBSVFFRFFDQUJRUU54QkVBZ0FVRUJhaUVCREFFTEMwRUFJQUZCZ0JCcUlnTTJBZ0EvQUVFUWRDSUNJQU5KQkVBZ0F5QUNhMEVRZGtFQmFrQUFHZ3NnQVNRVlFRQW9BZ0FoQVFOQUlBRkJBM0VFUUNBQlFRRnFJUUVNQVFzTFFRQWdBVUdBRUdvaUF6WUNBRDhBUVJCMElnSWdBMGtFUUNBRElBSnJRUkIyUVFGcVFBQWFDeUFCSkJZakFFRUpkQ0VEUVFBb0FnQWhBUU5BSUFGQkEzRUVRQ0FCUVFGcUlRRU1BUXNMUVFBZ0FTQURhaUlETmdJQVB3QkJFSFFpQWlBRFNRUkFJQU1nQW10QkVIWkJBV3BBQUJvTElBRWtGeU1BUVFsMElRTkJBQ2dDQUNFQkEwQWdBVUVEY1FSQUlBRkJBV29oQVF3QkN3dEJBQ0FCSUFOcUlnTTJBZ0EvQUVFUWRDSUNJQU5KQkVBZ0F5QUNhMEVRZGtFQmFrQUFHZ3NnQVNRWUl3QkJDWFFoQTBFQUtBSUFJUUVEUUNBQlFRTnhCRUFnQVVFQmFpRUJEQUVMQzBFQUlBRWdBMm9pQXpZQ0FEOEFRUkIwSWdJZ0Ewa0VRQ0FESUFKclFSQjJRUUZxUUFBYUN5QUJKQmtqQUNFRFFRQW9BZ0FoQVFOQUlBRkJBM0VFUUNBQlFRRnFJUUVNQVFzTFFRQWdBU0FEYWlJRE5nSUFQd0JCRUhRaUFpQURTUVJBSUFNZ0FtdEJFSFpCQVdwQUFCb0xJQUVrR2lNQUlRTkJBQ2dDQUNFQkEwQWdBVUVEY1FSQUlBRkJBV29oQVF3QkN3dEJBQ0FCSUFOcUlnTTJBZ0EvQUVFUWRDSUNJQU5KQkVBZ0F5QUNhMEVRZGtFQmFrQUFHZ3NnQVNRYkl3QWhBMEVBS0FJQUlRRURRQ0FCUVFOeEJFQWdBVUVCYWlFQkRBRUxDMEVBSUFFZ0Eyb2lBellDQUQ4QVFSQjBJZ0lnQTBrRVFDQURJQUpyUVJCMlFRRnFRQUFhQ3lBQkpCd2pBQ0VEUVFBb0FnQWhBUU5BSUFGQkEzRUVRQ0FCUVFGcUlRRU1BUXNMUVFBZ0FTQURhaUlETmdJQVB3QkJFSFFpQWlBRFNRUkFJQU1nQW10QkVIWkJBV3BBQUJvTElBRWtIU01BUVFOc0lRTkJBQ2dDQUNFQkEwQWdBVUVEY1FSQUlBRkJBV29oQVF3QkN3dEJBQ0FCSUFOcUlnTTJBZ0EvQUVFUWRDSUNJQU5KQkVBZ0F5QUNhMEVRZGtFQmFrQUFHZ3NnQVNFREl3QkJBMndoQWtFQUtBSUFJUUVEUUNBQlFRTnhCRUFnQVVFQmFpRUJEQUVMQzBFQUlBRWdBbW9pQWpZQ0FEOEFRUkIwSWdRZ0Fra0VRQ0FDSUFSclFSQjJRUUZxUUFBYUN5QUJJUUlEUUNBRkl3WklCRUJCQUNFQkl3b2dCU01IYkdvaEIwRUFJUVFEUUNBRUl3VklCRUFqQ3lBRUl3WnNhaUFGYWlBQk9nQUFJd0lnQkNNQmJDSUdJd2hJQkg4Z0J5QUdRUU4xYWlnQ0FDQUdRUWR4ZGtFQkl3Z2dCbXNpQm5SQkFXdEJBU01CZEVFQmF5QUdJd0ZJRzNFRlFRQUxJQUZxVENFQklBUkJBV29oQkF3QkN3c2dCVUVCYWlFRkRBRUxDeU1GUVFGcklRRURRQ0FCUVFCT0JFQWdBQkFKUlFSQVFRQWhCUU5BSUFVakFVZ0VRQ0FBSUFBUUNpQUZRUUZxSVFVTUFRc0xDeUFCSVFSQkFDRUZRUUFoQmtFQUlRZEJBQ0VJUVFBaENVRUFJUXBCQUNFTVFRQWhEVUVBSVE1QkFDRVBBMEFnQlNNRVNBUkFJeEFnQlVFQ2RHcEJBRFlDQUNNTklBVnFRUUE2QUFBZ0JVRUJhaUVGREFFTEN3TkFJQVlqQmtnRVFDQUVJd0ZzSWdVakNFZ0VmeU1LSUFZakIyeHFJUkJCQVNNQmRFRUJheUVMSXdnZ0JXc2lFU01CU0FSL1FRRWdFWFJCQVdzRklBc0xJQkFnQlVFRGRXb29BZ0FnQlVFSGNYWnhCVUVBQ3lNTElBUWpCbXhxSUFacUxRQUFhaUlGSXdKT0JFQWdCU01EYXlFRkN5TWhCRUJCQUNBRmF5QUZJeUVnQm1vdEFBQWJJUVVMSXc0Z0JrRUNkR29nQlRZQ0FDQUZCRUFqRUNBRlFRRnJRWDhnQldzZ0JVRUFTaHRCQW5ScUlnVW9BZ0JCQVdvaEN5QUZJQXMyQWdBZ0N5QU9JQXNnRGtvYklRNExJQVpCQVdvaEJnd0JDd3NEUUNBSElBNUlCRUFqRWlBSFFRSjBha0VBTmdJQUlBZEJBV29oQnd3QkN3c0RRQ0FNSXdSSUJFQWpFQ0FNUVFKMGFpZ0NBQ0VGUVFBaEJBTkFJQVFnQlVnRVFDTVNJQVJCQW5ScUlnWWdCaWdDQUVFQmFqWUNBQ0FFUVFGcUlRUU1BUXNMSUF4QkFXb2hEQXdCQ3dzRFFDQU5JQTVJQkVBZ0RVRUNkQ0lFSXhOcUlBazJBZ0FqRkNBRWFpQUpOZ0lBSUFrakVpQUVhaWdDQUdvaENTQU5RUUZxSVEwTUFRc0xBMEFnQ2lNRVNBUkFJeEVnQ2tFQ2RHcEJBRFlDQUNBS1FRRnFJUW9NQVFzTEEwQWdDQ01HU0FSQUl3NGdDRUVDZEdvb0FnQWlCQVJBSXhFZ0JFRUFTZ1IvUVFBaEJTQUVRUUZyQlVFQklRVkJmeUFFYXdzaUJFRUNkR29pQmlnQ0FDRUhJQVlnQjBFQmFqWUNBQ01VSUFkQkFuUnFJZ1lvQWdBaEJ5QUdJQWRCQVdvMkFnQWpEeUFIUVFOMGFpSUdJQWdqSDBnRWZ5TUpJQWdqQUVFQmRHeHFCU01nSUFnakgyc2pBRUVCZEd4cUMwRUNkVUVCZENBRmNqWUNBQ0FHSUFRMkFnUUxJQWhCQVdvaENBd0JDd3RCQUNRZUEwQWdEaUFQU2dSQUlBOUJBblFpQlNNVGFpZ0NBQ0lFSXhJZ0JXb29BZ0JxSVFVRFFDQUVJQVZJQkVBakR5QUVRUU4wYWlJR0tBSUFJUWdnQmlnQ0JDRUdRUUFoQnlBSVFRRnhJUXdnQ0VFQmRrRUNkQ0lJSXdCcUlRb0NRQ0FJRUFRRWZ5QUtFQVFGUVFBTERRQWpEQ0FHSXdCQkFYUnNhaUlOSXdCcUlRa2pEU0FHYWkwQUFFVUVRQU5BSUFjakFFZ0VRQ0FISUExcUlBY2dDR29wQXdBM0F3QWdCMEVJYWlFSERBRUxDeUFNQkVBZ0NpQUpFQWdGUVFBaENBTkFJQWdqQUVnRVFDQUlJQWxxSUFnZ0Ntb3BBd0EzQXdBZ0NFRUlhaUVJREFFTEN3c2pEU0FHYWtFQk9nQUFEQUVMSXg0akFHd2lCeU1YYWlFTElBZ2dEU01ZSUFkcUlnY1FBU0FIRUFRRVFDQU1CRUFnQ1NBS0l4b1FBd1VnQ1NBS0l4b1FBUXNqR2hBRUJFQWdEU01hRUFjakdpTWFJeHNRQXlNYkl4b2dDeEFESUFrZ0NTQUhFQU1GSXcwZ0JtcEJBRG9BQUF3Q0N3VWdEQVJBSUFvZ0NTQUxFQU1nQ3lBTEVBZ0ZJQW9nQ1NBTEVBRUxDeU1lUVFKMElnY2pGV29nQmpZQ0FDTVdJQWRxSUFnMkFnQWpIa0VCYWlRZUl4NUJnQVJHQkVBUUZ3c0xJQVJCQVdvaEJBd0JDd3NRRnlBUFFRRnFJUThNQVFzTElBTVFBaUFDRUFJakJFRUJheUVFQTBBZ0JFRUFUZ1JBSXcwZ0JHb3RBQUFFUUNBQ0l3d2dCQ01BUVFGMGJHb2dBaEFMQ3lBRElBSWdBeEFHSUFSQkFXc2hCQXdCQ3dzZ0FDQURJQUFRQmlBQlFRRnJJUUVNQVFzTEMvd0NBQ0FBUWRmbmdyOThOZ0lBSUFCQnJzYjB5SDAyQWdRZ0FFRUNOZ0lJSUFCQkFEWUNEQ0FBUVFBMkFoQWdBRUVBTmdJVUlBQkJBRFlDR0NBQVFZM2orc2dETmdJY0lBQkIxTFB2MHdjMkFpQWdBRUhQcGMrN2VqWUNKQ0FBUVpUZ3UrWUVOZ0lvSUFCQkFqWUNMQ0FBUVFBMkFqQWdBRUVBTmdJMElBQkI0NmZJcG5rMkFqZ2dBRUhveXN6T2VEWUNQQ0FBUVVCclFRQTJBZ0FnQUVFQU5nSkVJQUJCaThxRWtRRTJBa2dnQUVIVXdwUGZBRFlDVENBQVFmMno0ZlYrTmdKUUlBQkJ5SVMyK2dZMkFsUWdBRUdvb3J6cUJ6WUNXQ0FBUWV2M3hwQjROZ0pjSUFCQi9MUGg5WDQyQW1BZ0FFSEloTGI2QmpZQ1pDQUFRZU9ueUtaNU5nSm9JQUJCNk1yTXpuZzJBbXdnQUVFQU5nSndJQUJCQURZQ2RDQUFRZFhDaTd4OU5nSjRJQUJCa1pqTWpBYzJBbndnQUVHajV2aDlOZ0tBQVNBQVFmeW83clY2TmdLRUFTQUFRY1NvMEtOOU5nS0lBU0FBUWNUbXdORjZOZ0tNQVNBQVFjT1M1YklDTmdLUUFTQUFRWTMrN09FQ05nS1VBUXYvQWdBZ0FFR3czTCsyZnpZQ0FDQUFRYUxLMjU4R05nSUVJQUJCM2RYK2dINDJBZ2dnQUVIeDJhL2pCellDRENBQVFRRTJBaEFnQUVFQU5nSVVJQUJCQURZQ0dDQUFRUUkyQWh3Z0FFRUFOZ0lnSUFCQkFEWUNKQ0FBUVFBMkFpZ2dBRUVBTmdJc0lBQkJBRFlDTUNBQVFRQTJBalFnQUVGL05nSTRJQUJCQURZQ1BDQUFRVUJyUVlMSUJqWUNBQ0FBUVlISWx1SjZOZ0pFSUFCQkFUWUNTQ0FBUVFBMkFrd2dBRUVBTmdKUUlBQkJBRFlDVkNBQVFRRTJBbGdnQUVFQU5nSmNJQUJCQURZQ1lDQUFRUUEyQW1RZ0FFRUFOZ0pvSUFCQkFUWUNiQ0FBUVlMSUJqWUNjQ0FBUVlISWx1SjZOZ0owSUFCQjhlREhzM2cyQW5nZ0FFSGtrNC9vZkRZQ2ZDQUFRZExMdHY0Qk5nS0FBU0FBUWNiRXJPMEZOZ0tFQVNBQVFaVzNsSng5TmdLSUFTQUFRYStGd2NNRk5nS01BU0FBUVo2WDZ3MDJBcEFCSUFCQnZwM1k5WGcyQXBRQklBQkIwcUhCbm5nMkFwZ0JJQUJCN3ZybEh6WUNuQUVnQUVIQmpvNmpCVFlDb0FFZ0FFSGx3TURIQVRZQ3BBRUx2dzRBSUFCQnFNNlFsd00yQWdBZ0FFR1Ywdnp2QWpZQ0JDQUFRZit1bFo5Nk5nSUlJQUJCKzVUVHJRVTJBZ3dnQUVHVjErU0dlellDRUNBQVFZcmpnUFI1TmdJVUlBQkJBRFlDR0NBQVFiRzMxSzU1TmdJY0lBQkJxZnZTdHdRMkFpQWdBRUd1aWNaak5nSWtJQUJCNXJTWHh3QTJBaWdnQUVHVDErU0dlellDTENBQVFZcmpnUFI1TmdJd0lBQkJBRFlDTkNBQVFkZm5ncjk4TmdJNElBQkJyc2IweUgwMkFqd2dBRUZBYTBFQ05nSUFJQUJCQURZQ1JDQUFRUUEyQWtnZ0FFRUFOZ0pNSUFCQkFEWUNVQ0FBUWIrYXovZDhOZ0pVSUFCQi9hN0NpM3cyQWxnZ0FFSDlycFdmZWpZQ1hDQUFRZnVVMDYwRk5nSmdJQUJCbGRma2huczJBbVFnQUVHSzQ0RDBlVFlDYUNBQVFRQTJBbXdnQUVIanA4aW1lVFlDY0NBQVFlakt6TTU0TmdKMElBQkJBRFlDZUNBQVFRQTJBbndnQUVIaXA4aW1lVFlDZ0FFZ0FFSG95c3pPZURZQ2hBRWdBRUVCTmdLSUFTQUFRUUEyQW93QklBQkI0cWZJcG5rMkFwQUJJQUJCNk1yTXpuZzJBcFFCSUFCQjhwT2swd1EyQXBnQklBQkJ0S1dtcHdRMkFwd0JJQUJCOFpPazB3UTJBcUFCSUFCQnRLV21wd1EyQXFRQklBQkI4Wk9rMHdRMkFxZ0JJQUJCdEtXbXB3UTJBcXdCSUFCQjhwT2swd1EyQXJBQklBQkJ0S1dtcHdRMkFyUUJJQUJCOFpPazB3UTJBcmdCSUFCQnRLV21wd1EyQXJ3QklBQkI4Wk9rMHdRMkFzQUJJQUJCdEtXbXB3UTJBc1FCSUFCQjRxZklwbmsyQXNnQklBQkI2TXJNem5nMkFzd0JJQUJCNDZmSXBuazJBdEFCSUFCQjZNck16bmcyQXRRQklBQkI4Wk9rMHdRMkF0Z0JJQUJCdEtXbXB3UTJBdHdCSUFCQjhwT2swd1EyQXVBQklBQkJ0S1dtcHdRMkF1UUJJQUJCOFpPazB3UTJBdWdCSUFCQnRLV21wd1EyQXV3QklBQkJBRG9BOEFFZ0FFRUFPZ0R4QVNBQVFRQTZBUElCSUFCQkFEb0E4d0VnQUVFQU9nRDBBU0FBUVFBNkFQVUJJQUJCQVRvQTlnRWdBRUVBT2dEM0FTQUFRUUE2QVBnQklBQkJBRG9BK1FFZ0FFRUFPZ0Q2QVNBQVFRRTZBUHNCSUFCQkFEb0EvQUVnQUVFQk9nRDlBU0FBUVFFNkFQNEJJQUJCQVRvQS93RWdBRUd3MW82ckJEWUNnQUlnQUVHUTl0eXJlellDaEFJZ0FFSFV5S25OZWpZQ2lBSWdBRUhJby82akF6WUNqQUlnQUVHUms3aWhBallDa0FJZ0FFR240b0hRQnpZQ2xBSWdBRUhzcVlpTUFUWUNtQUlnQUVIWStkcktBVFlDbkFJZ0FFSFhqcW1GZWpZQ29BSWdBRUdldnBMMEJqWUNwQUlnQUVIQm91TFBlRFlDcUFJZ0FFSHQ5dkhRZWpZQ3JBSWdBRUc2bElOWE5nS3dBaUFBUWMybm5MZDdOZ0swQWlBQVFjUFhpL1FFTmdLNEFpQUFRYnVmcGJNQ05nSzhBaUFBUWFuczJza0NOZ0xBQWlBQVFZeTY3NlYrTmdMRUFpQUFRY3Yxem9sK05nTElBaUFBUWVMaXc5bDdOZ0xNQWlBQVFlYW1rVXMyQXRBQ0lBQkJ0cU9ualFNMkF0UUNJQUJCM2ZHRHFIbzJBdGdDSUFCQnZ1SFZxUUkyQXR3Q0lBQkJ4Ky81L3dVMkF1QUNJQUJCNVBuZGpubzJBdVFDSUFCQjI2T2J3UWMyQXVnQ0lBQkJrZnEvUFRZQzdBSWdBRUhydVB2YmV6WUM4QUlnQUVHbit0cm9CallDOUFJZ0FFSE0vZnV1ZURZQytBSWdBRUdDd0p6a0FqWUMvQUlnQUVHY2w2Q2ZBVFlDZ0FNZ0FFR09rY09hQXpZQ2hBTWdBRUc1cmZuYWZUWUNpQU1nQUVIOHFybnVCellDakFNZ0FFSEtyTld3ZXpZQ2tBTWdBRUc0NllhQUJqWUNsQU1nQUVIZ3I0Z1FOZ0tZQXlBQVFaZk1pN1FDTmdLY0F5QUFRUUEyQXFBRElBQkJBRFlDcEFNZ0FFRUFOZ0tvQXlBQVFRQTJBcXdESUFCQkFEWUNzQU1nQUVFQU5nSzBBeUFBUVFBMkFyZ0RJQUJCQURZQ3ZBTWdBRUdxMzdlWEFUWUN3QU1nQUVHSmtZM0dCallDeEFNZ0FFSFAvcXFWQnpZQ3lBTWdBRUhvL3FIb2VEWUN6QU1nQUVHeHBLRElBRFlDMEFNZ0FFSEh4SWFQQlRZQzFBTWdBRUg2Z2FlNUJEWUMyQU1nQUVHeHJlZVNBallDM0FNZ0FFRUFOZ0xnQXlBQVFRQTJBdVFESUFCQkFEWUM2QU1nQUVFQU5nTHNBeUFBUVFBMkF2QURJQUJCQURZQzlBTWdBRUVBTmdMNEF5QUFRUUEyQXZ3RElBQkJyZGUxdFFFMkFvQUVJQUJCOThXOHpYdzJBb1FFSUFCQnNzV1oxUVEyQW9nRUlBQkJxdkRGbUhzMkFvd0VJQUJCOUkramtuNDJBcEFFSUFCQjVONjZ6d0UyQXBRRUlBQkJncitPbW40MkFwZ0VJQUJCOS95Y2dRSTJBcHdFSUFCQnJLZTZ2bjgyQXFBRUlBQkI0TkNBNW5vMkFxUUVJQUJCek5hZDNRYzJBcWdFSUFCQmdhdlB5UU0yQXF3RUlBQkI1NGl5b3dRMkFyQUVJQUJCaTdHWXp3WTJBclFFSUFCQjFaamZvQVEyQXJnRUlBQkI3WWFZMGdBMkFyd0VJQUJCbm82WitubzJBc0FFSUFCQml0NlN1d1UyQXNRRUlBQkJ3Wi80dVhnMkFzZ0VJQUJCcnZMQjRuMDJBc3dFSUFCQjlvbjB3SGcyQXRBRUlBQkIvK2VadFhnMkF0UUVJQUJCek03QzRRTTJBdGdFSUFCQnRMdTcyUUEyQXR3RUlBQkJnSXY2d3djMkF1QUVJQUJCc3A2azBuazJBdVFFSUFCQnNmR3JnbjgyQXVnRUlBQkIvOXJGL25nMkF1d0VJQUJCOHZlSnNIdzJBdkFFSUFCQmpwSG0yUVEyQXZRRUlBQkIzY0xLMmdVMkF2Z0VJQUJCOE56MEhqWUMvQVFMeWdVQ0JINElmeUFBUVFnZ0FVRUhJQUpCRHhBTklBSTFBaHhDZ0lDQWdBaDhRaUNJSVFvRFFDQU9RUVZJQkVBZ0RrRUlhaUlWUVE5SUJFQWdDaUFDSUJWQkFuUnFOUUlBZkNFS0N5QURJQTVCQW5ScUlBbytBZ0FnQ2tJZ2lDRUtJQTVCQVdvaERnd0JDd3NnQUVFSUlBRkJIR3BCQnlBQ1FROFFEU0FDTlFJY1FvQ0FnSUFJZkVJZ2lDRUtBMEFnRDBFRlNBUkFJQTlCQ0dvaURrRVBTQVJBSUFvZ0FpQU9RUUowYWpVQ0FId2hDZ3NnQkNBUFFRSjBhaUFLUGdJQUlBcENJSWdoQ2lBUFFRRnFJUThNQVFzTElBTkJCU0FCUVRocVFRUWdCVUVGRUEwZ0JFRUZJQUZCeUFCcVFRUWdCa0VGRUEwRFFDQVFRUVZJQkVBZ0FDQVFRUUowSWdKcU5RSUFRb0NBZ0lBUWZDQUNJQVZxTlFJQWZTQUxmU0VLSUFJZ0Iyb2dDajRDQUVJQklBcENJSWg5SVFzZ0VFRUJhaUVRREFFTEN3TkFJQkZCQlVnRVFDQUhJQkZCQW5RaUFHbzFBZ0JDZ0lDQWdCQjhJQUFnQm1vMUFnQjlJQXg5SVFvZ0FDQUhhaUFLUGdJQVFnRWdDa0lnaUgwaERDQVJRUUZxSVJFTUFRc0xJQWNvQWhCQmdJQ0FnSGh4Qkg5Q0FTRUtBMEFnRWtFRlNBUkFJQWNnRWtFQ2RHb2lBRFVDQUVMLy8vLy9ENFVnQ253aENpQUFJQW8rQWdBZ0NrSWdpQ0VLSUJKQkFXb2hFZ3dCQ3d0QkFRVkJBQXNoQUNBSUlBY3BBd0EzQXdBZ0NDQUhLUU1JTndNSUlBTkJCU0FCUWRnQWFrRUVJQVZCQlJBTklBUkJCU0FCUWVnQWFrRUVJQVpCQlJBTkEwQWdFMEVGU0FSQUlBVWdFMEVDZENJQmFqVUNBRUtBZ0lDQUVId2dBU0FHYWpVQ0FIMGdEWDBoQ2lBQklBZHFJQW8rQWdCQ0FTQUtRaUNJZlNFTklCTkJBV29oRXd3QkN3c2dCeWdDRUVHQWdJQ0FlSEVFUUVJQklRb0RRQ0FVUVFWSUJFQWdCeUFVUVFKMGFpSUJOUUlBUXYvLy8vOFBoU0FLZkNFS0lBRWdDajRDQUNBS1FpQ0lJUW9nRkVFQmFpRVVEQUVMQ3lBQVFRSnlJUUFMSUFrZ0J5a0RBRGNEQUNBSklBY3BBd2czQXdnZ0FBdk9CQUlCZmdaL0EwQWdDa0VFU0FSQUlBQkJDQ0FCSUFwQkhHeHFRUWNnQWtFUEVBMGdBeUFLUVF4c2FpRU5RUUFoQ1NBQ05RSWNRb0NBZ0lBSWZFSWdpQ0VJQTBBZ0NVRURTQVJBSUFsQkNHb2lEa0VQU0FSQUlBZ2dBaUFPUVFKMGFqVUNBSHdoQ0FzZ0RTQUpRUUowYWlBSVBnSUFJQWhDSUlnaENDQUpRUUZxSVFrTUFRc0xJQXBCQVdvaENnd0JDd3NEUUNBTFFRUklCRUFnQ3dSQUlBVkJBRFlDQUNBRlFRQTJBZ1FnQlVFQU5nSUlCU0FGSUFBb0FnQTJBZ0FnQlNBQUtBSUVOZ0lFSUFVZ0FDZ0NDRFlDQ0F0QkFDRUNBMEFnQWtFRVNBUkFJQU1nQWtFTWJHcEJBeUFCUWZBQWFpQUNRUUowSWdrZ0MycEJBM1JxUVFJZ0JFRURFQTBnQVVId0FXb2dDV29nQzJvdEFBQUVRRUlBSVFoQkFDRUpBMEFnQ1VFRFNBUkFJQVVnQ1VFQ2RDSUthalVDQUNBRUlBcHFOUUlBZkNBSWZDRUlJQVVnQ21vZ0NENENBQ0FJUWlDSUlRZ2dDVUVCYWlFSkRBRUxDd1ZDQUNFSVFRQWhDUU5BSUFsQkEwZ0VRQ0FGSUFsQkFuUWlDbW8xQWdCQ2dJQ0FnQkI4SUFRZ0NtbzFBZ0I5SUFoOUlRZ2dCU0FLYWlBSVBnSUFRZ0VnQ0VJZ2lIMGhDQ0FKUVFGcUlRa01BUXNMQ3lBQ1FRRnFJUUlNQVFzTElBVW9BZ2hCZ0lDQWdIaHhCRUJCQUNFQ1FnRWhDQU5BSUFKQkEwZ0VRQ0FGSUFKQkFuUnFJZ2sxQWdCQy8vLy8vdytGSUFoOElRZ2dDU0FJUGdJQUlBaENJSWdoQ0NBQ1FRRnFJUUlNQVFzTElBeEJBU0FMZEhJaERBc2dCaUFISUF0c2FpSUNJQVVvQWdBMkFnQWdBaUFGS0FJRU5nSUVJQUlnQlNnQ0NEWUNDQ0FMUVFGcUlRc01BUXNMSUF3THFRRUJCSDhnQUVFQ2RDSUFJeFpxS0FJQUlRTWpEQ01WSUFCcUtBSUFJd0JCQVhSc2FpSUFJd0JxSVFRakhDTWFFQWNqR2lBQUl4b1FBU01hSUFNakdoQUJJQUFqR2lNYkVBRWpIQ01iSXhzUUFDTWJJQVFqR3hBQkl4b2hBd05BSUFFakFFZ0VRQ0FBSUFGcUlBRWdBMm9wQXdBM0F3QWdBVUVJYWlFQkRBRUxDeU1iSVFBRFFDQUNJd0JJQkVBZ0FpQUVhaUFBSUFKcUtRTUFOd01BSUFKQkNHb2hBZ3dCQ3dzTDFRRUJBMzhqSGtVRVFBOExJeGdoQVNNWklRSURRQ0FBSXdCSUJFQWdBQ0FDYWlBQUlBRnFLUU1BTndNQUlBQkJDR29oQUF3QkN3dEJBU0VBQTBBZ0FDTWVTQVJBSXhrakFDQUFRUUZyYkdvZ0FDTUFiQ0lCSXhocUl4a2dBV29RQUNBQVFRRnFJUUFNQVFzTEl4a2pBQ01lUVFGcmJHb2pIUkFNSXg1QkFXc2hBQU5BSUFCQkFFb0VRQ01kSXhrZ0FFRUJheUlCSXdCc2FpTWFFQUFqSFNNWUlBQWpBR3hxSXgwUUFDTVhJQUFqQUd4cUl4b2pIQkFBSUFBUUZpQUJJUUFNQVFzTEl4Y2pIU01jRUFCQkFCQVdRUUFrSGd1a0NBRU5meUFDUVNCSEJIOUJBUVVnQlVFd1J5QUZRU0JIY1FzRVFDQUFJQUVnQWlBRElBUWdCUkFQRHdzZ0JCQUNJQU5GQkVBUEN5QUZKQUFnQlVINEFHb2hDVUVBS0FJQUloRWhBZ05BSUFKQkEzRUVRQ0FDUVFGcUlRSU1BUXNMUVFBZ0FpQUphaUlKTmdJQVB3QkJFSFFpQmlBSlNRUkFJQWtnQm10QkVIWkJBV3BBQUJvTElBSWhDU0FGUVRCR0JFQWdBaEFTQlNBSkVCRUxRUUFvQWdBaEFnTkFJQUpCQTNFRVFDQUNRUUZxSVFJTUFRc0xRUUFnQWtFOGFpSUZOZ0lBUHdCQkVIUWlCaUFGU1FSQUlBVWdCbXRCRUhaQkFXcEFBQm9MSUFJaEJVRUFLQUlBSVFJRFFDQUNRUU54QkVBZ0FrRUJhaUVDREFFTEMwRUFJQUpCRkdvaUJqWUNBRDhBUVJCMElnd2dCa2tFUUNBR0lBeHJRUkIyUVFGcVFBQWFDeUFDSVFaQkFDZ0NBQ0VDQTBBZ0FrRURjUVJBSUFKQkFXb2hBZ3dCQ3d0QkFDQUNRUlJxSWd3MkFnQS9BRUVRZENJTklBeEpCRUFnRENBTmEwRVFka0VCYWtBQUdnc2dBaUVNUVFBb0FnQWhBZ05BSUFKQkEzRUVRQ0FDUVFGcUlRSU1BUXNMUVFBZ0FrRVVhaUlOTmdJQVB3QkJFSFFpRGlBTlNRUkFJQTBnRG10QkVIWkJBV3BBQUJvTElBSWhEVUVBS0FJQUlRSURRQ0FDUVFOeEJFQWdBa0VCYWlFQ0RBRUxDMEVBSUFKQkZHb2lEallDQUQ4QVFSQjBJZzhnRGtrRVFDQU9JQTlyUVJCMlFRRnFRQUFhQ3lBQ0lRNUJBQ2dDQUNFQ0EwQWdBa0VEY1FSQUlBSkJBV29oQWd3QkN3dEJBQ0FDUVJScUlnODJBZ0EvQUVFUWRDSUhJQTlKQkVBZ0R5QUhhMEVRZGtFQmFrQUFHZ3NnQWlFUElBTkJCWFFoQjBFQUtBSUFJUUlEUUNBQ1FRTnhCRUFnQWtFQmFpRUNEQUVMQzBFQUlBSWdCMm9pQnpZQ0FEOEFRUkIwSWdnZ0Iwa0VRQ0FISUFoclFSQjJRUUZxUUFBYUN5QUNJUWNnQTBFQmRDRUlRUUFvQWdBaEFnTkFJQUpCQTNFRVFDQUNRUUZxSVFJTUFRc0xRUUFnQWlBSWFpSUlOZ0lBUHdCQkVIUWlDaUFJU1FSQUlBZ2dDbXRCRUhaQkFXcEFBQm9MSUFJaENDQURJd0JCQVhSc0lRcEJBQ2dDQUNFQ0EwQWdBa0VEY1FSQUlBSkJBV29oQWd3QkN3dEJBQ0FDSUFwcUlnbzJBZ0EvQUVFUWRDSVNJQXBKQkVBZ0NpQVNhMEVRZGtFQmFrQUFHZ3NEUUNBRElBdEtCRUFnQ0NBTGFpQUJJQXRCQlhScUlBa2dCU0FHSUF3Z0RTQU9JQThnQnlBTFFRUjBhaUFISUFNZ0MycEJCSFJxRUJRaUNrRUJjVG9BQUNBRElBaHFJQXRxSUFwQkFYVkJBWEU2QUFBZ0MwRUJhaUVMREFFTEN3TkFJQU1nRUVvRVFDQVFJd0JCQVhSc0lnRWdBR29pQlNBSlFmZ0FhaUFCSUFKcUlnRVFBQ0FGSXdCcUlRVWdBU01BYWlFR1FRQWhBUU5BSUFFakFFZ0VRQ0FCSUFacUlBRWdCV29wQXdBM0F3QWdBVUVJYWlFQkRBRUxDeUFRUVFGcUlSQU1BUXNMSUFOQkFYUWlBU1FHUVJBa0IwR0FBU1FJSUFja0NpQUFKQWtnQWlRZ0lBTWtIeUFJSkNFZ0FSQU9KQUVnQkJBUVFRQWdFVFlDQUF2SkNBRU1meUFGUWNBQVJ5QUNRU0JIY2dSL1FRRUZJQU5CQW5RZ0JVRUJkR3hCZ0lEQUFVb0xCRUFnQUNBQklBSWdBeUFFSUFVUUR3OExJQVFRQWlBRFJRUkFEd3NnQlNRQVFRQW9BZ0FpRUNFQ0EwQWdBa0VEY1FSQUlBSkJBV29oQWd3QkN3dEJBQ0FDUVlBRmFpSUZOZ0lBUHdCQkVIUWlCaUFGU1FSQUlBVWdCbXRCRUhaQkFXcEFBQm9MSUFJaUJSQVRRUUFvQWdBaEFnTkFJQUpCQTNFRVFDQUNRUUZxSVFJTUFRc0xRUUFnQWtFOGFpSUdOZ0lBUHdCQkVIUWlEQ0FHU1FSQUlBWWdER3RCRUhaQkFXcEFBQm9MSUFJaERFRUFLQUlBSVFJRFFDQUNRUU54QkVBZ0FrRUJhaUVDREFFTEMwRUFJQUpCTUdvaUJqWUNBRDhBUVJCMElnMGdCa2tFUUNBR0lBMXJRUkIyUVFGcVFBQWFDeUFDSVExQkFDZ0NBQ0VDQTBBZ0FrRURjUVJBSUFKQkFXb2hBZ3dCQ3d0QkFDQUNRUXhxSWdZMkFnQS9BRUVRZENJT0lBWkpCRUFnQmlBT2EwRVFka0VCYWtBQUdnc2dBaUVHUVFBb0FnQWhBZ05BSUFKQkEzRUVRQ0FDUVFGcUlRSU1BUXNMUVFBZ0FrRU1haUlPTmdJQVB3QkJFSFFpQ2lBT1NRUkFJQTRnQ210QkVIWkJBV3BBQUJvTElBSWhEaUFEUVRCc0lRcEJBQ2dDQUNFQ0EwQWdBa0VEY1FSQUlBSkJBV29oQWd3QkN3dEJBQ0FDSUFwcUlnbzJBZ0EvQUVFUWRDSUhJQXBKQkVBZ0NpQUhhMEVRZGtFQmFrQUFHZ3NnQWlFS0lBTkJBblFoQjBFQUtBSUFJUUlEUUNBQ1FRTnhCRUFnQWtFQmFpRUNEQUVMQzBFQUlBSWdCMm9pQnpZQ0FEOEFRUkIwSWdnZ0Iwa0VRQ0FISUFoclFSQjJRUUZxUUFBYUN5QUNJUWNnQTBFRGJDTUFRUUYwYkNFSVFRQW9BZ0FoQWdOQUlBSkJBM0VFUUNBQ1FRRnFJUUlNQVFzTFFRQWdBaUFJYWlJSU5nSUFQd0JCRUhRaUNTQUlTUVJBSUFnZ0NXdEJFSFpCQVdwQUFCb0xJQUloQ0NNQUlRbEJBQ2dDQUNFQ0EwQWdBa0VEY1FSQUlBSkJBV29oQWd3QkN3dEJBQ0FDSUFscUlnazJBZ0EvQUVFUWRDSVJJQWxKQkVBZ0NTQVJhMEVRZGtFQmFrQUFHZ3NEUUNBRElBdEtCRUFnQnlBTGFpQUJJQXRCQlhScUlBVWdEQ0FOSUFZZ0RpQUtJQXRCREd4cUlBTkJER3dRRlNJSlFRRnhPZ0FBSUFNZ0Iyb2dDMm9nQ1VFQmRVRUJjVG9BQUNBSElBTkJBWFJxSUF0cUlBbEJBblZCQVhFNkFBQWdCeUFEUVFOc2FpQUxhaUFKUVFOMVFRRnhPZ0FBSUF0QkFXb2hDd3dCQ3dzakFFRUJkQ0VCQTBBZ0F5QVBTZ1JBSUFFZ0Qyd2lCaUFBYWlJTUl3QnFJUTBnRENBQ0VBVWdBaUFGUVlBQ2FpQUdJQWhxSWdZUUFDQU5JQUlRQlNBQ0lBVkJ3QUpxSUFZakFHb1FBQ0FNSUFWQmdBTnFJQWdnQXlBUGFpQUJiR29pQmhBQUlBMGdCVUhBQTJvZ0JpTUFhaEFBSUF3Z0FoQUZJQUlnQlVHQUJHb2dDQ0FEUVFGMElBOXFJQUZzYWlJR0VBQWdEU0FDRUFVZ0FpQUZRY0FFYWlBR0l3QnFFQUFnRDBFQmFpRVBEQUVMQ3lBRFFRSjBJZ0VrQmtFTUpBZEJ4QUFrQ0NBS0pBb2dBQ1FKSUFna0lDQURKQjhnQnlRaElBRVFEaVFCSUFRUUVFRUFJQkEyQWdBTHBRUUJDWDhnQWtINEFHb2hBMEVBS0FJQUlnb2hCUU5BSUFWQkEzRUVRQ0FGUVFGcUlRVU1BUXNMUVFBZ0F5QUZhaUlETmdJQVB3QkJFSFFpQkNBRFNRUkFJQU1nQkd0QkVIWkJBV3BBQUJvTElBSkJNRVlFUUNBRkVCSUZJQVVRRVF0QkFDZ0NBQ0VDQTBBZ0FrRURjUVJBSUFKQkFXb2hBZ3dCQ3d0QkFDQUNRVHhxSWdNMkFnQS9BRUVRZENJRUlBTkpCRUFnQXlBRWEwRVFka0VCYWtBQUdnc2dBaUVEUVFBb0FnQWhBZ05BSUFKQkEzRUVRQ0FDUVFGcUlRSU1BUXNMUVFBZ0FrRVVhaUlFTmdJQVB3QkJFSFFpQmlBRVNRUkFJQVFnQm10QkVIWkJBV3BBQUJvTElBSWhCRUVBS0FJQUlRSURRQ0FDUVFOeEJFQWdBa0VCYWlFQ0RBRUxDMEVBSUFKQkZHb2lCallDQUQ4QVFSQjBJZ2NnQmtrRVFDQUdJQWRyUVJCMlFRRnFRQUFhQ3lBQ0lRWkJBQ2dDQUNFQ0EwQWdBa0VEY1FSQUlBSkJBV29oQWd3QkN3dEJBQ0FDUVJScUlnYzJBZ0EvQUVFUWRDSUlJQWRKQkVBZ0J5QUlhMEVRZGtFQmFrQUFHZ3NnQWlFSFFRQW9BZ0FoQWdOQUlBSkJBM0VFUUNBQ1FRRnFJUUlNQVFzTFFRQWdBa0VVYWlJSU5nSUFQd0JCRUhRaUNTQUlTUVJBSUFnZ0NXdEJFSFpCQVdwQUFCb0xJQUloQ0VFQUtBSUFJUUlEUUNBQ1FRTnhCRUFnQWtFQmFpRUNEQUVMQzBFQUlBSkJGR29pQ1RZQ0FEOEFRUkIwSWdzZ0NVa0VRQ0FKSUF0clFSQjJRUUZxUUFBYUN5QUFJQVVnQXlBRUlBWWdCeUFJSUFJZ0FTQUJRUkJxRUJRaEFFRUFJQW8yQWdBZ0FBdUFBd0VJZjBFQUtBSUFJZ2doQWdOQUlBSkJBM0VFUUNBQ1FRRnFJUUlNQVFzTFFRQWdBa0dBQldvaUJqWUNBRDhBUVJCMElnTWdCa2tFUUNBR0lBTnJRUkIyUVFGcVFBQWFDeUFDSWdZUUUwRUFLQUlBSVFJRFFDQUNRUU54QkVBZ0FrRUJhaUVDREFFTEMwRUFJQUpCUEdvaUF6WUNBRDhBUVJCMElnUWdBMGtFUUNBRElBUnJRUkIyUVFGcVFBQWFDeUFDSVFOQkFDZ0NBQ0VDQTBBZ0FrRURjUVJBSUFKQkFXb2hBZ3dCQ3d0QkFDQUNRVEJxSWdRMkFnQS9BRUVRZENJRklBUkpCRUFnQkNBRmEwRVFka0VCYWtBQUdnc2dBaUVFUVFBb0FnQWhBZ05BSUFKQkEzRUVRQ0FDUVFGcUlRSU1BUXNMUVFBZ0FrRU1haUlGTmdJQVB3QkJFSFFpQnlBRlNRUkFJQVVnQjJ0QkVIWkJBV3BBQUJvTElBSWhCVUVBS0FJQUlRSURRQ0FDUVFOeEJFQWdBa0VCYWlFQ0RBRUxDMEVBSUFKQkRHb2lCellDQUQ4QVFSQjBJZ2tnQjBrRVFDQUhJQWxyUVJCMlFRRnFRQUFhQ3lBQUlBWWdBeUFFSUFVZ0FpQUJRUXdRRlNFQVFRQWdDRFlDQUNBQUN3PT1cIjtcblxuLy8gYmFzZTY0IC0+IFVpbnQ4QXJyYXksIHVzZWQgb25jZSBhdCBjdXJ2ZSBsb2FkIHRvIGRlY29kZSB0aGUgdmVuZG9yZWQgd2FzbS5cbi8vXG4vLyBQcmVmZXIgdGhlIHBsYXRmb3JtIGRlY29kZXIgKEJ1ZmZlciBpbiBOb2RlLCBhdG9iIGluIGJyb3dzZXJzL2V4dGVuc2lvbnMpIGZvclxuLy8gc3BlZWQsIGFuZCBmYWxsIGJhY2sgdG8gYSBwdXJlLUpTIGltcGxlbWVudGF0aW9uIG9ubHkgd2hlcmUgbmVpdGhlciBleGlzdHMgLS1cbi8vIGUuZy4gYSBTRVMgaGFyZGVuZWQgcmVhbG0gdGhhdCBoYXMgbm90IGVuZG93ZWQgYXRvYi9CdWZmZXIuIFRoZSBmYWxsYmFjayBrZWVwcyB0aGVcbi8vIGN1cnZlIGxvYWRhYmxlIGV2ZXJ5d2hlcmUgd2l0aG91dCBkZXBlbmRpbmcgb24gYW55IGhvc3QgYmFzZTY0IHByaW1pdGl2ZS5cblxuY29uc3QgQ0hBUlMgPSBcIkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky9cIjtcbmxldCBMT09LVVA7XG5cbmZ1bmN0aW9uIGRlY29kZVB1cmVKcyhiNjQpIHtcbiAgICBpZiAoIUxPT0tVUCkge1xuICAgICAgICBMT09LVVAgPSBuZXcgVWludDhBcnJheSgyNTYpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IENIQVJTLmxlbmd0aDsgaSsrKSBMT09LVVBbQ0hBUlMuY2hhckNvZGVBdChpKV0gPSBpO1xuICAgIH1cbiAgICBjb25zdCBsZW4gPSBiNjQubGVuZ3RoO1xuICAgIGxldCBwYWQgPSAwO1xuICAgIGlmIChsZW4gPiAwICYmIGI2NFtsZW4gLSAxXSA9PT0gXCI9XCIpIHBhZCsrO1xuICAgIGlmIChsZW4gPiAxICYmIGI2NFtsZW4gLSAyXSA9PT0gXCI9XCIpIHBhZCsrO1xuICAgIGNvbnN0IG91dExlbiA9ICgobGVuICogMykgPj4gMikgLSBwYWQ7XG4gICAgY29uc3Qgb3V0ID0gbmV3IFVpbnQ4QXJyYXkob3V0TGVuKTtcbiAgICBsZXQgbyA9IDA7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkgKz0gNCkge1xuICAgICAgICBjb25zdCBhID0gTE9PS1VQW2I2NC5jaGFyQ29kZUF0KGkpXTtcbiAgICAgICAgY29uc3QgYiA9IExPT0tVUFtiNjQuY2hhckNvZGVBdChpICsgMSldO1xuICAgICAgICBjb25zdCBjID0gTE9PS1VQW2I2NC5jaGFyQ29kZUF0KGkgKyAyKV07XG4gICAgICAgIGNvbnN0IGQgPSBMT09LVVBbYjY0LmNoYXJDb2RlQXQoaSArIDMpXTtcbiAgICAgICAgaWYgKG8gPCBvdXRMZW4pIG91dFtvKytdID0gKGEgPDwgMikgfCAoYiA+PiA0KTtcbiAgICAgICAgaWYgKG8gPCBvdXRMZW4pIG91dFtvKytdID0gKChiICYgMTUpIDw8IDQpIHwgKGMgPj4gMik7XG4gICAgICAgIGlmIChvIDwgb3V0TGVuKSBvdXRbbysrXSA9ICgoYyAmIDMpIDw8IDYpIHwgZDtcbiAgICB9XG4gICAgcmV0dXJuIG91dDtcbn1cblxuZnVuY3Rpb24gYmFzZTY0VG9VaW50OEFycmF5KGI2NCkge1xuICAgIGlmICh0eXBlb2YgQnVmZmVyICE9PSBcInVuZGVmaW5lZFwiICYmIHR5cGVvZiBCdWZmZXIuZnJvbSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgIC8vIE5vZGUgKGFuZCBOb2RlLWNvbXBhdGlibGUgcnVudGltZXMpIOKAlCBmYXN0ZXN0LlxuICAgICAgICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkoQnVmZmVyLmZyb20oYjY0LCBcImJhc2U2NFwiKSk7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgYXRvYiA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgIC8vIEJyb3dzZXJzLCBleHRlbnNpb25zLCBtb2Rlcm4gTm9kZSwgRGVuby5cbiAgICAgICAgY29uc3QgYmluID0gYXRvYihiNjQpO1xuICAgICAgICBjb25zdCBvdXQgPSBuZXcgVWludDhBcnJheShiaW4ubGVuZ3RoKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBiaW4ubGVuZ3RoOyBpKyspIG91dFtpXSA9IGJpbi5jaGFyQ29kZUF0KGkpO1xuICAgICAgICByZXR1cm4gb3V0O1xuICAgIH1cbiAgICAvLyBTRVMgaGFyZGVuZWQgcmVhbG0gb3IgYW55IGhvc3Qgd2l0aG91dCBhIGJhc2U2NCBwcmltaXRpdmUuXG4gICAgcmV0dXJuIGRlY29kZVB1cmVKcyhiNjQpO1xufVxuXG4vLyBNb2R1bGUtbG9jYWwgc2luZ2xldG9uIGNhY2hlLiBNdXN0IE5PVCBiZSBvbiBnbG9iYWxUaGlzOiBhc3NpZ25pbmcgdG8gYSBmcm96ZW5cbi8vIGdsb2JhbFRoaXMgKGUuZy4gYSBTRVMgaGFyZGVuZWQtcHJvZmlsZSByZWFsbSkgdGhyb3dzIGF0IG1vZHVsZSBsb2FkLlxubGV0IGN1cnZlX2JuMTI4ID0gbnVsbDtcblxuYXN5bmMgZnVuY3Rpb24gYnVpbGRCbjEyOChzaW5nbGVUaHJlYWQsIHBsdWdpbnMpIHtcbiAgICBpZiAoKCFzaW5nbGVUaHJlYWQpICYmIChjdXJ2ZV9ibjEyOCkpIHJldHVybiBjdXJ2ZV9ibjEyODtcblxuICAgIGxldCBibjEyOHdhc20gPSB7fTtcblxuICAgIGlmICghcGx1Z2lucykge1xuICAgICAgICAvLyBWZW5kb3JlZCwgdW5jb21wcmVzc2VkIHByZWJ1aWx0IHdhc206IHN0YXRpY2FsbHkgaW1wb3J0ZWQgKG5vIHJ1bnRpbWVcbiAgICAgICAgLy8gd2FzbWN1cnZlcyBkZXBlbmRlbmN5LCBubyBkeW5hbWljIGltcG9ydCkgYW5kIGJhc2U2NC1kZWNvZGVkIHdpdGhvdXRcbiAgICAgICAgLy8gYXRvYi9EZWNvbXByZXNzaW9uU3RyZWFtLCBzbyBpdCBsb2FkcyBpbiBOb2RlLCBicm93c2VycyBhbmQgU0VTXG4gICAgICAgIC8vIGhhcmRlbmVkIHJlYWxtcyBhbGlrZS4gUmVnZW5lcmF0ZSB0aGUgdmVuZG9yZWQgbW9kdWxlIHdpdGggYG5wbSBydW4gZ2VuLXdhc21gLlxuICAgICAgICBibjEyOHdhc20uY29kZSA9IGJhc2U2NFRvVWludDhBcnJheShjb2RlJDIpO1xuICAgICAgICBibjEyOHdhc20ucHEgPSBwcSQxO1xuICAgICAgICBibjEyOHdhc20ucHIgPSBwcSQxO1xuICAgICAgICBibjEyOHdhc20ucEcxZ2VuID0gcEcxZ2VuJDE7XG4gICAgICAgIGJuMTI4d2FzbS5wRzF6ZXJvID0gcEcxemVybyQxO1xuICAgICAgICBibjEyOHdhc20ucEcxYiA9IHBHMWIkMTtcbiAgICAgICAgYm4xMjh3YXNtLnBHMmdlbiA9IHBHMmdlbiQxO1xuICAgICAgICBibjEyOHdhc20ucEcyemVybyA9IHBHMnplcm8kMTtcbiAgICAgICAgYm4xMjh3YXNtLnBHMmIgPSBwRzJiJDE7XG4gICAgICAgIGJuMTI4d2FzbS5wT25lVCA9IHBPbmVUJDE7XG4gICAgICAgIGJuMTI4d2FzbS5wcmVQU2l6ZSA9IHByZVBTaXplJDE7XG4gICAgICAgIGJuMTI4d2FzbS5wcmVRU2l6ZSA9IHByZVFTaXplJDE7XG4gICAgICAgIGJuMTI4d2FzbS5uOHEgPSAzMjtcbiAgICAgICAgYm4xMjh3YXNtLm44ciA9IDMyO1xuICAgICAgICBibjEyOHdhc20ucSA9IHEkMTtcbiAgICAgICAgYm4xMjh3YXNtLnIgPSByJDE7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQ3VzdG9tLXBsdWdpbiBidWlsZCBwYXRoOiBidWlsZHMgdGhlIHdhc20gYXQgcnVudGltZSwgc28gaXQgbmVlZHMgdGhlXG4gICAgICAgIC8vIHdhc20gdG9vbGNoYWluLiBLZXB0IGFzIGEgZHluYW1pYyBpbXBvcnQgc28gd2FzbWJ1aWxkZXIvd2FzbWN1cnZlcyBzdGF5XG4gICAgICAgIC8vIE9QVElPTkFMIGRlcGVuZGVuY2llcyAob25seSByZXF1aXJlZCB3aGVuIGEgY2FsbGVyIHBhc3NlcyBgcGx1Z2luc2ApLlxuICAgICAgICBjb25zdCB7IE1vZHVsZUJ1aWxkZXIgfSA9IGF3YWl0IGltcG9ydCgnd2FzbWJ1aWxkZXInKTtcbiAgICAgICAgY29uc3QgeyBidWlsZEJuMTI4OiBidWlsZEJuMTI4d2FzbSB9ID0gYXdhaXQgaW1wb3J0KCd3YXNtY3VydmVzJyk7XG5cbiAgICAgICAgY29uc3QgbW9kdWxlQnVpbGRlciA9IG5ldyBNb2R1bGVCdWlsZGVyKCk7XG4gICAgICAgIG1vZHVsZUJ1aWxkZXIuc2V0TWVtb3J5KDI1KTtcbiAgICAgICAgYnVpbGRCbjEyOHdhc20obW9kdWxlQnVpbGRlcik7XG5cbiAgICAgICAgaWYgKHBsdWdpbnMpIHBsdWdpbnMobW9kdWxlQnVpbGRlcik7XG5cbiAgICAgICAgYm4xMjh3YXNtLmNvZGUgPSBtb2R1bGVCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICAgIGJuMTI4d2FzbS5wcSA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5mMW0ucHE7XG4gICAgICAgIGJuMTI4d2FzbS5wciA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5mcm0ucHE7XG4gICAgICAgIGJuMTI4d2FzbS5wRzFnZW4gPSBtb2R1bGVCdWlsZGVyLm1vZHVsZXMuYm4xMjgucEcxZ2VuO1xuICAgICAgICBibjEyOHdhc20ucEcxemVybyA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5ibjEyOC5wRzF6ZXJvO1xuICAgICAgICBibjEyOHdhc20ucEcxYiA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5ibjEyOC5wRzFiO1xuICAgICAgICBibjEyOHdhc20ucEcyZ2VuID0gbW9kdWxlQnVpbGRlci5tb2R1bGVzLmJuMTI4LnBHMmdlbjtcbiAgICAgICAgYm4xMjh3YXNtLnBHMnplcm8gPSBtb2R1bGVCdWlsZGVyLm1vZHVsZXMuYm4xMjgucEcyemVybztcbiAgICAgICAgYm4xMjh3YXNtLnBHMmIgPSBtb2R1bGVCdWlsZGVyLm1vZHVsZXMuYm4xMjgucEcyYjtcbiAgICAgICAgYm4xMjh3YXNtLnBPbmVUID0gbW9kdWxlQnVpbGRlci5tb2R1bGVzLmJuMTI4LnBPbmVUO1xuICAgICAgICBibjEyOHdhc20ucHJlUFNpemUgPSBtb2R1bGVCdWlsZGVyLm1vZHVsZXMuYm4xMjgucHJlUFNpemU7XG4gICAgICAgIGJuMTI4d2FzbS5wcmVRU2l6ZSA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5ibjEyOC5wcmVRU2l6ZTtcbiAgICAgICAgYm4xMjh3YXNtLm44cSA9IDMyO1xuICAgICAgICBibjEyOHdhc20ubjhyID0gMzI7XG4gICAgICAgIGJuMTI4d2FzbS5xID0gbW9kdWxlQnVpbGRlci5tb2R1bGVzLmJuMTI4LnE7XG4gICAgICAgIGJuMTI4d2FzbS5yID0gbW9kdWxlQnVpbGRlci5tb2R1bGVzLmJuMTI4LnI7XG4gICAgfVxuXG4gICAgLy8gQmF0Y2gtYWZmaW5lIE1TTSBoZWxwZXIgbW9kdWxlIChjdXJ2ZS1pbmRlcGVuZGVudDsgbGlua3MgYWdhaW5zdCB0aGVcbiAgICAvLyBtYWluIG1vZHVsZSdzIGV4cG9ydHMgKyBtZW1vcnkgYXQgcnVudGltZSBpbiBlYWNoIHdvcmtlcikuXG4gICAgYm4xMjh3YXNtLmJhdGNoQ29kZSA9IGJhc2U2NFRvVWludDhBcnJheShjb2RlJDEpO1xuICAgIC8vIFRoZSBiYXRjaCBtb2R1bGUncyBHTFYgcGF0aCBoYXJkY29kZXMgdGhlIGJuMjU0IGVuZG9tb3JwaGlzbSBjb25zdGFudHMuXG4gICAgYm4xMjh3YXNtLmdsdiA9IHRydWU7XG5cbiAgICBjb25zdCBwYXJhbXMgPSB7XG4gICAgICAgIG5hbWU6IFwiYm4xMjhcIixcbiAgICAgICAgd2FzbTogYm4xMjh3YXNtLFxuICAgICAgICBxOiBlKFwiMjE4ODgyNDI4NzE4MzkyNzUyMjIyNDY0MDU3NDUyNTcyNzUwODg2OTYzMTExNTcyOTc4MjM2NjI2ODkwMzc4OTQ2NDUyMjYyMDg1ODNcIiksXG4gICAgICAgIHI6IGUoXCIyMTg4ODI0Mjg3MTgzOTI3NTIyMjI0NjQwNTc0NTI1NzI3NTA4ODU0ODM2NDQwMDQxNjAzNDM0MzY5ODIwNDE4NjU3NTgwODQ5NTYxN1wiKSxcbiAgICAgICAgbjhxOiAzMixcbiAgICAgICAgbjhyOiAzMixcbiAgICAgICAgY29mYWN0b3JHMjogZShcIjMwNjQ0ZTcyZTEzMWEwMjliODUwNDViNjgxODE1ODVlMDZjZWVjZGE1NzJhMjQ4OTM0NWYyMjk5YzBmOWZhOGRcIiwgMTYpLFxuICAgICAgICBzaW5nbGVUaHJlYWQ6IHNpbmdsZVRocmVhZCA/IHRydWUgOiBmYWxzZVxuICAgIH07XG5cbiAgICBjb25zdCBjdXJ2ZSA9IGF3YWl0IGJ1aWxkRW5naW5lKHBhcmFtcyk7XG4gICAgY3VydmUudGVybWluYXRlID0gYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIXBhcmFtcy5zaW5nbGVUaHJlYWQpIHtcbiAgICAgICAgICAgIGN1cnZlX2JuMTI4ID0gbnVsbDtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMudG0udGVybWluYXRlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgaWYgKCFzaW5nbGVUaHJlYWQpIHtcbiAgICAgICAgY3VydmVfYm4xMjggPSBjdXJ2ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gY3VydmU7XG59XG5cbi8vIEFVVE8tR0VORVJBVEVEIGZyb20gd2FzbWN1cnZlcy9idWlsZC9ibHMxMjM4MV93YXNtLmpzIOKAlCBkbyBub3QgZWRpdC5cbi8vIFJlZ2VuZXJhdGUgd2l0aDogbnBtIHJ1biBnZW4td2FzbVxuLy8gJ2NvZGUnIGlzIGJhc2U2NCBvZiB0aGUgd2FzbS1vcHQgLU8yIG9wdGltaXplZCB3YXNtOyB0aGUgcmVzdCBhcmVcbi8vIHBvaW50ZXIgb2Zmc2V0cyAvIGZpZWxkIG1vZHVsaS5cbmNvbnN0IGNvZGUgPSBcIkFHRnpiUUVBQUFBQmp3RVJZQUovZndCZ0EzOS9md0JnQVg4QmYyQUVmMzkvZndCZ0JYOS9mMzkvQUdBQmZ3QmdBbjkvQVg5Z0JuOS9mMzkvZndCZ0EzOS9md0YvWUFoL2YzOS9mMzkvZndCZ0FuOStBR0FFZjM5L2Z3Ri9ZQXAvZjM5L2YzOS9mMzkvQUdBRmYzOS9mMzhCZjJBSGYzOS9mMzkvZndGL1lBbC9mMzkvZjM5L2YzOEJmMkFMZjM5L2YzOS9mMzkvZjM4QmZ3SVBBUU5sYm5ZR2JXVnRiM0o1QWdBWkE2OENyUUlBQlFJRkJnWUlDQUVBQUFvREFRSUJBUUFBQVFBQUFBQUNBZ0FGQVFNRUFRRURBQUlBQlFJRkJnWUlDQUVBQUFNQkFnRUJBQUFCQUFBQUFBSUNBQVVCQXdRQkFRTUFBZ0VBQUFJQ0FnVUZBQUFBQmdZR0FBQUJBUUVBQUFFQkFRQUFBQUFBQWdJQkFBRUFBQUFBQVFFQkFRRUxCd2tFQ1FRREF3QURBZ0FBQkFjSEFRRUhBQU1NQkFNQ0JRQUJBUUFCQVFBQUF3SUNCQU1BQWdJQ0JRVUFBQUFHQmdZQUFBRUJBUUFBQVFFQkFBQUFBQUFDQWdFQUFBQUFBQUVCQVFFQkNRUUpCQU1EQVFBREFBQUVCd2NCQVFjQkFBTUFBQVFIQndFQkJ3RUJCQVFFQkFRQUFnSUZCUUFCQUFFQkFBSUdBQU1DQkFNQUFnSUZCUUFCQVFBQkFRQUFBQUFHQUFNQ0FnUURBQUlCQXdRQkFBQUFBQUFBQUFBQUFBSUNBZ0lBQUFFQUFBQUFDQTBPRHhBQkI3NG52UUlKYVc1MGNWOWpiM0I1QUFBSmFXNTBjVjk2WlhKdkFBRUlhVzUwY1Y5dmJtVUFBd3RwYm5SeFgybHpXbVZ5YndBQ0IybHVkSEZmWlhFQUJBaHBiblJ4WDJkMFpRQUZDR2x1ZEhGZllXUmtBQVlJYVc1MGNWOXpkV0lBQndocGJuUnhYMjExYkFBSUMybHVkSEZmYzNGMVlYSmxBQWtPYVc1MGNWOXpjWFZoY21WUGJHUUFDZ2hwYm5SeFgyUnBkZ0FNRDJsdWRIRmZhVzUyWlhKelpVMXZaQUFOQ0dZeGJWOWpiM0I1QUFBSVpqRnRYM3BsY204QUFRcG1NVzFmYVhOYVpYSnZBQUlHWmpGdFgyVnhBQVFIWmpGdFgyRmtaQUFQQjJZeGJWOXpkV0lBRUFkbU1XMWZibVZuQUJFT1pqRnRYMmx6VG1WbllYUnBkbVVBR0FsbU1XMWZhWE5QYm1VQURnaG1NVzFmYzJsbmJnQVpDMll4YlY5dFVtVmtkV04wQUJJSFpqRnRYMjExYkFBVENtWXhiVjl6Y1hWaGNtVUFGQTFtTVcxZmMzRjFZWEpsVDJ4a0FCVVNaakZ0WDJaeWIyMU5iMjUwWjI5dFpYSjVBQmNRWmpGdFgzUnZUVzl1ZEdkdmJXVnllUUFXQzJZeGJWOXBiblpsY25ObEFCb0haakZ0WDI5dVpRQWJDR1l4YlY5c2IyRmtBQndQWmpGdFgzUnBiV1Z6VTJOaGJHRnlBQjBIWmpGdFgyVjRjQUFoRUdZeGJWOWlZWFJqYUVsdWRtVnljMlVBSGdobU1XMWZjM0Z5ZEFBaURHWXhiVjlwYzFOeGRXRnlaUUFqRldZeGJWOWlZWFJqYUZSdlRXOXVkR2R2YldWeWVRQWZGMll4YlY5aVlYUmphRVp5YjIxTmIyNTBaMjl0WlhKNUFDQUphVzUwY2w5amIzQjVBQ1FKYVc1MGNsOTZaWEp2QUNVSWFXNTBjbDl2Ym1VQUp3dHBiblJ5WDJseldtVnlid0FtQjJsdWRISmZaWEVBS0FocGJuUnlYMmQwWlFBcENHbHVkSEpmWVdSa0FDb0lhVzUwY2w5emRXSUFLd2hwYm5SeVgyMTFiQUFzQzJsdWRISmZjM0YxWVhKbEFDME9hVzUwY2w5emNYVmhjbVZQYkdRQUxnaHBiblJ5WDJScGRnQXZEMmx1ZEhKZmFXNTJaWEp6WlUxdlpBQXdDR1p5YlY5amIzQjVBQ1FJWm5KdFgzcGxjbThBSlFwbWNtMWZhWE5hWlhKdkFDWUdabkp0WDJWeEFDZ0habkp0WDJGa1pBQXlCMlp5YlY5emRXSUFNd2RtY20xZmJtVm5BRFFPWm5KdFgybHpUbVZuWVhScGRtVUFPd2xtY20xZmFYTlBibVVBTVFobWNtMWZjMmxuYmdBOEMyWnliVjl0VW1Wa2RXTjBBRFVIWm5KdFgyMTFiQUEyQ21aeWJWOXpjWFZoY21VQU53MW1jbTFmYzNGMVlYSmxUMnhrQURnU1puSnRYMlp5YjIxTmIyNTBaMjl0WlhKNUFEb1Fabkp0WDNSdlRXOXVkR2R2YldWeWVRQTVDMlp5YlY5cGJuWmxjbk5sQUQwSFpuSnRYMjl1WlFBK0NHWnliVjlzYjJGa0FEOFBabkp0WDNScGJXVnpVMk5oYkdGeUFFQUhabkp0WDJWNGNBQkVFR1p5YlY5aVlYUmphRWx1ZG1WeWMyVUFRUWhtY20xZmMzRnlkQUJGREdaeWJWOXBjMU54ZFdGeVpRQkdGV1p5YlY5aVlYUmphRlJ2VFc5dWRHZHZiV1Z5ZVFCQ0YyWnliVjlpWVhSamFFWnliMjFOYjI1MFoyOXRaWEo1QUVNR1puSmZZV1JrQURJR1puSmZjM1ZpQURNR1puSmZibVZuQURRR1puSmZiWFZzQUVjSlpuSmZjM0YxWVhKbEFFZ0tabkpmYVc1MlpYSnpaUUJKRFdaeVgybHpUbVZuWVhScGRtVUFTZ2RtY2w5amIzQjVBQ1FIWm5KZmVtVnlid0FsQm1aeVgyOXVaUUErQ1daeVgybHpXbVZ5YndBbUJXWnlYMlZ4QUNnTVp6RnRYMjExYkhScFpYaHdBSFVTWnpGdFgyMTFiSFJwWlhod1gyTm9kVzVyQUhRU1p6RnRYMjExYkhScFpYaHdRV1ptYVc1bEFIY1laekZ0WDIxMWJIUnBaWGh3UVdabWFXNWxYMk5vZFc1ckFIWUtaekZ0WDJseldtVnlid0JNRUdjeGJWOXBjMXBsY205QlptWnBibVVBU3dabk1XMWZaWEVBVkF0bk1XMWZaWEZOYVhobFpBQlRER2N4YlY5bGNVRm1abWx1WlFCU0NHY3hiVjlqYjNCNUFGQU9aekZ0WDJOdmNIbEJabVpwYm1VQVR3aG5NVzFmZW1WeWJ3Qk9EbWN4YlY5NlpYSnZRV1ptYVc1bEFFMEtaekZ0WDJSdmRXSnNaUUJXRUdjeGJWOWtiM1ZpYkdWQlptWnBibVVBVlFkbk1XMWZZV1JrQUZrTVp6RnRYMkZrWkUxcGVHVmtBRmdOWnpGdFgyRmtaRUZtWm1sdVpRQlhCMmN4YlY5dVpXY0FXdzFuTVcxZmJtVm5RV1ptYVc1bEFGb0haekZ0WDNOMVlnQmVER2N4YlY5emRXSk5hWGhsWkFCZERXY3hiVjl6ZFdKQlptWnBibVVBWEJKbk1XMWZabkp2YlUxdmJuUm5iMjFsY25rQVlCaG5NVzFmWm5KdmJVMXZiblJuYjIxbGNubEJabVpwYm1VQVh4Qm5NVzFmZEc5TmIyNTBaMjl0WlhKNUFHSVdaekZ0WDNSdlRXOXVkR2R2YldWeWVVRm1abWx1WlFCaEQyY3hiVjkwYVcxbGMxTmpZV3hoY2dCNEZXY3hiVjkwYVcxbGMxTmpZV3hoY2tGbVptbHVaUUI1RFdjeGJWOXViM0p0WVd4cGVtVUFad3BuTVcxZlRFVk5kRzlWQUdrS1p6RnRYMHhGVFhSdlF3QnFDbWN4YlY5VmRHOU1SVTBBYXdwbk1XMWZRM1J2VEVWTkFHd1BaekZ0WDJKaGRHTm9URVZOZEc5VkFHMFBaekZ0WDJKaGRHTm9URVZOZEc5REFHNFBaekZ0WDJKaGRHTm9WWFJ2VEVWTkFHOFBaekZ0WDJKaGRHTm9RM1J2VEVWTkFIQU1aekZ0WDNSdlFXWm1hVzVsQUdNT1p6RnRYM1J2U21GamIySnBZVzRBVVJGbk1XMWZZbUYwWTJoVWIwRm1abWx1WlFCbUUyY3hiVjlpWVhSamFGUnZTbUZqYjJKcFlXNEFjUXRuTVcxZmFXNURkWEoyWlFCbEVXY3hiVjlwYmtOMWNuWmxRV1ptYVc1bEFHUVhabkp0WDE5eVpYWmxjbk5sVUdWeWJYVjBZWFJwYjI0QWVnZG1jbTFmWm1aMEFIMElabkp0WDJsbVpuUUFmZ3BtY20xZmNtRjNabVowQUhzTFpuSnRYMlptZEVwdmFXNEFmdzVtY20xZlptWjBTbTlwYmtWNGRBQ0FBUkZtY20xZlptWjBTbTlwYmtWNGRFbHVkZ0NCQVFwbWNtMWZabVowVFdsNEFJSUJER1p5YlY5bVpuUkdhVzVoYkFDREFSMW1jbTFmY0hKbGNHRnlaVXhoWjNKaGJtZGxSWFpoYkhWaGRHbHZiZ0NFQVFod2IyeGZlbVZ5YndDRkFROXdiMnhmWTI5dWMzUnlkV04wVEVNQWhnRU1jV0Z3WDJKMWFXeGtRVUpEQUljQkMzRmhjRjlxYjJsdVFVSkRBSWdCREhGaGNGOWlZWFJqYUVGa1pBQ0pBUXBtTW0xZmFYTmFaWEp2QUVzSlpqSnRYMmx6VDI1bEFJb0JDR1l5YlY5NlpYSnZBRTBIWmpKdFgyOXVaUUNMQVFobU1tMWZZMjl3ZVFDTUFRZG1NbTFmYlhWc0FJMEJDR1l5YlY5dGRXd3hBSTRCQ21ZeWJWOXpjWFZoY21VQWp3RUhaakp0WDJGa1pBQ1FBUWRtTW0xZmMzVmlBSkVCQjJZeWJWOXVaV2NBa2dFSVpqSnRYM05wWjI0QWxRRU5aakp0WDJOdmJtcDFaMkYwWlFCYUVtWXliVjltY205dFRXOXVkR2R2YldWeWVRQmZFR1l5YlY5MGIwMXZiblJuYjIxbGNua0FZUVptTW0xZlpYRUFVZ3RtTW0xZmFXNTJaWEp6WlFDVEFRZG1NbTFmWlhod0FKZ0JEMll5YlY5MGFXMWxjMU5qWVd4aGNnQ1VBUkJtTW0xZlltRjBZMmhKYm5abGNuTmxBSmNCQ0dZeWJWOXpjWEowQUprQkRHWXliVjlwYzFOeGRXRnlaUUNhQVE1bU1tMWZhWE5PWldkaGRHbDJaUUNXQVF4bk1tMWZiWFZzZEdsbGVIQUF3Z0VTWnpKdFgyMTFiSFJwWlhod1gyTm9kVzVyQU1FQkVtY3liVjl0ZFd4MGFXVjRjRUZtWm1sdVpRREVBUmhuTW0xZmJYVnNkR2xsZUhCQlptWnBibVZmWTJoMWJtc0F3d0VLWnpKdFgybHpXbVZ5YndDY0FSQm5NbTFmYVhOYVpYSnZRV1ptYVc1bEFKc0JCbWN5YlY5bGNRQ2tBUXRuTW0xZlpYRk5hWGhsWkFDakFReG5NbTFmWlhGQlptWnBibVVBb2dFSVp6SnRYMk52Y0hrQW9BRU9aekp0WDJOdmNIbEJabVpwYm1VQW53RUlaekp0WDNwbGNtOEFuZ0VPWnpKdFgzcGxjbTlCWm1acGJtVUFuUUVLWnpKdFgyUnZkV0pzWlFDbUFSQm5NbTFmWkc5MVlteGxRV1ptYVc1bEFLVUJCMmN5YlY5aFpHUUFxUUVNWnpKdFgyRmtaRTFwZUdWa0FLZ0JEV2N5YlY5aFpHUkJabVpwYm1VQXB3RUhaekp0WDI1bFp3Q3JBUTFuTW0xZmJtVm5RV1ptYVc1bEFLb0JCMmN5YlY5emRXSUFyZ0VNWnpKdFgzTjFZazFwZUdWa0FLMEJEV2N5YlY5emRXSkJabVpwYm1VQXJBRVNaekp0WDJaeWIyMU5iMjUwWjI5dFpYSjVBTEFCR0djeWJWOW1jbTl0VFc5dWRHZHZiV1Z5ZVVGbVptbHVaUUN2QVJCbk1tMWZkRzlOYjI1MFoyOXRaWEo1QUxJQkZtY3liVjkwYjAxdmJuUm5iMjFsY25sQlptWnBibVVBc1FFUFp6SnRYM1JwYldWelUyTmhiR0Z5QU1VQkZXY3liVjkwYVcxbGMxTmpZV3hoY2tGbVptbHVaUURHQVExbk1tMWZibTl5YldGc2FYcGxBTGNCQ21jeWJWOU1SVTEwYjFVQXVBRUtaekp0WDB4RlRYUnZRd0M1QVFwbk1tMWZWWFJ2VEVWTkFMb0JDbWN5YlY5RGRHOU1SVTBBdXdFUFp6SnRYMkpoZEdOb1RFVk5kRzlWQUx3QkQyY3liVjlpWVhSamFFeEZUWFJ2UXdDOUFROW5NbTFmWW1GMFkyaFZkRzlNUlUwQXZnRVBaekp0WDJKaGRHTm9RM1J2VEVWTkFMOEJER2N5YlY5MGIwRm1abWx1WlFDekFRNW5NbTFmZEc5S1lXTnZZbWxoYmdDaEFSRm5NbTFmWW1GMFkyaFViMEZtWm1sdVpRQzJBUk5uTW0xZlltRjBZMmhVYjBwaFkyOWlhV0Z1QU1BQkMyY3liVjlwYmtOMWNuWmxBTFVCRVdjeWJWOXBia04xY25abFFXWm1hVzVsQUxRQkMyY3hiVjkwYVcxbGMwWnlBTWNCRjJjeGJWOWZjbVYyWlhKelpWQmxjbTExZEdGMGFXOXVBTWdCQjJjeGJWOW1ablFBeWdFSVp6RnRYMmxtWm5RQXl3RUtaekZ0WDNKaGQyWm1kQURKQVF0bk1XMWZabVowU205cGJnRE1BUTVuTVcxZlptWjBTbTlwYmtWNGRBRE5BUkZuTVcxZlptWjBTbTlwYmtWNGRFbHVkZ0RPQVFwbk1XMWZabVowVFdsNEFNOEJER2N4YlY5bVpuUkdhVzVoYkFEUUFSMW5NVzFmY0hKbGNHRnlaVXhoWjNKaGJtZGxSWFpoYkhWaGRHbHZiZ0RSQVF0bk1tMWZkR2x0WlhOR2NnRFNBUmRuTW0xZlgzSmxkbVZ5YzJWUVpYSnRkWFJoZEdsdmJnRFRBUWRuTW0xZlptWjBBTlVCQ0djeWJWOXBabVowQU5ZQkNtY3liVjl5WVhkbVpuUUExQUVMWnpKdFgyWm1kRXB2YVc0QTF3RU9aekp0WDJabWRFcHZhVzVGZUhRQTJBRVJaekp0WDJabWRFcHZhVzVGZUhSSmJuWUEyUUVLWnpKdFgyWm1kRTFwZUFEYUFReG5NbTFmWm1aMFJtbHVZV3dBMndFZFp6SnRYM0J5WlhCaGNtVk1ZV2R5WVc1blpVVjJZV3gxWVhScGIyNEEzQUVSWnpGdFgzUnBiV1Z6Um5KQlptWnBibVVBM1FFUlp6SnRYM1JwYldWelJuSkJabVpwYm1VQTNnRVJabkp0WDJKaGRHTm9RWEJ3YkhsTFpYa0Ezd0VSWnpGdFgySmhkR05vUVhCd2JIbExaWGtBNEFFV1p6RnRYMkpoZEdOb1FYQndiSGxMWlhsTmFYaGxaQURoQVJGbk1tMWZZbUYwWTJoQmNIQnNlVXRsZVFEaUFSWm5NbTFmWW1GMFkyaEJjSEJzZVV0bGVVMXBlR1ZrQU9NQkNtWTJiVjlwYzFwbGNtOEE1UUVKWmpadFgybHpUMjVsQU9ZQkNHWTJiVjk2WlhKdkFPY0JCMlkyYlY5dmJtVUE2QUVJWmpadFgyTnZjSGtBNlFFSFpqWnRYMjExYkFEcUFRcG1ObTFmYzNGMVlYSmxBT3NCQjJZMmJWOWhaR1FBN0FFSFpqWnRYM04xWWdEdEFRZG1ObTFmYm1WbkFPNEJDR1kyYlY5emFXZHVBTzhCRW1ZMmJWOW1jbTl0VFc5dWRHZHZiV1Z5ZVFDd0FSQm1ObTFmZEc5TmIyNTBaMjl0WlhKNUFMSUJCbVkyYlY5bGNRRHdBUXRtTm0xZmFXNTJaWEp6WlFEeEFRZG1ObTFmWlhod0FQVUJEMlkyYlY5MGFXMWxjMU5qWVd4aGNnRHlBUkJtTm0xZlltRjBZMmhKYm5abGNuTmxBUFFCRG1ZMmJWOXBjMDVsWjJGMGFYWmxBUE1CQ21aMGJWOXBjMXBsY204QTl3RUpablJ0WDJselQyNWxBUGdCQ0daMGJWOTZaWEp2QVBrQkIyWjBiVjl2Ym1VQStnRUlablJ0WDJOdmNIa0Erd0VIWm5SdFgyMTFiQUQ4QVFobWRHMWZiWFZzTVFEOUFRcG1kRzFmYzNGMVlYSmxBUDRCQjJaMGJWOWhaR1FBL3dFSFpuUnRYM04xWWdDQUFnZG1kRzFmYm1WbkFJRUNDR1owYlY5emFXZHVBSWdDRFdaMGJWOWpiMjVxZFdkaGRHVUFnZ0lTWm5SdFgyWnliMjFOYjI1MFoyOXRaWEo1QUlRQ0VHWjBiVjkwYjAxdmJuUm5iMjFsY25rQWd3SUdablJ0WDJWeEFJVUNDMlowYlY5cGJuWmxjbk5sQUlZQ0IyWjBiVjlsZUhBQWl3SVBablJ0WDNScGJXVnpVMk5oYkdGeUFJY0NFR1owYlY5aVlYUmphRWx1ZG1WeWMyVUFpZ0lJWm5SdFgzTnhjblFBakFJTVpuUnRYMmx6VTNGMVlYSmxBSTBDRG1aMGJWOXBjMDVsWjJGMGFYWmxBSWtDRVdaMGJWOW1jbTlpWlc1cGRYTk5ZWEF3QUpJQ0VXWjBiVjltY205aVpXNXBkWE5OWVhBeEFKTUNFV1owYlY5bWNtOWlaVzVwZFhOTllYQXlBSlFDRVdaMGJWOW1jbTlpWlc1cGRYTk5ZWEF6QUpVQ0VXWjBiVjltY205aVpXNXBkWE5OWVhBMEFKWUNFV1owYlY5bWNtOWlaVzVwZFhOTllYQTFBSmNDRVdaMGJWOW1jbTlpWlc1cGRYTk5ZWEEyQUpnQ0VXWjBiVjltY205aVpXNXBkWE5OWVhBM0FKa0NFV1owYlY5bWNtOWlaVzVwZFhOTllYQTRBSm9DRVdaMGJWOW1jbTlpWlc1cGRYTk5ZWEE1QUpzQ0UySnNjekV5TXpneFgzQmhhWEpwYm1kRmNURUFwd0lUWW14ek1USXpPREZmY0dGcGNtbHVaMFZ4TWdDb0FoTmliSE14TWpNNE1WOXdZV2x5YVc1blJYRXpBS2tDRTJKc2N6RXlNemd4WDNCaGFYSnBibWRGY1RRQXFnSVRZbXh6TVRJek9ERmZjR0ZwY21sdVowVnhOUUNyQWhCaWJITXhNak00TVY5d1lXbHlhVzVuQUt3Q0VtSnNjekV5TXpneFgzQnlaWEJoY21WSE1RQ2dBaEppYkhNeE1qTTRNVjl3Y21Wd1lYSmxSeklBb1FJVFlteHpNVEl6T0RGZmJXbHNiR1Z5VEc5dmNBQ2lBaHhpYkhNeE1qTTRNVjltYVc1aGJFVjRjRzl1Wlc1MGFXRjBhVzl1QUtZQ0gySnNjekV5TXpneFgyWnBibUZzUlhod2IyNWxiblJwWVhScGIyNVBiR1FBb3dJYVlteHpNVEl6T0RGZlgyTjVZMnh2ZEc5dGFXTlRjWFZoY21VQXBBSWFZbXh6TVRJek9ERmZYMk41WTJ4dmRHOXRhV05GZUhCZmR6QUFwUUlJWmpadFgyMTFiREVBamdJSlpqWnRYMjExYkRBeEFJOENDbVowYlY5dGRXd3dNVFFBa0FJUlp6RnRYMmx1UjNKdmRYQkJabVpwYm1VQW5BSUxaekZ0WDJsdVIzSnZkWEFBblFJUlp6SnRYMmx1UjNKdmRYQkJabVpwYm1VQW5nSUxaekp0WDJsdVIzSnZkWEFBbndJSzdkZ0VyUUkrQUNBQklBQXBBd0EzQXdBZ0FTQUFLUU1JTndNSUlBRWdBQ2tERURjREVDQUJJQUFwQXhnM0F4Z2dBU0FBS1FNZ053TWdJQUVnQUNrREtEY0RLQXNzQUNBQVFnQTNBd0FnQUVJQU53TUlJQUJDQURjREVDQUFRZ0EzQXhnZ0FFSUFOd01nSUFCQ0FEY0RLQXRFQUNBQUtRTW9VQVIrSUFBcEF5QlFCSDRnQUNrREdGQUVmaUFBS1FNUVVBUitJQUFwQXdoUUJINGdBQ2tEQUFWQ0FRc0ZRZ0VMQlVJQkN3VkNBUXNGUWdFTFVBc3NBQ0FBUWdFM0F3QWdBRUlBTndNSUlBQkNBRGNERUNBQVFnQTNBeGdnQUVJQU53TWdJQUJDQURjREtBdGlBQ0FBS1FNb0lBRXBBeWhSQkg4Z0FDa0RJQ0FCS1FNZ1VRUi9JQUFwQXhnZ0FTa0RHRkVFZnlBQUtRTVFJQUVwQXhCUkJIOGdBQ2tEQ0NBQktRTUlVUVIvSUFBcEF3QWdBU2tEQUZFRlFRQUxCVUVBQ3dWQkFBc0ZRUUFMQlVFQUN3dTNBUUFnQUNrREtDQUJLUU1vVkFSL1FRQUZJQUFwQXlnZ0FTa0RLRllFZjBFQkJTQUFLUU1nSUFFcEF5QlVCSDlCQUFVZ0FDa0RJQ0FCS1FNZ1ZnUi9RUUVGSUFBcEF4Z2dBU2tER0ZRRWYwRUFCU0FBS1FNWUlBRXBBeGhXQkg5QkFRVWdBQ2tERUNBQktRTVFWQVIvUVFBRklBQXBBeEFnQVNrREVGWUVmMEVCQlNBQUtRTUlJQUVwQXdoVUJIOUJBQVVnQUNrRENDQUJLUU1JVmdSL1FRRUZJQUFwQXdBZ0FTa0RBRm9MQ3dzTEN3c0xDd3NMQzZRQ0FRRitJQUlnQURVQ0FDQUJOUUlBZkNJRFBnSUFJQUlnQURVQ0JDQUJOUUlFZkNBRFFpQ0lmQ0lEUGdJRUlBSWdBRFVDQ0NBQk5RSUlmQ0FEUWlDSWZDSURQZ0lJSUFJZ0FEVUNEQ0FCTlFJTWZDQURRaUNJZkNJRFBnSU1JQUlnQURVQ0VDQUJOUUlRZkNBRFFpQ0lmQ0lEUGdJUUlBSWdBRFVDRkNBQk5RSVVmQ0FEUWlDSWZDSURQZ0lVSUFJZ0FEVUNHQ0FCTlFJWWZDQURRaUNJZkNJRFBnSVlJQUlnQURVQ0hDQUJOUUljZkNBRFFpQ0lmQ0lEUGdJY0lBSWdBRFVDSUNBQk5RSWdmQ0FEUWlDSWZDSURQZ0lnSUFJZ0FEVUNKQ0FCTlFJa2ZDQURRaUNJZkNJRFBnSWtJQUlnQURVQ0tDQUJOUUlvZkNBRFFpQ0lmQ0lEUGdJb0lBSWdBRFVDTENBQk5RSXNmQ0FEUWlDSWZDSURQZ0lzSUFOQ0lJaW5DL2dDQVFGK0lBSWdBRFVDQUNBQk5RSUFmU0lEUXYvLy8vOFBnejRDQUNBQ0lBQTFBZ1FnQVRVQ0JIMGdBMElnaDN3aUEwTC8vLy8vRDRNK0FnUWdBaUFBTlFJSUlBRTFBZ2g5SUFOQ0lJZDhJZ05DLy8vLy93K0RQZ0lJSUFJZ0FEVUNEQ0FCTlFJTWZTQURRaUNIZkNJRFF2Ly8vLzhQZ3o0Q0RDQUNJQUExQWhBZ0FUVUNFSDBnQTBJZ2gzd2lBMEwvLy8vL0Q0TStBaEFnQWlBQU5RSVVJQUUxQWhSOUlBTkNJSWQ4SWdOQy8vLy8vdytEUGdJVUlBSWdBRFVDR0NBQk5RSVlmU0FEUWlDSGZDSURRdi8vLy84UGd6NENHQ0FDSUFBMUFod2dBVFVDSEgwZ0EwSWdoM3dpQTBMLy8vLy9ENE0rQWh3Z0FpQUFOUUlnSUFFMUFpQjlJQU5DSUlkOElnTkMvLy8vL3crRFBnSWdJQUlnQURVQ0pDQUJOUUlrZlNBRFFpQ0hmQ0lEUXYvLy8vOFBnejRDSkNBQ0lBQTFBaWdnQVRVQ0tIMGdBMElnaDN3aUEwTC8vLy8vRDRNK0FpZ2dBaUFBTlFJc0lBRTFBaXg5SUFOQ0lJZDhJZ05DLy8vLy93K0RQZ0lzSUFOQ0lJZW5DODRmQVJsK0lBUWdBRFVDQUNJRklBRTFBZ0FpQm40Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0FpQURQZ0lBSUFSQ0lJZ2hBeUFESUFVZ0FUVUNCQ0lIZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBQTFBZ1FpQ0NBR2ZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QUNJQVErQWdRZ0EwSWdpQ0VFSUFRZ0JTQUJOUUlJSWdsK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdCeUFJZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBQTFBZ2dpQ2lBR2ZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUNJQU0rQWdnZ0JFSWdpQ0VESUFNZ0JTQUJOUUlNSWd0K0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdDQ0FKZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBY2dDbjRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBQU5RSU1JZ3dnQm40Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0FpQUVQZ0lNSUFOQ0lJZ2hCQ0FFSUFVZ0FUVUNFQ0lOZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBZ2dDMzRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBSklBcCtJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnQnlBTWZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQUExQWhBaURpQUdmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FDSUFNK0FoQWdCRUlnaUNFRElBTWdCU0FCTlFJVUlnOStJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nQ0NBTmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQW9nQzM0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QUpJQXgrSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0J5QU9maUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFBMUFoUWlFQ0FHZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBQ0lBUStBaFFnQTBJZ2lDRUVJQVFnQlNBQk5RSVlJaEYrSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0NDQVBmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUFvZ0RYNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FMSUF4K0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdDU0FPZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBY2dFSDRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBQU5RSVlJaElnQm40Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0FpQURQZ0lZSUFSQ0lJZ2hBeUFESUFVZ0FUVUNIQ0lUZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBZ2dFWDRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBS0lBOStJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nRENBTmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQXNnRG40Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QUpJQkIrSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0J5QVNmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFBMUFod2lGQ0FHZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBQ0lBUStBaHdnQTBJZ2lDRUVJQVFnQlNBQk5RSWdJaFYrSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0NDQVRmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUFvZ0VYNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FNSUE5K0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdEU0FPZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBc2dFSDRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBSklCSitJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnQnlBVWZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQUExQWlBaUZpQUdmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FDSUFNK0FpQWdCRUlnaUNFRElBTWdCU0FCTlFJa0loZCtJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nQ0NBVmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQW9nRTM0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QU1JQkYrSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0RpQVBmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUEwZ0VINGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBeUFMSUJKK0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdDU0FVZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBY2dGbjRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBQU5RSWtJaGdnQm40Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0FpQUVQZ0lrSUFOQ0lJZ2hCQ0FFSUFVZ0FUVUNLQ0laZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBZ2dGMzRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBS0lCVitJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnRENBVGZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQTRnRVg0Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0JDQVBJQkIrSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0RTQVNmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUFzZ0ZINGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FKSUJaK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdCeUFZZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBQTFBaWdpR2lBR2ZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUNJQU0rQWlnZ0JFSWdpQ0VESUFNZ0JTQUJOUUlzSWh0K0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdDQ0FaZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBb2dGMzRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBTUlCVitJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nRGlBVGZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQkFnRVg0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QVBJQkorSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0RTQVVmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFzZ0ZuNGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBeUFKSUJoK0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdCeUFhZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBQTFBaXdpQlNBR2ZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QUNJQVErQWl3Z0EwSWdpQ0VFSUFRZ0NDQWJmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUFvZ0dYNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FNSUJkK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdEaUFWZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlCQWdFMzRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBUklCSitJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnRHlBVWZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQTBnRm40Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0JDQUxJQmgrSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0NTQWFmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUFVZ0IzNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdBaUFEUGdJd0lBUkNJSWdoQXlBRElBb2dHMzRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBTUlCbCtJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nRGlBWGZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQkFnRlg0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QVNJQk4rSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0VTQVVmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUE4Z0ZuNGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBeUFOSUJoK0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdDeUFhZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBVWdDWDRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQWlBRVBnSTBJQU5DSUlnaEJDQUVJQXdnRzM0Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0JDQU9JQmwrSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0VDQVhmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUJJZ0ZYNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FUSUJSK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdFU0FXZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBOGdHSDRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBTklCcCtJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnQlNBTGZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUNJQU0rQWpnZ0JFSWdpQ0VESUFNZ0RpQWJmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUJBZ0dYNGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBeUFTSUJkK0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdGQ0FWZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElCTWdGbjRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBUklCaCtJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nRHlBYWZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQVVnRFg0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0FpQUVQZ0k4SUFOQ0lJZ2hCQ0FFSUJBZ0czNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FTSUJsK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdGQ0FYZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlCVWdGbjRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBVElCaCtJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnRVNBYWZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQVVnRDM0Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0FpQURQZ0pBSUFSQ0lJZ2hBeUFESUJJZ0czNGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBeUFVSUJsK0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdGaUFYZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElCVWdHSDRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBVElCcCtJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nQlNBUmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QUNJQVErQWtRZ0EwSWdpQ0VFSUFRZ0ZDQWJmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUJZZ0dYNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FYSUJoK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdGU0FhZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBVWdFMzRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQWlBRFBnSklJQVJDSUlnaEF5QURJQllnRzM0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QVlJQmwrSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0Z5QWFmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFVZ0ZYNGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBaUFFUGdKTUlBTkNJSWdoQkNBRUlCZ2dHMzRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBWklCcCtJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnQlNBWGZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUNJQU0rQWxBZ0JFSWdpQ0VESUFNZ0dpQWJmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFVZ0dYNGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBaUFFUGdKVUlBTkNJSWdoQkNBRUlBVWdHMzRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQWlBRFBnSllJQUlnQkQ0Q1hBdThHUUVRZmlBRElBQTFBZ0FpQmlBR2ZpQUNRdi8vLy84UGczd2lBa0lnaUh3aEF5QUJJQUkrQWdBZ0F5SUVRaUNJSVFVZ0FEVUNCQ0lISUFaK0lnSkNJSWhDQVlZZ0FrTC8vLy8vRDROQ0FZWWlBa0lnaUh3aEF5QURJQUpDLy8vLy93K0RJQVJDLy8vLy93K0RmQ0lDUWlDSWZDQUZmQ0VESUFFZ0FqNENCQ0FESWdSQ0lJZ2hCU0FBTlFJSUlnZ2dCbjRpQWtJZ2lFSUJoaUFDUXYvLy8vOFBnMElCaGlJQ1FpQ0lmQ0VESUFNZ0J5QUhmaUFDUXYvLy8vOFBnM3dpQWtJZ2lId2hBeUFESUFKQy8vLy8vdytESUFSQy8vLy8vdytEZkNJQ1FpQ0lmQ0FGZkNFRElBRWdBajRDQ0NBRElnUkNJSWdoQlNBQU5RSU1JZ2tnQm40aUFrSWdpQ0VESUFNZ0J5QUlmaUFDUXYvLy8vOFBnM3dpQWtJZ2lIeENBWVlnQWtMLy8vLy9ENE5DQVlZaUFrSWdpSHdoQXlBRElBSkMvLy8vL3crRElBUkMvLy8vL3crRGZDSUNRaUNJZkNBRmZDRURJQUVnQWo0Q0RDQURJZ1JDSUlnaEJTQUFOUUlRSWdvZ0JuNGlBa0lnaUNFRElBTWdCeUFKZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHhDQVlZZ0FrTC8vLy8vRDROQ0FZWWlBa0lnaUh3aEF5QURJQWdnQ0g0Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUNRdi8vLy84UGd5QUVRdi8vLy84UGczd2lBa0lnaUh3Z0JYd2hBeUFCSUFJK0FoQWdBeUlFUWlDSUlRVWdBRFVDRkNJTElBWitJZ0pDSUlnaEF5QURJQWNnQ240Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUlJQWwrSUFKQy8vLy8vdytEZkNJQ1FpQ0lmRUlCaGlBQ1F2Ly8vLzhQZzBJQmhpSUNRaUNJZkNFRElBTWdBa0wvLy8vL0Q0TWdCRUwvLy8vL0Q0TjhJZ0pDSUloOElBVjhJUU1nQVNBQ1BnSVVJQU1pQkVJZ2lDRUZJQUExQWhnaURDQUdmaUlDUWlDSUlRTWdBeUFISUF0K0lBSkMvLy8vL3crRGZDSUNRaUNJZkNFRElBTWdDQ0FLZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHhDQVlZZ0FrTC8vLy8vRDROQ0FZWWlBa0lnaUh3aEF5QURJQWtnQ1g0Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUNRdi8vLy84UGd5QUVRdi8vLy84UGczd2lBa0lnaUh3Z0JYd2hBeUFCSUFJK0FoZ2dBeUlFUWlDSUlRVWdBRFVDSENJTklBWitJZ0pDSUlnaEF5QURJQWNnREg0Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUlJQXQrSUFKQy8vLy8vdytEZkNJQ1FpQ0lmQ0VESUFNZ0NTQUtmaUFDUXYvLy8vOFBnM3dpQWtJZ2lIeENBWVlnQWtMLy8vLy9ENE5DQVlZaUFrSWdpSHdoQXlBRElBSkMvLy8vL3crRElBUkMvLy8vL3crRGZDSUNRaUNJZkNBRmZDRURJQUVnQWo0Q0hDQURJZ1JDSUlnaEJTQUFOUUlnSWc0Z0JuNGlBa0lnaUNFRElBTWdCeUFOZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHdoQXlBRElBZ2dESDRnQWtMLy8vLy9ENE44SWdKQ0lJaDhJUU1nQXlBSklBdCtJQUpDLy8vLy93K0RmQ0lDUWlDSWZFSUJoaUFDUXYvLy8vOFBnMElCaGlJQ1FpQ0lmQ0VESUFNZ0NpQUtmaUFDUXYvLy8vOFBnM3dpQWtJZ2lId2hBeUFESUFKQy8vLy8vdytESUFSQy8vLy8vdytEZkNJQ1FpQ0lmQ0FGZkNFRElBRWdBajRDSUNBRElnUkNJSWdoQlNBQU5RSWtJZzhnQm40aUFrSWdpQ0VESUFNZ0J5QU9maUFDUXYvLy8vOFBnM3dpQWtJZ2lId2hBeUFESUFnZ0RYNGdBa0wvLy8vL0Q0TjhJZ0pDSUloOElRTWdBeUFKSUF4K0lBSkMvLy8vL3crRGZDSUNRaUNJZkNFRElBTWdDaUFMZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHhDQVlZZ0FrTC8vLy8vRDROQ0FZWWlBa0lnaUh3aEF5QURJQUpDLy8vLy93K0RJQVJDLy8vLy93K0RmQ0lDUWlDSWZDQUZmQ0VESUFFZ0FqNENKQ0FESWdSQ0lJZ2hCU0FBTlFJb0loQWdCbjRpQWtJZ2lDRURJQU1nQnlBUGZpQUNRdi8vLy84UGczd2lBa0lnaUh3aEF5QURJQWdnRG40Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUpJQTErSUFKQy8vLy8vdytEZkNJQ1FpQ0lmQ0VESUFNZ0NpQU1maUFDUXYvLy8vOFBnM3dpQWtJZ2lIeENBWVlnQWtMLy8vLy9ENE5DQVlZaUFrSWdpSHdoQXlBRElBc2dDMzRnQWtMLy8vLy9ENE44SWdKQ0lJaDhJUU1nQXlBQ1F2Ly8vLzhQZ3lBRVF2Ly8vLzhQZzN3aUFrSWdpSHdnQlh3aEF5QUJJQUkrQWlnZ0F5SUVRaUNJSVFVZ0FEVUNMQ0lSSUFaK0lnSkNJSWdoQXlBRElBY2dFSDRnQWtMLy8vLy9ENE44SWdKQ0lJaDhJUU1nQXlBSUlBOStJQUpDLy8vLy93K0RmQ0lDUWlDSWZDRURJQU1nQ1NBT2ZpQUNRdi8vLy84UGczd2lBa0lnaUh3aEF5QURJQW9nRFg0Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUxJQXgrSUFKQy8vLy8vdytEZkNJQ1FpQ0lmRUlCaGlBQ1F2Ly8vLzhQZzBJQmhpSUNRaUNJZkNFRElBTWdBa0wvLy8vL0Q0TWdCRUwvLy8vL0Q0TjhJZ0pDSUloOElBVjhJUU1nQVNBQ1BnSXNJQU1pQkVJZ2lDRUZJQWNnRVg0aUFrSWdpQ0VESUFNZ0NDQVFmaUFDUXYvLy8vOFBnM3dpQWtJZ2lId2hBeUFESUFrZ0QzNGdBa0wvLy8vL0Q0TjhJZ0pDSUloOElRTWdBeUFLSUE1K0lBSkMvLy8vL3crRGZDSUNRaUNJZkNFRElBTWdDeUFOZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHhDQVlZZ0FrTC8vLy8vRDROQ0FZWWlBa0lnaUh3aEF5QURJQXdnREg0Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUNRdi8vLy84UGd5QUVRdi8vLy84UGczd2lBa0lnaUh3Z0JYd2hBeUFCSUFJK0FqQWdBeUlFUWlDSUlRVWdDQ0FSZmlJQ1FpQ0lJUU1nQXlBSklCQitJQUpDLy8vLy93K0RmQ0lDUWlDSWZDRURJQU1nQ2lBUGZpQUNRdi8vLy84UGczd2lBa0lnaUh3aEF5QURJQXNnRG40Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QU1JQTErSUFKQy8vLy8vdytEZkNJQ1FpQ0lmRUlCaGlBQ1F2Ly8vLzhQZzBJQmhpSUNRaUNJZkNFRElBTWdBa0wvLy8vL0Q0TWdCRUwvLy8vL0Q0TjhJZ0pDSUloOElBVjhJUU1nQVNBQ1BnSTBJQU1pQkVJZ2lDRUZJQWtnRVg0aUFrSWdpQ0VESUFNZ0NpQVFmaUFDUXYvLy8vOFBnM3dpQWtJZ2lId2hBeUFESUFzZ0QzNGdBa0wvLy8vL0Q0TjhJZ0pDSUloOElRTWdBeUFNSUE1K0lBSkMvLy8vL3crRGZDSUNRaUNJZkVJQmhpQUNRdi8vLy84UGcwSUJoaUlDUWlDSWZDRURJQU1nRFNBTmZpQUNRdi8vLy84UGczd2lBa0lnaUh3aEF5QURJQUpDLy8vLy93K0RJQVJDLy8vLy93K0RmQ0lDUWlDSWZDQUZmQ0VESUFFZ0FqNENPQ0FESWdSQ0lJZ2hCU0FLSUJGK0lnSkNJSWdoQXlBRElBc2dFSDRnQWtMLy8vLy9ENE44SWdKQ0lJaDhJUU1nQXlBTUlBOStJQUpDLy8vLy93K0RmQ0lDUWlDSWZDRURJQU1nRFNBT2ZpQUNRdi8vLy84UGczd2lBa0lnaUh4Q0FZWWdBa0wvLy8vL0Q0TkNBWVlpQWtJZ2lId2hBeUFESUFKQy8vLy8vdytESUFSQy8vLy8vdytEZkNJQ1FpQ0lmQ0FGZkNFRElBRWdBajRDUENBRElnUkNJSWdoQlNBTElCRitJZ0pDSUlnaEF5QURJQXdnRUg0Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QU5JQTkrSUFKQy8vLy8vdytEZkNJQ1FpQ0lmRUlCaGlBQ1F2Ly8vLzhQZzBJQmhpSUNRaUNJZkNFRElBTWdEaUFPZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHdoQXlBRElBSkMvLy8vL3crRElBUkMvLy8vL3crRGZDSUNRaUNJZkNBRmZDRURJQUVnQWo0Q1FDQURJZ1JDSUlnaEJTQU1JQkYrSWdKQ0lJZ2hBeUFESUEwZ0VINGdBa0wvLy8vL0Q0TjhJZ0pDSUloOElRTWdBeUFPSUE5K0lBSkMvLy8vL3crRGZDSUNRaUNJZkVJQmhpQUNRdi8vLy84UGcwSUJoaUlDUWlDSWZDRURJQU1nQWtMLy8vLy9ENE1nQkVMLy8vLy9ENE44SWdKQ0lJaDhJQVY4SVFNZ0FTQUNQZ0pFSUFNaUJFSWdpQ0VGSUEwZ0VYNGlBa0lnaUNFRElBTWdEaUFRZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHhDQVlZZ0FrTC8vLy8vRDROQ0FZWWlBa0lnaUh3aEF5QURJQThnRDM0Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUNRdi8vLy84UGd5QUVRdi8vLy84UGczd2lBa0lnaUh3Z0JYd2hBeUFCSUFJK0FrZ2dBeUlFUWlDSUlRVWdEaUFSZmlJQ1FpQ0lJUU1nQXlBUElCQitJQUpDLy8vLy93K0RmQ0lDUWlDSWZFSUJoaUFDUXYvLy8vOFBnMElCaGlJQ1FpQ0lmQ0VESUFNZ0FrTC8vLy8vRDRNZ0JFTC8vLy8vRDROOElnSkNJSWg4SUFWOElRTWdBU0FDUGdKTUlBTWlCRUlnaUNFRklBOGdFWDRpQWtJZ2lFSUJoaUFDUXYvLy8vOFBnMElCaGlJQ1FpQ0lmQ0VESUFNZ0VDQVFmaUFDUXYvLy8vOFBnM3dpQWtJZ2lId2hBeUFESUFKQy8vLy8vdytESUFSQy8vLy8vdytEZkNJQ1FpQ0lmQ0FGZkNFRElBRWdBajRDVUNBRElnUkNJSWdoQlNBUUlCRitJZ0pDSUloQ0FZWWdBa0wvLy8vL0Q0TkNBWVlpQWtJZ2lId2hBeUFESUFKQy8vLy8vdytESUFSQy8vLy8vdytEZkNJQ1FpQ0lmQ0FGZkNFRElBRWdBajRDVkNBRElnUkNJSWdoQlVJQUlRSkNBQ0VESUFNZ0VTQVJmaUFDUXYvLy8vOFBnM3dpQWtJZ2lId2hBeUFESUFKQy8vLy8vdytESUFSQy8vLy8vdytEZkNJQ1FpQ0lmQ0FGZkNFRElBRWdBajRDV0NBQklBTStBbHdMQ2dBZ0FDQUFJQUVRQ0F0QkFDQUFJQUExQUFBZ0FYd2lBVDRBQUNBQlFpQ0lJUUVEUUNBQlVFVUVRQ0FBUVFScUlnQTFBQUFnQVh3aEFTQUFJQUUrQUFBZ0FVSWdpQ0VCREFFTEN3dUVCQUlEZmdGL0lBQWdBMEdJQVNBREd5SURFQUFnQVVFb0VBQWdBa0hZQUNBQ0d5SUhFQUZCdUFFUUFVRXZJUUJCTHlFQkEwQWdBVUVvYWkwQUFDQUJRUU5HY2tVRVFDQUJRUUZySVFFTUFRc0xJQUZCSldvMUFBQkNBWHdpQmtJQlVRUkFRZ0JDQUlBYUN3TkFBa0FEUUNBQUlBTnFMUUFBSUFCQkIwWnlSUVJBSUFCQkFXc2hBQXdCQ3dzZ0FDQURha0VIYXlrQUFDQUdnQ0VGSUFBZ0FXdEJCR3NoQWdOQUlBVkNnSUNBZ0hDRFVDQUNRUUJPY1VVRVFDQUZRZ2lJSVFVZ0FrRUJhaUVDREFFTEN5QUZVQVJBSUFOQktCQUZSUTBCUWdFaEJVRUFJUUlMUWVnQlFTZzFBQUFnQlg0aUJENEFBRUhzQVVFc05RQUFJQVYrSUFSQ0lJaDhJZ1ErQUFCQjhBRkJNRFVBQUNBRmZpQUVRaUNJZkNJRVBnQUFRZlFCUVRRMUFBQWdCWDRnQkVJZ2lId2lCRDRBQUVINEFVRTROUUFBSUFWK0lBUkNJSWg4SWdRK0FBQkIvQUZCUERVQUFDQUZmaUFFUWlDSWZDSUVQZ0FBUVlBQ1FjQUFOUUFBSUFWK0lBUkNJSWg4SWdRK0FBQkJoQUpCeEFBMUFBQWdCWDRnQkVJZ2lId2lCRDRBQUVHSUFrSElBRFVBQUNBRmZpQUVRaUNJZkNJRVBnQUFRWXdDUWN3QU5RQUFJQVYrSUFSQ0lJaDhJZ1ErQUFCQmtBSkIwQUExQUFBZ0JYNGdCRUlnaUh3aUJENEFBRUdVQWtIVUFEVUFBQ0FGZmlBRVFpQ0lmRDRBQUNBRFFlZ0JJQUpySUFNUUJ4b2dBaUFIYWlBRkVBc01BUXNMQzQ0Q0FRcC9RWmdDSVFOQm1BSVFBVUhJQWlFSUlBRkJ5QUlRQUVINEFpRUpRZmdDRUFOQnFBTWhCaUFBUWFnREVBQkIyQU1oQzBHSUJDRUtRWmdGSVFRRFFDQUdFQUpGQkVBZ0NDQUdJQXNnQ2hBTUlBc2dDVUc0QkJBSUlBY0VmeUFGQkg5QnVBUWdBeEFGQkg5QnVBUWdBeUFFRUFjYVFRQUZJQU5CdUFRZ0JCQUhHa0VCQ3dWQnVBUWdBeUFFRUFZYVFRRUxCU0FGQkg5QnVBUWdBeUFFRUFZYVFRQUZJQU5CdUFRUUJRUi9JQU5CdUFRZ0JCQUhHa0VBQlVHNEJDQURJQVFRQnhwQkFRc0xDeUVNSUFNaEFDQUpJUU1nQkNFSklBQWhCQ0FGSVFjZ0RDRUZJQWdoQUNBR0lRZ2dDaUVHSUFBaENnd0JDd3NnQndSQUlBRWdBeUFDRUFjYUJTQURJQUlRQUFzTENRQWdBRUdvQmhBRUN5d0FJQUFnQVNBQ0VBWUVRQ0FDUWNnRklBSVFCeG9GSUFKQnlBVVFCUVJBSUFKQnlBVWdBaEFIR2dzTEN4Y0FJQUFnQVNBQ0VBY0VRQ0FDUWNnRklBSVFCaG9MQ3dzQVFkZ0dJQUFnQVJBUUM4WWhBUU4rSUFBZ0FEVUNBRUw5Ly9QL0R5SUVJQUExQWdCK1F2Ly8vLzhQZ3lJRFFjZ0ZOUUlBZm53aUFqNENBQ0FBSUFBMUFnUWdBa0lnaUh4QnpBVTFBZ0FnQTM1OElnSStBZ1FnQUNBQU5RSUlJQUpDSUloOFFkQUZOUUlBSUFOK2ZDSUNQZ0lJSUFBZ0FEVUNEQ0FDUWlDSWZFSFVCVFVDQUNBRGZud2lBajRDRENBQUlBQTFBaEFnQWtJZ2lIeEIyQVUxQWdBZ0EzNThJZ0krQWhBZ0FDQUFOUUlVSUFKQ0lJaDhRZHdGTlFJQUlBTitmQ0lDUGdJVUlBQWdBRFVDR0NBQ1FpQ0lmRUhnQlRVQ0FDQURmbndpQWo0Q0dDQUFJQUExQWh3Z0FrSWdpSHhCNUFVMUFnQWdBMzU4SWdJK0Fod2dBQ0FBTlFJZ0lBSkNJSWg4UWVnRk5RSUFJQU4rZkNJQ1BnSWdJQUFnQURVQ0pDQUNRaUNJZkVIc0JUVUNBQ0FEZm53aUFqNENKQ0FBSUFBMUFpZ2dBa0lnaUh4QjhBVTFBZ0FnQTM1OElnSStBaWdnQUNBQU5RSXNJQUpDSUloOFFmUUZOUUlBSUFOK2ZDSUNQZ0lzUWZnSUlBSkNJSWcrQWdBZ0FDQUFOUUlFSUFBMUFnUWdCSDVDLy8vLy93K0RJZ05CeUFVMUFnQitmQ0lDUGdJRUlBQWdBRFVDQ0NBQ1FpQ0lmRUhNQlRVQ0FDQURmbndpQWo0Q0NDQUFJQUExQWd3Z0FrSWdpSHhCMEFVMUFnQWdBMzU4SWdJK0Fnd2dBQ0FBTlFJUUlBSkNJSWg4UWRRRk5RSUFJQU4rZkNJQ1BnSVFJQUFnQURVQ0ZDQUNRaUNJZkVIWUJUVUNBQ0FEZm53aUFqNENGQ0FBSUFBMUFoZ2dBa0lnaUh4QjNBVTFBZ0FnQTM1OElnSStBaGdnQUNBQU5RSWNJQUpDSUloOFFlQUZOUUlBSUFOK2ZDSUNQZ0ljSUFBZ0FEVUNJQ0FDUWlDSWZFSGtCVFVDQUNBRGZud2lBajRDSUNBQUlBQTFBaVFnQWtJZ2lIeEI2QVUxQWdBZ0EzNThJZ0krQWlRZ0FDQUFOUUlvSUFKQ0lJaDhRZXdGTlFJQUlBTitmQ0lDUGdJb0lBQWdBRFVDTENBQ1FpQ0lmRUh3QlRVQ0FDQURmbndpQWo0Q0xDQUFJQUExQWpBZ0FrSWdpSHhCOUFVMUFnQWdBMzU4SWdJK0FqQkIvQWdnQWtJZ2lENENBQ0FBSUFBMUFnZ2dBRFVDQ0NBRWZrTC8vLy8vRDRNaUEwSElCVFVDQUg1OElnSStBZ2dnQUNBQU5RSU1JQUpDSUloOFFjd0ZOUUlBSUFOK2ZDSUNQZ0lNSUFBZ0FEVUNFQ0FDUWlDSWZFSFFCVFVDQUNBRGZud2lBajRDRUNBQUlBQTFBaFFnQWtJZ2lIeEIxQVUxQWdBZ0EzNThJZ0krQWhRZ0FDQUFOUUlZSUFKQ0lJaDhRZGdGTlFJQUlBTitmQ0lDUGdJWUlBQWdBRFVDSENBQ1FpQ0lmRUhjQlRVQ0FDQURmbndpQWo0Q0hDQUFJQUExQWlBZ0FrSWdpSHhCNEFVMUFnQWdBMzU4SWdJK0FpQWdBQ0FBTlFJa0lBSkNJSWg4UWVRRk5RSUFJQU4rZkNJQ1BnSWtJQUFnQURVQ0tDQUNRaUNJZkVIb0JUVUNBQ0FEZm53aUFqNENLQ0FBSUFBMUFpd2dBa0lnaUh4QjdBVTFBZ0FnQTM1OElnSStBaXdnQUNBQU5RSXdJQUpDSUloOFFmQUZOUUlBSUFOK2ZDSUNQZ0l3SUFBZ0FEVUNOQ0FDUWlDSWZFSDBCVFVDQUNBRGZud2lBajRDTkVHQUNTQUNRaUNJUGdJQUlBQWdBRFVDRENBQU5RSU1JQVIrUXYvLy8vOFBneUlEUWNnRk5RSUFmbndpQWo0Q0RDQUFJQUExQWhBZ0FrSWdpSHhCekFVMUFnQWdBMzU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UWRBRk5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVIVUJUVUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QjJBVTFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFkd0ZOUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFSGdCVFVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEI1QVUxQWdBZ0EzNThJZ0krQWlnZ0FDQUFOUUlzSUFKQ0lJaDhRZWdGTlFJQUlBTitmQ0lDUGdJc0lBQWdBRFVDTUNBQ1FpQ0lmRUhzQlRVQ0FDQURmbndpQWo0Q01DQUFJQUExQWpRZ0FrSWdpSHhCOEFVMUFnQWdBMzU4SWdJK0FqUWdBQ0FBTlFJNElBSkNJSWg4UWZRRk5RSUFJQU4rZkNJQ1BnSTRRWVFKSUFKQ0lJZytBZ0FnQUNBQU5RSVFJQUExQWhBZ0JINUMvLy8vL3crRElnTkJ5QVUxQWdCK2ZDSUNQZ0lRSUFBZ0FEVUNGQ0FDUWlDSWZFSE1CVFVDQUNBRGZud2lBajRDRkNBQUlBQTFBaGdnQWtJZ2lIeEIwQVUxQWdBZ0EzNThJZ0krQWhnZ0FDQUFOUUljSUFKQ0lJaDhRZFFGTlFJQUlBTitmQ0lDUGdJY0lBQWdBRFVDSUNBQ1FpQ0lmRUhZQlRVQ0FDQURmbndpQWo0Q0lDQUFJQUExQWlRZ0FrSWdpSHhCM0FVMUFnQWdBMzU4SWdJK0FpUWdBQ0FBTlFJb0lBSkNJSWg4UWVBRk5RSUFJQU4rZkNJQ1BnSW9JQUFnQURVQ0xDQUNRaUNJZkVIa0JUVUNBQ0FEZm53aUFqNENMQ0FBSUFBMUFqQWdBa0lnaUh4QjZBVTFBZ0FnQTM1OElnSStBakFnQUNBQU5RSTBJQUpDSUloOFFld0ZOUUlBSUFOK2ZDSUNQZ0kwSUFBZ0FEVUNPQ0FDUWlDSWZFSHdCVFVDQUNBRGZud2lBajRDT0NBQUlBQTFBandnQWtJZ2lIeEI5QVUxQWdBZ0EzNThJZ0krQWp4QmlBa2dBa0lnaUQ0Q0FDQUFJQUExQWhRZ0FEVUNGQ0FFZmtMLy8vLy9ENE1pQTBISUJUVUNBSDU4SWdJK0FoUWdBQ0FBTlFJWUlBSkNJSWg4UWN3Rk5RSUFJQU4rZkNJQ1BnSVlJQUFnQURVQ0hDQUNRaUNJZkVIUUJUVUNBQ0FEZm53aUFqNENIQ0FBSUFBMUFpQWdBa0lnaUh4QjFBVTFBZ0FnQTM1OElnSStBaUFnQUNBQU5RSWtJQUpDSUloOFFkZ0ZOUUlBSUFOK2ZDSUNQZ0lrSUFBZ0FEVUNLQ0FDUWlDSWZFSGNCVFVDQUNBRGZud2lBajRDS0NBQUlBQTFBaXdnQWtJZ2lIeEI0QVUxQWdBZ0EzNThJZ0krQWl3Z0FDQUFOUUl3SUFKQ0lJaDhRZVFGTlFJQUlBTitmQ0lDUGdJd0lBQWdBRFVDTkNBQ1FpQ0lmRUhvQlRVQ0FDQURmbndpQWo0Q05DQUFJQUExQWpnZ0FrSWdpSHhCN0FVMUFnQWdBMzU4SWdJK0FqZ2dBQ0FBTlFJOElBSkNJSWg4UWZBRk5RSUFJQU4rZkNJQ1BnSThJQUFnQURVQ1FDQUNRaUNJZkVIMEJUVUNBQ0FEZm53aUFqNENRRUdNQ1NBQ1FpQ0lQZ0lBSUFBZ0FEVUNHQ0FBTlFJWUlBUitRdi8vLy84UGd5SURRY2dGTlFJQWZud2lBajRDR0NBQUlBQTFBaHdnQWtJZ2lIeEJ6QVUxQWdBZ0EzNThJZ0krQWh3Z0FDQUFOUUlnSUFKQ0lJaDhRZEFGTlFJQUlBTitmQ0lDUGdJZ0lBQWdBRFVDSkNBQ1FpQ0lmRUhVQlRVQ0FDQURmbndpQWo0Q0pDQUFJQUExQWlnZ0FrSWdpSHhCMkFVMUFnQWdBMzU4SWdJK0FpZ2dBQ0FBTlFJc0lBSkNJSWg4UWR3Rk5RSUFJQU4rZkNJQ1BnSXNJQUFnQURVQ01DQUNRaUNJZkVIZ0JUVUNBQ0FEZm53aUFqNENNQ0FBSUFBMUFqUWdBa0lnaUh4QjVBVTFBZ0FnQTM1OElnSStBalFnQUNBQU5RSTRJQUpDSUloOFFlZ0ZOUUlBSUFOK2ZDSUNQZ0k0SUFBZ0FEVUNQQ0FDUWlDSWZFSHNCVFVDQUNBRGZud2lBajRDUENBQUlBQTFBa0FnQWtJZ2lIeEI4QVUxQWdBZ0EzNThJZ0krQWtBZ0FDQUFOUUpFSUFKQ0lJaDhRZlFGTlFJQUlBTitmQ0lDUGdKRVFaQUpJQUpDSUlnK0FnQWdBQ0FBTlFJY0lBQTFBaHdnQkg1Qy8vLy8vdytESWdOQnlBVTFBZ0IrZkNJQ1BnSWNJQUFnQURVQ0lDQUNRaUNJZkVITUJUVUNBQ0FEZm53aUFqNENJQ0FBSUFBMUFpUWdBa0lnaUh4QjBBVTFBZ0FnQTM1OElnSStBaVFnQUNBQU5RSW9JQUpDSUloOFFkUUZOUUlBSUFOK2ZDSUNQZ0lvSUFBZ0FEVUNMQ0FDUWlDSWZFSFlCVFVDQUNBRGZud2lBajRDTENBQUlBQTFBakFnQWtJZ2lIeEIzQVUxQWdBZ0EzNThJZ0krQWpBZ0FDQUFOUUkwSUFKQ0lJaDhRZUFGTlFJQUlBTitmQ0lDUGdJMElBQWdBRFVDT0NBQ1FpQ0lmRUhrQlRVQ0FDQURmbndpQWo0Q09DQUFJQUExQWp3Z0FrSWdpSHhCNkFVMUFnQWdBMzU4SWdJK0Fqd2dBQ0FBTlFKQUlBSkNJSWg4UWV3Rk5RSUFJQU4rZkNJQ1BnSkFJQUFnQURVQ1JDQUNRaUNJZkVId0JUVUNBQ0FEZm53aUFqNENSQ0FBSUFBMUFrZ2dBa0lnaUh4QjlBVTFBZ0FnQTM1OElnSStBa2hCbEFrZ0FrSWdpRDRDQUNBQUlBQTFBaUFnQURVQ0lDQUVma0wvLy8vL0Q0TWlBMEhJQlRVQ0FINThJZ0krQWlBZ0FDQUFOUUlrSUFKQ0lJaDhRY3dGTlFJQUlBTitmQ0lDUGdJa0lBQWdBRFVDS0NBQ1FpQ0lmRUhRQlRVQ0FDQURmbndpQWo0Q0tDQUFJQUExQWl3Z0FrSWdpSHhCMUFVMUFnQWdBMzU4SWdJK0Fpd2dBQ0FBTlFJd0lBSkNJSWg4UWRnRk5RSUFJQU4rZkNJQ1BnSXdJQUFnQURVQ05DQUNRaUNJZkVIY0JUVUNBQ0FEZm53aUFqNENOQ0FBSUFBMUFqZ2dBa0lnaUh4QjRBVTFBZ0FnQTM1OElnSStBamdnQUNBQU5RSThJQUpDSUloOFFlUUZOUUlBSUFOK2ZDSUNQZ0k4SUFBZ0FEVUNRQ0FDUWlDSWZFSG9CVFVDQUNBRGZud2lBajRDUUNBQUlBQTFBa1FnQWtJZ2lIeEI3QVUxQWdBZ0EzNThJZ0krQWtRZ0FDQUFOUUpJSUFKQ0lJaDhRZkFGTlFJQUlBTitmQ0lDUGdKSUlBQWdBRFVDVENBQ1FpQ0lmRUgwQlRVQ0FDQURmbndpQWo0Q1RFR1lDU0FDUWlDSVBnSUFJQUFnQURVQ0pDQUFOUUlrSUFSK1F2Ly8vLzhQZ3lJRFFjZ0ZOUUlBZm53aUFqNENKQ0FBSUFBMUFpZ2dBa0lnaUh4QnpBVTFBZ0FnQTM1OElnSStBaWdnQUNBQU5RSXNJQUpDSUloOFFkQUZOUUlBSUFOK2ZDSUNQZ0lzSUFBZ0FEVUNNQ0FDUWlDSWZFSFVCVFVDQUNBRGZud2lBajRDTUNBQUlBQTFBalFnQWtJZ2lIeEIyQVUxQWdBZ0EzNThJZ0krQWpRZ0FDQUFOUUk0SUFKQ0lJaDhRZHdGTlFJQUlBTitmQ0lDUGdJNElBQWdBRFVDUENBQ1FpQ0lmRUhnQlRVQ0FDQURmbndpQWo0Q1BDQUFJQUExQWtBZ0FrSWdpSHhCNUFVMUFnQWdBMzU4SWdJK0FrQWdBQ0FBTlFKRUlBSkNJSWg4UWVnRk5RSUFJQU4rZkNJQ1BnSkVJQUFnQURVQ1NDQUNRaUNJZkVIc0JUVUNBQ0FEZm53aUFqNENTQ0FBSUFBMUFrd2dBa0lnaUh4QjhBVTFBZ0FnQTM1OElnSStBa3dnQUNBQU5RSlFJQUpDSUloOFFmUUZOUUlBSUFOK2ZDSUNQZ0pRUVp3SklBSkNJSWcrQWdBZ0FDQUFOUUlvSUFBMUFpZ2dCSDVDLy8vLy93K0RJZ05CeUFVMUFnQitmQ0lDUGdJb0lBQWdBRFVDTENBQ1FpQ0lmRUhNQlRVQ0FDQURmbndpQWo0Q0xDQUFJQUExQWpBZ0FrSWdpSHhCMEFVMUFnQWdBMzU4SWdJK0FqQWdBQ0FBTlFJMElBSkNJSWg4UWRRRk5RSUFJQU4rZkNJQ1BnSTBJQUFnQURVQ09DQUNRaUNJZkVIWUJUVUNBQ0FEZm53aUFqNENPQ0FBSUFBMUFqd2dBa0lnaUh4QjNBVTFBZ0FnQTM1OElnSStBandnQUNBQU5RSkFJQUpDSUloOFFlQUZOUUlBSUFOK2ZDSUNQZ0pBSUFBZ0FEVUNSQ0FDUWlDSWZFSGtCVFVDQUNBRGZud2lBajRDUkNBQUlBQTFBa2dnQWtJZ2lIeEI2QVUxQWdBZ0EzNThJZ0krQWtnZ0FDQUFOUUpNSUFKQ0lJaDhRZXdGTlFJQUlBTitmQ0lDUGdKTUlBQWdBRFVDVUNBQ1FpQ0lmRUh3QlRVQ0FDQURmbndpQWo0Q1VDQUFJQUExQWxRZ0FrSWdpSHhCOUFVMUFnQWdBMzU4SWdJK0FsUkJvQWtnQWtJZ2lENENBQ0FBSUFBMUFpd2dBRFVDTENBRWZrTC8vLy8vRDRNaUEwSElCVFVDQUg1OElnSStBaXdnQUNBQU5RSXdJQUpDSUloOFFjd0ZOUUlBSUFOK2ZDSUNQZ0l3SUFBZ0FEVUNOQ0FDUWlDSWZFSFFCVFVDQUNBRGZud2lBajRDTkNBQUlBQTFBamdnQWtJZ2lIeEIxQVUxQWdBZ0EzNThJZ0krQWpnZ0FDQUFOUUk4SUFKQ0lJaDhRZGdGTlFJQUlBTitmQ0lDUGdJOElBQWdBRFVDUUNBQ1FpQ0lmRUhjQlRVQ0FDQURmbndpQWo0Q1FDQUFJQUExQWtRZ0FrSWdpSHhCNEFVMUFnQWdBMzU4SWdJK0FrUWdBQ0FBTlFKSUlBSkNJSWg4UWVRRk5RSUFJQU4rZkNJQ1BnSklJQUFnQURVQ1RDQUNRaUNJZkVIb0JUVUNBQ0FEZm53aUFqNENUQ0FBSUFBMUFsQWdBa0lnaUh4QjdBVTFBZ0FnQTM1OElnSStBbEFnQUNBQU5RSlVJQUpDSUloOFFmQUZOUUlBSUFOK2ZDSUNQZ0pVSUFBZ0FEVUNXQ0FDUWlDSWZFSDBCVFVDQUNBRGZud2lBajRDV0VHa0NTQUNRaUNJUGdJQVFmZ0lJQUJCTUdvZ0FSQVBDL1ErQVJ0K0lBVWdBVFVDQUNJRUlBQTFBZ0FpRW41OElnTkMvLy8vL3crRElRVWdCaUFBTlFJRUloTWdCSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUVlnQnlBQU5RSUlJaFFnQkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NDQUFOUUlNSWhVZ0JINThJQU5DSUloOElnTkMvLy8vL3crRElRZ2dDU0FBTlFJUUloWWdCSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWtnQ2lBQU5RSVVJaGNnQkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFvZ0N5QUFOUUlZSWhnZ0JINThJQU5DSUloOElnTkMvLy8vL3crRElRc2dEQ0FBTlFJY0loa2dCSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXdnRFNBQU5RSWdJaG9nQkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVEwZ0RpQUFOUUlrSWhzZ0JINThJQU5DSUloOElnTkMvLy8vL3crRElRNGdEeUFBTlFJb0lod2dCSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUThnRUNBQU5RSXNJaDBnQkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVJBZ0EwSWdpQ0VSSUFVZ0JVTDkvL1AvRDM1Qy8vLy8vdytESWdSQ3E5WCsvdzkrZkVJZ2lDQUdJQVJDLy8vN3p3dCtmSHdpQTBMLy8vLy9ENE1oQlNBSElBUkMvLy9QaWd0K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFR0lBZ2dCRUwrLzYvMUFYNThJQU5DSUloOElnTkMvLy8vL3crRElRY2dDU0FFUXFUc3c3VVBmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDQ0FLSUFSQ29LWER1UVorZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVKSUFzZ0JFSy9wWlNjRDM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFvZ0RDQUVRb1NYM2FNR2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaEN5QU5JQVJDMTltdW1nUitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RU1JQTRnQkVLMnorN1lCSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUTBnRHlBRVFwck4vOHNEZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRGlBUUlBUkM2cU9FMEFGK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFUElCRWdBMElnaUh3aEVDQUZJQklnQVRVQ0JDSUVmbndpQTBMLy8vLy9ENE1oQlNBR0lBUWdFMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUVlnQnlBRUlCUitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUhJQWdnQkNBVmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENDQUpJQVFnRm41OElBTkNJSWg4SWdOQy8vLy8vdytESVFrZ0NpQUVJQmQrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVLSUFzZ0JDQVlmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDeUFNSUFRZ0dYNThJQU5DSUloOElnTkMvLy8vL3crRElRd2dEU0FFSUJwK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTklBNGdCQ0FiZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRGlBUElBUWdISDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUThnRUNBRUlCMStmQ0FEUWlDSWZDSURRdi8vLy84UGd5RVFJQU5DSUlnaEVTQUZJQVZDL2Yvei93OStRdi8vLy84UGd5SUVRcXZWL3Y4UGZueENJSWdnQmlBRVF2Ly8rODhMZm54OElnTkMvLy8vL3crRElRVWdCeUFFUXYvL3o0b0xmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFJSUFSQy92K3Y5UUYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFrZ0JFS2s3TU8xRDM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NpQUVRcUNsdzdrR2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUxJQVJDdjZXVW5BOStmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUtJQXdnQkVLRWw5MmpCbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRFNBRVF0ZlpycG9FZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRENBT0lBUkN0cy91MkFSK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTklBOGdCRUthemYvTEEzNThJQU5DSUloOElnTkMvLy8vL3crRElRNGdFQ0FFUXVxamhOQUJmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEeUFSSUFOQ0lJaDhJUkFnQlNBU0lBRTFBZ2dpQkg1OElnTkMvLy8vL3crRElRVWdCaUFFSUJOK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFR0lBY2dCQ0FVZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQnlBSUlBUWdGWDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWdnQ1NBRUlCWitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUpJQW9nQkNBWGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENpQUxJQVFnR0g1OElBTkNJSWg4SWdOQy8vLy8vdytESVFzZ0RDQUVJQmwrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVNSUEwZ0JDQWFmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEU0FPSUFRZ0czNThJQU5DSUloOElnTkMvLy8vL3crRElRNGdEeUFFSUJ4K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFUElCQWdCQ0FkZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRUNBRFFpQ0lJUkVnQlNBRlF2My84LzhQZmtMLy8vLy9ENE1pQkVLcjFmNy9EMzU4UWlDSUlBWWdCRUwvLy92UEMzNThmQ0lEUXYvLy8vOFBneUVGSUFjZ0JFTC8vOCtLQzM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFZZ0NDQUVRdjcvci9VQmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJ5QUpJQVJDcE96RHRROStmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUlJQW9nQkVLZ3BjTzVCbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWtnQ3lBRVFyK2xsSndQZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ2lBTUlBUkNoSmZkb3daK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTElBMGdCRUxYMmE2YUJINThJQU5DSUloOElnTkMvLy8vL3crRElRd2dEaUFFUXJiUDd0Z0VmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEU0FQSUFSQ21zMy95d04rZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVPSUJBZ0JFTHFvNFRRQVg1OElBTkNJSWg4SWdOQy8vLy8vdytESVE4Z0VTQURRaUNJZkNFUUlBVWdFaUFCTlFJTUlnUitmQ0lEUXYvLy8vOFBneUVGSUFZZ0JDQVRmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFISUFRZ0ZINThJQU5DSUloOElnTkMvLy8vL3crRElRY2dDQ0FFSUJWK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSUlBa2dCQ0FXZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ1NBS0lBUWdGMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUW9nQ3lBRUlCaCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUxJQXdnQkNBWmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERDQU5JQVFnR241OElBTkNJSWg4SWdOQy8vLy8vdytESVEwZ0RpQUVJQnQrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVPSUE4Z0JDQWNmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEeUFRSUFRZ0hYNThJQU5DSUloOElnTkMvLy8vL3crRElSQWdBMElnaUNFUklBVWdCVUw5Ly9QL0QzNUMvLy8vL3crRElnUkNxOVgrL3c5K2ZFSWdpQ0FHSUFSQy8vLzd6d3QrZkh3aUEwTC8vLy8vRDRNaEJTQUhJQVJDLy8vUGlndCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUdJQWdnQkVMKy82LzFBWDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWNnQ1NBRVFxVHN3N1VQZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ0NBS0lBUkNvS1hEdVFaK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSklBc2dCRUsvcFpTY0QzNThJQU5DSUloOElnTkMvLy8vL3crRElRb2dEQ0FFUW9TWDNhTUdmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDeUFOSUFSQzE5bXVtZ1IrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVNSUE0Z0JFSzJ6KzdZQkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVEwZ0R5QUVRcHJOLzhzRGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERpQVFJQVJDNnFPRTBBRitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RVBJQkVnQTBJZ2lId2hFQ0FGSUJJZ0FUVUNFQ0lFZm53aUEwTC8vLy8vRDRNaEJTQUdJQVFnRTM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFZZ0J5QUVJQlIrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFnZ0JDQVZmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDQ0FKSUFRZ0ZuNThJQU5DSUloOElnTkMvLy8vL3crRElRa2dDaUFFSUJkK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFS0lBc2dCQ0FZZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ3lBTUlBUWdHWDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXdnRFNBRUlCcCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RU5JQTRnQkNBYmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERpQVBJQVFnSEg1OElBTkNJSWg4SWdOQy8vLy8vdytESVE4Z0VDQUVJQjErZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVRSUFOQ0lJZ2hFU0FGSUFWQy9mL3ovdzkrUXYvLy8vOFBneUlFUXF2Vi92OFBmbnhDSUlnZ0JpQUVRdi8vKzg4TGZueDhJZ05DLy8vLy93K0RJUVVnQnlBRVF2Ly96NG9MZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQmlBSUlBUkMvdit2OVFGK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSElBa2dCRUtrN01PMUQzNThJQU5DSUloOElnTkMvLy8vL3crRElRZ2dDaUFFUXFDbHc3a0dmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FMSUFSQ3Y2V1VuQTkrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVLSUF3Z0JFS0VsOTJqQm41OElBTkNJSWg4SWdOQy8vLy8vdytESVFzZ0RTQUVRdGZacnBvRWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERDQU9JQVJDdHMvdTJBUitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RU5JQThnQkVLYXpmL0xBMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUTRnRUNBRVF1cWpoTkFCZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRHlBUklBTkNJSWg4SVJBZ0JTQVNJQUUxQWhRaUJINThJZ05DLy8vLy93K0RJUVVnQmlBRUlCTitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUdJQWNnQkNBVWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJ5QUlJQVFnRlg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NTQUVJQlorZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVKSUFvZ0JDQVhmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDaUFMSUFRZ0dINThJQU5DSUloOElnTkMvLy8vL3crRElRc2dEQ0FFSUJsK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTUlBMGdCQ0FhZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRFNBT0lBUWdHMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUTRnRHlBRUlCeCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RVBJQkFnQkNBZGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEVDQURRaUNJSVJFZ0JTQUZRdjMvOC84UGZrTC8vLy8vRDRNaUJFS3IxZjcvRDM1OFFpQ0lJQVlnQkVMLy8vdlBDMzU4ZkNJRFF2Ly8vLzhQZ3lFRklBY2dCRUwvLzgrS0MzNThJQU5DSUloOElnTkMvLy8vL3crRElRWWdDQ0FFUXY3L3IvVUJmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCeUFKSUFSQ3BPekR0UTkrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVJSUFvZ0JFS2dwY081Qm41OElBTkNJSWg4SWdOQy8vLy8vdytESVFrZ0N5QUVRcitsbEp3UGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENpQU1JQVJDaEpmZG93WitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUxJQTBnQkVMWDJhNmFCSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXdnRGlBRVFyYlA3dGdFZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRFNBUElBUkNtczMveXdOK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFT0lCQWdCRUxxbzRUUUFYNThJQU5DSUloOElnTkMvLy8vL3crRElROGdFU0FEUWlDSWZDRVFJQVVnRWlBQk5RSVlJZ1IrZkNJRFF2Ly8vLzhQZ3lFRklBWWdCQ0FUZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQmlBSElBUWdGSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWNnQ0NBRUlCVitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUlJQWtnQkNBV2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUtJQVFnRjM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFvZ0N5QUVJQmgrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVMSUF3Z0JDQVpmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEQ0FOSUFRZ0duNThJQU5DSUloOElnTkMvLy8vL3crRElRMGdEaUFFSUJ0K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFT0lBOGdCQ0FjZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRHlBUUlBUWdIWDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUkFnQTBJZ2lDRVJJQVVnQlVMOS8vUC9EMzVDLy8vLy93K0RJZ1JDcTlYKy93OStmRUlnaUNBR0lBUkMvLy83end0K2ZId2lBMEwvLy8vL0Q0TWhCU0FISUFSQy8vL1BpZ3QrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVHSUFnZ0JFTCsvNi8xQVg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NTQUVRcVRzdzdVUGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENDQUtJQVJDb0tYRHVRWitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUpJQXNnQkVLL3BaU2NEMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUW9nRENBRVFvU1gzYU1HZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ3lBTklBUkMxOW11bWdSK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTUlBNGdCRUsyeis3WUJINThJQU5DSUloOElnTkMvLy8vL3crRElRMGdEeUFFUXByTi84c0RmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEaUFRSUFSQzZxT0UwQUYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVQSUJFZ0EwSWdpSHdoRUNBRklCSWdBVFVDSENJRWZud2lBMEwvLy8vL0Q0TWhCU0FHSUFRZ0UzNThJQU5DSUloOElnTkMvLy8vL3crRElRWWdCeUFFSUJSK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSElBZ2dCQ0FWZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ0NBSklBUWdGbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWtnQ2lBRUlCZCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUtJQXNnQkNBWWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEN5QU1JQVFnR1g1OElBTkNJSWg4SWdOQy8vLy8vdytESVF3Z0RTQUVJQnArZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVOSUE0Z0JDQWJmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEaUFQSUFRZ0hINThJQU5DSUloOElnTkMvLy8vL3crRElROGdFQ0FFSUIxK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFUUlBTkNJSWdoRVNBRklBVkMvZi96L3c5K1F2Ly8vLzhQZ3lJRVFxdlYvdjhQZm54Q0lJZ2dCaUFFUXYvLys4OExmbng4SWdOQy8vLy8vdytESVFVZ0J5QUVRdi8vejRvTGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUlJQVJDL3YrdjlRRitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUhJQWtnQkVLazdNTzFEMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWdnQ2lBRVFxQ2x3N2tHZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ1NBTElBUkN2NldVbkE5K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFS0lBd2dCRUtFbDkyakJuNThJQU5DSUloOElnTkMvLy8vL3crRElRc2dEU0FFUXRmWnJwb0VmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEQ0FPSUFSQ3RzL3UyQVIrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVOSUE4Z0JFS2F6Zi9MQTM1OElBTkNJSWg4SWdOQy8vLy8vdytESVE0Z0VDQUVRdXFqaE5BQmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaER5QVJJQU5DSUloOElSQWdCU0FTSUFFMUFpQWlCSDU4SWdOQy8vLy8vdytESVFVZ0JpQUVJQk4rZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVHSUFjZ0JDQVVmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCeUFJSUFRZ0ZYNThJQU5DSUloOElnTkMvLy8vL3crRElRZ2dDU0FFSUJaK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSklBb2dCQ0FYZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ2lBTElBUWdHSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRENBRUlCbCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RU1JQTBnQkNBYWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERTQU9JQVFnRzM1OElBTkNJSWg4SWdOQy8vLy8vdytESVE0Z0R5QUVJQngrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVQSUJBZ0JDQWRmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhFQ0FEUWlDSUlSRWdCU0FGUXYzLzgvOFBma0wvLy8vL0Q0TWlCRUtyMWY3L0QzNThRaUNJSUFZZ0JFTC8vL3ZQQzM1OGZDSURRdi8vLy84UGd5RUZJQWNnQkVMLy84K0tDMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUVlnQ0NBRVF2Ny9yL1VCZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQnlBSklBUkNwT3pEdFE5K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSUlBb2dCRUtncGNPNUJuNThJQU5DSUloOElnTkMvLy8vL3crRElRa2dDeUFFUXIrbGxKd1BmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDaUFNSUFSQ2hKZmRvd1orZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVMSUEwZ0JFTFgyYTZhQkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVF3Z0RpQUVRcmJQN3RnRWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERTQVBJQVJDbXMzL3l3TitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RU9JQkFnQkVMcW80VFFBWDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUThnRVNBRFFpQ0lmQ0VRSUFVZ0VpQUJOUUlrSWdSK2ZDSURRdi8vLy84UGd5RUZJQVlnQkNBVGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUhJQVFnRkg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NDQUVJQlYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVJSUFrZ0JDQVdmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FLSUFRZ0YzNThJQU5DSUloOElnTkMvLy8vL3crRElRb2dDeUFFSUJoK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTElBd2dCQ0FaZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRENBTklBUWdHbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUTBnRGlBRUlCdCtmQ0FEUWlDSWZDSURRdi8vLy84UGd5RU9JQThnQkNBY2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaER5QVFJQVFnSFg1OElBTkNJSWg4SWdOQy8vLy8vdytESVJBZ0EwSWdpQ0VSSUFVZ0JVTDkvL1AvRDM1Qy8vLy8vdytESWdSQ3E5WCsvdzkrZkVJZ2lDQUdJQVJDLy8vN3p3dCtmSHdpQTBMLy8vLy9ENE1oQlNBSElBUkMvLy9QaWd0K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFR0lBZ2dCRUwrLzYvMUFYNThJQU5DSUloOElnTkMvLy8vL3crRElRY2dDU0FFUXFUc3c3VVBmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDQ0FLSUFSQ29LWER1UVorZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVKSUFzZ0JFSy9wWlNjRDM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFvZ0RDQUVRb1NYM2FNR2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaEN5QU5JQVJDMTltdW1nUitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RU1JQTRnQkVLMnorN1lCSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUTBnRHlBRVFwck4vOHNEZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRGlBUUlBUkM2cU9FMEFGK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFUElCRWdBMElnaUh3aEVDQUZJQklnQVRVQ0tDSUVmbndpQTBMLy8vLy9ENE1oQlNBR0lBUWdFMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUVlnQnlBRUlCUitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUhJQWdnQkNBVmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENDQUpJQVFnRm41OElBTkNJSWg4SWdOQy8vLy8vdytESVFrZ0NpQUVJQmQrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVLSUFzZ0JDQVlmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDeUFNSUFRZ0dYNThJQU5DSUloOElnTkMvLy8vL3crRElRd2dEU0FFSUJwK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTklBNGdCQ0FiZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRGlBUElBUWdISDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUThnRUNBRUlCMStmQ0FEUWlDSWZDSURRdi8vLy84UGd5RVFJQU5DSUlnaEVTQUZJQVZDL2Yvei93OStRdi8vLy84UGd5SUVRcXZWL3Y4UGZueENJSWdnQmlBRVF2Ly8rODhMZm54OElnTkMvLy8vL3crRElRVWdCeUFFUXYvL3o0b0xmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFJSUFSQy92K3Y5UUYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFrZ0JFS2s3TU8xRDM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NpQUVRcUNsdzdrR2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUxJQVJDdjZXVW5BOStmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUtJQXdnQkVLRWw5MmpCbjU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRFNBRVF0ZlpycG9FZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRENBT0lBUkN0cy91MkFSK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTklBOGdCRUthemYvTEEzNThJQU5DSUloOElnTkMvLy8vL3crRElRNGdFQ0FFUXVxamhOQUJmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEeUFSSUFOQ0lJaDhJUkFnQlNBU0lBRTFBaXdpQkg1OElnTkMvLy8vL3crRElRVWdCaUFFSUJOK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFR0lBY2dCQ0FVZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQnlBSUlBUWdGWDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWdnQ1NBRUlCWitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUpJQW9nQkNBWGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENpQUxJQVFnR0g1OElBTkNJSWg4SWdOQy8vLy8vdytESVFzZ0RDQUVJQmwrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVNSUEwZ0JDQWFmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEU0FPSUFRZ0czNThJQU5DSUloOElnTkMvLy8vL3crRElRNGdEeUFFSUJ4K2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFUElCQWdCQ0FkZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRUNBRFFpQ0lJUkVnQWlBRklBVkMvZi96L3c5K1F2Ly8vLzhQZ3lJRVFxdlYvdjhQZm54Q0lJZ2dCaUFFUXYvLys4OExmbng4SWdOQy8vLy8vdytEUGdJQUlBSWdCeUFFUXYvL3o0b0xmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TStBZ1FnQWlBSUlBUkMvdit2OVFGK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3o0Q0NDQUNJQWtnQkVLazdNTzFEMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RQZ0lNSUFJZ0NpQUVRcUNsdzdrR2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNK0FoQWdBaUFMSUFSQ3Y2V1VuQTkrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBnejRDRkNBQ0lBd2dCRUtFbDkyakJuNThJQU5DSUloOElnTkMvLy8vL3crRFBnSVlJQUlnRFNBRVF0ZlpycG9FZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE0rQWh3Z0FpQU9JQVJDdHMvdTJBUitmQ0FEUWlDSWZDSURRdi8vLy84UGd6NENJQ0FDSUE4Z0JFS2F6Zi9MQTM1OElBTkNJSWg4SWdOQy8vLy8vdytEUGdJa0lBSWdFQ0FFUXVxamhOQUJmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TStBaWdnQWlBUklBTkNJSWg4UGdJc0lBSkJ5QVVRQlFSQUlBSkJ5QVVnQWhBSEdnc0xpRUFCRzM0Z0NpQUFOUUlBSWhFZ0VYNThJZ0pDLy8vLy93K0RJUW9nRUNBQU5RSUVJaE1nRVg0aUEwTC8vLy8vRDROQ0FZWjhJQUpDSUloOElnSkMvLy8vL3crRElSQWdBMElnaUVJQmhpQUNRaUNJZkNBUElBQTFBZ2dpRkNBUmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVE4Z0EwSWdpRUlCaGlBQ1FpQ0lmQ0FPSUFBMUFnd2lGU0FSZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUTRnQTBJZ2lFSUJoaUFDUWlDSWZDQU5JQUExQWhBaUZpQVJmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRMGdBMElnaUVJQmhpQUNRaUNJZkNBTUlBQTFBaFFpRnlBUmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVF3Z0EwSWdpRUlCaGlBQ1FpQ0lmQ0FMSUFBMUFoZ2lHQ0FSZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUXNnQTBJZ2lFSUJoaUFDUWlDSWZDQUpJQUExQWh3aUdTQVJmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRa2dBMElnaUVJQmhpQUNRaUNJZkNBSUlBQTFBaUFpR2lBUmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFnZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FISUFBMUFpUWlHeUFSZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUWNnQTBJZ2lFSUJoaUFDUWlDSWZDQUdJQUExQWlnaUhDQVJmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRWWdBMElnaUVJQmhpQUNRaUNJZkNBRUlCRWdBRFVDTENJUmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFRZ0JTQURRaUNJUWdHR0lBSkNJSWg4ZkNJQ1F2Ly8vLzhQZ3lFRklCSWdBa0lnaUh3aEVpQUtJQXBDL2Yvei93OStRdi8vLy84UGd5SURRcXZWL3Y4UGZueENJSWdnRUNBRFF2Ly8rODhMZm54OElnSkMvLy8vL3crRElRb2dEeUFEUXYvL3o0b0xmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhFQ0FPSUFOQy92K3Y5UUYrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVQSUEwZ0EwS2s3TU8xRDM1OElBSkNJSWg4SWdKQy8vLy8vdytESVE0Z0RDQURRcUNsdzdrR2Zud2dBa0lnaUh3aUFrTC8vLy8vRDRNaERTQUxJQU5DdjZXVW5BOStmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU1JQWtnQTBLRWw5MmpCbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQ0NBRFF0ZlpycG9FZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ1NBSElBTkN0cy91MkFSK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSUlBWWdBMEthemYvTEEzNThJQUpDSUloOElnSkMvLy8vL3crRElRY2dCQ0FEUXVxamhOQUJmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCaUFGSUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVFnRWlBQ1FpQ0lmQ0VGSUJBZ0V5QVRmbndpQWtMLy8vLy9ENE1oRUNBUElCTWdGSDRpQTBMLy8vLy9ENE5DQVlaOElBSkNJSWg4SWdKQy8vLy8vdytESVE4Z0EwSWdpRUlCaGlBQ1FpQ0lmQ0FPSUJNZ0ZYNGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFT0lBTkNJSWhDQVlZZ0FrSWdpSHdnRFNBVElCWitJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaERTQURRaUNJUWdHR0lBSkNJSWg4SUF3Z0V5QVhmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRd2dBMElnaUVJQmhpQUNRaUNJZkNBTElCTWdHSDRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUxJQU5DSUloQ0FZWWdBa0lnaUh3Z0NTQVRJQmwrSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhDU0FEUWlDSVFnR0dJQUpDSUloOElBZ2dFeUFhZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUWdnQTBJZ2lFSUJoaUFDUWlDSWZDQUhJQk1nRzM0aUEwTC8vLy8vRDROQ0FZWjhmQ0lDUXYvLy8vOFBneUVISUFOQ0lJaENBWVlnQWtJZ2lId2dCaUFUSUJ4K0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQmlBRFFpQ0lRZ0dHSUFKQ0lJaDhJQVFnRVNBVGZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFRZ0JTQURRaUNJUWdHR0lBSkNJSWg4ZkNJQ1F2Ly8vLzhQZ3lFRklBSkNJSWdoRWlBS0lBcEMvZi96L3c5K1F2Ly8vLzhQZ3lJRFFxdlYvdjhQZm54Q0lJZ2dFQ0FEUXYvLys4OExmbng4SWdKQy8vLy8vdytESVFvZ0R5QURRdi8vejRvTGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEVDQU9JQU5DL3YrdjlRRitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RVBJQTBnQTBLazdNTzFEMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUTRnRENBRFFxQ2x3N2tHZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oRFNBTElBTkN2NldVbkE5K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFTUlBa2dBMEtFbDkyakJuNThJQUpDSUloOElnSkMvLy8vL3crRElRc2dDQ0FEUXRmWnJwb0VmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhDU0FISUFOQ3RzL3UyQVIrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVJSUFZZ0EwS2F6Zi9MQTM1OElBSkNJSWg4SWdKQy8vLy8vdytESVFjZ0JDQURRdXFqaE5BQmZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEJpQUZJQUpDSUloOElnSkMvLy8vL3crRElRUWdFaUFDUWlDSWZDRUZJQThnRkNBVWZud2lBa0wvLy8vL0Q0TWhEeUFPSUJRZ0ZYNGlBMEwvLy8vL0Q0TkNBWVo4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUTRnQTBJZ2lFSUJoaUFDUWlDSWZDQU5JQlFnRm40aUEwTC8vLy8vRDROQ0FZWjhmQ0lDUXYvLy8vOFBneUVOSUFOQ0lJaENBWVlnQWtJZ2lId2dEQ0FVSUJkK0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oRENBRFFpQ0lRZ0dHSUFKQ0lJaDhJQXNnRkNBWWZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFzZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FKSUJRZ0dYNGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFSklBTkNJSWhDQVlZZ0FrSWdpSHdnQ0NBVUlCcCtJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaENDQURRaUNJUWdHR0lBSkNJSWg4SUFjZ0ZDQWJmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRY2dBMElnaUVJQmhpQUNRaUNJZkNBR0lCUWdISDRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUdJQU5DSUloQ0FZWWdBa0lnaUh3Z0JDQVJJQlIrSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhCQ0FGSUFOQ0lJaENBWVlnQWtJZ2lIeDhJZ0pDLy8vLy93K0RJUVVnQWtJZ2lDRVNJQW9nQ2tMOS8vUC9EMzVDLy8vLy93K0RJZ05DcTlYKy93OStmRUlnaUNBUUlBTkMvLy83end0K2ZId2lBa0wvLy8vL0Q0TWhDaUFQSUFOQy8vL1BpZ3QrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVRSUE0Z0EwTCsvNi8xQVg1OElBSkNJSWg4SWdKQy8vLy8vdytESVE4Z0RTQURRcVRzdzdVUGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaERpQU1JQU5Db0tYRHVRWitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU5JQXNnQTBLL3BaU2NEMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXdnQ1NBRFFvU1gzYU1HZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ3lBSUlBTkMxOW11bWdSK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSklBY2dBMEsyeis3WUJINThJQUpDSUloOElnSkMvLy8vL3crRElRZ2dCaUFEUXByTi84c0RmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCeUFFSUFOQzZxT0UwQUYrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVHSUFVZ0FrSWdpSHdpQWtMLy8vLy9ENE1oQkNBU0lBSkNJSWg4SVFVZ0RpQVZJQlYrZkNJQ1F2Ly8vLzhQZ3lFT0lBMGdGU0FXZmlJRFF2Ly8vLzhQZzBJQmhud2dBa0lnaUh3aUFrTC8vLy8vRDRNaERTQURRaUNJUWdHR0lBSkNJSWg4SUF3Z0ZTQVhmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRd2dBMElnaUVJQmhpQUNRaUNJZkNBTElCVWdHSDRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUxJQU5DSUloQ0FZWWdBa0lnaUh3Z0NTQVZJQmwrSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhDU0FEUWlDSVFnR0dJQUpDSUloOElBZ2dGU0FhZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUWdnQTBJZ2lFSUJoaUFDUWlDSWZDQUhJQlVnRzM0aUEwTC8vLy8vRDROQ0FZWjhmQ0lDUXYvLy8vOFBneUVISUFOQ0lJaENBWVlnQWtJZ2lId2dCaUFWSUJ4K0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQmlBRFFpQ0lRZ0dHSUFKQ0lJaDhJQVFnRVNBVmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFRZ0JTQURRaUNJUWdHR0lBSkNJSWg4ZkNJQ1F2Ly8vLzhQZ3lFRklBSkNJSWdoRWlBS0lBcEMvZi96L3c5K1F2Ly8vLzhQZ3lJRFFxdlYvdjhQZm54Q0lJZ2dFQ0FEUXYvLys4OExmbng4SWdKQy8vLy8vdytESVFvZ0R5QURRdi8vejRvTGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEVDQU9JQU5DL3YrdjlRRitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RVBJQTBnQTBLazdNTzFEMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUTRnRENBRFFxQ2x3N2tHZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oRFNBTElBTkN2NldVbkE5K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFTUlBa2dBMEtFbDkyakJuNThJQUpDSUloOElnSkMvLy8vL3crRElRc2dDQ0FEUXRmWnJwb0VmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhDU0FISUFOQ3RzL3UyQVIrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVJSUFZZ0EwS2F6Zi9MQTM1OElBSkNJSWg4SWdKQy8vLy8vdytESVFjZ0JDQURRdXFqaE5BQmZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEJpQUZJQUpDSUloOElnSkMvLy8vL3crRElRUWdFaUFDUWlDSWZDRUZJQTBnRmlBV2Zud2lBa0wvLy8vL0Q0TWhEU0FNSUJZZ0YzNGlBMEwvLy8vL0Q0TkNBWVo4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXdnQTBJZ2lFSUJoaUFDUWlDSWZDQUxJQllnR0g0aUEwTC8vLy8vRDROQ0FZWjhmQ0lDUXYvLy8vOFBneUVMSUFOQ0lJaENBWVlnQWtJZ2lId2dDU0FXSUJsK0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQ1NBRFFpQ0lRZ0dHSUFKQ0lJaDhJQWdnRmlBYWZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFnZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FISUJZZ0czNGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFSElBTkNJSWhDQVlZZ0FrSWdpSHdnQmlBV0lCeCtJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJpQURRaUNJUWdHR0lBSkNJSWg4SUFRZ0VTQVdmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRUWdCU0FEUWlDSVFnR0dJQUpDSUloOGZDSUNRdi8vLy84UGd5RUZJQUpDSUlnaEVpQUtJQXBDL2Yvei93OStRdi8vLy84UGd5SURRcXZWL3Y4UGZueENJSWdnRUNBRFF2Ly8rODhMZm54OElnSkMvLy8vL3crRElRb2dEeUFEUXYvL3o0b0xmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhFQ0FPSUFOQy92K3Y5UUYrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVQSUEwZ0EwS2s3TU8xRDM1OElBSkNJSWg4SWdKQy8vLy8vdytESVE0Z0RDQURRcUNsdzdrR2Zud2dBa0lnaUh3aUFrTC8vLy8vRDRNaERTQUxJQU5DdjZXVW5BOStmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU1JQWtnQTBLRWw5MmpCbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQ0NBRFF0ZlpycG9FZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ1NBSElBTkN0cy91MkFSK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSUlBWWdBMEthemYvTEEzNThJQUpDSUloOElnSkMvLy8vL3crRElRY2dCQ0FEUXVxamhOQUJmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCaUFGSUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVFnRWlBQ1FpQ0lmQ0VGSUF3Z0Z5QVhmbndpQWtMLy8vLy9ENE1oRENBTElCY2dHSDRpQTBMLy8vLy9ENE5DQVlaOElBSkNJSWg4SWdKQy8vLy8vdytESVFzZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FKSUJjZ0dYNGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFSklBTkNJSWhDQVlZZ0FrSWdpSHdnQ0NBWElCcCtJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaENDQURRaUNJUWdHR0lBSkNJSWg4SUFjZ0Z5QWJmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRY2dBMElnaUVJQmhpQUNRaUNJZkNBR0lCY2dISDRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUdJQU5DSUloQ0FZWWdBa0lnaUh3Z0JDQVJJQmQrSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhCQ0FGSUFOQ0lJaENBWVlnQWtJZ2lIeDhJZ0pDLy8vLy93K0RJUVVnQWtJZ2lDRVNJQW9nQ2tMOS8vUC9EMzVDLy8vLy93K0RJZ05DcTlYKy93OStmRUlnaUNBUUlBTkMvLy83end0K2ZId2lBa0wvLy8vL0Q0TWhDaUFQSUFOQy8vL1BpZ3QrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVRSUE0Z0EwTCsvNi8xQVg1OElBSkNJSWg4SWdKQy8vLy8vdytESVE4Z0RTQURRcVRzdzdVUGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaERpQU1JQU5Db0tYRHVRWitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU5JQXNnQTBLL3BaU2NEMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXdnQ1NBRFFvU1gzYU1HZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ3lBSUlBTkMxOW11bWdSK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSklBY2dBMEsyeis3WUJINThJQUpDSUloOElnSkMvLy8vL3crRElRZ2dCaUFEUXByTi84c0RmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCeUFFSUFOQzZxT0UwQUYrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVHSUFVZ0FrSWdpSHdpQWtMLy8vLy9ENE1oQkNBU0lBSkNJSWg4SVFVZ0N5QVlJQmgrZkNJQ1F2Ly8vLzhQZ3lFTElBa2dHQ0FaZmlJRFF2Ly8vLzhQZzBJQmhud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENTQURRaUNJUWdHR0lBSkNJSWg4SUFnZ0dDQWFmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRZ2dBMElnaUVJQmhpQUNRaUNJZkNBSElCZ2dHMzRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUhJQU5DSUloQ0FZWWdBa0lnaUh3Z0JpQVlJQngrSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhCaUFEUWlDSVFnR0dJQUpDSUloOElBUWdFU0FZZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUVFnQlNBRFFpQ0lRZ0dHSUFKQ0lJaDhmQ0lDUXYvLy8vOFBneUVGSUFKQ0lJZ2hFaUFLSUFwQy9mL3ovdzkrUXYvLy8vOFBneUlEUXF2Vi92OFBmbnhDSUlnZ0VDQURRdi8vKzg4TGZueDhJZ0pDLy8vLy93K0RJUW9nRHlBRFF2Ly96NG9MZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oRUNBT0lBTkMvdit2OVFGK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFUElBMGdBMEtrN01PMUQzNThJQUpDSUloOElnSkMvLy8vL3crRElRNGdEQ0FEUXFDbHc3a0dmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhEU0FMSUFOQ3Y2V1VuQTkrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVNSUFrZ0EwS0VsOTJqQm41OElBSkNJSWg4SWdKQy8vLy8vdytESVFzZ0NDQURRdGZacnBvRWZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENTQUhJQU5DdHMvdTJBUitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUlJQVlnQTBLYXpmL0xBMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUWNnQkNBRFF1cWpoTkFCZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQmlBRklBSkNJSWg4SWdKQy8vLy8vdytESVFRZ0VpQUNRaUNJZkNFRklBa2dHU0FaZm53aUFrTC8vLy8vRDRNaENTQUlJQmtnR240aUEwTC8vLy8vRDROQ0FZWjhJQUpDSUloOElnSkMvLy8vL3crRElRZ2dBMElnaUVJQmhpQUNRaUNJZkNBSElCa2dHMzRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUhJQU5DSUloQ0FZWWdBa0lnaUh3Z0JpQVpJQngrSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhCaUFEUWlDSVFnR0dJQUpDSUloOElBUWdFU0FaZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUVFnQlNBRFFpQ0lRZ0dHSUFKQ0lJaDhmQ0lDUXYvLy8vOFBneUVGSUFKQ0lJZ2hFaUFLSUFwQy9mL3ovdzkrUXYvLy8vOFBneUlEUXF2Vi92OFBmbnhDSUlnZ0VDQURRdi8vKzg4TGZueDhJZ0pDLy8vLy93K0RJUW9nRHlBRFF2Ly96NG9MZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oRUNBT0lBTkMvdit2OVFGK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFUElBMGdBMEtrN01PMUQzNThJQUpDSUloOElnSkMvLy8vL3crRElRNGdEQ0FEUXFDbHc3a0dmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhEU0FMSUFOQ3Y2V1VuQTkrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVNSUFrZ0EwS0VsOTJqQm41OElBSkNJSWg4SWdKQy8vLy8vdytESVFzZ0NDQURRdGZacnBvRWZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENTQUhJQU5DdHMvdTJBUitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUlJQVlnQTBLYXpmL0xBMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUWNnQkNBRFF1cWpoTkFCZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQmlBRklBSkNJSWg4SWdKQy8vLy8vdytESVFRZ0VpQUNRaUNJZkNFRklBZ2dHaUFhZm53aUFrTC8vLy8vRDRNaENDQUhJQm9nRzM0aUEwTC8vLy8vRDROQ0FZWjhJQUpDSUloOElnSkMvLy8vL3crRElRY2dBMElnaUVJQmhpQUNRaUNJZkNBR0lCb2dISDRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUdJQU5DSUloQ0FZWWdBa0lnaUh3Z0JDQVJJQnArSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhCQ0FGSUFOQ0lJaENBWVlnQWtJZ2lIeDhJZ0pDLy8vLy93K0RJUVVnQWtJZ2lDRVNJQW9nQ2tMOS8vUC9EMzVDLy8vLy93K0RJZ05DcTlYKy93OStmRUlnaUNBUUlBTkMvLy83end0K2ZId2lBa0wvLy8vL0Q0TWhDaUFQSUFOQy8vL1BpZ3QrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVRSUE0Z0EwTCsvNi8xQVg1OElBSkNJSWg4SWdKQy8vLy8vdytESVE4Z0RTQURRcVRzdzdVUGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaERpQU1JQU5Db0tYRHVRWitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU5JQXNnQTBLL3BaU2NEMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXdnQ1NBRFFvU1gzYU1HZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ3lBSUlBTkMxOW11bWdSK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSklBY2dBMEsyeis3WUJINThJQUpDSUloOElnSkMvLy8vL3crRElRZ2dCaUFEUXByTi84c0RmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCeUFFSUFOQzZxT0UwQUYrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVHSUFVZ0FrSWdpSHdpQWtMLy8vLy9ENE1oQkNBU0lBSkNJSWg4SVFVZ0J5QWJJQnQrZkNJQ1F2Ly8vLzhQZ3lFSElBWWdHeUFjZmlJRFF2Ly8vLzhQZzBJQmhud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEJpQURRaUNJUWdHR0lBSkNJSWg4SUFRZ0VTQWJmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRUWdCU0FEUWlDSVFnR0dJQUpDSUloOGZDSUNRdi8vLy84UGd5RUZJQUpDSUlnaEVpQUtJQXBDL2Yvei93OStRdi8vLy84UGd5SURRcXZWL3Y4UGZueENJSWdnRUNBRFF2Ly8rODhMZm54OElnSkMvLy8vL3crRElRb2dEeUFEUXYvL3o0b0xmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhFQ0FPSUFOQy92K3Y5UUYrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVQSUEwZ0EwS2s3TU8xRDM1OElBSkNJSWg4SWdKQy8vLy8vdytESVE0Z0RDQURRcUNsdzdrR2Zud2dBa0lnaUh3aUFrTC8vLy8vRDRNaERTQUxJQU5DdjZXVW5BOStmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU1JQWtnQTBLRWw5MmpCbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQ0NBRFF0ZlpycG9FZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ1NBSElBTkN0cy91MkFSK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSUlBWWdBMEthemYvTEEzNThJQUpDSUloOElnSkMvLy8vL3crRElRY2dCQ0FEUXVxamhOQUJmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCaUFGSUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVFnRWlBQ1FpQ0lmQ0VGSUFZZ0hDQWNmbndpQWtMLy8vLy9ENE1oQmlBRUlCRWdISDRpQTBMLy8vLy9ENE5DQVlaOElBSkNJSWg4SWdKQy8vLy8vdytESVFRZ0JTQURRaUNJUWdHR0lBSkNJSWg4ZkNJQ1F2Ly8vLzhQZ3lFRklBSkNJSWdoRWlBS0lBcEMvZi96L3c5K1F2Ly8vLzhQZ3lJRFFxdlYvdjhQZm54Q0lJZ2dFQ0FEUXYvLys4OExmbng4SWdKQy8vLy8vdytESVFvZ0R5QURRdi8vejRvTGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEVDQU9JQU5DL3YrdjlRRitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RVBJQTBnQTBLazdNTzFEMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUTRnRENBRFFxQ2x3N2tHZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oRFNBTElBTkN2NldVbkE5K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFTUlBa2dBMEtFbDkyakJuNThJQUpDSUloOElnSkMvLy8vL3crRElRc2dDQ0FEUXRmWnJwb0VmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhDU0FISUFOQ3RzL3UyQVIrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVJSUFZZ0EwS2F6Zi9MQTM1OElBSkNJSWg4SWdKQy8vLy8vdytESVFjZ0JDQURRdXFqaE5BQmZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEJpQUZJQUpDSUloOElnSkMvLy8vL3crRElRUWdFaUFDUWlDSWZDRUZJQVFnRVNBUmZud2lBa0wvLy8vL0Q0TWhCQ0FGSUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVVnQWtJZ2lDRVNJQUVnQ2lBS1F2My84LzhQZmtMLy8vLy9ENE1pQTBLcjFmNy9EMzU4UWlDSUlCQWdBMEwvLy92UEMzNThmQ0lDUXYvLy8vOFBnejRDQUNBQklBOGdBMEwvLzgrS0MzNThJQUpDSUloOElnSkMvLy8vL3crRFBnSUVJQUVnRGlBRFF2Ny9yL1VCZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE0rQWdnZ0FTQU5JQU5DcE96RHRROStmQ0FDUWlDSWZDSUNRdi8vLy84UGd6NENEQ0FCSUF3Z0EwS2dwY081Qm41OElBSkNJSWg4SWdKQy8vLy8vdytEUGdJUUlBRWdDeUFEUXIrbGxKd1BmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TStBaFFnQVNBSklBTkNoSmZkb3daK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3o0Q0dDQUJJQWdnQTBMWDJhNmFCSDU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RQZ0ljSUFFZ0J5QURRcmJQN3RnRWZud2dBa0lnaUh3aUFrTC8vLy8vRDRNK0FpQWdBU0FHSUFOQ21zMy95d04rZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBnejRDSkNBQklBUWdBMExxbzRUUUFYNThJQUpDSUloOElnSkMvLy8vL3crRFBnSW9JQUVnQlNBQ1FpQ0lmQ0lDUXYvLy8vOFBnejRDTENBU0lBSkNJSWg4cHdSQUlBRkJ5QVVnQVJBSEdnVWdBVUhJQlJBRkJFQWdBVUhJQlNBQkVBY2FDd3NMQ2dBZ0FDQUFJQUVRRXdzTEFDQUFRZmdGSUFFUUV3c1ZBQ0FBUWZnUkVBQkJxQklRQVVINEVTQUJFQklMRVFBZ0FFSFlFaEFYUWRnU1FiZ0hFQVVMSXdBZ0FCQUNCRUJCQUE4TElBQkJpQk1RRjBHSUUwRzRCeEFGQkVCQmZ3OExRUUVMRndBZ0FDQUJFQmNnQVVISUJTQUJFQTBnQVNBQkVCWUxDUUJCcUFZZ0FCQUFDN3dCQVFKL0lBSVFBVUV3SVFNRFFDQUJJQU5QQkVBZ0EwRXdSZ1JBUWJnVEVCc0ZRYmdUUWZnRlFiZ1RFQk1MSUFCQnVCTkI2Qk1RRXlBQ1FlZ1RJQUlRRHlBQVFUQnFJUUFnQTBFd2FpRUREQUVMQ3lBQlFUQndJZ1JGQkVBUEMwSG9FeEFCUVFBaEFRTkFJQUVnQkVaRkJFQWdBU0FBTFFBQU9nRG9FeUFBUVFGcUlRQWdBVUVCYWlFQkRBRUxDeUFEUVRCR0JFQkJ1Qk1RR3dWQnVCTkIrQVZCdUJNUUV3dEI2Qk5CdUJOQjZCTVFFeUFDUWVnVElBSVFEd3NjQUNBQklBSkJtQlFRSEVHWUZFR1lGQkFXSUFCQm1CUWdBeEFUQytFQkFRSi9RUUJCQUNnQ0FDSUZJQUpCQVdwQk1HeHFOZ0lBSUFVUUd5QUZRVEJxSVFVRFFDQUNJQVpIQkVBZ0FCQUNCRUFnQlVFd2F5QUZFQUFGSUFBZ0JVRXdheUFGRUJNTElBQWdBV29oQUNBRlFUQnFJUVVnQmtFQmFpRUdEQUVMQ3lBQUlBRnJJUUFnQXlBQ1FRRnJJQVJzYWlFQ0lBVkJNR3NpQlNBRkVCb0RRQ0FHQkVBZ0FCQUNCRUFnQlNBRlFUQnJFQUFnQWhBQkJTQUZRVEJyUWNnVUVBQWdCU0FBSUFWQk1Hc1FFeUFGUWNnVUlBSVFFd3NnQUNBQmF5RUFJQUlnQkdzaEFpQUZRVEJySVFVZ0JrRUJheUVHREFFTEMwRUFJQVUyQWdBTExRRUJmd05BSUFFZ0EwWkZCRUFnQUNBQ0VCWWdBRUV3YWlFQUlBSkJNR29oQWlBRFFRRnFJUU1NQVFzTEN5MEJBWDhEUUNBQklBTkdSUVJBSUFBZ0FoQVhJQUJCTUdvaEFDQUNRVEJxSVFJZ0EwRUJhaUVEREFFTEN3dVhBZ0FnQWtVRVFDQURFQnNQQ3lBQVFmZ1VFQUFnQXhBYkEwQWdBa0VCYXlJQ0lBRnFMUUFBSVFBZ0F5QURFQlFnQUVHQUFVOEVRQ0FEUWZnVUlBTVFFeUFBUVlBQmF5RUFDeUFESUFNUUZDQUFRY0FBVHdSQUlBTkIrQlFnQXhBVElBQkJRR29oQUFzZ0F5QURFQlFnQUVFZ1R3UkFJQU5CK0JRZ0F4QVRJQUJCSUdzaEFBc2dBeUFERUJRZ0FFRVFUd1JBSUFOQitCUWdBeEFUSUFCQkVHc2hBQXNnQXlBREVCUWdBRUVJVHdSQUlBTkIrQlFnQXhBVElBQkJDR3NoQUFzZ0F5QURFQlFnQUVFRVR3UkFJQU5CK0JRZ0F4QVRJQUJCQkdzaEFBc2dBeUFERUJRZ0FFRUNUd1JBSUFOQitCUWdBeEFUSUFCQkFtc2hBQXNnQXlBREVCUWdBQVJBSUFOQitCUWdBeEFUQ3lBQ0RRQUxDOVVCQVFGL0lBQVFBZ1JBSUFFUUFROExRUUVoQWtHWUNFR29GUkFBSUFCQjZBZEJNRUhZRlJBaElBQkJ5QWhCTUVHSUZoQWhBMEJCMkJWQnFBWVFCRVVFUUVIWUZVRzRGaEFVUVFFaEFBTkFRYmdXUWFnR0VBUkZCRUJCdUJaQnVCWVFGQ0FBUVFGcUlRQU1BUXNMUWFnVlFlZ1dFQUFnQWlBQWEwRUJheUVDQTBBZ0FnUkFRZWdXUWVnV0VCUWdBa0VCYXlFQ0RBRUxDeUFBSVFKQjZCWkJxQlVRRkVIWUZVR29GVUhZRlJBVFFZZ1dRZWdXUVlnV0VCTU1BUXNMUVlnV0VCZ0VRRUdJRmlBQkVCRUZRWWdXSUFFUUFBc0xJQUFnQUJBQ0JFQkJBUThMSUFCQmlBZEJNRUdZRnhBaFFaZ1hRYWdHRUFRTEtnQWdBU0FBS1FNQU53TUFJQUVnQUNrRENEY0RDQ0FCSUFBcEF4QTNBeEFnQVNBQUtRTVlOd01ZQ3g0QUlBQkNBRGNEQUNBQVFnQTNBd2dnQUVJQU53TVFJQUJDQURjREdBc3NBQ0FBS1FNWVVBUitJQUFwQXhCUUJINGdBQ2tEQ0ZBRWZpQUFLUU1BQlVJQkN3VkNBUXNGUWdFTFVBc2VBQ0FBUWdFM0F3QWdBRUlBTndNSUlBQkNBRGNERUNBQVFnQTNBeGdMUUFBZ0FDa0RHQ0FCS1FNWVVRUi9JQUFwQXhBZ0FTa0RFRkVFZnlBQUtRTUlJQUVwQXdoUkJIOGdBQ2tEQUNBQktRTUFVUVZCQUFzRlFRQUxCVUVBQ3d0ekFDQUFLUU1ZSUFFcEF4aFVCSDlCQUFVZ0FDa0RHQ0FCS1FNWVZnUi9RUUVGSUFBcEF4QWdBU2tERUZRRWYwRUFCU0FBS1FNUUlBRXBBeEJXQkg5QkFRVWdBQ2tEQ0NBQktRTUlWQVIvUVFBRklBQXBBd2dnQVNrRENGWUVmMEVCQlNBQUtRTUFJQUVwQXdCYUN3c0xDd3NMQzhRQkFRRitJQUlnQURVQ0FDQUJOUUlBZkNJRFBnSUFJQUlnQURVQ0JDQUJOUUlFZkNBRFFpQ0lmQ0lEUGdJRUlBSWdBRFVDQ0NBQk5RSUlmQ0FEUWlDSWZDSURQZ0lJSUFJZ0FEVUNEQ0FCTlFJTWZDQURRaUNJZkNJRFBnSU1JQUlnQURVQ0VDQUJOUUlRZkNBRFFpQ0lmQ0lEUGdJUUlBSWdBRFVDRkNBQk5RSVVmQ0FEUWlDSWZDSURQZ0lVSUFJZ0FEVUNHQ0FCTlFJWWZDQURRaUNJZkNJRFBnSVlJQUlnQURVQ0hDQUJOUUljZkNBRFFpQ0lmQ0lEUGdJY0lBTkNJSWluQy93QkFRRitJQUlnQURVQ0FDQUJOUUlBZlNJRFF2Ly8vLzhQZ3o0Q0FDQUNJQUExQWdRZ0FUVUNCSDBnQTBJZ2gzd2lBMEwvLy8vL0Q0TStBZ1FnQWlBQU5RSUlJQUUxQWdoOUlBTkNJSWQ4SWdOQy8vLy8vdytEUGdJSUlBSWdBRFVDRENBQk5RSU1mU0FEUWlDSGZDSURRdi8vLy84UGd6NENEQ0FDSUFBMUFoQWdBVFVDRUgwZ0EwSWdoM3dpQTBMLy8vLy9ENE0rQWhBZ0FpQUFOUUlVSUFFMUFoUjlJQU5DSUlkOElnTkMvLy8vL3crRFBnSVVJQUlnQURVQ0dDQUJOUUlZZlNBRFFpQ0hmQ0lEUXYvLy8vOFBnejRDR0NBQ0lBQTFBaHdnQVRVQ0hIMGdBMElnaDN3aUEwTC8vLy8vRDRNK0Fod2dBMElnaDZjTDVnNEJFWDRnQkNBQU5RSUFJZ1VnQVRVQ0FDSUdmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FDSUFNK0FnQWdCRUlnaUNFRElBTWdCU0FCTlFJRUlnZCtJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nQURVQ0JDSUlJQVorSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFJZ0JENENCQ0FEUWlDSUlRUWdCQ0FGSUFFMUFnZ2lDWDRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBSElBaCtJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnQURVQ0NDSUtJQVorSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFJZ0F6NENDQ0FFUWlDSUlRTWdBeUFGSUFFMUFnd2lDMzRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQXlBSUlBbCtJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nQnlBS2ZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQUExQWd3aURDQUdmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFDSUFRK0Fnd2dBMElnaUNFRUlBUWdCU0FCTlFJUUlnMStJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnQ0NBTGZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQWtnQ240Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0JDQUhJQXgrSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0FEVUNFQ0lPSUFaK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBSWdBejRDRUNBRVFpQ0lJUU1nQXlBRklBRTFBaFFpRDM0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QUlJQTErSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0NpQUxmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFrZ0RINGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBeUFISUE1K0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdBRFVDRkNJUUlBWitJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQUlnQkQ0Q0ZDQURRaUNJSVFRZ0JDQUZJQUUxQWhnaUVYNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FJSUE5K0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdDaUFOZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBc2dESDRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBSklBNStJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQVFnQnlBUWZpQURRdi8vLy84UGczd2lBMElnaUh3aEJDQUVJQUExQWhnaUVpQUdmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FDSUFNK0FoZ2dCRUlnaUNFRElBTWdCU0FCTlFJY0loTitJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nQ0NBUmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQW9nRDM0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QU1JQTErSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0N5QU9maUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUFrZ0VINGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBeUFISUJKK0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdBRFVDSENJRklBWitJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQUlnQkQ0Q0hDQURRaUNJSVFRZ0JDQUlJQk4rSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0NpQVJmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUF3Z0QzNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FOSUE1K0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdDeUFRZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBa2dFbjRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQkNBRklBZCtJQU5DLy8vLy93K0RmQ0lEUWlDSWZDRUVJQUlnQXo0Q0lDQUVRaUNJSVFNZ0F5QUtJQk4rSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFNZ0RDQVJmaUFFUXYvLy8vOFBnM3dpQkVJZ2lId2hBeUFESUE0Z0QzNGdCRUwvLy8vL0Q0TjhJZ1JDSUloOElRTWdBeUFOSUJCK0lBUkMvLy8vL3crRGZDSUVRaUNJZkNFRElBTWdDeUFTZmlBRVF2Ly8vLzhQZzN3aUJFSWdpSHdoQXlBRElBVWdDWDRnQkVMLy8vLy9ENE44SWdSQ0lJaDhJUU1nQWlBRVBnSWtJQU5DSUlnaEJDQUVJQXdnRTM0Z0EwTC8vLy8vRDROOElnTkNJSWg4SVFRZ0JDQU9JQkYrSUFOQy8vLy8vdytEZkNJRFFpQ0lmQ0VFSUFRZ0R5QVFmaUFEUXYvLy8vOFBnM3dpQTBJZ2lId2hCQ0FFSUEwZ0VuNGdBMEwvLy8vL0Q0TjhJZ05DSUloOElRUWdCQ0FGSUF0K0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBSWdBejRDS0NBRVFpQ0lJUU1nQXlBT0lCTitJQVJDLy8vLy93K0RmQ0lFUWlDSWZDRURJQU1nRUNBUmZpQUVRdi8vLy84UGczd2lCRUlnaUh3aEF5QURJQThnRW40Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QUZJQTErSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFJZ0JENENMQ0FEUWlDSUlRUWdCQ0FRSUJOK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBUWdFU0FTZmlBRFF2Ly8vLzhQZzN3aUEwSWdpSHdoQkNBRUlBVWdEMzRnQTBMLy8vLy9ENE44SWdOQ0lJaDhJUVFnQWlBRFBnSXdJQVJDSUlnaEF5QURJQklnRTM0Z0JFTC8vLy8vRDROOElnUkNJSWg4SVFNZ0F5QUZJQkYrSUFSQy8vLy8vdytEZkNJRVFpQ0lmQ0VESUFJZ0JENENOQ0FEUWlDSUlRUWdCQ0FGSUJOK0lBTkMvLy8vL3crRGZDSURRaUNJZkNFRUlBSWdBejRDT0NBQ0lBUStBandMemcwQkRINGdBeUFBTlFJQUlnWWdCbjRnQWtMLy8vLy9ENE44SWdKQ0lJaDhJUU1nQVNBQ1BnSUFJQU1pQkVJZ2lDRUZJQUExQWdRaUJ5QUdmaUlDUWlDSVFnR0dJQUpDLy8vLy93K0RRZ0dHSWdKQ0lJaDhJUU1nQXlBQ1F2Ly8vLzhQZ3lBRVF2Ly8vLzhQZzN3aUFrSWdpSHdnQlh3aEF5QUJJQUkrQWdRZ0F5SUVRaUNJSVFVZ0FEVUNDQ0lJSUFaK0lnSkNJSWhDQVlZZ0FrTC8vLy8vRDROQ0FZWWlBa0lnaUh3aEF5QURJQWNnQjM0Z0FrTC8vLy8vRDROOElnSkNJSWg4SVFNZ0F5QUNRdi8vLy84UGd5QUVRdi8vLy84UGczd2lBa0lnaUh3Z0JYd2hBeUFCSUFJK0FnZ2dBeUlFUWlDSUlRVWdBRFVDRENJSklBWitJZ0pDSUlnaEF5QURJQWNnQ0g0Z0FrTC8vLy8vRDROOElnSkNJSWg4UWdHR0lBSkMvLy8vL3crRFFnR0dJZ0pDSUloOElRTWdBeUFDUXYvLy8vOFBneUFFUXYvLy8vOFBnM3dpQWtJZ2lId2dCWHdoQXlBQklBSStBZ3dnQXlJRVFpQ0lJUVVnQURVQ0VDSUtJQVorSWdKQ0lJZ2hBeUFESUFjZ0NYNGdBa0wvLy8vL0Q0TjhJZ0pDSUloOFFnR0dJQUpDLy8vLy93K0RRZ0dHSWdKQ0lJaDhJUU1nQXlBSUlBaCtJQUpDLy8vLy93K0RmQ0lDUWlDSWZDRURJQU1nQWtMLy8vLy9ENE1nQkVMLy8vLy9ENE44SWdKQ0lJaDhJQVY4SVFNZ0FTQUNQZ0lRSUFNaUJFSWdpQ0VGSUFBMUFoUWlDeUFHZmlJQ1FpQ0lJUU1nQXlBSElBcCtJQUpDLy8vLy93K0RmQ0lDUWlDSWZDRURJQU1nQ0NBSmZpQUNRdi8vLy84UGczd2lBa0lnaUh4Q0FZWWdBa0wvLy8vL0Q0TkNBWVlpQWtJZ2lId2hBeUFESUFKQy8vLy8vdytESUFSQy8vLy8vdytEZkNJQ1FpQ0lmQ0FGZkNFRElBRWdBajRDRkNBRElnUkNJSWdoQlNBQU5RSVlJZ3dnQm40aUFrSWdpQ0VESUFNZ0J5QUxmaUFDUXYvLy8vOFBnM3dpQWtJZ2lId2hBeUFESUFnZ0NuNGdBa0wvLy8vL0Q0TjhJZ0pDSUloOFFnR0dJQUpDLy8vLy93K0RRZ0dHSWdKQ0lJaDhJUU1nQXlBSklBbCtJQUpDLy8vLy93K0RmQ0lDUWlDSWZDRURJQU1nQWtMLy8vLy9ENE1nQkVMLy8vLy9ENE44SWdKQ0lJaDhJQVY4SVFNZ0FTQUNQZ0lZSUFNaUJFSWdpQ0VGSUFBMUFod2lEU0FHZmlJQ1FpQ0lJUU1nQXlBSElBeCtJQUpDLy8vLy93K0RmQ0lDUWlDSWZDRURJQU1nQ0NBTGZpQUNRdi8vLy84UGczd2lBa0lnaUh3aEF5QURJQWtnQ240Z0FrTC8vLy8vRDROOElnSkNJSWg4UWdHR0lBSkMvLy8vL3crRFFnR0dJZ0pDSUloOElRTWdBeUFDUXYvLy8vOFBneUFFUXYvLy8vOFBnM3dpQWtJZ2lId2dCWHdoQXlBQklBSStBaHdnQXlJRVFpQ0lJUVVnQnlBTmZpSUNRaUNJSVFNZ0F5QUlJQXgrSUFKQy8vLy8vdytEZkNJQ1FpQ0lmQ0VESUFNZ0NTQUxmaUFDUXYvLy8vOFBnM3dpQWtJZ2lIeENBWVlnQWtMLy8vLy9ENE5DQVlZaUFrSWdpSHdoQXlBRElBb2dDbjRnQWtMLy8vLy9ENE44SWdKQ0lJaDhJUU1nQXlBQ1F2Ly8vLzhQZ3lBRVF2Ly8vLzhQZzN3aUFrSWdpSHdnQlh3aEF5QUJJQUkrQWlBZ0F5SUVRaUNJSVFVZ0NDQU5maUlDUWlDSUlRTWdBeUFKSUF4K0lBSkMvLy8vL3crRGZDSUNRaUNJZkNFRElBTWdDaUFMZmlBQ1F2Ly8vLzhQZzN3aUFrSWdpSHhDQVlZZ0FrTC8vLy8vRDROQ0FZWWlBa0lnaUh3aEF5QURJQUpDLy8vLy93K0RJQVJDLy8vLy93K0RmQ0lDUWlDSWZDQUZmQ0VESUFFZ0FqNENKQ0FESWdSQ0lJZ2hCU0FKSUExK0lnSkNJSWdoQXlBRElBb2dESDRnQWtMLy8vLy9ENE44SWdKQ0lJaDhRZ0dHSUFKQy8vLy8vdytEUWdHR0lnSkNJSWg4SVFNZ0F5QUxJQXQrSUFKQy8vLy8vdytEZkNJQ1FpQ0lmQ0VESUFNZ0FrTC8vLy8vRDRNZ0JFTC8vLy8vRDROOElnSkNJSWg4SUFWOElRTWdBU0FDUGdJb0lBTWlCRUlnaUNFRklBb2dEWDRpQWtJZ2lDRURJQU1nQ3lBTWZpQUNRdi8vLy84UGczd2lBa0lnaUh4Q0FZWWdBa0wvLy8vL0Q0TkNBWVlpQWtJZ2lId2hBeUFESUFKQy8vLy8vdytESUFSQy8vLy8vdytEZkNJQ1FpQ0lmQ0FGZkNFRElBRWdBajRDTENBRElnUkNJSWdoQlNBTElBMStJZ0pDSUloQ0FZWWdBa0wvLy8vL0Q0TkNBWVlpQWtJZ2lId2hBeUFESUF3Z0RINGdBa0wvLy8vL0Q0TjhJZ0pDSUloOElRTWdBeUFDUXYvLy8vOFBneUFFUXYvLy8vOFBnM3dpQWtJZ2lId2dCWHdoQXlBQklBSStBakFnQXlJRVFpQ0lJUVVnRENBTmZpSUNRaUNJUWdHR0lBSkMvLy8vL3crRFFnR0dJZ0pDSUloOElRTWdBeUFDUXYvLy8vOFBneUFFUXYvLy8vOFBnM3dpQWtJZ2lId2dCWHdoQXlBQklBSStBalFnQXlJRVFpQ0lJUVZDQUNFQ1FnQWhBeUFESUEwZ0RYNGdBa0wvLy8vL0Q0TjhJZ0pDSUloOElRTWdBeUFDUXYvLy8vOFBneUFFUXYvLy8vOFBnM3dpQWtJZ2lId2dCWHdoQXlBQklBSStBamdnQVNBRFBnSThDd29BSUFBZ0FDQUJFQ3dMc2dNQ0EzNEJmeUFBSUFOQmlCZ2dBeHNpQXhBa0lBRkJ5QmNRSkNBQ1FlZ1hJQUliSWdjUUpVR29HQkFsUVI4aEFFRWZJUUVEUUNBQlFjZ1hhaTBBQUNBQlFRTkdja1VFUUNBQlFRRnJJUUVNQVFzTElBRkJ4UmRxTlFBQVFnRjhJZ1pDQVZFRVFFSUFRZ0NBR2dzRFFBSkFBMEFnQUNBRGFpMEFBQ0FBUVFkR2NrVUVRQ0FBUVFGcklRQU1BUXNMSUFBZ0EycEJCMnNwQUFBZ0JvQWhCQ0FBSUFGclFRUnJJUUlEUUNBRVFvQ0FnSUJ3ZzFBZ0FrRUFUbkZGQkVBZ0JFSUlpQ0VFSUFKQkFXb2hBZ3dCQ3dzZ0JGQUVRQ0FEUWNnWEVDbEZEUUZDQVNFRVFRQWhBZ3RCeUJoQnlCYzFBQUFnQkg0aUJUNEFBRUhNR0VITUZ6VUFBQ0FFZmlBRlFpQ0lmQ0lGUGdBQVFkQVlRZEFYTlFBQUlBUitJQVZDSUloOElnVStBQUJCMUJoQjFCYzFBQUFnQkg0Z0JVSWdpSHdpQlQ0QUFFSFlHRUhZRnpVQUFDQUVmaUFGUWlDSWZDSUZQZ0FBUWR3WVFkd1hOUUFBSUFSK0lBVkNJSWg4SWdVK0FBQkI0QmhCNEJjMUFBQWdCSDRnQlVJZ2lId2lCVDRBQUVIa0dFSGtGelVBQUNBRWZpQUZRaUNJZkQ0QUFDQURRY2dZSUFKcklBTVFLeG9nQWlBSGFpQUVFQXNNQVFzTEM0NENBUXAvUWVnWUlRTkI2QmdRSlVHSUdTRUlJQUZCaUJrUUpFR29HU0VKUWFnWkVDZEJ5QmtoQmlBQVFjZ1pFQ1JCNkJraEMwR0lHaUVLUWVnYUlRUURRQ0FHRUNaRkJFQWdDQ0FHSUFzZ0NoQXZJQXNnQ1VHb0doQXNJQWNFZnlBRkJIOUJxQm9nQXhBcEJIOUJxQm9nQXlBRUVDc2FRUUFGSUFOQnFCb2dCQkFyR2tFQkN3VkJxQm9nQXlBRUVDb2FRUUVMQlNBRkJIOUJxQm9nQXlBRUVDb2FRUUFGSUFOQnFCb1FLUVIvSUFOQnFCb2dCQkFyR2tFQUJVR29HaUFESUFRUUt4cEJBUXNMQ3lFTUlBTWhBQ0FKSVFNZ0JDRUpJQUFoQkNBRklRY2dEQ0VGSUFnaEFDQUdJUWdnQ2lFR0lBQWhDZ3dCQ3dzZ0J3UkFJQUVnQXlBQ0VDc2FCU0FESUFJUUpBc0xDUUFnQUVISUd4QW9DeXdBSUFBZ0FTQUNFQ29FUUNBQ1FZZ2JJQUlRS3hvRklBSkJpQnNRS1FSQUlBSkJpQnNnQWhBckdnc0xDeGNBSUFBZ0FTQUNFQ3NFUUNBQ1FZZ2JJQUlRS2hvTEN3c0FRZWdiSUFBZ0FSQXpDN1lQQVFOK0lBQWdBRFVDQUVMLy8vLy9EeUlFSUFBMUFnQitRdi8vLy84UGd5SURRWWdiTlFJQWZud2lBajRDQUNBQUlBQTFBZ1FnQWtJZ2lIeEJqQnMxQWdBZ0EzNThJZ0krQWdRZ0FDQUFOUUlJSUFKQ0lJaDhRWkFiTlFJQUlBTitmQ0lDUGdJSUlBQWdBRFVDRENBQ1FpQ0lmRUdVR3pVQ0FDQURmbndpQWo0Q0RDQUFJQUExQWhBZ0FrSWdpSHhCbUJzMUFnQWdBMzU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UVp3Yk5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVHZ0d6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QnBCczFBZ0FnQTM1OElnSStBaHhCcUIwZ0FrSWdpRDRDQUNBQUlBQTFBZ1FnQURVQ0JDQUVma0wvLy8vL0Q0TWlBMEdJR3pVQ0FINThJZ0krQWdRZ0FDQUFOUUlJSUFKQ0lJaDhRWXdiTlFJQUlBTitmQ0lDUGdJSUlBQWdBRFVDRENBQ1FpQ0lmRUdRR3pVQ0FDQURmbndpQWo0Q0RDQUFJQUExQWhBZ0FrSWdpSHhCbEJzMUFnQWdBMzU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UVpnYk5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVHY0d6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4Qm9CczFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFhUWJOUUlBSUFOK2ZDSUNQZ0lnUWF3ZElBSkNJSWcrQWdBZ0FDQUFOUUlJSUFBMUFnZ2dCSDVDLy8vLy93K0RJZ05CaUJzMUFnQitmQ0lDUGdJSUlBQWdBRFVDRENBQ1FpQ0lmRUdNR3pVQ0FDQURmbndpQWo0Q0RDQUFJQUExQWhBZ0FrSWdpSHhCa0JzMUFnQWdBMzU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UVpRYk5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVHWUd6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4Qm5CczFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFhQWJOUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFR2tHelVDQUNBRGZud2lBajRDSkVHd0hTQUNRaUNJUGdJQUlBQWdBRFVDRENBQU5RSU1JQVIrUXYvLy8vOFBneUlEUVlnYk5RSUFmbndpQWo0Q0RDQUFJQUExQWhBZ0FrSWdpSHhCakJzMUFnQWdBMzU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UVpBYk5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVHVUd6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4Qm1CczFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFad2JOUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFR2dHelVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEJwQnMxQWdBZ0EzNThJZ0krQWloQnRCMGdBa0lnaUQ0Q0FDQUFJQUExQWhBZ0FEVUNFQ0FFZmtMLy8vLy9ENE1pQTBHSUd6VUNBSDU4SWdJK0FoQWdBQ0FBTlFJVUlBSkNJSWg4UVl3Yk5RSUFJQU4rZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVHUUd6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QmxCczFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFaZ2JOUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFR2NHelVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEJvQnMxQWdBZ0EzNThJZ0krQWlnZ0FDQUFOUUlzSUFKQ0lJaDhRYVFiTlFJQUlBTitmQ0lDUGdJc1FiZ2RJQUpDSUlnK0FnQWdBQ0FBTlFJVUlBQTFBaFFnQkg1Qy8vLy8vdytESWdOQmlCczFBZ0IrZkNJQ1BnSVVJQUFnQURVQ0dDQUNRaUNJZkVHTUd6VUNBQ0FEZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QmtCczFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFaUWJOUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFR1lHelVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEJuQnMxQWdBZ0EzNThJZ0krQWlnZ0FDQUFOUUlzSUFKQ0lJaDhRYUFiTlFJQUlBTitmQ0lDUGdJc0lBQWdBRFVDTUNBQ1FpQ0lmRUdrR3pVQ0FDQURmbndpQWo0Q01FRzhIU0FDUWlDSVBnSUFJQUFnQURVQ0dDQUFOUUlZSUFSK1F2Ly8vLzhQZ3lJRFFZZ2JOUUlBZm53aUFqNENHQ0FBSUFBMUFod2dBa0lnaUh4QmpCczFBZ0FnQTM1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFaQWJOUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFR1VHelVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEJtQnMxQWdBZ0EzNThJZ0krQWlnZ0FDQUFOUUlzSUFKQ0lJaDhRWndiTlFJQUlBTitmQ0lDUGdJc0lBQWdBRFVDTUNBQ1FpQ0lmRUdnR3pVQ0FDQURmbndpQWo0Q01DQUFJQUExQWpRZ0FrSWdpSHhCcEJzMUFnQWdBMzU4SWdJK0FqUkJ3QjBnQWtJZ2lENENBQ0FBSUFBMUFod2dBRFVDSENBRWZrTC8vLy8vRDRNaUEwR0lHelVDQUg1OElnSStBaHdnQUNBQU5RSWdJQUpDSUloOFFZd2JOUUlBSUFOK2ZDSUNQZ0lnSUFBZ0FEVUNKQ0FDUWlDSWZFR1FHelVDQUNBRGZud2lBajRDSkNBQUlBQTFBaWdnQWtJZ2lIeEJsQnMxQWdBZ0EzNThJZ0krQWlnZ0FDQUFOUUlzSUFKQ0lJaDhRWmdiTlFJQUlBTitmQ0lDUGdJc0lBQWdBRFVDTUNBQ1FpQ0lmRUdjR3pVQ0FDQURmbndpQWo0Q01DQUFJQUExQWpRZ0FrSWdpSHhCb0JzMUFnQWdBMzU4SWdJK0FqUWdBQ0FBTlFJNElBSkNJSWg4UWFRYk5RSUFJQU4rZkNJQ1BnSTRRY1FkSUFKQ0lJZytBZ0JCcUIwZ0FFRWdhaUFCRURJTGlCd0JFMzRnQlNBQk5RSUFJZ1FnQURVQ0FDSU9mbndpQTBMLy8vLy9ENE1oQlNBR0lBQTFBZ1FpRHlBRWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUhJQUExQWdnaUVDQUVmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCeUFJSUFBMUFnd2lFU0FFZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ0NBSklBQTFBaEFpRWlBRWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUtJQUExQWhRaUV5QUVmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDaUFMSUFBMUFoZ2lGQ0FFZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ3lBTUlBQTFBaHdpRlNBRWZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERDQURRaUNJSVEwZ0JTQUZRdi8vLy84UGZrTC8vLy8vRDRNaUJIeENJSWdnQmlBRVF2Ly8vLzhQZm54OElnTkMvLy8vL3crRElRVWdCeUFFUXY2MytmOFBmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFJSUFSQ2dzajJuUVYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFrZ0JFS0ZzSWZOQUg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NpQUVRb2l3NTVrRGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUxJQVJDeVByMXpBSitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUtJQXdnQkVMVHpyYWZCMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRFNBRFFpQ0lmQ0VNSUFVZ0RpQUJOUUlFSWdSK2ZDSURRdi8vLy84UGd5RUZJQVlnQkNBUGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUhJQVFnRUg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NDQUVJQkYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVJSUFrZ0JDQVNmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FLSUFRZ0UzNThJQU5DSUloOElnTkMvLy8vL3crRElRb2dDeUFFSUJSK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTElBd2dCQ0FWZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRENBRFFpQ0lJUTBnQlNBRlF2Ly8vLzhQZmtMLy8vLy9ENE1pQkh4Q0lJZ2dCaUFFUXYvLy8vOFBmbng4SWdOQy8vLy8vdytESVFVZ0J5QUVRdjYzK2Y4UGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUlJQVJDZ3NqMm5RVitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUhJQWtnQkVLRnNJZk5BSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWdnQ2lBRVFvaXc1NWtEZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ1NBTElBUkN5UHIxekFKK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFS0lBd2dCRUxUenJhZkIzNThJQU5DSUloOElnTkMvLy8vL3crRElRc2dEU0FEUWlDSWZDRU1JQVVnRGlBQk5RSUlJZ1IrZkNJRFF2Ly8vLzhQZ3lFRklBWWdCQ0FQZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQmlBSElBUWdFSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWNnQ0NBRUlCRitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUlJQWtnQkNBU2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUtJQVFnRTM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFvZ0N5QUVJQlIrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVMSUF3Z0JDQVZmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEQ0FEUWlDSUlRMGdCU0FGUXYvLy8vOFBma0wvLy8vL0Q0TWlCSHhDSUlnZ0JpQUVRdi8vLy84UGZueDhJZ05DLy8vLy93K0RJUVVnQnlBRVF2NjMrZjhQZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQmlBSUlBUkNnc2oyblFWK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSElBa2dCRUtGc0lmTkFINThJQU5DSUloOElnTkMvLy8vL3crRElRZ2dDaUFFUW9pdzU1a0RmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FMSUFSQ3lQcjF6QUorZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVLSUF3Z0JFTFR6cmFmQjM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFzZ0RTQURRaUNJZkNFTUlBVWdEaUFCTlFJTUlnUitmQ0lEUXYvLy8vOFBneUVGSUFZZ0JDQVBmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFISUFRZ0VINThJQU5DSUloOElnTkMvLy8vL3crRElRY2dDQ0FFSUJGK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSUlBa2dCQ0FTZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ1NBS0lBUWdFMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUW9nQ3lBRUlCUitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUxJQXdnQkNBVmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERDQURRaUNJSVEwZ0JTQUZRdi8vLy84UGZrTC8vLy8vRDRNaUJIeENJSWdnQmlBRVF2Ly8vLzhQZm54OElnTkMvLy8vL3crRElRVWdCeUFFUXY2MytmOFBmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFJSUFSQ2dzajJuUVYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFrZ0JFS0ZzSWZOQUg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NpQUVRb2l3NTVrRGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUxJQVJDeVByMXpBSitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUtJQXdnQkVMVHpyYWZCMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRFNBRFFpQ0lmQ0VNSUFVZ0RpQUJOUUlRSWdSK2ZDSURRdi8vLy84UGd5RUZJQVlnQkNBUGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUhJQVFnRUg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NDQUVJQkYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVJSUFrZ0JDQVNmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FLSUFRZ0UzNThJQU5DSUloOElnTkMvLy8vL3crRElRb2dDeUFFSUJSK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTElBd2dCQ0FWZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRENBRFFpQ0lJUTBnQlNBRlF2Ly8vLzhQZmtMLy8vLy9ENE1pQkh4Q0lJZ2dCaUFFUXYvLy8vOFBmbng4SWdOQy8vLy8vdytESVFVZ0J5QUVRdjYzK2Y4UGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUlJQVJDZ3NqMm5RVitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUhJQWtnQkVLRnNJZk5BSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWdnQ2lBRVFvaXc1NWtEZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ1NBTElBUkN5UHIxekFKK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFS0lBd2dCRUxUenJhZkIzNThJQU5DSUloOElnTkMvLy8vL3crRElRc2dEU0FEUWlDSWZDRU1JQVVnRGlBQk5RSVVJZ1IrZkNJRFF2Ly8vLzhQZ3lFRklBWWdCQ0FQZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQmlBSElBUWdFSDU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUWNnQ0NBRUlCRitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUlJQWtnQkNBU2Zud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUtJQVFnRTM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFvZ0N5QUVJQlIrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVMSUF3Z0JDQVZmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhEQ0FEUWlDSUlRMGdCU0FGUXYvLy8vOFBma0wvLy8vL0Q0TWlCSHhDSUlnZ0JpQUVRdi8vLy84UGZueDhJZ05DLy8vLy93K0RJUVVnQnlBRVF2NjMrZjhQZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQmlBSUlBUkNnc2oyblFWK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSElBa2dCRUtGc0lmTkFINThJQU5DSUloOElnTkMvLy8vL3crRElRZ2dDaUFFUW9pdzU1a0RmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FMSUFSQ3lQcjF6QUorZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVLSUF3Z0JFTFR6cmFmQjM1OElBTkNJSWg4SWdOQy8vLy8vdytESVFzZ0RTQURRaUNJZkNFTUlBVWdEaUFCTlFJWUlnUitmQ0lEUXYvLy8vOFBneUVGSUFZZ0JDQVBmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFISUFRZ0VINThJQU5DSUloOElnTkMvLy8vL3crRElRY2dDQ0FFSUJGK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFSUlBa2dCQ0FTZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oQ1NBS0lBUWdFMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUW9nQ3lBRUlCUitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUxJQXdnQkNBVmZud2dBMElnaUh3aUEwTC8vLy8vRDRNaERDQURRaUNJSVEwZ0JTQUZRdi8vLy84UGZrTC8vLy8vRDRNaUJIeENJSWdnQmlBRVF2Ly8vLzhQZm54OElnTkMvLy8vL3crRElRVWdCeUFFUXY2MytmOFBmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhCaUFJSUFSQ2dzajJuUVYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVISUFrZ0JFS0ZzSWZOQUg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFnZ0NpQUVRb2l3NTVrRGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaENTQUxJQVJDeVByMXpBSitmQ0FEUWlDSWZDSURRdi8vLy84UGd5RUtJQXdnQkVMVHpyYWZCMzU4SUFOQ0lJaDhJZ05DLy8vLy93K0RJUXNnRFNBRFFpQ0lmQ0VNSUFVZ0RpQUJOUUljSWdSK2ZDSURRdi8vLy84UGd5RUZJQVlnQkNBUGZud2dBMElnaUh3aUEwTC8vLy8vRDRNaEJpQUhJQVFnRUg1OElBTkNJSWg4SWdOQy8vLy8vdytESVFjZ0NDQUVJQkYrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBneUVJSUFrZ0JDQVNmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TWhDU0FLSUFRZ0UzNThJQU5DSUloOElnTkMvLy8vL3crRElRb2dDeUFFSUJSK2ZDQURRaUNJZkNJRFF2Ly8vLzhQZ3lFTElBd2dCQ0FWZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE1oRENBRFFpQ0lJUTBnQWlBRklBVkMvLy8vL3c5K1F2Ly8vLzhQZ3lJRWZFSWdpQ0FHSUFSQy8vLy8vdzkrZkh3aUEwTC8vLy8vRDRNK0FnQWdBaUFISUFSQy9yZjUvdzkrZkNBRFFpQ0lmQ0lEUXYvLy8vOFBnejRDQkNBQ0lBZ2dCRUtDeVBhZEJYNThJQU5DSUloOElnTkMvLy8vL3crRFBnSUlJQUlnQ1NBRVFvV3doODBBZm53Z0EwSWdpSHdpQTBMLy8vLy9ENE0rQWd3Z0FpQUtJQVJDaUxEbm1RTitmQ0FEUWlDSWZDSURRdi8vLy84UGd6NENFQ0FDSUFzZ0JFTEkrdlhNQW41OElBTkNJSWg4SWdOQy8vLy8vdytEUGdJVUlBSWdEQ0FFUXRQT3RwOEhmbndnQTBJZ2lId2lBMEwvLy8vL0Q0TStBaGdnQWlBTklBTkNJSWg4UGdJY0lBSkJpQnNRS1FSQUlBSkJpQnNnQWhBckdnc0xzQjBCRTM0Z0NDQUFOUUlBSWcwZ0RYNThJZ0pDLy8vLy93K0RJUWdnRENBQU5RSUVJZzhnRFg0aUEwTC8vLy8vRDROQ0FZWjhJQUpDSUloOElnSkMvLy8vL3crRElRd2dBMElnaUVJQmhpQUNRaUNJZkNBTElBQTFBZ2dpRUNBTmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFzZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FLSUFBMUFnd2lFU0FOZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUW9nQTBJZ2lFSUJoaUFDUWlDSWZDQUpJQUExQWhBaUVpQU5maUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRa2dBMElnaUVJQmhpQUNRaUNJZkNBSElBQTFBaFFpRXlBTmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFjZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FHSUFBMUFoZ2lGQ0FOZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUVlnQTBJZ2lFSUJoaUFDUWlDSWZDQUVJQTBnQURVQ0hDSU5maUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRUWdCU0FEUWlDSVFnR0dJQUpDSUloOGZDSUNRdi8vLy84UGd5RUZJQTRnQWtJZ2lId2hEaUFJSUFoQy8vLy8vdzkrUXYvLy8vOFBneUlEZkVJZ2lDQU1JQU5DLy8vLy93OStmSHdpQWtMLy8vLy9ENE1oQ0NBTElBTkMvcmY1L3c5K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFTUlBb2dBMEtDeVBhZEJYNThJQUpDSUloOElnSkMvLy8vL3crRElRc2dDU0FEUW9Xd2g4MEFmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhDaUFISUFOQ2lMRG5tUU4rZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVKSUFZZ0EwTEkrdlhNQW41OElBSkNJSWg4SWdKQy8vLy8vdytESVFjZ0JDQURRdFBPdHA4SGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEJpQUZJQUpDSUloOElnSkMvLy8vL3crRElRUWdEaUFDUWlDSWZDRUZJQXdnRHlBUGZud2lBa0wvLy8vL0Q0TWhEQ0FMSUE4Z0VINGlBMEwvLy8vL0Q0TkNBWVo4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQTBJZ2lFSUJoaUFDUWlDSWZDQUtJQThnRVg0aUEwTC8vLy8vRDROQ0FZWjhmQ0lDUXYvLy8vOFBneUVLSUFOQ0lJaENBWVlnQWtJZ2lId2dDU0FQSUJKK0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQ1NBRFFpQ0lRZ0dHSUFKQ0lJaDhJQWNnRHlBVGZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFjZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FHSUE4Z0ZINGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFR0lBTkNJSWhDQVlZZ0FrSWdpSHdnQkNBTklBOStJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJDQUZJQU5DSUloQ0FZWWdBa0lnaUh4OElnSkMvLy8vL3crRElRVWdBa0lnaUNFT0lBZ2dDRUwvLy8vL0QzNUMvLy8vL3crRElnTjhRaUNJSUF3Z0EwTC8vLy8vRDM1OGZDSUNRdi8vLy84UGd5RUlJQXNnQTBMK3Qvbi9EMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXdnQ2lBRFFvTEk5cDBGZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ3lBSklBTkNoYkNIelFCK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFS0lBY2dBMEtJc09lWkEzNThJQUpDSUloOElnSkMvLy8vL3crRElRa2dCaUFEUXNqNjljd0NmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCeUFFSUFOQzA4NjJud2QrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVHSUFVZ0FrSWdpSHdpQWtMLy8vLy9ENE1oQkNBT0lBSkNJSWg4SVFVZ0N5QVFJQkIrZkNJQ1F2Ly8vLzhQZ3lFTElBb2dFQ0FSZmlJRFF2Ly8vLzhQZzBJQmhud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENpQURRaUNJUWdHR0lBSkNJSWg4SUFrZ0VDQVNmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRa2dBMElnaUVJQmhpQUNRaUNJZkNBSElCQWdFMzRpQTBMLy8vLy9ENE5DQVlaOGZDSUNRdi8vLy84UGd5RUhJQU5DSUloQ0FZWWdBa0lnaUh3Z0JpQVFJQlIrSWdOQy8vLy8vdytEUWdHR2ZId2lBa0wvLy8vL0Q0TWhCaUFEUWlDSVFnR0dJQUpDSUloOElBUWdEU0FRZmlJRFF2Ly8vLzhQZzBJQmhueDhJZ0pDLy8vLy93K0RJUVFnQlNBRFFpQ0lRZ0dHSUFKQ0lJaDhmQ0lDUXYvLy8vOFBneUVGSUFKQ0lJZ2hEaUFJSUFoQy8vLy8vdzkrUXYvLy8vOFBneUlEZkVJZ2lDQU1JQU5DLy8vLy93OStmSHdpQWtMLy8vLy9ENE1oQ0NBTElBTkMvcmY1L3c5K2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFTUlBb2dBMEtDeVBhZEJYNThJQUpDSUloOElnSkMvLy8vL3crRElRc2dDU0FEUW9Xd2g4MEFmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhDaUFISUFOQ2lMRG5tUU4rZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVKSUFZZ0EwTEkrdlhNQW41OElBSkNJSWg4SWdKQy8vLy8vdytESVFjZ0JDQURRdFBPdHA4SGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEJpQUZJQUpDSUloOElnSkMvLy8vL3crRElRUWdEaUFDUWlDSWZDRUZJQW9nRVNBUmZud2lBa0wvLy8vL0Q0TWhDaUFKSUJFZ0VuNGlBMEwvLy8vL0Q0TkNBWVo4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUWtnQTBJZ2lFSUJoaUFDUWlDSWZDQUhJQkVnRTM0aUEwTC8vLy8vRDROQ0FZWjhmQ0lDUXYvLy8vOFBneUVISUFOQ0lJaENBWVlnQWtJZ2lId2dCaUFSSUJSK0lnTkMvLy8vL3crRFFnR0dmSHdpQWtMLy8vLy9ENE1oQmlBRFFpQ0lRZ0dHSUFKQ0lJaDhJQVFnRFNBUmZpSURRdi8vLy84UGcwSUJobng4SWdKQy8vLy8vdytESVFRZ0JTQURRaUNJUWdHR0lBSkNJSWg4ZkNJQ1F2Ly8vLzhQZ3lFRklBSkNJSWdoRGlBSUlBaEMvLy8vL3c5K1F2Ly8vLzhQZ3lJRGZFSWdpQ0FNSUFOQy8vLy8vdzkrZkh3aUFrTC8vLy8vRDRNaENDQUxJQU5DL3JmNS93OStmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RU1JQW9nQTBLQ3lQYWRCWDU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXNnQ1NBRFFvV3doODBBZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ2lBSElBTkNpTERubVFOK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFSklBWWdBMExJK3ZYTUFuNThJQUpDSUloOElnSkMvLy8vL3crRElRY2dCQ0FEUXRQT3RwOEhmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCaUFGSUFKQ0lJaDhJZ0pDLy8vLy93K0RJUVFnRGlBQ1FpQ0lmQ0VGSUFrZ0VpQVNmbndpQWtMLy8vLy9ENE1oQ1NBSElCSWdFMzRpQTBMLy8vLy9ENE5DQVlaOElBSkNJSWg4SWdKQy8vLy8vdytESVFjZ0EwSWdpRUlCaGlBQ1FpQ0lmQ0FHSUJJZ0ZINGlBMEwvLy8vL0Q0TkNBWVo4ZkNJQ1F2Ly8vLzhQZ3lFR0lBTkNJSWhDQVlZZ0FrSWdpSHdnQkNBTklCSitJZ05DLy8vLy93K0RRZ0dHZkh3aUFrTC8vLy8vRDRNaEJDQUZJQU5DSUloQ0FZWWdBa0lnaUh4OElnSkMvLy8vL3crRElRVWdBa0lnaUNFT0lBZ2dDRUwvLy8vL0QzNUMvLy8vL3crRElnTjhRaUNJSUF3Z0EwTC8vLy8vRDM1OGZDSUNRdi8vLy84UGd5RUlJQXNnQTBMK3Qvbi9EMzU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUXdnQ2lBRFFvTEk5cDBGZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQ3lBSklBTkNoYkNIelFCK2ZDQUNRaUNJZkNJQ1F2Ly8vLzhQZ3lFS0lBY2dBMEtJc09lWkEzNThJQUpDSUloOElnSkMvLy8vL3crRElRa2dCaUFEUXNqNjljd0NmbndnQWtJZ2lId2lBa0wvLy8vL0Q0TWhCeUFFSUFOQzA4NjJud2QrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVHSUFVZ0FrSWdpSHdpQWtMLy8vLy9ENE1oQkNBT0lBSkNJSWg4SVFVZ0J5QVRJQk4rZkNJQ1F2Ly8vLzhQZ3lFSElBWWdFeUFVZmlJRFF2Ly8vLzhQZzBJQmhud2dBa0lnaUh3aUFrTC8vLy8vRDRNaEJpQURRaUNJUWdHR0lBSkNJSWg4SUFRZ0RTQVRmaUlEUXYvLy8vOFBnMElCaG54OElnSkMvLy8vL3crRElRUWdCU0FEUWlDSVFnR0dJQUpDSUloOGZDSUNRdi8vLy84UGd5RUZJQUpDSUlnaERpQUlJQWhDLy8vLy93OStRdi8vLy84UGd5SURmRUlnaUNBTUlBTkMvLy8vL3c5K2ZId2lBa0wvLy8vL0Q0TWhDQ0FMSUFOQy9yZjUvdzkrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVNSUFvZ0EwS0N5UGFkQlg1OElBSkNJSWg4SWdKQy8vLy8vdytESVFzZ0NTQURRb1d3aDgwQWZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENpQUhJQU5DaUxEbm1RTitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUpJQVlnQTBMSSt2WE1BbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUWNnQkNBRFF0UE90cDhIZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQmlBRklBSkNJSWg4SWdKQy8vLy8vdytESVFRZ0RpQUNRaUNJZkNFRklBWWdGQ0FVZm53aUFrTC8vLy8vRDRNaEJpQUVJQTBnRkg0aUEwTC8vLy8vRDROQ0FZWjhJQUpDSUloOElnSkMvLy8vL3crRElRUWdCU0FEUWlDSVFnR0dJQUpDSUloOGZDSUNRdi8vLy84UGd5RUZJQUpDSUlnaERpQUlJQWhDLy8vLy93OStRdi8vLy84UGd5SURmRUlnaUNBTUlBTkMvLy8vL3c5K2ZId2lBa0wvLy8vL0Q0TWhDQ0FMSUFOQy9yZjUvdzkrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBneUVNSUFvZ0EwS0N5UGFkQlg1OElBSkNJSWg4SWdKQy8vLy8vdytESVFzZ0NTQURRb1d3aDgwQWZud2dBa0lnaUh3aUFrTC8vLy8vRDRNaENpQUhJQU5DaUxEbm1RTitmQ0FDUWlDSWZDSUNRdi8vLy84UGd5RUpJQVlnQTBMSSt2WE1BbjU4SUFKQ0lJaDhJZ0pDLy8vLy93K0RJUWNnQkNBRFF0UE90cDhIZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE1oQmlBRklBSkNJSWg4SWdKQy8vLy8vdytESVFRZ0RpQUNRaUNJZkNFRklBUWdEU0FOZm53aUFrTC8vLy8vRDRNaEJDQUZJQUpDSUloOElnSkMvLy8vL3crRElRVWdBa0lnaUNFT0lBRWdDQ0FJUXYvLy8vOFBma0wvLy8vL0Q0TWlBM3hDSUlnZ0RDQURRdi8vLy84UGZueDhJZ0pDLy8vLy93K0RQZ0lBSUFFZ0N5QURRdjYzK2Y4UGZud2dBa0lnaUh3aUFrTC8vLy8vRDRNK0FnUWdBU0FLSUFOQ2dzajJuUVYrZkNBQ1FpQ0lmQ0lDUXYvLy8vOFBnejRDQ0NBQklBa2dBMEtGc0lmTkFINThJQUpDSUloOElnSkMvLy8vL3crRFBnSU1JQUVnQnlBRFFvaXc1NWtEZm53Z0FrSWdpSHdpQWtMLy8vLy9ENE0rQWhBZ0FTQUdJQU5DeVByMXpBSitmQ0FDUWlDSWZDSUNRdi8vLy84UGd6NENGQ0FCSUFRZ0EwTFR6cmFmQjM1OElBSkNJSWg4SWdKQy8vLy8vdytEUGdJWUlBRWdCU0FDUWlDSWZDSUNRdi8vLy84UGd6NENIQ0FPSUFKQ0lJaDhwd1JBSUFGQmlCc2dBUkFyR2dVZ0FVR0lHeEFwQkVBZ0FVR0lHeUFCRUNzYUN3c0xDZ0FnQUNBQUlBRVFOZ3NMQUNBQVFhZ2JJQUVRTmdzVkFDQUFRYWdoRUNSQnlDRVFKVUdvSVNBQkVEVUxFUUFnQUVIb0lSQTZRZWdoUWFnY0VDa0xJd0FnQUJBbUJFQkJBQThMSUFCQmlDSVFPa0dJSWtHb0hCQXBCRUJCZnc4TFFRRUxGd0FnQUNBQkVEb2dBVUdJR3lBQkVEQWdBU0FCRURrTENRQkJ5QnNnQUJBa0M3d0JBUUovSUFJUUpVRWdJUU1EUUNBQklBTlBCRUFnQTBFZ1JnUkFRYWdpRUQ0RlFhZ2lRYWdiUWFnaUVEWUxJQUJCcUNKQnlDSVFOaUFDUWNnaUlBSVFNaUFBUVNCcUlRQWdBMEVnYWlFRERBRUxDeUFCUVI5eElnUkZCRUFQQzBISUloQWxRUUFoQVFOQUlBRWdCRVpGQkVBZ0FTQUFMUUFBT2dESUlpQUFRUUZxSVFBZ0FVRUJhaUVCREFFTEN5QURRU0JHQkVCQnFDSVFQZ1ZCcUNKQnFCdEJxQ0lRTmd0QnlDSkJxQ0pCeUNJUU5pQUNRY2dpSUFJUU1nc2NBQ0FCSUFKQjZDSVFQMEhvSWtIb0loQTVJQUJCNkNJZ0F4QTJDK0VCQVFKL1FRQkJBQ2dDQUNJRklBSkJBV3BCQlhScU5nSUFJQVVRUGlBRlFTQnFJUVVEUUNBQ0lBWkhCRUFnQUJBbUJFQWdCVUVnYXlBRkVDUUZJQUFnQlVFZ2F5QUZFRFlMSUFBZ0FXb2hBQ0FGUVNCcUlRVWdCa0VCYWlFR0RBRUxDeUFBSUFGcklRQWdBeUFDUVFGcklBUnNhaUVDSUFWQklHc2lCU0FGRUQwRFFDQUdCRUFnQUJBbUJFQWdCU0FGUVNCckVDUWdBaEFsQlNBRlFTQnJRWWdqRUNRZ0JTQUFJQVZCSUdzUU5pQUZRWWdqSUFJUU5nc2dBQ0FCYXlFQUlBSWdCR3NoQWlBRlFTQnJJUVVnQmtFQmF5RUdEQUVMQzBFQUlBVTJBZ0FMTFFFQmZ3TkFJQUVnQTBaRkJFQWdBQ0FDRURrZ0FFRWdhaUVBSUFKQklHb2hBaUFEUVFGcUlRTU1BUXNMQ3kwQkFYOERRQ0FCSUFOR1JRUkFJQUFnQWhBNklBQkJJR29oQUNBQ1FTQnFJUUlnQTBFQmFpRUREQUVMQ3d1WEFnQWdBa1VFUUNBREVENFBDeUFBUWFnakVDUWdBeEErQTBBZ0FrRUJheUlDSUFGcUxRQUFJUUFnQXlBREVEY2dBRUdBQVU4RVFDQURRYWdqSUFNUU5pQUFRWUFCYXlFQUN5QURJQU1RTnlBQVFjQUFUd1JBSUFOQnFDTWdBeEEySUFCQlFHb2hBQXNnQXlBREVEY2dBRUVnVHdSQUlBTkJxQ01nQXhBMklBQkJJR3NoQUFzZ0F5QURFRGNnQUVFUVR3UkFJQU5CcUNNZ0F4QTJJQUJCRUdzaEFBc2dBeUFERURjZ0FFRUlUd1JBSUFOQnFDTWdBeEEySUFCQkNHc2hBQXNnQXlBREVEY2dBRUVFVHdSQUlBTkJxQ01nQXhBMklBQkJCR3NoQUFzZ0F5QURFRGNnQUVFQ1R3UkFJQU5CcUNNZ0F4QTJJQUJCQW1zaEFBc2dBeUFERURjZ0FBUkFJQU5CcUNNZ0F4QTJDeUFDRFFBTEM5VUJBUUYvSUFBUUpnUkFJQUVRSlE4TFFTQWhBa0hvSEVISUl4QWtJQUJCeUJ4QklFSG9JeEJFSUFCQmlCMUJJRUdJSkJCRUEwQkI2Q05CeUJzUUtFVUVRRUhvSTBHb0pCQTNRUUVoQUFOQVFhZ2tRY2diRUNoRkJFQkJxQ1JCcUNRUU55QUFRUUZxSVFBTUFRc0xRY2dqUWNna0VDUWdBaUFBYTBFQmF5RUNBMEFnQWdSQVFjZ2tRY2drRURjZ0FrRUJheUVDREFFTEN5QUFJUUpCeUNSQnlDTVFOMEhvSTBISUkwSG9JeEEyUVlna1FjZ2tRWWdrRURZTUFRc0xRWWdrRURzRVFFR0lKQ0FCRURRRlFZZ2tJQUVRSkFzTElBQWdBQkFtQkVCQkFROExJQUJCaUJ4QklFSG9KQkJFUWVna1FjZ2JFQ2dMRlFBZ0FDQUJRWWdsRURaQmlDVkJxQnNnQWhBMkN3b0FJQUFnQUNBQkVFY0xDd0FnQUVHSUd5QUJFREFMQ1FBZ0FFR29IQkFwQ3c0QUlBQVFBaUFBUVRCcUVBSnhDd29BSUFCQjRBQnFFQUlMRFFBZ0FCQUJJQUJCTUdvUUFRc1ZBQ0FBRUFFZ0FFRXdhaEFiSUFCQjRBQnFFQUVMZWdBZ0FTQUFLUU1BTndNQUlBRWdBQ2tEQ0RjRENDQUJJQUFwQXhBM0F4QWdBU0FBS1FNWU53TVlJQUVnQUNrRElEY0RJQ0FCSUFBcEF5ZzNBeWdnQVNBQUtRTXdOd013SUFFZ0FDa0RPRGNET0NBQklBQXBBMEEzQTBBZ0FTQUFLUU5JTndOSUlBRWdBQ2tEVURjRFVDQUJJQUFwQTFnM0ExZ0x1Z0VBSUFFZ0FDa0RBRGNEQUNBQklBQXBBd2czQXdnZ0FTQUFLUU1RTndNUUlBRWdBQ2tER0RjREdDQUJJQUFwQXlBM0F5QWdBU0FBS1FNb053TW9JQUVnQUNrRE1EY0RNQ0FCSUFBcEF6ZzNBemdnQVNBQUtRTkFOd05BSUFFZ0FDa0RTRGNEU0NBQklBQXBBMUEzQTFBZ0FTQUFLUU5ZTndOWUlBRWdBQ2tEWURjRFlDQUJJQUFwQTJnM0EyZ2dBU0FBS1FOd053TndJQUVnQUNrRGVEY0RlQ0FCSUFBcEE0QUJOd09BQVNBQklBQXBBNGdCTndPSUFRc29BQ0FBRUVzRVFDQUJFRTRGSUFGQjRBQnFFQnNnQUVFd2FpQUJRVEJxRUFBZ0FDQUJFQUFMQ3hVQUlBQWdBUkFFSUFCQk1Hb2dBVUV3YWhBRWNRdHlBUUYvSUFBUVRBUkFJQUVRU3c4TElBRVFTd1JBUVFBUEN5QUFRZUFBYWlJQ0VBNEVRQ0FBSUFFUVVnOExJQUpCMkNVUUZDQUJRZGdsUVlnbUVCTWdBa0hZSlVHNEpoQVRJQUZCTUdwQnVDWkI2Q1lRRXlBQVFZZ21FQVFFUUNBQVFUQnFRZWdtRUFRRVFFRUJEd3NMUVFBTHJRRUJBbjhnQUJCTUJFQWdBUkJNRHdzZ0FSQk1CRUJCQUE4TElBQkI0QUJxSWdJUURnUkFJQUVnQUJCVER3c2dBVUhnQUdvaUF4QU9CRUFnQUNBQkVGTVBDeUFDUVpnbkVCUWdBMEhJSnhBVUlBQkJ5Q2RCK0NjUUV5QUJRWmduUWFnb0VCTWdBa0dZSjBIWUtCQVRJQU5CeUNkQmlDa1FFeUFBUVRCcVFZZ3BRYmdwRUJNZ0FVRXdha0hZS0VIb0tSQVRRZmduUWFnb0VBUUVRRUc0S1VIb0tSQUVCRUJCQVE4TEMwRUFDK2dCQUNBQUVFc0VRQ0FBSUFFUVVROExJQUJCbUNvUUZDQUFRVEJxUWNncUVCUkJ5Q3BCK0NvUUZDQUFRY2dxUWFnckVBOUJxQ3RCcUNzUUZFR29LMEdZS2tHb0t4QVFRYWdyUWZncVFhZ3JFQkJCcUN0QnFDdEJxQ3NRRDBHWUtrR1lLa0hZS3hBUFFkZ3JRWmdxUWRnckVBOGdBRUV3YWlBQVFUQnFJQUZCNEFCcUVBOUIyQ3NnQVJBVUlBRkJxQ3NnQVJBUUlBRkJxQ3NnQVJBUVFmZ3FRZmdxUVlnc0VBOUJpQ3hCaUN4QmlDd1FEMEdJTEVHSUxFR0lMQkFQUWFncklBRWdBVUV3YWhBUUlBRkJNR3BCMkNzZ0FVRXdhaEFUSUFGQk1HcEJpQ3dnQVVFd2FoQVFDNGdDQUNBQUVFd0VRQ0FBSUFFUVVBOExJQUJCNEFCcUVBNEVRQ0FBSUFFUVZROExJQUJCdUN3UUZDQUFRVEJxUWVnc0VCUkI2Q3hCbUMwUUZDQUFRZWdzUWNndEVBOUJ5QzFCeUMwUUZFSElMVUc0TEVISUxSQVFRY2d0UVpndFFjZ3RFQkJCeUMxQnlDMUJ5QzBRRDBHNExFRzRMRUg0TFJBUFFmZ3RRYmdzUWZndEVBOUIrQzFCcUM0UUZDQUFRVEJxSUFCQjRBQnFRZGd1RUJOQnlDMUJ5QzBnQVJBUFFhZ3VJQUVnQVJBUVFaZ3RRWmd0UVlndkVBOUJpQzlCaUM5QmlDOFFEMEdJTDBHSUwwR0lMeEFQUWNndElBRWdBVUV3YWhBUUlBRkJNR3BCK0MwZ0FVRXdhaEFUSUFGQk1HcEJpQzhnQVVFd2FoQVFRZGd1UWRndUlBRkI0QUJxRUE4TG1RSUFJQUFRU3dSQUlBRWdBaEJQSUFKQjRBQnFFQnNQQ3lBQkVFc0VRQ0FBSUFJUVR5QUNRZUFBYWhBYkR3c2dBQ0FCRUFRRVFDQUFRVEJxSUFGQk1Hb1FCQVJBSUFFZ0FoQlZEd3NMSUFFZ0FFRzRMeEFRSUFGQk1Hb2dBRUV3YWtHWU1CQVFRYmd2UWVndkVCUkI2QzlCNkM5QnlEQVFEMEhJTUVISU1FSElNQkFQUWJndlFjZ3dRZmd3RUJOQm1EQkJtREJCcURFUUR5QUFRY2d3UVlneUVCTkJxREZCMkRFUUZFR0lNa0dJTWtHNE1oQVBRZGd4UWZnd0lBSVFFQ0FDUWJneUlBSVFFQ0FBUVRCcVFmZ3dRZWd5RUJOQjZESkI2REpCNkRJUUQwR0lNaUFDSUFKQk1Hb1FFQ0FDUVRCcVFhZ3hJQUpCTUdvUUV5QUNRVEJxUWVneUlBSkJNR29RRUVHNEwwRzRMeUFDUWVBQWFoQVBDLzRDQVFGL0lBQVFUQVJBSUFFZ0FoQlBJQUpCNEFCcUVCc1BDeUFCRUVzRVFDQUFJQUlRVUE4TElBQkI0QUJxSWdNUURnUkFJQUFnQVNBQ0VGY1BDeUFEUVpnekVCUWdBVUdZTTBISU14QVRJQU5CbUROQitETVFFeUFCUVRCcVFmZ3pRYWcwRUJNZ0FFSElNeEFFQkVBZ0FFRXdha0dvTkJBRUJFQWdBU0FDRUZVUEN3dEJ5RE1nQUVIWU5CQVFRYWcwSUFCQk1HcEJ1RFVRRUVIWU5FR0lOUkFVUVlnMVFZZzFRZWcxRUE5QjZEVkI2RFZCNkRVUUQwSFlORUhvTlVHWU5oQVRRYmcxUWJnMVFjZzJFQThnQUVIb05VR29OeEFUUWNnMlFmZzJFQlJCcURkQnFEZEIyRGNRRDBINE5rR1lOaUFDRUJBZ0FrSFlOeUFDRUJBZ0FFRXdha0dZTmtHSU9CQVRRWWc0UVlnNFFZZzRFQTlCcURjZ0FpQUNRVEJxRUJBZ0FrRXdha0hJTmlBQ1FUQnFFQk1nQWtFd2FrR0lPQ0FDUVRCcUVCQWdBMEhZTkNBQ1FlQUFhaEFQSUFKQjRBQnFJQUpCNEFCcUVCUWdBa0hnQUdwQm1ETWdBa0hnQUdvUUVDQUNRZUFBYWtHSU5TQUNRZUFBYWhBUUM3WURBUUovSUFBUVRBUkFJQUVnQWhCUUR3c2dBUkJNQkVBZ0FDQUNFRkFQQ3lBQVFlQUFhaUlERUE0RVFDQUJJQUFnQWhCWUR3c2dBVUhnQUdvaUJCQU9CRUFnQUNBQklBSVFXQThMSUFOQnVEZ1FGQ0FFUWVnNEVCUWdBRUhvT0VHWU9SQVRJQUZCdURoQnlEa1FFeUFEUWJnNFFmZzVFQk1nQkVIb09FR29PaEFUSUFCQk1HcEJxRHBCMkRvUUV5QUJRVEJxUWZnNVFZZzdFQk5CbURsQnlEa1FCQVJBUWRnNlFZZzdFQVFFUUNBQUlBSVFWZzhMQzBISU9VR1lPVUc0T3hBUVFZZzdRZGc2UWVnN0VCQkJ1RHRCdUR0Qm1Ed1FEMEdZUEVHWVBCQVVRYmc3UVpnOFFjZzhFQk5CNkR0QjZEdEIrRHdRRDBHWU9VR1lQRUhZUFJBVFFmZzhRYWc5RUJSQjJEMUIyRDFCaUQ0UUQwR29QVUhJUENBQ0VCQWdBa0dJUGlBQ0VCQkIyRHBCeUR4QnVENFFFMEc0UGtHNFBrRzRQaEFQUWRnOUlBSWdBa0V3YWhBUUlBSkJNR3BCK0R3Z0FrRXdhaEFUSUFKQk1HcEJ1RDRnQWtFd2FoQVFJQU1nQkNBQ1FlQUFhaEFQSUFKQjRBQnFJQUpCNEFCcUVCUWdBa0hnQUdwQnVEZ2dBa0hnQUdvUUVDQUNRZUFBYWtIb09DQUNRZUFBYWhBUUlBSkI0QUJxUWJnN0lBSkI0QUJxRUJNTEZBQWdBQ0FCRUFBZ0FFRXdhaUFCUVRCcUVCRUxJZ0FnQUNBQkVBQWdBRUV3YWlBQlFUQnFFQkVnQUVIZ0FHb2dBVUhnQUdvUUFBc1NBQ0FCUWVnK0VGb2dBRUhvUGlBQ0VGY0xFZ0FnQVVINFB4QmFJQUJCK0Q4Z0FoQllDeFFBSUFGQmlNRUFFRnNnQUVHSXdRQWdBaEJaQ3hRQUlBQWdBUkFYSUFCQk1Hb2dBVUV3YWhBWEN5SUFJQUFnQVJBWElBQkJNR29nQVVFd2FoQVhJQUJCNEFCcUlBRkI0QUJxRUJjTEZBQWdBQ0FCRUJZZ0FFRXdhaUFCUVRCcUVCWUxJZ0FnQUNBQkVCWWdBRUV3YWlBQlFUQnFFQllnQUVIZ0FHb2dBVUhnQUdvUUZndFRBQ0FBRUV3RVFDQUJFQUVnQVVFd2FoQUJCU0FBUWVBQWFrR1l3Z0FRR2tHWXdnQkJ5TUlBRUJSQm1NSUFRY2pDQUVINHdnQVFFeUFBUWNqQ0FDQUJFQk1nQUVFd2FrSDR3Z0FnQVVFd2FoQVRDd3M0QUNBQVFUQnFRYWpEQUJBVUlBQkIyTU1BRUJRZ0FFSFl3d0JCMk1NQUVCTkIyTU1BUWFnbFFkakRBQkFQUWFqREFFSFl3d0FRQkFzUUFDQUFRWWpFQUJCalFZakVBQkJrQzVnQkFRTi9RUUJCQUNnQ0FDSUVJQUZCTUd4cU5nSUFJQUJCNEFCcVFaQUJJQUVnQkVFd0VCNGdCQ0VEQTBBZ0FTQUZSd1JBSUFNUUFnUkFJQUlRQVNBQ1FUQnFFQUVGSUFNZ0FFRXdha0hveEFBUUV5QURJQU1RRkNBRElBQWdBaEFUSUFOQjZNUUFJQUpCTUdvUUV3c2dBRUdRQVdvaEFDQUNRZUFBYWlFQ0lBTkJNR29oQXlBRlFRRnFJUVVNQVFzTFFRQWdCRFlDQUF0VUFDQUFFRXdFUUNBQkVFNEZJQUJCNEFCcVFaakZBQkFhUVpqRkFFSEl4UUFRRkVHWXhRQkJ5TVVBUWZqRkFCQVRJQUJCeU1VQUlBRVFFeUFBUVRCcVFmakZBQ0FCUVRCcUVCTWdBVUhnQUdvUUd3c0xNZ0FnQVNBQ2FrRUJheUVCQTBBZ0FTQUNTRVVFUUNBQklBQXRBQUE2QUFBZ0FVRUJheUVCSUFCQkFXb2hBQXdCQ3dzTExRQWdBQkJMQkVBZ0FSQk5Ed3NnQUVHb3hnQVFYMEdveGdCQk1DQUJFR2hCMk1ZQVFUQWdBVUV3YWhCb0MwTUFJQUFRU3dSQUlBRVFBU0FCUWNBQU9nQUFEd3NnQUVHSXh3QVFGMEdJeHdCQk1DQUJFR2dnQUVFd2FoQVpRWDlHQkVBZ0FTQUJMUUFBUVlBQmNqb0FBQXNMTWdBZ0FDMEFBRUhBQUhFRVFDQUJFRTBQQ3lBQVFUQkJ1TWNBRUdnZ0FFRXdha0V3UWVqSEFCQm9RYmpIQUNBQkVHRUx3UUVCQW44Z0FDMEFBQ0lDUWNBQWNRUkFJQUVRVFE4TElBSkJnQUZ4SVFNZ0FFSEl5QUFRQUVISXlBQWdBa0UvY1RvQUFFSEl5QUJCTUVHWXlBQVFhRUdZeUFBZ0FSQVdJQUZCeU1nQUVCUWdBVUhJeUFCQnlNZ0FFQk5CeU1nQVFhZ2xRY2pJQUJBUFFjaklBRUhJeUFBUUlrSEl5QUJCbU1nQUVCRkJ5TWdBRUJsQmYwWUVRQ0FEQkVCQnlNZ0FJQUZCTUdvUUFBVkJ5TWdBSUFGQk1Hb1FFUXNGSUFNRVFFSEl5QUFnQVVFd2FoQVJCVUhJeUFBZ0FVRXdhaEFBQ3dzTEx3RUJmd05BSUFFZ0EwWkZCRUFnQUNBQ0VHa2dBRUhnQUdvaEFDQUNRZUFBYWlFQ0lBTkJBV29oQXd3QkN3c0xMZ0VCZndOQUlBRWdBMFpGQkVBZ0FDQUNFR29nQUVIZ0FHb2hBQ0FDUVRCcUlRSWdBMEVCYWlFRERBRUxDd3N2QVFGL0EwQWdBU0FEUmtVRVFDQUFJQUlRYXlBQVFlQUFhaUVBSUFKQjRBQnFJUUlnQTBFQmFpRUREQUVMQ3d0SkFRRi9JQUFnQVVFQmEwRXdiR29oQUNBQ0lBRkJBV3RCNEFCc2FpRUNBMEFnQVNBRFJrVUVRQ0FBSUFJUWJDQUFRVEJySVFBZ0FrSGdBR3NoQWlBRFFRRnFJUU1NQVFzTEMwc0JBWDhnQUNBQlFRRnJRZUFBYkdvaEFDQUNJQUZCQVd0QmtBRnNhaUVDQTBBZ0FTQURSa1VFUUNBQUlBSVFVU0FBUWVBQWF5RUFJQUpCa0FGcklRSWdBMEVCYWlFRERBRUxDd3MxQUNBQlFRTjBJQUpySWdFZ0EwZ0VmMEVCSUFGMFFRRnJCVUVCSUFOMFFRRnJDeUFBSUFKQkEzWnFLQUFBSUFKQkIzRjJjUXVIQVFFRmYwRUJJQU5CQVd0MElRZ2dBVUVEZENFSklBUkJBV29oQ2dOQUlBSWdCMFpGQkVCQkFDRUdRUUFoQkFOQUlBUWdDa1pGQkVBZ0JTQUNJQVJzSUFkcWFpQUdPZ0FBSUFnZ0JpQURJQVJzSWdZZ0NVZ0VmeUFBSUFFZ0JpQURFSElGUVFBTGFrd2hCaUFFUVFGcUlRUU1BUXNMSUFBZ0FXb2hBQ0FIUVFGcUlRY01BUXNMQzlNQ0FRWi9JQVJGQkVBZ0J4Qk9Ed3RCQVNBR2RDRU1JQUpCQTNRaERTQUZJQVpzSVF0QkFFRUFLQUlBSWdsQkFTQUdRUUZyZENJS1FaQUJiR28yQWdBRFFDQUlJQXBHUlFSQUlBa2dDRUdRQVd4cUVFNGdDRUVCYWlFSURBRUxDeUFESUFRZ0JXeHFJUVZCQUNFSUEwQWdCQ0FJUndSQUlBc2dEVWdFZnlBQklBSWdDeUFHRUhJRlFRQUxJUU1nQXlBRkxRQUFhaUlESUFwT0JFQWdBeUFNYXlFREN5QURRUUJLQkVBZ0NTQURRUUZyUVpBQmJHb2lBeUFBSUFNUVdRVWdBMEVBU0FSQUlBbEJmeUFEYTBHUUFXeHFJZ01nQUNBREVGNExDeUFCSUFKcUlRRWdCVUVCYWlFRklBQkJrQUZxSVFBZ0NFRUJhaUVJREFFTEN5QUpJQXBCQVd0QmtBRnNhaUlBSUFjUVVDQUFRZmpJQUJCUUlBQkJrQUZySVFBRFFDQUFJQWxKUlFSQVFmaklBQ0FBUWZqSUFCQlpJQWRCK01nQUlBY1FXU0FBUVpBQmF5RUFEQUVMQzBFQUlBazJBZ0FMdVFFQkJIOGdCQkJPSUFORkJFQVBDeUFEWnkwQW1Fc2lCVUVDU1FSQVFRSWhCUXRCQUVFQUtBSUFJZ2NnQWtFRGRFRUJheUFGYmtFQmFpSUdRUUZxSUFOc2FrRURha0Y4Y1RZQ0FDQUJJQUlnQXlBRklBWWdCeEJ6QTBBZ0JrRUFUZ1JBSUFRUVRFVUVRRUVBSVFnRFFDQUZJQWhHUlFSQUlBUWdCQkJXSUFoQkFXb2hDQXdCQ3dzTElBQWdBU0FDSUFjZ0F5QUdJQVZCaU1vQUVIUWdCRUdJeWdBZ0JCQlpJQVpCQVdzaEJnd0JDd3RCQUNBSE5nSUFDOU1DQVFaL0lBUkZCRUFnQnhCT0R3dEJBU0FHZENFTUlBSkJBM1FoRFNBRklBWnNJUXRCQUVFQUtBSUFJZ2xCQVNBR1FRRnJkQ0lLUVpBQmJHbzJBZ0FEUUNBSUlBcEdSUVJBSUFrZ0NFR1FBV3hxRUU0Z0NFRUJhaUVJREFFTEN5QURJQVFnQld4cUlRVkJBQ0VJQTBBZ0JDQUlSd1JBSUFzZ0RVZ0VmeUFCSUFJZ0N5QUdFSElGUVFBTElRTWdBeUFGTFFBQWFpSURJQXBPQkVBZ0F5QU1heUVEQ3lBRFFRQktCRUFnQ1NBRFFRRnJRWkFCYkdvaUF5QUFJQU1RV0FVZ0EwRUFTQVJBSUFsQmZ5QURhMEdRQVd4cUlnTWdBQ0FERUYwTEN5QUJJQUpxSVFFZ0JVRUJhaUVGSUFCQjRBQnFJUUFnQ0VFQmFpRUlEQUVMQ3lBSklBcEJBV3RCa0FGc2FpSUFJQWNRVUNBQVFiakxBQkJRSUFCQmtBRnJJUUFEUUNBQUlBbEpSUVJBUWJqTEFDQUFRYmpMQUJCWklBZEJ1TXNBSUFjUVdTQUFRWkFCYXlFQURBRUxDMEVBSUFrMkFnQUx1UUVCQkg4Z0JCQk9JQU5GQkVBUEN5QURaeTBBMkUwaUJVRUNTUVJBUVFJaEJRdEJBRUVBS0FJQUlnY2dBa0VEZEVFQmF5QUZia0VCYWlJR1FRRnFJQU5zYWtFRGFrRjhjVFlDQUNBQklBSWdBeUFGSUFZZ0J4QnpBMEFnQmtFQVRnUkFJQVFRVEVVRVFFRUFJUWdEUUNBRklBaEdSUVJBSUFRZ0JCQldJQWhCQVdvaENBd0JDd3NMSUFBZ0FTQUNJQWNnQXlBR0lBVkJ5TXdBRUhZZ0JFSEl6QUFnQkJCWklBWkJBV3NoQmd3QkN3dEJBQ0FITmdJQUMrOERBUVovSUFKRkJFQWdBeEJPRHd0QkFDZ0NBQ0lJSVFSQkFDQUNRUU4wSWdrZ0NFRWdhbXBCZUhFMkFnQkJBU0VHSUFFb0FnQkJBWEVoQlVFQUlRSURRQ0FHSUFsR1JRUkFJQUVnQmtFRGRrRjhjV29vQWdBZ0JuWkJBWEVoQnlBRkJIOGdCd1IvSUFJRWYwRUFJUVVnQkVFQk9nQUFJQVJCQVdvaEJFRUJCVUVBSVFVZ0JFSC9BVG9BQUNBRVFRRnFJUVJCQVFzRklBSUVmMEVBSVFVZ0JFSC9BVG9BQUNBRVFRRnFJUVJCQVFWQkFDRUZJQVJCQVRvQUFDQUVRUUZxSVFSQkFBc0xCU0FIQkg4Z0FnUi9RUUFoQlNBRVFRQTZBQUFnQkVFQmFpRUVRUUVGUVFFaEJTQUVRUUE2QUFBZ0JFRUJhaUVFUVFBTEJTQUNCSDlCQVNFRklBUkJBRG9BQUNBRVFRRnFJUVJCQUFWQkFDRUZJQVJCQURvQUFDQUVRUUZxSVFSQkFBc0xDeUVDSUFaQkFXb2hCZ3dCQ3dzZ0JRUi9JQUlFZnlBRVFmOEJPZ0FBSUFSQkFXb2lCRUVBT2dBQUlBUkJBV29pQkVFQk9nQUFJQVJCQVdvRklBUkJBVG9BQUNBRVFRRnFDd1VnQWdSL0lBUkJBRG9BQUNBRVFRRnFJZ1JCQVRvQUFDQUVRUUZxQlNBRUN3dEJBV3NoQkNBQVFmak5BQkJRSUFNUVRnTkFJQU1nQXhCV0lBUXRBQUFpQndSQUlBZEJBVVlFUUNBRFFmak5BQ0FERUZrRklBTkIrTTBBSUFNUVhnc0xJQVFnQ0VaRkJFQWdCRUVCYXlFRURBRUxDMEVBSUFnMkFnQUw3d01CQm44Z0FrVUVRQ0FERUU0UEMwRUFLQUlBSWdnaEJFRUFJQUpCQTNRaUNTQUlRU0JxYWtGNGNUWUNBRUVCSVFZZ0FTZ0NBRUVCY1NFRlFRQWhBZ05BSUFZZ0NVWkZCRUFnQVNBR1FRTjJRWHh4YWlnQ0FDQUdka0VCY1NFSElBVUVmeUFIQkg4Z0FnUi9RUUFoQlNBRVFRRTZBQUFnQkVFQmFpRUVRUUVGUVFBaEJTQUVRZjhCT2dBQUlBUkJBV29oQkVFQkN3VWdBZ1IvUVFBaEJTQUVRZjhCT2dBQUlBUkJBV29oQkVFQkJVRUFJUVVnQkVFQk9nQUFJQVJCQVdvaEJFRUFDd3NGSUFjRWZ5QUNCSDlCQUNFRklBUkJBRG9BQUNBRVFRRnFJUVJCQVFWQkFTRUZJQVJCQURvQUFDQUVRUUZxSVFSQkFBc0ZJQUlFZjBFQklRVWdCRUVBT2dBQUlBUkJBV29oQkVFQUJVRUFJUVVnQkVFQU9nQUFJQVJCQVdvaEJFRUFDd3NMSVFJZ0JrRUJhaUVHREFFTEN5QUZCSDhnQWdSL0lBUkIvd0U2QUFBZ0JFRUJhaUlFUVFBNkFBQWdCRUVCYWlJRVFRRTZBQUFnQkVFQmFnVWdCRUVCT2dBQUlBUkJBV29MQlNBQ0JIOGdCRUVBT2dBQUlBUkJBV29pQkVFQk9nQUFJQVJCQVdvRklBUUxDMEVCYXlFRUlBQkJpTThBRUU4Z0F4Qk9BMEFnQXlBREVGWWdCQzBBQUNJSEJFQWdCMEVCUmdSQUlBTkJpTThBSUFNUVdBVWdBMEdJendBZ0F4QmRDd3NnQkNBSVJrVUVRQ0FFUVFGcklRUU1BUXNMUVFBZ0NEWUNBQXVKQVFFRWYwRUJJQUYwSVFRRFFDQUNJQVJIQkVBZ0FrSC9BWEV0QU9od1FSaDBJQUpCQ0haQi93RnhMUURvY0VFUWRHb2dBa0VZZGkwQTZIQWdBa0VRZGtIL0FYRXRBT2h3UVFoMGFtb2dBWGNpQXlBQ1N3UkFJQUFnQWtFRmRHb2lCVUhvOGdBUUpDQUFJQU5CQlhScUlnTWdCUkFrUWVqeUFDQURFQ1FMSUFKQkFXb2hBZ3dCQ3dzTGdRTUJDWDhnQUNBQkVIcEJBU0FCZENFS1FRRWhCQU5BSUFFZ0JFOEVRRUVCSUFSMElRY2dCRUVGZEVIb3p3QnFJUXRCQUNFRkEwQWdCU0FLU1FSQVFhanpBQkErSUFkQkFYWWhDRUVBSVFZRFFDQUdJQWhKQkVBZ0FDQUZJQVpxUVFWMGFpSUpJQWhCQlhScUlneEJxUE1BUWNqekFCQTJJQWxCNlBNQUVDUkI2UE1BUWNqekFDQUpFREpCNlBNQVFjanpBQ0FNRUROQnFQTUFJQXRCcVBNQUVEWWdCa0VCYWlFR0RBRUxDeUFGSUFkcUlRVU1BUXNMSUFSQkFXb2hCQXdCQ3dzZ0F4QXhJQUpGY1VVRVFFRUJJUVZCQVNBQmRDSUhRUUYySVFZRFFDQUZJQVpKQkVBZ0FDQUZRUVYwYWlFRUlBQWdCeUFGYTBFRmRHb2hBU0FDQkVBZ0F4QXhCRUFnQkVHSTh3QVFKQ0FCSUFRUUpFR0k4d0FnQVJBa0JTQUVRWWp6QUJBa0lBRWdBeUFFRURaQmlQTUFJQU1nQVJBMkN3VWdBeEF4UlFSQUlBUWdBeUFFRURZZ0FTQURJQUVRTmdzTElBVkJBV29oQlF3QkN3c2dBeEF4UlFSQUlBQWdBeUFBRURZZ0FDQUdRUVYwYWlJQklBTWdBUkEyQ3dzTE9nRUNmeUFBUVFGMklRSURRQ0FDQkVBZ0FrRUJkaUVDSUFGQkFXb2hBUXdCQ3dzZ0FFRUJJQUYwUndSQUFBc2dBVUVnU3dSQUFBc2dBUXNhQUNBQkVId2hBVUdJOUFBUVBpQUFJQUZCQUVHSTlBQVFld3NZQUNBQUlBRVFmQ0lBUVFFZ0FFRUZkRUdJMkFCcUVIc0xiUUVDZnlBRFFhajBBQkFrUVFBaEF3TkFJQUlnQTBaRkJFQWdBU0FEUVFWMGFpSUZRYWowQUVISTlBQVFOaUFBSUFOQkJYUnFJZ1pCNlBRQUVDUkI2UFFBUWNqMEFDQUdFREpCNlBRQVFjajBBQ0FGRUROQnFQUUFJQVJCcVBRQUVEWWdBMEVCYWlFRERBRUxDd3Q1QVFKL0lBVkJCWFJCcU9BQWFpRUhJQU5CaVBVQUVDUkJBQ0VGQTBBZ0FpQUZSa1VFUUNBQUlBVkJCWFJxSWdZZ0FTQUZRUVYwYWlJRFFhajFBQkF5SUFNZ0J5QURFRFlnQmlBRElBTVFNaUFEUVlqMUFDQURFRFpCcVBVQUlBWVFKRUdJOVFBZ0JFR0k5UUFRTmlBRlFRRnFJUVVNQVFzTEM1RUJBUU4vSUFWQkJYUkJxT0FBYWlFSUlBVkJCWFJCeU9nQWFpRUhJQU5CeVBVQUVDUkJBQ0VGQTBBZ0FpQUZSa1VFUUNBQklBVkJCWFJxSWdaQnlQVUFRZWoxQUJBMklBQWdCVUVGZEdvaUEwSG85UUFnQmhBeklBWWdCeUFHRURZZ0F5QUlJQU1RTmtIbzlRQWdBeUFERURNZ0F5QUhJQU1RTmtISTlRQWdCRUhJOVFBUU5pQUZRUUZxSVFVTUFRc0xDNnNCQVFkL0lBRWdBblloQkVFQklBSjBJZ1ZCQVhZaUJrRUZkQ0VISUFKQkJYUkI2TThBYWlFSVFRQWhBUU5BSUFFZ0JFWkZCRUJCaVBZQUVENUJBQ0VDQTBBZ0FpQUdSa1VFUUNBQUlBRWdCV3dnQW1wQkJYUnFJZ01nQjJvaUNVR0k5Z0JCcVBZQUVEWWdBMEhJOWdBUUpFSEk5Z0JCcVBZQUlBTVFNa0hJOWdCQnFQWUFJQWtRTTBHSTlnQWdDRUdJOWdBUU5pQUNRUUZxSVFJTUFRc0xJQUZCQVdvaEFRd0JDd3NMYkFFRWZ5QUJRUUYySVFRZ0FVRUJjUVJBSUFBZ0JFRUZkR29nQWlBQUlBUkJCWFJxRURZTEEwQWdBeUFFVDBVRVFDQUFJQUZCQVdzZ0EydEJCWFJxSWdVZ0FrSG85Z0FRTmlBQUlBTkJCWFJxSWdZZ0FpQUZFRFpCNlBZQUlBWVFKQ0FEUVFGcUlRTU1BUXNMQzRzQkFRTi9JQVZCQlhSQnFPQUFhaUVISUFWQkJYUkJ5T2dBYWlFSUlBTkJpUGNBRUNSQkFDRURBMEFnQWlBRFJrVUVRQ0FBSUFOQkJYUnFJZ1lnQjBHbzl3QVFOaUFCSUFOQkJYUnFJZ1ZCcVBjQVFhajNBQkF6SUFZZ0JTQUZFRE5CcVBjQUlBZ2dCaEEySUFWQmlQY0FJQVVRTmtHSTl3QWdCRUdJOXdBUU5pQURRUUZxSVFNTUFRc0xDeVVBSUFBZ0FVRUZkR29oQVFOQUlBQWdBVVpGQkVBZ0FCQWxJQUJCSUdvaEFBd0JDd3NMZEFFRWZ3TkFJQUlnQkVaRkJFQWdBQ2dDQUNFSElBQkJCR29oQUVFQUlRVURRQ0FGSUFkR1JRUkFJQU1nQUNnQ0FFRUZkR29oQmlBQklBQkJCR29pQUVISTl3QVFOa0hJOXdBZ0JpQUdFRElnQUVFZ2FpRUFJQVZCQVdvaEJRd0JDd3NnQVVFZ2FpRUJJQVJCQVdvaEJBd0JDd3NMb3dJQkJIOGdCQ0VMSUFNaUNpQUhRUVYwYWlFTUEwQWdDaUFNUmtVRVFDQUtFQ1VnQ3hBbElBcEJJR29oQ2lBTFFTQnFJUXNNQVFzTElBQWdBVUVzYkdvaERBTkFJQUFnREVjRVFDQUFLQUlJSWdFZ0NDQUphazhnQVNBSVNYSUVRQ0FBUVN4cUlRQU1BZ3NnQUNnQ0FDSUtCRUFnQ2tFQlJnUkFJQVFoRFFVZ0FFRXNhaUVBQ3dVZ0F5RU5DeUFBS0FJRUlnb2dCaUFIYWs4Z0JpQUtTM0lFUUNBQVFTeHFJUUFNQWdVZ0FpQUJJQWhyUVFWMGFpQUFRUXhxUWVqM0FCQTJJQTBnQ2lBR2EwRUZkR29pRFVIbzl3QWdEUkF5SUFCQkxHb2hBQXdDQ3dBTEN5QUVJUXNnQlNFQUlBTWlDaUFIUVFWMGFpRU1BMEFnQ2lBTVJrVUVRQ0FLSUFzZ0FCQTJJQXBCSUdvaENpQUxRU0JxSVFzZ0FFRWdhaUVBREFFTEN3dEtBQ0FBSUFOQkJYUnFJUU1EUUNBQUlBTkdSUVJBSUFBZ0FVR0krQUFRTmtHSStBQWdBaUFFRURNZ0FFRWdhaUVBSUFGQklHb2hBU0FDUVNCcUlRSWdCRUVnYWlFRURBRUxDd3MzQUNBQUlBSkJCWFJxSVFJRFFDQUFJQUpHUlFSQUlBQWdBU0FERURJZ0FFRWdhaUVBSUFGQklHb2hBU0FEUVNCcUlRTU1BUXNMQ3c0QUlBQVFEaUFBUVRCcUVBSnhDdzBBSUFBUUd5QUFRVEJxRUFFTEZBQWdBQ0FCRUFBZ0FFRXdhaUFCUVRCcUVBQUxkUUFnQUNBQlFhajRBQkFUSUFCQk1Hb2dBVUV3YWtIWStBQVFFeUFBSUFCQk1HcEJpUGtBRUE4Z0FTQUJRVEJxUWJqNUFCQVBRWWo1QUVHNCtRQkJpUGtBRUJOQjJQZ0FJQUlRRVVHbytBQWdBaUFDRUE5QnFQZ0FRZGo0QUNBQ1FUQnFFQTlCaVBrQUlBSkJNR29nQWtFd2FoQVFDeGdBSUFBZ0FTQUNFQk1nQUVFd2FpQUJJQUpCTUdvUUV3dHdBQ0FBSUFCQk1HcEI2UGtBRUJNZ0FDQUFRVEJxUVpqNkFCQVBJQUJCTUdwQnlQb0FFQkVnQUVISStnQkJ5UG9BRUE5QjZQa0FRZmo2QUJBUlFmajZBRUhvK1FCQitQb0FFQTlCbVBvQVFjajZBQ0FCRUJNZ0FVSDQrZ0FnQVJBUVFlajVBRUhvK1FBZ0FVRXdhaEFQQ3hzQUlBQWdBU0FDRUE4Z0FFRXdhaUFCUVRCcUlBSkJNR29RRHdzYkFDQUFJQUVnQWhBUUlBQkJNR29nQVVFd2FpQUNRVEJxRUJBTEZBQWdBQ0FCRUJFZ0FFRXdhaUFCUVRCcUVCRUxYUUFnQUVHbyt3QVFGQ0FBUVRCcVFkajdBQkFVUWRqN0FFR0kvQUFRRVVHbyt3QkJpUHdBUVlqOEFCQVFRWWo4QUVHNC9BQVFHaUFBUWJqOEFDQUJFQk1nQUVFd2FrRzQvQUFnQVVFd2FoQVRJQUZCTUdvZ0FVRXdhaEFSQ3h3QUlBQWdBU0FDSUFNUUhTQUFRVEJxSUFFZ0FpQURRVEJxRUIwTEZ3RUJmeUFBUVRCcUVCa2lBUVJBSUFFUEN5QUFFQmtMR0FBZ0FFRXdhaEFDQkVBZ0FCQVlEd3NnQUVFd2FoQVlDL1VCQVFKL1FRQkJBQ2dDQUNJRklBSkJBV3BCNEFCc2FqWUNBQ0FGRUlzQklBVkI0QUJxSVFVRFFDQUNJQVpIQkVBZ0FCQkxCRUFnQlVIZ0FHc2dCUkNNQVFVZ0FDQUZRZUFBYXlBRkVJMEJDeUFBSUFGcUlRQWdCVUhnQUdvaEJTQUdRUUZxSVFZTUFRc0xJQUFnQVdzaEFDQURJQUpCQVdzZ0JHeHFJUUlnQlVIZ0FHc2lCU0FGRUpNQkEwQWdCZ1JBSUFBUVN3UkFJQVVnQlVIZ0FHc1FqQUVnQWhCTkJTQUZRZUFBYTBIby9BQVFqQUVnQlNBQUlBVkI0QUJyRUkwQklBVkI2UHdBSUFJUWpRRUxJQUFnQVdzaEFDQUNJQVJySVFJZ0JVSGdBR3NoQlNBR1FRRnJJUVlNQVFzTFFRQWdCVFlDQUF1ekFnQWdBa1VFUUNBREVJc0JEd3NnQUVISS9RQVFqQUVnQXhDTEFRTkFJQUpCQVdzaUFpQUJhaTBBQUNFQUlBTWdBeENQQVNBQVFZQUJUd1JBSUFOQnlQMEFJQU1RalFFZ0FFR0FBV3NoQUFzZ0F5QURFSThCSUFCQndBQlBCRUFnQTBISS9RQWdBeENOQVNBQVFVQnFJUUFMSUFNZ0F4Q1BBU0FBUVNCUEJFQWdBMEhJL1FBZ0F4Q05BU0FBUVNCcklRQUxJQU1nQXhDUEFTQUFRUkJQQkVBZ0EwSEkvUUFnQXhDTkFTQUFRUkJySVFBTElBTWdBeENQQVNBQVFRaFBCRUFnQTBISS9RQWdBeENOQVNBQVFRaHJJUUFMSUFNZ0F4Q1BBU0FBUVFSUEJFQWdBMEhJL1FBZ0F4Q05BU0FBUVFScklRQUxJQU1nQXhDUEFTQUFRUUpQQkVBZ0EwSEkvUUFnQXhDTkFTQUFRUUpySVFBTElBTWdBeENQQVNBQUJFQWdBMEhJL1FBZ0F4Q05BUXNnQWcwQUN3dktBUUJCcUlFQkVJc0JRYWlCQVVHb2dRRVFrZ0VnQUVHby9nQkJNRUdJL3dBUW1BRkJpUDhBUWVqL0FCQ1BBU0FBUWVqL0FFSG8vd0FRalFGQjZQOEFRY2lBQVJCYVFjaUFBVUhvL3dCQnlJQUJFSTBCUWNpQUFVR29nUUVRVWdSQUFBdEJpUDhBSUFCQmlJSUJFSTBCUWVqL0FFR29nUUVRVWdSQVFhaUJBUkFCUWRpQkFSQWJRYWlCQVVHSWdnRWdBUkNOQVFWQjZJSUJFSXNCUWVpQ0FVSG8vd0JCNklJQkVKQUJRZWlDQVVIWS9nQkJNRUhvZ2dFUW1BRkI2SUlCUVlpQ0FTQUJFSTBCQ3d0bUFFR1loZ0VRaXdGQm1JWUJRWmlHQVJDU0FTQUFRY2lEQVVFd1FmaURBUkNZQVVINGd3RkIySVFCRUk4QklBQkIySVFCUWRpRUFSQ05BVUhZaEFGQnVJVUJFRnBCdUlVQlFkaUVBVUc0aFFFUWpRRkJ1SVVCUVppR0FSQlNCRUJCQUE4TFFRRUxEd0FnQUJCTElBQkI0QUJxRUV0eEN3b0FJQUJCd0FGcUVFc0xEZ0FnQUJCTklBQkI0QUJxRUUwTEZ3QWdBQkJOSUFCQjRBQnFFSXNCSUFCQndBRnFFRTBMZ2dJQUlBRWdBQ2tEQURjREFDQUJJQUFwQXdnM0F3Z2dBU0FBS1FNUU53TVFJQUVnQUNrREdEY0RHQ0FCSUFBcEF5QTNBeUFnQVNBQUtRTW9Od01vSUFFZ0FDa0RNRGNETUNBQklBQXBBemczQXpnZ0FTQUFLUU5BTndOQUlBRWdBQ2tEU0RjRFNDQUJJQUFwQTFBM0ExQWdBU0FBS1FOWU53TllJQUVnQUNrRFlEY0RZQ0FCSUFBcEEyZzNBMmdnQVNBQUtRTndOd053SUFFZ0FDa0RlRGNEZUNBQklBQXBBNEFCTndPQUFTQUJJQUFwQTRnQk53T0lBU0FCSUFBcEE1QUJOd09RQVNBQklBQXBBNWdCTndPWUFTQUJJQUFwQTZBQk53T2dBU0FCSUFBcEE2Z0JOd09vQVNBQklBQXBBN0FCTndPd0FTQUJJQUFwQTdnQk53TzRBUXVTQXdBZ0FTQUFLUU1BTndNQUlBRWdBQ2tEQ0RjRENDQUJJQUFwQXhBM0F4QWdBU0FBS1FNWU53TVlJQUVnQUNrRElEY0RJQ0FCSUFBcEF5ZzNBeWdnQVNBQUtRTXdOd013SUFFZ0FDa0RPRGNET0NBQklBQXBBMEEzQTBBZ0FTQUFLUU5JTndOSUlBRWdBQ2tEVURjRFVDQUJJQUFwQTFnM0ExZ2dBU0FBS1FOZ053TmdJQUVnQUNrRGFEY0RhQ0FCSUFBcEEzQTNBM0FnQVNBQUtRTjROd040SUFFZ0FDa0RnQUUzQTRBQklBRWdBQ2tEaUFFM0E0Z0JJQUVnQUNrRGtBRTNBNUFCSUFFZ0FDa0RtQUUzQTVnQklBRWdBQ2tEb0FFM0E2QUJJQUVnQUNrRHFBRTNBNmdCSUFFZ0FDa0RzQUUzQTdBQklBRWdBQ2tEdUFFM0E3Z0JJQUVnQUNrRHdBRTNBOEFCSUFFZ0FDa0R5QUUzQThnQklBRWdBQ2tEMEFFM0E5QUJJQUVnQUNrRDJBRTNBOWdCSUFFZ0FDa0Q0QUUzQStBQklBRWdBQ2tENkFFM0ErZ0JJQUVnQUNrRDhBRTNBL0FCSUFFZ0FDa0QrQUUzQS9nQklBRWdBQ2tEZ0FJM0E0QUNJQUVnQUNrRGlBSTNBNGdDSUFFZ0FDa0RrQUkzQTVBQ0lBRWdBQ2tEbUFJM0E1Z0NDeThBSUFBUW13RUVRQ0FCRUo0QkJTQUJRY0FCYWhDTEFTQUFRZUFBYWlBQlFlQUFhaENNQVNBQUlBRVFqQUVMQ3hjQUlBQWdBUkJTSUFCQjRBQnFJQUZCNEFCcUVGSnhDNFlCQVFGL0lBQVFuQUVFUUNBQkVKc0JEd3NnQVJDYkFRUkFRUUFQQ3lBQVFjQUJhaUlDRUlvQkJFQWdBQ0FCRUtJQkR3c2dBa0hZaHdFUWp3RWdBVUhZaHdGQnVJZ0JFSTBCSUFKQjJJY0JRWmlKQVJDTkFTQUJRZUFBYWtHWWlRRkIrSWtCRUkwQklBQkJ1SWdCRUZJRVFDQUFRZUFBYWtINGlRRVFVZ1JBUVFFUEN3dEJBQXZRQVFFQ2Z5QUFFSndCQkVBZ0FSQ2NBUThMSUFFUW5BRUVRRUVBRHdzZ0FFSEFBV29pQWhDS0FRUkFJQUVnQUJDakFROExJQUZCd0FGcUlnTVFpZ0VFUUNBQUlBRVFvd0VQQ3lBQ1FkaUtBUkNQQVNBRFFiaUxBUkNQQVNBQVFiaUxBVUdZakFFUWpRRWdBVUhZaWdGQitJd0JFSTBCSUFKQjJJb0JRZGlOQVJDTkFTQURRYmlMQVVHNGpnRVFqUUVnQUVIZ0FHcEJ1STRCUVppUEFSQ05BU0FCUWVBQWFrSFlqUUZCK0k4QkVJMEJRWmlNQVVINGpBRVFVZ1JBUVppUEFVSDRqd0VRVWdSQVFRRVBDd3RCQUF1c0FnQWdBQkNiQVFSQUlBQWdBUkNoQVE4TElBQkIySkFCRUk4QklBQkI0QUJxUWJpUkFSQ1BBVUc0a1FGQm1KSUJFSThCSUFCQnVKRUJRZmlTQVJDUUFVSDRrZ0ZCK0pJQkVJOEJRZmlTQVVIWWtBRkIrSklCRUpFQlFmaVNBVUdZa2dGQitKSUJFSkVCUWZpU0FVSDRrZ0ZCK0pJQkVKQUJRZGlRQVVIWWtBRkIySk1CRUpBQlFkaVRBVUhZa0FGQjJKTUJFSkFCSUFCQjRBQnFJQUJCNEFCcUlBRkJ3QUZxRUpBQlFkaVRBU0FCRUk4QklBRkIrSklCSUFFUWtRRWdBVUg0a2dFZ0FSQ1JBVUdZa2dGQm1KSUJRYmlVQVJDUUFVRzRsQUZCdUpRQlFiaVVBUkNRQVVHNGxBRkJ1SlFCUWJpVUFSQ1FBVUg0a2dFZ0FTQUJRZUFBYWhDUkFTQUJRZUFBYWtIWWt3RWdBVUhnQUdvUWpRRWdBVUhnQUdwQnVKUUJJQUZCNEFCcUVKRUJDOU1DQUNBQUVKd0JCRUFnQUNBQkVLQUJEd3NnQUVIQUFXb1FpZ0VFUUNBQUlBRVFwUUVQQ3lBQVFaaVZBUkNQQVNBQVFlQUFha0g0bFFFUWp3RkIrSlVCUWRpV0FSQ1BBU0FBUWZpVkFVRzRsd0VRa0FGQnVKY0JRYmlYQVJDUEFVRzRsd0ZCbUpVQlFiaVhBUkNSQVVHNGx3RkIySllCUWJpWEFSQ1JBVUc0bHdGQnVKY0JRYmlYQVJDUUFVR1lsUUZCbUpVQlFaaVlBUkNRQVVHWW1BRkJtSlVCUVppWUFSQ1FBVUdZbUFGQitKZ0JFSThCSUFCQjRBQnFJQUJCd0FGcVFkaVpBUkNOQVVHNGx3RkJ1SmNCSUFFUWtBRkIrSmdCSUFFZ0FSQ1JBVUhZbGdGQjJKWUJRYmlhQVJDUUFVRzRtZ0ZCdUpvQlFiaWFBUkNRQVVHNG1nRkJ1Sm9CUWJpYUFSQ1FBVUc0bHdFZ0FTQUJRZUFBYWhDUkFTQUJRZUFBYWtHWW1BRWdBVUhnQUdvUWpRRWdBVUhnQUdwQnVKb0JJQUZCNEFCcUVKRUJRZGlaQVVIWW1RRWdBVUhBQVdvUWtBRUw0QUlBSUFBUW13RUVRQ0FCSUFJUW53RWdBa0hBQVdvUWl3RVBDeUFCRUpzQkJFQWdBQ0FDRUo4QklBSkJ3QUZxRUlzQkR3c2dBQ0FCRUZJRVFDQUFRZUFBYWlBQlFlQUFhaEJTQkVBZ0FTQUNFS1VCRHdzTElBRWdBRUdZbXdFUWtRRWdBVUhnQUdvZ0FFSGdBR3BCMkp3QkVKRUJRWmliQVVING13RVFqd0ZCK0pzQlFmaWJBVUc0blFFUWtBRkJ1SjBCUWJpZEFVRzRuUUVRa0FGQm1Kc0JRYmlkQVVHWW5nRVFqUUZCMkp3QlFkaWNBVUg0bmdFUWtBRWdBRUc0blFGQnVLQUJFSTBCUWZpZUFVSFlud0VRandGQnVLQUJRYmlnQVVHWW9RRVFrQUZCMko4QlFaaWVBU0FDRUpFQklBSkJtS0VCSUFJUWtRRWdBRUhnQUdwQm1KNEJRZmloQVJDTkFVSDRvUUZCK0tFQlFmaWhBUkNRQVVHNG9BRWdBaUFDUWVBQWFoQ1JBU0FDUWVBQWFrSDRuZ0VnQWtIZ0FHb1FqUUVnQWtIZ0FHcEIrS0VCSUFKQjRBQnFFSkVCUVppYkFVR1ltd0VnQWtIQUFXb1FrQUVMMkFNQkFYOGdBQkNjQVFSQUlBRWdBaENmQVNBQ1FjQUJhaENMQVE4TElBRVFtd0VFUUNBQUlBSVFvQUVQQ3lBQVFjQUJhaUlERUlvQkJFQWdBQ0FCSUFJUXB3RVBDeUFEUWRpaUFSQ1BBU0FCUWRpaUFVRzRvd0VRalFFZ0EwSFlvZ0ZCbUtRQkVJMEJJQUZCNEFCcVFaaWtBVUg0cEFFUWpRRWdBRUc0b3dFUVVnUkFJQUJCNEFCcVFmaWtBUkJTQkVBZ0FTQUNFS1VCRHdzTFFiaWpBU0FBUWRpbEFSQ1JBVUg0cEFFZ0FFSGdBR3BCbUtjQkVKRUJRZGlsQVVHNHBnRVFqd0ZCdUtZQlFiaW1BVUg0cHdFUWtBRkIrS2NCUWZpbkFVSDRwd0VRa0FGQjJLVUJRZmluQVVIWXFBRVFqUUZCbUtjQlFaaW5BVUc0cVFFUWtBRWdBRUg0cHdGQitLb0JFSTBCUWJpcEFVR1lxZ0VRandGQitLb0JRZmlxQVVIWXF3RVFrQUZCbUtvQlFkaW9BU0FDRUpFQklBSkIyS3NCSUFJUWtRRWdBRUhnQUdwQjJLZ0JRYmlzQVJDTkFVRzRyQUZCdUt3QlFiaXNBUkNRQVVINHFnRWdBaUFDUWVBQWFoQ1JBU0FDUWVBQWFrRzRxUUVnQWtIZ0FHb1FqUUVnQWtIZ0FHcEJ1S3dCSUFKQjRBQnFFSkVCSUFOQjJLVUJJQUpCd0FGcUVKQUJJQUpCd0FGcUlBSkJ3QUZxRUk4QklBSkJ3QUZxUWRpaUFTQUNRY0FCYWhDUkFTQUNRY0FCYWtHNHBnRWdBa0hBQVdvUWtRRUxuUVFCQW44Z0FCQ2NBUVJBSUFFZ0FoQ2dBUThMSUFFUW5BRUVRQ0FBSUFJUW9BRVBDeUFBUWNBQmFpSURFSW9CQkVBZ0FTQUFJQUlRcUFFUEN5QUJRY0FCYWlJRUVJb0JCRUFnQUNBQklBSVFxQUVQQ3lBRFFaaXRBUkNQQVNBRVFmaXRBUkNQQVNBQVFmaXRBVUhZcmdFUWpRRWdBVUdZclFGQnVLOEJFSTBCSUFOQm1LMEJRWml3QVJDTkFTQUVRZml0QVVINHNBRVFqUUVnQUVIZ0FHcEIrTEFCUWRpeEFSQ05BU0FCUWVBQWFrR1lzQUZCdUxJQkVJMEJRZGl1QVVHNHJ3RVFVZ1JBUWRpeEFVRzRzZ0VRVWdSQUlBQWdBaENtQVE4TEMwRzRyd0ZCMks0QlFaaXpBUkNSQVVHNHNnRkIyTEVCUWZpekFSQ1JBVUdZc3dGQm1MTUJRZGkwQVJDUUFVSFl0QUZCMkxRQkVJOEJRWml6QVVIWXRBRkJ1TFVCRUkwQlFmaXpBVUg0c3dGQm1MWUJFSkFCUWRpdUFVSFl0QUZCMkxjQkVJMEJRWmkyQVVINHRnRVFqd0ZCMkxjQlFkaTNBVUc0dUFFUWtBRkIrTFlCUWJpMUFTQUNFSkVCSUFKQnVMZ0JJQUlRa1FGQjJMRUJRYmkxQVVHWXVRRVFqUUZCbUxrQlFaaTVBVUdZdVFFUWtBRkIyTGNCSUFJZ0FrSGdBR29Ra1FFZ0FrSGdBR3BCbUxZQklBSkI0QUJxRUkwQklBSkI0QUJxUVppNUFTQUNRZUFBYWhDUkFTQURJQVFnQWtIQUFXb1FrQUVnQWtIQUFXb2dBa0hBQVdvUWp3RWdBa0hBQVdwQm1LMEJJQUpCd0FGcUVKRUJJQUpCd0FGcVFmaXRBU0FDUWNBQmFoQ1JBU0FDUWNBQmFrR1lzd0VnQWtIQUFXb1FqUUVMR0FBZ0FDQUJFSXdCSUFCQjRBQnFJQUZCNEFCcUVKSUJDeWNBSUFBZ0FSQ01BU0FBUWVBQWFpQUJRZUFBYWhDU0FTQUFRY0FCYWlBQlFjQUJhaENNQVFzV0FDQUJRZmk1QVJDcUFTQUFRZmk1QVNBQ0VLY0JDeFlBSUFGQm1Md0JFS29CSUFCQm1Md0JJQUlRcUFFTEZnQWdBVUc0dmdFUXF3RWdBRUc0dmdFZ0FoQ3BBUXNXQUNBQUlBRVFYeUFBUWVBQWFpQUJRZUFBYWhCZkN5UUFJQUFnQVJCZklBQkI0QUJxSUFGQjRBQnFFRjhnQUVIQUFXb2dBVUhBQVdvUVh3c1dBQ0FBSUFFUVlTQUFRZUFBYWlBQlFlQUFhaEJoQ3lRQUlBQWdBUkJoSUFCQjRBQnFJQUZCNEFCcUVHRWdBRUhBQVdvZ0FVSEFBV29RWVF0Y0FDQUFFSndCQkVBZ0FSQk5JQUZCNEFCcUVFMEZJQUJCd0FGcVFkakFBUkNUQVVIWXdBRkJ1TUVCRUk4QlFkakFBVUc0d1FGQm1NSUJFSTBCSUFCQnVNRUJJQUVRalFFZ0FFSGdBR3BCbU1JQklBRkI0QUJxRUkwQkN3cytBQ0FBUWVBQWFrSDR3Z0VRandFZ0FFSFl3d0VRandFZ0FFSFl3d0ZCMk1NQkVJMEJRZGpEQVVINGhnRkIyTU1CRUpBQlFmakNBVUhZd3dFUVVnc1NBQ0FBUWJqRUFSQ3pBVUc0eEFFUXRBRUxvd0VCQTM5QkFFRUFLQUlBSWdRZ0FVSGdBR3hxTmdJQUlBQkJ3QUZxUWFBQ0lBRWdCRUhnQUJDWEFTQUVJUU1EUUNBQklBVkhCRUFnQXhCTEJFQWdBaEJOSUFKQjRBQnFFRTBGSUFNZ0FFSGdBR3BCK01VQkVJMEJJQU1nQXhDUEFTQURJQUFnQWhDTkFTQURRZmpGQVNBQ1FlQUFhaENOQVFzZ0FFR2dBbW9oQUNBQ1FjQUJhaUVDSUFOQjRBQnFJUU1nQlVFQmFpRUZEQUVMQzBFQUlBUTJBZ0FMWGdBZ0FCQ2NBUVJBSUFFUW5nRUZJQUJCd0FGcVFkakdBUkNUQVVIWXhnRkJ1TWNCRUk4QlFkakdBVUc0eHdGQm1NZ0JFSTBCSUFCQnVNY0JJQUVRalFFZ0FFSGdBR3BCbU1nQklBRkI0QUJxRUkwQklBRkJ3QUZxRUlzQkN3c3pBQ0FBRUpzQkJFQWdBUkNkQVE4TElBQkIrTWdCRUs4QlFmaklBVUhnQUNBQkVHaEIyTWtCUWVBQUlBRkI0QUJxRUdnTFJ3QWdBQkNiQVFSQUlBRVFUU0FCUWNBQU9nQUFEd3NnQUVHNHlnRVFYMEc0eWdGQjRBQWdBUkJvSUFCQjRBQnFFSlVCUVg5R0JFQWdBU0FCTFFBQVFZQUJjam9BQUFzTE53QWdBQzBBQUVIQUFIRUVRQ0FCRUowQkR3c2dBRUhnQUVHWXl3RVFhQ0FBUWVBQWFrSGdBRUg0eXdFUWFFR1l5d0VnQVJDeEFRdlRBUUVDZnlBQUxRQUFJZ0pCd0FCeEJFQWdBUkNkQVE4TElBSkJnQUZ4SVFNZ0FFRzR6UUVRakFGQnVNMEJJQUpCUDNFNkFBQkJ1TTBCUWVBQVFkak1BUkJvUWRqTUFTQUJFR0VnQVVHNHpRRVFqd0VnQVVHNHpRRkJ1TTBCRUkwQlFiak5BVUg0aGdGQnVNMEJFSkFCUWJqTkFVRzR6UUVRbVFGQnVNMEJRZGpNQVJDU0FVRzR6UUVRbFFGQmYwWUVRQ0FEQkVCQnVNMEJJQUZCNEFCcUVJd0JCVUc0elFFZ0FVSGdBR29Ra2dFTEJTQURCRUJCdU0wQklBRkI0QUJxRUpJQkJVRzR6UUVnQVVIZ0FHb1FqQUVMQ3dzd0FRRi9BMEFnQVNBRFJrVUVRQ0FBSUFJUXVBRWdBRUhBQVdvaEFDQUNRY0FCYWlFQ0lBTkJBV29oQXd3QkN3c0xNQUVCZndOQUlBRWdBMFpGQkVBZ0FDQUNFTGtCSUFCQndBRnFJUUFnQWtIZ0FHb2hBaUFEUVFGcUlRTU1BUXNMQ3pBQkFYOERRQ0FCSUFOR1JRUkFJQUFnQWhDNkFTQUFRY0FCYWlFQUlBSkJ3QUZxSVFJZ0EwRUJhaUVEREFFTEN3dE1BUUYvSUFBZ0FVRUJhMEhnQUd4cUlRQWdBaUFCUVFGclFjQUJiR29oQWdOQUlBRWdBMFpGQkVBZ0FDQUNFTHNCSUFCQjRBQnJJUUFnQWtIQUFXc2hBaUFEUVFGcUlRTU1BUXNMQzB3QkFYOGdBQ0FCUVFGclFjQUJiR29oQUNBQ0lBRkJBV3RCb0FKc2FpRUNBMEFnQVNBRFJrVUVRQ0FBSUFJUW9RRWdBRUhBQVdzaEFDQUNRYUFDYXlFQ0lBTkJBV29oQXd3QkN3c0wyd0lCQm44Z0JFVUVRQ0FIRUo0QkR3dEJBU0FHZENFTUlBSkJBM1FoRFNBRklBWnNJUXRCQUVFQUtBSUFJZ2xCQVNBR1FRRnJkQ0lLUWFBQ2JHbzJBZ0FEUUNBSUlBcEdSUVJBSUFrZ0NFR2dBbXhxRUo0QklBaEJBV29oQ0F3QkN3c2dBeUFFSUFWc2FpRUZRUUFoQ0FOQUlBUWdDRWNFUUNBTElBMUlCSDhnQVNBQ0lBc2dCaEJ5QlVFQUN5RURJQU1nQlMwQUFHb2lBeUFLVGdSQUlBTWdER3NoQXdzZ0EwRUFTZ1JBSUFrZ0EwRUJhMEdnQW14cUlnTWdBQ0FERUtrQkJTQURRUUJJQkVBZ0NVRi9JQU5yUWFBQ2JHb2lBeUFBSUFNUXJnRUxDeUFCSUFKcUlRRWdCVUVCYWlFRklBQkJvQUpxSVFBZ0NFRUJhaUVJREFFTEN5QUpJQXBCQVd0Qm9BSnNhaUlBSUFjUW9BRWdBRUdZemdFUW9BRWdBRUdnQW1zaEFBTkFJQUFnQ1VsRkJFQkJtTTRCSUFCQm1NNEJFS2tCSUFkQm1NNEJJQWNRcVFFZ0FFR2dBbXNoQUF3QkN3dEJBQ0FKTmdJQUM3OEJBUVIvSUFRUW5nRWdBMFVFUUE4TElBTm5MUURZMGdFaUJVRUNTUVJBUVFJaEJRdEJBRUVBS0FJQUlnY2dBa0VEZEVFQmF5QUZia0VCYWlJR1FRRnFJQU5zYWtFRGFrRjhjVFlDQUNBQklBSWdBeUFGSUFZZ0J4QnpBMEFnQmtFQVRnUkFJQVFRbkFGRkJFQkJBQ0VJQTBBZ0JTQUlSa1VFUUNBRUlBUVFwZ0VnQ0VFQmFpRUlEQUVMQ3dzZ0FDQUJJQUlnQnlBRElBWWdCVUc0MEFFUXdRRWdCRUc0MEFFZ0JCQ3BBU0FHUVFGcklRWU1BUXNMUVFBZ0J6WUNBQXZiQWdFR2Z5QUVSUVJBSUFjUW5nRVBDMEVCSUFaMElRd2dBa0VEZENFTklBVWdCbXdoQzBFQVFRQW9BZ0FpQ1VFQklBWkJBV3QwSWdwQm9BSnNhallDQUFOQUlBZ2dDa1pGQkVBZ0NTQUlRYUFDYkdvUW5nRWdDRUVCYWlFSURBRUxDeUFESUFRZ0JXeHFJUVZCQUNFSUEwQWdCQ0FJUndSQUlBc2dEVWdFZnlBQklBSWdDeUFHRUhJRlFRQUxJUU1nQXlBRkxRQUFhaUlESUFwT0JFQWdBeUFNYXlFREN5QURRUUJLQkVBZ0NTQURRUUZyUWFBQ2JHb2lBeUFBSUFNUXFBRUZJQU5CQUVnRVFDQUpRWDhnQTJ0Qm9BSnNhaUlESUFBZ0F4Q3RBUXNMSUFFZ0Ftb2hBU0FGUVFGcUlRVWdBRUhBQVdvaEFDQUlRUUZxSVFnTUFRc0xJQWtnQ2tFQmEwR2dBbXhxSWdBZ0J4Q2dBU0FBUWZqU0FSQ2dBU0FBUWFBQ2F5RUFBMEFnQUNBSlNVVUVRRUg0MGdFZ0FFSDQwZ0VRcVFFZ0IwSDQwZ0VnQnhDcEFTQUFRYUFDYXlFQURBRUxDMEVBSUFrMkFnQUx2d0VCQkg4Z0JCQ2VBU0FEUlFSQUR3c2dBMmN0QUxqWEFTSUZRUUpKQkVCQkFpRUZDMEVBUVFBb0FnQWlCeUFDUVFOMFFRRnJJQVZ1UVFGcUlnWkJBV29nQTJ4cVFRTnFRWHh4TmdJQUlBRWdBaUFESUFVZ0JpQUhFSE1EUUNBR1FRQk9CRUFnQkJDY0FVVUVRRUVBSVFnRFFDQUZJQWhHUlFSQUlBUWdCQkNtQVNBSVFRRnFJUWdNQVFzTEN5QUFJQUVnQWlBSElBTWdCaUFGUVpqVkFSRERBU0FFUVpqVkFTQUVFS2tCSUFaQkFXc2hCZ3dCQ3d0QkFDQUhOZ0lBQy9VREFRWi9JQUpGQkVBZ0F4Q2VBUThMUVFBb0FnQWlDQ0VFUVFBZ0FrRURkQ0lKSUFoQklHcHFRWGh4TmdJQVFRRWhCaUFCS0FJQVFRRnhJUVZCQUNFQ0EwQWdCaUFKUmtVRVFDQUJJQVpCQTNaQmZIRnFLQUlBSUFaMlFRRnhJUWNnQlFSL0lBY0VmeUFDQkg5QkFDRUZJQVJCQVRvQUFDQUVRUUZxSVFSQkFRVkJBQ0VGSUFSQi93RTZBQUFnQkVFQmFpRUVRUUVMQlNBQ0JIOUJBQ0VGSUFSQi93RTZBQUFnQkVFQmFpRUVRUUVGUVFBaEJTQUVRUUU2QUFBZ0JFRUJhaUVFUVFBTEN3VWdCd1IvSUFJRWYwRUFJUVVnQkVFQU9nQUFJQVJCQVdvaEJFRUJCVUVCSVFVZ0JFRUFPZ0FBSUFSQkFXb2hCRUVBQ3dVZ0FnUi9RUUVoQlNBRVFRQTZBQUFnQkVFQmFpRUVRUUFGUVFBaEJTQUVRUUE2QUFBZ0JFRUJhaUVFUVFBTEN3c2hBaUFHUVFGcUlRWU1BUXNMSUFVRWZ5QUNCSDhnQkVIL0FUb0FBQ0FFUVFGcUlnUkJBRG9BQUNBRVFRRnFJZ1JCQVRvQUFDQUVRUUZxQlNBRVFRRTZBQUFnQkVFQmFnc0ZJQUlFZnlBRVFRQTZBQUFnQkVFQmFpSUVRUUU2QUFBZ0JFRUJhZ1VnQkFzTFFRRnJJUVFnQUVIWTF3RVFvQUVnQXhDZUFRTkFJQU1nQXhDbUFTQUVMUUFBSWdjRVFDQUhRUUZHQkVBZ0EwSFkxd0VnQXhDcEFRVWdBMEhZMXdFZ0F4Q3VBUXNMSUFRZ0NFWkZCRUFnQkVFQmF5RUVEQUVMQzBFQUlBZzJBZ0FMOVFNQkJuOGdBa1VFUUNBREVKNEJEd3RCQUNnQ0FDSUlJUVJCQUNBQ1FRTjBJZ2tnQ0VFZ2FtcEJlSEUyQWdCQkFTRUdJQUVvQWdCQkFYRWhCVUVBSVFJRFFDQUdJQWxHUlFSQUlBRWdCa0VEZGtGOGNXb29BZ0FnQm5aQkFYRWhCeUFGQkg4Z0J3Ui9JQUlFZjBFQUlRVWdCRUVCT2dBQUlBUkJBV29oQkVFQkJVRUFJUVVnQkVIL0FUb0FBQ0FFUVFGcUlRUkJBUXNGSUFJRWYwRUFJUVVnQkVIL0FUb0FBQ0FFUVFGcUlRUkJBUVZCQUNFRklBUkJBVG9BQUNBRVFRRnFJUVJCQUFzTEJTQUhCSDhnQWdSL1FRQWhCU0FFUVFBNkFBQWdCRUVCYWlFRVFRRUZRUUVoQlNBRVFRQTZBQUFnQkVFQmFpRUVRUUFMQlNBQ0JIOUJBU0VGSUFSQkFEb0FBQ0FFUVFGcUlRUkJBQVZCQUNFRklBUkJBRG9BQUNBRVFRRnFJUVJCQUFzTEN5RUNJQVpCQVdvaEJnd0JDd3NnQlFSL0lBSUVmeUFFUWY4Qk9nQUFJQVJCQVdvaUJFRUFPZ0FBSUFSQkFXb2lCRUVCT2dBQUlBUkJBV29GSUFSQkFUb0FBQ0FFUVFGcUN3VWdBZ1IvSUFSQkFEb0FBQ0FFUVFGcUlnUkJBVG9BQUNBRVFRRnFCU0FFQ3d0QkFXc2hCQ0FBUWZqWkFSQ2ZBU0FERUo0QkEwQWdBeUFERUtZQklBUXRBQUFpQndSQUlBZEJBVVlFUUNBRFFmalpBU0FERUtnQkJTQURRZmpaQVNBREVLMEJDd3NnQkNBSVJrVUVRQ0FFUVFGcklRUU1BUXNMUVFBZ0NEWUNBQXNXQUNBQlFiamJBUkE2SUFCQnVOc0JRU0FnQWhCNEM0OEJBUVIvUVFFZ0FYUWhCQU5BSUFJZ0JFY0VRQ0FDUWY4QmNTMEEyUHdCUVJoMElBSkJDSFpCL3dGeExRRFkvQUZCRUhScUlBSkJHSFl0QU5qOEFTQUNRUkIyUWY4QmNTMEEyUHdCUVFoMGFtb2dBWGNpQXlBQ1N3UkFJQUFnQWtHUUFXeHFJZ1ZCMlA0QkVGQWdBQ0FEUVpBQmJHb2lBeUFGRUZCQjJQNEJJQU1RVUFzZ0FrRUJhaUVDREFFTEN3dU9Bd0VKZnlBQUlBRVF5QUZCQVNBQmRDRUtRUUVoQkFOQUlBRWdCRThFUUVFQklBUjBJUWNnQkVFRmRFSFkyd0ZxSVF0QkFDRUZBMEFnQlNBS1NRUkFRZmlBQWhBK0lBZEJBWFloQ0VFQUlRWURRQ0FHSUFoSkJFQWdBQ0FGSUFacVFaQUJiR29pQ1NBSVFaQUJiR29pREVINGdBSkJtSUVDRU1jQklBbEJxSUlDRUZCQnFJSUNRWmlCQWlBSkVGbEJxSUlDUVppQkFpQU1FRjVCK0lBQ0lBdEIrSUFDRURZZ0JrRUJhaUVHREFFTEN5QUZJQWRxSVFVTUFRc0xJQVJCQVdvaEJBd0JDd3NnQXhBeElBSkZjVVVFUUVFQklRVkJBU0FCZENJSFFRRjJJUVlEUUNBRklBWkpCRUFnQUNBRlFaQUJiR29oQkNBQUlBY2dCV3RCa0FGc2FpRUJJQUlFUUNBREVERUVRQ0FFUWVqL0FSQlFJQUVnQkJCUVFlai9BU0FCRUZBRklBUkI2UDhCRUZBZ0FTQURJQVFReHdGQjZQOEJJQU1nQVJESEFRc0ZJQU1RTVVVRVFDQUVJQU1nQkJESEFTQUJJQU1nQVJESEFRc0xJQVZCQVdvaEJRd0JDd3NnQXhBeFJRUkFJQUFnQXlBQUVNY0JJQUFnQmtHUUFXeHFJZ0VnQXlBQkVNY0JDd3NMR3dBZ0FSQjhJUUZCdUlNQ0VENGdBQ0FCUVFCQnVJTUNFTWtCQ3hrQUlBQWdBUkI4SWdCQkFTQUFRUVYwUWZqakFXb1F5UUVMY0FFQ2Z5QURRZGlEQWhBa1FRQWhBd05BSUFJZ0EwWkZCRUFnQVNBRFFaQUJiR29pQlVIWWd3SkIrSU1DRU1jQklBQWdBMEdRQVd4cUlnWkJpSVVDRUZCQmlJVUNRZmlEQWlBR0VGbEJpSVVDUWZpREFpQUZFRjVCMklNQ0lBUkIySU1DRURZZ0EwRUJhaUVEREFFTEN3dDlBUUovSUFWQkJYUkJtT3dCYWlFSElBTkJtSVlDRUNSQkFDRUZBMEFnQWlBRlJrVUVRQ0FBSUFWQmtBRnNhaUlHSUFFZ0JVR1FBV3hxSWdOQnVJWUNFRmtnQXlBSElBTVF4d0VnQmlBRElBTVFXU0FEUVppR0FpQURFTWNCUWJpR0FpQUdFRkJCbUlZQ0lBUkJtSVlDRURZZ0JVRUJhaUVGREFFTEN3dVhBUUVEZnlBRlFRVjBRWmpzQVdvaENDQUZRUVYwUWJqMEFXb2hCeUFEUWNpSEFoQWtRUUFoQlFOQUlBSWdCVVpGQkVBZ0FTQUZRWkFCYkdvaUJrSElod0pCNkljQ0VNY0JJQUFnQlVHUUFXeHFJZ05CNkljQ0lBWVFYaUFHSUFjZ0JoREhBU0FESUFnZ0F4REhBVUhvaHdJZ0F5QURFRjRnQXlBSElBTVF4d0ZCeUljQ0lBUkJ5SWNDRURZZ0JVRUJhaUVGREFFTEN3dXVBUUVIZnlBQklBSjJJUVJCQVNBQ2RDSUZRUUYySWdaQmtBRnNJUWNnQWtFRmRFSFkyd0ZxSVFoQkFDRUJBMEFnQVNBRVJrVUVRRUg0aUFJUVBrRUFJUUlEUUNBQ0lBWkdSUVJBSUFBZ0FTQUZiQ0FDYWtHUUFXeHFJZ01nQjJvaUNVSDRpQUpCbUlrQ0VNY0JJQU5CcUlvQ0VGQkJxSW9DUVppSkFpQURFRmxCcUlvQ1FaaUpBaUFKRUY1QitJZ0NJQWhCK0lnQ0VEWWdBa0VCYWlFQ0RBRUxDeUFCUVFGcUlRRU1BUXNMQzNNQkJIOGdBVUVCZGlFRUlBRkJBWEVFUUNBQUlBUkJrQUZzYWlBQ0lBQWdCRUdRQVd4cUVNY0JDd05BSUFNZ0JFOUZCRUFnQUNBQlFRRnJJQU5yUVpBQmJHb2lCU0FDUWJpTEFoREhBU0FBSUFOQmtBRnNhaUlHSUFJZ0JSREhBVUc0aXdJZ0JoQlFJQU5CQVdvaEF3d0JDd3NMa0FFQkEzOGdCVUVGZEVHWTdBRnFJUWNnQlVFRmRFRzQ5QUZxSVFnZ0EwSElqQUlRSkVFQUlRTURRQ0FDSUFOR1JRUkFJQUFnQTBHUUFXeHFJZ1lnQjBIb2pBSVF4d0VnQVNBRFFaQUJiR29pQlVIb2pBSkI2SXdDRUY0Z0JpQUZJQVVRWGtIb2pBSWdDQ0FHRU1jQklBVkJ5SXdDSUFVUXh3RkJ5SXdDSUFSQnlJd0NFRFlnQTBFQmFpRUREQUVMQ3dzWEFDQUJRZmlOQWhBNklBQkIrSTBDUVNBZ0FoREZBUXVTQVFFRWYwRUJJQUYwSVFRRFFDQUNJQVJIQkVBZ0FrSC9BWEV0QUppdkFrRVlkQ0FDUVFoMlFmOEJjUzBBbUs4Q1FSQjBhaUFDUVJoMkxRQ1lyd0lnQWtFUWRrSC9BWEV0QUppdkFrRUlkR3BxSUFGM0lnTWdBa3NFUUNBQUlBSkJvQUpzYWlJRlFaaXhBaENnQVNBQUlBTkJvQUpzYWlJRElBVVFvQUZCbUxFQ0lBTVFvQUVMSUFKQkFXb2hBZ3dCQ3dzTGxRTUJDWDhnQUNBQkVOTUJRUUVnQVhRaENrRUJJUVFEUUNBQklBUlBCRUJCQVNBRWRDRUhJQVJCQlhSQm1JNENhaUVMUVFBaEJRTkFJQVVnQ2trRVFFSFl0UUlRUGlBSFFRRjJJUWhCQUNFR0EwQWdCaUFJU1FSQUlBQWdCU0FHYWtHZ0FteHFJZ2tnQ0VHZ0FteHFJZ3hCMkxVQ1FmaTFBaERTQVNBSlFaaTRBaENnQVVHWXVBSkIrTFVDSUFrUXFRRkJtTGdDUWZpMUFpQU1FSzRCUWRpMUFpQUxRZGkxQWhBMklBWkJBV29oQmd3QkN3c2dCU0FIYWlFRkRBRUxDeUFFUVFGcUlRUU1BUXNMSUFNUU1TQUNSWEZGQkVCQkFTRUZRUUVnQVhRaUIwRUJkaUVHQTBBZ0JTQUdTUVJBSUFBZ0JVR2dBbXhxSVFRZ0FDQUhJQVZyUWFBQ2JHb2hBU0FDQkVBZ0F4QXhCRUFnQkVHNHN3SVFvQUVnQVNBRUVLQUJRYml6QWlBQkVLQUJCU0FFUWJpekFoQ2dBU0FCSUFNZ0JCRFNBVUc0c3dJZ0F5QUJFTklCQ3dVZ0F4QXhSUVJBSUFRZ0F5QUVFTklCSUFFZ0F5QUJFTklCQ3dzZ0JVRUJhaUVGREFFTEN5QURFREZGQkVBZ0FDQURJQUFRMGdFZ0FDQUdRYUFDYkdvaUFTQURJQUVRMGdFTEN3c2JBQ0FCRUh3aEFVRzR1Z0lRUGlBQUlBRkJBRUc0dWdJUTFBRUxHUUFnQUNBQkVId2lBRUVCSUFCQkJYUkJ1SllDYWhEVUFRdHpBUUovSUFOQjJMb0NFQ1JCQUNFREEwQWdBaUFEUmtVRVFDQUJJQU5Cb0FKc2FpSUZRZGk2QWtINHVnSVEwZ0VnQUNBRFFhQUNiR29pQmtHWXZRSVFvQUZCbUwwQ1FmaTZBaUFHRUtrQlFaaTlBa0g0dWdJZ0JSQ3VBVUhZdWdJZ0JFSFl1Z0lRTmlBRFFRRnFJUU1NQVFzTEM0QUJBUUovSUFWQkJYUkIySjRDYWlFSElBTkJ1TDhDRUNSQkFDRUZBMEFnQWlBRlJrVUVRQ0FBSUFWQm9BSnNhaUlHSUFFZ0JVR2dBbXhxSWdOQjJMOENFS2tCSUFNZ0J5QURFTklCSUFZZ0F5QURFS2tCSUFOQnVMOENJQU1RMGdGQjJMOENJQVlRb0FGQnVMOENJQVJCdUw4Q0VEWWdCVUVCYWlFRkRBRUxDd3VaQVFFRGZ5QUZRUVYwUWRpZUFtb2hDQ0FGUVFWMFFmaW1BbW9oQnlBRFFmakJBaEFrUVFBaEJRTkFJQUlnQlVaRkJFQWdBU0FGUWFBQ2JHb2lCa0g0d1FKQm1NSUNFTklCSUFBZ0JVR2dBbXhxSWdOQm1NSUNJQVlRcmdFZ0JpQUhJQVlRMGdFZ0F5QUlJQU1RMGdGQm1NSUNJQU1nQXhDdUFTQURJQWNnQXhEU0FVSDR3UUlnQkVINHdRSVFOaUFGUVFGcUlRVU1BUXNMQzdFQkFRZC9JQUVnQW5ZaEJFRUJJQUowSWdWQkFYWWlCa0dnQW13aEJ5QUNRUVYwUVppT0Ftb2hDRUVBSVFFRFFDQUJJQVJHUlFSQVFiakVBaEErUVFBaEFnTkFJQUlnQmtaRkJFQWdBQ0FCSUFWc0lBSnFRYUFDYkdvaUF5QUhhaUlKUWJqRUFrSFl4QUlRMGdFZ0EwSDR4Z0lRb0FGQitNWUNRZGpFQWlBREVLa0JRZmpHQWtIWXhBSWdDUkN1QVVHNHhBSWdDRUc0eEFJUU5pQUNRUUZxSVFJTUFRc0xJQUZCQVdvaEFRd0JDd3NMZEFFRWZ5QUJRUUYySVFRZ0FVRUJjUVJBSUFBZ0JFR2dBbXhxSUFJZ0FDQUVRYUFDYkdvUTBnRUxBMEFnQXlBRVQwVUVRQ0FBSUFGQkFXc2dBMnRCb0FKc2FpSUZJQUpCbU1rQ0VOSUJJQUFnQTBHZ0FteHFJZ1lnQWlBRkVOSUJRWmpKQWlBR0VLQUJJQU5CQVdvaEF3d0JDd3NMa2dFQkEzOGdCVUVGZEVIWW5nSnFJUWNnQlVFRmRFSDRwZ0pxSVFnZ0EwRzR5d0lRSkVFQUlRTURRQ0FDSUFOR1JRUkFJQUFnQTBHZ0FteHFJZ1lnQjBIWXl3SVEwZ0VnQVNBRFFhQUNiR29pQlVIWXl3SkIyTXNDRUs0QklBWWdCU0FGRUs0QlFkakxBaUFJSUFZUTBnRWdCVUc0eXdJZ0JSRFNBVUc0eXdJZ0JFRzR5d0lRTmlBRFFRRnFJUU1NQVFzTEN4WUFJQUZCK00wQ0VEb2dBRUg0elFKQklDQUNFSGtMRndBZ0FVR1l6Z0lRT2lBQVFaak9Ba0VnSUFJUXhnRUxSd0FnQWtHNHpnSVFKRUVBSVFJRFFDQUJJQUpHUlFSQUlBQkJ1TTRDSUFRUU5pQUFRU0JxSVFBZ0JFRWdhaUVFUWJqT0FpQURRYmpPQWhBMklBSkJBV29oQWd3QkN3c0xTZ0FnQWtIWXpnSVFKRUVBSVFJRFFDQUJJQUpHUlFSQUlBQkIyTTRDSUFRUXh3RWdBRUdRQVdvaEFDQUVRWkFCYWlFRVFkak9BaUFEUWRqT0FoQTJJQUpCQVdvaEFnd0JDd3NMU2dBZ0FrSDR6Z0lRSkVFQUlRSURRQ0FCSUFKR1JRUkFJQUJCK000Q0lBUVEzUUVnQUVIZ0FHb2hBQ0FFUVpBQmFpRUVRZmpPQWlBRFFmak9BaEEySUFKQkFXb2hBZ3dCQ3dzTFNnQWdBa0dZendJUUpFRUFJUUlEUUNBQklBSkdSUVJBSUFCQm1NOENJQVFRMGdFZ0FFR2dBbW9oQUNBRVFhQUNhaUVFUVpqUEFpQURRWmpQQWhBMklBSkJBV29oQWd3QkN3c0xTZ0FnQWtHNHp3SVFKRUVBSVFJRFFDQUJJQUpHUlFSQUlBQkJ1TThDSUFRUTNnRWdBRUhBQVdvaEFDQUVRYUFDYWlFRVFialBBaUFEUWJqUEFoQTJJQUpCQVdvaEFnd0JDd3NMSlFBZ0FFSFkyd0lRQUNBQUlBQkJNR29nQVJBUVFkamJBaUFBUVRCcUlBRkJNR29RRHdzWUFDQUFFRXNnQUVIZ0FHb1FTM0VnQUVIQUFXb1FTM0VMR1FBZ0FCQ0tBU0FBUWVBQWFoQkxjU0FBUWNBQmFoQkxjUXNXQUNBQUVFMGdBRUhnQUdvUVRTQUFRY0FCYWhCTkN4Y0FJQUFRaXdFZ0FFSGdBR29RVFNBQVFjQUJhaEJOQ3ljQUlBQWdBUkNNQVNBQVFlQUFhaUFCUWVBQWFoQ01BU0FBUWNBQmFpQUJRY0FCYWhDTUFRdmxBZ0FnQUNBQlFZamNBaENOQVNBQVFlQUFhaUFCUWVBQWFrSG8zQUlRalFFZ0FFSEFBV29nQVVIQUFXcEJ5TjBDRUkwQklBQWdBRUhnQUdwQnFONENFSkFCSUFFZ0FVSGdBR3BCaU44Q0VKQUJJQUFnQUVIQUFXcEI2TjhDRUpBQklBRWdBVUhBQVdwQnlPQUNFSkFCSUFCQjRBQnFJQUJCd0FGcVFhamhBaENRQVNBQlFlQUFhaUFCUWNBQmFrR0k0Z0lRa0FGQmlOd0NRZWpjQWtIbzRnSVFrQUZCaU53Q1FjamRBa0hJNHdJUWtBRkI2TndDUWNqZEFrR281QUlRa0FGQnFPRUNRWWppQWlBQ0VJMEJJQUpCcU9RQ0lBSVFrUUVnQWlBQ0VPUUJRWWpjQWlBQ0lBSVFrQUZCcU40Q1FZamZBaUFDUWVBQWFoQ05BU0FDUWVBQWFrSG80Z0lnQWtIZ0FHb1FrUUZCeU4wQ1FZamxBaERrQVNBQ1FlQUFha0dJNVFJZ0FrSGdBR29Ra0FGQjZOOENRY2pnQWlBQ1FjQUJhaENOQVNBQ1FjQUJha0hJNHdJZ0FrSEFBV29Ra1FFZ0FrSEFBV3BCNk53Q0lBSkJ3QUZxRUpBQkM0RUNBQ0FBUWVqbEFoQ1BBU0FBSUFCQjRBQnFRY2ptQWhDTkFVSEk1Z0pCeU9ZQ1Fham5BaENRQVNBQUlBQkI0QUJxUVlqb0FoQ1JBVUdJNkFJZ0FFSEFBV3BCaU9nQ0VKQUJRWWpvQWtHSTZBSVFqd0VnQUVIZ0FHb2dBRUhBQVdwQjZPZ0NFSTBCUWVqb0FrSG82QUpCeU9rQ0VKQUJJQUJCd0FGcVFhanFBaENQQVVISTZRSWdBUkRrQVVIbzVRSWdBU0FCRUpBQlFhanFBaUFCUWVBQWFoRGtBVUdvNXdJZ0FVSGdBR29nQVVIZ0FHb1FrQUZCNk9VQ1FhanFBaUFCUWNBQmFoQ1FBVUhJNlFJZ0FVSEFBV29nQVVIQUFXb1FrUUZCaU9nQ0lBRkJ3QUZxSUFGQndBRnFFSkFCUWFqbkFpQUJRY0FCYWlBQlFjQUJhaENRQVFzMUFDQUFJQUVnQWhDUUFTQUFRZUFBYWlBQlFlQUFhaUFDUWVBQWFoQ1FBU0FBUWNBQmFpQUJRY0FCYWlBQ1FjQUJhaENRQVFzMUFDQUFJQUVnQWhDUkFTQUFRZUFBYWlBQlFlQUFhaUFDUWVBQWFoQ1JBU0FBUWNBQmFpQUJRY0FCYWlBQ1FjQUJhaENSQVFzbkFDQUFJQUVRa2dFZ0FFSGdBR29nQVVIZ0FHb1FrZ0VnQUVIQUFXb2dBVUhBQVdvUWtnRUxLd0VCZnlBQVFjQUJhaENWQVNJQkJFQWdBUThMSUFCQjRBQnFFSlVCSWdFRVFDQUJEd3NnQUJDVkFRc21BQ0FBSUFFUVVpQUFRZUFBYWlBQlFlQUFhaEJTY1NBQVFjQUJhaUFCUWNBQmFoQlNjUXVyQWdBZ0FFR0k2d0lRandFZ0FFSGdBR3BCNk9zQ0VJOEJJQUJCd0FGcVFjanNBaENQQVNBQUlBQkI0QUJxUWFqdEFoQ05BU0FBSUFCQndBRnFRWWp1QWhDTkFTQUFRZUFBYWlBQVFjQUJha0hvN2dJUWpRRkI2TzRDUWNqdkFoRGtBVUdJNndKQnlPOENRY2p2QWhDUkFVSEk3QUpCcVBBQ0VPUUJRYWp3QWtHbzdRSkJxUEFDRUpFQlFlanJBa0dJN2dKQmlQRUNFSkVCSUFCQndBRnFRYWp3QWtIbzhRSVFqUUVnQUVIZ0FHcEJpUEVDUWNqeUFoQ05BVUhvOFFKQnlQSUNRZWp4QWhDUUFVSG84UUpCNlBFQ0VPUUJJQUJCeU84Q1FjanlBaENOQVVISThnSkI2UEVDUWVqeEFoQ1FBVUhvOFFKQjZQRUNFSk1CUWVqeEFrSEk3d0lnQVJDTkFVSG84UUpCcVBBQ0lBRkI0QUJxRUkwQlFlanhBa0dJOFFJZ0FVSEFBV29RalFFTE13QWdBQ0FCSUFJZ0F4Q1VBU0FBUWVBQWFpQUJJQUlnQTBIZ0FHb1FsQUVnQUVIQUFXb2dBU0FDSUFOQndBRnFFSlFCQ3lzQUlBQkJ3QUZxRUVzRVFDQUFJQUJCNEFCcUlBQkI0QUJxRUVzYkVKWUJEd3NnQUVIQUFXb1FsZ0VMK0FFQkFuOUJBRUVBS0FJQUlnVWdBa0VCYWtHZ0FteHFOZ0lBSUFVUTZBRWdCVUdnQW1vaEJRTkFJQUlnQmtjRVFDQUFFT1VCQkVBZ0JVR2dBbXNnQlJEcEFRVWdBQ0FGUWFBQ2F5QUZFT29CQ3lBQUlBRnFJUUFnQlVHZ0Ftb2hCU0FHUVFGcUlRWU1BUXNMSUFBZ0FXc2hBQ0FESUFKQkFXc2dCR3hxSVFJZ0JVR2dBbXNpQlNBRkVQRUJBMEFnQmdSQUlBQVE1UUVFUUNBRklBVkJvQUpyRU9rQklBSVE1d0VGSUFWQm9BSnJRYWp6QWhEcEFTQUZJQUFnQlVHZ0Ftc1E2Z0VnQlVHbzh3SWdBaERxQVFzZ0FDQUJheUVBSUFJZ0JHc2hBaUFGUWFBQ2F5RUZJQVpCQVdzaEJnd0JDd3RCQUNBRk5nSUFDN01DQUNBQ1JRUkFJQU1RNkFFUEN5QUFRY2oxQWhEcEFTQURFT2dCQTBBZ0FrRUJheUlDSUFGcUxRQUFJUUFnQXlBREVPc0JJQUJCZ0FGUEJFQWdBMEhJOVFJZ0F4RHFBU0FBUVlBQmF5RUFDeUFESUFNUTZ3RWdBRUhBQUU4RVFDQURRY2oxQWlBREVPb0JJQUJCUUdvaEFBc2dBeUFERU9zQklBQkJJRThFUUNBRFFjajFBaUFERU9vQklBQkJJR3NoQUFzZ0F5QURFT3NCSUFCQkVFOEVRQ0FEUWNqMUFpQURFT29CSUFCQkVHc2hBQXNnQXlBREVPc0JJQUJCQ0U4RVFDQURRY2oxQWlBREVPb0JJQUJCQ0dzaEFBc2dBeUFERU9zQklBQkJCRThFUUNBRFFjajFBaUFERU9vQklBQkJCR3NoQUFzZ0F5QURFT3NCSUFCQkFrOEVRQ0FEUWNqMUFpQURFT29CSUFCQkFtc2hBQXNnQXlBREVPc0JJQUFFUUNBRFFjajFBaUFERU9vQkN5QUNEUUFMQ3pJQUlBQkI2UGNDRUl3QklBQkJ3QUZxSUFFUTVBRWdBRUhnQUdvZ0FVSEFBV29RakFGQjZQY0NJQUZCNEFCcUVJd0JDeEVBSUFBUTVRRWdBRUdnQW1vUTVRRnhDeEVBSUFBUTVnRWdBRUdnQW1vUTVRRnhDeEFBSUFBUTV3RWdBRUdnQW1vUTV3RUxFQUFnQUJEb0FTQUFRYUFDYWhEbkFRc1lBQ0FBSUFFUTZRRWdBRUdnQW1vZ0FVR2dBbW9RNlFFTGhRRUFJQUFnQVVISStBSVE2Z0VnQUVHZ0Ftb2dBVUdnQW1wQjZQb0NFT29CSUFBZ0FFR2dBbXBCaVAwQ0VPd0JJQUVnQVVHZ0FtcEJxUDhDRU93QlFZajlBa0dvL3dKQmlQMENFT29CUWVqNkFpQUNFUFlCUWNqNEFpQUNJQUlRN0FGQnlQZ0NRZWo2QWlBQ1FhQUNhaERzQVVHSS9RSWdBa0dnQW1vZ0FrR2dBbW9RN1FFTEhBQWdBQ0FCSUFJUTZnRWdBRUdnQW1vZ0FTQUNRYUFDYWhEcUFRdDlBQ0FBSUFCQm9BSnFRY2lCQXhEcUFTQUFJQUJCb0FKcVFlaURBeERzQVNBQVFhQUNha0dJaGdNUTlnRWdBRUdJaGdOQmlJWURFT3dCUWNpQkEwR29pQU1ROWdGQnFJZ0RRY2lCQTBHb2lBTVE3QUZCNklNRFFZaUdBeUFCRU9vQklBRkJxSWdESUFFUTdRRkJ5SUVEUWNpQkF5QUJRYUFDYWhEc0FRc2dBQ0FBSUFFZ0FoRHNBU0FBUWFBQ2FpQUJRYUFDYWlBQ1FhQUNhaERzQVFzZ0FDQUFJQUVnQWhEdEFTQUFRYUFDYWlBQlFhQUNhaUFDUWFBQ2FoRHRBUXNZQUNBQUlBRVE3Z0VnQUVHZ0Ftb2dBVUdnQW1vUTdnRUxHQUFnQUNBQkVPa0JJQUJCb0FKcUlBRkJvQUpxRU80QkN4Z0FJQUFnQVJDeUFTQUFRYUFDYWlBQlFhQUNhaEN5QVFzWUFDQUFJQUVRc0FFZ0FFR2dBbW9nQVVHZ0Ftb1FzQUVMR1FBZ0FDQUJFUEFCSUFCQm9BSnFJQUZCb0FKcUVQQUJjUXRxQUNBQVFjaUtBeERyQVNBQVFhQUNha0hvakFNUTZ3RkI2SXdEUVlpUEF4RDJBVUhJaWdOQmlJOERRWWlQQXhEdEFVR0lqd05CcUpFREVQRUJJQUJCcUpFRElBRVE2Z0VnQUVHZ0FtcEJxSkVESUFGQm9BSnFFT29CSUFGQm9BSnFJQUZCb0FKcUVPNEJDeUFBSUFBZ0FTQUNJQU1ROGdFZ0FFR2dBbW9nQVNBQ0lBTkJvQUpxRVBJQkN4b0JBWDhnQUVHZ0Ftb1E3d0VpQVFSQUlBRVBDeUFBRU84QkN4MEFJQUJCb0FKcUVPVUJCRUFnQUJEekFROExJQUJCb0FKcUVQTUJDL2dCQVFKL1FRQkJBQ2dDQUNJRklBSkJBV3BCd0FSc2FqWUNBQ0FGRVBvQklBVkJ3QVJxSVFVRFFDQUNJQVpIQkVBZ0FCRDNBUVJBSUFWQndBUnJJQVVRK3dFRklBQWdCVUhBQkdzZ0JSRDhBUXNnQUNBQmFpRUFJQVZCd0FScUlRVWdCa0VCYWlFR0RBRUxDeUFBSUFGcklRQWdBeUFDUVFGcklBUnNhaUVDSUFWQndBUnJJZ1VnQlJDR0FnTkFJQVlFUUNBQUVQY0JCRUFnQlNBRlFjQUVheEQ3QVNBQ0VQa0JCU0FGUWNBRWEwSElrd01RK3dFZ0JTQUFJQVZCd0FSckVQd0JJQVZCeUpNRElBSVEvQUVMSUFBZ0FXc2hBQ0FDSUFScklRSWdCVUhBQkdzaEJTQUdRUUZySVFZTUFRc0xRUUFnQlRZQ0FBdXpBZ0FnQWtVRVFDQURFUG9CRHdzZ0FFR0ltQU1RK3dFZ0F4RDZBUU5BSUFKQkFXc2lBaUFCYWkwQUFDRUFJQU1nQXhEK0FTQUFRWUFCVHdSQUlBTkJpSmdESUFNUS9BRWdBRUdBQVdzaEFBc2dBeUFERVA0QklBQkJ3QUJQQkVBZ0EwR0ltQU1nQXhEOEFTQUFRVUJxSVFBTElBTWdBeEQrQVNBQVFTQlBCRUFnQTBHSW1BTWdBeEQ4QVNBQVFTQnJJUUFMSUFNZ0F4RCtBU0FBUVJCUEJFQWdBMEdJbUFNZ0F4RDhBU0FBUVJCcklRQUxJQU1nQXhEK0FTQUFRUWhQQkVBZ0EwR0ltQU1nQXhEOEFTQUFRUWhySVFBTElBTWdBeEQrQVNBQVFRUlBCRUFnQTBHSW1BTWdBeEQ4QVNBQVFRUnJJUUFMSUFNZ0F4RCtBU0FBUVFKUEJFQWdBMEdJbUFNZ0F4RDhBU0FBUVFKcklRQUxJQU1nQXhEK0FTQUFCRUFnQTBHSW1BTWdBeEQ4QVFzZ0FnMEFDd3ZSQVFCQnlLNERFUG9CUWNpdUEwSElyZ01RZ1FJZ0FFSEluQU5Cb0FKQmlLRURFSXNDUVlpaEEwSElwUU1RL2dFZ0FFSElwUU5CeUtVREVQd0JRY2lsQTBHSXFnTVFnZ0pCaUtvRFFjaWxBMEdJcWdNUS9BRkJpS29EUWNpdUF4Q0ZBZ1JBQUF0QmlLRURJQUJCaUxNREVQd0JRY2lsQTBISXJnTVFoUUlFUUVISXJnTVE1d0ZCNkxBREVPZ0JRY2l1QTBHSXN3TWdBUkQ4QVFWQnlMY0RFUG9CUWNpM0EwSElwUU5CeUxjREVQOEJRY2kzQTBIb25nTkJvQUpCeUxjREVJc0NRY2kzQTBHSXN3TWdBUkQ4QVFzTGFRQkI2TXNERVBvQlFlakxBMEhveXdNUWdRSWdBRUdJdkFOQm9BSkJxTDRERUlzQ1FhaStBMEhvd2dNUS9nRWdBRUhvd2dOQjZNSURFUHdCUWVqQ0EwR294d01RZ2dKQnFNY0RRZWpDQTBHb3h3TVEvQUZCcU1jRFFlakxBeENGQWdSQVFRQVBDMEVCQzNnQUlBQWdBRUhnQUdwQjZOQURFSkFCSUFCQjRBQnFJQUJCd0FGcVFjalJBeENRQVNBQVFlQUFhaUFCSUFKQndBRnFFSTBCUWNqUkF5QUJJQUlRalFFZ0FpQUNRY0FCYWlBQ0VKRUJJQUlnQWhEa0FVSG8wQU1nQVNBQ1FlQUFhaENOQVNBQ1FlQUFhaUFDUWNBQmFpQUNRZUFBYWhDUkFRdnNBUUFnQUNBQlFhalNBeENOQVNBQVFlQUFhaUFDUVlqVEF4Q05BU0FBSUFCQjRBQnFRZWpUQXhDUUFTQUFJQUJCd0FGcVFjalVBeENRQVNBQVFlQUFhaUFBUWNBQmFpQURFSkFCSUFNZ0FpQURFSTBCSUFOQmlOTURJQU1Ra1FFZ0F5QURFT1FCSUFOQnFOSURJQU1Ra0FFZ0FTQUNJQU5CNEFCcUVKQUJJQU5CNEFCcVFlalRBeUFEUWVBQWFoQ05BU0FEUWVBQWFrR28wZ01nQTBIZ0FHb1FrUUVnQTBIZ0FHcEJpTk1ESUFOQjRBQnFFSkVCUWNqVUF5QUJJQU5Cd0FGcUVJMEJJQU5Cd0FGcVFhalNBeUFEUWNBQmFoQ1JBU0FEUWNBQmFrR0kwd01nQTBIQUFXb1FrQUVMa0FFQUlBQWdBU0FDUWFqVkF4Q1BBaUFBUWFBQ2FpQURRY2pYQXhDT0FpQUNJQU5CNk5rREVKQUJJQUJCb0FKcUlBQWdCRUdnQW1vUTdBRWdCRUdnQW1vZ0FVSG8yUU1nQkVHZ0Ftb1Fqd0lnQkVHZ0FtcEJxTlVESUFSQm9BSnFFTzBCSUFSQm9BSnFRY2pYQXlBRVFhQUNhaER0QVVISTF3TWdCQkRwQVNBRUlBUVE5Z0VnQkVHbzFRTWdCQkRzQVF0UUFDQUJJQUJCTUdwQnlOb0RFQk1nQVVFd2FpQUFRVEJxUWZqYUF4QVRJQUZCNEFCcUlBQkJxTnNERUJNZ0FVR1FBV29nQUVIWTJ3TVFFeUFDSUFGQndBRnFRYWpiQTBISTJnTWdBaENRQWd0c0FDQUFRWWorQkNBQkVJMEJJQUJCNEFCcVFlaitCQ0FCUWVBQWFoQ05BU0FBUWNBQmFrSEkvd1FnQVVIQUFXb1FqUUVnQUVHZ0FtcEJxSUFGSUFGQm9BSnFFSTBCSUFCQmdBTnFRWWlCQlNBQlFZQURhaENOQVNBQVFlQURha0hvZ1FVZ0FVSGdBMm9RalFFTGlnSUFJQUFnQVJBQUlBQkJNR29nQVVFd2FoQVJJQUZCeUlJRklBRVFqUUVnQUVIZ0FHb2dBVUhnQUdvUUFDQUFRWkFCYWlBQlFaQUJhaEFSSUFGQjRBQnFRYWlEQlNBQlFlQUFhaENOQVNBQVFjQUJhaUFCUWNBQmFoQUFJQUJCOEFGcUlBRkI4QUZxRUJFZ0FVSEFBV3BCaUlRRklBRkJ3QUZxRUkwQklBQkJvQUpxSUFGQm9BSnFFQUFnQUVIUUFtb2dBVUhRQW1vUUVTQUJRYUFDYWtIb2hBVWdBVUdnQW1vUWpRRWdBRUdBQTJvZ0FVR0FBMm9RQUNBQVFiQURhaUFCUWJBRGFoQVJJQUZCZ0FOcVFjaUZCU0FCUVlBRGFoQ05BU0FBUWVBRGFpQUJRZUFEYWhBQUlBQkJrQVJxSUFGQmtBUnFFQkVnQVVIZ0EycEJxSVlGSUFGQjRBTnFFSTBCQzJ3QUlBQkJpSWNGSUFFUWpRRWdBRUhnQUdwQjZJY0ZJQUZCNEFCcUVJMEJJQUJCd0FGcVFjaUlCU0FCUWNBQmFoQ05BU0FBUWFBQ2FrR29pUVVnQVVHZ0Ftb1FqUUVnQUVHQUEycEJpSW9GSUFGQmdBTnFFSTBCSUFCQjRBTnFRZWlLQlNBQlFlQURhaENOQVF1S0FnQWdBQ0FCRUFBZ0FFRXdhaUFCUVRCcUVCRWdBVUhJaXdVZ0FSQ05BU0FBUWVBQWFpQUJRZUFBYWhBQUlBQkJrQUZxSUFGQmtBRnFFQkVnQVVIZ0FHcEJxSXdGSUFGQjRBQnFFSTBCSUFCQndBRnFJQUZCd0FGcUVBQWdBRUh3QVdvZ0FVSHdBV29RRVNBQlFjQUJha0dJalFVZ0FVSEFBV29RalFFZ0FFR2dBbW9nQVVHZ0Ftb1FBQ0FBUWRBQ2FpQUJRZEFDYWhBUklBRkJvQUpxUWVpTkJTQUJRYUFDYWhDTkFTQUFRWUFEYWlBQlFZQURhaEFBSUFCQnNBTnFJQUZCc0FOcUVCRWdBVUdBQTJwQnlJNEZJQUZCZ0FOcUVJMEJJQUJCNEFOcUlBRkI0QU5xRUFBZ0FFR1FCR29nQVVHUUJHb1FFU0FCUWVBRGFrR29qd1VnQVVIZ0Eyb1FqUUVMYkFBZ0FFR0lrQVVnQVJDTkFTQUFRZUFBYWtIb2tBVWdBVUhnQUdvUWpRRWdBRUhBQVdwQnlKRUZJQUZCd0FGcUVJMEJJQUJCb0FKcVFhaVNCU0FCUWFBQ2FoQ05BU0FBUVlBRGFrR0lrd1VnQVVHQUEyb1FqUUVnQUVIZ0EycEI2Sk1GSUFGQjRBTnFFSTBCQzRvQ0FDQUFJQUVRQUNBQVFUQnFJQUZCTUdvUUVTQUJRY2lVQlNBQkVJMEJJQUJCNEFCcUlBRkI0QUJxRUFBZ0FFR1FBV29nQVVHUUFXb1FFU0FCUWVBQWFrR29sUVVnQVVIZ0FHb1FqUUVnQUVIQUFXb2dBVUhBQVdvUUFDQUFRZkFCYWlBQlFmQUJhaEFSSUFGQndBRnFRWWlXQlNBQlFjQUJhaENOQVNBQVFhQUNhaUFCUWFBQ2FoQUFJQUJCMEFKcUlBRkIwQUpxRUJFZ0FVR2dBbXBCNkpZRklBRkJvQUpxRUkwQklBQkJnQU5xSUFGQmdBTnFFQUFnQUVHd0Eyb2dBVUd3QTJvUUVTQUJRWUFEYWtISWx3VWdBVUdBQTJvUWpRRWdBRUhnQTJvZ0FVSGdBMm9RQUNBQVFaQUVhaUFCUVpBRWFoQVJJQUZCNEFOcVFhaVlCU0FCUWVBRGFoQ05BUXRzQUNBQVFZaVpCU0FCRUkwQklBQkI0QUJxUWVpWkJTQUJRZUFBYWhDTkFTQUFRY0FCYWtISW1nVWdBVUhBQVdvUWpRRWdBRUdnQW1wQnFKc0ZJQUZCb0FKcUVJMEJJQUJCZ0FOcVFZaWNCU0FCUVlBRGFoQ05BU0FBUWVBRGFrSG9uQVVnQVVIZ0Eyb1FqUUVMaWdJQUlBQWdBUkFBSUFCQk1Hb2dBVUV3YWhBUklBRkJ5SjBGSUFFUWpRRWdBRUhnQUdvZ0FVSGdBR29RQUNBQVFaQUJhaUFCUVpBQmFoQVJJQUZCNEFCcVFhaWVCU0FCUWVBQWFoQ05BU0FBUWNBQmFpQUJRY0FCYWhBQUlBQkI4QUZxSUFGQjhBRnFFQkVnQVVIQUFXcEJpSjhGSUFGQndBRnFFSTBCSUFCQm9BSnFJQUZCb0FKcUVBQWdBRUhRQW1vZ0FVSFFBbW9RRVNBQlFhQUNha0hvbndVZ0FVR2dBbW9RalFFZ0FFR0FBMm9nQVVHQUEyb1FBQ0FBUWJBRGFpQUJRYkFEYWhBUklBRkJnQU5xUWNpZ0JTQUJRWUFEYWhDTkFTQUFRZUFEYWlBQlFlQURhaEFBSUFCQmtBUnFJQUZCa0FScUVCRWdBVUhnQTJwQnFLRUZJQUZCNEFOcUVJMEJDMndBSUFCQmlLSUZJQUVRalFFZ0FFSGdBR3BCNktJRklBRkI0QUJxRUkwQklBQkJ3QUZxUWNpakJTQUJRY0FCYWhDTkFTQUFRYUFDYWtHb3BBVWdBVUdnQW1vUWpRRWdBRUdBQTJwQmlLVUZJQUZCZ0FOcUVJMEJJQUJCNEFOcVFlaWxCU0FCUWVBRGFoQ05BUXVLQWdBZ0FDQUJFQUFnQUVFd2FpQUJRVEJxRUJFZ0FVSElwZ1VnQVJDTkFTQUFRZUFBYWlBQlFlQUFhaEFBSUFCQmtBRnFJQUZCa0FGcUVCRWdBVUhnQUdwQnFLY0ZJQUZCNEFCcUVJMEJJQUJCd0FGcUlBRkJ3QUZxRUFBZ0FFSHdBV29nQVVId0FXb1FFU0FCUWNBQmFrR0lxQVVnQVVIQUFXb1FqUUVnQUVHZ0Ftb2dBVUdnQW1vUUFDQUFRZEFDYWlBQlFkQUNhaEFSSUFGQm9BSnFRZWlvQlNBQlFhQUNhaENOQVNBQVFZQURhaUFCUVlBRGFoQUFJQUJCc0FOcUlBRkJzQU5xRUJFZ0FVR0FBMnBCeUtrRklBRkJnQU5xRUkwQklBQkI0QU5xSUFGQjRBTnFFQUFnQUVHUUJHb2dBVUdRQkdvUUVTQUJRZUFEYWtHb3FnVWdBVUhnQTJvUWpRRUxnd0VBSUFBUVN3UkFRUUVQQ3lBQUVHUkZCRUJCQUE4TElBQkJpS3NGUWZpckJSQVRJQUJCTUdwQnFLd0ZFQUFnQUVHNHF3VkJpSzBGRUJNZ0FFRXdha0c0clFVUUFFSDRxd1ZCK0tzRkVGVkIrS3NGSUFCQitLc0ZFRjFCK0tzRlFZaXRCVUg0cXdVUVhVSDRxd1ZCNktzRlFSQkIrS3NGRUhoQitLc0ZRWWl0QlJCVEN4RUFJQUJCNkswRkVHTkI2SzBGRUp3Q0M3TUNBQ0FBRUpzQkJFQkJBUThMSUFBUXRBRkZCRUJCQUE4TElBQkJ5SzRGUWZDd0JSQ05BU0FBUWVBQWFrSElyZ1ZCMExFRkVJMEJRZkN3QlVHb3J3VkJzTElGRUk0QlFkQ3hCVUdRc3dVUWtnRkI4TEFGUWZDekJSQ1NBVUhRc1FWQjJLOEZRZEMwQlJDTkFVR3dzZ1ZCNExJRlFjQ3dCUkFRUWJDeUJVSGdzZ1ZCNExJRkVBOUJ3TEFGUWJDeUJSQUFRWkN6QlVIQXN3VkJ3TEFGRUJCQmtMTUZRY0N6QlVIQXN3VVFEMEhBc0FWQmtMTUZFQUJCOExNRlFhQzBCVUhBc0FVUUQwSHdzd1ZCb0xRRlFhQzBCUkFRUWNDd0JVSHdzd1VRQUVHQXRRVkIwTFFGUWNDd0JSQVFRZEMwQlVHQXRRVkJnTFVGRUE5QndMQUZRZEMwQlJBQVFiQzFCUkNMQVVId3N3VkJ1TEFGUVFoQjhMTUZFTVVCUWZDekJVR3dzZ1ZCOExNRkVLZ0JRZkN6QlNBQUVLTUJDeElBSUFCQmtMWUZFTE1CUVpDMkJSQ2VBZ3NJQUNBQUlBRVFad3UyQ1FFQmZ5QUFJQUVRdHdFZ0FSQ2NBUVJBRHdzZ0FVSFF3d1VRb0FFZ0FVR2dBbW9oQUVFK0lRSURRRUhRd3dVZ0FCQ1BBVUd3eEFWQjBNQUZFSThCUWREQUJVR3d3UVVRandGQjBNQUZRZEREQlNBQVFlQUFhaENRQVNBQVFlQUFhaUFBUWVBQWFoQ1BBU0FBUWVBQWFpQUFJQUJCNEFCcUVKRUJJQUJCNEFCcVFiREJCU0FBUWVBQWFoQ1JBU0FBUWVBQWFpQUFRZUFBYWlBQVFlQUFhaENRQVNBQUlBQkJrTUlGRUpBQlFaRENCU0FBUVpEQ0JSQ1FBVUhRd3dWQmtNSUZJQUJCd0FGcUVKQUJRWkRDQlVId3dnVVFqd0ZCa01VRlFmQy9CUkNQQVVId3dnVWdBRUhnQUdwQjBNTUZFSkVCUWREREJTQUFRZUFBYWtIUXd3VVFrUUZCa01VRlFiREVCVUdReFFVUWtBRkJrTVVGUVpERkJSQ1BBVUdReFFWQjBNQUZRWkRGQlJDUkFVR1F4UVZCOEw4RlFaREZCUkNSQVNBQVFlQUFha0hRd3dWQnNNUUZFSkVCUWJERUJVR1F3Z1ZCc01RRkVJMEJRYkRCQlVHd3dRVkJzTUVGRUpBQlFiREJCVUd3d1FWQnNNRUZFSkFCUWJEQkJVR3d3UVZCc01FRkVKQUJRYkRFQlVHd3dRVkJzTVFGRUpFQlFaRENCVUh3dndVZ0FFSGdBR29RalFFZ0FFSGdBR29nQUVIZ0FHb2dBRUhnQUdvUWtBRWdBRUhnQUdvZ0FFSGdBR29Ra2dFZ0FFSEFBV29nQUVIQUFXb1Fqd0VnQUVIQUFXb2dBQ0FBUWNBQmFoQ1JBU0FBUWNBQmFrSHd3Z1VnQUVIQUFXb1FrUUZCME1BRlFkREFCVUhRd0FVUWtBRkIwTUFGUWREQUJVSFF3QVVRa0FFZ0FFSEFBV3BCME1BRklBQkJ3QUZxRUpFQlFaREZCVUh3dndVZ0FCQ05BU0FBSUFBZ0FCQ1FBU0FBUWFBQ2FpRUFJQUlzQUtqUUF3UkFRWkRGQlVIUXR3VVFqd0VnQVVIZ0FHcEJzTGdGRUk4QlFkQzNCU0FCUWZDNUJSQ05BU0FCUWVBQWFrR1F4UVVnQUVIZ0FHb1FrQUVnQUVIZ0FHb2dBRUhnQUdvUWp3RWdBRUhnQUdwQnNMZ0ZJQUJCNEFCcUVKRUJJQUJCNEFCcVFkQzNCU0FBUWVBQWFoQ1JBU0FBUWVBQWFrSFF0d1VnQUVIZ0FHb1FqUUZCOExrRlFkRERCVUhRdWdVUWtRRkIwTG9GUWJDN0JSQ1BBVUd3dXdWQnNMc0ZRWkM4QlJDUUFVR1F2QVZCa0x3RlFaQzhCUkNRQVVHUXZBVkIwTG9GUWZDOEJSQ05BU0FBUWVBQWFrR3d4QVZCMEwwRkVKRUJRZEM5QlVHd3hBVkIwTDBGRUpFQlFkQzlCU0FCSUFCQndBRnFFSTBCUVpDOEJVSFF3d1ZCc0w0RkVJMEJRZEM5QlVIUXd3VVFqd0ZCME1NRlFmQzhCVUhRd3dVUWtRRkIwTU1GUWJDK0JVSFF3d1VRa1FGQjBNTUZRYkMrQlVIUXd3VVFrUUZCa01VRlFkQzZCVUdReFFVUWtBRkJrTVVGUVpERkJSQ1BBVUdReFFWQjBMY0ZRWkRGQlJDUkFVR1F4UVZCc0xzRlFaREZCUkNSQVNBQlFlQUFha0dReFFVZ0FCQ1FBVUd3dmdWQjBNTUZRWkMvQlJDUkFVR1F2d1ZCMEwwRlFaQy9CUkNOQVVHd3hBVkI4THdGUWZDNUJSQ05BVUh3dVFWQjhMa0ZRZkM1QlJDUUFVR1F2d1ZCOExrRlFiREVCUkNSQVNBQUlBQVFqd0VnQUVHd3VBVWdBQkNSQVVHUXhRVkJrTGtGRUk4QklBQkJrTGtGSUFBUWtRRWdBRUhBQVdvZ0FFSEFBV29nQUVIQUFXb1FrQUVnQUVIQUFXb2dBQ0FBUWNBQmFoQ1JBVUdReFFWQmtNVUZJQUFRa0FGQjBMMEZRZEM5QlJDU0FVSFF2UVZCMEwwRklBQkI0QUJxRUpBQklBQkJvQUpxSVFBTElBSUVRQ0FDUVFGcklRSU1BUXNMQzMwQkFYOGdBaEQ2QVNBQUVFd0VRQThMSUFFUVRBUkFEd3NnQVVHZ0Ftb2hBVUUrSVFNRFFDQUFJQUVnQWhDUkFpQUJRYUFDYWlFQklBTXNBS2pRQXdSQUlBQWdBU0FDRUpFQ0lBRkJvQUpxSVFFTElBSWdBaEQrQVNBRFFRRkdSUVJBSUFOQkFXc2hBd3dCQ3dzZ0FDQUJJQUlRa1FJZ0FpQUNFSUlDQ3hBQUlBQkI4TVVGUWFBRUlBRVFpd0lMN0FVQUlBQWdBRUdBQTJwQjBNNEZFSTBCSUFCQmdBTnFRWkRLQlJEa0FTQUFRWkRLQlVHUXlnVVFrQUVnQUNBQVFZQURha0d3endVUWtBRkJzTThGUVpES0JVR1F5Z1VRalFGQjBNNEZRYkRQQlJEa0FVSFF6Z1ZCc004RlFiRFBCUkNRQVVHUXlnVkJzTThGUVpES0JSQ1JBVUhRemdWQjBNNEZRZkRLQlJDUUFTQUFRYUFDYWlBQVFjQUJha0hRemdVUWpRRWdBRUhBQVdwQjBNc0ZFT1FCSUFCQm9BSnFRZERMQlVIUXl3VVFrQUVnQUVHZ0Ftb2dBRUhBQVdwQnNNOEZFSkFCUWJEUEJVSFF5d1ZCME1zRkVJMEJRZERPQlVHd3p3VVE1QUZCME00RlFiRFBCVUd3endVUWtBRkIwTXNGUWJEUEJVSFF5d1VRa1FGQjBNNEZRZERPQlVHd3pBVVFrQUVnQUVIZ0FHb2dBRUhnQTJwQjBNNEZFSTBCSUFCQjRBTnFRWkROQlJEa0FTQUFRZUFBYWtHUXpRVkJrTTBGRUpBQklBQkI0QUJxSUFCQjRBTnFRYkRQQlJDUUFVR3d6d1ZCa00wRlFaRE5CUkNOQVVIUXpnVkJzTThGRU9RQlFkRE9CVUd3endWQnNNOEZFSkFCUVpETkJVR3d6d1ZCa00wRkVKRUJRZERPQlVIUXpnVkI4TTBGRUpBQlFaREtCU0FBSUFFUWtRRWdBU0FCSUFFUWtBRkJrTW9GSUFFZ0FSQ1FBVUh3eWdVZ0FFR0FBMm9nQVVHQUEyb1FrQUVnQVVHQUEyb2dBVUdBQTJvZ0FVR0FBMm9Ra0FGQjhNb0ZJQUZCZ0FOcUlBRkJnQU5xRUpBQlFmRE5CVUg0MmdKQnNNOEZFSTBCUWJEUEJTQUFRYUFDYWlBQlFhQUNhaENRQVNBQlFhQUNhaUFCUWFBQ2FpQUJRYUFDYWhDUUFVR3d6d1VnQVVHZ0Ftb2dBVUdnQW1vUWtBRkJrTTBGSUFCQndBRnFJQUZCd0FGcUVKRUJJQUZCd0FGcUlBRkJ3QUZxSUFGQndBRnFFSkFCUVpETkJTQUJRY0FCYWlBQlFjQUJhaENRQVVIUXl3VWdBRUhnQUdvZ0FVSGdBR29Ra1FFZ0FVSGdBR29nQVVIZ0FHb2dBVUhnQUdvUWtBRkIwTXNGSUFGQjRBQnFJQUZCNEFCcUVKQUJRYkRNQlNBQVFlQURhaUFCUWVBRGFoQ1FBU0FCUWVBRGFpQUJRZUFEYWlBQlFlQURhaENRQVVHd3pBVWdBVUhnQTJvZ0FVSGdBMm9Ra0FFTGh3RUJBbjhnQUVIWTBBVVFnZ0lnQVJENkFVSFEwQVVzQUFBaUF3UkFJQU5CQVVZRVFDQUJJQUFnQVJEOEFRVWdBVUhZMEFVZ0FSRDhBUXNMUVQ4aEFnTkFJQUVnQVJDa0FpQUNMQUNRMEFVaUF3UkFJQU5CQVVZRVFDQUJJQUFnQVJEOEFRVWdBVUhZMEFVZ0FSRDhBUXNMSUFJRVFDQUNRUUZySVFJTUFRc0xJQUVnQVJDQ0FndnJBZ0FnQUVHWTFRVVFtQUlnQUVIWTJRVVFoZ0pCbU5VRlFkalpCVUdZM2dVUS9BRkJtTjRGUWRqWkJSRDdBVUdZM2dWQm1ONEZFSlFDUVpqZUJVSFkyUVZCbU40RkVQd0JRWmplQlVIWTJRVVFwQUpCMk5rRlFkalpCUkNDQWtHWTNnVkIyT0lGRUtVQ1FkamlCVUdZNXdVUXBBSkIyTmtGUWRqaUJVSFk2d1VRL0FGQjJPc0ZRZGpaQlJDbEFrSFkyUVZCbU5VRkVLVUNRWmpWQlVHWThBVVFwUUpCbVBBRlFaam5CVUdZOEFVUS9BRkJtUEFGUVpqbkJSQ2xBa0hZNndWQjJPc0ZFSUlDUVpqbkJVSFk2d1ZCbU9jRkVQd0JRWmpuQlVHWTNnVkJtT2NGRVB3QlFaamVCVUhZNndVUWdnSkIyTmtGUVpqZUJVSFkyUVVRL0FGQjJOa0ZRZGpaQlJDVkFrR1k4QVZCMk9zRlFaandCUkQ4QVVHWThBVkJtUEFGRUpNQ1FkamlCVUdZMVFWQjJPSUZFUHdCUWRqaUJVSFk0Z1VRbEFKQjJPSUZRZGpaQlVIWTRnVVEvQUZCMk9JRlFaandCVUhZNGdVUS9BRkIyT0lGUVpqbkJTQUJFUHdCQzJnQVFkajBCUkQ2QVNBQVFZamNBeEJuSUFGQnFONERFS0VDUVlqY0F4Q2NBa1VFUUVFQUR3dEJxTjRERUo0Q1JRUkFRUUFQQzBHSTNBTkJxTjREUVpqNUJSQ2lBa0hZOUFWQm1Qa0ZRZGowQlJEOEFVSFk5QVZCMlBRRkVLWUNRZGowQlNBQ0VJVUNDN01CQUVIWS9RVVErZ0VnQUVHSTNBTVFaeUFCUWFqZUF4Q2hBa0dJM0FNUW5BSkZCRUJCQUE4TFFhamVBeENlQWtVRVFFRUFEd3RCaU53RFFhamVBMEdZZ2dZUW9nSkIyUDBGUVppQ0JrSFkvUVVRL0FFZ0FrR0kzQU1RWnlBRFFhamVBeENoQWtHSTNBTVFuQUpGQkVCQkFBOExRYWplQXhDZUFrVUVRRUVBRHd0QmlOd0RRYWplQTBHWWdnWVFvZ0pCMlAwRlFaaUNCa0hZL1FVUS9BRkIyUDBGUWRqOUJSQ21Ba0hZL1FVZ0JCQ0ZBZ3YrQVFCQjJJWUdFUG9CSUFCQmlOd0RFR2NnQVVHbzNnTVFvUUpCaU53REVKd0NSUVJBUVFBUEMwR28zZ01RbmdKRkJFQkJBQThMUVlqY0EwR28zZ05CbUlzR0VLSUNRZGlHQmtHWWl3WkIySVlHRVB3QklBSkJpTndERUdjZ0EwR28zZ01Rb1FKQmlOd0RFSndDUlFSQVFRQVBDMEdvM2dNUW5nSkZCRUJCQUE4TFFZamNBMEdvM2dOQm1Jc0dFS0lDUWRpR0JrR1lpd1pCMklZR0VQd0JJQVJCaU53REVHY2dCVUdvM2dNUW9RSkJpTndERUp3Q1JRUkFRUUFQQzBHbzNnTVFuZ0pGQkVCQkFBOExRWWpjQTBHbzNnTkJtSXNHRUtJQ1FkaUdCa0dZaXdaQjJJWUdFUHdCUWRpR0JrSFloZ1lRcGdKQjJJWUdJQVlRaFFJTHlRSUFRZGlQQmhENkFTQUFRWWpjQXhCbklBRkJxTjRERUtFQ1FZamNBeENjQWtVRVFFRUFEd3RCcU40REVKNENSUVJBUVFBUEMwR0kzQU5CcU40RFFaaVVCaENpQWtIWWp3WkJtSlFHUWRpUEJoRDhBU0FDUVlqY0F4Qm5JQU5CcU40REVLRUNRWWpjQXhDY0FrVUVRRUVBRHd0QnFONERFSjRDUlFSQVFRQVBDMEdJM0FOQnFONERRWmlVQmhDaUFrSFlqd1pCbUpRR1FkaVBCaEQ4QVNBRVFZamNBeEJuSUFWQnFONERFS0VDUVlqY0F4Q2NBa1VFUUVFQUR3dEJxTjRERUo0Q1JRUkFRUUFQQzBHSTNBTkJxTjREUVppVUJoQ2lBa0hZandaQm1KUUdRZGlQQmhEOEFTQUdRWWpjQXhCbklBZEJxTjRERUtFQ1FZamNBeENjQWtVRVFFRUFEd3RCcU40REVKNENSUVJBUVFBUEMwR0kzQU5CcU40RFFaaVVCaENpQWtIWWp3WkJtSlFHUWRpUEJoRDhBVUhZandaQjJJOEdFS1lDUWRpUEJpQUlFSVVDQzVRREFFSFltQVlRK2dFZ0FFR0kzQU1RWnlBQlFhamVBeENoQWtHSTNBTVFuQUpGQkVCQkFBOExRYWplQXhDZUFrVUVRRUVBRHd0QmlOd0RRYWplQTBHWW5RWVFvZ0pCMkpnR1FaaWRCa0hZbUFZUS9BRWdBa0dJM0FNUVp5QURRYWplQXhDaEFrR0kzQU1RbkFKRkJFQkJBQThMUWFqZUF4Q2VBa1VFUUVFQUR3dEJpTndEUWFqZUEwR1luUVlRb2dKQjJKZ0dRWmlkQmtIWW1BWVEvQUVnQkVHSTNBTVFaeUFGUWFqZUF4Q2hBa0dJM0FNUW5BSkZCRUJCQUE4TFFhamVBeENlQWtVRVFFRUFEd3RCaU53RFFhamVBMEdZblFZUW9nSkIySmdHUVppZEJrSFltQVlRL0FFZ0JrR0kzQU1RWnlBSFFhamVBeENoQWtHSTNBTVFuQUpGQkVCQkFBOExRYWplQXhDZUFrVUVRRUVBRHd0QmlOd0RRYWplQTBHWW5RWVFvZ0pCMkpnR1FaaWRCa0hZbUFZUS9BRWdDRUdJM0FNUVp5QUpRYWplQXhDaEFrR0kzQU1RbkFKRkJFQkJBQThMUWFqZUF4Q2VBa1VFUUVFQUR3dEJpTndEUWFqZUEwR1luUVlRb2dKQjJKZ0dRWmlkQmtIWW1BWVEvQUZCMkpnR1FkaVlCaENtQWtIWW1BWWdDaENGQWdzckFDQUFRWWpjQXhCbklBRkJxTjRERUtFQ1FZamNBMEdvM2dOQjJLRUdFS0lDUWRpaEJpQUNFS1lDQ3d2Y3dBRjdBRUVBQ3dRWWt3RUFBRUVJQ3lBQkFBQUEvLy8vLy81Yi92OENwTDFUQmRpaENRallPVE5JZlowcFU2ZnRjd0JCeUFVTE1LdXEvLy8vLy82NS8vOVRzZjcvcXg0azlyRDJvTkl3Wjc4U2hmT0VTM2RrMTZ4TFE3YW5HMHVhNW44NTZoRUJHZ0JCK0FVTE1FWVhOQncwSDkvMDhRVFJDYWJtZGdyVnRwVk1iRWZsamNDRG5aT3BpT3RuTFpVWnRZVStlWnFxNDhxUzVZK1lFUUJCcUFZTE1QMy9BZ0FBQUFsMkFnQU14QXNBOU91NldNZFRWNWhJWDBWWFVuQlRXTTUzYmV4V29wY2FCMXlUNUlENncxNzJGUUJCMkFZTE1BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCaUFjTE1GWFYvLy8vZi8vYy8vK3BXUC8vVlE4U2UxaDdVR21ZczErSndubkNwVHV5YTlhbElkdlRqU1ZOODc4YzlZZ0FEUUJCdUFjTE1GYlYvLy8vZi8vYy8vK3BXUC8vVlE4U2UxaDdVR21ZczErSndubkNwVHV5YTlhbElkdlRqU1ZOODc4YzlZZ0FEUUJCNkFjTE1GWFYvLy8vZi8vYy8vK3BXUC8vVlE4U2UxaDdVR21ZczErSndubkNwVHV5YTlhbElkdlRqU1ZOODc4YzlZZ0FEUUJCbUFnTE1LNnEvUC8vLy9WRC9mOUg3ZkwvdHpKcG5lbWlTVHJvQjNxN01vTXg4NmpzYWNEMG9CNk5GTzhHQXY4K0pyTUtCQUJCeUFnTE1LdnEvLy8vdjMvdS8vOVVyUC8vcWdlSlBhdzlxRFRNMmE5RTRUemgwaDNaTmV2U2tPM3B4cEttK1YrT2VrU0FCZ0JCaUJzTElBRUFBQUQvLy8vLy9sdisvd0trdlZNRjJLRUpDTmc1TTBoOW5TbFRwKzF6QUVHb0d3c2diWnp5ODVEcG1ja2pYSktIeSsxc0s0ODVWSEtXRk5NRkVmOVpuOW5aU0FjQVFjZ2JDeUQrLy8vL0FRQUFBQUpJQXdENnQ0Ulk5VSs4N085UGpKbHZCY1dzV2JFa0dBQkI2QnNMSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUdJSEFzZ0FBQUFnUC8vLzMvL0xmOS9BZExlcVFMczBBUUU3SndacEw3T2xLblQ5amtBUWFnY0N5QUJBQUNBLy8vL2YvOHQvMzhCMHQ2cEF1elFCQVRzbkJta3ZzNlVxZFAyT1FCQnlCd0xJUC8vLy8vK1cvNy9BcVM5VXdYWW9Ra0kyRGt6U0gyZEtWT243WE1BQUFBQUFFSG9IQXNnZlBRWERGeHRxNXpsY1V2OVBlbmhIQVhWSFVjd3NtME5hanM2ZEpEcERqOEFRWWdkQ3lBQUFBQ0EveTMvZndIUzNxa0M3TkFFQk95Y0dhUyt6cFNwMC9ZNUFBQUFBQUJCcUNVTE1QUC9EQUFBQUNlcUNnQTAvRElBekZOL2dBcHJldW1QUjlja3V1YStmdE94TDZ0NHZ6dHp5WTUrM29NOVVVWFdDUUJCbU1zQUN5QVJFUkVSRVJFUkVSRVJFQkFQRGcwTkRBc0tDUWdIQndZRkJBTUNBUUVCQVFCQjJNMEFDeUFSRVJFUkVSRVJFUkVSRUJBUERnME5EQXNLQ1FnSEJ3WUZCQU1DQVFFQkFRQkI2TThBQzZBSS92Ly8vd0VBQUFBQ1NBTUErcmVFV1BWUHZPenZUNHlaYndYRnJGbXhKQmdEQUFBQS9mLy8vL3dUKy84STdEajdENGpsSEJpSXJabllkOWg4K2ZYSVc3SFBpYXAwVnJEei9ya0dZRUFCTHdjbWVtWWx2dzJhem5TRFdTMEY1Q3hOQ1JDOTAybTJNSkduWWFDeWY2bjc1S2dtUzdQUENFVHpMSHIvQnV5a05SK0pFZ29MQXFEQ0pZZ2hDSDEvY1J5WDJNVWEyTXJjT1VmQlFlUHVxWHRnVHpUUkhDT2pZR1RGN2wveVQ2a1V4SlZ1bTFTQVVEWWRuZDBHUlo4SmRGSWN6RUFuZGJDVm14MTh5K2hTSmxxd3lGMERtVU5jNGdFUEVCYzlaMStieG1OVHJTYnp2R0ZqdzE2YWdkend6NW1YWXh6WnEvQUV2cFVRSXZMbXlTRDJTYXhDVXhGTnlNSEtjaVZ4RnM2Rll2emNoa2RYN05Wa2VSV1dGMGlhd0VKWE5QaFRkek0xdXBSM1VLNFdVTXo0U1R3YUpSZTI4dHNGNFRqUTN6WWI4MnZuTmozZGdMaFUvQnRKeXRxSWN2TDJ4VnMxNHByZEJMc2NPSm5KQ2FiU0pHVVd6WnlTTGZYalAwWUVxN0Z6K3IwT2VQMzJGeWJtTWp0M25GQU9TRzlYeCtIM2wrdXh2QkJmNlhIYUsyY3pxaWRnTEM3dVRvRlNSUE1YRW0rdjVUa3NNeCthbjl5WVpmS28wRTdTeDdMRGNCWm1nUklSQmg3aUlycUg4TjA4QWpnR1RLVXYvSmRmUTJ1cmxOTmJuUWlIbG5zQnJoU0Y5Tyt3QUoxZ1dqZzVsS2tRNVFpdUt0THo4RFhEc0xpYWJudGd5L21zWkMyMjFnYXA0Z3IxMVdOMENXNVA1MVFWa0Y4clFOY0toVkg3Z2M4dnJmcmdMTm4zMlZXUHoxbWNEZFZnZFFHOVk3ZjJaRE9yNTU3Qkx4cS81VlIycThQY2tTOGtXWFI5N2M0bktIbmtIQTk4M0FwNHZucmtKTmVTRFV3Qk84Wm5sQzdCWXVRYVEyL1djVVZkWDFINi9lbGdVODczRGVUTUZXR08wdzJlQmZyQ2dITmoyN25pWVMxYURSRGEzZmFtVDZleGRvTXMxR3Rid3p0YUVSU0szQWYyeHB5dGVNa01DS3hXZjdMSFBzT0RKNDZQOC9sZEFvU3FZRjNKMDdVaHBtOEVDUTlQdXk2bm5BM21nV3pscFB6aUEvakhDMFFzQUh2MUJrejVhYmhJcjBSQ1dLWmdncVVMSVVGb3lMOFA2TUhteTA5UGhqUk82bVFmajFFdHY1S1BxYUVXWk9tcUlvZEozRVRicUJFRzBJRkgrWDkxQ0FHN2dYMGdrY3F6bmlRM2ZGRlZyRmN4QjBOUzlSb3VIRlRlSyt6REEyRFJlWmFtMUFUbzhEYWxWVUxvdkF3MTNwTnZjVnA1bmx0eTZMc3hOa1dvSzBKdW9MdU1abFBnOWxkSUtBK2NlYzJYQTBRTC9GWjVwdDRuTXE4WXIwazIrL0d5VE5IenJISzZwcVlKVFdmOW83TjU0aDVMOG0wcFRMVVQzS1luMk5LVlJIbEZFTlkwYW9TV3RhTzRRRjluUElpNkx0YlFjK0IvbVYxK0lvcU4veG5vdzd4QjRFK1NySXNzR1NFYUcrcjBKMFU3anJwa09BQXRUNTdaR09UMHZ3WngzK2s0bFo3N1IyOGpSTzNwL2Q5T0x3VzhVU2JRcWpaOXdJTnpzTlR3aDJjZlQyOElpU3gwWVBVWFk3OW9LYWRZWTN6MEZ3eGNiYXVjNVhGTC9UM3A0UndGMVIxSE1MSnREV283T25TUTZRNC9BRUdJMkFBTG9BaisvLy8vQVFBQUFBSklBd0Q2dDRSWTlVKzg3TzlQakpsdkJjV3NXYkVrR1AvLy8vOEFBQUFBQWFRQkFQMWJRcXo2SjE3Mjl5Zkd6TGVDWXRhc1dCSU1BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBUWFqZ0FBdWdDTW4vLy84MkFBQUFOenhhQUZ2RFFRTGJsanJ1UlphUy9ud1ZLZzhpRGZFWG5Qci8vMk1GQUFCa0ZkZ0kxTiszbFVpRGp4T3NkQy9jeTZZSXE3TUQ1aEozMXZML2lDa05BSW50TVpoNnZ4ZDhHMHFGOU8rY0NWbzR5dndrMVFYTVpvMFkvSXNrNXdOMHdaTzgyMHRVU1B1V1JKVXNTMjlQcjFQd2hXZDZ4WEFuak1iQnhHU2Vyd09nR1ErSnlLYkdtQkpXd3NZZ0VMeU1tUVhKcHNtRWRXSTZNdGh6T2JtcG9ZRk8wNmhkSWQwbXRYU2UyOFpLaDREcmlpWkF2NXBLTmZJYTFwVHIyUkhHZXpKMGdPR1hrT29HSDRIQ0E5bTZrSmFhN1FpMHFOY0NSdDdFQ25wc0ZVMnNyQnc1TG85aG05NjlxckY5L2kxcC9tZVNJM1hpaUNPMjluczg1Wk5aNHJaWGw4R01EQUJkenl4WFBrbEMrL3dGK3pOYzYxOWdEK0Z2aHNORW5pSVdjTmFrOFdpdnpJNERUZmF0Y2toWHM3K0duNTlYWEVRQ2g2d0luS1JkYVlTTmxwNXhwcHVrd2JmczJiUUVLbHBNODhhMzVFay9QMUtLV3ZtLy8yZ3IyWHFqRG9XbThxOFFiVW5rTzRHczVXUTAzWGdjc004bkdydXp5QkxLaEg1Sm45eXVmZ0FpbzhXemhiR1h6N2xYc09iQjVrQnpEeFlOUFRKQjlsWmF6VjlFOHhoS0RhOUhINUZZakd5OXZlaUgzazByemozTisySEw0SWdscXd1eVROK3NCMVJPVHZsZHR0MlBGWHBrald6VTJNV0RFdDBiYlJEUXdxd3g5T0NQMWtwMThtaDVRQU1WYzdDSXJRN0l0MURlODlMOXpyVXhwc1FPYTY0cEUzM1RBamcxQ013N24wU2V2MmhudUVJcU9UMVhmVlIwRUQ3M2JvazY4MVgwNDEvdy84UXh2NnlrcXZjRldLY2p4VmNCcjh3M0VOZStjNzZnUDViM2NUWEMwSUdiaTJaUFBDaVI0L21TWFJuUWl3aXY4d3d1b3NKWE44MXM0SEVhWFRpN0crSXo2d2ZjUmFjT3FmallmaC9qNCtzYVdPOHYzd3ZaYzNRMjVwdlpKbGVEWTh5SnIvNzRtYzNlZjZXQS9UcFQzNzJjT1Y0WkpiNExiUmsvcjFQUnRidVRQVHZLYlJrdVA0QkY5NXlhTlFNL3hXQnYrV2RVeFRRUVNIUHMzbHdIU1IwRXluR2FISkxDNmg0WkR2TWFEazE4YStEcmVHU2ZHNlRodE1vb3JmUVIxVlQvWWVvdGx0TC8yNlV5YVJaTTdoMi84R2t6V1haeG5aaFBhQTZjM1BmRldYcG1vaE04d1JORUEvR1F3Z2tQRDVVQU9VOU9hSjV1OW11bXJNWDVUbG9VY2ZTZXhKemFTcHlac1FoMFRmOUR5VmZydGhWeGRQRG12aDBwRDFaTmloQUVPNENqdXd2bXczaldHTENTcVlRZDA0ZTJEM0Rxb2xsL2xweHhTK3J5dDROZzZ5V3lIZk5qd1VyYTJmVUZza3l0VnYxbU9UQ1VINzhVcUVMNEtSOFBsNzNvb2NtR0dHWHJrYlE1S041UXAzV2oyV0NTY1l2UlNZbTlHbkVVTFhuVDBHN2JyYXdTUnI1NEJhcTFSNDNUQ25jTkVRalpqbTArbG96bjIrT3p2UDdDWUJPa20rWnc3ckRIbFFUK1JZWUVFUVE1SXZDRndFd1ZhV1YwSFlWUlBDTU9PM1JDZDdqZ0phSHNwQ0hvdjFFcEV3WTRGZ2RWS1YrK0NhSEI4MXZPVVZBYWtKaTBKckRPWTJwMXVJS0xZVFBDWEFCQnlPZ0FDNkFJVmxWVlZmLy8vLytwa3FtcXJNTFRONjQ2d1ZzRmtDWWlNUDVveG94dm5rS0VORWlEc0JNN3NZOTJRQm93YndzQjQxS0JkaG1iWlAycDFyOFErZ0hTVXVJL0JncWNHbVZGKy85eGdJTXFVTmlpcUtoeDdGMWR5clNEdEh2U0NPQmtKd09nZGF2QzkwQXB5QWUxM1ltL29TakR0UmNob0ZxRDhVNG9CenRiQjBzelJkY3p6Ni9uakNKRmFNZEQwVWxiV1hjN09neXlpczExdGl5UkxqRDBEY0ErS09mOFNTektGS3drUGlpeUFCTERucXJrcG9kRDFsS2pJaERuenE0TS9VM254d2pHUkdWaU9WZ1NhZ1JKTE42dWpWZXd4N1NoYk4xZmNtd2lXRlFYU1JkUHlwWGE1cW1FaVZ3TmhFM0hsSlNmVzlxSzJ2dXFNU1dkdUgrWU80c3JSaU1wV1ZTQzdqWVh6SndKQnRtc3RkcHV4M240QVRlZ1ZON1pLT29FNWt5anliUzU2RXltUVRhYzBqZ2VOR2xIUUxMb0FhZk91WGJMTnBMK1RqazI1VlZCeHBkbFlGaWtRaGUxTGU5ZEtDZ21YZDdRREluUTRvZXFKZHpaTUozdDFXdkUweGVxL0pBV01JVlZHR0FNMnFvM1dEcjdZdzREMjZyMU9yVkpVQUo1YWFWQ1lFdTNmenNCOThnRHM1bmlkZlNTWGMvd1lHT3Z6ZFlpWlFRY3VRQ1EyK1dmSzdueWVnUjhDTlhVVWRYdUpETWIzMG5WdlNZNWFMM25CS2VFcHUzOGJubGZYOGJ2ZUZLSjg0cWc3RU80Z0pmT2l3MzNuOFlxaExRMmdPV3hUN29VR3crSGc1UlpKZGFTVXFnaEhnY2ZSbUthYXhtOEFsS2k0aDVaM0duaC9EVTVMbzRtZlUwK0pKSGFkY2xVaGttTEhuQWY3K2hheWtUM1hLL1E4ZjAvLzZrQ2p5aWppWmxBY2NFYUx1VWF2WEhTalh2c1BzT3VjNUlzaGJ5V01FU1RMSTh1dFlaRDVZMlFkRVB4STM2M1AxRTgxL3BSMHNzMy9VRHB3NUN2YmZremxDVXVYTXdnd1VUMC9VdnpQajQvaFhHMURlZncwVlNoRkJRUlFMT1EwQVNBU0lCd25wWExiTmtocWRadUJIcy8yOWJ5TkRMRmZ3Y2VWek5HQWxDVVFKVlpGaHMrVWI4QnRFNTN3cEk1Z0xnTVVaY0YwM3pmS0dMbmtWeHp0Uit2cjJmemovMzdpdVN4YmI0UXhZMk9CNkdacVhtUkUzQStSTW1JZmg1MlVVV0JJb2tMeDQxMDZTUFNnNUUwZStHNE40MGdOQXlNS0JJeldKSU93K1VsMVQ3bEY4bktHMmovU0tmbXlJZElGbjl6UkJXN3dMMk9ubW8vc0gva2RHaUJWbDZQZ24yNDcyTWdJZDh6VEtZY0JSNHlUekREaHE5ZE5DQ3NDMk5kNTVXUjVqdGY4Zmx1S2dIRmRGT293eG45VER1Yi8zeFYvbjhkOFJlMHZPaGZvM0sxWEJpNVdxUzRlZjMrKysxTEJrLzdTWDdXUEkrMnNrK0VEY2ZBWWNURGJadDF1eFNNS2p6RHFlams3VUhWb3NLK3JPZU53N0c4YnJXdEFudmdTVGpTak5YUVdEMHRlb0plM1Y5UVpLVE5jSVZDUlA5eUFmZ2FsK0J0M1RqOExseEp1U3Z3aTVSakhYTGtGa2Jjb0prR0E3alhtcmdEVWpuVS9PM0pMaThHWmx3b0I2dTY3VmFsWjZMUVMxaGxISEF5SkhOUVRMU2tBUCtkNTRXRkIrL3RtTytkeEVkM2d6akNKMncyRnJNVVJETlNWTk5IUXlGZUFFSG84QUFMZ0FJQWdFREFJS0JnNEJDUVVOQXdzSER3Q0loSXlDaW9hT2dZbUZqWU9MaDQrQVNFUk1Ra3BHVGtGSlJVMURTMGRQUU1qRXpNTEt4czdCeWNYTnc4dkh6OEFvSkN3aUtpWXVJU2tsTFNNckp5OGdxS1Nzb3FxbXJxR3BwYTJqcTZldm9HaGtiR0pxWm01aGFXVnRZMnRuYjJEbzVPemk2dWJ1NGVubDdlUHI1Ky9nR0JRY0Vob1dIaEVaRlIwVEd4Y2ZFSmlVbkpLYWxwNlJtWldkazV1WG41QllWRnhTV2xaZVVWbFZYVk5iVjE5UTJOVGMwdHJXM3RIWjFkM1QyOWZmMERnMFBESTZOajR4T1RVOU16czNQekM0dEx5eXVyYStzYm0xdmJPN3Q3K3dlSFI4Y25wMmZuRjVkWDF6ZTNkL2NQajAvUEw2OXY3eCtmWDk4L3YzLy9BRUdvL2dBTE1LcnEvLy8vdjMvdS8vOVVyUC8vcWdlSlBhdzlxRFRNMmE5RTRUemgwaDNaTmV2U2tPM3B4cEttK1YrT2VrU0FCZ0JCMlA0QUN6QlYxZi8vLzMvLzNQLy9xVmovLzFVUEVudFllMUJwbUxOZmljSjV3cVU3c212V3BTSGIwNDBsVGZPL0hQV0lBQTBBUWNpREFRc3dxdXIvLy8rL2YrNy8vMVNzLy8rcUI0azlyRDJvTk16WnIwVGhQT0hTSGRrMTY5S1E3ZW5Ha3FiNVg0NTZSSUFHQUVINGhnRUxZUFAvREFBQUFDZXFDZ0EwL0RJQXpGTi9nQXByZXVtUFI5Y2t1dWErZnRPeEw2dDR2enR6eVk1KzNvTTlVVVhXQ2ZQL0RBQUFBQ2VxQ2dBMC9ESUF6Rk4vZ0FwcmV1bVBSOWNrdXVhK2Z0T3hMNnQ0dnp0enlZNSszb005VVVYV0NRQkIyTklCQ3lBUkVSRVJFUkVSRVJFUkVCQVBEZzBOREFzS0NRZ0hCd1lGQkFNQ0FRRUJBUUJCdU5jQkN5QVJFUkVSRVJFUkVSRVJFQkFQRGcwTkRBc0tDUWdIQndZRkJBTUNBUUVCQVFCQjJOc0JDNkFJL3YvLy93RUFBQUFDU0FNQStyZUVXUFZQdk96dlQ0eVpid1hGckZteEpCZ0RBQUFBL2YvLy8vd1QrLzhJN0RqN0Q0amxIQmlJclpuWWQ5aDgrZlhJVzdIUGlhcDBWckR6L3JrR1lFQUJMd2NtZW1ZbHZ3MmF6blNEV1MwRjVDeE5DUkM5MDJtMk1KR25ZYUN5ZjZuNzVLZ21TN1BQQ0VUekxIci9CdXlrTlIrSkVnb0xBcURDSllnaENIMS9jUnlYMk1VYTJNcmNPVWZCUWVQdXFYdGdUelRSSENPallHVEY3bC95VDZrVXhKVnVtMVNBVURZZG5kMEdSWjhKZEZJY3pFQW5kYkNWbXgxOHkraFNKbHF3eUYwRG1VTmM0Z0VQRUJjOVoxK2J4bU5UclNienZHRmp3MTZhZ2R6d3o1bVhZeHpacS9BRXZwVVFJdkxteVNEMlNheENVeEZOeU1IS2NpVnhGczZGWXZ6Y2hrZFg3TlZrZVJXV0YwaWF3RUpYTlBoVGR6TTF1cFIzVUs0V1VNejRTVHdhSlJlMjh0c0Y0VGpRM3pZYjgydm5OajNkZ0xoVS9CdEp5dHFJY3ZMMnhWczE0cHJkQkxzY09KbkpDYWJTSkdVV3paeVNMZlhqUDBZRXE3RnorcjBPZVAzMkZ5Ym1NanQzbkZBT1NHOVh4K0gzbCt1eHZCQmY2WEhhSzJjenFpZGdMQzd1VG9GU1JQTVhFbSt2NVRrc014K2FuOXlZWmZLbzBFN1N4N0xEY0JabWdSSVJCaDdpSXJxSDhOMDhBamdHVEtVdi9KZGZRMnVybE5OYm5RaUhsbnNCcmhTRjlPK3dBSjFnV2pnNWxLa1E1UWl1S3RMejhEWERzTGlhYm50Z3kvbXNaQzIyMWdhcDRncjExV04wQ1c1UDUxUVZrRjhyUU5jS2hWSDdnYzh2cmZyZ0xObjMyVldQejFtY0RkVmdkUUc5WTdmMlpET3I1NTdCTHhxLzVWUjJxOFBja1M4a1dYUjk3YzRuS0hua0hBOTgzQXA0dm5ya0pOZVNEVXdCTzhabmxDN0JZdVFhUTIvV2NVVmRYMUg2L2VsZ1U4NzNEZVRNRldHTzB3MmVCZnJDZ0hOajI3bmlZUzFhRFJEYTNmYW1UNmV4ZG9NczFHdGJ3enRhRVJTSzNBZjJ4cHl0ZU1rTUNLeFdmN0xIUHNPREo0NlA4L2xkQW9TcVlGM0owN1VocG04RUNROVB1eTZubkEzbWdXemxwUHppQS9qSEMwUXNBSHYxQmt6NWFiaElyMFJDV0taZ2dxVUxJVUZveUw4UDZNSG15MDlQaGpSTzZtUWZqMUV0djVLUHFhRVdaT21xSW9kSjNFVGJxQkVHMElGSCtYOTFDQUc3Z1gwZ2tjcXpuaVEzZkZGVnJGY3hCME5TOVJvdUhGVGVLK3pEQTJEUmVaYW0xQVRvOERhbFZVTG92QXcxM3BOdmNWcDVubHR5NkxzeE5rV29LMEp1b0x1TVpsUGc5bGRJS0ErY2VjMlhBMFFML0ZaNXB0NG5NcThZcjBrMisvR3lUTkh6ckhLNnBxWUpUV2Y5bzdONTRoNUw4bTBwVExVVDNLWW4yTktWUkhsRkVOWTBhb1NXdGFPNFFGOW5QSWk2THRiUWMrQi9tVjErSW9xTi94bm93N3hCNEUrU3JJc3NHU0VhRytyMEowVTdqcnBrT0FBdFQ1N1pHT1QwdndaeDMrazRsWjc3UjI4alJPM3AvZDlPTHdXOFVTYlFxalo5d0lOenNOVHdoMmNmVDI4SWlTeDBZUFVYWTc5b0thZFlZM3owRnd4Y2JhdWM1WEZML1QzcDRSd0YxUjFITUxKdERXbzdPblNRNlE0L0FFSDQ0d0VMb0FqKy8vLy9BUUFBQUFKSUF3RDZ0NFJZOVUrODdPOVBqSmx2QmNXc1diRWtHUC8vLy84QUFBQUFBYVFCQVAxYlFxejZKMTcyOXlmR3pMZUNZdGFzV0JJTUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFRWmpzQVF1Z0NNbi8vLzgyQUFBQU56eGFBRnZEUVFMYmxqcnVSWmFTL253VktnOGlEZkVYblByLy8yTUZBQUJrRmRnSTFOKzNsVWlEanhPc2RDL2N5NllJcTdNRDVoSjMxdkwvaUNrTkFJbnRNWmg2dnhkOEcwcUY5TytjQ1ZvNHl2d2sxUVhNWm8wWS9Jc2s1d04wd1pPODIwdFVTUHVXUkpVc1MyOVByMVB3aFdkNnhYQW5qTWJCeEdTZXJ3T2dHUStKeUtiR21CSld3c1lnRUx5TW1RWEpwc21FZFdJNk10aHpPYm1wb1lGTzA2aGRJZDBtdFhTZTI4WktoNERyaWlaQXY1cEtOZklhMXBUcjJSSEdlekowZ09HWGtPb0dINEhDQTltNmtKYWE3UWkwcU5jQ1J0N0VDbnBzRlUyc3JCdzVMbzlobTk2OXFyRjkvaTFwL21lU0kzWGlpQ08yOW5zODVaTlo0clpYbDhHTURBQmR6eXhYUGtsQysvd0Yrek5jNjE5Z0QrRnZoc05FbmlJV2NOYWs4V2l2ekk0RFRmYXRja2hYczcrR241OVhYRVFDaDZ3SW5LUmRhWVNObHA1eHBwdWt3YmZzMmJRRUtscE04OGEzNUVrL1AxS0tXdm0vLzJncjJYcWpEb1dtOHE4UWJVbmtPNEdzNVdRMDNYZ2NzTThuR3J1enlCTEtoSDVKbjl5dWZnQWlvOFd6aGJHWHo3bFhzT2JCNWtCekR4WU5QVEpCOWxaYXpWOUU4eGhLRGE5SEg1RllqR3k5dmVpSDNrMHJ6ajNOKzJITDRJZ2xxd3V5VE4rc0IxUk9UdmxkdHQyUEZYcGtqV3pVMk1XREV0MGJiUkRRd3F3eDlPQ1Axa3AxOG1oNVFBTVZjN0NJclE3SXQxRGU4OUw5enJVeHBzUU9hNjRwRTMzVEFqZzFDTXc3bjBTZXYyaG51RUlxT1QxWGZWUjBFRDczYm9rNjgxWDA0MS93LzhReHY2eWtxdmNGV0tjanhWY0JyOHczRU5lK2M3NmdQNWIzY1RYQzBJR2JpMlpQUENpUjQvbVNYUm5RaXdpdjh3d3Vvc0pYTjgxczRIRWFYVGk3RytJejZ3ZmNSYWNPcWZqWWZoL2o0K3NhV084djN3dlpjM1EyNXB2WkpsZURZOHlKci83NG1jM2VmNldBL1RwVDM3MmNPVjRaSmI0TGJSay9yMVBSdGJ1VFBUdktiUmt1UDRCRjk1eWFOUU0veFdCditXZFV4VFFRU0hQczNsd0hTUjBFeW5HYUhKTEM2aDRaRHZNYURrMThhK0RyZUdTZkc2VGh0TW9vcmZRUjFWVC9ZZW90bHRMLzI2VXlhUlpNN2gyLzhHa3pXWFp4blpoUGFBNmMzUGZGV1hwbW9oTTh3Uk5FQS9HUXdna1BENVVBT1U5T2FKNXU5bXVtck1YNVRsb1VjZlNleEp6YVNweVpzUWgwVGY5RHlWZnJ0aFZ4ZFBEbXZoMHBEMVpOaWhBRU80Q2p1d3ZtdzNqV0dMQ1NxWVFkMDRlMkQzRHFvbGwvbHB4eFMrcnl0NE5nNnlXeUhmTmp3VXJhMmZVRnNreXRWdjFtT1RDVUg3OFVxRUw0S1I4UGw3M29vY21HR0dYcmtiUTVLTjVRcDNXajJXQ1NjWXZSU1ltOUduRVVMWG5UMEc3YnJhd1NScjU0QmFxMVI0M1RDbmNORVFqWmptMCtsb3puMitPenZQN0NZQk9rbStadzdyREhsUVQrUllZRUVRUTVJdkNGd0V3VmFXVjBIWVZSUENNT08zUkNkN2pnSmFIc3BDSG92MUVwRXdZNEZnZFZLVisrQ2FIQjgxdk9VVkFha0ppMEpyRE9ZMnAxdUlLTFlUUENYQUJCdVBRQkM2QUlWbFZWVmYvLy8vK3BrcW1xck1MVE42NDZ3VnNGa0NZaU1QNW94b3h2bmtLRU5FaURzQk03c1k5MlFCb3did3NCNDFLQmRobWJaUDJwMXI4UStnSFNVdUkvQmdxY0dtVkYrLzl4Z0lNcVVOaWlxS2h4N0YxZHlyU0R0SHZTQ09Ca0p3T2dkYXZDOTBBcHlBZTEzWW0vb1NqRHRSY2hvRnFEOFU0b0J6dGJCMHN6UmRjeno2L25qQ0pGYU1kRDBVbGJXWGM3T2d5eWlzMTF0aXlSTGpEMERjQStLT2Y4U1N6S0ZLd2tQaWl5QUJMRG5xcmtwb2REMWxLakloRG56cTRNL1Uzbnh3akdSR1ZpT1ZnU2FnUkpMTjZ1alZld3g3U2hiTjFmY213aVdGUVhTUmRQeXBYYTVxbUVpVndOaEUzSGxKU2ZXOXFLMnZ1cU1TV2R1SCtZTzRzclJpTXBXVlNDN2pZWHpKd0pCdG1zdGRwdXgzbjRBVGVnVk43WktPb0U1a3lqeWJTNTZFeW1RVGFjMGpnZU5HbEhRTExvQWFmT3VYYkxOcEwrVGprMjVWVkJ4cGRsWUZpa1FoZTFMZTlkS0NnbVhkN1FESW5RNG9lcUpkelpNSjN0MVd2RTB4ZXEvSkFXTUlWVkdHQU0ycW8zV0RyN1l3NEQyNnIxT3JWSlVBSjVhYVZDWUV1M2Z6c0I5OGdEczVuaWRmU1NYYy93WUdPdnpkWWlaUVFjdVFDUTIrV2ZLN255ZWdSOENOWFVVZFh1SkRNYjMwblZ2U1k1YUwzbkJLZUVwdTM4Ym5sZlg4YnZlRktKODRxZzdFTzRnSmZPaXczM244WXFoTFEyZ09XeFQ3b1VHdytIZzVSWkpkYVNVcWdoSGdjZlJtS2FheG04QWxLaTRoNVozR25oL0RVNUxvNG1mVTArSkpIYWRjbFVoa21MSG5BZjcraGF5a1QzWEsvUThmMC8vNmtDanlpamlabEFjY0VhTHVVYXZYSFNqWHZzUHNPdWM1SXNoYnlXTUVTVExJOHV0WVpENVkyUWRFUHhJMzYzUDFFODEvcFIwc3MzL1VEcHc1Q3ZiZmt6bENVdVhNd2d3VVQwL1V2elBqNC9oWEcxRGVmdzBWU2hGQlFSUUxPUTBBU0FTSUJ3bnBYTGJOa2hxZFp1QkhzLzI5YnlORExGZndjZVZ6TkdBbENVUUpWWkZocytVYjhCdEU1M3dwSTVnTGdNVVpjRjAzemZLR0xua1Z4enRSK3ZyMmZ6ai8zN2l1U3hiYjRReFkyT0I2R1pxWG1SRTNBK1JNbUlmaDUyVVVXQklva0x4NDEwNlNQU2c1RTBlK0c0TjQwZ05BeU1LQkl6V0pJT3crVWwxVDdsRjhuS0cyai9TS2ZteUlkSUZuOXpSQlc3d0wyT25tby9zSC9rZEdpQlZsNlBnbjI0NzJNZ0lkOHpUS1ljQlI0eVR6RERocTlkTkNDc0MyTmQ1NVdSNWp0ZjhmbHVLZ0hGZEZPb3d4bjlURHViLzN4Vi9uOGQ4UmUwdk9oZm8zSzFYQmk1V3FTNGVmMysrKzFMQmsvN1NYN1dQSSsyc2srRURjZkFZY1REYlp0MXV4U01LanpEcWVqazdVSFZvc0srck9lTnc3Rzhicld0QW52Z1NUalNqTlhRV0QwdGVvSmUzVjlRWktUTmNJVkNSUDl5QWZnYWwrQnQzVGo4TGx4SnVTdndpNVJqSFhMa0ZrYmNvSmtHQTdqWG1yZ0RVam5VL08zSkxpOEdabHdvQjZ1NjdWYWxaNkxRUzFobEhIQXlKSE5RVExTa0FQK2Q1NFdGQisvdG1PK2R4RWQzZ3pqQ0oydzJGck1VUkROU1ZOTkhReUZlQUVIWS9BRUxnQUlBZ0VEQUlLQmc0QkNRVU5Bd3NIRHdDSWhJeUNpb2FPZ1ltRmpZT0xoNCtBU0VSTVFrcEdUa0ZKUlUxRFMwZFBRTWpFek1MS3hzN0J5Y1hOdzh2SHo4QW9KQ3dpS2lZdUlTa2xMU01ySnk4Z3FLU3NvcXFtcnFHcHBhMmpxNmV2b0doa2JHSnFabTVoYVdWdFkydG5iMkRvNU96aTZ1YnU0ZW5sN2VQcjUrL2dHQlFjRWhvV0hoRVpGUjBUR3hjZkVKaVVuSkthbHA2Um1aV2RrNXVYbjVCWVZGeFNXbFplVVZsVlhWTmJWMTlRMk5UYzB0clczdEhaMWQzVDI5ZmYwRGcwUERJNk5qNHhPVFU5TXpzM1B6QzR0THl5dXJhK3NibTF2Yk83dDcrd2VIUjhjbnAyZm5GNWRYMXplM2QvY1BqMC9QTDY5djd4K2ZYOTgvdjMvL0FFR1lqZ0lMb0FqKy8vLy9BUUFBQUFKSUF3RDZ0NFJZOVUrODdPOVBqSmx2QmNXc1diRWtHQU1BQUFEOS8vLy8vQlA3L3dqc09Qc1BpT1VjR0lpdG1kaDMySHo1OWNoYnNjK0pxblJXc1BQK3VRWmdRQUV2QnlaNlppVy9EWnJPZElOWkxRWGtMRTBKRUwzVGFiWXdrYWRob0xKL3FmdmtxQ1pMczg4SVJQTXNldjhHN0tRMUg0a1NDZ3NDb01JbGlDRUlmWDl4SEpmWXhScll5dHc1UjhGQjQrNnBlMkJQTk5FY0k2TmdaTVh1WC9KUHFSVEVsVzZiVklCUU5oMmQzUVpGbndsMFVoek1RQ2Qxc0pXYkhYekw2RkltV3JESVhRT1pRMXppQVE4UUZ6MW5YNXZHWTFPdEp2TzhZV1BEWHBxQjNQRFBtWmRqSE5tcjhBUytsUkFpOHViSklQWkpyRUpURVUzSXdjcHlKWEVXem9WaS9OeUdSMWZzMVdSNUZaWVhTSnJBUWxjMCtGTjNNelc2bEhkUXJoWlF6UGhKUEJvbEY3Ynkyd1hoT05EZk5odnphK2MyUGQyQXVGVDhHMG5LMm9oeTh2YkZXelhpbXQwRXV4dzRtY2tKcHRJa1pSYk5uSkl0OWVNL1JnU3JzWFA2dlE1NC9mWVhKdVl5TzNlY1VBNUliMWZINGZlWDY3RzhFRi9wY2Rvclp6T3FKMkFzTHU1T2dWSkU4eGNTYjYvbE9Td3pINXFmM0pobDhxalFUdExIc3NOd0ZtYUJFaEVHSHVJaXVvZnczVHdDT0FaTXBTLzhsMTlEYTZ1VTAxdWRDSWVXZXdHdUZJWDA3N0FBbldCYU9EbVVxUkRsQ0s0cTB2UHdOY093dUpwdWUyREwrYXhrTGJiV0JxbmlDdlhWWTNRSmJrL25WQldRWHl0QTF3cUZVZnVCenkrdCt1QXMyZmZaVlkvUFdad04xV0IxQWIxanQvWmtNNnZubnNFdkdyL2xWSGFydzl5Ukx5UlpkSDN0emljb2VlUWNEM3pjQ25pK2V1UWsxNUlOVEFFN3htZVVMc0ZpNUJwRGI5WnhSVjFmVWZyOTZXQlR6dmNONU13VllZN1REWjRGK3NLQWMyUGJ1ZUpoTFZvTkVOcmQ5cVpQcDdGMmd5elVhMXZETzFvUkZJcmNCL2JHbksxNHlRd0lyRlovc3NjK3c0TW5qby96K1YwQ2hLcGdYY25UdFNHbWJ3UUpEMCs3THFlY0RlYUJiT1drL09JRCtNY0xSQ3dBZS9VR1RQbHB1RWl2UkVKWXBtQ0NwUXNoUVdqSXZ3L293ZWJMVDArR05FN3FaQitQVVMyL2tvK3BvUlprNmFvaWgwbmNSTnVvRVFiUWdVZjVmM1VJQWJ1QmZTQ1J5ck9lSkRkOFVWV3NWekVIUTFMMUdpNGNWTjRyN01NRFlORjVscWJVQk9qd05xVlZRdWk4RERYZWsyOXhXbm1lVzNMb3V6RTJSYWdyUW02Z3U0eG1VK0QyVjBnb0Q1eDV6WmNEUkF2OFZubW0zaWN5cnhpdlNUYjc4YkpNMGZPc2NycW1wZ2xOWi8yanMzbmlIa3Z5YlNsTXRSUGNwaWZZMHBWRWVVVVExalJxaEphMW83aEFYMmM4aUxvdTF0Qno0SCtaWFg0aWlvMy9HZWpEdkVIZ1Q1S3NpeXdaSVJvYjZ2UW5SVHVPdW1RNEFDMVBudGtZNVBTL0JuSGY2VGlWbnZ0SGJ5TkU3ZW45MzA0dkJieFJKdENxTm4zQWczT3cxUENIWng5UGJ3aUpMSFJnOVJkanYyZ3BwMWhqZlBRWERGeHRxNXpsY1V2OVBlbmhIQVhWSFVjd3NtME5hanM2ZEpEcERqOEFRYmlXQWd1Z0NQNy8vLzhCQUFBQUFrZ0RBUHEzaEZqMVQ3enM3MCtNbVc4RnhheFpzU1FZLy8vLy93QUFBQUFCcEFFQS9WdENyUG9uWHZiM0o4Yk10NEppMXF4WUVnd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUNBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUlBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUJCMko0Q0M2QUl5Zi8vL3pZQUFBQTNQRm9BVzhOQkF0dVdPdTVGbHBMK2ZCVXFEeUlOOFJlYyt2Ly9Zd1VBQUdRVjJBalUzN2VWU0lPUEU2eDBMOXpMcGdpcnN3UG1FbmZXOHYrSUtRMEFpZTB4bUhxL0Yzd2JTb1gwNzV3SldqaksvQ1RWQmN4bWpSajhpeVRuQTNUQms3emJTMVJJKzVaRWxTeExiMCt2VS9DRlozckZjQ2VNeHNIRVpKNnZBNkFaRDRuSXBzYVlFbGJDeGlBUXZJeVpCY21teVlSMVlqb3kySE01dWFtaGdVN1RxRjBoM1NhMWRKN2J4a3FIZ091S0prQy9ta28xOGhyV2xPdlpFY1o3TW5TQTRaZVE2Z1lmZ2NJRDJicVFscHJ0Q0xTbzF3Skczc1FLZW13VlRheXNIRGt1ajJHYjNyMnFzWDMrTFduK1o1SWpkZUtJSTdiMmV6emxrMW5pdGxlWHdZd01BRjNQTEZjK1NVTDcvQVg3TTF6clgyQVA0VytHdzBTZUloWncxcVR4YUsvTWpnTk45cTF5U0ZlenY0YWZuMWRjUkFLSHJBaWNwRjFwaEkyV25uR21tNlRCdCt6WnRBUXFXa3p6eHJma1NUOC9Vb3BhK2IvL2FDdlplcU1PaGFieXJ4QnRTZVE3Z2F6bFpEVGRlQnl3enljYXU3UElFc3FFZmttZjNLNStBQ0tqeGJPRnNaZlB1VmV3NXNIbVFITVBGZzA5TWtIMlZsck5YMFR6R0VvTnIwY2ZrVmlNYkwyOTZJZmVUU3ZPUGMzN1ljdmdpQ1dyQzdKTTM2d0hWRTVPK1YyMjNZOFZlbVNOYk5UWXhZTVMzUnR0RU5EQ3JESDA0SS9XU25YeWFIbEFBeFZ6c0lpdERzaTNVTjd6MHYzT3RUR214QTVycmlrVGZkTUNPRFVJekR1ZlJKNi9hR2U0UWlvNVBWZDlWSFFRUHZkdWlUcnpWZlRqWC9EL3hERy9yS1NxOXdWWXB5UEZWd0d2ekRjUTE3NXp2cUEvbHZkeE5jTFFnWnVMWms4OEtKSGorWkpkR2RDTENLL3pEQzZpd2xjM3pXemdjUnBkT0xzYjRqUHJCOXhGcHc2cCtOaCtIK1BqNnhwWTd5L2ZDOWx6ZERibW05a21WNE5qekltdi92aVp6ZDUvcFlEOU9sUGZ2Wnc1WGhrbHZndHRHVCt2VTlHMXU1TTlPOHB0R1M0L2dFWDNuSm8xQXovRllHLzVaMVRGTkJCSWMremVYQWRKSFFUS2Nab2Nrc0xxSGhrTzh4b09UWHhyNE90NFpKOGJwT0cweWlpdDlCSFZWUDloNmkyVzB2L2JwVEpwRmt6dUhiL3dhVE5aZG5HZG1FOW9EcHpjOThWWmVtYWlFenpCRTBRRDhaRENDUThQbFFBNVQwNW9ubTcyYTZhc3hmbE9XaFJ4OUo3RW5OcEtuSm14Q0hSTi8wUEpWK3UyRlhGMDhPYStIU2tQVmsyS0VBUTdnS083QytiRGVOWVlzSktwaEIzVGg3WVBjT3FpV1grV25IRkw2dkszZzJEckpiSWQ4MlBCU3RyWjlRV3lUSzFXL1dZNU1KUWZ2eFNvUXZncEh3K1h2ZWloeVlZWVpldVJ0RGtvM2xDbmRhUFpZSkp4aTlGSmliMGFjUlF0ZWRQUWJ0dXRyQkpHdm5nRnFyVkhqZE1LZHcwUkNObU9iVDZXak9mYjQ3Tzgvc0pnRTZTYjVuRHVzTWVWQlA1RmhnUVJCRGtpOElYQVRCVnBaWFFkaFZFOEl3NDdkRUozdU9BbG9leWtJZWkvVVNrVEJqZ1dCMVVwWDc0Sm9jSHpXODVSVUJxUW1MUW1zTTVqYW5XNGdvdGhNOEpjQUVINHBnSUxvQWhXVlZWVi8vLy8vNm1TcWFxc3d0TTNyanJCV3dXUUppSXcvbWpHakcrZVFvUTBTSU93RXp1eGozWkFHakJ2Q3dIalVvRjJHWnRrL2FuV3Z4RDZBZEpTNGo4R0Nwd2FaVVg3LzNHQWd5cFEyS0tvcUhIc1hWM0t0SU8wZTlJSTRHUW5BNkIxcThMM1FDbklCN1hkaWIraEtNTzFGeUdnV29QeFRpZ0hPMXNIU3pORjF6UFByK2VNSWtWb3gwUFJTVnRaZHpzNkRMS0t6WFcyTEpFdU1QUU53RDRvNS94SkxNb1VyQ1ErS0xJQUVzT2VxdVNtaDBQV1VxTWlFT2ZPcmd6OVRlZkhDTVpFWldJNVdCSnFCRWtzM3E2TlY3REh0S0ZzM1Y5eWJDSllWQmRKRjAvS2xkcm1xWVNKWEEyRVRjZVVsSjliMm9yYSs2b3hKWjI0ZjVnN2l5dEdJeWxaVklMdU5oZk1uQWtHMmF5MTJtN0hlZmdCTjZCVTN0a282Z1RtVEtQSnRMbm9US1pCTnB6U09CNDBhVWRBc3VnQnA4NjVkc3Mya3Y1T09UYmxWVUhHbDJWZ1dLUkNGN1V0NzEwb0tDWmQzdEFNaWREaWg2b2wzTmt3bmUzVmE4VFRGNnI4a0JZd2hWVVlZQXphcWpkWU92dGpEZ1BicXZVNnRVbFFBbmxwcFVKZ1M3ZC9Pd0gzeUFPem1lSjE5Skpkei9CZ1k2L04xaUpsQkJ5NUFKRGI1WjhydWZKNkJId0kxZFJSMWU0a014dmZTZFc5Smpsb3ZlY0VwNFNtN2Z4dWVWOWZ4dTk0VW9uemlxRHNRN2lBbDg2TERmZWZ4aXFFdERhQTViRlB1aFFiRDRlRGxGa2wxcEpTcUNFZUJ4OUdZcHByR2J3Q1VxTGlIbG5jYWVIOE5Ua3VqaVo5VFQ0a2tkcDF5VlNHU1lzZWNCL3Y2RnJLUlBkY3I5RHgvVC8vcVFLUEtLT0ptVUJ4d1JvdTVScTljZEtOZSt3K3c2NXpraXlGdkpZd1JKTXNqeTYxaGtQbGpaQjBRL0VqZnJjL1VUelgrbEhTeXpmOVFPbkRrSzl0K1RPVUpTNWN6Q0RCUlBUOVMvTStQaitGY2JVTjUvRFJWS0VVRkJGQXM1RFFCSUJJZ0hDZWxjdHMyU0dwMW00RWV6L2IxdkkwTXNWL0J4NVhNMFlDVUpSQWxWa1dHejVSdndHMFRuZkNram1BdUF4Umx3WFRmTjhvWXVlUlhITzFINit2Wi9PUC9mdUs1TEZ0dmhERmpZNEhvWm1wZVpFVGNENUV5WWgrSG5aUlJZRWlpUXZIalhUcEk5S0RrVFI3NGJnM2pTQTBESXdvRWpOWWtnN0Q1U1hWUHVVWHljb2JhUDlJcCtiSWgwZ1dmM05FRmJ2QXZZNmVhait3ZitSMGFJRldYbytDZmJqdll5QWgzek5NcGh3RkhqSlBNTU9HcjEwMElLd0xZMTNubFpIbU8xL3grVzRxQWNWMFU2akRHZjFNTzV2L2ZGWCtmeDN4RjdTODZGK2pjclZjR0xsYXBMaDUvZjc3N1VzR1QvdEpmdFk4ajdheVQ0UU54OEJoeE1OdG0zVzdGSXdxUE1PcDZPVHRRZFdpd3I2czU0M0RzYnh1dGEwQ2UrQkpPTktNMWRCWVBTMTZnbDdkWDFCa3BNMXdoVUpFLzNJQitCcVg0RzNkT1B3dVhFbTVLL0NMbEdNZGN1UVdSdHlnbVFZRHVOZWF1QU5TT2RUODdja3VMd1ptWENnSHE3cnRWcVZub3RCTFdHVWNjRElrYzFCTXRLUUEvNTNuaFlVSDcrMlk3NTNFUjNlRE9NSW5iRFlXc3hSRU0xSlUwMGRESVY0QVFaaXZBZ3VBQWdDQVFNQWdvR0RnRUpCUTBEQ3djUEFJaUVqSUtLaG82QmlZV05nNHVIajRCSVJFeENTa1pPUVVsRlRVTkxSMDlBeU1UTXdzckd6c0hKeGMzRHk4ZlB3Q2drTENJcUppNGhLU1V0SXlzbkx5Q29wS3lpcXFhdW9hbWxyYU9ycDYrZ2FHUnNZbXBtYm1GcFpXMWphMmR2WU9qazdPTHE1dTdoNmVYdDQrdm43K0FZRkJ3U0doWWVFUmtWSFJNYkZ4OFFtSlNja3BxV25wR1psWjJUbTVlZmtGaFVYRkphVmw1UldWVmRVMXRYWDFEWTFOelMydGJlMGRuVjNkUGIxOS9RT0RROE1qbzJQakU1TlQwek96Yy9NTGkwdkxLNnRyNnh1Ylc5czd1M3Y3QjRkSHh5ZW5aK2NYbDFmWE43ZDM5dytQVDg4dnIyL3ZINTlmM3orL2YvOEFRZGpQQWd1UUFSWU1VLzJRaDdOYzlmOTJtV2Y4RjNqQm9Uc1V4NVZQRlVmbjBQUE5hcTd3UVBUYkljeHV6dTExK3d1ZVFYY0JFbkVpNXd6Vms2eTZqdjBZZVJwaklvek9KUWRYRTE5WjNaUlJRRkFwV0t4UndGa0FyVCtNSEE1cW9naFEvRDY4Qy8zL0FnQUFBQWwyQWdBTXhBc0E5T3U2V01kVFY1aElYMFZYVW5CVFdNNTNiZXhXb3BjYUIxeVQ1SUQ2dzE3MkZRQkI2TkFDQzVBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEvZjhDQUFBQUNYWUNBQXpFQ3dEMDY3cFl4MU5YbUVoZlJWZFNjRk5Zem5kdDdGYWlseG9IWEpQa2dQckRYdllWQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFSDQwUUlMb0FJUUNwUUNvby95OVJxV3RJY20rL1d6Z09VcVByV1RxS0hwcmp3YW5abVVtR3MyWXhoanQyZHYxN3hRUTVLUmdRVUc5aU9lZGNDcHBjTmd6YnlkeGFDcUJuaUc0aGgrc1R0bnMwR0Z6TFlhRzBlRkZmSU83YmJDOCsxZ2N3a3FraEZLVEVsZytBcHpURnFjTmw0ZitueFpXbU1LcW15RjV1ZGZTUTF1NmJYdnU2SWw3L0IxcWRNSDVkcUFmbzc5Z3dCZHNHVGZrdnpBcmR4aEZDc0tKNm9Zb092a08ycXNyWVk2b3ozSlRseEplZTNLUEtSUVdCZm44aHZlWTZIQ0t3djkvd0lBQUFBSmRnSUFETVFMQVBUcnVsakhVMWVZU0Y5RlYxSndVMWpPZDIzc1ZxS1hHZ2RjaytTQStzTmU5aFVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFaalVBZ3VnQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUDMvQWdBQUFBbDJBZ0FNeEFzQTlPdTZXTWRUVjVoSVgwVlhVbkJUV001M2JleFdvcGNhQjF5VDVJRDZ3MTcyRlFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQnVOWUNDOEFFL2Y4Q0FBQUFDWFlDQUF6RUN3RDA2N3BZeDFOWG1FaGZSVmRTY0ZOWXpuZHQ3RmFpbHhvSFhKUGtnUHJEWHZZVkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVINDJnSUxZUDMvQWdBQUFBbDJBZ0FNeEFzQTlPdTZXTWRUVjVoSVgwVlhVbkJUV001M2JleFdvcGNhQjF5VDVJRDZ3MTcyRmYzL0FnQUFBQWwyQWdBTXhBc0E5T3U2V01kVFY1aElYMFZYVW5CVFdNNTNiZXhXb3BjYUIxeVQ1SUQ2dzE3MkZRQkJ5SndEQzZBQ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFSG9uZ01Mb0FJQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFZaThBd3VnQWdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQnFOQURDMEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUFBQUFBQUFBQkFBQUJBQUVCQUVHSS9nUUxZUDMvQWdBQUFBbDJBZ0FNeEFzQTlPdTZXTWRUVjVoSVgwVlhVbkJUV001M2JleFdvcGNhQjF5VDVJRDZ3MTcyRlFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkI2UDRFQzJEOS93SUFBQUFKZGdJQURNUUxBUFRydWxqSFUxZVlTRjlGVjFKd1Uxak9kMjNzVnFLWEdnZGNrK1NBK3NOZTloVUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUWNqL0JBdGcvZjhDQUFBQUNYWUNBQXpFQ3dEMDY3cFl4MU5YbUVoZlJWZFNjRk5Zem5kdDdGYWlseG9IWEpQa2dQckRYdllWQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFR29nQVVMWVAzL0FnQUFBQWwyQWdBTXhBc0E5T3U2V01kVFY1aElYMFZYVW5CVFdNNTNiZXhXb3BjYUIxeVQ1SUQ2dzE3MkZRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCaUlFRkMyRDkvd0lBQUFBSmRnSUFETVFMQVBUcnVsakhVMWVZU0Y5RlYxSndVMWpPZDIzc1ZxS1hHZ2RjaytTQStzTmU5aFVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFlaUJCUXRnL2Y4Q0FBQUFDWFlDQUF6RUN3RDA2N3BZeDFOWG1FaGZSVmRTY0ZOWXpuZHQ3RmFpbHhvSFhKUGtnUHJEWHZZVkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhJZ2dVTFlQMy9BZ0FBQUFsMkFnQU14QXNBOU91NldNZFRWNWhJWDBWWFVuQlRXTTUzYmV4V29wY2FCMXlUNUlENncxNzJGUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQnFJTUZDMkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCeDhIR0c1TWtEemRLbHpSOUdJcXRkbFJ1RjA2OUNjRmlleTdvQnZnNjJqdEpRMElOdWZma0RRWWRqVkdVZzhCZ0FRWWlFQlF0Z3cwVjFodVRKRFluVnBZVXlVeUx6S2l4K216Qm1DSWhRSkJDSWZvd2JEYUpva052aVQvRGtGRHFGWkJVL2JlVVVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVIb2hBVUxZR1hVR2JOU2xRZ0hFNE1LdFpKZmFjYVBJaGZSekR6b2wrNHAzTExLcmx1alRjNnFYZXFUNHh6clp2dXdEeUx5Q0ViVzVVeXRhdmF5N0h4Si9HdWdRbGlVMDVrbDFKVkl6OURvcUVDNm5CdkJpZDZnNWNzVE9DNnZmNFNJMnU4T0VRQkJ5SVVGQzJEYUQ2TmFvcWZQZTN4K2tpckIzaGZjOGI1T2E5aU5DQytuMUhUYWh5REswUjI4enBabVdhSXQwb2Y5dSsxK0t3N2FENk5hb3FmUGUzeCtraXJCM2hmYzhiNU9hOWlOQ0MrbjFIVGFoeURLMFIyOHpwWm1XYUl0MG9mOXUrMStLdzRBUWFpR0JRdGdQK1M4RGZVODJJS1BBWjNmVXo2Qm9vSGhaVHlseXZER2xmNVFqVkxQSlhWcmlubjBVTzJGU3IzdStHejlvQjBYYk1aQzhnckRKamR3L3JiUnFzRXFmS0lVUzdyN0IwQ2dLUlEwWmpKOFVlOXJJdEpPWmJxVkFOMzNoc3pzY09NQ0FFR0lod1VMWVAzL0FnQUFBQWwyQWdBTXhBc0E5T3U2V01kVFY1aElYMFZYVW5CVFdNNTNiZXhXb3BjYUIxeVQ1SUQ2dzE3MkZRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCNkljRkMyRG9aSXA1R3pieE1DcGF6bjZyM2JqejkzY1Z4anJLcUJhYkF2MTArQzlxd200Y2NHQm10elkyWUdFYkpLdWtHd1VBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFjaUlCUXRnY2ZCeGh1VEpBODNTcGMwZlJpS3JYWlViaGRPdlFuQlluc3U2QWI0T3RvN1NVTkNEYm4zNUEwR0hZMVJsSVBBWUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUdvaVFVTFlEcTZqWGtiTnZ2c0xGcUdrYmpkQU1HTzJpc2o4WS9BRGlGSHl2SEdQTUhWQkZ4N3YwY3FJa2RaWHh6bGhQRVFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQmlJb0ZDMkN1cXZ6Ly8vLzFRLzMvUiszeS83Y3lhWjNwb2trNjZBZDZ1ektETWZPbzdHbkE5S0FlalJUdkJnTC9QaWF6Q2dRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRZWlLQlF0Z3cwVjFodVRKRFluVnBZVXlVeUx6S2l4K216Qm1DSWhRSkJDSWZvd2JEYUpva052aVQvRGtGRHFGWkJVL2JlVVVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVISWl3VUxZUDMvQWdBQUFBbDJBZ0FNeEFzQTlPdTZXTWRUVjVoSVgwVlhVbkJUV001M2JleFdvcGNhQjF5VDVJRDZ3MTcyRlFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJxSXdGQzJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRDkvd0lBQUFBSmRnSUFETVFMQVBUcnVsakhVMWVZU0Y5RlYxSndVMWpPZDIzc1ZxS1hHZ2RjaytTQStzTmU5aFVBUVlpTkJRdGdycXI4Ly8vLzlVUDkvMGZ0OHYrM01tbWQ2YUpKT3VnSGVyc3lnekh6cU94cHdQU2dIbzBVN3dZQy96NG1zd29FQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFSG9qUVVMWU5HYVhLVmRXQzgrZzRIQmhqMGhsRUl5TjJLTHlFUW9PQmcrRUJuOUtxMlN1ZkI4ckU5T2VSM0lYb0o5L0pMVkM5b1BvMXFpcDg5N2ZINlNLc0hlRjl6eHZrNXIySTBJTDZmVWROcUhJTXJSSGJ6T2xtWlpvaTNTaC8yNzdYNHJEZ0JCeUk0RkMyRFJtbHlsWFZndlBvT0J3WVk5SVpSQ01qZGlpOGhFS0RnWVBoQVovU3F0a3Jud2ZLeFBUbmtkeUY2Q2ZmeVMxUXZSbWx5bFhWZ3ZQb09Cd1lZOUlaUkNNamRpaThoRUtEZ1lQaEFaL1NxdGtybndmS3hQVG5rZHlGNkNmZnlTMVFzQVFhaVBCUXRnMmcraldxS256M3Q4ZnBJcXdkNFgzUEcrVG12WWpRZ3ZwOVIwMm9jZ3l0RWR2TTZXWmxtaUxkS0gvYnZ0ZmlzTzBacGNwVjFZTHo2RGdjR0dQU0dVUWpJM1lvdklSQ2c0R0Q0UUdmMHFyWks1OEh5c1QwNTVIY2hlZ24zOGt0VUxBRUdJa0FVTFlQMy9BZ0FBQUFsMkFnQU14QXNBOU91NldNZFRWNWhJWDBWWFVuQlRXTTUzYmV4V29wY2FCMXlUNUlENncxNzJGUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQjZKQUZDMkJ4OEhHRzVNa0R6ZEtselI5R0lxdGRsUnVGMDY5Q2NGaWV5N29Cdmc2Mmp0SlEwSU51ZmZrRFFZZGpWR1VnOEJnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRY2lSQlF0ZzZHU0tlUnMyOFRBcVdzNStxOTI0OC9kM0ZjWTZ5cWdXbXdMOWRQZ3Zhc0p1SEhCZ1pyYzJObUJoR3lTcnBCc0ZBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVHb2tnVUxZT2hraW5rYk52RXdLbHJPZnF2ZHVQUDNkeFhHT3Nxb0Zwc0MvWFQ0TDJyQ2JoeHdZR2EzTmpaZ1lSc2txNlFiQlFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJpSk1GQzJEOS93SUFBQUFKZGdJQURNUUxBUFRydWxqSFUxZVlTRjlGVjFKd1Uxak9kMjNzVnFLWEdnZGNrK1NBK3NOZTloVUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUWVpVEJRdGdjZkJ4aHVUSkE4M1NwYzBmUmlLclhaVWJoZE92UW5CWW5zdTZBYjRPdG83U1VOQ0RibjM1QTBHSFkxUmxJUEFZQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFSElsQVVMWVAzL0FnQUFBQWwyQWdBTXhBc0E5T3U2V01kVFY1aElYMFZYVW5CVFdNNTNiZXhXb3BjYUIxeVQ1SUQ2dzE3MkZRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCcUpVRkMyQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQURvWklwNUd6YnhNQ3Bhem42cjNiano5M2NWeGpyS3FCYWJBdjEwK0M5cXdtNGNjR0JtdHpZMllHRWJKS3VrR3dVQVFZaVdCUXRnT3JxTmVSczIrK3dzV29hUnVOMEF3WTdhS3lQeGo4QU9JVWZLOGNZOHdkVUVYSHUvUnlvaVIxbGZIT1dFOFJBQkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhvbGdVTFlHekdRdklLd3lZM2NQNjIwYXJCS255aUZFdTYrd2RBb0NrVU5HWXlmRkh2YXlMU1RtVzZsUURkOTRiTTdIRGpBai9rdkEzMVBOaUNqd0dkMzFNK2dhS0I0V1U4cGNyd3hwWCtVSTFTenlWMWE0cDU5RkR0aFVxOTd2aHMvYUFkRndCQnlKY0ZDMkRhRDZOYW9xZlBlM3gra2lyQjNoZmM4YjVPYTlpTkNDK24xSFRhaHlESzBSMjh6cFptV2FJdDBvZjl1KzErS3c3YUQ2TmFvcWZQZTN4K2tpckIzaGZjOGI1T2E5aU5DQytuMUhUYWh5REswUjI4enBabVdhSXQwb2Y5dSsxK0t3NEFRYWlZQlF0Z1J0YmxUSzFxOXJMc2ZFbjhhNkJDV0pUVG1TWFVsVWpQME9pb1FMcWNHOEdKM3FEbHl4TTRMcTkvaElqYTd3NFJaZFFaczFLVkNBY1Rnd3Exa2w5cHhvOGlGOUhNUE9pWDdpbmNzc3F1VzZOTnpxcGQ2cFBqSE90bSs3QVBJdklJQUVHSW1RVUxZUDMvQWdBQUFBbDJBZ0FNeEFzQTlPdTZXTWRUVjVoSVgwVlhVbkJUV001M2JleFdvcGNhQjF5VDVJRDZ3MTcyRlFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkI2SmtGQzJEOS93SUFBQUFKZGdJQURNUUxBUFRydWxqSFUxZVlTRjlGVjFKd1Uxak9kMjNzVnFLWEdnZGNrK1NBK3NOZTloVUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUWNpYUJRdGcvZjhDQUFBQUNYWUNBQXpFQ3dEMDY3cFl4MU5YbUVoZlJWZFNjRk5Zem5kdDdGYWlseG9IWEpQa2dQckRYdllWQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFR29td1VMWUs2cS9QLy8vL1ZEL2Y5SDdmTC90ekpwbmVtaVNUcm9CM3E3TW9NeDg2anNhY0Qwb0I2TkZPOEdBdjgrSnJNS0JBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCaUp3RkMyQ3VxdnovLy8vMVEvMy9SKzN5LzdjeWFaM3Bva2s2NkFkNnV6S0RNZk9vN0duQTlLQWVqUlR2QmdML1BpYXpDZ1FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFlaWNCUXRncnFyOC8vLy85VVA5LzBmdDh2KzNNbW1kNmFKSk91Z0hlcnN5Z3pIenFPeHB3UFNnSG8wVTd3WUMvejRtc3dvRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUhJblFVTFlQMy9BZ0FBQUFsMkFnQU14QXNBOU91NldNZFRWNWhJWDBWWFVuQlRXTTUzYmV4V29wY2FCMXlUNUlENncxNzJGUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQnFKNEZDMkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCeDhIR0c1TWtEemRLbHpSOUdJcXRkbFJ1RjA2OUNjRmlleTdvQnZnNjJqdEpRMElOdWZma0RRWWRqVkdVZzhCZ0FRWWlmQlF0Z3cwVjFodVRKRFluVnBZVXlVeUx6S2l4K216Qm1DSWhRSkJDSWZvd2JEYUpva052aVQvRGtGRHFGWkJVL2JlVVVBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVIb253VUxZRWJXNVV5dGF2YXk3SHhKL0d1Z1FsaVUwNWtsMUpWSXo5RG9xRUM2bkJ2QmlkNmc1Y3NUT0M2dmY0U0kydThPRVdYVUdiTlNsUWdIRTRNS3RaSmZhY2FQSWhmUnpEem9sKzRwM0xMS3JsdWpUYzZxWGVxVDR4enJadnV3RHlMeUNBQkJ5S0FGQzJEUm1seWxYVmd2UG9PQndZWTlJWlJDTWpkaWk4aEVLRGdZUGhBWi9TcXRrcm53Zkt4UFRua2R5RjZDZmZ5UzFRdlJtbHlsWFZndlBvT0J3WVk5SVpSQ01qZGlpOGhFS0RnWVBoQVovU3F0a3Jud2ZLeFBUbmtkeUY2Q2ZmeVMxUXNBUWFpaEJRdGdiTVpDOGdyREpqZHcvcmJScXNFcWZLSVVTN3I3QjBDZ0tSUTBaako4VWU5ckl0Sk9aYnFWQU4zM2hzenNjT01DUCtTOERmVTgySUtQQVozZlV6NkJvb0hoWlR5bHl2REdsZjVRalZMUEpYVnJpbm4wVU8yRlNyM3UrR3o5b0IwWEFFR0lvZ1VMWVAzL0FnQUFBQWwyQWdBTXhBc0E5T3U2V01kVFY1aElYMFZYVW5CVFdNNTNiZXhXb3BjYUIxeVQ1SUQ2dzE3MkZRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJCNktJRkMyRG9aSXA1R3pieE1DcGF6bjZyM2JqejkzY1Z4anJLcUJhYkF2MTArQzlxd200Y2NHQm10elkyWUdFYkpLdWtHd1VBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFjaWpCUXRnY2ZCeGh1VEpBODNTcGMwZlJpS3JYWlViaGRPdlFuQlluc3U2QWI0T3RvN1NVTkNEYm4zNUEwR0hZMVJsSVBBWUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUdvcEFVTFlISHdjWWJreVFQTjBxWE5IMFlpcTEyVkc0WFRyMEp3V0o3THVnRytEcmFPMGxEUWcyNTkrUU5CaDJOVVpTRHdHQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQmlLVUZDMkQ5L3dJQUFBQUpkZ0lBRE1RTEFQVHJ1bGpIVTFlWVNGOUZWMUp3VTFqT2QyM3NWcUtYR2dkY2srU0Erc05lOWhVQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFRZWlsQlF0ZzZHU0tlUnMyOFRBcVdzNStxOTI0OC9kM0ZjWTZ5cWdXbXdMOWRQZ3Zhc0p1SEhCZ1pyYzJObUJoR3lTcnBCc0ZBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUVISXBnVUxZUDMvQWdBQUFBbDJBZ0FNeEFzQTlPdTZXTWRUVjVoSVgwVlhVbkJUV001M2JleFdvcGNhQjF5VDVJRDZ3MTcyRlFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJxS2NGQzJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRDkvd0lBQUFBSmRnSUFETVFMQVBUcnVsakhVMWVZU0Y5RlYxSndVMWpPZDIzc1ZxS1hHZ2RjaytTQStzTmU5aFVBUVlpb0JRdGdycXI4Ly8vLzlVUDkvMGZ0OHYrM01tbWQ2YUpKT3VnSGVyc3lnekh6cU94cHdQU2dIbzBVN3dZQy96NG1zd29FQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFSG9xQVVMWU5vUG8xcWlwODk3Zkg2U0tzSGVGOXp4dms1cjJJMElMNmZVZE5xSElNclJIYnpPbG1aWm9pM1NoLzI3N1g0ckR0R2FYS1ZkV0M4K2c0SEJoajBobEVJeU4yS0x5RVFvT0JnK0VCbjlLcTJTdWZCOHJFOU9lUjNJWG9KOS9KTFZDd0JCeUtrRkMyRGFENk5hb3FmUGUzeCtraXJCM2hmYzhiNU9hOWlOQ0MrbjFIVGFoeURLMFIyOHpwWm1XYUl0MG9mOXUrMStLdzdhRDZOYW9xZlBlM3gra2lyQjNoZmM4YjVPYTlpTkNDK24xSFRhaHlESzBSMjh6cFptV2FJdDBvZjl1KzErS3c0QVFhaXFCUXRnMFpwY3BWMVlMejZEZ2NHR1BTR1VRakkzWW92SVJDZzRHRDRRR2YwcXJaSzU4SHlzVDA1NUhjaGVnbjM4a3RVTDJnK2pXcUtuejN0OGZwSXF3ZDRYM1BHK1RtdllqUWd2cDlSMDJvY2d5dEVkdk02V1psbWlMZEtIL2J2dGZpc09BRUdJcXdVTE1ISHdjWWJreVFQTjBxWE5IMFlpcTEyVkc0WFRyMEp3V0o3THVnRytEcmFPMGxEUWcyNTkrUU5CaDJOVVpTRHdHQUJCdUtzRkN6RG9aSXA1R3pieE1DcGF6bjZyM2JqejkzY1Z4anJLcUJhYkF2MTArQzlxd200Y2NHQm10elkyWUdFYkpLdWtHd1VBUWVpckJRc1FWVlZWVlFBQUFBQlc0VlZWQUl4c09RQkJ5SzRGQzJCVVZRRUFBQUFFR0FFQXNEb0ZBRkNGYnljOEpYeTFQR01DdGVzeDdORWlicUpNMGZJbVlaSFRsbVVBR2xlNCt4ZFhWZjcvLy8vNm9mNy9vM2I1LzF1WnRNNTAwU1FkOUFPOVhabkJtSGxVOWpSZ2VsQ1BSb3AzQTRGL0g1TlpCUUlBUWFpdkJRc3djZkJ4aHVUSkE4M1NwYzBmUmlLclhaVWJoZE92UW5CWW5zdTZBYjRPdG83U1VOQ0RibjM1QTBHSFkxUmxJUEFZQUVIWXJ3VUxZTkdhWEtWZFdDOCtnNEhCaGowaGxFSXlOMktMeUVRb09CZytFQm45S3EyU3VmQjhyRTlPZVIzSVhvSjkvSkxWQzlHYVhLVmRXQzgrZzRIQmhqMGhsRUl5TjJLTHlFUW9PQmcrRUJuOUtxMlN1ZkI4ckU5T2VSM0lYb0o5L0pMVkN3QkJ1TEFGQ3dnQUFBRUFBQUFCMGdCQjhNVUZDNkFFRUhYMVhiVzV2TUFrKzR2bU1JYjVKWW4wMWZ2SSt3WkVvSkVoMFpHRUw0NXBnRzhLWlhHZFBvQ3JUQjBCTDJ3aUdaRklGMGQ4OW1mWGtvWFlHNGcvcngwVzB1NmU1R2NhR0xLdWFYaU10K1c4ZXo4RUZKTlQ5cTRhY1BJM0pmWnpLaTFpNlJESjhhL1VxY3FTTkRHRFloazlxTDdDUGk4dWM2b3ZzSi9ueDZUaEc1YlhmMk5KYkVWM2dlamNpdWdJRjVrNU5uby8zalUybkhVeGZKOGRuTEFncUU3Q0U1NzZmVmNEcEVkcHhUKzN6bHo4M0xiQnBLYThabkEyZ2IwYmRTZkdDKytqR0FRUTRQbXBjWnUvU1JjTHRuMEprUkpSSEk4dzVjWkZnMG5DMTYyZHNTT0liU3lWVnRYdFRBQ1NsZkUrd0Q3c2EweXQ1a3dFSUswZkNvMlVGYzBKTVYzRjBBcy9MTUJHVHpNNVY4QTA2MkphTzZWMkZoMUJPRVZ5TkRSRzBGb2JlaElwQVZ2SXhYU2tZVjZXNzRZb2p2eU5ReEtmUmU4dlU1WVNCTUhOYVhIdVFDcXlTN2VPcGtDY0MwMW85SkNIRVNVZndOVElrOEpyV1JJU1lTZC9nMlFRNU4wa3Z4RDdmd2Z6QVN2TkMxZWZ4Sk5HTjB6eVd3d2F0anJIbXpXbERUWGRyTmZra3cxbjBsYTJHbTY0bVpEVERTdU9sMGlCTWhtSURtczRGUFFUc2FTYURXUGkzS0FIR0ROMWs3dm5KNmx2UmttdGFLcEg0L1RxYnhEVzBBb2NEdzg2LzRQdWNzaGNnMkNtdVVOT0I1cnV6K24xMzZyQXFhM2V4NHlPYVRBc1B6V3JkamNIMFVNNjNMb1hoWVFYcVJTTlA2RzZZM1BRQjBWOVAzdVgxSk1CN29rS0hHcEp3S205NGJjbHlOeTFIZTRDQUFBQUFBQkJrTkFGQzBFQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUJBQUFCQVA4QUFRPT1cIjtcbmNvbnN0IHBxID0gNzEyO1xuY29uc3QgcHIgPSAzNDY0O1xuY29uc3QgcEcxZ2VuID0gNDI5Njg7XG5jb25zdCBwRzF6ZXJvID0gNDMxMTI7XG5jb25zdCBwRzFiID0gNDc3NjtcbmNvbnN0IHBHMmdlbiA9IDQzMjU2O1xuY29uc3QgcEcyemVybyA9IDQzNTQ0O1xuY29uc3QgcEcyYiA9IDE3MjcyO1xuY29uc3QgcE9uZVQgPSA0MzgzMjtcbmNvbnN0IHByZVBTaXplID0gMjg4O1xuY29uc3QgcHJlUVNpemUgPSAyMDQ0ODtcbmNvbnN0IHEgPSBcIjQwMDI0MDk1NTUyMjE2NjczOTM0MTc3ODk4MjU3MzU5MDQxNTY1NTY4ODI4MTk5MzkwMDc4ODUzMzIwNTgxMzYxMjQwMzE2NTA0OTA4Mzc4NjQ0NDI2ODc2MjkxMjkwMTU2NjQwMzc4OTQyNzI1NTk3ODdcIjtcbmNvbnN0IHIgPSBcIjUyNDM1ODc1MTc1MTI2MTkwNDc5NDQ3NzQwNTA4MTg1OTY1ODM3NjkwNTUyNTAwNTI3NjM3ODIyNjAzNjU4Njk5OTM4NTgxMTg0NTEzXCI7XG5cbi8vIE1vZHVsZS1sb2NhbCBzaW5nbGV0b24gY2FjaGUuIE11c3QgTk9UIGJlIG9uIGdsb2JhbFRoaXM6IGFzc2lnbmluZyB0byBhIGZyb3plblxuLy8gZ2xvYmFsVGhpcyAoZS5nLiBhIFNFUyBoYXJkZW5lZC1wcm9maWxlIHJlYWxtKSB0aHJvd3MgYXQgbW9kdWxlIGxvYWQuXG5sZXQgY3VydmVfYmxzMTIzODEgPSBudWxsO1xuXG5hc3luYyBmdW5jdGlvbiBidWlsZEJsczEyMzgxKHNpbmdsZVRocmVhZCwgcGx1Z2lucykge1xuICAgIGlmICgoIXNpbmdsZVRocmVhZCkgJiYgKGN1cnZlX2JsczEyMzgxKSkgcmV0dXJuIGN1cnZlX2JsczEyMzgxO1xuXG4gICAgY29uc3QgYmxzMTIzODF3YXNtID0ge307XG5cbiAgICBpZiAoIXBsdWdpbnMpIHtcbiAgICAgICAgLy8gVmVuZG9yZWQsIHVuY29tcHJlc3NlZCBwcmVidWlsdCB3YXNtOiBzdGF0aWMgaW1wb3J0IChubyBydW50aW1lXG4gICAgICAgIC8vIHdhc21jdXJ2ZXMgZGVwZW5kZW5jeSwgbm8gZHluYW1pYyBpbXBvcnQpIGFuZCBiYXNlNjQtZGVjb2RlZCB3aXRob3V0XG4gICAgICAgIC8vIGF0b2IvRGVjb21wcmVzc2lvblN0cmVhbSwgc28gaXQgbG9hZHMgaW4gTm9kZSwgYnJvd3NlcnMgYW5kIFNFU1xuICAgICAgICAvLyBoYXJkZW5lZCByZWFsbXMgYWxpa2UuIEFsc28gYXZvaWRzIHJlY29tcGlsaW5nIHRoZSB3YXNtIG9uIGV2ZXJ5IGxvYWQuXG4gICAgICAgIC8vIFJlZ2VuZXJhdGUgdGhlIHZlbmRvcmVkIG1vZHVsZSB3aXRoIGBucG0gcnVuIGdlbi13YXNtYC5cbiAgICAgICAgYmxzMTIzODF3YXNtLmNvZGUgPSBiYXNlNjRUb1VpbnQ4QXJyYXkoY29kZSk7XG4gICAgICAgIGJsczEyMzgxd2FzbS5wcSA9IHBxO1xuICAgICAgICBibHMxMjM4MXdhc20ucHIgPSBwcjtcbiAgICAgICAgYmxzMTIzODF3YXNtLnBHMWdlbiA9IHBHMWdlbjtcbiAgICAgICAgYmxzMTIzODF3YXNtLnBHMXplcm8gPSBwRzF6ZXJvO1xuICAgICAgICBibHMxMjM4MXdhc20ucEcxYiA9IHBHMWI7XG4gICAgICAgIGJsczEyMzgxd2FzbS5wRzJnZW4gPSBwRzJnZW47XG4gICAgICAgIGJsczEyMzgxd2FzbS5wRzJ6ZXJvID0gcEcyemVybztcbiAgICAgICAgYmxzMTIzODF3YXNtLnBHMmIgPSBwRzJiO1xuICAgICAgICBibHMxMjM4MXdhc20ucE9uZVQgPSBwT25lVDtcbiAgICAgICAgYmxzMTIzODF3YXNtLnByZVBTaXplID0gcHJlUFNpemU7XG4gICAgICAgIGJsczEyMzgxd2FzbS5wcmVRU2l6ZSA9IHByZVFTaXplO1xuICAgICAgICBibHMxMjM4MXdhc20ubjhxID0gNDg7XG4gICAgICAgIGJsczEyMzgxd2FzbS5uOHIgPSAzMjtcbiAgICAgICAgYmxzMTIzODF3YXNtLnEgPSBxO1xuICAgICAgICBibHMxMjM4MXdhc20uciA9IHI7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQ3VzdG9tLXBsdWdpbiBidWlsZCBwYXRoOiBidWlsZHMgdGhlIHdhc20gYXQgcnVudGltZSwgc28gaXQgbmVlZHMgdGhlXG4gICAgICAgIC8vIHdhc20gdG9vbGNoYWluLiBLZXB0IGFzIGEgZHluYW1pYyBpbXBvcnQgc28gd2FzbWJ1aWxkZXIvd2FzbWN1cnZlcyBzdGF5XG4gICAgICAgIC8vIE9QVElPTkFMIGRlcGVuZGVuY2llcyAob25seSByZXF1aXJlZCB3aGVuIGEgY2FsbGVyIHBhc3NlcyBgcGx1Z2luc2ApLlxuICAgICAgICBjb25zdCB7IE1vZHVsZUJ1aWxkZXIgfSA9IGF3YWl0IGltcG9ydCgnd2FzbWJ1aWxkZXInKTtcbiAgICAgICAgY29uc3QgeyBidWlsZEJsczEyMzgxOiBidWlsZEJsczEyMzgxd2FzbSB9ID0gYXdhaXQgaW1wb3J0KCd3YXNtY3VydmVzJyk7XG5cbiAgICAgICAgY29uc3QgbW9kdWxlQnVpbGRlciA9IG5ldyBNb2R1bGVCdWlsZGVyKCk7XG4gICAgICAgIG1vZHVsZUJ1aWxkZXIuc2V0TWVtb3J5KDI1KTtcbiAgICAgICAgYnVpbGRCbHMxMjM4MXdhc20obW9kdWxlQnVpbGRlcik7XG5cbiAgICAgICAgaWYgKHBsdWdpbnMpIHBsdWdpbnMobW9kdWxlQnVpbGRlcik7XG5cbiAgICAgICAgYmxzMTIzODF3YXNtLmNvZGUgPSBtb2R1bGVCdWlsZGVyLmJ1aWxkKCk7XG4gICAgICAgIGJsczEyMzgxd2FzbS5wcSA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5mMW0ucHE7XG4gICAgICAgIGJsczEyMzgxd2FzbS5wciA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5mcm0ucHE7XG4gICAgICAgIGJsczEyMzgxd2FzbS5wRzFnZW4gPSBtb2R1bGVCdWlsZGVyLm1vZHVsZXMuYmxzMTIzODEucEcxZ2VuO1xuICAgICAgICBibHMxMjM4MXdhc20ucEcxemVybyA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5ibHMxMjM4MS5wRzF6ZXJvO1xuICAgICAgICBibHMxMjM4MXdhc20ucEcxYiA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5ibHMxMjM4MS5wRzFiO1xuICAgICAgICBibHMxMjM4MXdhc20ucEcyZ2VuID0gbW9kdWxlQnVpbGRlci5tb2R1bGVzLmJsczEyMzgxLnBHMmdlbjtcbiAgICAgICAgYmxzMTIzODF3YXNtLnBHMnplcm8gPSBtb2R1bGVCdWlsZGVyLm1vZHVsZXMuYmxzMTIzODEucEcyemVybztcbiAgICAgICAgYmxzMTIzODF3YXNtLnBHMmIgPSBtb2R1bGVCdWlsZGVyLm1vZHVsZXMuYmxzMTIzODEucEcyYjtcbiAgICAgICAgYmxzMTIzODF3YXNtLnBPbmVUID0gbW9kdWxlQnVpbGRlci5tb2R1bGVzLmJsczEyMzgxLnBPbmVUO1xuICAgICAgICBibHMxMjM4MXdhc20ucHJlUFNpemUgPSBtb2R1bGVCdWlsZGVyLm1vZHVsZXMuYmxzMTIzODEucHJlUFNpemU7XG4gICAgICAgIGJsczEyMzgxd2FzbS5wcmVRU2l6ZSA9IG1vZHVsZUJ1aWxkZXIubW9kdWxlcy5ibHMxMjM4MS5wcmVRU2l6ZTtcbiAgICAgICAgYmxzMTIzODF3YXNtLm44cSA9IDQ4O1xuICAgICAgICBibHMxMjM4MXdhc20ubjhyID0gMzI7XG4gICAgICAgIGJsczEyMzgxd2FzbS5xID0gbW9kdWxlQnVpbGRlci5tb2R1bGVzLmJsczEyMzgxLnE7XG4gICAgICAgIGJsczEyMzgxd2FzbS5yID0gbW9kdWxlQnVpbGRlci5tb2R1bGVzLmJsczEyMzgxLnI7XG4gICAgfVxuXG5cbiAgICAvLyBCYXRjaC1hZmZpbmUgTVNNIGhlbHBlciBtb2R1bGUgKGN1cnZlLWluZGVwZW5kZW50OyBsaW5rcyBhZ2FpbnN0IHRoZVxuICAgIC8vIG1haW4gbW9kdWxlJ3MgZXhwb3J0cyArIG1lbW9yeSBhdCBydW50aW1lIGluIGVhY2ggd29ya2VyKS5cbiAgICBibHMxMjM4MXdhc20uYmF0Y2hDb2RlID0gYmFzZTY0VG9VaW50OEFycmF5KGNvZGUkMSk7XG4gICAgLy8gVGhlIGJhdGNoIG1vZHVsZSdzIEdMViBwYXRoIGNhcnJpZXMgYmxzMTItMzgxIEcxIGNvbnN0YW50cyB0b28gKEcyIEdMU1xuICAgIC8vIGlzIGJuMjU0LW9ubHk7IHRoZSB3YXNtIGZhbGxzIHRocm91Z2ggaW50ZXJuYWxseSBmb3IgYmxzIEcyIHNpemVzKS5cbiAgICBibHMxMjM4MXdhc20uZ2x2ID0gdHJ1ZTtcblxuICAgIGNvbnN0IHBhcmFtcyA9IHtcbiAgICAgICAgbmFtZTogXCJibHMxMjM4MVwiLFxuICAgICAgICB3YXNtOiBibHMxMjM4MXdhc20sXG4gICAgICAgIHE6IGUoXCIxYTAxMTFlYTM5N2ZlNjlhNGIxYmE3YjY0MzRiYWNkNzY0Nzc0Yjg0ZjM4NTEyYmY2NzMwZDJhMGY2YjBmNjI0MWVhYmZmZmViMTUzZmZmZmI5ZmVmZmZmZmZmZmFhYWJcIiwgMTYpLFxuICAgICAgICByOiBlKFwiNzNlZGE3NTMyOTlkN2Q0ODMzMzlkODA4MDlhMWQ4MDU1M2JkYTQwMmZmZmU1YmZlZmZmZmZmZmYwMDAwMDAwMVwiLCAxNiksXG4gICAgICAgIG44cTogNDgsXG4gICAgICAgIG44cjogMzIsXG4gICAgICAgIGNvZmFjdG9yRzE6IGUoXCIweDM5NmM4YzAwNTU1NWUxNTY4YzAwYWFhYjAwMDBhYWFiXCIsIDE2KSxcbiAgICAgICAgY29mYWN0b3JHMjogZShcIjB4NWQ1NDNhOTU0MTRlN2YxMDkxZDUwNzkyODc2YTIwMmNkOTFkZTQ1NDcwODVhYmFhNjhhMjA1YjJlNWE3ZGRmYTYyOGYxY2I0ZDllODJlZjIxNTM3ZTI5M2E2NjkxYWUxNjE2ZWM2ZTc4NmYwYzcwY2YxYzM4ZTMxYzcyMzhlNVwiLCAxNiksXG4gICAgICAgIHNpbmdsZVRocmVhZDogc2luZ2xlVGhyZWFkID8gdHJ1ZSA6IGZhbHNlXG4gICAgfTtcblxuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgYnVpbGRFbmdpbmUocGFyYW1zKTtcbiAgICBjdXJ2ZS50ZXJtaW5hdGUgPSBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICghcGFyYW1zLnNpbmdsZVRocmVhZCkge1xuICAgICAgICAgICAgY3VydmVfYmxzMTIzODEgPSBudWxsO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy50bS50ZXJtaW5hdGUoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBpZiAoIXNpbmdsZVRocmVhZCkge1xuICAgICAgICBjdXJ2ZV9ibHMxMjM4MSA9IGN1cnZlO1xuICAgIH1cblxuICAgIHJldHVybiBjdXJ2ZTtcbn1cblxuY29uc3QgYmxzMTIzODFyID0gZShcIjczZWRhNzUzMjk5ZDdkNDgzMzM5ZDgwODA5YTFkODA1NTNiZGE0MDJmZmZlNWJmZWZmZmZmZmZmMDAwMDAwMDFcIiwgMTYpO1xuY29uc3QgYm4xMjhyID0gZShcIjIxODg4MjQyODcxODM5Mjc1MjIyMjQ2NDA1NzQ1MjU3Mjc1MDg4NTQ4MzY0NDAwNDE2MDM0MzQzNjk4MjA0MTg2NTc1ODA4NDk1NjE3XCIpO1xuXG5jb25zdCBibHMxMjM4MXEgPSBlKFwiMWEwMTExZWEzOTdmZTY5YTRiMWJhN2I2NDM0YmFjZDc2NDc3NGI4NGYzODUxMmJmNjczMGQyYTBmNmIwZjYyNDFlYWJmZmZlYjE1M2ZmZmZiOWZlZmZmZmZmZmZhYWFiXCIsIDE2KTtcbmNvbnN0IGJuMTI4cSA9IGUoXCIyMTg4ODI0Mjg3MTgzOTI3NTIyMjI0NjQwNTc0NTI1NzI3NTA4ODY5NjMxMTE1NzI5NzgyMzY2MjY4OTAzNzg5NDY0NTIyNjIwODU4M1wiKTtcblxuYXN5bmMgZnVuY3Rpb24gZ2V0Q3VydmVGcm9tUihyLCBzaW5nbGVUaHJlYWQsIHBsdWdpbnMpIHtcbiAgICBsZXQgY3VydmU7XG4gICAgaWYgKGVxKHIsIGJuMTI4cikpIHtcbiAgICAgICAgY3VydmUgPSBhd2FpdCBidWlsZEJuMTI4KHNpbmdsZVRocmVhZCwgcGx1Z2lucyk7XG4gICAgfSBlbHNlIGlmIChlcShyLCBibHMxMjM4MXIpKSB7XG4gICAgICAgIGN1cnZlID0gYXdhaXQgYnVpbGRCbHMxMjM4MShzaW5nbGVUaHJlYWQsIHBsdWdpbnMpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ3VydmUgbm90IHN1cHBvcnRlZDogJHt0b1N0cmluZyhyKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGN1cnZlO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRDdXJ2ZUZyb21RKHEsIHNpbmdsZVRocmVhZCwgcGx1Z2lucykge1xuICAgIGxldCBjdXJ2ZTtcbiAgICBpZiAoZXEocSwgYm4xMjhxKSkge1xuICAgICAgICBjdXJ2ZSA9IGF3YWl0IGJ1aWxkQm4xMjgoc2luZ2xlVGhyZWFkLCBwbHVnaW5zKTtcbiAgICB9IGVsc2UgaWYgKGVxKHEsIGJsczEyMzgxcSkpIHtcbiAgICAgICAgY3VydmUgPSBhd2FpdCBidWlsZEJsczEyMzgxKHNpbmdsZVRocmVhZCwgcGx1Z2lucyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDdXJ2ZSBub3Qgc3VwcG9ydGVkOiAke3RvU3RyaW5nKHEsIDE2KX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGN1cnZlO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRDdXJ2ZUZyb21OYW1lKG5hbWUsIHNpbmdsZVRocmVhZCwgcGx1Z2lucykge1xuICAgIGxldCBjdXJ2ZTtcbiAgICBjb25zdCBub3JtTmFtZSA9IG5vcm1hbGl6ZU5hbWUobmFtZSk7XG4gICAgaWYgKFtcIkJOMTI4XCIsIFwiQk4yNTRcIiwgXCJBTFRCTjEyOFwiXS5pbmRleE9mKG5vcm1OYW1lKSA+PSAwKSB7XG4gICAgICAgIGN1cnZlID0gYXdhaXQgYnVpbGRCbjEyOChzaW5nbGVUaHJlYWQsIHBsdWdpbnMpO1xuICAgIH0gZWxzZSBpZiAoW1wiQkxTMTIzODFcIl0uaW5kZXhPZihub3JtTmFtZSkgPj0gMCkge1xuICAgICAgICBjdXJ2ZSA9IGF3YWl0IGJ1aWxkQmxzMTIzODEoc2luZ2xlVGhyZWFkLCBwbHVnaW5zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEN1cnZlIG5vdCBzdXBwb3J0ZWQ6ICR7bmFtZX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGN1cnZlO1xuXG4gICAgZnVuY3Rpb24gbm9ybWFsaXplTmFtZShuKSB7XG4gICAgICAgIHJldHVybiBuLnRvVXBwZXJDYXNlKCkubWF0Y2goL1tBLVphLXowLTldKy9nKS5qb2luKFwiXCIpO1xuICAgIH1cblxufVxuXG5jb25zdCBTY2FsYXI9X1NjYWxhcjtcbmNvbnN0IHV0aWxzID0gX3V0aWxzO1xuXG5leHBvcnQgeyBCaWdCdWZmZXIsIENoYUNoYSwgRUMsIFpxRmllbGQgYXMgRjFGaWVsZCwgRjJGaWVsZCwgRjNGaWVsZCwgUG9sRmllbGQsIFNjYWxhciwgWnFGaWVsZCwgYnVpbGRCbHMxMjM4MSwgYnVpbGRCbjEyOCwgZ2V0Q3VydmVGcm9tTmFtZSwgZ2V0Q3VydmVGcm9tUSwgZ2V0Q3VydmVGcm9tUiwgdXRpbHMgfTtcbiIsIlxuaW1wb3J0IGZzIGZyb21cImZzXCI7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvcGVuKGZpbGVOYW1lLCBvcGVuRmxhZ3MsIGNhY2hlU2l6ZSwgcGFnZVNpemUpIHtcbiAgICBjYWNoZVNpemUgPSBjYWNoZVNpemUgfHwgNDA5Nio2NDtcbiAgICBpZiAodHlwZW9mIG9wZW5GbGFncyAhPT0gXCJudW1iZXJcIiAmJiBbXCJ3K1wiLCBcInd4K1wiLCBcInJcIiwgXCJheCtcIiwgXCJhK1wiXS5pbmRleE9mKG9wZW5GbGFncykgPDApXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgb3BlbiBvcHRpb25cIik7XG4gICAgY29uc3QgZmQgPWF3YWl0IGZzLnByb21pc2VzLm9wZW4oZmlsZU5hbWUsIG9wZW5GbGFncyk7XG5cbiAgICBjb25zdCBzdGF0cyA9IGF3YWl0IGZkLnN0YXQoKTtcblxuICAgIHJldHVybiAgbmV3IEZhc3RGaWxlKGZkLCBzdGF0cywgY2FjaGVTaXplLCBwYWdlU2l6ZSwgZmlsZU5hbWUpO1xufVxuXG5cbmNsYXNzIEZhc3RGaWxlIHtcblxuICAgIGNvbnN0cnVjdG9yKGZkLCBzdGF0cywgY2FjaGVTaXplLCBwYWdlU2l6ZSwgZmlsZU5hbWUpIHtcbiAgICAgICAgdGhpcy5maWxlTmFtZSA9IGZpbGVOYW1lO1xuICAgICAgICB0aGlzLmZkID0gZmQ7XG4gICAgICAgIHRoaXMucG9zID0gMDtcbiAgICAgICAgdGhpcy5wYWdlU2l6ZSA9IHBhZ2VTaXplIHx8ICgxIDw8IDgpO1xuICAgICAgICB3aGlsZSAodGhpcy5wYWdlU2l6ZSA8IHN0YXRzLmJsa3NpemUpIHtcbiAgICAgICAgICAgIHRoaXMucGFnZVNpemUgKj0gMjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnRvdGFsU2l6ZSA9IHN0YXRzLnNpemU7XG4gICAgICAgIHRoaXMudG90YWxQYWdlcyA9IE1hdGguZmxvb3IoKHN0YXRzLnNpemUgLTEpIC8gdGhpcy5wYWdlU2l6ZSkrMTtcbiAgICAgICAgdGhpcy5tYXhQYWdlc0xvYWRlZCA9IE1hdGguZmxvb3IoIGNhY2hlU2l6ZSAvIHRoaXMucGFnZVNpemUpKzE7XG4gICAgICAgIC8vIFJlYWRzL3dyaXRlcyBhdCBsZWFzdCB0aGlzIGxhcmdlIGJ5cGFzcyB0aGUgcGFnZSBjYWNoZSBhbmQgbW92ZSBieXRlc1xuICAgICAgICAvLyBzdHJhaWdodCBiZXR3ZWVuIGRpc2sgYW5kIHRoZSBjYWxsZXIncyBidWZmZXIgKHNlZSByZWFkVG9CdWZmZXIgL1xuICAgICAgICAvLyB3cml0ZSksIGF2b2lkaW5nIHRoZSBleHRyYSBidWZmZXI8LT5wYWdlIGNvcHkgdGhhdCBkb21pbmF0ZXMgbGFyZ2VcbiAgICAgICAgLy8gc2VxdWVudGlhbCB0cmFuc2ZlcnMgKGUuZy4gemtleS9wdGF1IHNlY3Rpb25zKS5cbiAgICAgICAgdGhpcy5kaXJlY3RSZWFkVGhyZXNob2xkID0gMSA8PCAyMDtcbiAgICAgICAgdGhpcy5kaXJlY3RXcml0ZVRocmVzaG9sZCA9IDEgPDwgMjA7XG4gICAgICAgIHRoaXMucGFnZXMgPSB7fTtcbiAgICAgICAgdGhpcy5wZW5kaW5nTG9hZHMgPSBbXTtcbiAgICAgICAgdGhpcy53cml0aW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMucmVhZGluZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmF2QnVmZnMgPSBbXTtcbiAgICAgICAgdGhpcy5oaXN0b3J5ID0ge307XG4gICAgfVxuXG4gICAgX2xvYWRQYWdlKHApIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IFAgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KT0+IHtcbiAgICAgICAgICAgIHNlbGYucGVuZGluZ0xvYWRzLnB1c2goe1xuICAgICAgICAgICAgICAgIHBhZ2U6IHAsXG4gICAgICAgICAgICAgICAgcmVzb2x2ZTogcmVzb2x2ZSxcbiAgICAgICAgICAgICAgICByZWplY3Q6IHJlamVjdFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIExvYWQgcmVxdWVzdDogXCIsIHApO1xuICAgICAgICByZXR1cm4gUDtcbiAgICB9XG5cbiAgICBfX3N0YXR1c1BhZ2UocywgcCkge1xuICAgICAgICBjb25zdCBsb2dFbnRyeSA9IFtdO1xuICAgICAgICBjb25zdCBzZWxmPXRoaXM7XG4gICAgICAgIGlmICghc2VsZi5sb2dIaXN0b3J5KSByZXR1cm47XG4gICAgICAgIGxvZ0VudHJ5LnB1c2goXCI9PVwiICsgcysgXCIgXCIgK3ApO1xuICAgICAgICBsZXQgUyA9IFwiXCI7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxzZWxmLnBlbmRpbmdMb2Fkcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKHNlbGYucGVuZGluZ0xvYWRzW2ldLnBhZ2UgPT0gcCkgUyA9IFMgKyBcIiBcIiArIGk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKFMpIGxvZ0VudHJ5LnB1c2goXCJQZW5kaW5nIGxvYWRzOlwiK1MpO1xuICAgICAgICBpZiAodHlwZW9mIHNlbGYucGFnZXNbcF0gIT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgY29uc3QgcGFnZSA9IHNlbGYucGFnZXNbcF07XG4gICAgICAgICAgICBsb2dFbnRyeS5wdXNoKFwiTG9hZGVkXCIpO1xuICAgICAgICAgICAgbG9nRW50cnkucHVzaChcInBlbmRpbmdPcHM6IFwiK3BhZ2UucGVuZGluZ09wcyk7XG4gICAgICAgICAgICBpZiAocGFnZS5sb2FkaW5nKSBsb2dFbnRyeS5wdXNoKFwibG9hZGluZzogXCIrcGFnZS5sb2FkaW5nKTtcbiAgICAgICAgICAgIGlmIChwYWdlLndyaXRpbmcpIGxvZ0VudHJ5LnB1c2goXCJ3cml0aW5nXCIpO1xuICAgICAgICAgICAgaWYgKHBhZ2UuZGlydHkpIGxvZ0VudHJ5LnB1c2goXCJkaXJ0eVwiKTtcbiAgICAgICAgfVxuICAgICAgICBsb2dFbnRyeS5wdXNoKFwiPT1cIik7XG5cbiAgICAgICAgaWYgKCFzZWxmLmhpc3RvcnlbcF0pIHNlbGYuaGlzdG9yeVtwXSA9IFtdO1xuICAgICAgICBzZWxmLmhpc3RvcnlbcF0ucHVzaChsb2dFbnRyeSk7XG4gICAgfVxuXG4gICAgX19wcmludEhpc3RvcnkocCkge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgaWYgKCFzZWxmLmhpc3RvcnlbcF0pIGNvbnNvbGUubG9nKFwiRW1wdHkgSGlzdG9yeSBcIiwgcCk7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiSGlzdG9yeSBcIitwKTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHNlbGYuaGlzdG9yeVtwXS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgZm9yIChsZXQgaj0wOyBqPHNlbGYuaGlzdG9yeVtwXVtpXS5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiLT4gXCIgKyBzZWxmLmhpc3RvcnlbcF1baV1bal0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG5cblxuICAgIF90cmlnZ2VyTG9hZCgpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgaWYgKHNlbGYucmVhZGluZykgcmV0dXJuO1xuICAgICAgICBpZiAoc2VsZi5wZW5kaW5nTG9hZHMubGVuZ3RoPT0wKSByZXR1cm47XG5cbiAgICAgICAgY29uc3QgcGFnZUlkeHMgPSBPYmplY3Qua2V5cyhzZWxmLnBhZ2VzKTtcblxuICAgICAgICBjb25zdCBkZWxldGFibGVQYWdlcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8cGFnZUlkeHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IHBhZ2UgPSBzZWxmLnBhZ2VzW3BhcnNlSW50KHBhZ2VJZHhzW2ldKV07XG4gICAgICAgICAgICBpZiAoKHBhZ2UuZGlydHkgPT0gZmFsc2UpJiYocGFnZS5wZW5kaW5nT3BzPT0wKSYmKCFwYWdlLndyaXRpbmcpJiYoIXBhZ2UubG9hZGluZykpIGRlbGV0YWJsZVBhZ2VzLnB1c2gocGFyc2VJbnQocGFnZUlkeHNbaV0pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBmcmVlUGFnZXMgPSBzZWxmLm1heFBhZ2VzTG9hZGVkIC0gcGFnZUlkeHMubGVuZ3RoO1xuXG4gICAgICAgIGNvbnN0IG9wcyA9IFtdO1xuXG4gICAgICAgIC8vIHdoaWxlIHBlbmRpbmcgbG9hZHMgYW5kXG4gICAgICAgIC8vICAgICB0aGUgcGFnZSBpcyBsb2FkZWQgb3IgSSBjYW4gcmVjb3ZlciBvbmUuXG4gICAgICAgIHdoaWxlIChcbiAgICAgICAgICAgIChzZWxmLnBlbmRpbmdMb2Fkcy5sZW5ndGg+MCkgJiZcbiAgICAgICAgICAgICggICAodHlwZW9mIHNlbGYucGFnZXNbc2VsZi5wZW5kaW5nTG9hZHNbMF0ucGFnZV0gIT0gXCJ1bmRlZmluZWRcIiApXG4gICAgICAgICAgICAgIHx8KCAgKGZyZWVQYWdlcz4wKVxuICAgICAgICAgICAgICAgICB8fChkZWxldGFibGVQYWdlcy5sZW5ndGg+MCkpKSkge1xuICAgICAgICAgICAgY29uc3QgbG9hZCA9IHNlbGYucGVuZGluZ0xvYWRzLnNoaWZ0KCk7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHNlbGYucGFnZXNbbG9hZC5wYWdlXSAhPSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgc2VsZi5wYWdlc1tsb2FkLnBhZ2VdLnBlbmRpbmdPcHMgKys7XG4gICAgICAgICAgICAgICAgY29uc3QgaWR4ID0gZGVsZXRhYmxlUGFnZXMuaW5kZXhPZihsb2FkLnBhZ2UpO1xuICAgICAgICAgICAgICAgIGlmIChpZHg+PTApIGRlbGV0YWJsZVBhZ2VzLnNwbGljZShpZHgsIDEpO1xuICAgICAgICAgICAgICAgIGlmIChzZWxmLnBhZ2VzW2xvYWQucGFnZV0ubG9hZGluZykge1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnBhZ2VzW2xvYWQucGFnZV0ubG9hZGluZy5wdXNoKGxvYWQpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGxvYWQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIExvYWQgKGNhY2hlZCk6IFwiLCBsb2FkLnBhZ2UpO1xuXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmIChmcmVlUGFnZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgZnJlZVBhZ2VzLS07XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZnAgPSBkZWxldGFibGVQYWdlcy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkJlZm9yZSBVbmxvYWQ6IFwiLCBmcCk7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuYXZCdWZmcy51bnNoaWZ0KHNlbGYucGFnZXNbZnBdKTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHNlbGYucGFnZXNbZnBdO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIFVubG9hZDogXCIsIGZwKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAobG9hZC5wYWdlPj1zZWxmLnRvdGFsUGFnZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5wYWdlc1tsb2FkLnBhZ2VdID0gZ2V0TmV3UGFnZSgpO1xuICAgICAgICAgICAgICAgICAgICBsb2FkLnJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBMb2FkIChuZXcpOiBcIiwgbG9hZC5wYWdlKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnJlYWRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnBhZ2VzW2xvYWQucGFnZV0gPSBnZXROZXdQYWdlKCk7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbbG9hZC5wYWdlXS5sb2FkaW5nID0gW2xvYWRdO1xuICAgICAgICAgICAgICAgICAgICBvcHMucHVzaChzZWxmLmZkLnJlYWQoc2VsZi5wYWdlc1tsb2FkLnBhZ2VdLmJ1ZmYsIDAsIHNlbGYucGFnZVNpemUsIGxvYWQucGFnZSpzZWxmLnBhZ2VTaXplKS50aGVuKChyZXMpPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5wYWdlc1tsb2FkLnBhZ2VdLnNpemUgPSByZXMuYnl0ZXNSZWFkO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbG9hZGluZyA9IHNlbGYucGFnZXNbbG9hZC5wYWdlXS5sb2FkaW5nO1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHNlbGYucGFnZXNbbG9hZC5wYWdlXS5sb2FkaW5nO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpPGxvYWRpbmcubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2FkaW5nW2ldLnJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX19zdGF0dXNQYWdlKFwiQWZ0ZXIgTG9hZCAobG9hZGVkKTogXCIsIGxvYWQucGFnZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgICAgICAgICAgICAgICB9LCAoZXJyKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsb2FkLnJlamVjdChlcnIpO1xuICAgICAgICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuX19zdGF0dXNQYWdlKFwiQWZ0ZXIgTG9hZCAobG9hZGluZyk6IFwiLCBsb2FkLnBhZ2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBpZiAob3BzLmxlbmd0aD4xKSBjb25zb2xlLmxvZyhvcHMubGVuZ3RoKTtcblxuICAgICAgICBQcm9taXNlLmFsbChvcHMpLnRoZW4oICgpID0+IHtcbiAgICAgICAgICAgIHNlbGYucmVhZGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKHNlbGYucGVuZGluZ0xvYWRzLmxlbmd0aD4wKSBzZXRJbW1lZGlhdGUoc2VsZi5fdHJpZ2dlckxvYWQuYmluZChzZWxmKSk7XG4gICAgICAgICAgICBzZWxmLl90cnlDbG9zZSgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBmdW5jdGlvbiBnZXROZXdQYWdlKCkge1xuICAgICAgICAgICAgaWYgKHNlbGYuYXZCdWZmcy5sZW5ndGg+MCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHAgPSBzZWxmLmF2QnVmZnMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICBwLmRpcnR5ID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgcC5wZW5kaW5nT3BzID0gMTtcbiAgICAgICAgICAgICAgICBwLnNpemUgPTA7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHA7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIGRpcnR5OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgYnVmZjogbmV3IFVpbnQ4QXJyYXkoc2VsZi5wYWdlU2l6ZSksXG4gICAgICAgICAgICAgICAgICAgIHBlbmRpbmdPcHM6IDEsXG4gICAgICAgICAgICAgICAgICAgIHNpemU6IDBcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICB9XG5cblxuICAgIF90cmlnZ2VyV3JpdGUoKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBpZiAoc2VsZi53cml0aW5nKSByZXR1cm47XG5cbiAgICAgICAgY29uc3QgcGFnZUlkeHMgPSBPYmplY3Qua2V5cyhzZWxmLnBhZ2VzKTtcblxuICAgICAgICBjb25zdCBvcHMgPSBbXTtcblxuICAgICAgICBmb3IgKGxldCBpPTA7IGk8cGFnZUlkeHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IHBhZ2UgPSBzZWxmLnBhZ2VzW3BhcnNlSW50KHBhZ2VJZHhzW2ldKV07XG4gICAgICAgICAgICBpZiAocGFnZS5kaXJ0eSkge1xuICAgICAgICAgICAgICAgIHBhZ2UuZGlydHkgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBwYWdlLndyaXRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHNlbGYud3JpdGluZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgb3BzLnB1c2goIHNlbGYuZmQud3JpdGUocGFnZS5idWZmLCAwLCBwYWdlLnNpemUsIHBhcnNlSW50KHBhZ2VJZHhzW2ldKSpzZWxmLnBhZ2VTaXplKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgcGFnZS53cml0aW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9LCAoZXJyKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiRVJST1IgV3JpdGluZzogXCIrZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5lcnJvciA9IGVycjtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fdHJ5Q2xvc2UoKTtcbiAgICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc2VsZi53cml0aW5nKSB7XG4gICAgICAgICAgICBQcm9taXNlLmFsbChvcHMpLnRoZW4oICgpID0+IHtcbiAgICAgICAgICAgICAgICBzZWxmLndyaXRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBzZXRJbW1lZGlhdGUoc2VsZi5fdHJpZ2dlcldyaXRlLmJpbmQoc2VsZikpO1xuICAgICAgICAgICAgICAgIHNlbGYuX3RyeUNsb3NlKCk7XG4gICAgICAgICAgICAgICAgaWYgKHNlbGYucGVuZGluZ0xvYWRzLmxlbmd0aD4wKSBzZXRJbW1lZGlhdGUoc2VsZi5fdHJpZ2dlckxvYWQuYmluZChzZWxmKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIF9nZXREaXJ0eVBhZ2UoKSB7XG4gICAgICAgIGZvciAobGV0IHAgaW4gdGhpcy5wYWdlcykge1xuICAgICAgICAgICAgaWYgKHRoaXMucGFnZXNbcF0uZGlydHkpIHJldHVybiBwO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAtMTtcbiAgICB9XG5cbiAgICAvLyBJdGVyYXRlIHRoZSBhY3R1YWxseS1jYWNoZWQgcGFnZXMgKHVzdWFsbHkgZmV3KSByYXRoZXIgdGhhbiBldmVyeSBwYWdlXG4gICAgLy8gaW5kZXggaW4gW2ZpcnN0UGFnZSwgbGFzdFBhZ2VdLCBzbyB0aGUgY2hlY2sgc3RheXMgTyhjYWNoZWQgcGFnZXMpIGV2ZW5cbiAgICAvLyBmb3IgdmVyeSBsYXJnZSByYW5nZXMgLyBzbWFsbCBwYWdlIHNpemVzLlxuICAgIF9yYW5nZUhhc0NhY2hlZFBhZ2VzKHBvcywgbGVuKSB7XG4gICAgICAgIGNvbnN0IGZpcnN0UGFnZSA9IE1hdGguZmxvb3IocG9zIC8gdGhpcy5wYWdlU2l6ZSk7XG4gICAgICAgIGNvbnN0IGxhc3RQYWdlID0gTWF0aC5mbG9vcigocG9zICsgbGVuIC0gMSkgLyB0aGlzLnBhZ2VTaXplKTtcbiAgICAgICAgZm9yIChjb25zdCBrIG9mIE9iamVjdC5rZXlzKHRoaXMucGFnZXMpKSB7XG4gICAgICAgICAgICBjb25zdCBwID0gK2s7XG4gICAgICAgICAgICBpZiAocCA+PSBmaXJzdFBhZ2UgJiYgcCA8PSBsYXN0UGFnZSkgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGFzeW5jIHdyaXRlKGJ1ZmYsIHBvcykge1xuICAgICAgICBpZiAoYnVmZi5ieXRlTGVuZ3RoID09IDApIHJldHVybjtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIpIHBvcyA9IHNlbGYucG9zO1xuICAgICAgICBzZWxmLnBvcyA9IHBvcytidWZmLmJ5dGVMZW5ndGg7XG4gICAgICAgIGlmIChzZWxmLnRvdGFsU2l6ZSA8IHBvcyArIGJ1ZmYuYnl0ZUxlbmd0aCkgc2VsZi50b3RhbFNpemUgPSBwb3MgKyBidWZmLmJ5dGVMZW5ndGg7XG4gICAgICAgIGlmIChzZWxmLnBlbmRpbmdDbG9zZSlcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIldyaXRpbmcgYSBjbG9zaW5nIGZpbGVcIik7XG5cbiAgICAgICAgLy8gRGlyZWN0LXdyaXRlIGZhc3QgcGF0aDogZm9yIGxhcmdlIHdyaXRlcyB0byBhIHJlZ2lvbiB3aXRoIG5vIGNhY2hlZFxuICAgICAgICAvLyBwYWdlcywgd3JpdGUgc3RyYWlnaHQgdG8gZGlzaywgc2tpcHBpbmcgdGhlIGJ1ZmYtPnBhZ2UgY29weSBhbmQgdGhlXG4gICAgICAgIC8vIGRlZmVycmVkIHBhZ2UgZmx1c2guIEFueSBjYWNoZWQgcGFnZSBpbiByYW5nZSAoZXZlbiBjbGVhbikgd291bGQgZ29cbiAgICAgICAgLy8gc3RhbGUgYWZ0ZXIgYSBkaXJlY3Qgd3JpdGUsIHNvIHdlIGZhbGwgYmFjayB0byB0aGUgY2FjaGVkIHBhdGggdGhlbi5cbiAgICAgICAgLy8gQXJyYXlCdWZmZXIuaXNWaWV3IGdhdGU6IGZkLndyaXRlIG5lZWRzIGEgcmVhbCBUeXBlZEFycmF5L0RhdGFWaWV3OyBhXG4gICAgICAgIC8vIEJpZ0J1ZmZlciAocGFnZWQsIG5vdCBhIHZpZXcpIG11c3QgdXNlIHRoZSBjYWNoZWQgcGF0aC5cbiAgICAgICAgaWYgKGJ1ZmYuYnl0ZUxlbmd0aCA+PSBzZWxmLmRpcmVjdFdyaXRlVGhyZXNob2xkICYmIEFycmF5QnVmZmVyLmlzVmlldyhidWZmKSAmJiAhc2VsZi5fcmFuZ2VIYXNDYWNoZWRQYWdlcyhwb3MsIGJ1ZmYuYnl0ZUxlbmd0aCkpIHtcbiAgICAgICAgICAgIGxldCBkb25lID0gMDtcbiAgICAgICAgICAgIHdoaWxlIChkb25lIDwgYnVmZi5ieXRlTGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgeyBieXRlc1dyaXR0ZW4gfSA9IGF3YWl0IHNlbGYuZmQud3JpdGUoYnVmZiwgZG9uZSwgYnVmZi5ieXRlTGVuZ3RoIC0gZG9uZSwgcG9zICsgZG9uZSk7XG4gICAgICAgICAgICAgICAgaWYgKGJ5dGVzV3JpdHRlbiA9PT0gMCkgYnJlYWs7ICAgLy8gc2hvdWxkIG5vdCBoYXBwZW5cbiAgICAgICAgICAgICAgICBkb25lICs9IGJ5dGVzV3JpdHRlbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGxhc3RQYWdlID0gTWF0aC5mbG9vcigocG9zICsgYnVmZi5ieXRlTGVuZ3RoIC0gMSkgLyBzZWxmLnBhZ2VTaXplKTtcbiAgICAgICAgICAgIGlmIChsYXN0UGFnZSArIDEgPiBzZWxmLnRvdGFsUGFnZXMpIHNlbGYudG90YWxQYWdlcyA9IGxhc3RQYWdlICsgMTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGZpcnN0UGFnZSA9IE1hdGguZmxvb3IocG9zIC8gc2VsZi5wYWdlU2l6ZSk7XG4gICAgICAgIGNvbnN0IGxhc3RQYWdlID0gTWF0aC5mbG9vcigocG9zICsgYnVmZi5ieXRlTGVuZ3RoIC0xKSAvIHNlbGYucGFnZVNpemUpO1xuXG4gICAgICAgIGNvbnN0IHBhZ2VQcm9taXNlcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpPWZpcnN0UGFnZTsgaTw9bGFzdFBhZ2U7IGkrKykgcGFnZVByb21pc2VzLnB1c2goc2VsZi5fbG9hZFBhZ2UoaSkpO1xuICAgICAgICBzZWxmLl90cmlnZ2VyTG9hZCgpO1xuXG4gICAgICAgIGxldCBwID0gZmlyc3RQYWdlO1xuICAgICAgICBsZXQgbyA9IHBvcyAlIHNlbGYucGFnZVNpemU7XG4gICAgICAgIGxldCByID0gYnVmZi5ieXRlTGVuZ3RoO1xuICAgICAgICB3aGlsZSAocj4wKSB7XG4gICAgICAgICAgICBhd2FpdCBwYWdlUHJvbWlzZXNbcC1maXJzdFBhZ2VdO1xuICAgICAgICAgICAgY29uc3QgbCA9IChvK3IgPiBzZWxmLnBhZ2VTaXplKSA/IChzZWxmLnBhZ2VTaXplIC1vKSA6IHI7XG4gICAgICAgICAgICBjb25zdCBzcmNWaWV3ID0gYnVmZi5zbGljZSggYnVmZi5ieXRlTGVuZ3RoIC0gciwgYnVmZi5ieXRlTGVuZ3RoIC0gciArIGwpO1xuICAgICAgICAgICAgY29uc3QgZHN0VmlldyA9IG5ldyBVaW50OEFycmF5KHNlbGYucGFnZXNbcF0uYnVmZi5idWZmZXIsIG8sIGwpO1xuICAgICAgICAgICAgZHN0Vmlldy5zZXQoc3JjVmlldyk7XG4gICAgICAgICAgICBzZWxmLnBhZ2VzW3BdLmRpcnR5ID0gdHJ1ZTtcbiAgICAgICAgICAgIHNlbGYucGFnZXNbcF0ucGVuZGluZ09wcyAtLTtcbiAgICAgICAgICAgIHNlbGYucGFnZXNbcF0uc2l6ZSA9IE1hdGgubWF4KG8rbCwgc2VsZi5wYWdlc1twXS5zaXplKTtcbiAgICAgICAgICAgIGlmIChwPj1zZWxmLnRvdGFsUGFnZXMpIHtcbiAgICAgICAgICAgICAgICBzZWxmLnRvdGFsUGFnZXMgPSBwKzE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByID0gci1sO1xuICAgICAgICAgICAgcCArKztcbiAgICAgICAgICAgIG8gPSAwO1xuICAgICAgICAgICAgaWYgKCFzZWxmLndyaXRpbmcpIHNldEltbWVkaWF0ZShzZWxmLl90cmlnZ2VyV3JpdGUuYmluZChzZWxmKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyByZWFkKGxlbiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBsZXQgYnVmZiA9IG5ldyBVaW50OEFycmF5KGxlbik7XG4gICAgICAgIGF3YWl0IHNlbGYucmVhZFRvQnVmZmVyKGJ1ZmYsIDAsIGxlbiwgcG9zKTtcblxuICAgICAgICByZXR1cm4gYnVmZjtcbiAgICB9XG5cbiAgICAvLyBJdGVyYXRlIHRoZSBhY3R1YWxseS1jYWNoZWQgcGFnZXMgKHVzdWFsbHkgZmV3KSByYXRoZXIgdGhhbiBldmVyeSBwYWdlXG4gICAgLy8gaW5kZXggaW4gW2ZpcnN0UGFnZSwgbGFzdFBhZ2VdLCBzbyB0aGUgY2hlY2sgc3RheXMgTyhjYWNoZWQgcGFnZXMpIGV2ZW5cbiAgICAvLyBmb3IgdmVyeSBsYXJnZSByYW5nZXMgLyBzbWFsbCBwYWdlIHNpemVzLlxuICAgIF9yYW5nZUhhc0RpcnR5UGFnZXMocG9zLCBsZW4pIHtcbiAgICAgICAgY29uc3QgZmlyc3RQYWdlID0gTWF0aC5mbG9vcihwb3MgLyB0aGlzLnBhZ2VTaXplKTtcbiAgICAgICAgY29uc3QgbGFzdFBhZ2UgPSBNYXRoLmZsb29yKChwb3MgKyBsZW4gLSAxKSAvIHRoaXMucGFnZVNpemUpO1xuICAgICAgICBmb3IgKGNvbnN0IGsgb2YgT2JqZWN0LmtleXModGhpcy5wYWdlcykpIHtcbiAgICAgICAgICAgIGNvbnN0IHAgPSAraztcbiAgICAgICAgICAgIGlmIChwID49IGZpcnN0UGFnZSAmJiBwIDw9IGxhc3RQYWdlKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGFnZSA9IHRoaXMucGFnZXNbcF07XG4gICAgICAgICAgICAgICAgaWYgKHBhZ2UuZGlydHkgfHwgcGFnZS53cml0aW5nKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFRvQnVmZmVyKGJ1ZmZEc3QsIG9mZnNldCwgbGVuLCBwb3MpIHtcbiAgICAgICAgaWYgKGxlbiA9PSAwKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIpIHBvcyA9IHNlbGYucG9zO1xuICAgICAgICBzZWxmLnBvcyA9IHBvcytsZW47XG4gICAgICAgIGlmIChzZWxmLnBlbmRpbmdDbG9zZSlcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJlYWRpbmcgYSBjbG9zaW5nIGZpbGVcIik7XG5cbiAgICAgICAgLy8gRGlyZWN0LXJlYWQgZmFzdCBwYXRoOiBmb3IgbGFyZ2UgcmVhZHMgd2l0aCBubyBvdmVybGFwcGluZyB1bndyaXR0ZW5cbiAgICAgICAgLy8gKGRpcnR5KSBwYWdlcywgY29weSBzdHJhaWdodCBmcm9tIGRpc2sgaW50byB0aGUgZGVzdGluYXRpb24gYnVmZmVyLlxuICAgICAgICAvLyBUaGlzIHNraXBzIHRoZSBwYWdlIGNhY2hlIGFuZCB0aGUgcGFnZS0+ZGVzdGluYXRpb24gY29weSBpdCBpbmN1cnMsXG4gICAgICAgIC8vIHdoaWNoIGRvbWluYXRlcyBsYXJnZSBzZXF1ZW50aWFsIHJlYWRzIChlLmcuIHprZXkvcHRhdSBzZWN0aW9ucykuXG4gICAgICAgIC8vIEFycmF5QnVmZmVyLmlzVmlldyBnYXRlOiB0aGUgZGlyZWN0IHBhdGggaGFuZHMgYnVmZkRzdCB0byBmZC5yZWFkLCB3aGljaFxuICAgICAgICAvLyBuZWVkcyBhIHJlYWwgVHlwZWRBcnJheS9EYXRhVmlldy4gQSBCaWdCdWZmZXIgKHBhZ2VkLCBub3QgYSB2aWV3KSBtdXN0XG4gICAgICAgIC8vIGdvIHRocm91Z2ggdGhlIGNhY2hlZCBwYXRoLCB3aGljaCBjb3BpZXMgaW50byBpdCB2aWEgaXRzIG93biAuc2V0KCkuXG4gICAgICAgIGlmIChsZW4gPj0gc2VsZi5kaXJlY3RSZWFkVGhyZXNob2xkICYmIEFycmF5QnVmZmVyLmlzVmlldyhidWZmRHN0KSAmJiAhc2VsZi5fcmFuZ2VIYXNEaXJ0eVBhZ2VzKHBvcywgbGVuKSkge1xuICAgICAgICAgICAgbGV0IHRvUmVhZCA9IChwb3MgKyBsZW4gPiBzZWxmLnRvdGFsU2l6ZSkgPyAoc2VsZi50b3RhbFNpemUgLSBwb3MpIDogbGVuO1xuICAgICAgICAgICAgaWYgKHRvUmVhZCA8IDApIHRvUmVhZCA9IDA7XG4gICAgICAgICAgICBsZXQgZG9uZSA9IDA7XG4gICAgICAgICAgICB3aGlsZSAoZG9uZSA8IHRvUmVhZCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHsgYnl0ZXNSZWFkIH0gPSBhd2FpdCBzZWxmLmZkLnJlYWQoYnVmZkRzdCwgb2Zmc2V0ICsgZG9uZSwgdG9SZWFkIC0gZG9uZSwgcG9zICsgZG9uZSk7XG4gICAgICAgICAgICAgICAgaWYgKGJ5dGVzUmVhZCA9PT0gMCkgYnJlYWs7ICAgLy8gRU9GXG4gICAgICAgICAgICAgICAgZG9uZSArPSBieXRlc1JlYWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobGVuID4gc2VsZi5wYWdlU2l6ZSpzZWxmLm1heFBhZ2VzTG9hZGVkKjAuOCkge1xuICAgICAgICAgICAgY29uc3QgY2FjaGVTaXplID0gTWF0aC5mbG9vcihsZW4gKiAxLjEpO1xuICAgICAgICAgICAgdGhpcy5tYXhQYWdlc0xvYWRlZCA9IE1hdGguZmxvb3IoIGNhY2hlU2l6ZSAvIHNlbGYucGFnZVNpemUpKzE7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZmlyc3RQYWdlID0gTWF0aC5mbG9vcihwb3MgLyBzZWxmLnBhZ2VTaXplKTtcbiAgICAgICAgY29uc3QgbGFzdFBhZ2UgPSBNYXRoLmZsb29yKChwb3MgKyBsZW4gLTEpIC8gc2VsZi5wYWdlU2l6ZSk7XG5cbiAgICAgICAgY29uc3QgcGFnZVByb21pc2VzID0gW107XG4gICAgICAgIGZvciAobGV0IGk9Zmlyc3RQYWdlOyBpPD1sYXN0UGFnZTsgaSsrKSBwYWdlUHJvbWlzZXMucHVzaChzZWxmLl9sb2FkUGFnZShpKSk7XG5cbiAgICAgICAgc2VsZi5fdHJpZ2dlckxvYWQoKTtcblxuICAgICAgICBsZXQgcCA9IGZpcnN0UGFnZTtcbiAgICAgICAgbGV0IG8gPSBwb3MgJSBzZWxmLnBhZ2VTaXplO1xuICAgICAgICAvLyBSZW1haW5pbmcgYnl0ZXMgdG8gcmVhZFxuICAgICAgICBsZXQgciA9IHBvcyArIGxlbiA+IHNlbGYudG90YWxTaXplID8gbGVuIC0gKHBvcyArIGxlbiAtIHNlbGYudG90YWxTaXplKTogbGVuO1xuICAgICAgICB3aGlsZSAocj4wKSB7XG4gICAgICAgICAgICBhd2FpdCBwYWdlUHJvbWlzZXNbcCAtIGZpcnN0UGFnZV07XG4gICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIEF3YWl0IChyZWFkKTogXCIsIHApO1xuXG4gICAgICAgICAgICAvLyBieXRlcyB0byBjb3B5IGZyb20gdGhpcyBwYWdlXG4gICAgICAgICAgICBjb25zdCBsID0gKG8rciA+IHNlbGYucGFnZVNpemUpID8gKHNlbGYucGFnZVNpemUgLW8pIDogcjtcbiAgICAgICAgICAgIGNvbnN0IHNyY1ZpZXcgPSBuZXcgVWludDhBcnJheShzZWxmLnBhZ2VzW3BdLmJ1ZmYuYnVmZmVyLCBzZWxmLnBhZ2VzW3BdLmJ1ZmYuYnl0ZU9mZnNldCArIG8sIGwpO1xuICAgICAgICAgICAgYnVmZkRzdC5zZXQoc3JjVmlldywgb2Zmc2V0K2xlbi1yKTtcbiAgICAgICAgICAgIHNlbGYucGFnZXNbcF0ucGVuZGluZ09wcyAtLTtcblxuICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBPcCBkb25lOiBcIiwgcCk7XG5cbiAgICAgICAgICAgIHIgPSByLWw7XG4gICAgICAgICAgICBwICsrO1xuICAgICAgICAgICAgbyA9IDA7XG4gICAgICAgICAgICBpZiAoc2VsZi5wZW5kaW5nTG9hZHMubGVuZ3RoPjApIHNldEltbWVkaWF0ZShzZWxmLl90cmlnZ2VyTG9hZC5iaW5kKHNlbGYpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucG9zID0gcG9zICsgbGVuO1xuXG4gICAgfVxuXG5cbiAgICBfdHJ5Q2xvc2UoKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBpZiAoIXNlbGYucGVuZGluZ0Nsb3NlKSByZXR1cm47XG4gICAgICAgIGlmIChzZWxmLmVycm9yKSB7XG4gICAgICAgICAgICBzZWxmLnBlbmRpbmdDbG9zZVJlamVjdChzZWxmLmVycm9yKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBwID0gc2VsZi5fZ2V0RGlydHlQYWdlKCk7XG4gICAgICAgIGlmICgocD49MCkgfHwgKHNlbGYud3JpdGluZykgfHwgKHNlbGYucmVhZGluZykgfHwgKHNlbGYucGVuZGluZ0xvYWRzLmxlbmd0aD4wKSkgcmV0dXJuO1xuICAgICAgICBzZWxmLnBlbmRpbmdDbG9zZSgpO1xuICAgIH1cblxuICAgIGNsb3NlKCkge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgaWYgKHNlbGYucGVuZGluZ0Nsb3NlKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2xvc2luZyB0aGUgZmlsZSB0d2ljZVwiKTtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHNlbGYucGVuZGluZ0Nsb3NlID0gcmVzb2x2ZTtcbiAgICAgICAgICAgIHNlbGYucGVuZGluZ0Nsb3NlUmVqZWN0ID0gcmVqZWN0O1xuICAgICAgICAgICAgc2VsZi5fdHJ5Q2xvc2UoKTtcbiAgICAgICAgfSkudGhlbigoKT0+IHtcbiAgICAgICAgICAgIHNlbGYuZmQuY2xvc2UoKTtcbiAgICAgICAgfSwgKGVycikgPT4ge1xuICAgICAgICAgICAgc2VsZi5mZC5jbG9zZSgpO1xuICAgICAgICAgICAgdGhyb3cgKGVycik7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGFzeW5jIGRpc2NhcmQoKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBhd2FpdCBzZWxmLmNsb3NlKCk7XG4gICAgICAgIGF3YWl0IGZzLnByb21pc2VzLnVubGluayh0aGlzLmZpbGVOYW1lKTtcbiAgICB9XG5cbiAgICBhc3luYyB3cml0ZVVMRTMyKHYsIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgdG1wQnVmZjMyID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG4gICAgICAgIGNvbnN0IHRtcEJ1ZmYzMnYgPSBuZXcgRGF0YVZpZXcodG1wQnVmZjMyLmJ1ZmZlcik7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgdHJ1ZSk7XG5cbiAgICAgICAgYXdhaXQgc2VsZi53cml0ZSh0bXBCdWZmMzIsIHBvcyk7XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGVVQkUzMih2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgY29uc3QgdG1wQnVmZjMyID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG4gICAgICAgIGNvbnN0IHRtcEJ1ZmYzMnYgPSBuZXcgRGF0YVZpZXcodG1wQnVmZjMyLmJ1ZmZlcik7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgZmFsc2UpO1xuXG4gICAgICAgIGF3YWl0IHNlbGYud3JpdGUodG1wQnVmZjMyLCBwb3MpO1xuICAgIH1cblxuXG4gICAgYXN5bmMgd3JpdGVVTEU2NCh2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgY29uc3QgdG1wQnVmZjY0ID0gbmV3IFVpbnQ4QXJyYXkoOCk7XG4gICAgICAgIGNvbnN0IHRtcEJ1ZmY2NHYgPSBuZXcgRGF0YVZpZXcodG1wQnVmZjY0LmJ1ZmZlcik7XG5cbiAgICAgICAgdG1wQnVmZjY0di5zZXRVaW50MzIoMCwgdiAmIDB4RkZGRkZGRkYsIHRydWUpO1xuICAgICAgICB0bXBCdWZmNjR2LnNldFVpbnQzMig0LCBNYXRoLmZsb29yKHYgLyAweDEwMDAwMDAwMCkgLCB0cnVlKTtcblxuICAgICAgICBhd2FpdCBzZWxmLndyaXRlKHRtcEJ1ZmY2NCwgcG9zKTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkVUxFMzIocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgc2VsZi5yZWFkKDQsIHBvcyk7XG5cbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBVaW50MzJBcnJheShiLmJ1ZmZlcik7XG5cbiAgICAgICAgcmV0dXJuIHZpZXdbMF07XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFVCRTMyKHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgYiA9IGF3YWl0IHNlbGYucmVhZCg0LCBwb3MpO1xuXG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgRGF0YVZpZXcoYi5idWZmZXIpO1xuXG4gICAgICAgIHJldHVybiB2aWV3LmdldFVpbnQzMigwLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFVMRTY0KHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgYiA9IGF3YWl0IHNlbGYucmVhZCg4LCBwb3MpO1xuXG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgVWludDMyQXJyYXkoYi5idWZmZXIpO1xuXG4gICAgICAgIHJldHVybiB2aWV3WzFdICogMHgxMDAwMDAwMDAgKyB2aWV3WzBdO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRTdHJpbmcocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIGlmIChzZWxmLnBlbmRpbmdDbG9zZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBhIGNsb3NpbmcgZmlsZVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBjdXJyZW50UG9zaXRpb24gPSB0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIgPyBzZWxmLnBvcyA6IHBvcztcbiAgICAgICAgbGV0IGN1cnJlbnRQYWdlID0gTWF0aC5mbG9vcihjdXJyZW50UG9zaXRpb24gLyBzZWxmLnBhZ2VTaXplKTtcblxuICAgICAgICBsZXQgZW5kT2ZTdHJpbmdGb3VuZCA9IGZhbHNlO1xuICAgICAgICBsZXQgc3RyID0gXCJcIjtcblxuICAgICAgICB3aGlsZSAoIWVuZE9mU3RyaW5nRm91bmQpIHtcbiAgICAgICAgICAgIC8vUmVhZCBwYWdlXG4gICAgICAgICAgICBsZXQgcGFnZVByb21pc2UgPSBzZWxmLl9sb2FkUGFnZShjdXJyZW50UGFnZSk7XG4gICAgICAgICAgICBzZWxmLl90cmlnZ2VyTG9hZCgpO1xuICAgICAgICAgICAgYXdhaXQgcGFnZVByb21pc2U7XG4gICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIEF3YWl0IChyZWFkKTogXCIsIGN1cnJlbnRQYWdlKTtcblxuICAgICAgICAgICAgbGV0IG9mZnNldE9uUGFnZSA9IGN1cnJlbnRQb3NpdGlvbiAlIHNlbGYucGFnZVNpemU7XG5cbiAgICAgICAgICAgIGNvbnN0IGRhdGFBcnJheSA9IG5ldyBVaW50OEFycmF5KFxuICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbY3VycmVudFBhZ2VdLmJ1ZmYuYnVmZmVyLFxuICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbY3VycmVudFBhZ2VdLmJ1ZmYuYnl0ZU9mZnNldCArIG9mZnNldE9uUGFnZSxcbiAgICAgICAgICAgICAgICBzZWxmLnBhZ2VTaXplIC0gb2Zmc2V0T25QYWdlXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBsZXQgaW5kZXhFbmRPZlN0cmluZyA9IGRhdGFBcnJheS5maW5kSW5kZXgoZWxlbWVudCA9PiBlbGVtZW50ID09PSAwKTtcbiAgICAgICAgICAgIGVuZE9mU3RyaW5nRm91bmQgPSBpbmRleEVuZE9mU3RyaW5nICE9PSAtMTtcblxuICAgICAgICAgICAgaWYgKGVuZE9mU3RyaW5nRm91bmQpIHtcbiAgICAgICAgICAgICAgICBzdHIgKz0gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKGRhdGFBcnJheS5zbGljZSgwLCBpbmRleEVuZE9mU3RyaW5nKSk7XG4gICAgICAgICAgICAgICAgc2VsZi5wb3MgPSBjdXJyZW50UGFnZSAqIHRoaXMucGFnZVNpemUgKyBvZmZzZXRPblBhZ2UgKyBpbmRleEVuZE9mU3RyaW5nICsgMTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RyICs9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhQXJyYXkpO1xuICAgICAgICAgICAgICAgIHNlbGYucG9zID0gY3VycmVudFBhZ2UgKiB0aGlzLnBhZ2VTaXplICsgb2Zmc2V0T25QYWdlICsgZGF0YUFycmF5Lmxlbmd0aDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2VsZi5wYWdlc1tjdXJyZW50UGFnZV0ucGVuZGluZ09wcy0tO1xuICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBPcCBkb25lOiBcIiwgY3VycmVudFBhZ2UpO1xuXG4gICAgICAgICAgICBjdXJyZW50UG9zaXRpb24gPSBzZWxmLnBvcztcbiAgICAgICAgICAgIGN1cnJlbnRQYWdlKys7XG5cbiAgICAgICAgICAgIGlmIChzZWxmLnBlbmRpbmdMb2Fkcy5sZW5ndGggPiAwKSBzZXRJbW1lZGlhdGUoc2VsZi5fdHJpZ2dlckxvYWQuYmluZChzZWxmKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gc3RyO1xuICAgIH1cbn1cbiIsImV4cG9ydCBmdW5jdGlvbiBjcmVhdGVOZXcobykge1xuICAgIGNvbnN0IGluaXRpYWxTaXplID0gby5pbml0aWFsU2l6ZSB8fCAxPDwyMDtcbiAgICBjb25zdCBmZCA9IG5ldyBNZW1GaWxlKCk7XG4gICAgZmQubyA9IG87XG4gICAgZmQuby5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoaW5pdGlhbFNpemUpO1xuICAgIGZkLmFsbG9jU2l6ZSA9IGluaXRpYWxTaXplO1xuICAgIGZkLnRvdGFsU2l6ZSA9IDA7XG4gICAgZmQucmVhZE9ubHkgPSBmYWxzZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRFeGlzdGluZyhvKSB7XG4gICAgY29uc3QgZmQgPSBuZXcgTWVtRmlsZSgpO1xuICAgIGZkLm8gPSBvO1xuICAgIGZkLmFsbG9jU2l6ZSA9IG8uZGF0YS5ieXRlTGVuZ3RoO1xuICAgIGZkLnRvdGFsU2l6ZSA9IG8uZGF0YS5ieXRlTGVuZ3RoO1xuICAgIGZkLnJlYWRPbmx5ID0gdHJ1ZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRXcml0ZUV4aXN0aW5nKG8pIHtcbiAgICBjb25zdCBmZCA9IG5ldyBNZW1GaWxlKCk7XG4gICAgZmQubyA9IG87XG4gICAgZmQuYWxsb2NTaXplID0gby5kYXRhLmJ5dGVMZW5ndGg7XG4gICAgZmQudG90YWxTaXplID0gby5kYXRhLmJ5dGVMZW5ndGg7XG4gICAgZmQucmVhZE9ubHkgPSBmYWxzZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuY29uc3QgdG1wQnVmZjMyID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG5jb25zdCB0bXBCdWZmMzJ2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmYzMi5idWZmZXIpO1xuY29uc3QgdG1wQnVmZjY0ID0gbmV3IFVpbnQ4QXJyYXkoOCk7XG5jb25zdCB0bXBCdWZmNjR2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmY2NC5idWZmZXIpO1xuXG5jbGFzcyBNZW1GaWxlIHtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnBhZ2VTaXplID0gMSA8PCAxNDsgIC8vIGZvciBjb21wYXRpYmlsaXR5XG4gICAgfVxuXG4gICAgX3Jlc2l6ZUlmTmVlZGVkKG5ld0xlbikge1xuICAgICAgICBpZiAobmV3TGVuID4gdGhpcy5hbGxvY1NpemUpIHtcbiAgICAgICAgICAgIGNvbnN0IG5ld0FsbG9jU2l6ZSA9IE1hdGgubWF4KFxuICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NTaXplICsgKDEgPDwgMjApLFxuICAgICAgICAgICAgICAgIE1hdGguZmxvb3IodGhpcy5hbGxvY1NpemUgKiAxLjEpLFxuICAgICAgICAgICAgICAgIG5ld0xlblxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IG5ld0RhdGEgPSBuZXcgVWludDhBcnJheShuZXdBbGxvY1NpemUpO1xuICAgICAgICAgICAgbmV3RGF0YS5zZXQodGhpcy5vLmRhdGEpO1xuICAgICAgICAgICAgdGhpcy5vLmRhdGEgPSBuZXdEYXRhO1xuICAgICAgICAgICAgdGhpcy5hbGxvY1NpemUgPSBuZXdBbGxvY1NpemU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyB3cml0ZShidWZmLCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9dGhpcztcbiAgICAgICAgaWYgKHR5cGVvZiBwb3MgPT0gXCJ1bmRlZmluZWRcIikgcG9zID0gc2VsZi5wb3M7XG4gICAgICAgIGlmICh0aGlzLnJlYWRPbmx5KSB0aHJvdyBuZXcgRXJyb3IoXCJXcml0aW5nIGEgcmVhZCBvbmx5IGZpbGVcIik7XG5cbiAgICAgICAgdGhpcy5fcmVzaXplSWZOZWVkZWQocG9zICsgYnVmZi5ieXRlTGVuZ3RoKTtcblxuICAgICAgICB0aGlzLm8uZGF0YS5zZXQoYnVmZi5zbGljZSgpLCBwb3MpO1xuXG4gICAgICAgIGlmIChwb3MgKyBidWZmLmJ5dGVMZW5ndGggPiB0aGlzLnRvdGFsU2l6ZSkgdGhpcy50b3RhbFNpemUgPSBwb3MgKyBidWZmLmJ5dGVMZW5ndGg7XG5cbiAgICAgICAgdGhpcy5wb3MgPSBwb3MgKyBidWZmLmJ5dGVMZW5ndGg7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFRvQnVmZmVyKGJ1ZmZEZXN0LCBvZmZzZXQsIGxlbiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBpZiAodHlwZW9mIHBvcyA9PSBcInVuZGVmaW5lZFwiKSBwb3MgPSBzZWxmLnBvcztcbiAgICAgICAgaWYgKHRoaXMucmVhZE9ubHkpIHtcbiAgICAgICAgICAgIGlmIChwb3MgKyBsZW4gPiB0aGlzLnRvdGFsU2l6ZSkgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBvdXQgb2YgYm91bmRzXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3Jlc2l6ZUlmTmVlZGVkKHBvcyArIGxlbik7XG5cbiAgICAgICAgY29uc3QgYnVmZlNyYyA9IG5ldyBVaW50OEFycmF5KHRoaXMuby5kYXRhLmJ1ZmZlciwgdGhpcy5vLmRhdGEuYnl0ZU9mZnNldCArIHBvcywgbGVuKTtcblxuICAgICAgICBidWZmRGVzdC5zZXQoYnVmZlNyYywgb2Zmc2V0KTtcblxuICAgICAgICB0aGlzLnBvcyA9IHBvcyArIGxlbjtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkKGxlbiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShsZW4pO1xuICAgICAgICBhd2FpdCBzZWxmLnJlYWRUb0J1ZmZlcihidWZmLCAwLCBsZW4sIHBvcyk7XG5cbiAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgfVxuXG4gICAgY2xvc2UoKSB7XG4gICAgICAgIGlmICh0aGlzLm8uZGF0YS5ieXRlTGVuZ3RoICE9IHRoaXMudG90YWxTaXplKSB7XG4gICAgICAgICAgICB0aGlzLm8uZGF0YSA9IHRoaXMuby5kYXRhLnNsaWNlKDAsIHRoaXMudG90YWxTaXplKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGRpc2NhcmQoKSB7XG4gICAgfVxuXG5cbiAgICBhc3luYyB3cml0ZVVMRTMyKHYsIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICB0bXBCdWZmMzJ2LnNldFVpbnQzMigwLCB2LCB0cnVlKTtcblxuICAgICAgICBhd2FpdCBzZWxmLndyaXRlKHRtcEJ1ZmYzMiwgcG9zKTtcbiAgICB9XG5cbiAgICBhc3luYyB3cml0ZVVCRTMyKHYsIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICB0bXBCdWZmMzJ2LnNldFVpbnQzMigwLCB2LCBmYWxzZSk7XG5cbiAgICAgICAgYXdhaXQgc2VsZi53cml0ZSh0bXBCdWZmMzIsIHBvcyk7XG4gICAgfVxuXG5cbiAgICBhc3luYyB3cml0ZVVMRTY0KHYsIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICB0bXBCdWZmNjR2LnNldFVpbnQzMigwLCB2ICYgMHhGRkZGRkZGRiwgdHJ1ZSk7XG4gICAgICAgIHRtcEJ1ZmY2NHYuc2V0VWludDMyKDQsIE1hdGguZmxvb3IodiAvIDB4MTAwMDAwMDAwKSAsIHRydWUpO1xuXG4gICAgICAgIGF3YWl0IHNlbGYud3JpdGUodG1wQnVmZjY0LCBwb3MpO1xuICAgIH1cblxuXG4gICAgYXN5bmMgcmVhZFVMRTMyKHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgYiA9IGF3YWl0IHNlbGYucmVhZCg0LCBwb3MpO1xuXG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgVWludDMyQXJyYXkoYi5idWZmZXIpO1xuXG4gICAgICAgIHJldHVybiB2aWV3WzBdO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRVQkUzMihwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGIgPSBhd2FpdCBzZWxmLnJlYWQoNCwgcG9zKTtcblxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IERhdGFWaWV3KGIuYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gdmlldy5nZXRVaW50MzIoMCwgZmFsc2UpO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRVTEU2NChwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGIgPSBhd2FpdCBzZWxmLnJlYWQoOCwgcG9zKTtcblxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IFVpbnQzMkFycmF5KGIuYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gdmlld1sxXSAqIDB4MTAwMDAwMDAwICsgdmlld1swXTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkU3RyaW5nKHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICBsZXQgY3VycmVudFBvc2l0aW9uID0gdHlwZW9mIHBvcyA9PSBcInVuZGVmaW5lZFwiID8gc2VsZi5wb3MgOiBwb3M7XG5cbiAgICAgICAgaWYgKGN1cnJlbnRQb3NpdGlvbiA+IHRoaXMudG90YWxTaXplKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5yZWFkT25seSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJlYWRpbmcgb3V0IG9mIGJvdW5kc1wiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuX3Jlc2l6ZUlmTmVlZGVkKHBvcyk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZGF0YUFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoXG4gICAgICAgICAgICBzZWxmLm8uZGF0YS5idWZmZXIsXG4gICAgICAgICAgICBjdXJyZW50UG9zaXRpb24sXG4gICAgICAgICAgICB0aGlzLnRvdGFsU2l6ZSAtIGN1cnJlbnRQb3NpdGlvblxuICAgICAgICApO1xuXG4gICAgICAgIGxldCBpbmRleEVuZE9mU3RyaW5nID0gZGF0YUFycmF5LmZpbmRJbmRleChlbGVtZW50ID0+IGVsZW1lbnQgPT09IDApO1xuICAgICAgICBsZXQgZW5kT2ZTdHJpbmdGb3VuZCA9IGluZGV4RW5kT2ZTdHJpbmcgIT09IC0xO1xuXG4gICAgICAgIGxldCBzdHIgPSBcIlwiO1xuICAgICAgICBpZiAoZW5kT2ZTdHJpbmdGb3VuZCkge1xuICAgICAgICAgICAgc3RyID0gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKGRhdGFBcnJheS5zbGljZSgwLCBpbmRleEVuZE9mU3RyaW5nKSk7XG4gICAgICAgICAgICBzZWxmLnBvcyA9IGN1cnJlbnRQb3NpdGlvbiArIGluZGV4RW5kT2ZTdHJpbmcgKyAxO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc2VsZi5wb3MgPSBjdXJyZW50UG9zaXRpb247XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG59XG4iLCJjb25zdCBQQUdFX1NJWkUgPSAxPDwyMjtcblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU5ldyhvKSB7XG4gICAgY29uc3QgaW5pdGlhbFNpemUgPSBvLmluaXRpYWxTaXplIHx8IDA7XG4gICAgY29uc3QgZmQgPSBuZXcgQmlnTWVtRmlsZSgpO1xuICAgIGZkLm8gPSBvO1xuICAgIGNvbnN0IG5QYWdlcyA9IGluaXRpYWxTaXplID8gTWF0aC5mbG9vcigoaW5pdGlhbFNpemUgLSAxKSAvIFBBR0VfU0laRSkrMSA6IDA7XG4gICAgZmQuby5kYXRhID0gW107XG4gICAgZm9yIChsZXQgaT0wOyBpPG5QYWdlcy0xOyBpKyspIHtcbiAgICAgICAgZmQuby5kYXRhLnB1c2goIG5ldyBVaW50OEFycmF5KFBBR0VfU0laRSkpO1xuICAgIH1cbiAgICBpZiAoblBhZ2VzKSBmZC5vLmRhdGEucHVzaCggbmV3IFVpbnQ4QXJyYXkoaW5pdGlhbFNpemUgLSBQQUdFX1NJWkUqKG5QYWdlcy0xKSkpO1xuICAgIGZkLnRvdGFsU2l6ZSA9IDA7XG4gICAgZmQucmVhZE9ubHkgPSBmYWxzZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRFeGlzdGluZyhvKSB7XG4gICAgY29uc3QgZmQgPSBuZXcgQmlnTWVtRmlsZSgpO1xuICAgIGZkLm8gPSBvO1xuICAgIGZkLnRvdGFsU2l6ZSA9IChvLmRhdGEubGVuZ3RoLTEpKiBQQUdFX1NJWkUgKyBvLmRhdGFbby5kYXRhLmxlbmd0aC0xXS5ieXRlTGVuZ3RoO1xuICAgIGZkLnJlYWRPbmx5ID0gdHJ1ZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRXcml0ZUV4aXN0aW5nKG8pIHtcbiAgICBjb25zdCBmZCA9IG5ldyBCaWdNZW1GaWxlKCk7XG4gICAgZmQubyA9IG87XG4gICAgZmQudG90YWxTaXplID0gKG8uZGF0YS5sZW5ndGgtMSkqIFBBR0VfU0laRSArIG8uZGF0YVtvLmRhdGEubGVuZ3RoLTFdLmJ5dGVMZW5ndGg7XG4gICAgZmQucmVhZE9ubHkgPSBmYWxzZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuY29uc3QgdG1wQnVmZjMyID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG5jb25zdCB0bXBCdWZmMzJ2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmYzMi5idWZmZXIpO1xuY29uc3QgdG1wQnVmZjY0ID0gbmV3IFVpbnQ4QXJyYXkoOCk7XG5jb25zdCB0bXBCdWZmNjR2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmY2NC5idWZmZXIpO1xuXG5jbGFzcyBCaWdNZW1GaWxlIHtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnBhZ2VTaXplID0gMSA8PCAxNDsgIC8vIGZvciBjb21wYXRpYmlsaXR5XG4gICAgfVxuXG4gICAgX3Jlc2l6ZUlmTmVlZGVkKG5ld0xlbikge1xuXG4gICAgICAgIGlmIChuZXdMZW4gPD0gdGhpcy50b3RhbFNpemUpIHJldHVybjtcblxuICAgICAgICBpZiAodGhpcy5yZWFkT25seSkgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBvdXQgb2YgZmlsZSBib3VuZHNcIik7XG5cbiAgICAgICAgY29uc3QgblBhZ2VzID0gTWF0aC5mbG9vcigobmV3TGVuIC0gMSkgLyBQQUdFX1NJWkUpKzE7XG4gICAgICAgIGZvciAobGV0IGk9IE1hdGgubWF4KHRoaXMuby5kYXRhLmxlbmd0aC0xLCAwKTsgaTxuUGFnZXM7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgbmV3U2l6ZSA9IGk8blBhZ2VzLTEgPyBQQUdFX1NJWkUgOiBuZXdMZW4gLSAoblBhZ2VzLTEpKlBBR0VfU0laRTtcbiAgICAgICAgICAgIGNvbnN0IHAgPSBuZXcgVWludDhBcnJheShuZXdTaXplKTtcbiAgICAgICAgICAgIGlmIChpID09IHRoaXMuby5kYXRhLmxlbmd0aC0xKSBwLnNldCh0aGlzLm8uZGF0YVtpXSk7XG4gICAgICAgICAgICB0aGlzLm8uZGF0YVtpXSA9IHA7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50b3RhbFNpemUgPSBuZXdMZW47XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGUoYnVmZiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPXRoaXM7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIpIHBvcyA9IHNlbGYucG9zO1xuICAgICAgICBpZiAodGhpcy5yZWFkT25seSkgdGhyb3cgbmV3IEVycm9yKFwiV3JpdGluZyBhIHJlYWQgb25seSBmaWxlXCIpO1xuXG4gICAgICAgIHRoaXMuX3Jlc2l6ZUlmTmVlZGVkKHBvcyArIGJ1ZmYuYnl0ZUxlbmd0aCk7XG5cbiAgICAgICAgY29uc3QgZmlyc3RQYWdlID0gTWF0aC5mbG9vcihwb3MgLyBQQUdFX1NJWkUpO1xuXG4gICAgICAgIGxldCBwID0gZmlyc3RQYWdlO1xuICAgICAgICBsZXQgbyA9IHBvcyAlIFBBR0VfU0laRTtcbiAgICAgICAgbGV0IHIgPSBidWZmLmJ5dGVMZW5ndGg7XG4gICAgICAgIHdoaWxlIChyPjApIHtcbiAgICAgICAgICAgIGNvbnN0IGwgPSAobytyID4gUEFHRV9TSVpFKSA/IChQQUdFX1NJWkUgLW8pIDogcjtcbiAgICAgICAgICAgIGNvbnN0IHNyY1ZpZXcgPSBidWZmLnNsaWNlKGJ1ZmYuYnl0ZUxlbmd0aCAtIHIsIGJ1ZmYuYnl0ZUxlbmd0aCAtIHIgKyBsKTtcbiAgICAgICAgICAgIGNvbnN0IGRzdFZpZXcgPSBuZXcgVWludDhBcnJheShzZWxmLm8uZGF0YVtwXS5idWZmZXIsIG8sIGwpO1xuICAgICAgICAgICAgZHN0Vmlldy5zZXQoc3JjVmlldyk7XG4gICAgICAgICAgICByID0gci1sO1xuICAgICAgICAgICAgcCArKztcbiAgICAgICAgICAgIG8gPSAwO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5wb3MgPSBwb3MgKyBidWZmLmJ5dGVMZW5ndGg7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFRvQnVmZmVyKGJ1ZmZEc3QsIG9mZnNldCwgbGVuLCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIpIHBvcyA9IHNlbGYucG9zO1xuICAgICAgICBpZiAodGhpcy5yZWFkT25seSkge1xuICAgICAgICAgICAgaWYgKHBvcyArIGxlbiA+IHRoaXMudG90YWxTaXplKSB0aHJvdyBuZXcgRXJyb3IoXCJSZWFkaW5nIG91dCBvZiBib3VuZHNcIik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fcmVzaXplSWZOZWVkZWQocG9zICsgbGVuKTtcblxuICAgICAgICBjb25zdCBmaXJzdFBhZ2UgPSBNYXRoLmZsb29yKHBvcyAvIFBBR0VfU0laRSk7XG5cbiAgICAgICAgbGV0IHAgPSBmaXJzdFBhZ2U7XG4gICAgICAgIGxldCBvID0gcG9zICUgUEFHRV9TSVpFO1xuICAgICAgICAvLyBSZW1haW5pbmcgYnl0ZXMgdG8gcmVhZFxuICAgICAgICBsZXQgciA9IGxlbjtcbiAgICAgICAgd2hpbGUgKHI+MCkge1xuICAgICAgICAgICAgLy8gYnl0ZXMgdG8gY29weSBmcm9tIHRoaXMgcGFnZVxuICAgICAgICAgICAgY29uc3QgbCA9IChvK3IgPiBQQUdFX1NJWkUpID8gKFBBR0VfU0laRSAtbykgOiByO1xuICAgICAgICAgICAgY29uc3Qgc3JjVmlldyA9IG5ldyBVaW50OEFycmF5KHNlbGYuby5kYXRhW3BdLmJ1ZmZlciwgbywgbCk7XG4gICAgICAgICAgICBidWZmRHN0LnNldChzcmNWaWV3LCBvZmZzZXQrbGVuLXIpO1xuICAgICAgICAgICAgciA9IHItbDtcbiAgICAgICAgICAgIHAgKys7XG4gICAgICAgICAgICBvID0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucG9zID0gcG9zICsgbGVuO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWQobGVuLCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShsZW4pO1xuXG4gICAgICAgIGF3YWl0IHNlbGYucmVhZFRvQnVmZmVyKGJ1ZmYsIDAsIGxlbiwgcG9zKTtcblxuICAgICAgICByZXR1cm4gYnVmZjtcbiAgICB9XG5cbiAgICBjbG9zZSgpIHtcbiAgICB9XG5cbiAgICBhc3luYyBkaXNjYXJkKCkge1xuICAgIH1cblxuXG4gICAgYXN5bmMgd3JpdGVVTEUzMih2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgdHJ1ZSk7XG5cbiAgICAgICAgYXdhaXQgc2VsZi53cml0ZSh0bXBCdWZmMzIsIHBvcyk7XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGVVQkUzMih2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgZmFsc2UpO1xuXG4gICAgICAgIGF3YWl0IHNlbGYud3JpdGUodG1wQnVmZjMyLCBwb3MpO1xuICAgIH1cblxuXG4gICAgYXN5bmMgd3JpdGVVTEU2NCh2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdG1wQnVmZjY0di5zZXRVaW50MzIoMCwgdiAmIDB4RkZGRkZGRkYsIHRydWUpO1xuICAgICAgICB0bXBCdWZmNjR2LnNldFVpbnQzMig0LCBNYXRoLmZsb29yKHYgLyAweDEwMDAwMDAwMCkgLCB0cnVlKTtcblxuICAgICAgICBhd2FpdCBzZWxmLndyaXRlKHRtcEJ1ZmY2NCwgcG9zKTtcbiAgICB9XG5cblxuICAgIGFzeW5jIHJlYWRVTEUzMihwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGIgPSBhd2FpdCBzZWxmLnJlYWQoNCwgcG9zKTtcblxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IFVpbnQzMkFycmF5KGIuYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gdmlld1swXTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkVUJFMzIocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgc2VsZi5yZWFkKDQsIHBvcyk7XG5cbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhiLmJ1ZmZlcik7XG5cbiAgICAgICAgcmV0dXJuIHZpZXcuZ2V0VWludDMyKDAsIGZhbHNlKTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkVUxFNjQocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgc2VsZi5yZWFkKDgsIHBvcyk7XG5cbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBVaW50MzJBcnJheShiLmJ1ZmZlcik7XG5cbiAgICAgICAgcmV0dXJuIHZpZXdbMV0gKiAweDEwMDAwMDAwMCArIHZpZXdbMF07XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFN0cmluZyhwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGZpeGVkU2l6ZSA9IDIwNDg7XG5cbiAgICAgICAgbGV0IGN1cnJlbnRQb3NpdGlvbiA9IHR5cGVvZiBwb3MgPT0gXCJ1bmRlZmluZWRcIiA/IHNlbGYucG9zIDogcG9zO1xuXG4gICAgICAgIGlmIChjdXJyZW50UG9zaXRpb24gPiB0aGlzLnRvdGFsU2l6ZSkge1xuICAgICAgICAgICAgaWYgKHRoaXMucmVhZE9ubHkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJSZWFkaW5nIG91dCBvZiBib3VuZHNcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLl9yZXNpemVJZk5lZWRlZChwb3MpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGVuZE9mU3RyaW5nRm91bmQgPSBmYWxzZTtcbiAgICAgICAgbGV0IHN0ciA9IFwiXCI7XG5cbiAgICAgICAgd2hpbGUgKCFlbmRPZlN0cmluZ0ZvdW5kKSB7XG4gICAgICAgICAgICBsZXQgY3VycmVudFBhZ2UgPSBNYXRoLmZsb29yKGN1cnJlbnRQb3NpdGlvbiAvIFBBR0VfU0laRSk7XG4gICAgICAgICAgICBsZXQgb2Zmc2V0T25QYWdlID0gY3VycmVudFBvc2l0aW9uICUgUEFHRV9TSVpFO1xuXG4gICAgICAgICAgICBpZiAoc2VsZi5vLmRhdGFbY3VycmVudFBhZ2VdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJFUlJPUlwiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IHJlYWRMZW5ndGggPSBNYXRoLm1pbihmaXhlZFNpemUsIHNlbGYuby5kYXRhW2N1cnJlbnRQYWdlXS5sZW5ndGggLSBvZmZzZXRPblBhZ2UpO1xuICAgICAgICAgICAgY29uc3QgZGF0YUFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5vLmRhdGFbY3VycmVudFBhZ2VdLmJ1ZmZlciwgb2Zmc2V0T25QYWdlLCByZWFkTGVuZ3RoKTtcblxuICAgICAgICAgICAgbGV0IGluZGV4RW5kT2ZTdHJpbmcgPSBkYXRhQXJyYXkuZmluZEluZGV4KGVsZW1lbnQgPT4gZWxlbWVudCA9PT0gMCk7XG4gICAgICAgICAgICBlbmRPZlN0cmluZ0ZvdW5kID0gaW5kZXhFbmRPZlN0cmluZyAhPT0gLTE7XG5cbiAgICAgICAgICAgIGlmIChlbmRPZlN0cmluZ0ZvdW5kKSB7XG4gICAgICAgICAgICAgICAgc3RyICs9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhQXJyYXkuc2xpY2UoMCwgaW5kZXhFbmRPZlN0cmluZykpO1xuICAgICAgICAgICAgICAgIHNlbGYucG9zID0gY3VycmVudFBhZ2UgKiBQQUdFX1NJWkUgKyBvZmZzZXRPblBhZ2UgKyBpbmRleEVuZE9mU3RyaW5nICsgMTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RyICs9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhQXJyYXkpO1xuICAgICAgICAgICAgICAgIHNlbGYucG9zID0gY3VycmVudFBhZ2UgKiBQQUdFX1NJWkUgKyBvZmZzZXRPblBhZ2UgKyBkYXRhQXJyYXkubGVuZ3RoO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjdXJyZW50UG9zaXRpb24gPSBzZWxmLnBvcztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3RyO1xuICAgIH1cbn1cbiIsImltcG9ydCB7IG9wZW4gfSBmcm9tIFwiLi9vc2ZpbGUuanNcIjtcbmltcG9ydCAqIGFzIG1lbUZpbGUgZnJvbSBcIi4vbWVtZmlsZS5qc1wiO1xuaW1wb3J0ICogYXMgYmlnTWVtRmlsZSBmcm9tIFwiLi9iaWdtZW1maWxlLmpzXCI7XG5pbXBvcnQgeyBPX1RSVU5DLCBPX0NSRUFULCBPX1JEV1IsIE9fRVhDTCwgT19SRE9OTFkgfSBmcm9tIFwiY29uc3RhbnRzXCI7XG5cblxuY29uc3QgREVGQVVMVF9DQUNIRV9TSVpFID0gKDEgPDwgMTYpO1xuY29uc3QgREVGQVVMVF9QQUdFX1NJWkUgPSAoMSA8PCAxMyk7XG5cbi8vIFJvYnVzdCBOb2RlIGRldGVjdGlvbiB0aGF0IG5ldmVyIHRocm93cyAodW5saWtlIGBwcm9jZXNzLmJyb3dzZXJgLCB3aGljaCBpcyBhXG4vLyB3ZWJwYWNrLWlzbSBhbmQgaXMgdW5kZWZpbmVkIHVuZGVyIFZpdGUvZXNidWlsZC9TRVMpLlxuY29uc3QgaXNOb2RlID0gdHlwZW9mIHByb2Nlc3MgIT09IFwidW5kZWZpbmVkXCIgJiYgcHJvY2Vzcy52ZXJzaW9ucyAhPSBudWxsICYmIHByb2Nlc3MudmVyc2lvbnMubm9kZSAhPSBudWxsO1xuXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVPdmVycmlkZShvLCBiLCBjKSB7XG4gICAgaWYgKHR5cGVvZiBvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG8gPSB7XG4gICAgICAgICAgICB0eXBlOiBcImZpbGVcIixcbiAgICAgICAgICAgIGZpbGVOYW1lOiBvLFxuICAgICAgICAgICAgY2FjaGVTaXplOiBiIHx8IERFRkFVTFRfQ0FDSEVfU0laRSxcbiAgICAgICAgICAgIHBhZ2VTaXplOiBjIHx8IERFRkFVTFRfUEFHRV9TSVpFXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChvLnR5cGUgPT0gXCJmaWxlXCIpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IG9wZW4oby5maWxlTmFtZSwgT19UUlVOQyB8IE9fQ1JFQVQgfCBPX1JEV1IsIG8uY2FjaGVTaXplLCBvLnBhZ2VTaXplKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcIm1lbVwiKSB7XG4gICAgICAgIHJldHVybiBtZW1GaWxlLmNyZWF0ZU5ldyhvKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcImJpZ01lbVwiKSB7XG4gICAgICAgIHJldHVybiBiaWdNZW1GaWxlLmNyZWF0ZU5ldyhvKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIEZhc3RGaWxlIHR5cGU6IFwiK28udHlwZSk7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTm9PdmVycmlkZShvLCBiLCBjKSB7XG4gICAgaWYgKHR5cGVvZiBvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG8gPSB7XG4gICAgICAgICAgICB0eXBlOiBcImZpbGVcIixcbiAgICAgICAgICAgIGZpbGVOYW1lOiBvLFxuICAgICAgICAgICAgY2FjaGVTaXplOiBiIHx8IERFRkFVTFRfQ0FDSEVfU0laRSxcbiAgICAgICAgICAgIHBhZ2VTaXplOiBjIHx8IERFRkFVTFRfUEFHRV9TSVpFXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChvLnR5cGUgPT0gXCJmaWxlXCIpIHtcbiAgICAgICAgcmV0dXJuIG9wZW4oby5maWxlTmFtZSwgT19UUlVOQyB8IE9fQ1JFQVQgfCBPX1JEV1IgfCBPX0VYQ0wsIG8uY2FjaGVTaXplLCBvLnBhZ2VTaXplKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcIm1lbVwiKSB7XG4gICAgICAgIHJldHVybiBtZW1GaWxlLmNyZWF0ZU5ldyhvKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcImJpZ01lbVwiKSB7XG4gICAgICAgIHJldHVybiBiaWdNZW1GaWxlLmNyZWF0ZU5ldyhvKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIEZhc3RGaWxlIHR5cGU6IFwiK28udHlwZSk7XG4gICAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZEV4aXN0aW5nKG8sIGIsIGMpIHtcbiAgICBpZiAobyBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHtcbiAgICAgICAgbyA9IHtcbiAgICAgICAgICAgIHR5cGU6IFwibWVtXCIsXG4gICAgICAgICAgICBkYXRhOiBvXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmICghaXNOb2RlKSB7XG4gICAgICAgIGlmICh0eXBlb2YgbyA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgY29uc3QgYnVmZiA9IGF3YWl0IGZldGNoKG8pLnRoZW4oIGZ1bmN0aW9uKHJlcykge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXMuYXJyYXlCdWZmZXIoKTtcbiAgICAgICAgICAgIH0pLnRoZW4oZnVuY3Rpb24gKGFiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KGFiKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgbyA9IHtcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm1lbVwiLFxuICAgICAgICAgICAgICAgIGRhdGE6IGJ1ZmZcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBpZiAodHlwZW9mIG8gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIG8gPSB7XG4gICAgICAgICAgICAgICAgdHlwZTogXCJmaWxlXCIsXG4gICAgICAgICAgICAgICAgZmlsZU5hbWU6IG8sXG4gICAgICAgICAgICAgICAgY2FjaGVTaXplOiBiIHx8IERFRkFVTFRfQ0FDSEVfU0laRSxcbiAgICAgICAgICAgICAgICBwYWdlU2l6ZTogYyB8fCBERUZBVUxUX1BBR0VfU0laRVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoby50eXBlID09IFwiZmlsZVwiKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBvcGVuKG8uZmlsZU5hbWUsIE9fUkRPTkxZLCBvLmNhY2hlU2l6ZSwgby5wYWdlU2l6ZSk7XG4gICAgfSBlbHNlIGlmIChvLnR5cGUgPT0gXCJtZW1cIikge1xuICAgICAgICByZXR1cm4gYXdhaXQgbWVtRmlsZS5yZWFkRXhpc3Rpbmcobyk7XG4gICAgfSBlbHNlIGlmIChvLnR5cGUgPT0gXCJiaWdNZW1cIikge1xuICAgICAgICByZXR1cm4gYXdhaXQgYmlnTWVtRmlsZS5yZWFkRXhpc3Rpbmcobyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBGYXN0RmlsZSB0eXBlOiBcIitvLnR5cGUpO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRXcml0ZUV4aXN0aW5nKG8sIGIsIGMpIHtcbiAgICBpZiAodHlwZW9mIG8gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgbyA9IHtcbiAgICAgICAgICAgIHR5cGU6IFwiZmlsZVwiLFxuICAgICAgICAgICAgZmlsZU5hbWU6IG8sXG4gICAgICAgICAgICBjYWNoZVNpemU6IGIgfHwgREVGQVVMVF9DQUNIRV9TSVpFLFxuICAgICAgICAgICAgcGFnZVNpemU6IGMgfHwgREVGQVVMVF9QQUdFX1NJWkVcbiAgICAgICAgfTtcbiAgICB9XG4gICAgaWYgKG8udHlwZSA9PSBcImZpbGVcIikge1xuICAgICAgICByZXR1cm4gb3BlbihvLmZpbGVOYW1lLCBPX0NSRUFUIHwgT19SRFdSLCBvLmNhY2hlU2l6ZSwgby5wYWdlU2l6ZSk7XG4gICAgfSBlbHNlIGlmIChvLnR5cGUgPT0gXCJtZW1cIikge1xuICAgICAgICByZXR1cm4gbWVtRmlsZS5yZWFkV3JpdGVFeGlzdGluZyhvKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcImJpZ01lbVwiKSB7XG4gICAgICAgIHJldHVybiBiaWdNZW1GaWxlLnJlYWRXcml0ZUV4aXN0aW5nKG8pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgRmFzdEZpbGUgdHlwZTogXCIrby50eXBlKTtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWFkV3JpdGVFeGlzdGluZ09yQ3JlYXRlKG8sIGIsIGMpIHtcbiAgICBpZiAodHlwZW9mIG8gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgbyA9IHtcbiAgICAgICAgICAgIHR5cGU6IFwiZmlsZVwiLFxuICAgICAgICAgICAgZmlsZU5hbWU6IG8sXG4gICAgICAgICAgICBjYWNoZVNpemU6IGIgfHwgREVGQVVMVF9DQUNIRV9TSVpFLFxuICAgICAgICAgICAgcGFnZVNpemU6IGMgfHwgREVGQVVMVF9QQUdFX1NJWkVcbiAgICAgICAgfTtcbiAgICB9XG4gICAgaWYgKG8udHlwZSA9PSBcImZpbGVcIikge1xuICAgICAgICByZXR1cm4gb3BlbihvLmZpbGVOYW1lLCBPX0NSRUFUIHwgT19SRFdSIHwgT19FWENMLCBvLmNhY2hlU2l6ZSk7XG4gICAgfSBlbHNlIGlmIChvLnR5cGUgPT0gXCJtZW1cIikge1xuICAgICAgICByZXR1cm4gbWVtRmlsZS5yZWFkV3JpdGVFeGlzdGluZyhvKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcImJpZ01lbVwiKSB7XG4gICAgICAgIHJldHVybiBiaWdNZW1GaWxlLnJlYWRXcml0ZUV4aXN0aW5nKG8pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgRmFzdEZpbGUgdHlwZTogXCIrby50eXBlKTtcbiAgICB9XG59XG4iLCJcbmltcG9ydCAgeyBTY2FsYXIsIEJpZ0J1ZmZlciB9IGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmltcG9ydCAqIGFzIGZhc3RGaWxlIGZyb20gXCJmYXN0ZmlsZVwiO1xuXG4vLyAxIEdpQiB0aHJlc2hvbGQgKG1hdGNoZWQgdG8gQmlnQnVmZmVyJ3MgcGFnZSBzaXplKTogc2VjdGlvbnMgYXQvYWJvdmUgdGhpcyBhcmVcbi8vIHJlYWQgaW50byBhIHBhZ2VkIEJpZ0J1ZmZlciBpbnN0ZWFkIG9mIG9uZSBmbGF0IFVpbnQ4QXJyYXkuXG5jb25zdCBNQVhfQlVGRkVSX1NJWkUgPSAxIDw8IDMwO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZEJpbkZpbGUoZmlsZU5hbWUsIHR5cGUsIG1heFZlcnNpb24sIGNhY2hlU2l6ZSwgcGFnZVNpemUpIHtcblxuICAgIGNvbnN0IGZkID0gYXdhaXQgZmFzdEZpbGUucmVhZEV4aXN0aW5nKGZpbGVOYW1lLCBjYWNoZVNpemUsIHBhZ2VTaXplKTtcblxuICAgIGNvbnN0IGIgPSBhd2FpdCBmZC5yZWFkKDQpO1xuICAgIGxldCByZWFkZWRUeXBlID0gXCJcIjtcbiAgICBmb3IgKGxldCBpPTA7IGk8NDsgaSsrKSByZWFkZWRUeXBlICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYltpXSk7XG5cbiAgICBpZiAocmVhZGVkVHlwZSAhPSB0eXBlKSB0aHJvdyBuZXcgRXJyb3IoZmlsZU5hbWUgKyBcIjogSW52YWxpZCBGaWxlIGZvcm1hdFwiKTtcblxuICAgIGxldCB2ID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG5cbiAgICBpZiAodj5tYXhWZXJzaW9uKSB0aHJvdyBuZXcgRXJyb3IoXCJWZXJzaW9uIG5vdCBzdXBwb3J0ZWRcIik7XG5cbiAgICBjb25zdCBuU2VjdGlvbnMgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcblxuICAgIC8vIFNjYW4gc2VjdGlvbnNcbiAgICBsZXQgc2VjdGlvbnMgPSBbXTtcbiAgICBmb3IgKGxldCBpPTA7IGk8blNlY3Rpb25zOyBpKyspIHtcbiAgICAgICAgbGV0IGh0ID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgICAgIGxldCBobCA9IGF3YWl0IGZkLnJlYWRVTEU2NCgpO1xuICAgICAgICBpZiAodHlwZW9mIHNlY3Rpb25zW2h0XSA9PSBcInVuZGVmaW5lZFwiKSBzZWN0aW9uc1todF0gPSBbXTtcbiAgICAgICAgc2VjdGlvbnNbaHRdLnB1c2goe1xuICAgICAgICAgICAgcDogZmQucG9zLFxuICAgICAgICAgICAgc2l6ZTogaGxcbiAgICAgICAgfSk7XG4gICAgICAgIGZkLnBvcyArPSBobDtcbiAgICB9XG5cbiAgICByZXR1cm4ge2ZkLCBzZWN0aW9uc307XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVCaW5GaWxlKGZpbGVOYW1lLCB0eXBlLCB2ZXJzaW9uLCBuU2VjdGlvbnMsIGNhY2hlU2l6ZSwgcGFnZVNpemUpIHtcblxuICAgIGNvbnN0IGZkID0gYXdhaXQgZmFzdEZpbGUuY3JlYXRlT3ZlcnJpZGUoZmlsZU5hbWUsIGNhY2hlU2l6ZSwgcGFnZVNpemUpO1xuXG4gICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KDQpO1xuICAgIGZvciAobGV0IGk9MDsgaTw0OyBpKyspIGJ1ZmZbaV0gPSB0eXBlLmNoYXJDb2RlQXQoaSk7XG4gICAgYXdhaXQgZmQud3JpdGUoYnVmZiwgMCk7IC8vIE1hZ2ljIFwicjFjc1wiXG5cbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKHZlcnNpb24pOyAvLyBWZXJzaW9uXG4gICAgYXdhaXQgZmQud3JpdGVVTEUzMihuU2VjdGlvbnMpOyAvLyBOdW1iZXIgb2YgU2VjdGlvbnNcblxuICAgIHJldHVybiBmZDtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0V3JpdGVTZWN0aW9uKGZkLCBpZFNlY3Rpb24pIHtcbiAgICBpZiAodHlwZW9mIGZkLndyaXRpbmdTZWN0aW9uICE9PSBcInVuZGVmaW5lZFwiKSB0aHJvdyBuZXcgRXJyb3IoXCJBbHJlYWR5IHdyaXRpbmcgYSBzZWN0aW9uXCIpO1xuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoaWRTZWN0aW9uKTsgLy8gSGVhZGVyIHR5cGVcbiAgICBmZC53cml0aW5nU2VjdGlvbiA9IHtcbiAgICAgICAgcFNlY3Rpb25TaXplOiBmZC5wb3NcbiAgICB9O1xuICAgIGF3YWl0IGZkLndyaXRlVUxFNjQoMCk7IC8vIFRlbXBvcmFsbHkgc2V0IHRvIDAgbGVuZ3RoXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBlbmRXcml0ZVNlY3Rpb24oZmQpIHtcbiAgICBpZiAodHlwZW9mIGZkLndyaXRpbmdTZWN0aW9uID09PSBcInVuZGVmaW5lZFwiKSB0aHJvdyBuZXcgRXJyb3IoXCJOb3Qgd3JpdGluZyBhIHNlY3Rpb25cIik7XG5cbiAgICBjb25zdCBzZWN0aW9uU2l6ZSA9IGZkLnBvcyAtIGZkLndyaXRpbmdTZWN0aW9uLnBTZWN0aW9uU2l6ZSAtIDg7XG4gICAgY29uc3Qgb2xkUG9zID0gZmQucG9zO1xuICAgIGZkLnBvcyA9IGZkLndyaXRpbmdTZWN0aW9uLnBTZWN0aW9uU2l6ZTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTY0KHNlY3Rpb25TaXplKTtcbiAgICBmZC5wb3MgPSBvbGRQb3M7XG4gICAgZGVsZXRlIGZkLndyaXRpbmdTZWN0aW9uO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIGlkU2VjdGlvbikge1xuICAgIGlmICh0eXBlb2YgZmQucmVhZGluZ1NlY3Rpb24gIT09IFwidW5kZWZpbmVkXCIpIHRocm93IG5ldyBFcnJvcihcIkFscmVhZHkgcmVhZGluZyBhIHNlY3Rpb25cIik7XG4gICAgaWYgKCFzZWN0aW9uc1tpZFNlY3Rpb25dKSAgdGhyb3cgbmV3IEVycm9yKGZkLmZpbGVOYW1lICsgXCI6IE1pc3Npbmcgc2VjdGlvbiBcIisgaWRTZWN0aW9uICk7XG4gICAgaWYgKHNlY3Rpb25zW2lkU2VjdGlvbl0ubGVuZ3RoPjEpIHRocm93IG5ldyBFcnJvcihmZC5maWxlTmFtZSArXCI6IFNlY3Rpb24gRHVwbGljYXRlZCBcIiAraWRTZWN0aW9uKTtcblxuICAgIGZkLnBvcyA9IHNlY3Rpb25zW2lkU2VjdGlvbl1bMF0ucDtcblxuICAgIGZkLnJlYWRpbmdTZWN0aW9uID0gc2VjdGlvbnNbaWRTZWN0aW9uXVswXTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGVuZFJlYWRTZWN0aW9uKGZkLCBub0NoZWNrKSB7XG4gICAgaWYgKHR5cGVvZiBmZC5yZWFkaW5nU2VjdGlvbiA9PT0gXCJ1bmRlZmluZWRcIikgdGhyb3cgbmV3IEVycm9yKFwiTm90IHJlYWRpbmcgYSBzZWN0aW9uXCIpO1xuICAgIGlmICghbm9DaGVjaykge1xuICAgICAgICBpZiAoZmQucG9zLWZkLnJlYWRpbmdTZWN0aW9uLnAgIT0gIGZkLnJlYWRpbmdTZWN0aW9uLnNpemUpIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgc2VjdGlvbiBzaXplIHJlYWRpbmdcIik7XG4gICAgfVxuICAgIGRlbGV0ZSBmZC5yZWFkaW5nU2VjdGlvbjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdyaXRlQmlnSW50KGZkLCBuLCBuOCwgcG9zKSB7XG4gICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KG44KTtcbiAgICBTY2FsYXIudG9ScHJMRShidWZmLCAwLCBuLCBuOCk7XG4gICAgYXdhaXQgZmQud3JpdGUoYnVmZiwgcG9zKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRCaWdJbnQoZmQsIG44LCBwb3MpIHtcbiAgICBjb25zdCBidWZmID0gYXdhaXQgZmQucmVhZChuOCwgcG9zKTtcbiAgICByZXR1cm4gU2NhbGFyLmZyb21ScHJMRShidWZmLCAwLCBuOCk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjb3B5U2VjdGlvbihmZEZyb20sIHNlY3Rpb25zLCBmZFRvLCBzZWN0aW9uSWQsIHNpemUpIHtcbiAgICBpZiAodHlwZW9mIHNpemUgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgc2l6ZSA9IHNlY3Rpb25zW3NlY3Rpb25JZF1bMF0uc2l6ZTtcbiAgICB9XG4gICAgY29uc3QgY2h1bmtTaXplID0gZmRGcm9tLnBhZ2VTaXplO1xuICAgIGF3YWl0IHN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmRGcm9tLCBzZWN0aW9ucywgc2VjdGlvbklkKTtcbiAgICBhd2FpdCBzdGFydFdyaXRlU2VjdGlvbihmZFRvLCBzZWN0aW9uSWQpO1xuICAgIGZvciAobGV0IHA9MDsgcDxzaXplOyBwKz1jaHVua1NpemUpIHtcbiAgICAgICAgY29uc3QgbCA9IE1hdGgubWluKHNpemUgLXAsIGNodW5rU2l6ZSk7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZEZyb20ucmVhZChsKTtcbiAgICAgICAgYXdhaXQgZmRUby53cml0ZShidWZmKTtcbiAgICB9XG4gICAgYXdhaXQgZW5kV3JpdGVTZWN0aW9uKGZkVG8pO1xuICAgIGF3YWl0IGVuZFJlYWRTZWN0aW9uKGZkRnJvbSwgc2l6ZSAhPSBzZWN0aW9uc1tzZWN0aW9uSWRdWzBdLnNpemUpO1xuXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkU2VjdGlvbihmZCwgc2VjdGlvbnMsIGlkU2VjdGlvbiwgb2Zmc2V0LCBsZW5ndGgpIHtcblxuICAgIG9mZnNldCA9ICh0eXBlb2Ygb2Zmc2V0ID09PSBcInVuZGVmaW5lZFwiKSA/IDAgOiBvZmZzZXQ7XG4gICAgbGVuZ3RoID0gKHR5cGVvZiBsZW5ndGggPT09IFwidW5kZWZpbmVkXCIpID8gc2VjdGlvbnNbaWRTZWN0aW9uXVswXS5zaXplIC0gb2Zmc2V0IDogbGVuZ3RoO1xuXG5cbiAgICBpZiAob2Zmc2V0ICsgbGVuZ3RoID4gc2VjdGlvbnNbaWRTZWN0aW9uXVswXS5zaXplKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJlYWRpbmcgb3V0IG9mIHRoZSByYW5nZSBvZiB0aGUgc2VjdGlvblwiKTtcbiAgICB9XG5cbiAgICBsZXQgYnVmZjtcbiAgICBpZiAobGVuZ3RoIDwgTUFYX0JVRkZFUl9TSVpFKSB7XG4gICAgICAgIGJ1ZmYgPSBuZXcgVWludDhBcnJheShsZW5ndGgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGJ1ZmYgPSBuZXcgQmlnQnVmZmVyKGxlbmd0aCk7XG4gICAgfVxuXG4gICAgYXdhaXQgZmQucmVhZFRvQnVmZmVyKGJ1ZmYsIDAsIGxlbmd0aCwgc2VjdGlvbnNbaWRTZWN0aW9uXVswXS5wICsgb2Zmc2V0KTtcblxuXG4gICAgcmV0dXJuIGJ1ZmY7XG59XG5cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlY3Rpb25Jc0VxdWFsKGZkMSwgc2VjdGlvbnMxLCBmZDIsIHNlY3Rpb25zMiwgaWRTZWN0aW9uKSB7XG4gICAgY29uc3QgTUFYX0JVRkZfU0laRSA9IGZkMS5wYWdlU2l6ZSAqIDE2O1xuICAgIGF3YWl0IHN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmQxLCBzZWN0aW9uczEsIGlkU2VjdGlvbik7XG4gICAgYXdhaXQgc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZDIsIHNlY3Rpb25zMiwgaWRTZWN0aW9uKTtcbiAgICBpZiAoc2VjdGlvbnMxW2lkU2VjdGlvbl1bMF0uc2l6ZSAhPSBzZWN0aW9uczJbaWRTZWN0aW9uXVswXS5zaXplKSByZXR1cm4gZmFsc2U7XG4gICAgY29uc3QgdG90YWxCeXRlcz1zZWN0aW9uczFbaWRTZWN0aW9uXVswXS5zaXplO1xuICAgIGZvciAobGV0IGk9MDsgaTx0b3RhbEJ5dGVzOyBpKz0gTUFYX0JVRkZfU0laRSkge1xuICAgICAgICBjb25zdCBuID0gTWF0aC5taW4odG90YWxCeXRlcy1pLCBNQVhfQlVGRl9TSVpFKTtcbiAgICAgICAgY29uc3QgYnVmZjEgPSBhd2FpdCBmZDEucmVhZChuKTtcbiAgICAgICAgY29uc3QgYnVmZjIgPSBhd2FpdCBmZDIucmVhZChuKTtcbiAgICAgICAgZm9yIChsZXQgaj0wOyBqPG47IGorKykgaWYgKGJ1ZmYxW2pdICE9IGJ1ZmYyW2pdKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGF3YWl0IGVuZFJlYWRTZWN0aW9uKGZkMSk7XG4gICAgYXdhaXQgZW5kUmVhZFNlY3Rpb24oZmQyKTtcbiAgICByZXR1cm4gdHJ1ZTtcbn1cbiIsImltcG9ydCB7IFNjYWxhciwgYnVpbGRCbjEyOCwgYnVpbGRCbHMxMjM4MX0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuXG5jb25zdCBibHMxMjM4MXIgPSBTY2FsYXIuZShcIjczZWRhNzUzMjk5ZDdkNDgzMzM5ZDgwODA5YTFkODA1NTNiZGE0MDJmZmZlNWJmZWZmZmZmZmZmMDAwMDAwMDFcIiwgMTYpO1xuY29uc3QgYm4xMjhyID0gU2NhbGFyLmUoXCIyMTg4ODI0Mjg3MTgzOTI3NTIyMjI0NjQwNTc0NTI1NzI3NTA4ODU0ODM2NDQwMDQxNjAzNDM0MzY5ODIwNDE4NjU3NTgwODQ5NTYxN1wiKTtcblxuY29uc3QgYmxzMTIzODFxID0gU2NhbGFyLmUoXCIxYTAxMTFlYTM5N2ZlNjlhNGIxYmE3YjY0MzRiYWNkNzY0Nzc0Yjg0ZjM4NTEyYmY2NzMwZDJhMGY2YjBmNjI0MWVhYmZmZmViMTUzZmZmZmI5ZmVmZmZmZmZmZmFhYWJcIiwgMTYpO1xuY29uc3QgYm4xMjhxID0gU2NhbGFyLmUoXCIyMTg4ODI0Mjg3MTgzOTI3NTIyMjI0NjQwNTc0NTI1NzI3NTA4ODY5NjMxMTE1NzI5NzgyMzY2MjY4OTAzNzg5NDY0NTIyNjIwODU4M1wiKTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldEN1cnZlRnJvbVIociwgb3B0aW9ucykge1xuICAgIGxldCBjdXJ2ZTtcbiAgICAvLyBjaGVjayB0aGF0IG9wdGlvbnMgcGFyYW0gaXMgZGVmaW5lZCBhbmQgdGhhdCBvcHRpb25zLnNpbmdsZVRocmVhZCBpcyBkZWZpbmVkXG4gICAgbGV0IHNpbmdsZVRocmVhZCA9IG9wdGlvbnMgJiYgb3B0aW9ucy5zaW5nbGVUaHJlYWQ7XG4gICAgaWYgKFNjYWxhci5lcShyLCBibjEyOHIpKSB7XG4gICAgICAgIGN1cnZlID0gYXdhaXQgYnVpbGRCbjEyOChzaW5nbGVUaHJlYWQpO1xuICAgIH0gZWxzZSBpZiAoU2NhbGFyLmVxKHIsIGJsczEyMzgxcikpIHtcbiAgICAgICAgY3VydmUgPSBhd2FpdCBidWlsZEJsczEyMzgxKHNpbmdsZVRocmVhZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDdXJ2ZSBub3Qgc3VwcG9ydGVkOiAke1NjYWxhci50b1N0cmluZyhyKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGN1cnZlO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0Q3VydmVGcm9tUShxLCBvcHRpb25zKSB7XG4gICAgbGV0IGN1cnZlO1xuICAgIGxldCBzaW5nbGVUaHJlYWQgPSBvcHRpb25zICYmIG9wdGlvbnMuc2luZ2xlVGhyZWFkO1xuICAgIGlmIChTY2FsYXIuZXEocSwgYm4xMjhxKSkge1xuICAgICAgICBjdXJ2ZSA9IGF3YWl0IGJ1aWxkQm4xMjgoc2luZ2xlVGhyZWFkKTtcbiAgICB9IGVsc2UgaWYgKFNjYWxhci5lcShxLCBibHMxMjM4MXEpKSB7XG4gICAgICAgIGN1cnZlID0gYXdhaXQgYnVpbGRCbHMxMjM4MShzaW5nbGVUaHJlYWQpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ3VydmUgbm90IHN1cHBvcnRlZDogJHtTY2FsYXIudG9TdHJpbmcocSl9YCk7XG4gICAgfVxuICAgIHJldHVybiBjdXJ2ZTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldEN1cnZlRnJvbU5hbWUobmFtZSwgb3B0aW9ucykge1xuICAgIGxldCBjdXJ2ZTtcbiAgICBsZXQgc2luZ2xlVGhyZWFkID0gb3B0aW9ucyAmJiBvcHRpb25zLnNpbmdsZVRocmVhZDtcbiAgICBjb25zdCBub3JtTmFtZSA9IG5vcm1hbGl6ZU5hbWUobmFtZSk7XG4gICAgaWYgKFtcIkJOMTI4XCIsIFwiQk4yNTRcIiwgXCJBTFRCTjEyOFwiXS5pbmRleE9mKG5vcm1OYW1lKSA+PSAwKSB7XG4gICAgICAgIGN1cnZlID0gYXdhaXQgYnVpbGRCbjEyOChzaW5nbGVUaHJlYWQpO1xuICAgIH0gZWxzZSBpZiAoW1wiQkxTMTIzODFcIl0uaW5kZXhPZihub3JtTmFtZSkgPj0gMCkge1xuICAgICAgICBjdXJ2ZSA9IGF3YWl0IGJ1aWxkQmxzMTIzODEoc2luZ2xlVGhyZWFkKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEN1cnZlIG5vdCBzdXBwb3J0ZWQ6ICR7bmFtZX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGN1cnZlO1xuXG4gICAgZnVuY3Rpb24gbm9ybWFsaXplTmFtZShuKSB7XG4gICAgICAgIHJldHVybiBuLnRvVXBwZXJDYXNlKCkubWF0Y2goL1tBLVphLXowLTldKy9nKS5qb2luKFwiXCIpO1xuICAgIH1cblxufVxuXG4iLCIvKipcbiAqIENoZWNrcyBpZiBzb21ldGhpbmcgaXMgVWludDhBcnJheS4gQmUgY2FyZWZ1bDogbm9kZWpzIEJ1ZmZlciB3aWxsIHJldHVybiB0cnVlLlxuICogQHBhcmFtIGEgLSB2YWx1ZSB0byB0ZXN0XG4gKiBAcmV0dXJucyBgdHJ1ZWAgd2hlbiB0aGUgdmFsdWUgaXMgYSBVaW50OEFycmF5LWNvbXBhdGlibGUgdmlldy5cbiAqIEBleGFtcGxlXG4gKiBDaGVjayB3aGV0aGVyIGEgdmFsdWUgaXMgYSBVaW50OEFycmF5LWNvbXBhdGlibGUgdmlldy5cbiAqIGBgYHRzXG4gKiBpc0J5dGVzKG5ldyBVaW50OEFycmF5KFsxLCAyLCAzXSkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0J5dGVzKGEpIHtcbiAgICAvLyBQbGFpbiBgaW5zdGFuY2VvZiBVaW50OEFycmF5YCBpcyB0b28gc3RyaWN0IGZvciBzb21lIEJ1ZmZlciAvIHByb3h5IC8gY3Jvc3MtcmVhbG0gY2FzZXMuXG4gICAgLy8gVGhlIGZhbGxiYWNrIHN0aWxsIHJlcXVpcmVzIGEgcmVhbCBBcnJheUJ1ZmZlciB2aWV3LCBzbyBwbGFpblxuICAgIC8vIEpTT04tZGVzZXJpYWxpemVkIGB7IGNvbnN0cnVjdG9yOiAuLi4gfWAgc3Bvb2ZpbmcgaXMgcmVqZWN0ZWQsIGFuZFxuICAgIC8vIGBCWVRFU19QRVJfRUxFTUVOVCA9PT0gMWAga2VlcHMgdGhlIGZhbGxiYWNrIG9uIGJ5dGUtb3JpZW50ZWQgdmlld3MuXG4gICAgcmV0dXJuIChhIGluc3RhbmNlb2YgVWludDhBcnJheSB8fFxuICAgICAgICAoQXJyYXlCdWZmZXIuaXNWaWV3KGEpICYmXG4gICAgICAgICAgICBhLmNvbnN0cnVjdG9yLm5hbWUgPT09ICdVaW50OEFycmF5JyAmJlxuICAgICAgICAgICAgJ0JZVEVTX1BFUl9FTEVNRU5UJyBpbiBhICYmXG4gICAgICAgICAgICBhLkJZVEVTX1BFUl9FTEVNRU5UID09PSAxKSk7XG59XG4vKipcbiAqIEFzc2VydHMgc29tZXRoaW5nIGlzIGEgbm9uLW5lZ2F0aXZlIGludGVnZXIuXG4gKiBAcGFyYW0gbiAtIG51bWJlciB0byB2YWxpZGF0ZVxuICogQHBhcmFtIHRpdGxlIC0gbGFiZWwgaW5jbHVkZWQgaW4gdGhyb3duIGVycm9yc1xuICogQHRocm93cyBPbiB3cm9uZyBhcmd1bWVudCB0eXBlcy4ge0BsaW5rIFR5cGVFcnJvcn1cbiAqIEB0aHJvd3MgT24gd3JvbmcgYXJndW1lbnQgcmFuZ2VzIG9yIHZhbHVlcy4ge0BsaW5rIFJhbmdlRXJyb3J9XG4gKiBAZXhhbXBsZVxuICogVmFsaWRhdGUgYSBub24tbmVnYXRpdmUgaW50ZWdlciBvcHRpb24uXG4gKiBgYGB0c1xuICogYW51bWJlcigzMiwgJ2xlbmd0aCcpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhbnVtYmVyKG4sIHRpdGxlID0gJycpIHtcbiAgICBpZiAodHlwZW9mIG4gIT09ICdudW1iZXInKSB7XG4gICAgICAgIGNvbnN0IHByZWZpeCA9IHRpdGxlICYmIGBcIiR7dGl0bGV9XCIgYDtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgJHtwcmVmaXh9ZXhwZWN0ZWQgbnVtYmVyLCBnb3QgJHt0eXBlb2Ygbn1gKTtcbiAgICB9XG4gICAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcihuKSB8fCBuIDwgMCkge1xuICAgICAgICBjb25zdCBwcmVmaXggPSB0aXRsZSAmJiBgXCIke3RpdGxlfVwiIGA7XG4gICAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKGAke3ByZWZpeH1leHBlY3RlZCBpbnRlZ2VyID49IDAsIGdvdCAke259YCk7XG4gICAgfVxufVxuLyoqXG4gKiBBc3NlcnRzIHNvbWV0aGluZyBpcyBVaW50OEFycmF5LlxuICogQHBhcmFtIHZhbHVlIC0gdmFsdWUgdG8gdmFsaWRhdGVcbiAqIEBwYXJhbSBsZW5ndGggLSBvcHRpb25hbCBleGFjdCBsZW5ndGggY29uc3RyYWludFxuICogQHBhcmFtIHRpdGxlIC0gbGFiZWwgaW5jbHVkZWQgaW4gdGhyb3duIGVycm9yc1xuICogQHJldHVybnMgVGhlIHZhbGlkYXRlZCBieXRlIGFycmF5LlxuICogQHRocm93cyBPbiB3cm9uZyBhcmd1bWVudCB0eXBlcy4ge0BsaW5rIFR5cGVFcnJvcn1cbiAqIEB0aHJvd3MgT24gd3JvbmcgYXJndW1lbnQgcmFuZ2VzIG9yIHZhbHVlcy4ge0BsaW5rIFJhbmdlRXJyb3J9XG4gKiBAZXhhbXBsZVxuICogVmFsaWRhdGUgdGhhdCBhIHZhbHVlIGlzIGEgYnl0ZSBhcnJheS5cbiAqIGBgYHRzXG4gKiBhYnl0ZXMobmV3IFVpbnQ4QXJyYXkoWzEsIDIsIDNdKSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFieXRlcyh2YWx1ZSwgbGVuZ3RoLCB0aXRsZSA9ICcnKSB7XG4gICAgY29uc3QgYnl0ZXMgPSBpc0J5dGVzKHZhbHVlKTtcbiAgICBjb25zdCBsZW4gPSB2YWx1ZT8ubGVuZ3RoO1xuICAgIGNvbnN0IG5lZWRzTGVuID0gbGVuZ3RoICE9PSB1bmRlZmluZWQ7XG4gICAgaWYgKCFieXRlcyB8fCAobmVlZHNMZW4gJiYgbGVuICE9PSBsZW5ndGgpKSB7XG4gICAgICAgIGNvbnN0IHByZWZpeCA9IHRpdGxlICYmIGBcIiR7dGl0bGV9XCIgYDtcbiAgICAgICAgY29uc3Qgb2ZMZW4gPSBuZWVkc0xlbiA/IGAgb2YgbGVuZ3RoICR7bGVuZ3RofWAgOiAnJztcbiAgICAgICAgY29uc3QgZ290ID0gYnl0ZXMgPyBgbGVuZ3RoPSR7bGVufWAgOiBgdHlwZT0ke3R5cGVvZiB2YWx1ZX1gO1xuICAgICAgICBjb25zdCBtZXNzYWdlID0gcHJlZml4ICsgJ2V4cGVjdGVkIFVpbnQ4QXJyYXknICsgb2ZMZW4gKyAnLCBnb3QgJyArIGdvdDtcbiAgICAgICAgaWYgKCFieXRlcylcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IobWVzc2FnZSk7XG4gICAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKG1lc3NhZ2UpO1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWU7XG59XG4vKipcbiAqIENvcGllcyBieXRlcyBpbnRvIGEgZnJlc2ggVWludDhBcnJheS5cbiAqIEJ1ZmZlci1zdHlsZSBzbGljZXMgY2FuIGFsaWFzIHRoZSBzYW1lIGJhY2tpbmcgc3RvcmUsIHNvIGNhbGxlcnMgdGhhdCBuZWVkIG93bmVyc2hpcCBzaG91bGQgY29weS5cbiAqIEBwYXJhbSBieXRlcyAtIHNvdXJjZSBieXRlcyB0byBjbG9uZVxuICogQHJldHVybnMgRnJlc2hseSBhbGxvY2F0ZWQgY29weSBvZiBgYnl0ZXNgLlxuICogQHRocm93cyBPbiB3cm9uZyBhcmd1bWVudCB0eXBlcy4ge0BsaW5rIFR5cGVFcnJvcn1cbiAqIEBleGFtcGxlXG4gKiBDbG9uZSBhIGJ5dGUgYXJyYXkgYmVmb3JlIG11dGF0aW5nIGl0LlxuICogYGBgdHNcbiAqIGNvbnN0IGNvcHkgPSBjb3B5Qnl0ZXMobmV3IFVpbnQ4QXJyYXkoWzEsIDIsIDNdKSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvcHlCeXRlcyhieXRlcykge1xuICAgIC8vIGBVaW50OEFycmF5LmZyb20oLi4uKWAgd291bGQgYWxzbyBhY2NlcHQgYXJyYXlzIC8gb3RoZXIgdHlwZWQgYXJyYXlzLiBLZWVwIHRoaXMgaGVscGVyIHN0cmljdFxuICAgIC8vIGJlY2F1c2UgY2FsbGVycyB1c2UgaXQgYXQgYnl0ZS12YWxpZGF0aW9uIGJvdW5kYXJpZXMgYmVmb3JlIG11dGF0aW5nIHRoZSBkZXRhY2hlZCBjb3B5LlxuICAgIHJldHVybiBVaW50OEFycmF5LmZyb20oYWJ5dGVzKGJ5dGVzKSk7XG59XG4vKipcbiAqIEFzc2VydHMgc29tZXRoaW5nIGlzIGEgd3JhcHBlZCBoYXNoIGNvbnN0cnVjdG9yLlxuICogQHBhcmFtIGggLSBoYXNoIGNvbnN0cnVjdG9yIHRvIHZhbGlkYXRlXG4gKiBAdGhyb3dzIE9uIHdyb25nIGFyZ3VtZW50IHR5cGVzIG9yIGludmFsaWQgaGFzaCB3cmFwcGVyIHNoYXBlLiB7QGxpbmsgVHlwZUVycm9yfVxuICogQHRocm93cyBPbiBpbnZhbGlkIGhhc2ggbWV0YWRhdGEgcmFuZ2VzIG9yIHZhbHVlcy4ge0BsaW5rIFJhbmdlRXJyb3J9XG4gKiBAdGhyb3dzIElmIHRoZSBoYXNoIG1ldGFkYXRhIGFsbG93cyBlbXB0eSBvdXRwdXRzIG9yIGJsb2NrIHNpemVzLiB7QGxpbmsgRXJyb3J9XG4gKiBAZXhhbXBsZVxuICogVmFsaWRhdGUgYSBjYWxsYWJsZSBoYXNoIHdyYXBwZXIuXG4gKiBgYGB0c1xuICogaW1wb3J0IHsgYWhhc2ggfSBmcm9tICdAbm9ibGUvaGFzaGVzL3V0aWxzLmpzJztcbiAqIGltcG9ydCB7IHNoYTI1NiB9IGZyb20gJ0Bub2JsZS9oYXNoZXMvc2hhMi5qcyc7XG4gKiBhaGFzaChzaGEyNTYpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhaGFzaChoKSB7XG4gICAgaWYgKHR5cGVvZiBoICE9PSAnZnVuY3Rpb24nIHx8IHR5cGVvZiBoLmNyZWF0ZSAhPT0gJ2Z1bmN0aW9uJylcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignSGFzaCBtdXN0IHdyYXBwZWQgYnkgdXRpbHMuY3JlYXRlSGFzaGVyJyk7XG4gICAgYW51bWJlcihoLm91dHB1dExlbik7XG4gICAgYW51bWJlcihoLmJsb2NrTGVuKTtcbiAgICAvLyBITUFDIGFuZCBLREYgY2FsbGVycyB0cmVhdCB0aGVzZSBhcyByZWFsIGJ5dGUgbGVuZ3RoczsgYWxsb3dpbmcgemVybyBsZXRzIGZha2Ugd3JhcHBlcnMgcGFzc1xuICAgIC8vIHZhbGlkYXRpb24gYW5kIGNhbiBwcm9kdWNlIGVtcHR5IG91dHB1dHMgaW5zdGVhZCBvZiBmYWlsaW5nIGZhc3QuXG4gICAgaWYgKGgub3V0cHV0TGVuIDwgMSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdcIm91dHB1dExlblwiIG11c3QgYmUgPj0gMScpO1xuICAgIGlmIChoLmJsb2NrTGVuIDwgMSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdcImJsb2NrTGVuXCIgbXVzdCBiZSA+PSAxJyk7XG59XG4vKipcbiAqIEFzc2VydHMgYSBoYXNoIGluc3RhbmNlIGhhcyBub3QgYmVlbiBkZXN0cm95ZWQgb3IgZmluaXNoZWQuXG4gKiBAcGFyYW0gaW5zdGFuY2UgLSBoYXNoIGluc3RhbmNlIHRvIHZhbGlkYXRlXG4gKiBAcGFyYW0gY2hlY2tGaW5pc2hlZCAtIHdoZXRoZXIgdG8gcmVqZWN0IGZpbmFsaXplZCBpbnN0YW5jZXNcbiAqIEB0aHJvd3MgSWYgdGhlIGhhc2ggaW5zdGFuY2UgaGFzIGFscmVhZHkgYmVlbiBkZXN0cm95ZWQgb3IgZmluYWxpemVkLiB7QGxpbmsgRXJyb3J9XG4gKiBAZXhhbXBsZVxuICogVmFsaWRhdGUgdGhhdCBhIGhhc2ggaW5zdGFuY2UgaXMgc3RpbGwgdXNhYmxlLlxuICogYGBgdHNcbiAqIGltcG9ydCB7IGFleGlzdHMgfSBmcm9tICdAbm9ibGUvaGFzaGVzL3V0aWxzLmpzJztcbiAqIGltcG9ydCB7IHNoYTI1NiB9IGZyb20gJ0Bub2JsZS9oYXNoZXMvc2hhMi5qcyc7XG4gKiBjb25zdCBoYXNoID0gc2hhMjU2LmNyZWF0ZSgpO1xuICogYWV4aXN0cyhoYXNoKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYWV4aXN0cyhpbnN0YW5jZSwgY2hlY2tGaW5pc2hlZCA9IHRydWUpIHtcbiAgICBpZiAoaW5zdGFuY2UuZGVzdHJveWVkKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0hhc2ggaW5zdGFuY2UgaGFzIGJlZW4gZGVzdHJveWVkJyk7XG4gICAgaWYgKGNoZWNrRmluaXNoZWQgJiYgaW5zdGFuY2UuZmluaXNoZWQpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSGFzaCNkaWdlc3QoKSBoYXMgYWxyZWFkeSBiZWVuIGNhbGxlZCcpO1xufVxuLyoqXG4gKiBBc3NlcnRzIG91dHB1dCBpcyBhIHN1ZmZpY2llbnRseS1zaXplZCBieXRlIGFycmF5LlxuICogQHBhcmFtIG91dCAtIGRlc3RpbmF0aW9uIGJ1ZmZlclxuICogQHBhcmFtIGluc3RhbmNlIC0gaGFzaCBpbnN0YW5jZSBwcm92aWRpbmcgb3V0cHV0IGxlbmd0aFxuICogT3ZlcnNpemVkIGJ1ZmZlcnMgYXJlIGFsbG93ZWQ7IGRvd25zdHJlYW0gY29kZSBvbmx5IHByb21pc2VzIHRvIGZpbGwgdGhlIGZpcnN0IGBvdXRwdXRMZW5gIGJ5dGVzLlxuICogQHRocm93cyBPbiB3cm9uZyBhcmd1bWVudCB0eXBlcy4ge0BsaW5rIFR5cGVFcnJvcn1cbiAqIEB0aHJvd3MgT24gd3JvbmcgYXJndW1lbnQgcmFuZ2VzIG9yIHZhbHVlcy4ge0BsaW5rIFJhbmdlRXJyb3J9XG4gKiBAZXhhbXBsZVxuICogVmFsaWRhdGUgYSBjYWxsZXItcHJvdmlkZWQgZGlnZXN0IGJ1ZmZlci5cbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBhb3V0cHV0IH0gZnJvbSAnQG5vYmxlL2hhc2hlcy91dGlscy5qcyc7XG4gKiBpbXBvcnQgeyBzaGEyNTYgfSBmcm9tICdAbm9ibGUvaGFzaGVzL3NoYTIuanMnO1xuICogY29uc3QgaGFzaCA9IHNoYTI1Ni5jcmVhdGUoKTtcbiAqIGFvdXRwdXQobmV3IFVpbnQ4QXJyYXkoaGFzaC5vdXRwdXRMZW4pLCBoYXNoKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYW91dHB1dChvdXQsIGluc3RhbmNlKSB7XG4gICAgYWJ5dGVzKG91dCwgdW5kZWZpbmVkLCAnZGlnZXN0SW50bygpIG91dHB1dCcpO1xuICAgIGNvbnN0IG1pbiA9IGluc3RhbmNlLm91dHB1dExlbjtcbiAgICBpZiAob3V0Lmxlbmd0aCA8IG1pbikge1xuICAgICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignXCJkaWdlc3RJbnRvKCkgb3V0cHV0XCIgZXhwZWN0ZWQgdG8gYmUgb2YgbGVuZ3RoID49JyArIG1pbik7XG4gICAgfVxufVxuLyoqXG4gKiBDYXN0cyBhIHR5cGVkIGFycmF5IHZpZXcgdG8gVWludDhBcnJheS5cbiAqIEBwYXJhbSBhcnIgLSBzb3VyY2UgdHlwZWQgYXJyYXlcbiAqIEByZXR1cm5zIFVpbnQ4QXJyYXkgdmlldyBvdmVyIHRoZSBzYW1lIGJ1ZmZlci5cbiAqIEBleGFtcGxlXG4gKiBSZWludGVycHJldCBhIHR5cGVkIGFycmF5IGFzIGJ5dGVzLlxuICogYGBgdHNcbiAqIHU4KG5ldyBVaW50MzJBcnJheShbMSwgMl0pKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gdTgoYXJyKSB7XG4gICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KGFyci5idWZmZXIsIGFyci5ieXRlT2Zmc2V0LCBhcnIuYnl0ZUxlbmd0aCk7XG59XG4vKipcbiAqIENhc3RzIGEgdHlwZWQgYXJyYXkgdmlldyB0byBVaW50MzJBcnJheS5cbiAqIGBhcnIuYnl0ZU9mZnNldGAgbXVzdCBhbHJlYWR5IGJlIDQtYnl0ZSBhbGlnbmVkIG9yIHRoZSBwbGF0Zm9ybVxuICogVWludDMyQXJyYXkgY29uc3RydWN0b3Igd2lsbCB0aHJvdy5cbiAqIEBwYXJhbSBhcnIgLSBzb3VyY2UgdHlwZWQgYXJyYXlcbiAqIEByZXR1cm5zIFVpbnQzMkFycmF5IHZpZXcgb3ZlciB0aGUgc2FtZSBidWZmZXIuXG4gKiBAZXhhbXBsZVxuICogUmVpbnRlcnByZXQgYSBieXRlIGFycmF5IGFzIDMyLWJpdCB3b3Jkcy5cbiAqIGBgYHRzXG4gKiB1MzIobmV3IFVpbnQ4QXJyYXkoOCkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1MzIoYXJyKSB7XG4gICAgcmV0dXJuIG5ldyBVaW50MzJBcnJheShhcnIuYnVmZmVyLCBhcnIuYnl0ZU9mZnNldCwgTWF0aC5mbG9vcihhcnIuYnl0ZUxlbmd0aCAvIDQpKTtcbn1cbi8qKlxuICogWmVyb2l6ZXMgdHlwZWQgYXJyYXlzIGluIHBsYWNlLiBXYXJuaW5nOiBKUyBwcm92aWRlcyBubyBndWFyYW50ZWVzLlxuICogQHBhcmFtIGFycmF5cyAtIGFycmF5cyB0byBvdmVyd3JpdGUgd2l0aCB6ZXJvc1xuICogQGV4YW1wbGVcbiAqIFplcm9pemUgc2Vuc2l0aXZlIGJ1ZmZlcnMgaW4gcGxhY2UuXG4gKiBgYGB0c1xuICogY2xlYW4obmV3IFVpbnQ4QXJyYXkoWzEsIDIsIDNdKSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNsZWFuKC4uLmFycmF5cykge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyYXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGFycmF5c1tpXS5maWxsKDApO1xuICAgIH1cbn1cbi8qKlxuICogQ3JlYXRlcyBhIERhdGFWaWV3IGZvciBieXRlLWxldmVsIG1hbmlwdWxhdGlvbi5cbiAqIEBwYXJhbSBhcnIgLSBzb3VyY2UgdHlwZWQgYXJyYXlcbiAqIEByZXR1cm5zIERhdGFWaWV3IG92ZXIgdGhlIHNhbWUgYnVmZmVyIHJlZ2lvbi5cbiAqIEBleGFtcGxlXG4gKiBDcmVhdGUgYSBEYXRhVmlldyBvdmVyIGFuIGV4aXN0aW5nIGJ1ZmZlci5cbiAqIGBgYHRzXG4gKiBjcmVhdGVWaWV3KG5ldyBVaW50OEFycmF5KDQpKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlVmlldyhhcnIpIHtcbiAgICByZXR1cm4gbmV3IERhdGFWaWV3KGFyci5idWZmZXIsIGFyci5ieXRlT2Zmc2V0LCBhcnIuYnl0ZUxlbmd0aCk7XG59XG4vKipcbiAqIFJvdGF0ZS1yaWdodCBvcGVyYXRpb24gZm9yIHVpbnQzMiB2YWx1ZXMuXG4gKiBAcGFyYW0gd29yZCAtIHNvdXJjZSB3b3JkXG4gKiBAcGFyYW0gc2hpZnQgLSBzaGlmdCBhbW91bnQgaW4gYml0c1xuICogQHJldHVybnMgUm90YXRlZCB3b3JkLlxuICogQGV4YW1wbGVcbiAqIFJvdGF0ZSBhIDMyLWJpdCB3b3JkIHRvIHRoZSByaWdodC5cbiAqIGBgYHRzXG4gKiByb3RyKDB4MTIzNDU2NzgsIDgpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByb3RyKHdvcmQsIHNoaWZ0KSB7XG4gICAgcmV0dXJuICh3b3JkIDw8ICgzMiAtIHNoaWZ0KSkgfCAod29yZCA+Pj4gc2hpZnQpO1xufVxuLyoqXG4gKiBSb3RhdGUtbGVmdCBvcGVyYXRpb24gZm9yIHVpbnQzMiB2YWx1ZXMuXG4gKiBAcGFyYW0gd29yZCAtIHNvdXJjZSB3b3JkXG4gKiBAcGFyYW0gc2hpZnQgLSBzaGlmdCBhbW91bnQgaW4gYml0c1xuICogQHJldHVybnMgUm90YXRlZCB3b3JkLlxuICogQGV4YW1wbGVcbiAqIFJvdGF0ZSBhIDMyLWJpdCB3b3JkIHRvIHRoZSBsZWZ0LlxuICogYGBgdHNcbiAqIHJvdGwoMHgxMjM0NTY3OCwgOCk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJvdGwod29yZCwgc2hpZnQpIHtcbiAgICByZXR1cm4gKHdvcmQgPDwgc2hpZnQpIHwgKCh3b3JkID4+PiAoMzIgLSBzaGlmdCkpID4+PiAwKTtcbn1cbi8qKiBXaGV0aGVyIHRoZSBjdXJyZW50IHBsYXRmb3JtIGlzIGxpdHRsZS1lbmRpYW4uICovXG5leHBvcnQgY29uc3QgaXNMRSA9IC8qIEBfX1BVUkVfXyAqLyAoKCkgPT4gbmV3IFVpbnQ4QXJyYXkobmV3IFVpbnQzMkFycmF5KFsweDExMjIzMzQ0XSkuYnVmZmVyKVswXSA9PT0gMHg0NCkoKTtcbi8qKlxuICogQnl0ZS1zd2FwIG9wZXJhdGlvbiBmb3IgdWludDMyIHZhbHVlcy5cbiAqIEBwYXJhbSB3b3JkIC0gc291cmNlIHdvcmRcbiAqIEByZXR1cm5zIFdvcmQgd2l0aCByZXZlcnNlZCBieXRlIG9yZGVyLlxuICogQGV4YW1wbGVcbiAqIFJldmVyc2UgdGhlIGJ5dGUgb3JkZXIgb2YgYSAzMi1iaXQgd29yZC5cbiAqIGBgYHRzXG4gKiBieXRlU3dhcCgweDExMjIzMzQ0KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYnl0ZVN3YXAod29yZCkge1xuICAgIHJldHVybiAoKCh3b3JkIDw8IDI0KSAmIDB4ZmYwMDAwMDApIHxcbiAgICAgICAgKCh3b3JkIDw8IDgpICYgMHhmZjAwMDApIHxcbiAgICAgICAgKCh3b3JkID4+PiA4KSAmIDB4ZmYwMCkgfFxuICAgICAgICAoKHdvcmQgPj4+IDI0KSAmIDB4ZmYpKTtcbn1cbi8qKlxuICogQ29uZGl0aW9uYWxseSBieXRlLXN3YXBzIG9uZSAzMi1iaXQgd29yZCBvbiBiaWctZW5kaWFuIHBsYXRmb3Jtcy5cbiAqIEBwYXJhbSBuIC0gc291cmNlIHdvcmRcbiAqIEByZXR1cm5zIE9yaWdpbmFsIG9yIGJ5dGUtc3dhcHBlZCB3b3JkIGRlcGVuZGluZyBvbiBwbGF0Zm9ybSBlbmRpYW5uZXNzLlxuICogQGV4YW1wbGVcbiAqIE5vcm1hbGl6ZSBhIDMyLWJpdCB3b3JkIGZvciBob3N0IGVuZGlhbm5lc3MuXG4gKiBgYGB0c1xuICogc3dhcDhJZkJFKDB4MTEyMjMzNDQpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBzd2FwOElmQkUgPSBpc0xFXG4gICAgPyAobikgPT4gblxuICAgIDogKG4pID0+IGJ5dGVTd2FwKG4pID4+PiAwO1xuLyoqXG4gKiBCeXRlLXN3YXBzIGV2ZXJ5IHdvcmQgb2YgYSBVaW50MzJBcnJheSBpbiBwbGFjZS5cbiAqIEBwYXJhbSBhcnIgLSBhcnJheSB0byBtdXRhdGVcbiAqIEByZXR1cm5zIFRoZSBzYW1lIGFycmF5IGFmdGVyIG11dGF0aW9uOyBjYWxsZXJzIHBhc3MgbGl2ZSBzdGF0ZSBhcnJheXMgaGVyZS5cbiAqIEBleGFtcGxlXG4gKiBSZXZlcnNlIHRoZSBieXRlIG9yZGVyIG9mIGV2ZXJ5IHdvcmQgaW4gcGxhY2UuXG4gKiBgYGB0c1xuICogYnl0ZVN3YXAzMihuZXcgVWludDMyQXJyYXkoWzB4MTEyMjMzNDRdKSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ5dGVTd2FwMzIoYXJyKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnIubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgYXJyW2ldID0gYnl0ZVN3YXAoYXJyW2ldKTtcbiAgICB9XG4gICAgcmV0dXJuIGFycjtcbn1cbi8qKlxuICogQ29uZGl0aW9uYWxseSBieXRlLXN3YXBzIGEgVWludDMyQXJyYXkgb24gYmlnLWVuZGlhbiBwbGF0Zm9ybXMuXG4gKiBAcGFyYW0gdSAtIGFycmF5IHRvIG5vcm1hbGl6ZSBmb3IgaG9zdCBlbmRpYW5uZXNzXG4gKiBAcmV0dXJucyBPcmlnaW5hbCBvciBieXRlLXN3YXBwZWQgYXJyYXkgZGVwZW5kaW5nIG9uIHBsYXRmb3JtIGVuZGlhbm5lc3MuXG4gKiAgIE9uIGJpZy1lbmRpYW4gcnVudGltZXMgdGhpcyBtdXRhdGVzIGB1YCBpbiBwbGFjZSB2aWEgYGJ5dGVTd2FwMzIoLi4uKWAuXG4gKiBAZXhhbXBsZVxuICogTm9ybWFsaXplIGEgd29yZCBhcnJheSBmb3IgaG9zdCBlbmRpYW5uZXNzLlxuICogYGBgdHNcbiAqIHN3YXAzMklmQkUobmV3IFVpbnQzMkFycmF5KFsweDExMjIzMzQ0XSkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBzd2FwMzJJZkJFID0gaXNMRVxuICAgID8gKHUpID0+IHVcbiAgICA6IGJ5dGVTd2FwMzI7XG4vLyBCdWlsdC1pbiBoZXggY29udmVyc2lvbiBodHRwczovL2Nhbml1c2UuY29tL21kbi1qYXZhc2NyaXB0X2J1aWx0aW5zX3VpbnQ4YXJyYXlfZnJvbWhleFxuY29uc3QgaGFzSGV4QnVpbHRpbiA9IC8qIEBfX1BVUkVfXyAqLyAoKCkgPT4gXG4vLyBAdHMtaWdub3JlXG50eXBlb2YgVWludDhBcnJheS5mcm9tKFtdKS50b0hleCA9PT0gJ2Z1bmN0aW9uJyAmJiB0eXBlb2YgVWludDhBcnJheS5mcm9tSGV4ID09PSAnZnVuY3Rpb24nKSgpO1xuLy8gQXJyYXkgd2hlcmUgaW5kZXggMHhmMCAoMjQwKSBpcyBtYXBwZWQgdG8gc3RyaW5nICdmMCdcbmNvbnN0IGhleGVzID0gLyogQF9fUFVSRV9fICovIEFycmF5LmZyb20oeyBsZW5ndGg6IDI1NiB9LCAoXywgaSkgPT4gaS50b1N0cmluZygxNikucGFkU3RhcnQoMiwgJzAnKSk7XG4vKipcbiAqIENvbnZlcnQgYnl0ZSBhcnJheSB0byBoZXggc3RyaW5nLlxuICogVXNlcyB0aGUgYnVpbHQtaW4gZnVuY3Rpb24gd2hlbiBhdmFpbGFibGUgYW5kIGFzc3VtZXMgaXQgbWF0Y2hlcyB0aGUgdGVzdGVkXG4gKiBmYWxsYmFjayBzZW1hbnRpY3MuXG4gKiBAcGFyYW0gYnl0ZXMgLSBieXRlcyB0byBlbmNvZGVcbiAqIEByZXR1cm5zIExvd2VyY2FzZSBoZXhhZGVjaW1hbCBzdHJpbmcuXG4gKiBAdGhyb3dzIE9uIHdyb25nIGFyZ3VtZW50IHR5cGVzLiB7QGxpbmsgVHlwZUVycm9yfVxuICogQGV4YW1wbGVcbiAqIENvbnZlcnQgYnl0ZXMgdG8gbG93ZXJjYXNlIGhleGFkZWNpbWFsLlxuICogYGBgdHNcbiAqIGJ5dGVzVG9IZXgoVWludDhBcnJheS5mcm9tKFsweGNhLCAweGZlLCAweDAxLCAweDIzXSkpOyAvLyAnY2FmZTAxMjMnXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ5dGVzVG9IZXgoYnl0ZXMpIHtcbiAgICBhYnl0ZXMoYnl0ZXMpO1xuICAgIC8vIEB0cy1pZ25vcmVcbiAgICBpZiAoaGFzSGV4QnVpbHRpbilcbiAgICAgICAgcmV0dXJuIGJ5dGVzLnRvSGV4KCk7XG4gICAgLy8gcHJlLWNhY2hpbmcgaW1wcm92ZXMgdGhlIHNwZWVkIDZ4XG4gICAgbGV0IGhleCA9ICcnO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaGV4ICs9IGhleGVzW2J5dGVzW2ldXTtcbiAgICB9XG4gICAgcmV0dXJuIGhleDtcbn1cbi8vIFdlIHVzZSBvcHRpbWl6ZWQgdGVjaG5pcXVlIHRvIGNvbnZlcnQgaGV4IHN0cmluZyB0byBieXRlIGFycmF5XG5jb25zdCBhc2NpaXMgPSB7IF8wOiA0OCwgXzk6IDU3LCBBOiA2NSwgRjogNzAsIGE6IDk3LCBmOiAxMDIgfTtcbmZ1bmN0aW9uIGFzY2lpVG9CYXNlMTYoY2gpIHtcbiAgICBpZiAoY2ggPj0gYXNjaWlzLl8wICYmIGNoIDw9IGFzY2lpcy5fOSlcbiAgICAgICAgcmV0dXJuIGNoIC0gYXNjaWlzLl8wOyAvLyAnMicgPT4gNTAtNDhcbiAgICBpZiAoY2ggPj0gYXNjaWlzLkEgJiYgY2ggPD0gYXNjaWlzLkYpXG4gICAgICAgIHJldHVybiBjaCAtIChhc2NpaXMuQSAtIDEwKTsgLy8gJ0InID0+IDY2LSg2NS0xMClcbiAgICBpZiAoY2ggPj0gYXNjaWlzLmEgJiYgY2ggPD0gYXNjaWlzLmYpXG4gICAgICAgIHJldHVybiBjaCAtIChhc2NpaXMuYSAtIDEwKTsgLy8gJ2InID0+IDk4LSg5Ny0xMClcbiAgICByZXR1cm47XG59XG4vKipcbiAqIENvbnZlcnQgaGV4IHN0cmluZyB0byBieXRlIGFycmF5LiBVc2VzIGJ1aWx0LWluIGZ1bmN0aW9uLCB3aGVuIGF2YWlsYWJsZS5cbiAqIEBwYXJhbSBoZXggLSBoZXhhZGVjaW1hbCBzdHJpbmcgdG8gZGVjb2RlXG4gKiBAcmV0dXJucyBEZWNvZGVkIGJ5dGVzLlxuICogQHRocm93cyBPbiB3cm9uZyBhcmd1bWVudCB0eXBlcy4ge0BsaW5rIFR5cGVFcnJvcn1cbiAqIEB0aHJvd3MgT24gd3JvbmcgYXJndW1lbnQgcmFuZ2VzIG9yIHZhbHVlcy4ge0BsaW5rIFJhbmdlRXJyb3J9XG4gKiBAZXhhbXBsZVxuICogRGVjb2RlIGxvd2VyY2FzZSBoZXhhZGVjaW1hbCBpbnRvIGJ5dGVzLlxuICogYGBgdHNcbiAqIGhleFRvQnl0ZXMoJ2NhZmUwMTIzJyk7IC8vIFVpbnQ4QXJyYXkuZnJvbShbMHhjYSwgMHhmZSwgMHgwMSwgMHgyM10pXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhleFRvQnl0ZXMoaGV4KSB7XG4gICAgaWYgKHR5cGVvZiBoZXggIT09ICdzdHJpbmcnKVxuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdoZXggc3RyaW5nIGV4cGVjdGVkLCBnb3QgJyArIHR5cGVvZiBoZXgpO1xuICAgIGlmIChoYXNIZXhCdWlsdGluKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gVWludDhBcnJheS5mcm9tSGV4KGhleCk7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBTeW50YXhFcnJvcilcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihlcnJvci5tZXNzYWdlKTtcbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGhsID0gaGV4Lmxlbmd0aDtcbiAgICBjb25zdCBhbCA9IGhsIC8gMjtcbiAgICBpZiAoaGwgJSAyKVxuICAgICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignaGV4IHN0cmluZyBleHBlY3RlZCwgZ290IHVucGFkZGVkIGhleCBvZiBsZW5ndGggJyArIGhsKTtcbiAgICBjb25zdCBhcnJheSA9IG5ldyBVaW50OEFycmF5KGFsKTtcbiAgICBmb3IgKGxldCBhaSA9IDAsIGhpID0gMDsgYWkgPCBhbDsgYWkrKywgaGkgKz0gMikge1xuICAgICAgICBjb25zdCBuMSA9IGFzY2lpVG9CYXNlMTYoaGV4LmNoYXJDb2RlQXQoaGkpKTtcbiAgICAgICAgY29uc3QgbjIgPSBhc2NpaVRvQmFzZTE2KGhleC5jaGFyQ29kZUF0KGhpICsgMSkpO1xuICAgICAgICBpZiAobjEgPT09IHVuZGVmaW5lZCB8fCBuMiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBjb25zdCBjaGFyID0gaGV4W2hpXSArIGhleFtoaSArIDFdO1xuICAgICAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2hleCBzdHJpbmcgZXhwZWN0ZWQsIGdvdCBub24taGV4IGNoYXJhY3RlciBcIicgKyBjaGFyICsgJ1wiIGF0IGluZGV4ICcgKyBoaSk7XG4gICAgICAgIH1cbiAgICAgICAgYXJyYXlbYWldID0gbjEgKiAxNiArIG4yOyAvLyBtdWx0aXBseSBmaXJzdCBvY3RldCwgZS5nLiAnYTMnID0+IDEwKjE2KzMgPT4gMTYwICsgMyA9PiAxNjNcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5O1xufVxuLyoqXG4gKiBUaGVyZSBpcyBubyBzZXRJbW1lZGlhdGUgaW4gYnJvd3NlciBhbmQgc2V0VGltZW91dCBpcyBzbG93LlxuICogVGhpcyB5aWVsZHMgdG8gdGhlIFByb21pc2UvbWljcm90YXNrIHNjaGVkdWxlciBxdWV1ZSwgbm90IHRvIHRpbWVycyBvciB0aGVcbiAqIGZ1bGwgbWFjcm90YXNrIGV2ZW50IGxvb3AuXG4gKiBAZXhhbXBsZVxuICogWWllbGQgdG8gdGhlIG5leHQgc2NoZWR1bGVyIHRpY2suXG4gKiBgYGB0c1xuICogYXdhaXQgbmV4dFRpY2soKTtcbiAqIGBgYFxuICovXG5leHBvcnQgY29uc3QgbmV4dFRpY2sgPSBhc3luYyAoKSA9PiB7IH07XG4vKipcbiAqIFJldHVybnMgY29udHJvbCB0byB0aGUgUHJvbWlzZS9taWNyb3Rhc2sgc2NoZWR1bGVyIGV2ZXJ5IGB0aWNrYFxuICogbWlsbGlzZWNvbmRzIHRvIGF2b2lkIGJsb2NraW5nIGxvbmcgbG9vcHMuXG4gKiBAcGFyYW0gaXRlcnMgLSBudW1iZXIgb2YgbG9vcCBpdGVyYXRpb25zIHRvIHJ1blxuICogQHBhcmFtIHRpY2sgLSBtYXhpbXVtIHRpbWUgc2xpY2UgaW4gbWlsbGlzZWNvbmRzXG4gKiBAcGFyYW0gY2IgLSBjYWxsYmFjayBleGVjdXRlZCBvbiBlYWNoIGl0ZXJhdGlvblxuICogQGV4YW1wbGVcbiAqIFJ1biBhIGxvb3AgdGhhdCBwZXJpb2RpY2FsbHkgeWllbGRzIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AuXG4gKiBgYGB0c1xuICogYXdhaXQgYXN5bmNMb29wKDIsIDAsICgpID0+IHt9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYXN5bmNMb29wKGl0ZXJzLCB0aWNrLCBjYikge1xuICAgIGxldCB0cyA9IERhdGUubm93KCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpdGVyczsgaSsrKSB7XG4gICAgICAgIGNiKGkpO1xuICAgICAgICAvLyBEYXRlLm5vdygpIGlzIG5vdCBtb25vdG9uaWMsIHNvIGluIGNhc2UgaWYgY2xvY2sgZ29lcyBiYWNrd2FyZHMgd2UgcmV0dXJuIHJldHVybiBjb250cm9sIHRvb1xuICAgICAgICBjb25zdCBkaWZmID0gRGF0ZS5ub3coKSAtIHRzO1xuICAgICAgICBpZiAoZGlmZiA+PSAwICYmIGRpZmYgPCB0aWNrKVxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIGF3YWl0IG5leHRUaWNrKCk7XG4gICAgICAgIHRzICs9IGRpZmY7XG4gICAgfVxufVxuLyoqXG4gKiBDb252ZXJ0cyBzdHJpbmcgdG8gYnl0ZXMgdXNpbmcgVVRGOCBlbmNvZGluZy5cbiAqIEJ1aWx0LWluIGRvZXNuJ3QgdmFsaWRhdGUgaW5wdXQgdG8gYmUgc3RyaW5nOiB3ZSBkbyB0aGUgY2hlY2suXG4gKiBOb24tQVNDSUkgZGV0YWlscyBhcmUgZGVsZWdhdGVkIHRvIHRoZSBwbGF0Zm9ybSBgVGV4dEVuY29kZXJgLlxuICogQHBhcmFtIHN0ciAtIHN0cmluZyB0byBlbmNvZGVcbiAqIEByZXR1cm5zIFVURi04IGVuY29kZWQgYnl0ZXMuXG4gKiBAdGhyb3dzIE9uIHdyb25nIGFyZ3VtZW50IHR5cGVzLiB7QGxpbmsgVHlwZUVycm9yfVxuICogQGV4YW1wbGVcbiAqIEVuY29kZSBhIHN0cmluZyBhcyBVVEYtOCBieXRlcy5cbiAqIGBgYHRzXG4gKiB1dGY4VG9CeXRlcygnYWJjJyk7IC8vIFVpbnQ4QXJyYXkuZnJvbShbOTcsIDk4LCA5OV0pXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHV0ZjhUb0J5dGVzKHN0cikge1xuICAgIGlmICh0eXBlb2Ygc3RyICE9PSAnc3RyaW5nJylcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc3RyaW5nIGV4cGVjdGVkJyk7XG4gICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShzdHIpKTsgLy8gaHR0cHM6Ly9idWd6aWwubGEvMTY4MTgwOVxufVxuLyoqXG4gKiBIZWxwZXIgZm9yIEtERnM6IGNvbnN1bWVzIFVpbnQ4QXJyYXkgb3Igc3RyaW5nLlxuICogU3RyaW5nIGlucHV0cyBhcmUgVVRGLTggZW5jb2RlZDsgYnl0ZS1hcnJheSBpbnB1dHMgc3RheSBhbGlhc2VkIHRvIHRoZSBjYWxsZXIgYnVmZmVyLlxuICogQHBhcmFtIGRhdGEgLSB1c2VyLXByb3ZpZGVkIEtERiBpbnB1dFxuICogQHBhcmFtIGVycm9yVGl0bGUgLSBsYWJlbCBpbmNsdWRlZCBpbiB0aHJvd24gZXJyb3JzXG4gKiBAcmV0dXJucyBCeXRlIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dC5cbiAqIEB0aHJvd3MgT24gd3JvbmcgYXJndW1lbnQgdHlwZXMuIHtAbGluayBUeXBlRXJyb3J9XG4gKiBAZXhhbXBsZVxuICogTm9ybWFsaXplIEtERiBpbnB1dCB0byBieXRlcy5cbiAqIGBgYHRzXG4gKiBrZGZJbnB1dFRvQnl0ZXMoJ3Bhc3N3b3JkJyk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGtkZklucHV0VG9CeXRlcyhkYXRhLCBlcnJvclRpdGxlID0gJycpIHtcbiAgICBpZiAodHlwZW9mIGRhdGEgPT09ICdzdHJpbmcnKVxuICAgICAgICByZXR1cm4gdXRmOFRvQnl0ZXMoZGF0YSk7XG4gICAgcmV0dXJuIGFieXRlcyhkYXRhLCB1bmRlZmluZWQsIGVycm9yVGl0bGUpO1xufVxuLyoqXG4gKiBDb3BpZXMgc2V2ZXJhbCBVaW50OEFycmF5cyBpbnRvIG9uZS5cbiAqIEBwYXJhbSBhcnJheXMgLSBhcnJheXMgdG8gY29uY2F0ZW5hdGVcbiAqIEByZXR1cm5zIENvbmNhdGVuYXRlZCBieXRlIGFycmF5LlxuICogQHRocm93cyBPbiB3cm9uZyBhcmd1bWVudCB0eXBlcy4ge0BsaW5rIFR5cGVFcnJvcn1cbiAqIEBleGFtcGxlXG4gKiBDb25jYXRlbmF0ZSBtdWx0aXBsZSBieXRlIGFycmF5cy5cbiAqIGBgYHRzXG4gKiBjb25jYXRCeXRlcyhuZXcgVWludDhBcnJheShbMV0pLCBuZXcgVWludDhBcnJheShbMl0pKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY29uY2F0Qnl0ZXMoLi4uYXJyYXlzKSB7XG4gICAgbGV0IHN1bSA9IDA7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY29uc3QgYSA9IGFycmF5c1tpXTtcbiAgICAgICAgYWJ5dGVzKGEpO1xuICAgICAgICBzdW0gKz0gYS5sZW5ndGg7XG4gICAgfVxuICAgIGNvbnN0IHJlcyA9IG5ldyBVaW50OEFycmF5KHN1bSk7XG4gICAgZm9yIChsZXQgaSA9IDAsIHBhZCA9IDA7IGkgPCBhcnJheXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY29uc3QgYSA9IGFycmF5c1tpXTtcbiAgICAgICAgcmVzLnNldChhLCBwYWQpO1xuICAgICAgICBwYWQgKz0gYS5sZW5ndGg7XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG4vKipcbiAqIE1lcmdlcyBkZWZhdWx0IG9wdGlvbnMgYW5kIHBhc3NlZCBvcHRpb25zLlxuICogQHBhcmFtIGRlZmF1bHRzIC0gYmFzZSBvcHRpb24gb2JqZWN0XG4gKiBAcGFyYW0gb3B0cyAtIHVzZXIgb3ZlcnJpZGVzXG4gKiBAcmV0dXJucyBNZXJnZWQgb3B0aW9uIG9iamVjdC4gVGhlIG1lcmdlIG11dGF0ZXMgYGRlZmF1bHRzYCBpbiBwbGFjZS5cbiAqIEB0aHJvd3MgT24gd3JvbmcgYXJndW1lbnQgdHlwZXMuIHtAbGluayBUeXBlRXJyb3J9XG4gKiBAZXhhbXBsZVxuICogTWVyZ2UgdXNlciBvdmVycmlkZXMgb250byBkZWZhdWx0IG9wdGlvbnMuXG4gKiBgYGB0c1xuICogY2hlY2tPcHRzKHsgZGtMZW46IDMyIH0sIHsgYXN5bmNUaWNrOiAxMCB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY2hlY2tPcHRzKGRlZmF1bHRzLCBvcHRzKSB7XG4gICAgaWYgKG9wdHMgIT09IHVuZGVmaW5lZCAmJiB7fS50b1N0cmluZy5jYWxsKG9wdHMpICE9PSAnW29iamVjdCBPYmplY3RdJylcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignb3B0aW9ucyBtdXN0IGJlIG9iamVjdCBvciB1bmRlZmluZWQnKTtcbiAgICBjb25zdCBtZXJnZWQgPSBPYmplY3QuYXNzaWduKGRlZmF1bHRzLCBvcHRzKTtcbiAgICByZXR1cm4gbWVyZ2VkO1xufVxuLyoqXG4gKiBDcmVhdGVzIGEgY2FsbGFibGUgaGFzaCBmdW5jdGlvbiBmcm9tIGEgc3RhdGVmdWwgY2xhc3MgY29uc3RydWN0b3IuXG4gKiBAcGFyYW0gaGFzaENvbnMgLSBoYXNoIGNvbnN0cnVjdG9yIG9yIGZhY3RvcnlcbiAqIEBwYXJhbSBpbmZvIC0gb3B0aW9uYWwgbWV0YWRhdGEgc3VjaCBhcyBERVIgT0lEXG4gKiBAcmV0dXJucyBGcm96ZW4gY2FsbGFibGUgaGFzaCB3cmFwcGVyIHdpdGggYC5jcmVhdGUoKWAuXG4gKiAgIFdyYXBwZXIgY29uc3RydWN0aW9uIGVhZ2VybHkgY2FsbHMgYGhhc2hDb25zKHVuZGVmaW5lZClgIG9uY2UgdG8gcmVhZFxuICogICBgb3V0cHV0TGVuYCAvIGBibG9ja0xlbmAsIHNvIGNvbnN0cnVjdG9yIHNpZGUgZWZmZWN0cyBoYXBwZW4gYXQgbW9kdWxlXG4gKiAgIGluaXQgdGltZS5cbiAqIEBleGFtcGxlXG4gKiBXcmFwIGEgc3RhdGVmdWwgaGFzaCBjb25zdHJ1Y3RvciBpbnRvIGEgY2FsbGFibGUgaGVscGVyLlxuICogYGBgdHNcbiAqIGltcG9ydCB7IGNyZWF0ZUhhc2hlciB9IGZyb20gJ0Bub2JsZS9oYXNoZXMvdXRpbHMuanMnO1xuICogaW1wb3J0IHsgc2hhMjU2IH0gZnJvbSAnQG5vYmxlL2hhc2hlcy9zaGEyLmpzJztcbiAqIGNvbnN0IHdyYXBwZWQgPSBjcmVhdGVIYXNoZXIoc2hhMjU2LmNyZWF0ZSwgeyBvaWQ6IHNoYTI1Ni5vaWQgfSk7XG4gKiB3cmFwcGVkKG5ldyBVaW50OEFycmF5KFsxXSkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVIYXNoZXIoaGFzaENvbnMsIGluZm8gPSB7fSkge1xuICAgIGNvbnN0IGhhc2hDID0gKG1zZywgb3B0cykgPT4gaGFzaENvbnMob3B0cylcbiAgICAgICAgLnVwZGF0ZShtc2cpXG4gICAgICAgIC5kaWdlc3QoKTtcbiAgICBjb25zdCB0bXAgPSBoYXNoQ29ucyh1bmRlZmluZWQpO1xuICAgIGhhc2hDLm91dHB1dExlbiA9IHRtcC5vdXRwdXRMZW47XG4gICAgaGFzaEMuYmxvY2tMZW4gPSB0bXAuYmxvY2tMZW47XG4gICAgaGFzaEMuY2FuWE9GID0gdG1wLmNhblhPRjtcbiAgICBoYXNoQy5jcmVhdGUgPSAob3B0cykgPT4gaGFzaENvbnMob3B0cyk7XG4gICAgT2JqZWN0LmFzc2lnbihoYXNoQywgaW5mbyk7XG4gICAgcmV0dXJuIE9iamVjdC5mcmVlemUoaGFzaEMpO1xufVxuLyoqXG4gKiBDcnlwdG9ncmFwaGljYWxseSBzZWN1cmUgUFJORyBiYWNrZWQgYnkgYGNyeXB0by5nZXRSYW5kb21WYWx1ZXNgLlxuICogQHBhcmFtIGJ5dGVzTGVuZ3RoIC0gbnVtYmVyIG9mIHJhbmRvbSBieXRlcyB0byBnZW5lcmF0ZVxuICogQHJldHVybnMgUmFuZG9tIGJ5dGVzLlxuICogVGhlIHBsYXRmb3JtIGBnZXRSYW5kb21WYWx1ZXMoKWAgaW1wbGVtZW50YXRpb24gc3RpbGwgZGVmaW5lcyBhbnlcbiAqIHNpbmdsZS1jYWxsIGxlbmd0aCBjYXAsIGFuZCB0aGlzIGhlbHBlciByZWplY3RzIG92ZXJzaXplIHJlcXVlc3RzXG4gKiB3aXRoIGEgc3RhYmxlIGxpYnJhcnkgYFJhbmdlRXJyb3JgIGluc3RlYWQgb2YgaG9zdC1zcGVjaWZpYyBlcnJvcnMuXG4gKiBAdGhyb3dzIE9uIHdyb25nIGFyZ3VtZW50IHR5cGVzLiB7QGxpbmsgVHlwZUVycm9yfVxuICogQHRocm93cyBPbiB3cm9uZyBhcmd1bWVudCByYW5nZXMgb3IgdmFsdWVzLiB7QGxpbmsgUmFuZ2VFcnJvcn1cbiAqIEB0aHJvd3MgSWYgdGhlIGN1cnJlbnQgcnVudGltZSBkb2VzIG5vdCBwcm92aWRlIGBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzYC4ge0BsaW5rIEVycm9yfVxuICogQGV4YW1wbGVcbiAqIEdlbmVyYXRlIGEgZnJlc2ggcmFuZG9tIGtleSBvciBub25jZS5cbiAqIGBgYHRzXG4gKiBjb25zdCBrZXkgPSByYW5kb21CeXRlcygxNik7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJhbmRvbUJ5dGVzKGJ5dGVzTGVuZ3RoID0gMzIpIHtcbiAgICAvLyBNYXRjaCB0aGUgcmVwbydzIG90aGVyIGxlbmd0aC10YWtpbmcgaGVscGVycyBpbnN0ZWFkIG9mIHJlbHlpbmcgb24gVWludDhBcnJheSBjb2VyY2lvbi5cbiAgICBhbnVtYmVyKGJ5dGVzTGVuZ3RoLCAnYnl0ZXNMZW5ndGgnKTtcbiAgICBjb25zdCBjciA9IHR5cGVvZiBnbG9iYWxUaGlzID09PSAnb2JqZWN0JyA/IGdsb2JhbFRoaXMuY3J5cHRvIDogbnVsbDtcbiAgICBpZiAodHlwZW9mIGNyPy5nZXRSYW5kb21WYWx1ZXMgIT09ICdmdW5jdGlvbicpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignY3J5cHRvLmdldFJhbmRvbVZhbHVlcyBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICAvLyBXZWIgQ3J5cHRvZ3JhcGh5IEFQSSBMZXZlbCAyIMKnMTAuMS4xOlxuICAgIC8vIGlmIGBieXRlTGVuZ3RoID4gNjU1MzZgLCB0aHJvdyBgUXVvdGFFeGNlZWRlZEVycm9yYC5cbiAgICAvLyBLZWVwIHRoZSBndWFyZCBleHBsaWNpdCBzbyBjYWxsZXJzIGNhbiBzZWUgdGhlIHF1b3RhIGluIGNvZGVcbiAgICAvLyBpbnN0ZWFkIG9mIGRpc2NvdmVyaW5nIGl0IGJ5IHJlYWRpbmcgdGhlIHNwZWMgb3IgaG9zdCBlcnJvcnMuXG4gICAgLy8gVGhpcyB3cmFwcGVyIHN1cmZhY2VzIHRoZSBzYW1lIHF1b3RhIGFzIGEgc3RhYmxlIGxpYnJhcnkgUmFuZ2VFcnJvci5cbiAgICBpZiAoYnl0ZXNMZW5ndGggPiA2NTUzNilcbiAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoYFwiYnl0ZXNMZW5ndGhcIiBleHBlY3RlZCA8PSA2NTUzNiwgZ290ICR7Ynl0ZXNMZW5ndGh9YCk7XG4gICAgcmV0dXJuIGNyLmdldFJhbmRvbVZhbHVlcyhuZXcgVWludDhBcnJheShieXRlc0xlbmd0aCkpO1xufVxuLyoqXG4gKiBDcmVhdGVzIE9JRCBtZXRhZGF0YSBmb3IgTklTVCBoYXNoZXMgd2l0aCBwcmVmaXggYDA2IDA5IDYwIDg2IDQ4IDAxIDY1IDAzIDA0IDAyYC5cbiAqIEBwYXJhbSBzdWZmaXggLSBmaW5hbCBPSUQgYnl0ZSBmb3IgdGhlIHNlbGVjdGVkIGhhc2guXG4gKiAgIFRoZSBoZWxwZXIgYWNjZXB0cyBhbnkgYnl0ZSBldmVuIHRob3VnaCBvbmx5IHRoZSBkb2N1bWVudGVkIE5JU1QgaGFzaFxuICogICBzdWZmaXhlcyBhcmUgbWVhbmluZ2Z1bCBkb3duc3RyZWFtLlxuICogQHJldHVybnMgT2JqZWN0IGNvbnRhaW5pbmcgdGhlIERFUi1lbmNvZGVkIE9JRC5cbiAqIEBleGFtcGxlXG4gKiBCdWlsZCBPSUQgbWV0YWRhdGEgZm9yIGEgTklTVCBoYXNoLlxuICogYGBgdHNcbiAqIG9pZE5pc3QoMHgwMSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IG9pZE5pc3QgPSAoc3VmZml4KSA9PiAoe1xuICAgIC8vIEN1cnJlbnQgTklTVCBoYXNoQWxncyBzdWZmaXhlcyB1c2VkIGhlcmUgZml0IGluIG9uZSBERVIgc3ViaWRlbnRpZmllciBvY3RldC5cbiAgICAvLyBMYXJnZXIgc3VmZml4IHZhbHVlcyB3b3VsZCBuZWVkIGJhc2UtMTI4IE9JRCBlbmNvZGluZyBhbmQgYSBkaWZmZXJlbnQgbGVuZ3RoIGJ5dGUuXG4gICAgb2lkOiBVaW50OEFycmF5LmZyb20oWzB4MDYsIDB4MDksIDB4NjAsIDB4ODYsIDB4NDgsIDB4MDEsIDB4NjUsIDB4MDMsIDB4MDQsIDB4MDIsIHN1ZmZpeF0pLFxufSk7XG4vLyMgc291cmNlTWFwcGluZ1VSTD11dGlscy5qcy5tYXAiLCIvKipcbiAqIEludGVybmFsIGhlbHBlcnMgZm9yIGJsYWtlIGhhc2guXG4gKiBAbW9kdWxlXG4gKi9cbmltcG9ydCB7IHJvdHIgfSBmcm9tIFwiLi91dGlscy5qc1wiO1xuLyoqXG4gKiBJbnRlcm5hbCBibGFrZSBwZXJtdXRhdGlvbiB0YWJsZS5cbiAqIFJvd3MgYDAuLjlgIHNlcnZlIEJMQUtFMnMsIHJvd3MgYDAuLjExYCBzZXJ2ZSBCTEFLRTJiIHdpdGggYDEwLi4xMSA9IDAuLjFgLCBhbmQgQmxha2UxIGFsc29cbiAqIHJldXNlcyB0aGUgbGF0ZXIgcm93cyBzaG93biBiZWxvdy4gQmxha2UxIGV4cGFuZHMgcm91bmRzIGAxMC4uMTVgIGFzIGBTSUdNQVtpICUgMTBdYCwgc28gcm93c1xuICogYDEwLi4xNWAgaW50ZW50aW9uYWxseSByZXBlYXQgcm93cyBgMC4uNWAgZm9yIHRoZSAxNC1yb3VuZCAoMjU2KSBhbmQgMTYtcm91bmQgKDUxMikgdmFyaWFudHMuXG4gKi9cbi8vIHByZXR0aWVyLWlnbm9yZVxuZXhwb3J0IGNvbnN0IEJTSUdNQSA9IC8qIEBfX1BVUkVfXyAqLyBVaW50OEFycmF5LmZyb20oW1xuICAgIDAsIDEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTUsXG4gICAgMTQsIDEwLCA0LCA4LCA5LCAxNSwgMTMsIDYsIDEsIDEyLCAwLCAyLCAxMSwgNywgNSwgMyxcbiAgICAxMSwgOCwgMTIsIDAsIDUsIDIsIDE1LCAxMywgMTAsIDE0LCAzLCA2LCA3LCAxLCA5LCA0LFxuICAgIDcsIDksIDMsIDEsIDEzLCAxMiwgMTEsIDE0LCAyLCA2LCA1LCAxMCwgNCwgMCwgMTUsIDgsXG4gICAgOSwgMCwgNSwgNywgMiwgNCwgMTAsIDE1LCAxNCwgMSwgMTEsIDEyLCA2LCA4LCAzLCAxMyxcbiAgICAyLCAxMiwgNiwgMTAsIDAsIDExLCA4LCAzLCA0LCAxMywgNywgNSwgMTUsIDE0LCAxLCA5LFxuICAgIDEyLCA1LCAxLCAxNSwgMTQsIDEzLCA0LCAxMCwgMCwgNywgNiwgMywgOSwgMiwgOCwgMTEsXG4gICAgMTMsIDExLCA3LCAxNCwgMTIsIDEsIDMsIDksIDUsIDAsIDE1LCA0LCA4LCA2LCAyLCAxMCxcbiAgICA2LCAxNSwgMTQsIDksIDExLCAzLCAwLCA4LCAxMiwgMiwgMTMsIDcsIDEsIDQsIDEwLCA1LFxuICAgIDEwLCAyLCA4LCA0LCA3LCA2LCAxLCA1LCAxNSwgMTEsIDksIDE0LCAzLCAxMiwgMTMsIDAsXG4gICAgMCwgMSwgMiwgMywgNCwgNSwgNiwgNywgOCwgOSwgMTAsIDExLCAxMiwgMTMsIDE0LCAxNSxcbiAgICAxNCwgMTAsIDQsIDgsIDksIDE1LCAxMywgNiwgMSwgMTIsIDAsIDIsIDExLCA3LCA1LCAzLFxuICAgIC8vIEJsYWtlMSwgdW51c2VkIGluIG90aGVyc1xuICAgIDExLCA4LCAxMiwgMCwgNSwgMiwgMTUsIDEzLCAxMCwgMTQsIDMsIDYsIDcsIDEsIDksIDQsXG4gICAgNywgOSwgMywgMSwgMTMsIDEyLCAxMSwgMTQsIDIsIDYsIDUsIDEwLCA0LCAwLCAxNSwgOCxcbiAgICA5LCAwLCA1LCA3LCAyLCA0LCAxMCwgMTUsIDE0LCAxLCAxMSwgMTIsIDYsIDgsIDMsIDEzLFxuICAgIDIsIDEyLCA2LCAxMCwgMCwgMTEsIDgsIDMsIDQsIDEzLCA3LCA1LCAxNSwgMTQsIDEsIDksXG5dKTtcbi8vIDMyLWJpdCAvIEJMQUtFMnMgZmlyc3QgaGFsZiBvZiBHLCB3aXRoIHRoZSBmaXhlZCBgKDE2LCAxMilgIHJvdGF0aW9uIHBhaXIuXG4vLyBQYXJhbWV0ZXIgYHhgIGlzIHRoZSBSRkMgNzY5MyBmaXJzdC1oYWxmIG1lc3NhZ2Ugd29yZCwgb3IgQmxha2UxJ3MgcHJlLW1peGVkXG4vLyBgbVtzaWdtYVtyXVsyaV1dIF4gdVtzaWdtYVtyXVsyaSsxXV1gIGFkZGVuZCBpbiB0aGUgMzItYml0IHBhdGguXG5leHBvcnQgZnVuY3Rpb24gRzFzKGEsIGIsIGMsIGQsIHgpIHtcbiAgICBhID0gKGEgKyBiICsgeCkgfCAwO1xuICAgIGQgPSByb3RyKGQgXiBhLCAxNik7XG4gICAgYyA9IChjICsgZCkgfCAwO1xuICAgIGIgPSByb3RyKGIgXiBjLCAxMik7XG4gICAgcmV0dXJuIHsgYSwgYiwgYywgZCB9O1xufVxuLy8gMzItYml0IC8gQkxBS0UycyBzZWNvbmQgaGFsZiBvZiBHLlxuLy8gUGFyYW1ldGVyIGB4YCBpcyB0aGUgUkZDIDc2OTMgc2Vjb25kLWhhbGYgKGB5YCkgbWVzc2FnZSB3b3JkLCBvciBCbGFrZTEncyBwcmUtbWl4ZWRcbi8vIGBtW3NpZ21hW3JdWzJpICsgMV1dIF4gdVtzaWdtYVtyXVsyaV1dYCBhZGRlbmQgaW4gdGhlIDMyLWJpdCBwYXRoLlxuZXhwb3J0IGZ1bmN0aW9uIEcycyhhLCBiLCBjLCBkLCB4KSB7XG4gICAgYSA9IChhICsgYiArIHgpIHwgMDtcbiAgICBkID0gcm90cihkIF4gYSwgOCk7XG4gICAgYyA9IChjICsgZCkgfCAwO1xuICAgIGIgPSByb3RyKGIgXiBjLCA3KTtcbiAgICByZXR1cm4geyBhLCBiLCBjLCBkIH07XG59XG4vLyMgc291cmNlTWFwcGluZ1VSTD1fYmxha2UuanMubWFwIiwiY29uc3QgVTMyX01BU0s2NCA9IC8qIEBfX1BVUkVfXyAqLyBCaWdJbnQoMiAqKiAzMiAtIDEpO1xuY29uc3QgXzMybiA9IC8qIEBfX1BVUkVfXyAqLyBCaWdJbnQoMzIpO1xuLy8gU3BsaXQgYmlnaW50IGludG8gdHdvIDMyLWJpdCBoYWx2ZXMuIFdpdGggYGxlPXRydWVgLCByZXR1cm5lZCBmaWVsZHMgYmVjb21lIGB7IGg6IGxvdywgbDogaGlnaFxuLy8gfWAgdG8gbWF0Y2ggbGl0dGxlLWVuZGlhbiB3b3JkIG9yZGVyIHJhdGhlciB0aGFuIHRoZSBwcm9wZXJ0eSBuYW1lcy5cbmZ1bmN0aW9uIGZyb21CaWcobiwgbGUgPSBmYWxzZSkge1xuICAgIGlmIChsZSlcbiAgICAgICAgcmV0dXJuIHsgaDogTnVtYmVyKG4gJiBVMzJfTUFTSzY0KSwgbDogTnVtYmVyKChuID4+IF8zMm4pICYgVTMyX01BU0s2NCkgfTtcbiAgICByZXR1cm4geyBoOiBOdW1iZXIoKG4gPj4gXzMybikgJiBVMzJfTUFTSzY0KSB8IDAsIGw6IE51bWJlcihuICYgVTMyX01BU0s2NCkgfCAwIH07XG59XG4vLyBTcGxpdCBiaWdpbnQgbGlzdCBpbnRvIGBbaGlnaFdvcmRzLCBsb3dXb3Jkc11gIHdoZW4gYGxlPWZhbHNlYDsgd2l0aCBgbGU9dHJ1ZWAsIHRoZSBmaXJzdCBhcnJheVxuLy8gaG9sZHMgdGhlIGxvdyBoYWx2ZXMgYmVjYXVzZSBgZnJvbUJpZyguLi4pYCBzd2FwcyB0aGUgc2VtYW50aWMgbWVhbmluZyBvZiBgaGAgYW5kIGBsYC5cbmZ1bmN0aW9uIHNwbGl0KGxzdCwgbGUgPSBmYWxzZSkge1xuICAgIGNvbnN0IGxlbiA9IGxzdC5sZW5ndGg7XG4gICAgbGV0IEFoID0gbmV3IFVpbnQzMkFycmF5KGxlbik7XG4gICAgbGV0IEFsID0gbmV3IFVpbnQzMkFycmF5KGxlbik7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgICBjb25zdCB7IGgsIGwgfSA9IGZyb21CaWcobHN0W2ldLCBsZSk7XG4gICAgICAgIFtBaFtpXSwgQWxbaV1dID0gW2gsIGxdO1xuICAgIH1cbiAgICByZXR1cm4gW0FoLCBBbF07XG59XG4vLyBDb21iaW5lIGV4cGxpY2l0IGAoaGlnaCwgbG93KWAgMzItYml0IGhhbHZlcyBpbnRvIGEgYmlnaW50OyBgPj4+IDBgIG5vcm1hbGl6ZXMgc2lnbmVkIEpTXG4vLyBiaXR3aXNlIHJlc3VsdHMgYmFjayB0byB1aW50MzIgZmlyc3QsIGFuZCBsaXR0bGUtZW5kaWFuIGNhbGxlcnMgbXVzdCBzd2FwLlxuY29uc3QgdG9CaWcgPSAoaCwgbCkgPT4gKEJpZ0ludChoID4+PiAwKSA8PCBfMzJuKSB8IEJpZ0ludChsID4+PiAwKTtcbi8vIEhpZ2ggMzItYml0IGhhbGYgb2YgYSA2NC1iaXQgbG9naWNhbCByaWdodCBzaGlmdCBmb3IgYHNgIGluIGAwLi4zMWAuXG5jb25zdCBzaHJTSCA9IChoLCBfbCwgcykgPT4gaCA+Pj4gcztcbi8vIExvdyAzMi1iaXQgaGFsZiBvZiBhIDY0LWJpdCBsb2dpY2FsIHJpZ2h0IHNoaWZ0LCB2YWxpZCBmb3IgYHNgIGluIGAxLi4zMWAuXG5jb25zdCBzaHJTTCA9IChoLCBsLCBzKSA9PiAoaCA8PCAoMzIgLSBzKSkgfCAobCA+Pj4gcyk7XG4vLyBIaWdoIDMyLWJpdCBoYWxmIG9mIGEgNjQtYml0IHJpZ2h0IHJvdGF0ZSwgdmFsaWQgZm9yIGBzYCBpbiBgMS4uMzFgLlxuY29uc3Qgcm90clNIID0gKGgsIGwsIHMpID0+IChoID4+PiBzKSB8IChsIDw8ICgzMiAtIHMpKTtcbi8vIExvdyAzMi1iaXQgaGFsZiBvZiBhIDY0LWJpdCByaWdodCByb3RhdGUsIHZhbGlkIGZvciBgc2AgaW4gYDEuLjMxYC5cbmNvbnN0IHJvdHJTTCA9IChoLCBsLCBzKSA9PiAoaCA8PCAoMzIgLSBzKSkgfCAobCA+Pj4gcyk7XG4vLyBIaWdoIDMyLWJpdCBoYWxmIG9mIGEgNjQtYml0IHJpZ2h0IHJvdGF0ZSwgdmFsaWQgZm9yIGBzYCBpbiBgMzMuLjYzYDsgYDMyYCB1c2VzIGByb3RyMzIqYC5cbmNvbnN0IHJvdHJCSCA9IChoLCBsLCBzKSA9PiAoaCA8PCAoNjQgLSBzKSkgfCAobCA+Pj4gKHMgLSAzMikpO1xuLy8gTG93IDMyLWJpdCBoYWxmIG9mIGEgNjQtYml0IHJpZ2h0IHJvdGF0ZSwgdmFsaWQgZm9yIGBzYCBpbiBgMzMuLjYzYDsgYDMyYCB1c2VzIGByb3RyMzIqYC5cbmNvbnN0IHJvdHJCTCA9IChoLCBsLCBzKSA9PiAoaCA+Pj4gKHMgLSAzMikpIHwgKGwgPDwgKDY0IC0gcykpO1xuLy8gSGlnaCAzMi1iaXQgaGFsZiBvZiBhIDY0LWJpdCByaWdodCByb3RhdGUgZm9yIGBzID09PSAzMmA7IHRoaXMgaXMganVzdCB0aGUgc3dhcHBlZCBsb3cgaGFsZi5cbmNvbnN0IHJvdHIzMkggPSAoX2gsIGwpID0+IGw7XG4vLyBMb3cgMzItYml0IGhhbGYgb2YgYSA2NC1iaXQgcmlnaHQgcm90YXRlIGZvciBgcyA9PT0gMzJgOyB0aGlzIGlzIGp1c3QgdGhlIHN3YXBwZWQgaGlnaCBoYWxmLlxuY29uc3Qgcm90cjMyTCA9IChoLCBfbCkgPT4gaDtcbi8vIEhpZ2ggMzItYml0IGhhbGYgb2YgYSA2NC1iaXQgbGVmdCByb3RhdGUsIHZhbGlkIGZvciBgc2AgaW4gYDEuLjMxYC5cbmNvbnN0IHJvdGxTSCA9IChoLCBsLCBzKSA9PiAoaCA8PCBzKSB8IChsID4+PiAoMzIgLSBzKSk7XG4vLyBMb3cgMzItYml0IGhhbGYgb2YgYSA2NC1iaXQgbGVmdCByb3RhdGUsIHZhbGlkIGZvciBgc2AgaW4gYDEuLjMxYC5cbmNvbnN0IHJvdGxTTCA9IChoLCBsLCBzKSA9PiAobCA8PCBzKSB8IChoID4+PiAoMzIgLSBzKSk7XG4vLyBIaWdoIDMyLWJpdCBoYWxmIG9mIGEgNjQtYml0IGxlZnQgcm90YXRlLCB2YWxpZCBmb3IgYHNgIGluIGAzMy4uNjNgOyBgMzJgIHVzZXMgYHJvdHIzMipgLlxuY29uc3Qgcm90bEJIID0gKGgsIGwsIHMpID0+IChsIDw8IChzIC0gMzIpKSB8IChoID4+PiAoNjQgLSBzKSk7XG4vLyBMb3cgMzItYml0IGhhbGYgb2YgYSA2NC1iaXQgbGVmdCByb3RhdGUsIHZhbGlkIGZvciBgc2AgaW4gYDMzLi42M2A7IGAzMmAgdXNlcyBgcm90cjMyKmAuXG5jb25zdCByb3RsQkwgPSAoaCwgbCwgcykgPT4gKGggPDwgKHMgLSAzMikpIHwgKGwgPj4+ICg2NCAtIHMpKTtcbi8vIEFkZCB0d28gc3BsaXQgNjQtYml0IHdvcmRzIGFuZCByZXR1cm4gdGhlIHNwbGl0IGB7IGgsIGwgfWAgc3VtLlxuLy8gSlMgdXNlcyAzMi1iaXQgc2lnbmVkIGludGVnZXJzIGZvciBiaXR3aXNlIG9wZXJhdGlvbnMsIHNvIHdlIGNhbm5vdCBzaW1wbHkgc2hpZnQgdGhlIGNhcnJ5IG91dFxuLy8gb2YgdGhlIGxvdyBzdW0gYW5kIGluc3RlYWQgdXNlIGRpdmlzaW9uLlxuZnVuY3Rpb24gYWRkKEFoLCBBbCwgQmgsIEJsKSB7XG4gICAgY29uc3QgbCA9IChBbCA+Pj4gMCkgKyAoQmwgPj4+IDApO1xuICAgIHJldHVybiB7IGg6IChBaCArIEJoICsgKChsIC8gMiAqKiAzMikgfCAwKSkgfCAwLCBsOiBsIHwgMCB9O1xufVxuLy8gQWRkaXRpb24gd2l0aCBtb3JlIHRoYW4gMiBlbGVtZW50c1xuLy8gVW5tYXNrZWQgbG93LXdvcmQgYWNjdW11bGF0b3IgZm9yIDMtd2F5IGFkZGl0aW9uOyBwYXNzIHRoZSByYXcgcmVzdWx0IGludG8gYGFkZDNIKC4uLilgLlxuY29uc3QgYWRkM0wgPSAoQWwsIEJsLCBDbCkgPT4gKEFsID4+PiAwKSArIChCbCA+Pj4gMCkgKyAoQ2wgPj4+IDApO1xuLy8gSGlnaC13b3JkIGZpbmFsaXplIHN0ZXAgZm9yIDMtd2F5IGFkZGl0aW9uOyBgbG93YCBtdXN0IGJlIHRoZSB1bnRydW5jYXRlZCBvdXRwdXQgb2YgYGFkZDNMKC4uLilgLlxuY29uc3QgYWRkM0ggPSAobG93LCBBaCwgQmgsIENoKSA9PiAoQWggKyBCaCArIENoICsgKChsb3cgLyAyICoqIDMyKSB8IDApKSB8IDA7XG4vLyBVbm1hc2tlZCBsb3ctd29yZCBhY2N1bXVsYXRvciBmb3IgNC13YXkgYWRkaXRpb247IHBhc3MgdGhlIHJhdyByZXN1bHQgaW50byBgYWRkNEgoLi4uKWAuXG5jb25zdCBhZGQ0TCA9IChBbCwgQmwsIENsLCBEbCkgPT4gKEFsID4+PiAwKSArIChCbCA+Pj4gMCkgKyAoQ2wgPj4+IDApICsgKERsID4+PiAwKTtcbi8vIEhpZ2gtd29yZCBmaW5hbGl6ZSBzdGVwIGZvciA0LXdheSBhZGRpdGlvbjsgYGxvd2AgbXVzdCBiZSB0aGUgdW50cnVuY2F0ZWQgb3V0cHV0IG9mIGBhZGQ0TCguLi4pYC5cbmNvbnN0IGFkZDRIID0gKGxvdywgQWgsIEJoLCBDaCwgRGgpID0+IChBaCArIEJoICsgQ2ggKyBEaCArICgobG93IC8gMiAqKiAzMikgfCAwKSkgfCAwO1xuLy8gVW5tYXNrZWQgbG93LXdvcmQgYWNjdW11bGF0b3IgZm9yIDUtd2F5IGFkZGl0aW9uOyBwYXNzIHRoZSByYXcgcmVzdWx0IGludG8gYGFkZDVIKC4uLilgLlxuY29uc3QgYWRkNUwgPSAoQWwsIEJsLCBDbCwgRGwsIEVsKSA9PiAoQWwgPj4+IDApICsgKEJsID4+PiAwKSArIChDbCA+Pj4gMCkgKyAoRGwgPj4+IDApICsgKEVsID4+PiAwKTtcbi8vIEhpZ2gtd29yZCBmaW5hbGl6ZSBzdGVwIGZvciA1LXdheSBhZGRpdGlvbjsgYGxvd2AgbXVzdCBiZSB0aGUgdW50cnVuY2F0ZWQgb3V0cHV0IG9mIGBhZGQ1TCguLi4pYC5cbmNvbnN0IGFkZDVIID0gKGxvdywgQWgsIEJoLCBDaCwgRGgsIEVoKSA9PiAoQWggKyBCaCArIENoICsgRGggKyBFaCArICgobG93IC8gMiAqKiAzMikgfCAwKSkgfCAwO1xuLy8gcHJldHRpZXItaWdub3JlXG5leHBvcnQgeyBhZGQsIGFkZDNILCBhZGQzTCwgYWRkNEgsIGFkZDRMLCBhZGQ1SCwgYWRkNUwsIGZyb21CaWcsIHJvdGxCSCwgcm90bEJMLCByb3RsU0gsIHJvdGxTTCwgcm90cjMySCwgcm90cjMyTCwgcm90ckJILCByb3RyQkwsIHJvdHJTSCwgcm90clNMLCBzaHJTSCwgc2hyU0wsIHNwbGl0LCB0b0JpZyB9O1xuLy8gQ2Fub25pY2FsIGdyb3VwZWQgbmFtZXNwYWNlIGZvciBjYWxsZXJzIHRoYXQgcHJlZmVyIG9uZSBvYmplY3QuXG4vLyBOYW1lZCBleHBvcnRzIHN0YXkgZm9yIGRpcmVjdCBpbXBvcnRzLlxuLy8gcHJldHRpZXItaWdub3JlXG5jb25zdCB1NjQgPSB7XG4gICAgZnJvbUJpZywgc3BsaXQsIHRvQmlnLFxuICAgIHNoclNILCBzaHJTTCxcbiAgICByb3RyU0gsIHJvdHJTTCwgcm90ckJILCByb3RyQkwsXG4gICAgcm90cjMySCwgcm90cjMyTCxcbiAgICByb3RsU0gsIHJvdGxTTCwgcm90bEJILCByb3RsQkwsXG4gICAgYWRkLCBhZGQzTCwgYWRkM0gsIGFkZDRMLCBhZGQ0SCwgYWRkNUgsIGFkZDVMLFxufTtcbi8vIERlZmF1bHQgZXhwb3J0IG1pcnJvcnMgbmFtZWQgYHU2NGAgZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBvYmplY3Qtc3R5bGUgaW1wb3J0cy5cbmV4cG9ydCBkZWZhdWx0IHU2NDtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPV91NjQuanMubWFwIiwiLyoqXG4gKiBibGFrZTJiICg2NC1iaXQpICYgYmxha2UycyAoOCB0byAzMi1iaXQpIGhhc2ggZnVuY3Rpb25zLlxuICogYiBjb3VsZCBoYXZlIGJlZW4gZmFzdGVyLCBidXQgdGhlcmUgaXMgbm8gZmFzdCB1NjQgaW4ganMsIHNvIHMgaXMgMS41eCBmYXN0ZXIuXG4gKiBAbW9kdWxlXG4gKi9cbmltcG9ydCB7IEJTSUdNQSwgRzFzLCBHMnMgfSBmcm9tIFwiLi9fYmxha2UuanNcIjtcbmltcG9ydCB7IFNIQTI1Nl9JViB9IGZyb20gXCIuL19tZC5qc1wiO1xuaW1wb3J0ICogYXMgdTY0IGZyb20gXCIuL191NjQuanNcIjtcbi8vIHByZXR0aWVyLWlnbm9yZVxuaW1wb3J0IHsgYWJ5dGVzLCBhZXhpc3RzLCBhbnVtYmVyLCBhb3V0cHV0LCBjbGVhbiwgY3JlYXRlSGFzaGVyLCBzd2FwMzJJZkJFLCBzd2FwOElmQkUsIHUzMiB9IGZyb20gXCIuL3V0aWxzLmpzXCI7XG4vLyBTYW1lIElWIHdvcmRzIGFzIGBTSEE1MTJfSVZgLCBidXQgZW5kaWFuLXN3YXBwZWQgaW50byBMRSB1MzIgbG93L2hpZ2ggaGFsdmVzXG4vLyBmb3IgdGhlIEJMQUtFMmIgdTY0IGhlbHBlcnMgYmVsb3cuXG5jb25zdCBCMkJfSVYgPSAvKiBAX19QVVJFX18gKi8gVWludDMyQXJyYXkuZnJvbShbXG4gICAgMHhmM2JjYzkwOCwgMHg2YTA5ZTY2NywgMHg4NGNhYTczYiwgMHhiYjY3YWU4NSwgMHhmZTk0ZjgyYiwgMHgzYzZlZjM3MiwgMHg1ZjFkMzZmMSwgMHhhNTRmZjUzYSxcbiAgICAweGFkZTY4MmQxLCAweDUxMGU1MjdmLCAweDJiM2U2YzFmLCAweDliMDU2ODhjLCAweGZiNDFiZDZiLCAweDFmODNkOWFiLCAweDEzN2UyMTc5LCAweDViZTBjZDE5LFxuXSk7XG4vLyBTaGFyZWQgc3luY2hyb25vdXMgQkxBS0UyYiB3b3JrIHZlY3RvciBhcyBMRSB1MzIgbG93L2hpZ2ggaGFsdmVzLlxuY29uc3QgQkJVRiA9IC8qIEBfX1BVUkVfXyAqLyBuZXcgVWludDMyQXJyYXkoMzIpO1xuLy8gQkxBS0UyYiBHIG1peCBzcGxpdCBpbnRvIHR3byBoYWxmLXJvdW5kcyBvdmVyIExFIHUzMiBsb3cvaGlnaCBsaW1icy5cbmZ1bmN0aW9uIEcxYihhLCBiLCBjLCBkLCBtc2csIHgpIHtcbiAgICAvLyBOT1RFOiBWIGlzIExFIGhlcmVcbiAgICBjb25zdCBYbCA9IG1zZ1t4XSwgWGggPSBtc2dbeCArIDFdOyAvLyBwcmV0dGllci1pZ25vcmVcbiAgICBsZXQgQWwgPSBCQlVGWzIgKiBhXSwgQWggPSBCQlVGWzIgKiBhICsgMV07IC8vIHByZXR0aWVyLWlnbm9yZVxuICAgIGxldCBCbCA9IEJCVUZbMiAqIGJdLCBCaCA9IEJCVUZbMiAqIGIgKyAxXTsgLy8gcHJldHRpZXItaWdub3JlXG4gICAgbGV0IENsID0gQkJVRlsyICogY10sIENoID0gQkJVRlsyICogYyArIDFdOyAvLyBwcmV0dGllci1pZ25vcmVcbiAgICBsZXQgRGwgPSBCQlVGWzIgKiBkXSwgRGggPSBCQlVGWzIgKiBkICsgMV07IC8vIHByZXR0aWVyLWlnbm9yZVxuICAgIC8vIHZbYV0gPSAodlthXSArIHZbYl0gKyB4KSB8IDA7XG4gICAgbGV0IGxsID0gdTY0LmFkZDNMKEFsLCBCbCwgWGwpO1xuICAgIEFoID0gdTY0LmFkZDNIKGxsLCBBaCwgQmgsIFhoKTtcbiAgICBBbCA9IGxsIHwgMDtcbiAgICAvLyB2W2RdID0gcm90cih2W2RdIF4gdlthXSwgMzIpXG4gICAgKHsgRGgsIERsIH0gPSB7IERoOiBEaCBeIEFoLCBEbDogRGwgXiBBbCB9KTtcbiAgICAoeyBEaCwgRGwgfSA9IHsgRGg6IHU2NC5yb3RyMzJIKERoLCBEbCksIERsOiB1NjQucm90cjMyTChEaCwgRGwpIH0pO1xuICAgIC8vIHZbY10gPSAodltjXSArIHZbZF0pIHwgMDtcbiAgICAoeyBoOiBDaCwgbDogQ2wgfSA9IHU2NC5hZGQoQ2gsIENsLCBEaCwgRGwpKTtcbiAgICAvLyB2W2JdID0gcm90cih2W2JdIF4gdltjXSwgMjQpXG4gICAgKHsgQmgsIEJsIH0gPSB7IEJoOiBCaCBeIENoLCBCbDogQmwgXiBDbCB9KTtcbiAgICAoeyBCaCwgQmwgfSA9IHsgQmg6IHU2NC5yb3RyU0goQmgsIEJsLCAyNCksIEJsOiB1NjQucm90clNMKEJoLCBCbCwgMjQpIH0pO1xuICAgICgoQkJVRlsyICogYV0gPSBBbCksIChCQlVGWzIgKiBhICsgMV0gPSBBaCkpO1xuICAgICgoQkJVRlsyICogYl0gPSBCbCksIChCQlVGWzIgKiBiICsgMV0gPSBCaCkpO1xuICAgICgoQkJVRlsyICogY10gPSBDbCksIChCQlVGWzIgKiBjICsgMV0gPSBDaCkpO1xuICAgICgoQkJVRlsyICogZF0gPSBEbCksIChCQlVGWzIgKiBkICsgMV0gPSBEaCkpO1xufVxuLy8gU2Vjb25kIGhhbGYtcm91bmQgb2YgdGhlIHNhbWUgTEUtbGltYiBCTEFLRTJiIEcgbWl4OyBgeGAgaXMgdGhlIG1lc3NhZ2Ugd29yZCBvZmZzZXQuXG5mdW5jdGlvbiBHMmIoYSwgYiwgYywgZCwgbXNnLCB4KSB7XG4gICAgLy8gTk9URTogViBpcyBMRSBoZXJlXG4gICAgY29uc3QgWGwgPSBtc2dbeF0sIFhoID0gbXNnW3ggKyAxXTsgLy8gcHJldHRpZXItaWdub3JlXG4gICAgbGV0IEFsID0gQkJVRlsyICogYV0sIEFoID0gQkJVRlsyICogYSArIDFdOyAvLyBwcmV0dGllci1pZ25vcmVcbiAgICBsZXQgQmwgPSBCQlVGWzIgKiBiXSwgQmggPSBCQlVGWzIgKiBiICsgMV07IC8vIHByZXR0aWVyLWlnbm9yZVxuICAgIGxldCBDbCA9IEJCVUZbMiAqIGNdLCBDaCA9IEJCVUZbMiAqIGMgKyAxXTsgLy8gcHJldHRpZXItaWdub3JlXG4gICAgbGV0IERsID0gQkJVRlsyICogZF0sIERoID0gQkJVRlsyICogZCArIDFdOyAvLyBwcmV0dGllci1pZ25vcmVcbiAgICAvLyB2W2FdID0gKHZbYV0gKyB2W2JdICsgeCkgfCAwO1xuICAgIGxldCBsbCA9IHU2NC5hZGQzTChBbCwgQmwsIFhsKTtcbiAgICBBaCA9IHU2NC5hZGQzSChsbCwgQWgsIEJoLCBYaCk7XG4gICAgQWwgPSBsbCB8IDA7XG4gICAgLy8gdltkXSA9IHJvdHIodltkXSBeIHZbYV0sIDE2KVxuICAgICh7IERoLCBEbCB9ID0geyBEaDogRGggXiBBaCwgRGw6IERsIF4gQWwgfSk7XG4gICAgKHsgRGgsIERsIH0gPSB7IERoOiB1NjQucm90clNIKERoLCBEbCwgMTYpLCBEbDogdTY0LnJvdHJTTChEaCwgRGwsIDE2KSB9KTtcbiAgICAvLyB2W2NdID0gKHZbY10gKyB2W2RdKSB8IDA7XG4gICAgKHsgaDogQ2gsIGw6IENsIH0gPSB1NjQuYWRkKENoLCBDbCwgRGgsIERsKSk7XG4gICAgLy8gdltiXSA9IHJvdHIodltiXSBeIHZbY10sIDYzKVxuICAgICh7IEJoLCBCbCB9ID0geyBCaDogQmggXiBDaCwgQmw6IEJsIF4gQ2wgfSk7XG4gICAgKHsgQmgsIEJsIH0gPSB7IEJoOiB1NjQucm90ckJIKEJoLCBCbCwgNjMpLCBCbDogdTY0LnJvdHJCTChCaCwgQmwsIDYzKSB9KTtcbiAgICAoKEJCVUZbMiAqIGFdID0gQWwpLCAoQkJVRlsyICogYSArIDFdID0gQWgpKTtcbiAgICAoKEJCVUZbMiAqIGJdID0gQmwpLCAoQkJVRlsyICogYiArIDFdID0gQmgpKTtcbiAgICAoKEJCVUZbMiAqIGNdID0gQ2wpLCAoQkJVRlsyICogYyArIDFdID0gQ2gpKTtcbiAgICAoKEJCVUZbMiAqIGRdID0gRGwpLCAoQkJVRlsyICogZCArIDFdID0gRGgpKTtcbn1cbmZ1bmN0aW9uIGNoZWNrQmxha2UyT3B0cyhvdXRwdXRMZW4sIG9wdHMgPSB7fSwga2V5TGVuLCBzYWx0TGVuLCBwZXJzTGVuKSB7XG4gICAgYW51bWJlcihrZXlMZW4pO1xuICAgIC8vIFJGQyA3NjkzIMKnMi4xIHJlcXVpcmVzIGRpZ2VzdCBsZW5ndGggbm4gaW4gMS4ua2V5TGVuLlxuICAgIGlmIChvdXRwdXRMZW4gPD0gMCB8fCBvdXRwdXRMZW4gPiBrZXlMZW4pXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignb3V0cHV0TGVuIGJpZ2dlciB0aGFuIGtleUxlbicpO1xuICAgIGNvbnN0IHsga2V5LCBzYWx0LCBwZXJzb25hbGl6YXRpb24gfSA9IG9wdHM7XG4gICAgLy8gVGhpcyBBUEkgdXNlcyBgdW5kZWZpbmVkYCBmb3IgdGhlIFJGQyA3NjkzIGBrayA9IDBgIGNhc2UsIHNvIGEgcHJvdmlkZWQga2V5IG11c3QgYmUgbm9uLWVtcHR5LlxuICAgIGlmIChrZXkgIT09IHVuZGVmaW5lZCAmJiAoa2V5Lmxlbmd0aCA8IDEgfHwga2V5Lmxlbmd0aCA+IGtleUxlbikpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignXCJrZXlcIiBleHBlY3RlZCB0byBiZSB1bmRlZmluZWQgb3Igb2YgbGVuZ3RoPTEuLicgKyBrZXlMZW4pO1xuICAgIGlmIChzYWx0ICE9PSB1bmRlZmluZWQpXG4gICAgICAgIGFieXRlcyhzYWx0LCBzYWx0TGVuLCAnc2FsdCcpO1xuICAgIGlmIChwZXJzb25hbGl6YXRpb24gIT09IHVuZGVmaW5lZClcbiAgICAgICAgYWJ5dGVzKHBlcnNvbmFsaXphdGlvbiwgcGVyc0xlbiwgJ3BlcnNvbmFsaXphdGlvbicpO1xufVxuLyoqIEludGVybmFsIGJhc2UgY2xhc3MgZm9yIEJMQUtFMi4gKi9cbmV4cG9ydCBjbGFzcyBfQkxBS0UyIHtcbiAgICBidWZmZXI7XG4gICAgYnVmZmVyMzI7XG4gICAgZmluaXNoZWQgPSBmYWxzZTtcbiAgICBkZXN0cm95ZWQgPSBmYWxzZTtcbiAgICBsZW5ndGggPSAwO1xuICAgIHBvcyA9IDA7XG4gICAgYmxvY2tMZW47XG4gICAgb3V0cHV0TGVuO1xuICAgIGNhblhPRiA9IGZhbHNlO1xuICAgIGNvbnN0cnVjdG9yKGJsb2NrTGVuLCBvdXRwdXRMZW4pIHtcbiAgICAgICAgYW51bWJlcihibG9ja0xlbik7XG4gICAgICAgIGFudW1iZXIob3V0cHV0TGVuKTtcbiAgICAgICAgdGhpcy5ibG9ja0xlbiA9IGJsb2NrTGVuO1xuICAgICAgICB0aGlzLm91dHB1dExlbiA9IG91dHB1dExlbjtcbiAgICAgICAgdGhpcy5idWZmZXIgPSBuZXcgVWludDhBcnJheShibG9ja0xlbik7XG4gICAgICAgIHRoaXMuYnVmZmVyMzIgPSB1MzIodGhpcy5idWZmZXIpO1xuICAgIH1cbiAgICB1cGRhdGUoZGF0YSkge1xuICAgICAgICBhZXhpc3RzKHRoaXMpO1xuICAgICAgICBhYnl0ZXMoZGF0YSk7XG4gICAgICAgIC8vIE1haW4gZGlmZmVyZW5jZSB3aXRoIG90aGVyIGhhc2hlczogdGhlcmUgaXMgZmxhZyBmb3IgbGFzdCBibG9jayxcbiAgICAgICAgLy8gc28gd2UgY2Fubm90IHByb2Nlc3MgY3VycmVudCBibG9jayBiZWZvcmUgd2Uga25vdyB0aGF0IHRoZXJlXG4gICAgICAgIC8vIGlzIHRoZSBuZXh0IG9uZS4gVGhpcyBzaWduaWZpY2FudGx5IGNvbXBsaWNhdGVzIGxvZ2ljIGFuZCByZWR1Y2VzIGFiaWxpdHlcbiAgICAgICAgLy8gdG8gZG8gemVyby1jb3B5IHByb2Nlc3NpbmdcbiAgICAgICAgY29uc3QgeyBibG9ja0xlbiwgYnVmZmVyLCBidWZmZXIzMiB9ID0gdGhpcztcbiAgICAgICAgY29uc3QgbGVuID0gZGF0YS5sZW5ndGg7XG4gICAgICAgIGNvbnN0IG9mZnNldCA9IGRhdGEuYnl0ZU9mZnNldDtcbiAgICAgICAgY29uc3QgYnVmID0gZGF0YS5idWZmZXI7XG4gICAgICAgIGZvciAobGV0IHBvcyA9IDA7IHBvcyA8IGxlbjspIHtcbiAgICAgICAgICAgIC8vIElmIGJ1ZmZlciBpcyBmdWxsIGFuZCB3ZSBzdGlsbCBoYXZlIGlucHV0IChkb24ndCBwcm9jZXNzIGxhc3QgYmxvY2ssIHNhbWUgYXMgYmxha2UycylcbiAgICAgICAgICAgIGlmICh0aGlzLnBvcyA9PT0gYmxvY2tMZW4pIHtcbiAgICAgICAgICAgICAgICBzd2FwMzJJZkJFKGJ1ZmZlcjMyKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbXByZXNzKGJ1ZmZlcjMyLCAwLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgc3dhcDMySWZCRShidWZmZXIzMik7XG4gICAgICAgICAgICAgICAgdGhpcy5wb3MgPSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgdGFrZSA9IE1hdGgubWluKGJsb2NrTGVuIC0gdGhpcy5wb3MsIGxlbiAtIHBvcyk7XG4gICAgICAgICAgICBjb25zdCBkYXRhT2Zmc2V0ID0gb2Zmc2V0ICsgcG9zO1xuICAgICAgICAgICAgLy8gWmVyby1jb3B5IG9ubHkgZm9yIGZ1bGwsIDQtYnl0ZS1hbGlnbmVkLCBub24tZmluYWwgYmxvY2tzLlxuICAgICAgICAgICAgaWYgKHRha2UgPT09IGJsb2NrTGVuICYmICEoZGF0YU9mZnNldCAlIDQpICYmIHBvcyArIHRha2UgPCBsZW4pIHtcbiAgICAgICAgICAgICAgICBjb25zdCBkYXRhMzIgPSBuZXcgVWludDMyQXJyYXkoYnVmLCBkYXRhT2Zmc2V0LCBNYXRoLmZsb29yKChsZW4gLSBwb3MpIC8gNCkpO1xuICAgICAgICAgICAgICAgIHN3YXAzMklmQkUoZGF0YTMyKTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBwb3MzMiA9IDA7IHBvcyArIGJsb2NrTGVuIDwgbGVuOyBwb3MzMiArPSBidWZmZXIzMi5sZW5ndGgsIHBvcyArPSBibG9ja0xlbikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxlbmd0aCArPSBibG9ja0xlbjtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21wcmVzcyhkYXRhMzIsIHBvczMyLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHN3YXAzMklmQkUoZGF0YTMyKTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJ1ZmZlci5zZXQoZGF0YS5zdWJhcnJheShwb3MsIHBvcyArIHRha2UpLCB0aGlzLnBvcyk7XG4gICAgICAgICAgICB0aGlzLnBvcyArPSB0YWtlO1xuICAgICAgICAgICAgdGhpcy5sZW5ndGggKz0gdGFrZTtcbiAgICAgICAgICAgIHBvcyArPSB0YWtlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICBkaWdlc3RJbnRvKG91dCkge1xuICAgICAgICBhZXhpc3RzKHRoaXMpO1xuICAgICAgICBhb3V0cHV0KG91dCwgdGhpcyk7XG4gICAgICAgIGNvbnN0IHsgcG9zLCBidWZmZXIzMiB9ID0gdGhpcztcbiAgICAgICAgdGhpcy5maW5pc2hlZCA9IHRydWU7XG4gICAgICAgIC8vIFBhZGRpbmdcbiAgICAgICAgY2xlYW4odGhpcy5idWZmZXIuc3ViYXJyYXkocG9zKSk7XG4gICAgICAgIHN3YXAzMklmQkUoYnVmZmVyMzIpO1xuICAgICAgICB0aGlzLmNvbXByZXNzKGJ1ZmZlcjMyLCAwLCB0cnVlKTtcbiAgICAgICAgc3dhcDMySWZCRShidWZmZXIzMik7XG4gICAgICAgIC8vIFJlamVjdCB1bmFsaWduZWQgdmlld3MgZXhwbGljaXRseSBpbnN0ZWFkIG9mIGhpZGluZyB0aGVtIGJlaGluZCBhIGZ1bGwgc2NyYXRjaCBjb3B5LlxuICAgICAgICBpZiAob3V0LmJ5dGVPZmZzZXQgJiAzKVxuICAgICAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1wiZGlnZXN0SW50bygpIG91dHB1dFwiIGV4cGVjdGVkIDQtYnl0ZSBhbGlnbmVkIGJ5dGVPZmZzZXQsIGdvdCAnICsgb3V0LmJ5dGVPZmZzZXQpO1xuICAgICAgICBjb25zdCBzdGF0ZSA9IHRoaXMuZ2V0KCk7XG4gICAgICAgIGNvbnN0IG91dDMyID0gdTMyKG91dCk7XG4gICAgICAgIGNvbnN0IGZ1bGwgPSBNYXRoLmZsb29yKHRoaXMub3V0cHV0TGVuIC8gNCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZnVsbDsgaSsrKVxuICAgICAgICAgICAgb3V0MzJbaV0gPSBzd2FwOElmQkUoc3RhdGVbaV0pO1xuICAgICAgICBjb25zdCB0YWlsID0gdGhpcy5vdXRwdXRMZW4gJSA0O1xuICAgICAgICBpZiAoIXRhaWwpXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIGNvbnN0IG9mZiA9IGZ1bGwgKiA0O1xuICAgICAgICBjb25zdCB3b3JkID0gc3RhdGVbZnVsbF07XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGFpbDsgaSsrKVxuICAgICAgICAgICAgb3V0W29mZiArIGldID0gd29yZCA+Pj4gKDggKiBpKTtcbiAgICB9XG4gICAgZGlnZXN0KCkge1xuICAgICAgICBjb25zdCB7IGJ1ZmZlciwgb3V0cHV0TGVuIH0gPSB0aGlzO1xuICAgICAgICB0aGlzLmRpZ2VzdEludG8oYnVmZmVyKTtcbiAgICAgICAgLy8gUmV0dXJuIGEgY29weSBzbyBjYWxsZXJzIGRvIG5vdCBhbGlhcyB0aGUgaW5zdGFuY2Ugc2NyYXRjaCBidWZmZXIgdXNlZCBkdXJpbmcgZmluYWxpemF0aW9uLlxuICAgICAgICBjb25zdCByZXMgPSBidWZmZXIuc2xpY2UoMCwgb3V0cHV0TGVuKTtcbiAgICAgICAgdGhpcy5kZXN0cm95KCk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuICAgIF9jbG9uZUludG8odG8pIHtcbiAgICAgICAgY29uc3QgeyBidWZmZXIsIGxlbmd0aCwgZmluaXNoZWQsIGRlc3Ryb3llZCwgb3V0cHV0TGVuLCBwb3MgfSA9IHRoaXM7XG4gICAgICAgIC8vIFJlY3JlYXRlIG9ubHkgYGRrTGVuYDsga2V5L3NhbHQvcGVyc29uYWxpemF0aW9uIGFyZSBhbHJlYWR5IGFic29yYmVkIGludG8gdGhlIGNvcGllZCBzdGF0ZS5cbiAgICAgICAgdG8gfHw9IG5ldyB0aGlzLmNvbnN0cnVjdG9yKHsgZGtMZW46IG91dHB1dExlbiB9KTtcbiAgICAgICAgdG8uc2V0KC4uLnRoaXMuZ2V0KCkpO1xuICAgICAgICB0by5idWZmZXIuc2V0KGJ1ZmZlcik7XG4gICAgICAgIHRvLmRlc3Ryb3llZCA9IGRlc3Ryb3llZDtcbiAgICAgICAgdG8uZmluaXNoZWQgPSBmaW5pc2hlZDtcbiAgICAgICAgdG8ubGVuZ3RoID0gbGVuZ3RoO1xuICAgICAgICB0by5wb3MgPSBwb3M7XG4gICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgdG8ub3V0cHV0TGVuID0gb3V0cHV0TGVuO1xuICAgICAgICByZXR1cm4gdG87XG4gICAgfVxuICAgIGNsb25lKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fY2xvbmVJbnRvKCk7XG4gICAgfVxufVxuLyoqIEludGVybmFsIGJsYWtlMmIgaGFzaCBjbGFzcyB3aXRoIHN0YXRlIHN0b3JlZCBhcyBMRSB1MzIgbG93L2hpZ2ggaGFsdmVzLiAqL1xuZXhwb3J0IGNsYXNzIF9CTEFLRTJiIGV4dGVuZHMgX0JMQUtFMiB7XG4gICAgLy8gU2FtZSBJViB3b3JkcyBhcyBTSEEtNTEyIC8gQkxBS0UyYiwgZW5jb2RlZCBhcyBMRSB1MzIgbG93L2hpZ2ggaGFsdmVzLlxuICAgIHYwbCA9IEIyQl9JVlswXSB8IDA7XG4gICAgdjBoID0gQjJCX0lWWzFdIHwgMDtcbiAgICB2MWwgPSBCMkJfSVZbMl0gfCAwO1xuICAgIHYxaCA9IEIyQl9JVlszXSB8IDA7XG4gICAgdjJsID0gQjJCX0lWWzRdIHwgMDtcbiAgICB2MmggPSBCMkJfSVZbNV0gfCAwO1xuICAgIHYzbCA9IEIyQl9JVls2XSB8IDA7XG4gICAgdjNoID0gQjJCX0lWWzddIHwgMDtcbiAgICB2NGwgPSBCMkJfSVZbOF0gfCAwO1xuICAgIHY0aCA9IEIyQl9JVls5XSB8IDA7XG4gICAgdjVsID0gQjJCX0lWWzEwXSB8IDA7XG4gICAgdjVoID0gQjJCX0lWWzExXSB8IDA7XG4gICAgdjZsID0gQjJCX0lWWzEyXSB8IDA7XG4gICAgdjZoID0gQjJCX0lWWzEzXSB8IDA7XG4gICAgdjdsID0gQjJCX0lWWzE0XSB8IDA7XG4gICAgdjdoID0gQjJCX0lWWzE1XSB8IDA7XG4gICAgY29uc3RydWN0b3Iob3B0cyA9IHt9KSB7XG4gICAgICAgIGNvbnN0IG9sZW4gPSBvcHRzLmRrTGVuID09PSB1bmRlZmluZWQgPyA2NCA6IG9wdHMuZGtMZW47XG4gICAgICAgIHN1cGVyKDEyOCwgb2xlbik7XG4gICAgICAgIGNoZWNrQmxha2UyT3B0cyhvbGVuLCBvcHRzLCA2NCwgMTYsIDE2KTtcbiAgICAgICAgbGV0IHsga2V5LCBwZXJzb25hbGl6YXRpb24sIHNhbHQgfSA9IG9wdHM7XG4gICAgICAgIGxldCBrZXlMZW5ndGggPSAwO1xuICAgICAgICBpZiAoa2V5ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGFieXRlcyhrZXksIHVuZGVmaW5lZCwgJ2tleScpO1xuICAgICAgICAgICAga2V5TGVuZ3RoID0ga2V5Lmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgICAvLyBSRkMgNzY5MyDCpzIuNTogeG9yIGBwWzBdID0gMHgwMTAxa2tubmAgaW50byB0aGUgbG93IDMyIGJpdHMgb2YgYGhbMF1gO1xuICAgICAgICAvLyB0aGUgaGlnaCAzMiBiaXRzIHN0YXkgYXQgYElWWzBdYC5cbiAgICAgICAgdGhpcy52MGwgXj0gdGhpcy5vdXRwdXRMZW4gfCAoa2V5TGVuZ3RoIDw8IDgpIHwgKDB4MDEgPDwgMTYpIHwgKDB4MDEgPDwgMjQpO1xuICAgICAgICBpZiAoc2FsdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBhYnl0ZXMoc2FsdCwgdW5kZWZpbmVkLCAnc2FsdCcpO1xuICAgICAgICAgICAgY29uc3Qgc2x0ID0gdTMyKHNhbHQpO1xuICAgICAgICAgICAgdGhpcy52NGwgXj0gc3dhcDhJZkJFKHNsdFswXSk7XG4gICAgICAgICAgICB0aGlzLnY0aCBePSBzd2FwOElmQkUoc2x0WzFdKTtcbiAgICAgICAgICAgIHRoaXMudjVsIF49IHN3YXA4SWZCRShzbHRbMl0pO1xuICAgICAgICAgICAgdGhpcy52NWggXj0gc3dhcDhJZkJFKHNsdFszXSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHBlcnNvbmFsaXphdGlvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBhYnl0ZXMocGVyc29uYWxpemF0aW9uLCB1bmRlZmluZWQsICdwZXJzb25hbGl6YXRpb24nKTtcbiAgICAgICAgICAgIGNvbnN0IHBlcnMgPSB1MzIocGVyc29uYWxpemF0aW9uKTtcbiAgICAgICAgICAgIHRoaXMudjZsIF49IHN3YXA4SWZCRShwZXJzWzBdKTtcbiAgICAgICAgICAgIHRoaXMudjZoIF49IHN3YXA4SWZCRShwZXJzWzFdKTtcbiAgICAgICAgICAgIHRoaXMudjdsIF49IHN3YXA4SWZCRShwZXJzWzJdKTtcbiAgICAgICAgICAgIHRoaXMudjdoIF49IHN3YXA4SWZCRShwZXJzWzNdKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoa2V5ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIFBhZCB0byBibG9ja0xlbiBhbmQgdXBkYXRlXG4gICAgICAgICAgICBjb25zdCB0bXAgPSBuZXcgVWludDhBcnJheSh0aGlzLmJsb2NrTGVuKTtcbiAgICAgICAgICAgIHRtcC5zZXQoa2V5KTtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlKHRtcCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gcHJldHRpZXItaWdub3JlXG4gICAgZ2V0KCkge1xuICAgICAgICBsZXQgeyB2MGwsIHYwaCwgdjFsLCB2MWgsIHYybCwgdjJoLCB2M2wsIHYzaCwgdjRsLCB2NGgsIHY1bCwgdjVoLCB2NmwsIHY2aCwgdjdsLCB2N2ggfSA9IHRoaXM7XG4gICAgICAgIHJldHVybiBbdjBsLCB2MGgsIHYxbCwgdjFoLCB2MmwsIHYyaCwgdjNsLCB2M2gsIHY0bCwgdjRoLCB2NWwsIHY1aCwgdjZsLCB2NmgsIHY3bCwgdjdoXTtcbiAgICB9XG4gICAgLy8gcHJldHRpZXItaWdub3JlXG4gICAgc2V0KHYwbCwgdjBoLCB2MWwsIHYxaCwgdjJsLCB2MmgsIHYzbCwgdjNoLCB2NGwsIHY0aCwgdjVsLCB2NWgsIHY2bCwgdjZoLCB2N2wsIHY3aCkge1xuICAgICAgICB0aGlzLnYwbCA9IHYwbCB8IDA7XG4gICAgICAgIHRoaXMudjBoID0gdjBoIHwgMDtcbiAgICAgICAgdGhpcy52MWwgPSB2MWwgfCAwO1xuICAgICAgICB0aGlzLnYxaCA9IHYxaCB8IDA7XG4gICAgICAgIHRoaXMudjJsID0gdjJsIHwgMDtcbiAgICAgICAgdGhpcy52MmggPSB2MmggfCAwO1xuICAgICAgICB0aGlzLnYzbCA9IHYzbCB8IDA7XG4gICAgICAgIHRoaXMudjNoID0gdjNoIHwgMDtcbiAgICAgICAgdGhpcy52NGwgPSB2NGwgfCAwO1xuICAgICAgICB0aGlzLnY0aCA9IHY0aCB8IDA7XG4gICAgICAgIHRoaXMudjVsID0gdjVsIHwgMDtcbiAgICAgICAgdGhpcy52NWggPSB2NWggfCAwO1xuICAgICAgICB0aGlzLnY2bCA9IHY2bCB8IDA7XG4gICAgICAgIHRoaXMudjZoID0gdjZoIHwgMDtcbiAgICAgICAgdGhpcy52N2wgPSB2N2wgfCAwO1xuICAgICAgICB0aGlzLnY3aCA9IHY3aCB8IDA7XG4gICAgfVxuICAgIGNvbXByZXNzKG1zZywgb2Zmc2V0LCBpc0xhc3QpIHtcbiAgICAgICAgdGhpcy5nZXQoKS5mb3JFYWNoKCh2LCBpKSA9PiAoQkJVRltpXSA9IHYpKTsgLy8gRmlyc3QgaGFsZiBmcm9tIHN0YXRlLlxuICAgICAgICBCQlVGLnNldChCMkJfSVYsIDE2KTsgLy8gU2Vjb25kIGhhbGYgZnJvbSBJVi5cbiAgICAgICAgbGV0IHsgaCwgbCB9ID0gdTY0LmZyb21CaWcoQmlnSW50KHRoaXMubGVuZ3RoKSk7XG4gICAgICAgIEJCVUZbMjRdID0gQjJCX0lWWzhdIF4gbDsgLy8gTG93IHdvcmQgb2YgdGhlIG9mZnNldC5cbiAgICAgICAgQkJVRlsyNV0gPSBCMkJfSVZbOV0gXiBoOyAvLyBIaWdoIHdvcmQuXG4gICAgICAgIC8vIEludmVydCBhbGwgYml0cyBmb3IgbGFzdCBibG9ja1xuICAgICAgICBpZiAoaXNMYXN0KSB7XG4gICAgICAgICAgICBCQlVGWzI4XSA9IH5CQlVGWzI4XTtcbiAgICAgICAgICAgIEJCVUZbMjldID0gfkJCVUZbMjldO1xuICAgICAgICB9XG4gICAgICAgIGxldCBqID0gMDtcbiAgICAgICAgY29uc3QgcyA9IEJTSUdNQTtcbiAgICAgICAgLy8gU0lHTUEgc2VsZWN0cyA2NC1iaXQgbWVzc2FnZSB3b3JkczsgbXVsdGlwbHkgYnkgMiBiZWNhdXNlIGBtc2dgIHN0b3Jlc1xuICAgICAgICAvLyBlYWNoIHdvcmQgYXMgW2xvdzMyLCBoaWdoMzJdLlxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDEyOyBpKyspIHtcbiAgICAgICAgICAgIEcxYigwLCA0LCA4LCAxMiwgbXNnLCBvZmZzZXQgKyAyICogc1tqKytdKTtcbiAgICAgICAgICAgIEcyYigwLCA0LCA4LCAxMiwgbXNnLCBvZmZzZXQgKyAyICogc1tqKytdKTtcbiAgICAgICAgICAgIEcxYigxLCA1LCA5LCAxMywgbXNnLCBvZmZzZXQgKyAyICogc1tqKytdKTtcbiAgICAgICAgICAgIEcyYigxLCA1LCA5LCAxMywgbXNnLCBvZmZzZXQgKyAyICogc1tqKytdKTtcbiAgICAgICAgICAgIEcxYigyLCA2LCAxMCwgMTQsIG1zZywgb2Zmc2V0ICsgMiAqIHNbaisrXSk7XG4gICAgICAgICAgICBHMmIoMiwgNiwgMTAsIDE0LCBtc2csIG9mZnNldCArIDIgKiBzW2orK10pO1xuICAgICAgICAgICAgRzFiKDMsIDcsIDExLCAxNSwgbXNnLCBvZmZzZXQgKyAyICogc1tqKytdKTtcbiAgICAgICAgICAgIEcyYigzLCA3LCAxMSwgMTUsIG1zZywgb2Zmc2V0ICsgMiAqIHNbaisrXSk7XG4gICAgICAgICAgICBHMWIoMCwgNSwgMTAsIDE1LCBtc2csIG9mZnNldCArIDIgKiBzW2orK10pO1xuICAgICAgICAgICAgRzJiKDAsIDUsIDEwLCAxNSwgbXNnLCBvZmZzZXQgKyAyICogc1tqKytdKTtcbiAgICAgICAgICAgIEcxYigxLCA2LCAxMSwgMTIsIG1zZywgb2Zmc2V0ICsgMiAqIHNbaisrXSk7XG4gICAgICAgICAgICBHMmIoMSwgNiwgMTEsIDEyLCBtc2csIG9mZnNldCArIDIgKiBzW2orK10pO1xuICAgICAgICAgICAgRzFiKDIsIDcsIDgsIDEzLCBtc2csIG9mZnNldCArIDIgKiBzW2orK10pO1xuICAgICAgICAgICAgRzJiKDIsIDcsIDgsIDEzLCBtc2csIG9mZnNldCArIDIgKiBzW2orK10pO1xuICAgICAgICAgICAgRzFiKDMsIDQsIDksIDE0LCBtc2csIG9mZnNldCArIDIgKiBzW2orK10pO1xuICAgICAgICAgICAgRzJiKDMsIDQsIDksIDE0LCBtc2csIG9mZnNldCArIDIgKiBzW2orK10pO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudjBsIF49IEJCVUZbMF0gXiBCQlVGWzE2XTtcbiAgICAgICAgdGhpcy52MGggXj0gQkJVRlsxXSBeIEJCVUZbMTddO1xuICAgICAgICB0aGlzLnYxbCBePSBCQlVGWzJdIF4gQkJVRlsxOF07XG4gICAgICAgIHRoaXMudjFoIF49IEJCVUZbM10gXiBCQlVGWzE5XTtcbiAgICAgICAgdGhpcy52MmwgXj0gQkJVRls0XSBeIEJCVUZbMjBdO1xuICAgICAgICB0aGlzLnYyaCBePSBCQlVGWzVdIF4gQkJVRlsyMV07XG4gICAgICAgIHRoaXMudjNsIF49IEJCVUZbNl0gXiBCQlVGWzIyXTtcbiAgICAgICAgdGhpcy52M2ggXj0gQkJVRls3XSBeIEJCVUZbMjNdO1xuICAgICAgICB0aGlzLnY0bCBePSBCQlVGWzhdIF4gQkJVRlsyNF07XG4gICAgICAgIHRoaXMudjRoIF49IEJCVUZbOV0gXiBCQlVGWzI1XTtcbiAgICAgICAgdGhpcy52NWwgXj0gQkJVRlsxMF0gXiBCQlVGWzI2XTtcbiAgICAgICAgdGhpcy52NWggXj0gQkJVRlsxMV0gXiBCQlVGWzI3XTtcbiAgICAgICAgdGhpcy52NmwgXj0gQkJVRlsxMl0gXiBCQlVGWzI4XTtcbiAgICAgICAgdGhpcy52NmggXj0gQkJVRlsxM10gXiBCQlVGWzI5XTtcbiAgICAgICAgdGhpcy52N2wgXj0gQkJVRlsxNF0gXiBCQlVGWzMwXTtcbiAgICAgICAgdGhpcy52N2ggXj0gQkJVRlsxNV0gXiBCQlVGWzMxXTtcbiAgICAgICAgY2xlYW4oQkJVRik7XG4gICAgfVxuICAgIGRlc3Ryb3koKSB7XG4gICAgICAgIHRoaXMuZGVzdHJveWVkID0gdHJ1ZTtcbiAgICAgICAgY2xlYW4odGhpcy5idWZmZXIzMik7XG4gICAgICAgIHRoaXMuc2V0KDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDApO1xuICAgIH1cbn1cbi8qKlxuICogQmxha2UyYiBoYXNoIGZ1bmN0aW9uLiA2NC1iaXQuIDEuNXggc2xvd2VyIHRoYW4gYmxha2UycyBpbiBKUy5cbiAqIEBwYXJhbSBtc2cgLSBtZXNzYWdlIHRoYXQgd291bGQgYmUgaGFzaGVkXG4gKiBAcGFyYW0gb3B0cyAtIE9wdGlvbmFsIG91dHB1dCwgTUFDLCBzYWx0LCBhbmQgcGVyc29uYWxpemF0aW9uIHNldHRpbmdzLlxuICogICBgZGtMZW5gIG11c3QgYmUgMS4uNjQgYnl0ZXM7IGBzYWx0YCBhbmQgYHBlcnNvbmFsaXphdGlvbmAsIGlmIHByZXNlbnQsXG4gKiAgIG11c3QgYmUgMTYgYnl0ZXMgZWFjaC4gU2VlIHtAbGluayBCbGFrZTJPcHRzfS5cbiAqIEByZXR1cm5zIERpZ2VzdCBieXRlcy5cbiAqIEBleGFtcGxlXG4gKiBIYXNoIGEgbWVzc2FnZSB3aXRoIEJsYWtlMmIuXG4gKiBgYGB0c1xuICogYmxha2UyYihuZXcgVWludDhBcnJheShbOTcsIDk4LCA5OV0pKTtcbiAqIGBgYFxuICovXG5leHBvcnQgY29uc3QgYmxha2UyYiA9IC8qIEBfX1BVUkVfXyAqLyBjcmVhdGVIYXNoZXIoKG9wdHMpID0+IG5ldyBfQkxBS0UyYihvcHRzKSk7XG4vKipcbiAqIEJMQUtFMi1jb21wcmVzcyBjb3JlIG1ldGhvZC5cbiAqIFJ1bnMgb25seSB0aGUgcm91bmQgZnVuY3Rpb24gb3ZlciBhIGNhbGxlci1zdXBwbGllZCBsb2NhbCB2ZWN0b3I7IGNhbGxlcnMgaW5pdGlhbGl6ZSBgdjAuLnYxNWBcbiAqIGFuZCBhcHBseSB0aGUgZmluYWwgYGhbaV0gXj0gdltpXSBeIHZbaSArIDhdYCBmb2xkIHRoZW1zZWx2ZXMuXG4gKiBAcGFyYW0gcyAtIGZsYXR0ZW5lZCBzaWdtYSBzY2hlZHVsZSBieXRlc1xuICogQHBhcmFtIG9mZnNldCAtIHN0YXJ0aW5nIHdvcmQgb2Zmc2V0IGluc2lkZSBgbXNnYCwgbm90IGEgYnl0ZSBvZmZzZXRcbiAqIEBwYXJhbSBtc2cgLSBtZXNzYWdlIHdvcmRzXG4gKiBAcGFyYW0gcm91bmRzIC0gcm91bmQgY291bnQgdG8gZXhlY3V0ZVxuICogQHBhcmFtIHYwIC0gc3RhdGUgd29yZCAwXG4gKiBAcGFyYW0gdjEgLSBzdGF0ZSB3b3JkIDFcbiAqIEBwYXJhbSB2MiAtIHN0YXRlIHdvcmQgMlxuICogQHBhcmFtIHYzIC0gc3RhdGUgd29yZCAzXG4gKiBAcGFyYW0gdjQgLSBzdGF0ZSB3b3JkIDRcbiAqIEBwYXJhbSB2NSAtIHN0YXRlIHdvcmQgNVxuICogQHBhcmFtIHY2IC0gc3RhdGUgd29yZCA2XG4gKiBAcGFyYW0gdjcgLSBzdGF0ZSB3b3JkIDdcbiAqIEBwYXJhbSB2OCAtIHN0YXRlIHdvcmQgOFxuICogQHBhcmFtIHY5IC0gc3RhdGUgd29yZCA5XG4gKiBAcGFyYW0gdjEwIC0gc3RhdGUgd29yZCAxMFxuICogQHBhcmFtIHYxMSAtIHN0YXRlIHdvcmQgMTFcbiAqIEBwYXJhbSB2MTIgLSBzdGF0ZSB3b3JkIDEyXG4gKiBAcGFyYW0gdjEzIC0gc3RhdGUgd29yZCAxM1xuICogQHBhcmFtIHYxNCAtIHN0YXRlIHdvcmQgMTRcbiAqIEBwYXJhbSB2MTUgLSBzdGF0ZSB3b3JkIDE1XG4gKiBAcmV0dXJucyBVcGRhdGVkIGNvbXByZXNzaW9uIHN0YXRlIHdvcmRzLlxuICogQGV4YW1wbGVcbiAqIFJ1biB0aGUgQkxBS0UyIGNvbXByZXNzaW9uIGNvcmUgb24gemVyb2VkIHN0YXRlIGFuZCBtZXNzYWdlIHdvcmRzLlxuICogYGBgdHNcbiAqIGltcG9ydCB7IGNvbXByZXNzIH0gZnJvbSAnQG5vYmxlL2hhc2hlcy9ibGFrZTIuanMnO1xuICogY29uc3Qgc3RhdGUgPSBjb21wcmVzcyhcbiAqICAgbmV3IFVpbnQ4QXJyYXkoMTYpLFxuICogICAwLFxuICogICBuZXcgVWludDMyQXJyYXkoMTYpLFxuICogICAxLFxuICogICAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLFxuICogICAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwXG4gKiApO1xuICogc3RhdGUudjA7XG4gKiBgYGBcbiAqL1xuLy8gcHJldHRpZXItaWdub3JlXG5leHBvcnQgZnVuY3Rpb24gY29tcHJlc3Mocywgb2Zmc2V0LCBtc2csIHJvdW5kcywgdjAsIHYxLCB2MiwgdjMsIHY0LCB2NSwgdjYsIHY3LCB2OCwgdjksIHYxMCwgdjExLCB2MTIsIHYxMywgdjE0LCB2MTUpIHtcbiAgICBsZXQgaiA9IDA7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByb3VuZHM7IGkrKykge1xuICAgICAgICAoeyBhOiB2MCwgYjogdjQsIGM6IHY4LCBkOiB2MTIgfSA9IEcxcyh2MCwgdjQsIHY4LCB2MTIsIG1zZ1tvZmZzZXQgKyBzW2orK11dKSk7XG4gICAgICAgICh7IGE6IHYwLCBiOiB2NCwgYzogdjgsIGQ6IHYxMiB9ID0gRzJzKHYwLCB2NCwgdjgsIHYxMiwgbXNnW29mZnNldCArIHNbaisrXV0pKTtcbiAgICAgICAgKHsgYTogdjEsIGI6IHY1LCBjOiB2OSwgZDogdjEzIH0gPSBHMXModjEsIHY1LCB2OSwgdjEzLCBtc2dbb2Zmc2V0ICsgc1tqKytdXSkpO1xuICAgICAgICAoeyBhOiB2MSwgYjogdjUsIGM6IHY5LCBkOiB2MTMgfSA9IEcycyh2MSwgdjUsIHY5LCB2MTMsIG1zZ1tvZmZzZXQgKyBzW2orK11dKSk7XG4gICAgICAgICh7IGE6IHYyLCBiOiB2NiwgYzogdjEwLCBkOiB2MTQgfSA9IEcxcyh2MiwgdjYsIHYxMCwgdjE0LCBtc2dbb2Zmc2V0ICsgc1tqKytdXSkpO1xuICAgICAgICAoeyBhOiB2MiwgYjogdjYsIGM6IHYxMCwgZDogdjE0IH0gPSBHMnModjIsIHY2LCB2MTAsIHYxNCwgbXNnW29mZnNldCArIHNbaisrXV0pKTtcbiAgICAgICAgKHsgYTogdjMsIGI6IHY3LCBjOiB2MTEsIGQ6IHYxNSB9ID0gRzFzKHYzLCB2NywgdjExLCB2MTUsIG1zZ1tvZmZzZXQgKyBzW2orK11dKSk7XG4gICAgICAgICh7IGE6IHYzLCBiOiB2NywgYzogdjExLCBkOiB2MTUgfSA9IEcycyh2MywgdjcsIHYxMSwgdjE1LCBtc2dbb2Zmc2V0ICsgc1tqKytdXSkpO1xuICAgICAgICAoeyBhOiB2MCwgYjogdjUsIGM6IHYxMCwgZDogdjE1IH0gPSBHMXModjAsIHY1LCB2MTAsIHYxNSwgbXNnW29mZnNldCArIHNbaisrXV0pKTtcbiAgICAgICAgKHsgYTogdjAsIGI6IHY1LCBjOiB2MTAsIGQ6IHYxNSB9ID0gRzJzKHYwLCB2NSwgdjEwLCB2MTUsIG1zZ1tvZmZzZXQgKyBzW2orK11dKSk7XG4gICAgICAgICh7IGE6IHYxLCBiOiB2NiwgYzogdjExLCBkOiB2MTIgfSA9IEcxcyh2MSwgdjYsIHYxMSwgdjEyLCBtc2dbb2Zmc2V0ICsgc1tqKytdXSkpO1xuICAgICAgICAoeyBhOiB2MSwgYjogdjYsIGM6IHYxMSwgZDogdjEyIH0gPSBHMnModjEsIHY2LCB2MTEsIHYxMiwgbXNnW29mZnNldCArIHNbaisrXV0pKTtcbiAgICAgICAgKHsgYTogdjIsIGI6IHY3LCBjOiB2OCwgZDogdjEzIH0gPSBHMXModjIsIHY3LCB2OCwgdjEzLCBtc2dbb2Zmc2V0ICsgc1tqKytdXSkpO1xuICAgICAgICAoeyBhOiB2MiwgYjogdjcsIGM6IHY4LCBkOiB2MTMgfSA9IEcycyh2MiwgdjcsIHY4LCB2MTMsIG1zZ1tvZmZzZXQgKyBzW2orK11dKSk7XG4gICAgICAgICh7IGE6IHYzLCBiOiB2NCwgYzogdjksIGQ6IHYxNCB9ID0gRzFzKHYzLCB2NCwgdjksIHYxNCwgbXNnW29mZnNldCArIHNbaisrXV0pKTtcbiAgICAgICAgKHsgYTogdjMsIGI6IHY0LCBjOiB2OSwgZDogdjE0IH0gPSBHMnModjMsIHY0LCB2OSwgdjE0LCBtc2dbb2Zmc2V0ICsgc1tqKytdXSkpO1xuICAgIH1cbiAgICByZXR1cm4geyB2MCwgdjEsIHYyLCB2MywgdjQsIHY1LCB2NiwgdjcsIHY4LCB2OSwgdjEwLCB2MTEsIHYxMiwgdjEzLCB2MTQsIHYxNSB9O1xufVxuLy8gQmxha2UycyByZXVzZXMgdGhlIFNIQS0yNTYgSVYgd29yZHMgYXMtaXMuXG5jb25zdCBCMlNfSVYgPSAvKiBAX19QVVJFX18gKi8gU0hBMjU2X0lWLnNsaWNlKCk7XG4vKiogSW50ZXJuYWwgYmxha2UycyBoYXNoIGNsYXNzLiAqL1xuZXhwb3J0IGNsYXNzIF9CTEFLRTJzIGV4dGVuZHMgX0JMQUtFMiB7XG4gICAgLy8gSW50ZXJuYWwgc3RhdGUsIHNhbWUgYXMgU0hBLTI1NlxuICAgIHYwID0gQjJTX0lWWzBdIHwgMDtcbiAgICB2MSA9IEIyU19JVlsxXSB8IDA7XG4gICAgdjIgPSBCMlNfSVZbMl0gfCAwO1xuICAgIHYzID0gQjJTX0lWWzNdIHwgMDtcbiAgICB2NCA9IEIyU19JVls0XSB8IDA7XG4gICAgdjUgPSBCMlNfSVZbNV0gfCAwO1xuICAgIHY2ID0gQjJTX0lWWzZdIHwgMDtcbiAgICB2NyA9IEIyU19JVls3XSB8IDA7XG4gICAgY29uc3RydWN0b3Iob3B0cyA9IHt9KSB7XG4gICAgICAgIGNvbnN0IG9sZW4gPSBvcHRzLmRrTGVuID09PSB1bmRlZmluZWQgPyAzMiA6IG9wdHMuZGtMZW47XG4gICAgICAgIHN1cGVyKDY0LCBvbGVuKTtcbiAgICAgICAgY2hlY2tCbGFrZTJPcHRzKG9sZW4sIG9wdHMsIDMyLCA4LCA4KTtcbiAgICAgICAgbGV0IHsga2V5LCBwZXJzb25hbGl6YXRpb24sIHNhbHQgfSA9IG9wdHM7XG4gICAgICAgIGxldCBrZXlMZW5ndGggPSAwO1xuICAgICAgICBpZiAoa2V5ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGFieXRlcyhrZXksIHVuZGVmaW5lZCwgJ2tleScpO1xuICAgICAgICAgICAga2V5TGVuZ3RoID0ga2V5Lmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgICAvLyBSRkMgNzY5MyDCpzIuNTogeG9yIGBwWzBdID0gMHgwMTAxa2tubmAgZGlyZWN0bHkgaW50byBgaFswXWAsIHNpbmNlXG4gICAgICAgIC8vIEJMQUtFMnMgc3RvcmVzIGVhY2ggc3RhdGUgd29yZCBhcyBvbmUgYHUzMmAuXG4gICAgICAgIHRoaXMudjAgXj0gdGhpcy5vdXRwdXRMZW4gfCAoa2V5TGVuZ3RoIDw8IDgpIHwgKDB4MDEgPDwgMTYpIHwgKDB4MDEgPDwgMjQpO1xuICAgICAgICBpZiAoc2FsdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBhYnl0ZXMoc2FsdCwgdW5kZWZpbmVkLCAnc2FsdCcpO1xuICAgICAgICAgICAgY29uc3Qgc2x0ID0gdTMyKHNhbHQpO1xuICAgICAgICAgICAgdGhpcy52NCBePSBzd2FwOElmQkUoc2x0WzBdKTtcbiAgICAgICAgICAgIHRoaXMudjUgXj0gc3dhcDhJZkJFKHNsdFsxXSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHBlcnNvbmFsaXphdGlvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBhYnl0ZXMocGVyc29uYWxpemF0aW9uLCB1bmRlZmluZWQsICdwZXJzb25hbGl6YXRpb24nKTtcbiAgICAgICAgICAgIGNvbnN0IHBlcnMgPSB1MzIocGVyc29uYWxpemF0aW9uKTtcbiAgICAgICAgICAgIHRoaXMudjYgXj0gc3dhcDhJZkJFKHBlcnNbMF0pO1xuICAgICAgICAgICAgdGhpcy52NyBePSBzd2FwOElmQkUocGVyc1sxXSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGtleSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAvLyBQYWQgdG8gYmxvY2tMZW4gYW5kIHVwZGF0ZVxuICAgICAgICAgICAgY29uc3QgdG1wID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5ibG9ja0xlbik7XG4gICAgICAgICAgICB0bXAuc2V0KGtleSk7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZSh0bXApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGdldCgpIHtcbiAgICAgICAgY29uc3QgeyB2MCwgdjEsIHYyLCB2MywgdjQsIHY1LCB2NiwgdjcgfSA9IHRoaXM7XG4gICAgICAgIHJldHVybiBbdjAsIHYxLCB2MiwgdjMsIHY0LCB2NSwgdjYsIHY3XTtcbiAgICB9XG4gICAgLy8gcHJldHRpZXItaWdub3JlXG4gICAgc2V0KHYwLCB2MSwgdjIsIHYzLCB2NCwgdjUsIHY2LCB2Nykge1xuICAgICAgICB0aGlzLnYwID0gdjAgfCAwO1xuICAgICAgICB0aGlzLnYxID0gdjEgfCAwO1xuICAgICAgICB0aGlzLnYyID0gdjIgfCAwO1xuICAgICAgICB0aGlzLnYzID0gdjMgfCAwO1xuICAgICAgICB0aGlzLnY0ID0gdjQgfCAwO1xuICAgICAgICB0aGlzLnY1ID0gdjUgfCAwO1xuICAgICAgICB0aGlzLnY2ID0gdjYgfCAwO1xuICAgICAgICB0aGlzLnY3ID0gdjcgfCAwO1xuICAgIH1cbiAgICBjb21wcmVzcyhtc2csIG9mZnNldCwgaXNMYXN0KSB7XG4gICAgICAgIGNvbnN0IHsgaCwgbCB9ID0gdTY0LmZyb21CaWcoQmlnSW50KHRoaXMubGVuZ3RoKSk7XG4gICAgICAgIC8vIFNlZWQgdjguLnYxNSBmcm9tIHRoZSBJViwgeG9yIHRoZSBsb3cvaGlnaCAzMi1iaXQgYnl0ZSBjb3VudGVyIGludG9cbiAgICAgICAgLy8gdjEyL3YxMywgYW5kIGludmVydCB2MTQgb24gdGhlIGZpbmFsIGJsb2NrLlxuICAgICAgICAvLyBwcmV0dGllci1pZ25vcmVcbiAgICAgICAgY29uc3QgeyB2MCwgdjEsIHYyLCB2MywgdjQsIHY1LCB2NiwgdjcsIHY4LCB2OSwgdjEwLCB2MTEsIHYxMiwgdjEzLCB2MTQsIHYxNSB9ID0gY29tcHJlc3MoQlNJR01BLCBvZmZzZXQsIG1zZywgMTAsIHRoaXMudjAsIHRoaXMudjEsIHRoaXMudjIsIHRoaXMudjMsIHRoaXMudjQsIHRoaXMudjUsIHRoaXMudjYsIHRoaXMudjcsIEIyU19JVlswXSwgQjJTX0lWWzFdLCBCMlNfSVZbMl0sIEIyU19JVlszXSwgbCBeIEIyU19JVls0XSwgaCBeIEIyU19JVls1XSwgaXNMYXN0ID8gfkIyU19JVls2XSA6IEIyU19JVls2XSwgQjJTX0lWWzddKTtcbiAgICAgICAgdGhpcy52MCBePSB2MCBeIHY4O1xuICAgICAgICB0aGlzLnYxIF49IHYxIF4gdjk7XG4gICAgICAgIHRoaXMudjIgXj0gdjIgXiB2MTA7XG4gICAgICAgIHRoaXMudjMgXj0gdjMgXiB2MTE7XG4gICAgICAgIHRoaXMudjQgXj0gdjQgXiB2MTI7XG4gICAgICAgIHRoaXMudjUgXj0gdjUgXiB2MTM7XG4gICAgICAgIHRoaXMudjYgXj0gdjYgXiB2MTQ7XG4gICAgICAgIHRoaXMudjcgXj0gdjcgXiB2MTU7XG4gICAgfVxuICAgIGRlc3Ryb3koKSB7XG4gICAgICAgIHRoaXMuZGVzdHJveWVkID0gdHJ1ZTtcbiAgICAgICAgY2xlYW4odGhpcy5idWZmZXIzMik7XG4gICAgICAgIHRoaXMuc2V0KDAsIDAsIDAsIDAsIDAsIDAsIDAsIDApO1xuICAgIH1cbn1cbi8qKlxuICogQmxha2UycyBoYXNoIGZ1bmN0aW9uLiBGb2N1c2VzIG9uIDgtYml0IHRvIDMyLWJpdCBwbGF0Zm9ybXMuIDEuNXggZmFzdGVyIHRoYW4gYmxha2UyYiBpbiBKUy5cbiAqIEBwYXJhbSBtc2cgLSBtZXNzYWdlIHRoYXQgd291bGQgYmUgaGFzaGVkXG4gKiBAcGFyYW0gb3B0cyAtIE9wdGlvbmFsIG91dHB1dCwgTUFDLCBzYWx0LCBhbmQgcGVyc29uYWxpemF0aW9uIHNldHRpbmdzLlxuICogICBgZGtMZW5gIG11c3QgYmUgMS4uMzIgYnl0ZXM7IGBzYWx0YCBhbmQgYHBlcnNvbmFsaXphdGlvbmAsIGlmIHByZXNlbnQsXG4gKiAgIG11c3QgYmUgOCBieXRlcyBlYWNoLiBTZWUge0BsaW5rIEJsYWtlMk9wdHN9LlxuICogQHJldHVybnMgRGlnZXN0IGJ5dGVzLlxuICogQGV4YW1wbGVcbiAqIEhhc2ggYSBtZXNzYWdlIHdpdGggQmxha2Uycy5cbiAqIGBgYHRzXG4gKiBibGFrZTJzKG5ldyBVaW50OEFycmF5KFs5NywgOTgsIDk5XSkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBibGFrZTJzID0gLyogQF9fUFVSRV9fICovIGNyZWF0ZUhhc2hlcigob3B0cykgPT4gbmV3IF9CTEFLRTJzKG9wdHMpKTtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPWJsYWtlMi5qcy5tYXAiLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG4vKiBnbG9iYWwgd2luZG93ICovXG5pbXBvcnQgeyBibGFrZTJiIH0gZnJvbSBcIkBub2JsZS9oYXNoZXMvYmxha2UyLmpzXCI7XG5pbXBvcnQgeyB1MzIgfSBmcm9tIFwiQG5vYmxlL2hhc2hlcy91dGlscy5qc1wiO1xuaW1wb3J0IHJlYWRsaW5lIGZyb20gXCJyZWFkbGluZVwiO1xuaW1wb3J0IHsgQ2hhQ2hhIH0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuaW1wb3J0IGNyeXB0byBmcm9tIFwiY3J5cHRvXCI7XG5cbmNvbnN0IF9yZXZUYWJsZSA9IFtdO1xuZm9yIChsZXQgaT0wOyBpPDI1NjsgaSsrKSB7XG4gICAgX3JldlRhYmxlW2ldID0gX3JldlNsb3coaSwgOCk7XG59XG5cbmZ1bmN0aW9uIF9yZXZTbG93KGlkeCwgYml0cykge1xuICAgIGxldCByZXMgPTA7XG4gICAgbGV0IGEgPSBpZHg7XG4gICAgZm9yIChsZXQgaT0wOyBpPGJpdHM7IGkrKykge1xuICAgICAgICByZXMgPDw9IDE7XG4gICAgICAgIHJlcyA9IHJlcyB8IChhICYxKTtcbiAgICAgICAgYSA+Pj0xO1xuICAgIH1cbiAgICByZXR1cm4gcmVzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gYml0UmV2ZXJzZShpZHgsIGJpdHMpIHtcbiAgICByZXR1cm4gKFxuICAgICAgICBfcmV2VGFibGVbaWR4ID4+PiAyNF0gfFxuICAgICAgICAoX3JldlRhYmxlWyhpZHggPj4+IDE2KSAmIDB4RkZdIDw8IDgpIHxcbiAgICAgICAgKF9yZXZUYWJsZVsoaWR4ID4+PiA4KSAmIDB4RkZdIDw8IDE2KSB8XG4gICAgICAgIChfcmV2VGFibGVbaWR4ICYgMHhGRl0gPDwgMjQpXG4gICAgKSA+Pj4gKDMyLWJpdHMpO1xufVxuXG5cbmV4cG9ydCBmdW5jdGlvbiBsb2cyKCBWIClcbntcbiAgICByZXR1cm4oICggKCBWICYgMHhGRkZGMDAwMCApICE9PSAwID8gKCBWICY9IDB4RkZGRjAwMDAsIDE2ICkgOiAwICkgfCAoICggViAmIDB4RkYwMEZGMDAgKSAhPT0gMCA/ICggViAmPSAweEZGMDBGRjAwLCA4ICkgOiAwICkgfCAoICggViAmIDB4RjBGMEYwRjAgKSAhPT0gMCA/ICggViAmPSAweEYwRjBGMEYwLCA0ICkgOiAwICkgfCAoICggViAmIDB4Q0NDQ0NDQ0MgKSAhPT0gMCA/ICggViAmPSAweENDQ0NDQ0NDLCAyICkgOiAwICkgfCAoICggViAmIDB4QUFBQUFBQUEgKSAhPT0gMCApICk7XG59XG5cblxuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdEhhc2goYiwgdGl0bGUpIHtcbiAgICBjb25zdCBhID0gbmV3IERhdGFWaWV3KGIuYnVmZmVyLCBiLmJ5dGVPZmZzZXQsIGIuYnl0ZUxlbmd0aCk7XG4gICAgbGV0IFMgPSBcIlwiO1xuICAgIGZvciAobGV0IGk9MDsgaTw0OyBpKyspIHtcbiAgICAgICAgaWYgKGk+MCkgUyArPSBcIlxcblwiO1xuICAgICAgICBTICs9IFwiXFx0XFx0XCI7XG4gICAgICAgIGZvciAobGV0IGo9MDsgajw0OyBqKyspIHtcbiAgICAgICAgICAgIGlmIChqPjApIFMgKz0gXCIgXCI7XG4gICAgICAgICAgICBTICs9IGEuZ2V0VWludDMyKGkqMTYraio0KS50b1N0cmluZygxNikucGFkU3RhcnQoOCwgXCIwXCIpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmICh0aXRsZSkgUyA9IHRpdGxlICsgXCJcXG5cIiArIFM7XG4gICAgcmV0dXJuIFM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBoYXNoSXNFcXVhbChoMSwgaDIpIHtcbiAgICBpZiAoaDEuYnl0ZUxlbmd0aCAhPSBoMi5ieXRlTGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gICAgdmFyIGR2MSA9IG5ldyBJbnQ4QXJyYXkoaDEpO1xuICAgIHZhciBkdjIgPSBuZXcgSW50OEFycmF5KGgyKTtcbiAgICBmb3IgKHZhciBpID0gMCA7IGkgIT0gaDEuYnl0ZUxlbmd0aCA7IGkrKylcbiAgICB7XG4gICAgICAgIGlmIChkdjFbaV0gIT0gZHYyW2ldKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2xvbmVIYXNoZXIoaCkge1xuICAgIHJldHVybiBoLmNsb25lKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmcm9tUGFydGlhbEhhc2gocGFydGlhbCkge1xuICAgIC8vIE5PVEU6IHRoaXMgaXMgdW5zYWZlIGFuZCB1c2VzIGludGVybmFsIEFQSVxuICAgIGNvbnN0IGJ1ZiA9IHBhcnRpYWwuc3ViYXJyYXkoMCwgMTI4KTtcbiAgICBjb25zdCByZXN0ID0gdTMyKHBhcnRpYWwuc3ViYXJyYXkoMTI4KSk7XG4gICAgY29uc3QgcmVzID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG4gICAgcmVzLmJ1ZmZlci5zZXQoYnVmKTtcbiAgICAocmVzLnYwbCA9IHJlc3RbMF0gfCAwKSwgKHJlcy52MGggPSByZXN0WzFdIHwgMCk7XG4gICAgKHJlcy52MWwgPSByZXN0WzJdIHwgMCksIChyZXMudjFoID0gcmVzdFszXSB8IDApO1xuICAgIChyZXMudjJsID0gcmVzdFs0XSB8IDApLCAocmVzLnYyaCA9IHJlc3RbNV0gfCAwKTtcbiAgICAocmVzLnYzbCA9IHJlc3RbNl0gfCAwKSwgKHJlcy52M2ggPSByZXN0WzddIHwgMCk7XG4gICAgKHJlcy52NGwgPSByZXN0WzhdIHwgMCksIChyZXMudjRoID0gcmVzdFs5XSB8IDApO1xuICAgIChyZXMudjVsID0gcmVzdFsxMF0gfCAwKSwgKHJlcy52NWggPSByZXN0WzExXSB8IDApO1xuICAgIChyZXMudjZsID0gcmVzdFsxMl0gfCAwKSwgKHJlcy52NmggPSByZXN0WzEzXSB8IDApO1xuICAgIChyZXMudjdsID0gcmVzdFsxNF0gfCAwKSwgKHJlcy52N2ggPSByZXN0WzE1XSB8IDApO1xuICAgIGNvbnN0IHNoaWZ0ID0gMiAqKiAzMjtcbiAgICBjb25zdCBsZW4gPSByZXN0WzE2XSArIHJlc3RbMTddICogc2hpZnQ7XG4gICAgY29uc3QgcG9zID0gcmVzdFsxOF0gKyByZXN0WzE5XSAqIHNoaWZ0O1xuICAgIHJlcy5sZW5ndGggPSBsZW4gKyBwb3M7XG4gICAgcmVzLnBvcyA9IHBvcztcbiAgICByZXR1cm4gcmVzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdG9QYXJ0aWFsSGFzaChoYXNoKXtcbiAgICAvLyBOT1RFOiB0aGlzIGlzIHVuc2FmZSBhbmQgdXNlcyBpbnRlcm5hbCBBUElcbiAgICBjb25zdCByZXMgPSBuZXcgVWludDhBcnJheSgyMTYpO1xuICAgIGNvbnN0IHJlczMyID0gdTMyKHJlcy5zdWJhcnJheSgxMjgpKTtcbiAgICByZXMuc2V0KGhhc2guYnVmZmVyKTtcbiAgICAocmVzMzJbMF0gPSBoYXNoLnYwbCksIChyZXMzMlsxXSA9IGhhc2gudjBoKTtcbiAgICAocmVzMzJbMl0gPSBoYXNoLnYxbCksIChyZXMzMlszXSA9IGhhc2gudjFoKTtcbiAgICAocmVzMzJbNF0gPSBoYXNoLnYybCksIChyZXMzMls1XSA9IGhhc2gudjJoKTtcbiAgICAocmVzMzJbNl0gPSBoYXNoLnYzbCksIChyZXMzMls3XSA9IGhhc2gudjNoKTtcbiAgICAocmVzMzJbOF0gPSBoYXNoLnY0bCksIChyZXMzMls5XSA9IGhhc2gudjRoKTtcbiAgICAocmVzMzJbMTBdID0gaGFzaC52NWwpLCAocmVzMzJbMTFdID0gaGFzaC52NWgpO1xuICAgIChyZXMzMlsxMl0gPSBoYXNoLnY2bCksIChyZXMzMlsxM10gPSBoYXNoLnY2aCk7XG4gICAgKHJlczMyWzE0XSA9IGhhc2gudjdsKSwgKHJlczMyWzE1XSA9IGhhc2gudjdoKTtcbiAgICByZXMzMlsxOF0gPSBoYXNoLnBvcztcbiAgICByZXMzMlsxNl0gPSBoYXNoLmxlbmd0aC1oYXNoLnBvcztcbiAgICByZXR1cm4gcmVzO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2FtZVJhdGlvKGN1cnZlLCBnMXMsIGcxc3gsIGcycywgZzJzeCkge1xuICAgIGlmIChjdXJ2ZS5HMS5pc1plcm8oZzFzKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmIChjdXJ2ZS5HMS5pc1plcm8oZzFzeCkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAoY3VydmUuRzIuaXNaZXJvKGcycykpIHJldHVybiBmYWxzZTtcbiAgICBpZiAoY3VydmUuRzIuaXNaZXJvKGcyc3gpKSByZXR1cm4gZmFsc2U7XG4gICAgLy8gcmV0dXJuIGN1cnZlLkYxMi5lcShjdXJ2ZS5wYWlyaW5nKGcxcywgZzJzeCksIGN1cnZlLnBhaXJpbmcoZzFzeCwgZzJzKSk7XG4gICAgY29uc3QgcmVzID0gYXdhaXQgY3VydmUucGFpcmluZ0VxKGcxcywgZzJzeCwgY3VydmUuRzEubmVnKGcxc3gpLCBnMnMpO1xuICAgIHJldHVybiByZXM7XG59XG5cblxuZXhwb3J0IGZ1bmN0aW9uIGFza0VudHJvcHkoKSB7XG4gICAgLy8gVXNlIHRoZSBicm93c2VyIHByb21wdCBvbmx5IHdoZW4gYSByZWFsIERPTSB3aW5kb3cgZXhpc3RzLiBcIm5vdCBOb2RlXCIgaXNcbiAgICAvLyBOT1QgdGhlIHNhbWUgYXMgXCJicm93c2VyXCIgKEJ1bi9EZW5vL2VkZ2UvU0VTIGhhdmUgbmVpdGhlciB3aW5kb3cgbm9yIGFyZVxuICAgIC8vIGNsYXNzaWMgTm9kZSksIHNvIGRldGVjdCB0aGUgYWN0dWFsIEFQSS5cbiAgICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiAmJiB0eXBlb2Ygd2luZG93LnByb21wdCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgIHJldHVybiB3aW5kb3cucHJvbXB0KFwiRW50ZXIgYSByYW5kb20gdGV4dC4gKEVudHJvcHkpOiBcIiwgXCJcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcmwgPSByZWFkbGluZS5jcmVhdGVJbnRlcmZhY2Uoe1xuICAgICAgICAgICAgaW5wdXQ6IHByb2Nlc3Muc3RkaW4sXG4gICAgICAgICAgICBvdXRwdXQ6IHByb2Nlc3Muc3Rkb3V0XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICAgICAgcmwucXVlc3Rpb24oXCJFbnRlciBhIHJhbmRvbSB0ZXh0LiAoRW50cm9weSk6IFwiLCAoaW5wdXQpID0+IHJlc29sdmUoaW5wdXQpICk7XG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFJhbmRvbUJ5dGVzKG4pIHtcbiAgICBsZXQgYXJyYXkgPSBuZXcgVWludDhBcnJheShuKTtcbiAgICBpZiAoY3J5cHRvICYmIGNyeXB0by5yYW5kb21GaWxsU3luYykgeyAvLyBOb2RlOiBubyBwZXItY2FsbCBzaXplIGxpbWl0XG4gICAgICAgIGNyeXB0by5yYW5kb21GaWxsU3luYyhhcnJheSk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgZ2xvYmFsVGhpcy5jcnlwdG8gIT09IFwidW5kZWZpbmVkXCIgJiYgZ2xvYmFsVGhpcy5jcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKSB7XG4gICAgICAgIC8vIFdlYiBDcnlwdG8gY2FwcyBlYWNoIGNhbGwgYXQgNjU1MzYgYnl0ZXM7IGZpbGwgaW4gd2luZG93cy5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpICs9IDY1NTM2KSB7XG4gICAgICAgICAgICBnbG9iYWxUaGlzLmNyeXB0by5nZXRSYW5kb21WYWx1ZXMoYXJyYXkuc3ViYXJyYXkoaSwgTWF0aC5taW4oaSArIDY1NTM2LCBuKSkpO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gc2VjdXJlIHJhbmRvbSBzb3VyY2UgYXZhaWxhYmxlXCIpO1xuICAgIH1cbiAgICByZXR1cm4gYXJyYXk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaGEyNTZkaWdlc3QoZGF0YSkge1xuICAgIGlmIChjcnlwdG8gJiYgY3J5cHRvLmNyZWF0ZUhhc2gpIHsgLy8gTm9kZVxuICAgICAgICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKGRhdGEpLmRpZ2VzdCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFdlYiBDcnlwdG86IHBhc3MgdGhlIHZpZXcgKGRhdGEpLCBub3QgZGF0YS5idWZmZXIsIHNvIGJ5dGVPZmZzZXQgYW5kXG4gICAgICAgIC8vIGJ5dGVMZW5ndGggb2Ygc3ViYXJyYXkgdmlld3MgYXJlIHJlc3BlY3RlZC5cbiAgICAgICAgY29uc3QgYnVmZmVyID0gYXdhaXQgZ2xvYmFsVGhpcy5jcnlwdG8uc3VidGxlLmRpZ2VzdChcIlNIQS0yNTZcIiwgZGF0YSk7XG4gICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheShidWZmZXIpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBAcGFyYW0ge1VpbnQ4QXJyYXl9IGRhdGFcbiAqIEBwYXJhbSB7bnVtYmVyfSBvZmZzZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlYWRVSW50MzJCRShkYXRhLCBvZmZzZXQpIHtcbiAgICByZXR1cm4gbmV3IERhdGFWaWV3KGRhdGEuYnVmZmVyKS5nZXRVaW50MzIob2Zmc2V0LCBmYWxzZSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRSYW5kb21SbmcoZW50cm9weSkge1xuICAgIC8vIEdlbmVyYXRlIGEgcmFuZG9tIFJuZ1xuICAgIHdoaWxlICghZW50cm9weSkge1xuICAgICAgICBlbnRyb3B5ID0gYXdhaXQgYXNrRW50cm9weSgpO1xuICAgIH1cbiAgICBjb25zdCBoYXNoZXIgPSBibGFrZTJiLmNyZWF0ZSg2NCk7XG4gICAgaGFzaGVyLnVwZGF0ZShnZXRSYW5kb21CeXRlcyg2NCkpO1xuICAgIGNvbnN0IGVuYyA9IG5ldyBUZXh0RW5jb2RlcigpOyAvLyBhbHdheXMgdXRmLThcbiAgICBoYXNoZXIudXBkYXRlKGVuYy5lbmNvZGUoZW50cm9weSkpO1xuICAgIGNvbnN0IGhhc2ggPSBoYXNoZXIuZGlnZXN0KCk7XG5cbiAgICBjb25zdCBzZWVkID0gW107XG4gICAgZm9yIChsZXQgaT0wO2k8ODtpKyspIHtcbiAgICAgICAgc2VlZFtpXSA9IHJlYWRVSW50MzJCRShoYXNoLCBpKjQpO1xuICAgIH1cbiAgICBjb25zdCBybmcgPSBuZXcgQ2hhQ2hhKHNlZWQpO1xuICAgIHJldHVybiBybmc7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBybmdGcm9tQmVhY29uUGFyYW1zKGJlYWNvbkhhc2gsIG51bUl0ZXJhdGlvbnNFeHApIHtcbiAgICBsZXQgbkl0ZXJhdGlvbnNJbm5lcjtcbiAgICBsZXQgbkl0ZXJhdGlvbnNPdXRlcjtcbiAgICBpZiAobnVtSXRlcmF0aW9uc0V4cDwzMikge1xuICAgICAgICBuSXRlcmF0aW9uc0lubmVyID0gKDEgPDwgbnVtSXRlcmF0aW9uc0V4cCkgPj4+IDA7XG4gICAgICAgIG5JdGVyYXRpb25zT3V0ZXIgPSAxO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIG5JdGVyYXRpb25zSW5uZXIgPSAweDEwMDAwMDAwMDtcbiAgICAgICAgbkl0ZXJhdGlvbnNPdXRlciA9ICgxIDw8IChudW1JdGVyYXRpb25zRXhwLTMyKSkgPj4+IDA7XG4gICAgfVxuXG4gICAgbGV0IGN1ckhhc2ggPSBiZWFjb25IYXNoO1xuICAgIGZvciAobGV0IGk9MDsgaTxuSXRlcmF0aW9uc091dGVyOyBpKyspIHtcbiAgICAgICAgZm9yIChsZXQgaj0wOyBqPG5JdGVyYXRpb25zSW5uZXI7IGorKykge1xuICAgICAgICAgICAgY3VySGFzaCA9IGF3YWl0IHNoYTI1NmRpZ2VzdChjdXJIYXNoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGN1ckhhc2hWID0gbmV3IERhdGFWaWV3KGN1ckhhc2guYnVmZmVyLCBjdXJIYXNoLmJ5dGVPZmZzZXQsIGN1ckhhc2guYnl0ZUxlbmd0aCk7XG4gICAgY29uc3Qgc2VlZCA9IFtdO1xuICAgIGZvciAobGV0IGk9MDsgaTw4OyBpKyspIHtcbiAgICAgICAgc2VlZFtpXSA9IGN1ckhhc2hWLmdldFVpbnQzMihpKjQsIGZhbHNlKTtcbiAgICB9XG5cbiAgICBjb25zdCBybmcgPSBuZXcgQ2hhQ2hhKHNlZWQpO1xuXG4gICAgcmV0dXJuIHJuZztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGhleDJCeXRlQXJyYXkocykge1xuICAgIGlmIChzIGluc3RhbmNlb2YgVWludDhBcnJheSkgcmV0dXJuIHM7XG4gICAgaWYgKHMuc2xpY2UoMCwyKSA9PSBcIjB4XCIpIHM9IHMuc2xpY2UoMik7XG4gICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KHMubWF0Y2goL1tcXGRhLWZdezJ9L2dpKS5tYXAoZnVuY3Rpb24gKGgpIHtcbiAgICAgICAgcmV0dXJuIHBhcnNlSW50KGgsIDE2KTtcbiAgICB9KSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBieXRlQXJyYXkyaGV4KGJ5dGVBcnJheSkge1xuICAgIHJldHVybiBBcnJheS5wcm90b3R5cGUubWFwLmNhbGwoYnl0ZUFycmF5LCBmdW5jdGlvbihieXRlKSB7XG4gICAgICAgIHJldHVybiAoXCIwXCIgKyAoYnl0ZSAmIDB4RkYpLnRvU3RyaW5nKDE2KSkuc2xpY2UoLTIpO1xuICAgIH0pLmpvaW4oXCJcIik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzdHJpbmdpZnlCaWdJbnRzV2l0aEZpZWxkKEZyLCBvKSB7XG4gICAgaWYgKG8gaW5zdGFuY2VvZiBVaW50OEFycmF5KSAge1xuICAgICAgICByZXR1cm4gRnIudG9TdHJpbmcobyk7XG4gICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KG8pKSB7XG4gICAgICAgIHJldHVybiBvLm1hcChzdHJpbmdpZnlCaWdJbnRzV2l0aEZpZWxkLmJpbmQobnVsbCwgRnIpKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBvID09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgY29uc3QgcmVzID0ge307XG4gICAgICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhvKTtcbiAgICAgICAga2V5cy5mb3JFYWNoKCAoaykgPT4ge1xuICAgICAgICAgICAgcmVzW2tdID0gc3RyaW5naWZ5QmlnSW50c1dpdGhGaWVsZChGciwgb1trXSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH0gZWxzZSBpZiAoKHR5cGVvZihvKSA9PSBcImJpZ2ludFwiKSB8fCBvLmVxICE9PSB1bmRlZmluZWQpICB7XG4gICAgICAgIHJldHVybiBvLnRvU3RyaW5nKDEwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gbztcbiAgICB9XG59XG4iLCJleHBvcnQgY29uc3QgSEVBREVSX1pLRVlfU0VDVElPTiA9IDE7XG5cbmV4cG9ydCBjb25zdCBHUk9USDE2X1BST1RPQ09MX0lEID0gMTtcbmV4cG9ydCBjb25zdCBQTE9OS19QUk9UT0NPTF9JRCA9IDI7XG5leHBvcnQgY29uc3QgRkZMT05LX1BST1RPQ09MX0lEID0gMTA7XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDIyIGlkZW4zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG4vLyBGRmxvbmsgY29uc3RhbnRzXG5leHBvcnQgY29uc3QgRkZfVF9QT0xfREVHX01JTiA9IDM7XG5cbi8vIEZGbG9uayBBXG5leHBvcnQgY29uc3QgQSA9IDEyO1xuXG4vLyBaS0VZIGNvbnN0YW50c1xuZXhwb3J0IGNvbnN0IFpLRVlfRkZfTlNFQ1RJT05TID0gMTc7XG5cbmV4cG9ydCBjb25zdCBaS0VZX0ZGX0hFQURFUl9TRUNUSU9OID0gMjtcbmV4cG9ydCBjb25zdCBaS0VZX0ZGX0FERElUSU9OU19TRUNUSU9OID0gMztcbmV4cG9ydCBjb25zdCBaS0VZX0ZGX0FfTUFQX1NFQ1RJT04gPSA0O1xuZXhwb3J0IGNvbnN0IFpLRVlfRkZfQl9NQVBfU0VDVElPTiA9IDU7XG5leHBvcnQgY29uc3QgWktFWV9GRl9DX01BUF9TRUNUSU9OID0gNjtcbmV4cG9ydCBjb25zdCBaS0VZX0ZGX1FMX1NFQ1RJT04gPSA3O1xuZXhwb3J0IGNvbnN0IFpLRVlfRkZfUVJfU0VDVElPTiA9IDg7XG5leHBvcnQgY29uc3QgWktFWV9GRl9RTV9TRUNUSU9OID0gOTtcbmV4cG9ydCBjb25zdCBaS0VZX0ZGX1FPX1NFQ1RJT04gPSAxMDtcbmV4cG9ydCBjb25zdCBaS0VZX0ZGX1FDX1NFQ1RJT04gPSAxMTtcbmV4cG9ydCBjb25zdCBaS0VZX0ZGX1NJR01BMV9TRUNUSU9OID0gMTI7XG5leHBvcnQgY29uc3QgWktFWV9GRl9TSUdNQTJfU0VDVElPTiA9IDEzO1xuZXhwb3J0IGNvbnN0IFpLRVlfRkZfU0lHTUEzX1NFQ1RJT04gPSAxNDtcbmV4cG9ydCBjb25zdCBaS0VZX0ZGX0xBR1JBTkdFX1NFQ1RJT04gPSAxNTtcbmV4cG9ydCBjb25zdCBaS0VZX0ZGX1BUQVVfU0VDVElPTiA9IDE2O1xuZXhwb3J0IGNvbnN0IFpLRVlfRkZfQzBfU0VDVElPTiA9IDE3O1xuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuLy8gRm9ybWF0XG4vLyA9PT09PT1cbi8vIEhlYWRlcigxKVxuLy8gICAgICBQcm92ZXIgVHlwZSAxIEdyb3RoXG4vLyBIZWFkZXJHcm90aCgyKVxuLy8gICAgICBuOHFcbi8vICAgICAgcVxuLy8gICAgICBuOHJcbi8vICAgICAgclxuLy8gICAgICBOVmFyc1xuLy8gICAgICBOUHViXG4vLyAgICAgIERvbWFpblNpemUgIChtdWx0aXBsZSBvZiAyXG4vLyAgICAgIGFscGhhMVxuLy8gICAgICBiZXRhMVxuLy8gICAgICBkZWx0YTFcbi8vICAgICAgYmV0YTJcbi8vICAgICAgZ2FtbWEyXG4vLyAgICAgIGRlbHRhMlxuLy8gSUMoMylcbi8vIENvZWZzKDQpXG4vLyBQb2ludHNBKDUpXG4vLyBQb2ludHNCMSg2KVxuLy8gUG9pbnRzQjIoNylcbi8vIFBvaW50c0MoOClcbi8vIFBvaW50c0goOSlcbi8vIENvbnRyaWJ1dGlvbnMoMTApXG5cbmltcG9ydCB7IFNjYWxhciwgRjFGaWVsZCB9IGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmltcG9ydCAqIGFzIGJpbkZpbGVVdGlscyBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuXG5pbXBvcnQgeyBnZXRDdXJ2ZUZyb21RIGFzIGdldEN1cnZlIH0gZnJvbSBcIi4vY3VydmVzLmpzXCI7XG5pbXBvcnQgeyBsb2cyIH0gZnJvbSBcIi4vbWlzYy5qc1wiO1xuaW1wb3J0IHtGRkxPTktfUFJPVE9DT0xfSUQsIEdST1RIMTZfUFJPVE9DT0xfSUQsIFBMT05LX1BST1RPQ09MX0lEfSBmcm9tIFwiLi96a2V5X2NvbnN0YW50cy5qc1wiO1xuaW1wb3J0IHtaS0VZX0ZGX0hFQURFUl9TRUNUSU9OfSBmcm9tIFwiLi9mZmxvbmtfY29uc3RhbnRzLmpzXCI7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZUhlYWRlcihmZCwgemtleSkge1xuXG4gICAgLy8gV3JpdGUgdGhlIGhlYWRlclxuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkLCAxKTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKDEpOyAvLyBHcm90aFxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmQpO1xuXG4gICAgLy8gV3JpdGUgdGhlIEdyb3RoIGhlYWRlciBzZWN0aW9uXG4gICAgLy8vLy8vLy8vLy9cblxuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgZ2V0Q3VydmUoemtleS5xKTtcblxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZCwgMik7XG4gICAgY29uc3QgcHJpbWVRID0gY3VydmUucTtcbiAgICBjb25zdCBuOHEgPSAoTWF0aC5mbG9vciggKFNjYWxhci5iaXRMZW5ndGgocHJpbWVRKSAtIDEpIC8gNjQpICsxKSo4O1xuXG4gICAgY29uc3QgcHJpbWVSID0gY3VydmUucjtcbiAgICBjb25zdCBuOHIgPSAoTWF0aC5mbG9vciggKFNjYWxhci5iaXRMZW5ndGgocHJpbWVSKSAtIDEpIC8gNjQpICsxKSo4O1xuXG4gICAgYXdhaXQgZmQud3JpdGVVTEUzMihuOHEpO1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy53cml0ZUJpZ0ludChmZCwgcHJpbWVRLCBuOHEpO1xuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIobjhyKTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMud3JpdGVCaWdJbnQoZmQsIHByaW1lUiwgbjhyKTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKHprZXkublZhcnMpOyAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUb3RhbCBudW1iZXIgb2YgYmFyc1xuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoemtleS5uUHVibGljKTsgICAgICAgICAgICAgICAgICAgICAgIC8vIFRvdGFsIG51bWJlciBvZiBwdWJsaWMgdmFycyAobm90IGluY2x1ZGluZyBPTkUpXG4gICAgYXdhaXQgZmQud3JpdGVVTEUzMih6a2V5LmRvbWFpblNpemUpOyAgICAgICAgICAgICAgICAgIC8vIGRvbWFpblNpemVcbiAgICBhd2FpdCB3cml0ZUcxKGZkLCBjdXJ2ZSwgemtleS52a19hbHBoYV8xKTtcbiAgICBhd2FpdCB3cml0ZUcxKGZkLCBjdXJ2ZSwgemtleS52a19iZXRhXzEpO1xuICAgIGF3YWl0IHdyaXRlRzIoZmQsIGN1cnZlLCB6a2V5LnZrX2JldGFfMik7XG4gICAgYXdhaXQgd3JpdGVHMihmZCwgY3VydmUsIHprZXkudmtfZ2FtbWFfMik7XG4gICAgYXdhaXQgd3JpdGVHMShmZCwgY3VydmUsIHprZXkudmtfZGVsdGFfMSk7XG4gICAgYXdhaXQgd3JpdGVHMihmZCwgY3VydmUsIHprZXkudmtfZGVsdGFfMik7XG5cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkKTtcblxuXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZVpLZXkoZmlsZU5hbWUsIHprZXkpIHtcblxuICAgIGxldCBjdXJ2ZSA9IGdldEN1cnZlKHprZXkucSk7XG5cbiAgICBjb25zdCBmZCA9IGF3YWl0IGJpbkZpbGVVdGlscy5jcmVhdGVCaW5GaWxlKGZpbGVOYW1lLFwiemtleVwiLCAxLCA5KTtcblxuICAgIGF3YWl0IHdyaXRlSGVhZGVyKGZkLCB6a2V5KTtcbiAgICBjb25zdCBuOHIgPSAoTWF0aC5mbG9vciggKFNjYWxhci5iaXRMZW5ndGgoemtleS5yKSAtIDEpIC8gNjQpICsxKSo4O1xuICAgIGNvbnN0IFJyID0gU2NhbGFyLm1vZChTY2FsYXIuc2hsKDEsIG44cio4KSwgemtleS5yKTtcbiAgICBjb25zdCBSMnIgPSBTY2FsYXIubW9kKFNjYWxhci5tdWwoUnIsUnIpLCB6a2V5LnIpO1xuXG4gICAgLy8gV3JpdGUgUG9scyAoQSBhbmQgQiAoQyBjYW4gYmUgb21pdHRlZCkpXG4gICAgLy8vLy8vLy8vLy9cblxuICAgIHprZXkuY2NvZWZzID0gemtleS5jY29lZnMuZmlsdGVyKGMgPT4gYy5tYXRyaXg8Mik7XG4gICAgemtleS5jY29lZnMuc29ydCggKGEsYikgPT4gYS5jb25zdHJhaW50IC0gYi5jb25zdHJhaW50ICk7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkLCA0KTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKHprZXkuY2NvZWZzLmxlbmd0aCk7XG4gICAgZm9yIChsZXQgaT0wOyBpPHprZXkuY2NvZWZzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGNvZWYgPSB6a2V5LmNjb2Vmc1tpXTtcbiAgICAgICAgYXdhaXQgZmQud3JpdGVVTEUzMihjb2VmLm1hdHJpeCk7XG4gICAgICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoY29lZi5jb25zdHJhaW50KTtcbiAgICAgICAgYXdhaXQgZmQud3JpdGVVTEUzMihjb2VmLnNpZ25hbCk7XG4gICAgICAgIGF3YWl0IHdyaXRlRnIyKGNvZWYudmFsdWUpO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkKTtcblxuXG4gICAgLy8gV3JpdGUgSUMgU2VjdGlvblxuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkLCAzKTtcbiAgICBmb3IgKGxldCBpPTA7IGk8PSB6a2V5Lm5QdWJsaWM7IGkrKykge1xuICAgICAgICBhd2FpdCB3cml0ZUcxKGZkLCBjdXJ2ZSwgemtleS5JQ1tpXSApO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkKTtcblxuXG4gICAgLy8gV3JpdGUgQVxuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkLCA1KTtcbiAgICBmb3IgKGxldCBpPTA7IGk8emtleS5uVmFyczsgaSsrKSB7XG4gICAgICAgIGF3YWl0IHdyaXRlRzEoZmQsIGN1cnZlLCB6a2V5LkFbaV0pO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkKTtcblxuICAgIC8vIFdyaXRlIEIxXG4gICAgLy8vLy8vLy8vLy9cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24oZmQsIDYpO1xuICAgIGZvciAobGV0IGk9MDsgaTx6a2V5Lm5WYXJzOyBpKyspIHtcbiAgICAgICAgYXdhaXQgd3JpdGVHMShmZCwgY3VydmUsIHprZXkuQjFbaV0pO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkKTtcblxuICAgIC8vIFdyaXRlIEIyXG4gICAgLy8vLy8vLy8vLy9cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24oZmQsIDcpO1xuICAgIGZvciAobGV0IGk9MDsgaTx6a2V5Lm5WYXJzOyBpKyspIHtcbiAgICAgICAgYXdhaXQgd3JpdGVHMihmZCwgY3VydmUsIHprZXkuQjJbaV0pO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkKTtcblxuICAgIC8vIFdyaXRlIENcbiAgICAvLy8vLy8vLy8vL1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZCwgOCk7XG4gICAgZm9yIChsZXQgaT16a2V5Lm5QdWJsaWMrMTsgaTx6a2V5Lm5WYXJzOyBpKyspIHtcbiAgICAgICAgYXdhaXQgd3JpdGVHMShmZCwgY3VydmUsIHprZXkuQ1tpXSk7XG4gICAgfVxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmQpO1xuXG5cbiAgICAvLyBXcml0ZSBIIHBvaW50c1xuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkLCA5KTtcbiAgICBmb3IgKGxldCBpPTA7IGk8emtleS5kb21haW5TaXplOyBpKyspIHtcbiAgICAgICAgYXdhaXQgd3JpdGVHMShmZCwgY3VydmUsIHprZXkuaEV4cHNbaV0pO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkKTtcblxuICAgIGF3YWl0IGZkLmNsb3NlKCk7XG5cbiAgICBhc3luYyBmdW5jdGlvbiB3cml0ZUZyMihuKSB7XG4gICAgICAgIC8vIENvbnZlcnQgdG8gbW9udGdvbWVyeVxuICAgICAgICBuID0gU2NhbGFyLm1vZCggU2NhbGFyLm11bChuLCBSMnIpLCB6a2V5LnIpO1xuXG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy53cml0ZUJpZ0ludChmZCwgbiwgbjhyKTtcbiAgICB9XG5cbn1cblxuYXN5bmMgZnVuY3Rpb24gd3JpdGVHMShmZCwgY3VydmUsIHApIHtcbiAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkoY3VydmUuRzEuRi5uOCoyKTtcbiAgICBjdXJ2ZS5HMS50b1JwckxFTShidWZmLCAwLCBwKTtcbiAgICBhd2FpdCBmZC53cml0ZShidWZmKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gd3JpdGVHMihmZCwgY3VydmUsIHApIHtcbiAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkoY3VydmUuRzIuRi5uOCoyKTtcbiAgICBjdXJ2ZS5HMi50b1JwckxFTShidWZmLCAwLCBwKTtcbiAgICBhd2FpdCBmZC53cml0ZShidWZmKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZEcxKGZkLCBjdXJ2ZSwgdG9PYmplY3QpIHtcbiAgICBjb25zdCBidWZmID0gYXdhaXQgZmQucmVhZChjdXJ2ZS5HMS5GLm44KjIpO1xuICAgIGNvbnN0IHJlcyA9IGN1cnZlLkcxLmZyb21ScHJMRU0oYnVmZiwgMCk7XG4gICAgcmV0dXJuIHRvT2JqZWN0ID8gY3VydmUuRzEudG9PYmplY3QocmVzKSA6IHJlcztcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZEcyKGZkLCBjdXJ2ZSwgdG9PYmplY3QpIHtcbiAgICBjb25zdCBidWZmID0gYXdhaXQgZmQucmVhZChjdXJ2ZS5HMi5GLm44KjIpO1xuICAgIGNvbnN0IHJlcyA9IGN1cnZlLkcyLmZyb21ScHJMRU0oYnVmZiwgMCk7XG4gICAgcmV0dXJuIHRvT2JqZWN0ID8gY3VydmUuRzIudG9PYmplY3QocmVzKSA6IHJlcztcbn1cblxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZEhlYWRlcihmZCwgc2VjdGlvbnMsIHRvT2JqZWN0LCBvcHRpb25zKSB7XG4gICAgLy8gUmVhZCBIZWFkZXJcbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIDEpO1xuICAgIGNvbnN0IHByb3RvY29sSWQgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmQpO1xuXG4gICAgaWYgKHByb3RvY29sSWQgPT09IEdST1RIMTZfUFJPVE9DT0xfSUQpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHJlYWRIZWFkZXJHcm90aDE2KGZkLCBzZWN0aW9ucywgdG9PYmplY3QsIG9wdGlvbnMpO1xuICAgIH0gZWxzZSBpZiAocHJvdG9jb2xJZCA9PT0gUExPTktfUFJPVE9DT0xfSUQpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHJlYWRIZWFkZXJQbG9uayhmZCwgc2VjdGlvbnMsIHRvT2JqZWN0LCBvcHRpb25zKTtcbiAgICB9IGVsc2UgaWYgKHByb3RvY29sSWQgPT09IEZGTE9OS19QUk9UT0NPTF9JRCkge1xuICAgICAgICByZXR1cm4gYXdhaXQgcmVhZEhlYWRlckZGbG9uayhmZCwgc2VjdGlvbnMsIHRvT2JqZWN0LCBvcHRpb25zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJQcm90b2NvbCBub3Qgc3VwcG9ydGVkOiBcIik7XG4gICAgfVxufVxuXG5cblxuXG5hc3luYyBmdW5jdGlvbiByZWFkSGVhZGVyR3JvdGgxNihmZCwgc2VjdGlvbnMsIHRvT2JqZWN0LCBvcHRpb25zKSB7XG4gICAgY29uc3QgemtleSA9IHt9O1xuXG4gICAgemtleS5wcm90b2NvbCA9IFwiZ3JvdGgxNlwiO1xuXG4gICAgLy8gUmVhZCBHcm90aCBIZWFkZXJcbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIDIpO1xuICAgIGNvbnN0IG44cSA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkubjhxID0gbjhxO1xuICAgIHprZXkucSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmlnSW50KGZkLCBuOHEpO1xuXG4gICAgY29uc3QgbjhyID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgemtleS5uOHIgPSBuOHI7XG4gICAgemtleS5yID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRCaWdJbnQoZmQsIG44cik7XG4gICAgemtleS5jdXJ2ZSA9IGF3YWl0IGdldEN1cnZlKHprZXkucSwgb3B0aW9ucyk7XG4gICAgemtleS5uVmFycyA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkublB1YmxpYyA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkuZG9tYWluU2l6ZSA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkucG93ZXIgPSBsb2cyKHprZXkuZG9tYWluU2l6ZSk7XG4gICAgemtleS52a19hbHBoYV8xID0gYXdhaXQgcmVhZEcxKGZkLCB6a2V5LmN1cnZlLCB0b09iamVjdCk7XG4gICAgemtleS52a19iZXRhXzEgPSBhd2FpdCByZWFkRzEoZmQsIHprZXkuY3VydmUsIHRvT2JqZWN0KTtcbiAgICB6a2V5LnZrX2JldGFfMiA9IGF3YWl0IHJlYWRHMihmZCwgemtleS5jdXJ2ZSwgdG9PYmplY3QpO1xuICAgIHprZXkudmtfZ2FtbWFfMiA9IGF3YWl0IHJlYWRHMihmZCwgemtleS5jdXJ2ZSwgdG9PYmplY3QpO1xuICAgIHprZXkudmtfZGVsdGFfMSA9IGF3YWl0IHJlYWRHMShmZCwgemtleS5jdXJ2ZSwgdG9PYmplY3QpO1xuICAgIHprZXkudmtfZGVsdGFfMiA9IGF3YWl0IHJlYWRHMihmZCwgemtleS5jdXJ2ZSwgdG9PYmplY3QpO1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRSZWFkU2VjdGlvbihmZCk7XG5cbiAgICByZXR1cm4gemtleTtcblxufVxuXG5hc3luYyBmdW5jdGlvbiByZWFkSGVhZGVyUGxvbmsoZmQsIHNlY3Rpb25zLCB0b09iamVjdCwgb3B0aW9ucykge1xuICAgIGNvbnN0IHprZXkgPSB7fTtcblxuICAgIHprZXkucHJvdG9jb2wgPSBcInBsb25rXCI7XG5cbiAgICAvLyBSZWFkIFBsb25rIEhlYWRlclxuICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkLCBzZWN0aW9ucywgMik7XG4gICAgY29uc3QgbjhxID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgemtleS5uOHEgPSBuOHE7XG4gICAgemtleS5xID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRCaWdJbnQoZmQsIG44cSk7XG5cbiAgICBjb25zdCBuOHIgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICB6a2V5Lm44ciA9IG44cjtcbiAgICB6a2V5LnIgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpZ0ludChmZCwgbjhyKTtcbiAgICB6a2V5LmN1cnZlID0gYXdhaXQgZ2V0Q3VydmUoemtleS5xLCBvcHRpb25zKTtcbiAgICB6a2V5Lm5WYXJzID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgemtleS5uUHVibGljID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgemtleS5kb21haW5TaXplID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgemtleS5wb3dlciA9IGxvZzIoemtleS5kb21haW5TaXplKTtcbiAgICB6a2V5Lm5BZGRpdGlvbnMgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICB6a2V5Lm5Db25zdHJhaW50cyA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkuazEgPSBhd2FpdCBmZC5yZWFkKG44cik7XG4gICAgemtleS5rMiA9IGF3YWl0IGZkLnJlYWQobjhyKTtcblxuICAgIHprZXkuUW0gPSBhd2FpdCByZWFkRzEoZmQsIHprZXkuY3VydmUsIHRvT2JqZWN0KTtcbiAgICB6a2V5LlFsID0gYXdhaXQgcmVhZEcxKGZkLCB6a2V5LmN1cnZlLCB0b09iamVjdCk7XG4gICAgemtleS5RciA9IGF3YWl0IHJlYWRHMShmZCwgemtleS5jdXJ2ZSwgdG9PYmplY3QpO1xuICAgIHprZXkuUW8gPSBhd2FpdCByZWFkRzEoZmQsIHprZXkuY3VydmUsIHRvT2JqZWN0KTtcbiAgICB6a2V5LlFjID0gYXdhaXQgcmVhZEcxKGZkLCB6a2V5LmN1cnZlLCB0b09iamVjdCk7XG4gICAgemtleS5TMSA9IGF3YWl0IHJlYWRHMShmZCwgemtleS5jdXJ2ZSwgdG9PYmplY3QpO1xuICAgIHprZXkuUzIgPSBhd2FpdCByZWFkRzEoZmQsIHprZXkuY3VydmUsIHRvT2JqZWN0KTtcbiAgICB6a2V5LlMzID0gYXdhaXQgcmVhZEcxKGZkLCB6a2V5LmN1cnZlLCB0b09iamVjdCk7XG4gICAgemtleS5YXzIgPSBhd2FpdCByZWFkRzIoZmQsIHprZXkuY3VydmUsIHRvT2JqZWN0KTtcblxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRSZWFkU2VjdGlvbihmZCk7XG5cbiAgICByZXR1cm4gemtleTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZEhlYWRlckZGbG9uayhmZCwgc2VjdGlvbnMsIHRvT2JqZWN0LCBvcHRpb25zKSB7XG4gICAgY29uc3QgemtleSA9IHt9O1xuXG4gICAgemtleS5wcm90b2NvbCA9IFwiZmZsb25rXCI7XG4gICAgemtleS5wcm90b2NvbElkID0gRkZMT05LX1BST1RPQ09MX0lEO1xuXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmQsIHNlY3Rpb25zLCBaS0VZX0ZGX0hFQURFUl9TRUNUSU9OKTtcbiAgICBjb25zdCBuOHEgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICB6a2V5Lm44cSA9IG44cTtcbiAgICB6a2V5LnEgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpZ0ludChmZCwgbjhxKTtcbiAgICB6a2V5LmN1cnZlID0gYXdhaXQgZ2V0Q3VydmUoemtleS5xLCBvcHRpb25zKTtcblxuICAgIGNvbnN0IG44ciA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkubjhyID0gbjhyO1xuICAgIHprZXkuciA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmlnSW50KGZkLCBuOHIpO1xuXG4gICAgemtleS5uVmFycyA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkublB1YmxpYyA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkuZG9tYWluU2l6ZSA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkucG93ZXIgPSBsb2cyKHprZXkuZG9tYWluU2l6ZSk7XG4gICAgemtleS5uQWRkaXRpb25zID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgemtleS5uQ29uc3RyYWludHMgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcblxuICAgIHprZXkuazEgPSBhd2FpdCBmZC5yZWFkKG44cik7XG4gICAgemtleS5rMiA9IGF3YWl0IGZkLnJlYWQobjhyKTtcblxuICAgIHprZXkudzMgPSBhd2FpdCBmZC5yZWFkKG44cik7XG4gICAgemtleS53NCA9IGF3YWl0IGZkLnJlYWQobjhyKTtcbiAgICB6a2V5Lnc4ID0gYXdhaXQgZmQucmVhZChuOHIpO1xuICAgIHprZXkud3IgPSBhd2FpdCBmZC5yZWFkKG44cik7XG5cbiAgICB6a2V5LlhfMiA9IGF3YWl0IHJlYWRHMihmZCwgemtleS5jdXJ2ZSwgdG9PYmplY3QpO1xuXG4gICAgemtleS5DMCA9IGF3YWl0IHJlYWRHMShmZCwgemtleS5jdXJ2ZSwgdG9PYmplY3QpO1xuXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkKTtcblxuICAgIHJldHVybiB6a2V5O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZFpLZXkoZmlsZU5hbWUsIHRvT2JqZWN0KSB7XG4gICAgY29uc3Qge2ZkLCBzZWN0aW9uc30gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUoZmlsZU5hbWUsIFwiemtleVwiLCAxKTtcblxuICAgIGNvbnN0IHprZXkgPSBhd2FpdCByZWFkSGVhZGVyKGZkLCBzZWN0aW9ucywgdG9PYmplY3QpO1xuXG4gICAgY29uc3QgRnIgPSBuZXcgRjFGaWVsZCh6a2V5LnIpO1xuICAgIGNvbnN0IFJyID0gU2NhbGFyLm1vZChTY2FsYXIuc2hsKDEsIHprZXkubjhyKjgpLCB6a2V5LnIpO1xuICAgIGNvbnN0IFJyaSA9IEZyLmludihScik7XG4gICAgY29uc3QgUnJpMiA9IEZyLm11bChScmksIFJyaSk7XG5cbiAgICBsZXQgY3VydmUgPSBhd2FpdCBnZXRDdXJ2ZSh6a2V5LnEpO1xuXG4gICAgLy8gUmVhZCBJQyBTZWN0aW9uXG4gICAgLy8vLy8vLy8vLy9cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIDMpO1xuICAgIHprZXkuSUMgPSBbXTtcbiAgICBmb3IgKGxldCBpPTA7IGk8PSB6a2V5Lm5QdWJsaWM7IGkrKykge1xuICAgICAgICBjb25zdCBQID0gYXdhaXQgcmVhZEcxKGZkLCBjdXJ2ZSwgdG9PYmplY3QpO1xuICAgICAgICB6a2V5LklDLnB1c2goUCk7XG4gICAgfVxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRSZWFkU2VjdGlvbihmZCk7XG5cblxuICAgIC8vIFJlYWQgQ29lZnNcbiAgICAvLy8vLy8vLy8vL1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkLCBzZWN0aW9ucywgNCk7XG4gICAgY29uc3QgbkNDb2VmcyA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHprZXkuY2NvZWZzID0gW107XG4gICAgZm9yIChsZXQgaT0wOyBpPG5DQ29lZnM7IGkrKykge1xuICAgICAgICBjb25zdCBtID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgICAgIGNvbnN0IGMgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICAgICAgY29uc3QgcyA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgICAgICBjb25zdCB2ID0gYXdhaXQgcmVhZEZyMih0b09iamVjdCk7XG4gICAgICAgIHprZXkuY2NvZWZzLnB1c2goe1xuICAgICAgICAgICAgbWF0cml4OiBtLFxuICAgICAgICAgICAgY29uc3RyYWludDogYyxcbiAgICAgICAgICAgIHNpZ25hbDogcyxcbiAgICAgICAgICAgIHZhbHVlOiB2XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmQpO1xuXG4gICAgLy8gUmVhZCBBIHBvaW50c1xuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmQsIHNlY3Rpb25zLCA1KTtcbiAgICB6a2V5LkEgPSBbXTtcbiAgICBmb3IgKGxldCBpPTA7IGk8emtleS5uVmFyczsgaSsrKSB7XG4gICAgICAgIGNvbnN0IEEgPSBhd2FpdCByZWFkRzEoZmQsIGN1cnZlLCB0b09iamVjdCk7XG4gICAgICAgIHprZXkuQVtpXSA9IEE7XG4gICAgfVxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRSZWFkU2VjdGlvbihmZCk7XG5cblxuICAgIC8vIFJlYWQgQjFcbiAgICAvLy8vLy8vLy8vL1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkLCBzZWN0aW9ucywgNik7XG4gICAgemtleS5CMSA9IFtdO1xuICAgIGZvciAobGV0IGk9MDsgaTx6a2V5Lm5WYXJzOyBpKyspIHtcbiAgICAgICAgY29uc3QgQjEgPSBhd2FpdCByZWFkRzEoZmQsIGN1cnZlLCB0b09iamVjdCk7XG5cbiAgICAgICAgemtleS5CMVtpXSA9IEIxO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmQpO1xuXG5cbiAgICAvLyBSZWFkIEIyIHBvaW50c1xuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmQsIHNlY3Rpb25zLCA3KTtcbiAgICB6a2V5LkIyID0gW107XG4gICAgZm9yIChsZXQgaT0wOyBpPHprZXkublZhcnM7IGkrKykge1xuICAgICAgICBjb25zdCBCMiA9IGF3YWl0IHJlYWRHMihmZCwgY3VydmUsIHRvT2JqZWN0KTtcbiAgICAgICAgemtleS5CMltpXSA9IEIyO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmQpO1xuXG5cbiAgICAvLyBSZWFkIEMgcG9pbnRzXG4gICAgLy8vLy8vLy8vLy9cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIDgpO1xuICAgIHprZXkuQyA9IFtdO1xuICAgIGZvciAobGV0IGk9emtleS5uUHVibGljKzE7IGk8emtleS5uVmFyczsgaSsrKSB7XG4gICAgICAgIGNvbnN0IEMgPSBhd2FpdCByZWFkRzEoZmQsIGN1cnZlLCB0b09iamVjdCk7XG5cbiAgICAgICAgemtleS5DW2ldID0gQztcbiAgICB9XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkKTtcblxuXG4gICAgLy8gUmVhZCBIIHBvaW50c1xuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmQsIHNlY3Rpb25zLCA5KTtcbiAgICB6a2V5LmhFeHBzID0gW107XG4gICAgZm9yIChsZXQgaT0wOyBpPHprZXkuZG9tYWluU2l6ZTsgaSsrKSB7XG4gICAgICAgIGNvbnN0IEggPSBhd2FpdCByZWFkRzEoZmQsIGN1cnZlLCB0b09iamVjdCk7XG4gICAgICAgIHprZXkuaEV4cHMucHVzaChIKTtcbiAgICB9XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkKTtcblxuICAgIGF3YWl0IGZkLmNsb3NlKCk7XG5cbiAgICByZXR1cm4gemtleTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIHJlYWRGcjIoLyogdG9PYmplY3QgKi8pIHtcbiAgICAgICAgY29uc3QgbiA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmlnSW50KGZkLCB6a2V5Lm44cik7XG4gICAgICAgIHJldHVybiBGci5tdWwobiwgUnJpMik7XG4gICAgfVxuXG59XG5cblxuYXN5bmMgZnVuY3Rpb24gcmVhZENvbnRyaWJ1dGlvbihmZCwgY3VydmUsIHRvT2JqZWN0KSB7XG4gICAgY29uc3QgYyA9IHtkZWx0YTp7fX07XG4gICAgYy5kZWx0YUFmdGVyID0gYXdhaXQgcmVhZEcxKGZkLCBjdXJ2ZSwgdG9PYmplY3QpO1xuICAgIGMuZGVsdGEuZzFfcyA9IGF3YWl0IHJlYWRHMShmZCwgY3VydmUsIHRvT2JqZWN0KTtcbiAgICBjLmRlbHRhLmcxX3N4ID0gYXdhaXQgcmVhZEcxKGZkLCBjdXJ2ZSwgdG9PYmplY3QpO1xuICAgIGMuZGVsdGEuZzJfc3B4ID0gYXdhaXQgcmVhZEcyKGZkLCBjdXJ2ZSwgdG9PYmplY3QpO1xuICAgIGMudHJhbnNjcmlwdCA9IGF3YWl0IGZkLnJlYWQoNjQpO1xuICAgIGMudHlwZSA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuXG4gICAgY29uc3QgcGFyYW1MZW5ndGggPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICBjb25zdCBjdXJQb3MgPSBmZC5wb3M7XG4gICAgbGV0IGxhc3RUeXBlID0wO1xuICAgIHdoaWxlIChmZC5wb3MtY3VyUG9zIDwgcGFyYW1MZW5ndGgpIHtcbiAgICAgICAgY29uc3QgYnVmZlR5cGUgPSBhd2FpdCBmZC5yZWFkKDEpO1xuICAgICAgICBpZiAoYnVmZlR5cGVbMF08PSBsYXN0VHlwZSkgdGhyb3cgbmV3IEVycm9yKFwiUGFyYW1ldGVycyBpbiB0aGUgY29udHJpYnV0aW9uIG11c3QgYmUgc29ydGVkXCIpO1xuICAgICAgICBsYXN0VHlwZSA9IGJ1ZmZUeXBlWzBdO1xuICAgICAgICBpZiAoYnVmZlR5cGVbMF09PTEpIHsgICAgIC8vIE5hbWVcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZMZW4gPSBhd2FpdCBmZC5yZWFkKDEpO1xuICAgICAgICAgICAgY29uc3QgYnVmZlN0ciA9IGF3YWl0IGZkLnJlYWQoYnVmZkxlblswXSk7XG4gICAgICAgICAgICBjLm5hbWUgPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoYnVmZlN0cik7XG4gICAgICAgIH0gZWxzZSBpZiAoYnVmZlR5cGVbMF09PTIpIHtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZFeHAgPSBhd2FpdCBmZC5yZWFkKDEpO1xuICAgICAgICAgICAgYy5udW1JdGVyYXRpb25zRXhwID0gYnVmZkV4cFswXTtcbiAgICAgICAgfSBlbHNlIGlmIChidWZmVHlwZVswXT09Mykge1xuICAgICAgICAgICAgY29uc3QgYnVmZkxlbiA9IGF3YWl0IGZkLnJlYWQoMSk7XG4gICAgICAgICAgICBjLmJlYWNvbkhhc2ggPSBhd2FpdCBmZC5yZWFkKGJ1ZmZMZW5bMF0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUGFyYW1ldGVyIG5vdCByZWNvZ25pemVkXCIpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChmZC5wb3MgIT0gY3VyUG9zICsgcGFyYW1MZW5ndGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUGFyYW1ldGVycyBkbyBub3QgbWF0Y2hcIik7XG4gICAgfVxuXG4gICAgcmV0dXJuIGM7XG59XG5cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRNUENQYXJhbXMoZmQsIGN1cnZlLCBzZWN0aW9ucykge1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkLCBzZWN0aW9ucywgMTApO1xuICAgIGNvbnN0IHJlcyA9IHsgY29udHJpYnV0aW9uczogW119O1xuICAgIHJlcy5jc0hhc2ggPSBhd2FpdCBmZC5yZWFkKDY0KTtcbiAgICBjb25zdCBuID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgZm9yIChsZXQgaT0wOyBpPG47IGkrKykge1xuICAgICAgICBjb25zdCBjID0gYXdhaXQgcmVhZENvbnRyaWJ1dGlvbihmZCwgY3VydmUpO1xuICAgICAgICByZXMuY29udHJpYnV0aW9ucy5wdXNoKGMpO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmQpO1xuXG4gICAgcmV0dXJuIHJlcztcbn1cblxuYXN5bmMgZnVuY3Rpb24gd3JpdGVDb250cmlidXRpb24oZmQsIGN1cnZlLCBjKSB7XG4gICAgYXdhaXQgd3JpdGVHMShmZCwgY3VydmUsIGMuZGVsdGFBZnRlcik7XG4gICAgYXdhaXQgd3JpdGVHMShmZCwgY3VydmUsIGMuZGVsdGEuZzFfcyk7XG4gICAgYXdhaXQgd3JpdGVHMShmZCwgY3VydmUsIGMuZGVsdGEuZzFfc3gpO1xuICAgIGF3YWl0IHdyaXRlRzIoZmQsIGN1cnZlLCBjLmRlbHRhLmcyX3NweCk7XG4gICAgYXdhaXQgZmQud3JpdGUoYy50cmFuc2NyaXB0KTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKGMudHlwZSB8fCAwKTtcblxuICAgIGNvbnN0IHBhcmFtcyA9IFtdO1xuICAgIGlmIChjLm5hbWUpIHtcbiAgICAgICAgcGFyYW1zLnB1c2goMSk7ICAgICAgLy8gUGFyYW0gTmFtZVxuICAgICAgICBjb25zdCBuYW1lRGF0YSA9IG5ldyBUZXh0RW5jb2RlcihcInV0Zi04XCIpLmVuY29kZShjLm5hbWUuc3Vic3RyaW5nKDAsNjQpKTtcbiAgICAgICAgcGFyYW1zLnB1c2gobmFtZURhdGEuYnl0ZUxlbmd0aCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxuYW1lRGF0YS5ieXRlTGVuZ3RoOyBpKyspIHBhcmFtcy5wdXNoKG5hbWVEYXRhW2ldKTtcbiAgICB9XG4gICAgaWYgKGMudHlwZSA9PSAxKSB7XG4gICAgICAgIHBhcmFtcy5wdXNoKDIpOyAgICAgIC8vIFBhcmFtIG51bUl0ZXJhdGlvbnNFeHBcbiAgICAgICAgcGFyYW1zLnB1c2goYy5udW1JdGVyYXRpb25zRXhwKTtcblxuICAgICAgICBwYXJhbXMucHVzaCgzKTsgICAgICAvLyBCZWFjb24gSGFzaFxuICAgICAgICBwYXJhbXMucHVzaChjLmJlYWNvbkhhc2guYnl0ZUxlbmd0aCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxjLmJlYWNvbkhhc2guYnl0ZUxlbmd0aDsgaSsrKSBwYXJhbXMucHVzaChjLmJlYWNvbkhhc2hbaV0pO1xuICAgIH1cbiAgICBpZiAocGFyYW1zLmxlbmd0aD4wKSB7XG4gICAgICAgIGNvbnN0IHBhcmFtc0J1ZmYgPSBuZXcgVWludDhBcnJheShwYXJhbXMpO1xuICAgICAgICBhd2FpdCBmZC53cml0ZVVMRTMyKHBhcmFtc0J1ZmYuYnl0ZUxlbmd0aCk7XG4gICAgICAgIGF3YWl0IGZkLndyaXRlKHBhcmFtc0J1ZmYpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoMCk7XG4gICAgfVxuXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZU1QQ1BhcmFtcyhmZCwgY3VydmUsIG1wY1BhcmFtcykge1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZCwgMTApO1xuICAgIGF3YWl0IGZkLndyaXRlKG1wY1BhcmFtcy5jc0hhc2gpO1xuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIobXBjUGFyYW1zLmNvbnRyaWJ1dGlvbnMubGVuZ3RoKTtcbiAgICBmb3IgKGxldCBpPTA7IGk8bXBjUGFyYW1zLmNvbnRyaWJ1dGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgYXdhaXQgd3JpdGVDb250cmlidXRpb24oZmQsIGN1cnZlLG1wY1BhcmFtcy5jb250cmlidXRpb25zW2ldKTtcbiAgICB9XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFdyaXRlU2VjdGlvbihmZCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBoYXNoRzEoaGFzaGVyLCBjdXJ2ZSwgcCkge1xuICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShjdXJ2ZS5HMS5GLm44KjIpO1xuICAgIGN1cnZlLkcxLnRvUnByVW5jb21wcmVzc2VkKGJ1ZmYsIDAsIHApO1xuICAgIGhhc2hlci51cGRhdGUoYnVmZik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBoYXNoRzIoaGFzaGVyLGN1cnZlLCBwKSB7XG4gICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KGN1cnZlLkcyLkYubjgqMik7XG4gICAgY3VydmUuRzIudG9ScHJVbmNvbXByZXNzZWQoYnVmZiwgMCwgcCk7XG4gICAgaGFzaGVyLnVwZGF0ZShidWZmKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGhhc2hQdWJLZXkoaGFzaGVyLCBjdXJ2ZSwgYykge1xuICAgIGhhc2hHMShoYXNoZXIsIGN1cnZlLCBjLmRlbHRhQWZ0ZXIpO1xuICAgIGhhc2hHMShoYXNoZXIsIGN1cnZlLCBjLmRlbHRhLmcxX3MpO1xuICAgIGhhc2hHMShoYXNoZXIsIGN1cnZlLCBjLmRlbHRhLmcxX3N4KTtcbiAgICBoYXNoRzIoaGFzaGVyLCBjdXJ2ZSwgYy5kZWx0YS5nMl9zcHgpO1xuICAgIGhhc2hlci51cGRhdGUoYy50cmFuc2NyaXB0KTtcbn1cblxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0IHsgU2NhbGFyIH0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuXG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcblxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd3JpdGUoZmQsIHdpdG5lc3MsIHByaW1lKSB7XG5cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24oZmQsIDEpO1xuICAgIGNvbnN0IG44ID0gKE1hdGguZmxvb3IoIChTY2FsYXIuYml0TGVuZ3RoKHByaW1lKSAtIDEpIC8gNjQpICsxKSo4O1xuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIobjgpO1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy53cml0ZUJpZ0ludChmZCwgcHJpbWUsIG44KTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKHdpdG5lc3MubGVuZ3RoKTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkKTtcblxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZCwgMik7XG4gICAgZm9yIChsZXQgaT0wOyBpPHdpdG5lc3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLndyaXRlQmlnSW50KGZkLCB3aXRuZXNzW2ldLCBuOCk7XG4gICAgfVxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmQsIDIpO1xuXG5cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdyaXRlQmluKGZkLCB3aXRuZXNzQmluLCBwcmltZSkge1xuXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkLCAxKTtcbiAgICBjb25zdCBuOCA9IChNYXRoLmZsb29yKCAoU2NhbGFyLmJpdExlbmd0aChwcmltZSkgLSAxKSAvIDY0KSArMSkqODtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKG44KTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMud3JpdGVCaWdJbnQoZmQsIHByaW1lLCBuOCk7XG4gICAgaWYgKHdpdG5lc3NCaW4uYnl0ZUxlbmd0aCAlIG44ICE9IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCB3aXRuZXNzIGxlbmd0aFwiKTtcbiAgICB9XG4gICAgYXdhaXQgZmQud3JpdGVVTEUzMih3aXRuZXNzQmluLmJ5dGVMZW5ndGggLyBuOCk7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFdyaXRlU2VjdGlvbihmZCk7XG5cblxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZCwgMik7XG4gICAgYXdhaXQgZmQud3JpdGUod2l0bmVzc0Jpbik7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFdyaXRlU2VjdGlvbihmZCk7XG5cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRIZWFkZXIoZmQsIHNlY3Rpb25zKSB7XG5cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIDEpO1xuICAgIGNvbnN0IG44ID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgY29uc3QgcSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmlnSW50KGZkLCBuOCk7XG4gICAgY29uc3QgbldpdG5lc3MgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmQpO1xuXG4gICAgcmV0dXJuIHtuOCwgcSwgbldpdG5lc3N9O1xuXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkKGZpbGVOYW1lKSB7XG5cbiAgICBjb25zdCB7ZmQsIHNlY3Rpb25zfSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmluRmlsZShmaWxlTmFtZSwgXCJ3dG5zXCIsIDIpO1xuXG4gICAgY29uc3Qge244LCBuV2l0bmVzc30gPSBhd2FpdCByZWFkSGVhZGVyKGZkLCBzZWN0aW9ucyk7XG5cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIDIpO1xuICAgIGNvbnN0IHJlcyA9IFtdO1xuICAgIGZvciAobGV0IGk9MDsgaTxuV2l0bmVzczsgaSsrKSB7XG4gICAgICAgIGNvbnN0IHYgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpZ0ludChmZCwgbjgpO1xuICAgICAgICByZXMucHVzaCh2KTtcbiAgICB9XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkKTtcblxuICAgIGF3YWl0IGZkLmNsb3NlKCk7XG5cbiAgICByZXR1cm4gcmVzO1xufVxuXG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCAqIGFzIHprZXlVdGlscyBmcm9tIFwiLi96a2V5X3V0aWxzLmpzXCI7XG5pbXBvcnQgKiBhcyB3dG5zVXRpbHMgZnJvbSBcIi4vd3Ruc191dGlscy5qc1wiO1xuaW1wb3J0IHsgbG9nMiB9IGZyb20gXCIuL21pc2MuanNcIjtcbmltcG9ydCB7IFNjYWxhciwgdXRpbHMsIEJpZ0J1ZmZlciB9IGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmNvbnN0IHtzdHJpbmdpZnlCaWdJbnRzfSA9IHV0aWxzO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBncm90aDE2UHJvdmUoemtleUZpbGVOYW1lLCB3aXRuZXNzRmlsZU5hbWUsIGxvZ2dlciwgb3B0aW9ucykge1xuICAgIC8vIE9wdC1pbiBwZXJpb2RpYyBtZW1vcnktdXNhZ2UgbG9nZ2luZyAoaGVhcC9SU1MvZXh0ZXJuYWwvQXJyYXlCdWZmZXJzKS5cbiAgICAvLyBvcHRpb25zLm1lbW9yeUxvZ2dpbmc6IHRydWUgKDFzIGludGVydmFsKSBvciBhbiBpbnRlcnZhbCBpbiBtcy5cbiAgICAvLyBOb2RlLW9ubHk6IHByb2Nlc3MubWVtb3J5VXNhZ2UgZG9lcyBub3QgZXhpc3QgaW4gYnJvd3NlcnMuXG4gICAgbGV0IG1lbVRpbWVyID0gbnVsbDtcbiAgICBpZiAobG9nZ2VyICYmIG9wdGlvbnMgJiYgb3B0aW9ucy5tZW1vcnlMb2dnaW5nXG4gICAgICAgICYmIHR5cGVvZiBwcm9jZXNzICE9PSBcInVuZGVmaW5lZFwiICYmIHR5cGVvZiBwcm9jZXNzLm1lbW9yeVVzYWdlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgY29uc3QgaW50ZXJ2YWwgPSBOdW1iZXIob3B0aW9ucy5tZW1vcnlMb2dnaW5nKSA+IDEgPyBOdW1iZXIob3B0aW9ucy5tZW1vcnlMb2dnaW5nKSA6IDEwMDA7XG4gICAgICAgIG1lbVRpbWVyID0gbW9uaXRvck1lbW9yeVVzYWdlKGxvZ2dlciwgaW50ZXJ2YWwpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gYXdhaXQgX2dyb3RoMTZQcm92ZSh6a2V5RmlsZU5hbWUsIHdpdG5lc3NGaWxlTmFtZSwgbG9nZ2VyLCBvcHRpb25zKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgICBpZiAobWVtVGltZXIpIHtcbiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwobWVtVGltZXIpO1xuICAgICAgICAgICAgbWVtVXNhZ2UobG9nZ2VyKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gX2dyb3RoMTZQcm92ZSh6a2V5RmlsZU5hbWUsIHdpdG5lc3NGaWxlTmFtZSwgbG9nZ2VyLCBvcHRpb25zKSB7XG5cbiAgICBjb25zdCB7ZmQ6IGZkV3Rucywgc2VjdGlvbnM6IHNlY3Rpb25zV3Ruc30gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUod2l0bmVzc0ZpbGVOYW1lLCBcInd0bnNcIiwgMiwgMTw8MjUsIDE8PDIzKTtcblxuICAgIGNvbnN0IHd0bnMgPSBhd2FpdCB3dG5zVXRpbHMucmVhZEhlYWRlcihmZFd0bnMsIHNlY3Rpb25zV3Rucyk7XG5cbiAgICBjb25zdCB7ZmQ6IGZkWktleSwgc2VjdGlvbnM6IHNlY3Rpb25zWktleX0gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUoemtleUZpbGVOYW1lLCBcInprZXlcIiwgMiwgMTw8MjUsIDE8PDIzKTtcblxuICAgIGNvbnN0IHprZXkgPSBhd2FpdCB6a2V5VXRpbHMucmVhZEhlYWRlcihmZFpLZXksIHNlY3Rpb25zWktleSwgdW5kZWZpbmVkLCBvcHRpb25zKTtcblxuICAgIGlmICh6a2V5LnByb3RvY29sICE9IFwiZ3JvdGgxNlwiKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcInprZXkgZmlsZSBpcyBub3QgZ3JvdGgxNlwiKTtcbiAgICB9XG5cbiAgICBpZiAoIVNjYWxhci5lcSh6a2V5LnIsICB3dG5zLnEpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkN1cnZlIG9mIHRoZSB3aXRuZXNzIGRvZXMgbm90IG1hdGNoIHRoZSBjdXJ2ZSBvZiB0aGUgcHJvdmluZyBrZXlcIik7XG4gICAgfVxuXG4gICAgaWYgKHd0bnMubldpdG5lc3MgIT0gemtleS5uVmFycykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgd2l0bmVzcyBsZW5ndGguIENpcmN1aXQ6ICR7emtleS5uVmFyc30sIHdpdG5lc3M6ICR7d3Rucy5uV2l0bmVzc31gKTtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJ2ZSA9IHprZXkuY3VydmU7XG4gICAgY29uc3QgRnIgPSBjdXJ2ZS5GcjtcbiAgICBjb25zdCBHMSA9IGN1cnZlLkcxO1xuICAgIGNvbnN0IEcyID0gY3VydmUuRzI7XG5cbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgIC8vIE1TTSBiYXRjaGluZyBtb2RlLCB0aHJlYWRlZCB0byBldmVyeSBtdWx0aWV4cCBiZWxvdzpcbiAgICAvLyAgIFwiYXV0b1wiICAgICAoZGVmYXVsdCkgdXNlIHRoZSBiYXRjaC1hZmZpbmUgTVNNIG1vZHVsZSBvbmx5IGZvclxuICAgIC8vICAgICAgICAgICAgICBjYWNoZS1mcmllbmRseSBjaHVuayBzaXplcyAod2hlcmUgaXQgaXMgbWVhc3VyYWJseSBmYXN0ZXIpO1xuICAgIC8vICAgXCJlbmFibGVkXCIgIGFsd2F5cyB1c2UgaXQgKGJlc3QgZm9yIHNtYWxsL21lZGl1bSBjaXJjdWl0cyk7XG4gICAgLy8gICBcImRpc2FibGVkXCIgbmV2ZXIgdXNlIGl0IChwbGFpbiBpbi1tb2R1bGUgbXVsdGlleHA7IGxvd2VzdCBtZW1vcnkpLlxuICAgIGNvbnN0IG1zbUJhdGNoaW5nID0gb3B0aW9ucy5tc21CYXRjaGluZyB8fCBcImF1dG9cIjtcbiAgICBpZiAobXNtQmF0Y2hpbmcgIT09IFwiYXV0b1wiICYmIG1zbUJhdGNoaW5nICE9PSBcImVuYWJsZWRcIiAmJiBtc21CYXRjaGluZyAhPT0gXCJkaXNhYmxlZFwiKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgZ3JvdGgxNlByb3ZlOiBpbnZhbGlkIG1zbUJhdGNoaW5nIFwiJHttc21CYXRjaGluZ31cIiAoZXhwZWN0ZWQgXCJhdXRvXCIsIFwiZW5hYmxlZFwiIG9yIFwiZGlzYWJsZWRcIilgKTtcbiAgICB9XG4gICAgLy8gbXNtR2x2IC8gbXNtR2xzOiBcImF1dG9cIiAoZGVmYXVsdCAtLSB1c2UgdGhlIEcxL0cyIGVuZG9tb3JwaGlzbSBNU00gcGF0aHNcbiAgICAvLyB3aGVyZSB0aGUgY3VydmUgc3VwcG9ydHMgdGhlbTsgdGhlIHdhc20gc3RpbGwgZ2F0ZXMgaW50ZXJuYWxseSBvbiBjaHVua1xuICAgIC8vIHNpemVzKSBvciBcImRpc2FibGVkXCIgKGdlbmVyaWMgYmF0Y2ggYWNjdW11bGF0aW9uKS4gQS9CIGFuZCBkZWJ1Z2dpbmdcbiAgICAvLyBhaWRzLCBsaWtlIG1zbUJhdGNoaW5nLlxuICAgIGNvbnN0IG1zbUdsdiA9IG9wdGlvbnMubXNtR2x2IHx8IFwiYXV0b1wiO1xuICAgIGNvbnN0IG1zbUdscyA9IG9wdGlvbnMubXNtR2xzIHx8IFwiYXV0b1wiO1xuICAgIGZvciAoY29uc3QgW25hbWUsIHZdIG9mIFtbXCJtc21HbHZcIiwgbXNtR2x2XSwgW1wibXNtR2xzXCIsIG1zbUdsc11dKSB7XG4gICAgICAgIGlmICh2ICE9PSBcImF1dG9cIiAmJiB2ICE9PSBcImRpc2FibGVkXCIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgZ3JvdGgxNlByb3ZlOiBpbnZhbGlkICR7bmFtZX0gXCIke3Z9XCIgKGV4cGVjdGVkIFwiYXV0b1wiIG9yIFwiZGlzYWJsZWRcIilgKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBtc21PcHRzID0geyBiYXRjaDogbXNtQmF0Y2hpbmcsIGdsdjogbXNtR2x2LCBnbHM6IG1zbUdscyB9O1xuXG4gICAgY29uc3QgcG93ZXIgPSBsb2cyKHprZXkuZG9tYWluU2l6ZSk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJSZWFkaW5nIFd0bnNcIik7XG4gICAgY29uc3QgYnVmZldpdG5lc3MgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRXdG5zLCBzZWN0aW9uc1d0bnMsIDIpO1xuXG4gICAgLy8gUmVhZGVyIGZvciBhIHprZXkgc2VjdGlvbiB0aGF0IHJldHVybnMgYW4gYXJiaXRyYXJ5IHN1Yi1yYW5nZSBkaXJlY3RseSBmcm9tXG4gICAgLy8gZGlzaywgdXNlZCB0byBmZWVkIG11bHRpRXhwIGJhc2VzIHRvIHRoZSB3b3JrZXJzIGluIGNodW5rcyBpbnN0ZWFkIG9mXG4gICAgLy8gcmVhZGluZyB0aGUgd2hvbGUgKHBvdGVudGlhbGx5IGh1bmRyZWRzIG9mIE1CKSBzZWN0aW9uIGludG8gb25lIGJ1ZmZlciBhbmRcbiAgICAvLyBzbGljaW5nIGl0LiBCb3VuZHMgdGhlIGJhc2VzIHJlc2lkZW50IGluIFJBTSB0byBhIGZldyBpbi1mbGlnaHQgY2h1bmtzLlxuICAgIGNvbnN0IG1rU2VjdGlvblJlYWRlciA9IChpZFNlY3Rpb24pID0+IHtcbiAgICAgICAgY29uc3Qgc3RhcnQgPSBzZWN0aW9uc1pLZXlbaWRTZWN0aW9uXVswXS5wO1xuICAgICAgICBjb25zdCBzaXplID0gc2VjdGlvbnNaS2V5W2lkU2VjdGlvbl1bMF0uc2l6ZTtcbiAgICAgICAgcmV0dXJuIGFzeW5jIChvZmYsIGxlbikgPT4ge1xuICAgICAgICAgICAgaWYgKG9mZiArIGxlbiA+IHNpemUpIHRocm93IG5ldyBFcnJvcihgZ3JvdGgxNlByb3ZlOiByZWFkIG91dCBvZiByYW5nZSBvZiBzZWN0aW9uICR7aWRTZWN0aW9ufWApO1xuICAgICAgICAgICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KGxlbik7XG4gICAgICAgICAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKGJ1ZmYsIDAsIGxlbiwgc3RhcnQgKyBvZmYpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgICAgIH07XG4gICAgfTtcblxuICAgIGxldCByZXNIO1xuICAgIGxldCByZXNIUHJvbWlzZTtcbiAgICBsZXQgYnVmZlBvZGRfVDtcblxuICAgIGxldCBhYmNQcm9taXNlID0gKGFzeW5jIGZ1bmN0aW9uICgpe1xuICAgICAgICBsZXQgYnVmZkFfVCwgYnVmZkJfVCwgYnVmZkNfVDtcblxuICAgICAgICBhd2FpdCAoYXN5bmMgZnVuY3Rpb24gKCl7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJSZWFkaW5nIENvZWZmc1wiKTtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZDb2VmZnMgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRaS2V5LCBzZWN0aW9uc1pLZXksIDQpO1xuXG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJCdWlsZGluZyBBQkNcIik7XG5cbiAgICAgICAgICAgIGlmIChvcHRpb25zLmJ1aWxkQUJDID09PSBcImpzXCIpIHtcbiAgICAgICAgICAgICAgICBbYnVmZkFfVCwgYnVmZkJfVCwgYnVmZkNfVF0gPSBhd2FpdCBidWlsZEFCQzEoY3VydmUsIHprZXksIGJ1ZmZXaXRuZXNzLCBidWZmQ29lZmZzLCBsb2dnZXIpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zLmJ1aWxkQUJDID09PSBcInN0cmVhbVwiKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcCA9IHBpY2tTdHJlYW1QYXJhbXMoY3VydmUsIHprZXksIGJ1ZmZDb2VmZnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIFtidWZmQV9ULCBidWZmQl9ULCBidWZmQ19UXSA9IGF3YWl0IGJ1aWxkQUJDU3RyZWFtKGN1cnZlLCB6a2V5LCBidWZmV2l0bmVzcywgYnVmZkNvZWZmcywgbG9nZ2VyLCBwLm5DaHVua3MsIHAubWF4SW5GbGlnaHQpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBEZWZhdWx0OiBzdHJlYW1pbmcgYnVpbGQgKGJvdW5kZWQgd29ya2VyIG1lbW9yeSwgdHVuYWJsZVxuICAgICAgICAgICAgICAgIC8vIHBhcmFsbGVsaXNtKS4gVGhlIHBlci1jaHVuayB3aXRuZXNzIGdhdGhlciBrZWVwcyB0aGUgd2l0bmVzc1xuICAgICAgICAgICAgICAgIC8vIG91dCBvZiBXQVNNIGVudGlyZWx5LCBzbyB0aGVyZSBpcyBubyB3aXRuZXNzIHNpemUgbGltaXQuXG4gICAgICAgICAgICAgICAgY29uc3QgcCA9IHBpY2tTdHJlYW1QYXJhbXMoY3VydmUsIHprZXksIGJ1ZmZDb2VmZnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgYnVpbGRBQkM6IHN0cmVhbSBuQ2h1bmtzPSR7cC5uQ2h1bmtzfSBtYXhJbkZsaWdodD0ke3AubWF4SW5GbGlnaHR9YCk7XG4gICAgICAgICAgICAgICAgW2J1ZmZBX1QsIGJ1ZmZCX1QsIGJ1ZmZDX1RdID0gYXdhaXQgYnVpbGRBQkNTdHJlYW0oY3VydmUsIHprZXksIGJ1ZmZXaXRuZXNzLCBidWZmQ29lZmZzLCBsb2dnZXIsIHAubkNodW5rcywgcC5tYXhJbkZsaWdodCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pKCk7XG5cblxuICAgICAgICAvLyBEbyBub3QgY2FsbCBnYygpIGhlcmUuIGdjKCkgaXMgYSBzdG9wLXRoZS13b3JsZCBwYXVzZSB0aGF0IGJsb2NrcyB0aGVcbiAgICAgICAgLy8gTm9kZS5qcyBldmVudCBsb29wLiBJZiB0aGUgcGF1c2UgZXhjZWVkcyB0aGUgd29ya2VyIGlkbGUtdGVybWluYXRpb25cbiAgICAgICAgLy8gdGltZW91dCAoMXMpLCBhIHdvcmtlciBjbG9zZXMgaXRzIHBvcnQgd2hpbGUgdGhlIG1haW4gdGhyZWFkIGlzIGJsb2NrZWQsXG4gICAgICAgIC8vIGFuZCB0aGUgbmV4dCB0YXNrIGRpc3BhdGNoZWQgdG8gaXQgaXMgc2lsZW50bHkgZHJvcHBlZCDihpIgaGFuZy4gVGhlXG4gICAgICAgIC8vIGNvZWZmaWNpZW50cyBidWZmZXIgZ29lcyBvdXQgb2Ygc2NvcGUgYXQgdGhlIGVuZCBvZiB0aGUgaW5uZXIgSUlGRSBhYm92ZVxuICAgICAgICAvLyBhbmQgaXMgcmVjbGFpbWVkIGJ5IFY4J3MgaW5jcmVtZW50YWwgR0MgYXV0b21hdGljYWxseS5cblxuICAgICAgICBjb25zdCBpbmMgPSBwb3dlciA9PT0gRnIucyA/IGN1cnZlLkZyLnNoaWZ0IDogY3VydmUuRnIud1twb3dlcisxXTtcblxuICAgICAgICBsZXQgYnVmZkFvZGRfVCwgYnVmZkJvZGRfVCwgYnVmZkNvZGRfVDtcbiAgICAgICAgLy8gVGhlIElGRlQgaW5wdXQgKGJ1ZmZYX1QpIGlzIGRyb3BwZWQgaW1tZWRpYXRlbHksIGFuZCB0aGUgRkZUIGlucHV0XG4gICAgICAgIC8vIChidWZmWG9kZCkgZ29lcyBvdXQgb2Ygc2NvcGUgcmlnaHQgYWZ0ZXIgLS0gc28gYm90aCBjYW4gYmUgY29uc3VtZWRcbiAgICAgICAgLy8gKGNvbnN1bWU9dHJ1ZSksIHNraXBwaW5nIGZmamF2YXNjcmlwdCdzIGRlZmVuc2l2ZSBmdWxsLWlucHV0IGNvcHkuXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgIChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgbGV0IGJ1ZmZBID0gYXdhaXQgRnIuaWZmdChidWZmQV9ULCBcIlwiLCBcIlwiLCBsb2dnZXIsIFwiSUZGVF9BXCIsIHRydWUpO1xuICAgICAgICAgICAgICAgIGJ1ZmZBX1QgPSBudWxsO1xuICAgICAgICAgICAgICAgIGNvbnN0IGJ1ZmZBb2RkID0gYXdhaXQgRnIuYmF0Y2hBcHBseUtleShidWZmQSwgRnIuZSgxKSwgaW5jKTtcbiAgICAgICAgICAgICAgICBidWZmQW9kZF9UID0gYXdhaXQgRnIuZmZ0KGJ1ZmZBb2RkLCBcIlwiLCBcIlwiLCBsb2dnZXIsIFwiRkZUX0FcIiwgdHJ1ZSk7XG4gICAgICAgICAgICB9KSgpLFxuICAgICAgICAgICAgKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBsZXQgYnVmZkIgPSBhd2FpdCBGci5pZmZ0KGJ1ZmZCX1QsIFwiXCIsIFwiXCIsIGxvZ2dlciwgXCJJRkZUX0JcIiwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgYnVmZkJfVCA9IG51bGw7XG4gICAgICAgICAgICAgICAgY29uc3QgYnVmZkJvZGQgPSBhd2FpdCBGci5iYXRjaEFwcGx5S2V5KGJ1ZmZCLCBGci5lKDEpLCBpbmMpO1xuICAgICAgICAgICAgICAgIGJ1ZmZCb2RkX1QgPSBhd2FpdCBGci5mZnQoYnVmZkJvZGQsIFwiXCIsIFwiXCIsIGxvZ2dlciwgXCJGRlRfQlwiLCB0cnVlKTtcbiAgICAgICAgICAgIH0pKCksXG4gICAgICAgICAgICAoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGxldCBidWZmQyA9IGF3YWl0IEZyLmlmZnQoYnVmZkNfVCwgXCJcIiwgXCJcIiwgbG9nZ2VyLCBcIklGRlRfQ1wiLCB0cnVlKTtcbiAgICAgICAgICAgICAgICBidWZmQ19UID0gbnVsbDtcbiAgICAgICAgICAgICAgICBjb25zdCBidWZmQ29kZCA9IGF3YWl0IEZyLmJhdGNoQXBwbHlLZXkoYnVmZkMsIEZyLmUoMSksIGluYyk7XG4gICAgICAgICAgICAgICAgYnVmZkNvZGRfVCA9IGF3YWl0IEZyLmZmdChidWZmQ29kZCwgXCJcIiwgXCJcIiwgbG9nZ2VyLCBcIkZGVF9DXCIsIHRydWUpO1xuICAgICAgICAgICAgfSkoKSxcbiAgICAgICAgXSk7XG5cbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiSm9pbiBBQkNcIik7XG4gICAgICAgIGJ1ZmZQb2RkX1QgPSBhd2FpdCBqb2luQUJDKGN1cnZlLCB6a2V5LCBidWZmQW9kZF9ULCBidWZmQm9kZF9ULCBidWZmQ29kZF9ULCBsb2dnZXIpO1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJKb2luIEFCQyBmaW5pc2hlZFwiKTtcbiAgICAgICAgYnVmZkFvZGRfVCA9IG51bGw7XG4gICAgICAgIGJ1ZmZCb2RkX1QgPSBudWxsO1xuICAgICAgICBidWZmQ29kZF9UID0gbnVsbDtcblxuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykge2dsb2JhbFRoaXMuZ2MoKTt9XG4gICAgfSkoKTtcbiAgICAvL2F3YWl0IGFiY1Byb21pc2U7XG5cbiAgICBsZXQgcHJvb2YgPSB7fTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIGNhbGNQaUEoKXtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiUmVhZGluZyBBIFBvaW50c1wiKTtcbiAgICAgICAgcHJvb2YucGlfYSA9IGF3YWl0IGN1cnZlLkcxLm11bHRpRXhwQWZmaW5lQ2h1bmtlZChta1NlY3Rpb25SZWFkZXIoNSksIHNlY3Rpb25zWktleVs1XVswXS5zaXplLCBidWZmV2l0bmVzcywgbG9nZ2VyLCBcIm11bHRpZXhwIEFcIiwgbXNtT3B0cyk7XG4gICAgfVxuXG4gICAgbGV0IHBpYVByb21pc2UgPSBjYWxjUGlBKCk7XG4gICAgLy9hd2FpdCBwaWFQcm9taXNlO1xuXG4gICAgbGV0IHBpYjE7XG5cbiAgICBhc3luYyBmdW5jdGlvbiBjYWxjUGlCMSgpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiUmVhZGluZyBCMSBQb2ludHNcIik7XG4gICAgICAgIHBpYjEgPSBhd2FpdCBjdXJ2ZS5HMS5tdWx0aUV4cEFmZmluZUNodW5rZWQobWtTZWN0aW9uUmVhZGVyKDYpLCBzZWN0aW9uc1pLZXlbNl1bMF0uc2l6ZSwgYnVmZldpdG5lc3MsIGxvZ2dlciwgXCJtdWx0aWV4cCBCMVwiLCBtc21PcHRzKTtcbiAgICB9XG5cbiAgICBsZXQgcGliMVByb21pc2UgPSBjYWxjUGlCMSgpO1xuICAgIC8vYXdhaXQgcGliMVByb21pc2U7XG5cbiAgICBhc3luYyBmdW5jdGlvbiBjYWxjUGlCKCkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJSZWFkaW5nIEIyIFBvaW50c1wiKTtcbiAgICAgICAgcHJvb2YucGlfYiA9IGF3YWl0IGN1cnZlLkcyLm11bHRpRXhwQWZmaW5lQ2h1bmtlZChta1NlY3Rpb25SZWFkZXIoNyksIHNlY3Rpb25zWktleVs3XVswXS5zaXplLCBidWZmV2l0bmVzcywgbG9nZ2VyLCBcIm11bHRpZXhwIEIyXCIsIG1zbU9wdHMpO1xuICAgIH1cblxuICAgIGxldCBwaWJQcm9taXNlID0gY2FsY1BpQigpO1xuICAgIC8vYXdhaXQgcGliUHJvbWlzZTtcblxuICAgIGxldCBwaWNQcm9taXNlID0gKGFzeW5jIGZ1bmN0aW9uICgpe1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJSZWFkaW5nIEMgUG9pbnRzXCIpO1xuICAgICAgICBwcm9vZi5waV9jID0gYXdhaXQgY3VydmUuRzEubXVsdGlFeHBBZmZpbmVDaHVua2VkKG1rU2VjdGlvblJlYWRlcig4KSwgc2VjdGlvbnNaS2V5WzhdWzBdLnNpemUsIGJ1ZmZXaXRuZXNzLnNsaWNlKCh6a2V5Lm5QdWJsaWMrMSkqY3VydmUuRnIubjgpLCBsb2dnZXIsIFwibXVsdGlleHAgQ1wiLCBtc21PcHRzKTtcbiAgICB9KSgpO1xuICAgIC8vYXdhaXQgcGljUHJvbWlzZTtcblxuICAgIHJlc0hQcm9taXNlID0gKGFzeW5jIGZ1bmN0aW9uICgpe1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJSZWFkaW5nIEggUG9pbnRzXCIpO1xuICAgICAgICBhd2FpdCBhYmNQcm9taXNlO1xuICAgICAgICByZXNIID0gYXdhaXQgY3VydmUuRzEubXVsdGlFeHBBZmZpbmVDaHVua2VkKG1rU2VjdGlvblJlYWRlcig5KSwgc2VjdGlvbnNaS2V5WzldWzBdLnNpemUsIGJ1ZmZQb2RkX1QsIGxvZ2dlciwgXCJtdWx0aWV4cCBIXCIsIG1zbU9wdHMpO1xuICAgIH0pKCk7XG4gICAgLy9hd2FpdCByZXNIUHJvbWlzZTtcblxuXG4gICAgY29uc3QgciA9IGN1cnZlLkZyLnJhbmRvbSgpO1xuICAgIGNvbnN0IHMgPSBjdXJ2ZS5Gci5yYW5kb20oKTtcblxuICAgIGF3YWl0IHBpYVByb21pc2U7XG4gICAgcHJvb2YucGlfYSAgPSBHMS5hZGQoIHByb29mLnBpX2EsIHprZXkudmtfYWxwaGFfMSApO1xuICAgIHByb29mLnBpX2EgID0gRzEuYWRkKCBwcm9vZi5waV9hLCBHMS50aW1lc0ZyKCB6a2V5LnZrX2RlbHRhXzEsIHIgKSk7XG5cbiAgICBhd2FpdCBwaWJQcm9taXNlO1xuICAgIHByb29mLnBpX2IgID0gRzIuYWRkKCBwcm9vZi5waV9iLCB6a2V5LnZrX2JldGFfMiApO1xuICAgIHByb29mLnBpX2IgID0gRzIuYWRkKCBwcm9vZi5waV9iLCBHMi50aW1lc0ZyKCB6a2V5LnZrX2RlbHRhXzIsIHMgKSk7XG5cbiAgICBhd2FpdCBwaWIxUHJvbWlzZTtcbiAgICBwaWIxID0gRzEuYWRkKCBwaWIxLCB6a2V5LnZrX2JldGFfMSApO1xuICAgIHBpYjEgPSBHMS5hZGQoIHBpYjEsIEcxLnRpbWVzRnIoIHprZXkudmtfZGVsdGFfMSwgcyApKTtcblxuICAgIGF3YWl0IFByb21pc2UuYWxsKFtwaWNQcm9taXNlLCByZXNIUHJvbWlzZV0pO1xuICAgIHByb29mLnBpX2MgPSBHMS5hZGQocHJvb2YucGlfYywgcmVzSCk7XG5cblxuICAgIHByb29mLnBpX2MgID0gRzEuYWRkKCBwcm9vZi5waV9jLCBHMS50aW1lc0ZyKCBwcm9vZi5waV9hLCBzICkpO1xuICAgIHByb29mLnBpX2MgID0gRzEuYWRkKCBwcm9vZi5waV9jLCBHMS50aW1lc0ZyKCBwaWIxLCByICkpO1xuICAgIHByb29mLnBpX2MgID0gRzEuYWRkKCBwcm9vZi5waV9jLCBHMS50aW1lc0ZyKCB6a2V5LnZrX2RlbHRhXzEsIEZyLm5lZyhGci5tdWwocixzKSApKSk7XG5cblxuICAgIGxldCBwdWJsaWNTaWduYWxzID0gW107XG5cbiAgICBmb3IgKGxldCBpPTE7IGk8PSB6a2V5Lm5QdWJsaWM7IGkrKykge1xuICAgICAgICBjb25zdCBiID0gYnVmZldpdG5lc3Muc2xpY2UoaSpGci5uOCwgaSpGci5uOCtGci5uOCk7XG4gICAgICAgIHB1YmxpY1NpZ25hbHMucHVzaChTY2FsYXIuZnJvbVJwckxFKGIpKTtcbiAgICB9XG5cbiAgICBwcm9vZi5waV9hID0gRzEudG9PYmplY3QoRzEudG9BZmZpbmUocHJvb2YucGlfYSkpO1xuICAgIHByb29mLnBpX2IgPSBHMi50b09iamVjdChHMi50b0FmZmluZShwcm9vZi5waV9iKSk7XG4gICAgcHJvb2YucGlfYyA9IEcxLnRvT2JqZWN0KEcxLnRvQWZmaW5lKHByb29mLnBpX2MpKTtcblxuICAgIHByb29mLnByb3RvY29sID0gXCJncm90aDE2XCI7XG4gICAgcHJvb2YuY3VydmUgPSBjdXJ2ZS5uYW1lO1xuXG4gICAgYXdhaXQgZmRaS2V5LmNsb3NlKCk7XG4gICAgYXdhaXQgZmRXdG5zLmNsb3NlKCk7XG5cbiAgICBwcm9vZiA9IHN0cmluZ2lmeUJpZ0ludHMocHJvb2YpO1xuICAgIHB1YmxpY1NpZ25hbHMgPSBzdHJpbmdpZnlCaWdJbnRzKHB1YmxpY1NpZ25hbHMpO1xuXG4gICAgcmV0dXJuIHtwcm9vZiwgcHVibGljU2lnbmFsc307XG59XG5cblxuYXN5bmMgZnVuY3Rpb24gYnVpbGRBQkMxKGN1cnZlLCB6a2V5LCB3aXRuZXNzLCBjb2VmZnMsIGxvZ2dlcikge1xuICAgIGNvbnN0IG44ID0gY3VydmUuRnIubjg7XG4gICAgY29uc3Qgc0NvZWYgPSA0KjMgKyB6a2V5Lm44cjtcbiAgICBjb25zdCBuQ29lZiA9IChjb2VmZnMuYnl0ZUxlbmd0aC00KSAvIHNDb2VmO1xuXG4gICAgY29uc3Qgb3V0QnVmZkEgPSBuZXcgQmlnQnVmZmVyKHprZXkuZG9tYWluU2l6ZSAqIG44KTtcbiAgICBjb25zdCBvdXRCdWZmQiA9IG5ldyBCaWdCdWZmZXIoemtleS5kb21haW5TaXplICogbjgpO1xuICAgIGNvbnN0IG91dEJ1ZmZDID0gbmV3IEJpZ0J1ZmZlcih6a2V5LmRvbWFpblNpemUgKiBuOCk7XG5cbiAgICBjb25zdCBvdXRCdWYgPSBbIG91dEJ1ZmZBLCBvdXRCdWZmQiBdO1xuICAgIGZvciAobGV0IGk9MDsgaTxuQ29lZjsgaSsrKSB7XG4gICAgICAgIGlmICgobG9nZ2VyKSYmKGklMTAwMDAwMCA9PSAwKSkgbG9nZ2VyLmRlYnVnKGBRQVAgQUI6ICR7aX0vJHtuQ29lZn1gKTtcblxuICAgICAgICBsZXQgYnVmZkNvZWZWLCBjb2VmO1xuICAgICAgICBpZiAoY29lZmZzLmJ1ZmZlcikge1xuICAgICAgICAgICAgLy8gaWYgd2UgaGF2ZSBkaXJlY3QgYWNjZXNzIHRvIGFycmF5IGJ1ZmZlciwgdGhlbiB3ZSBjYW4gY3JlYXRlIHplcm8tY29weSB2aWV3c1xuICAgICAgICAgICAgY29uc3QgY29lZmZPZmZzZXQgPSA0ICsgaSAqIHNDb2VmO1xuICAgICAgICAgICAgYnVmZkNvZWZWID0gbmV3IERhdGFWaWV3KGNvZWZmcy5idWZmZXIsIGNvZWZmcy5ieXRlT2Zmc2V0ICsgY29lZmZPZmZzZXQsIHNDb2VmKTtcbiAgICAgICAgICAgIGNvZWYgPSBuZXcgVWludDhBcnJheShjb2VmZnMuYnVmZmVyLCBjb2VmZnMuYnl0ZU9mZnNldCArIGNvZWZmT2Zmc2V0ICsgMTIsIG44KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGNvZWZmcyBpcyBhIEJpZ0J1ZmZlciBhbmQgd2UgbmVlZCB0byBjb3B5IHRoZSBzbGljZVxuICAgICAgICAgICAgY29uc3QgYnVmZkNvZWYgPSBjb2VmZnMuc2xpY2UoNCtpKnNDb2VmLCA0K2kqc0NvZWYrc0NvZWYpO1xuICAgICAgICAgICAgYnVmZkNvZWZWID0gbmV3IERhdGFWaWV3KGJ1ZmZDb2VmLmJ1ZmZlcik7XG4gICAgICAgICAgICBjb2VmID0gYnVmZkNvZWYuc2xpY2UoMTIsIDEyK244KTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBtID0gYnVmZkNvZWZWLmdldFVpbnQzMigwLCB0cnVlKTtcbiAgICAgICAgY29uc3QgYyA9IGJ1ZmZDb2VmVi5nZXRVaW50MzIoNCwgdHJ1ZSk7XG4gICAgICAgIGNvbnN0IHMgPSBidWZmQ29lZlYuZ2V0VWludDMyKDgsIHRydWUpO1xuXG4gICAgICAgIG91dEJ1ZlttXS5zZXQoXG4gICAgICAgICAgICBjdXJ2ZS5Gci5hZGQoXG4gICAgICAgICAgICAgICAgb3V0QnVmW21dLnNsaWNlKGMqbjgsIGMqbjgrbjgpLFxuICAgICAgICAgICAgICAgIGN1cnZlLkZyLm11bChjb2VmLCB3aXRuZXNzLnNsaWNlKHMqbjgsIHMqbjgrbjgpKVxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIGMqbjhcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoaSUxMDAwMDAwID09IDAgJiYgbG9nZ2VyKSBtZW1Vc2FnZShsb2dnZXIpO1xuICAgIH1cblxuICAgIGZvciAobGV0IGk9MDsgaTx6a2V5LmRvbWFpblNpemU7IGkrKykge1xuICAgICAgICBpZiAoKGxvZ2dlcikmJihpJTEwMDAwMDAgPT0gMCkpIGxvZ2dlci5kZWJ1ZyhgUUFQIEM6ICR7aX0vJHt6a2V5LmRvbWFpblNpemV9YCk7XG4gICAgICAgIG91dEJ1ZmZDLnNldChcbiAgICAgICAgICAgIGN1cnZlLkZyLm11bChcbiAgICAgICAgICAgICAgICBvdXRCdWZmQS5zbGljZShpKm44LCBpKm44K244KSxcbiAgICAgICAgICAgICAgICBvdXRCdWZmQi5zbGljZShpKm44LCBpKm44K244KSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICBpKm44XG4gICAgICAgICk7XG4gICAgfVxuXG5cbiAgICByZXR1cm4gW291dEJ1ZmZBLCBvdXRCdWZmQiwgb3V0QnVmZkNdO1xuXG59XG5cblxuLy8gQWRhcHRpdmUgcGFyYW1ldGVycyBmb3IgYnVpbGRBQkNTdHJlYW0sIHNjYWxlZCB0byBjaXJjdWl0IHNpemUgYW5kIGEgd29ya2VyLW1lbW9yeVxuLy8gYnVkZ2V0LiBLZXkgZmFjdCBmcm9tIHByb2ZpbGluZzogZWFjaCBjb25jdXJyZW50bHktYWN0aXZlIHdvcmtlciBncm93cyBpdHMgV0FTTVxuLy8gbWVtb3J5IGFuZCBuZXZlciBzaHJpbmtzLCBzbyB0aGUgbWVtb3J5IGJ1aWxkQUJDIGxlYXZlcyBiZWhpbmQgZm9yIHRoZSByZXN0IG9mIHRoZVxuLy8gcHJvdmUgaXMgfiBtYXhJbkZsaWdodCDDlyBwZXJXb3JrZXIsIHdoZXJlIHBlcldvcmtlciA9IHdpdG5lc3MgKyAoY29lZmZzKzPCt2RvbWFpbikvbkNodW5rcy5cbi8vICAgLSBuQ2h1bmtzIHNocmlua3MgcGVyV29ya2VyIChhbmQgZ2l2ZXMgdGhlIHBvb2wgY2h1bmtzIHRvIGxvYWQtYmFsYW5jZSk7XG4vLyAgIC0gbWF4SW5GbGlnaHQgaXMgdGhlbiBjaG9zZW4gdG8ga2VlcCB0aGF0IHBlcnNpc3RlbnQgZmxvb3IgdW5kZXIgZmxvb3JCdWRnZXQsXG4vLyAgICAgdXNpbmcgYXMgbXVjaCBwYXJhbGxlbGlzbSAoc3BlZWQpIGFzIHRoZSBidWRnZXQgYWxsb3dzIChjYXBwZWQgYnkgY29uY3VycmVuY3kpLlxuLy8gU21hbGwgY2lyY3VpdHMgZ2V0IG5DaHVua3PiiYhjb25jdXJyZW5jeSBhbmQgaGlnaCBwYXJhbGxlbGlzbSAobWVtb3J5IGlzIGEgbm9uLWlzc3VlKTtcbi8vIGxhcmdlIG9uZXMgZ2V0IG1vcmUgY2h1bmtzIGFuZCBhIHBhcmFsbGVsaXNtIGJvdW5kZWQgYnkgZmxvb3JCdWRnZXQuXG5mdW5jdGlvbiBwaWNrU3RyZWFtUGFyYW1zKGN1cnZlLCB6a2V5LCBjb2VmZnMsIG9wdGlvbnMpIHtcbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICBjb25zdCBuOCA9IGN1cnZlLkZyLm44O1xuICAgIGNvbnN0IGNvbmN1cnJlbmN5ID0gY3VydmUudG0uY29uY3VycmVuY3kgfHwgMTtcbiAgICAvLyBQZXItdGFzayBieXRlczogY29lZmYgY2h1bmsgKyBnYXRoZXJlZCB3aXRuZXNzIHZhbHVlcyAobjggcGVyIGNvZWZmaWNpZW50KVxuICAgIC8vICsgMyBvdXRwdXQgY2h1bmtzLiBUaGUgd2l0bmVzcyBpdHNlbGYgc3RheXMgSlMtc2lkZSAoZ2F0aGVyZWQgcGVyIGNodW5rKS5cbiAgICBjb25zdCBuQ29lZnMgPSAoY29lZmZzLmJ5dGVMZW5ndGggLSA0KSAvICgxMiArIG44KTtcbiAgICBjb25zdCB2YXJpYWJsZUJ5dGVzID0gY29lZmZzLmJ5dGVMZW5ndGggKyBuQ29lZnMgKiBuOCArIDMgKiB6a2V5LmRvbWFpblNpemUgKiBuODtcblxuICAgIC8vIFBlcnNpc3RlbnQgd29ya2VyIG1lbW9yeSBidWlsZEFCQyBtYXkgbGVhdmUgYmVoaW5kIChkZWZhdWx0IDI1NiBNQjsgb3ZlcnJpZGVcbiAgICAvLyB2aWEgb3B0aW9ucy5idWlsZEFCQ0Zsb29yQnVkZ2V0IOKAlCByYWlzZSBpdCBmb3IgbW9yZSBwYXJhbGxlbGlzbS9zcGVlZCwgbG93ZXIgaXRcbiAgICAvLyBmb3IgYSBzbWFsbGVyIHBlYWspLiBCZWNhdXNlIGVhY2ggYnVzeSB3b3JrZXIncyBXQVNNIG1lbW9yeSBuZXZlciBzaHJpbmtzLCB0aGlzXG4gICAgLy8gZGlyZWN0bHkgYm91bmRzIHRoZSBmbG9vciB0aGUgcmVzdCBvZiB0aGUgcHJvdmUgaW5oZXJpdHMuXG4gICAgY29uc3QgZmxvb3JCdWRnZXQgPSBvcHRpb25zLmJ1aWxkQUJDRmxvb3JCdWRnZXQgfHwgKDI1NiAqIDEwMjQgKiAxMDI0KTtcblxuICAgIGNvbnN0IHRhcmdldFBlckNodW5rID0gMzIgKiAxMDI0ICogMTAyNDtcbiAgICBsZXQgbkNodW5rcyA9IE1hdGgubWF4KDEsIE1hdGguY2VpbCh2YXJpYWJsZUJ5dGVzIC8gdGFyZ2V0UGVyQ2h1bmspKTtcbiAgICBjb25zdCBwZXJXb3JrZXIgPSBNYXRoLmNlaWwodmFyaWFibGVCeXRlcyAvIG5DaHVua3MpO1xuICAgIGxldCBtYXhJbkZsaWdodCA9IE1hdGgubWF4KDEsIE1hdGgubWluKGNvbmN1cnJlbmN5LCBNYXRoLmZsb29yKGZsb29yQnVkZ2V0IC8gcGVyV29ya2VyKSkpO1xuICAgIG5DaHVua3MgPSBNYXRoLm1pbigyNTYsIE1hdGgubWF4KG5DaHVua3MsIG1heEluRmxpZ2h0ICogMykpO1xuICAgIG1heEluRmxpZ2h0ID0gTWF0aC5taW4obWF4SW5GbGlnaHQsIG5DaHVua3MpO1xuXG4gICAgaWYgKG9wdGlvbnMuYnVpbGRBQkNuQ2h1bmtzKSBuQ2h1bmtzID0gb3B0aW9ucy5idWlsZEFCQ25DaHVua3M7XG4gICAgaWYgKG9wdGlvbnMuYnVpbGRBQkNtYXhJbkZsaWdodCkgbWF4SW5GbGlnaHQgPSBvcHRpb25zLmJ1aWxkQUJDbWF4SW5GbGlnaHQ7XG4gICAgcmV0dXJuIHsgbkNodW5rcywgbWF4SW5GbGlnaHQgfTtcbn1cblxuLy8gU3RyZWFtaW5nIGJ1aWxkQUJDOiB0aGUgZG9tYWluIGlzIHNwbGl0IGludG8gYG5DaHVua3NgIGRpc2pvaW50IG91dHB1dCByYW5nZXNcbi8vIHByb2Nlc3NlZCB3aXRoIGJvdW5kZWQgY29uY3VycmVuY3kuIFRoZSB3aXRuZXNzIHZhbHVlcyBlYWNoIGNodW5rIHJlZmVyZW5jZXNcbi8vIGFyZSBnYXRoZXJlZCBKUy1zaWRlIGludG8gYSBjb21wYWN0IHBlci1jb2VmZmljaWVudCBidWZmZXIgKHMtaW5kaWNlcyByZW1hcHBlZFxuLy8gdG8gc2VxdWVudGlhbCBwb3NpdGlvbnMpLCBzbyBhIHRhc2sgaG9sZHMgb25seSBpdHMgY29lZmYgY2h1bmsgKyBnYXRoZXJlZFxuLy8gdmFsdWVzICsgb3V0cHV0IGNodW5rIC0tIHRoZSB3aXRuZXNzIGl0c2VsZiBuZXZlciBlbnRlcnMgV0FTTSBhbmQgaXRzIHNpemUgaXNcbi8vIHVuYm91bmRlZC5cbmFzeW5jIGZ1bmN0aW9uIGJ1aWxkQUJDU3RyZWFtKGN1cnZlLCB6a2V5LCB3aXRuZXNzLCBjb2VmZnMsIGxvZ2dlciwgbkNodW5rcywgbWF4SW5GbGlnaHQpIHtcbiAgICBjb25zdCBuOCA9IGN1cnZlLkZyLm44O1xuICAgIGNvbnN0IHNDb2VmID0gNCAqIDMgKyB6a2V5Lm44cjtcbiAgICBjb25zdCBkb21haW5TaXplID0gemtleS5kb21haW5TaXplO1xuXG4gICAgbGV0IGdldFVpbnQzMjtcbiAgICBpZiAoY29lZmZzIGluc3RhbmNlb2YgQmlnQnVmZmVyKSB7XG4gICAgICAgIGNvbnN0IGNvZWZmc0RWID0gW107XG4gICAgICAgIGNvbnN0IFBBR0VfTEVOID0gY29lZmZzLmJ1ZmZlcnNbMF0ubGVuZ3RoO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvZWZmcy5idWZmZXJzLmxlbmd0aDsgaSsrKSBjb2VmZnNEVi5wdXNoKG5ldyBEYXRhVmlldyhjb2VmZnMuYnVmZmVyc1tpXS5idWZmZXIpKTtcbiAgICAgICAgZ2V0VWludDMyID0gKHBvcykgPT4gY29lZmZzRFZbTWF0aC5mbG9vcihwb3MgLyBQQUdFX0xFTildLmdldFVpbnQzMihwb3MgJSBQQUdFX0xFTiwgdHJ1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgY29lZmZzRFYgPSBuZXcgRGF0YVZpZXcoY29lZmZzLmJ1ZmZlciwgY29lZmZzLmJ5dGVPZmZzZXQsIGNvZWZmcy5ieXRlTGVuZ3RoKTtcbiAgICAgICAgZ2V0VWludDMyID0gKHBvcykgPT4gY29lZmZzRFYuZ2V0VWludDMyKHBvcywgdHJ1ZSk7XG4gICAgfVxuICAgIGZ1bmN0aW9uIGdldEN1dFBvaW50KHYpIHtcbiAgICAgICAgbGV0IG0gPSAwLCBuID0gZ2V0VWludDMyKDApO1xuICAgICAgICB3aGlsZSAobSA8IG4pIHtcbiAgICAgICAgICAgIGNvbnN0IGsgPSBNYXRoLmZsb29yKChuICsgbSkgLyAyKTtcbiAgICAgICAgICAgIGNvbnN0IHZhID0gZ2V0VWludDMyKDQgKyBrICogc0NvZWYgKyA0KTtcbiAgICAgICAgICAgIGlmICh2YSA+IHYpIG4gPSBrIC0gMTsgZWxzZSBpZiAodmEgPCB2KSBtID0gayArIDE7IGVsc2UgbiA9IGs7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIDQgKyBtICogc0NvZWY7XG4gICAgfVxuXG4gICAgY29uc3QgZWxlbWVudHNQZXJDaHVuayA9IE1hdGguZmxvb3IoKGRvbWFpblNpemUgLSAxKSAvIG5DaHVua3MpICsgMTtcbiAgICBjb25zdCBjdXRQb2ludHMgPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5DaHVua3M7IGkrKykgY3V0UG9pbnRzLnB1c2goZ2V0Q3V0UG9pbnQoaSAqIGVsZW1lbnRzUGVyQ2h1bmspKTtcbiAgICBjdXRQb2ludHMucHVzaChjb2VmZnMuYnl0ZUxlbmd0aCk7XG5cbiAgICAvLyBSZXR1cm4gYSBmbGF0IFVpbnQ4QXJyYXkgd2hlbiB0aGUgZG9tYWluIGZpdHMgdW5kZXIgQmlnQnVmZmVyJ3MgMSBHaUIgcGFnZSxcbiAgICAvLyBzbyB0aGUgZG93bnN0cmVhbSBJRkZUIGNhbiBjb25zdW1lIGl0IGluIHBsYWNlIChza2lwIGl0cyBkZWZlbnNpdmUgY29weSkuXG4gICAgLy8gTGFyZ2VyIGRvbWFpbnMgc3RheSBwYWdlZCBCaWdCdWZmZXJzICh0aGUgSUZGVCBmbGF0dGVucyB0aG9zZSBhcyBiZWZvcmUpLlxuICAgIGNvbnN0IG91dEJ5dGVzID0gZG9tYWluU2l6ZSAqIG44O1xuICAgIGNvbnN0IG1rT3V0ID0gKCkgPT4gKG91dEJ5dGVzIDwgKDEgPDwgMzApKSA/IG5ldyBVaW50OEFycmF5KG91dEJ5dGVzKSA6IG5ldyBCaWdCdWZmZXIob3V0Qnl0ZXMpO1xuICAgIGNvbnN0IG91dEJ1ZmZBID0gbWtPdXQoKTtcbiAgICBjb25zdCBvdXRCdWZmQiA9IG1rT3V0KCk7XG4gICAgY29uc3Qgb3V0QnVmZkMgPSBta091dCgpO1xuXG4gICAgY29uc3QgaW5GbGlnaHQgPSBuZXcgU2V0KCk7XG4gICAgY29uc3QgdGFza3MgPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5DaHVua3M7IGkrKykge1xuICAgICAgICBjb25zdCBvdXRPZmZzZXQgPSBpICogZWxlbWVudHNQZXJDaHVuaztcbiAgICAgICAgY29uc3QgbiA9IE1hdGgubWluKGVsZW1lbnRzUGVyQ2h1bmssIGRvbWFpblNpemUgLSBvdXRPZmZzZXQpO1xuICAgICAgICBpZiAobiA8PSAwKSBicmVhaztcbiAgICAgICAgY29uc3QgY3BBID0gY3V0UG9pbnRzW2ldLCBjcEIgPSBjdXRQb2ludHNbaSArIDFdO1xuICAgICAgICB3aGlsZSAoaW5GbGlnaHQuc2l6ZSA+PSBtYXhJbkZsaWdodCkgYXdhaXQgUHJvbWlzZS5yYWNlKGluRmxpZ2h0KTtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBidWlsZEFCQ1N0cmVhbTogJHtpfS8ke25DaHVua3N9YCk7XG4gICAgICAgIGNvbnN0IG9wID0gKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIC8vIEdhdGhlciB0aGUgd2l0bmVzcyB2YWx1ZXMgdGhpcyBjaHVuayByZWZlcmVuY2VzIGludG8gYSBjb21wYWN0XG4gICAgICAgICAgICAvLyBidWZmZXIgKG9uZSBlbnRyeSBwZXIgY29lZmZpY2llbnQsIGluIGNvZWZmaWNpZW50IG9yZGVyKSBhbmRcbiAgICAgICAgICAgIC8vIHJld3JpdGUgZWFjaCBjb2VmZmljaWVudCdzIHMtaW5kZXggdG8gaXRzIHNlcXVlbnRpYWwgcG9zaXRpb24uXG4gICAgICAgICAgICAvLyBUaGUgd2l0bmVzcyBpdHNlbGYgbmV2ZXIgZW50ZXJzIFdBU00sIHNvIGl0cyBzaXplIGlzIHVuYm91bmRlZFxuICAgICAgICAgICAgLy8gKGl0IGNhbiBzdGF5IGEgQmlnQnVmZmVyKSBhbmQgZWFjaCB0YXNrIHNoaXBzIG9ubHkgd2hhdCBpdCB1c2VzXG4gICAgICAgICAgICAvLyAtLSB0eXBpY2FsbHkgbXVjaCBsZXNzIHRoYW4gYSBmdWxsIHdpdG5lc3MgY29weSBwZXIgdGFzay5cbiAgICAgICAgICAgIGNvbnN0IGNvZWZmQ2h1bmsgPSBjb2VmZnMuc2xpY2UoY3BBLCBjcEIpO1xuICAgICAgICAgICAgY29uc3QgbkNvZWZDaHVuayA9IChjcEIgLSBjcEEpIC8gc0NvZWY7XG4gICAgICAgICAgICBjb25zdCBnYXRoZXJlZCA9IG5ldyBVaW50OEFycmF5KG5Db2VmQ2h1bmsgKiBuOCk7XG4gICAgICAgICAgICAvLyBIb3QgbG9vcCAob25lIGl0ZXJhdGlvbiBwZXIgY29lZmZpY2llbnQpOiB1c2UgdHlwZWQtYXJyYXkgbGFuZVxuICAgICAgICAgICAgLy8gY29waWVzIGluc3RlYWQgb2Ygc2V0KHN1YmFycmF5KSAtLSBwZXItZWxlbWVudCBtZW1jcHkgZGlzcGF0Y2hcbiAgICAgICAgICAgIC8vIGRvbWluYXRlZCB0aGUgcHJvZmlsZSBvdGhlcndpc2UuIFVpbnQzMiBsYW5lcyBvbiBwdXJwb3NlOiB0aGVcbiAgICAgICAgICAgIC8vIGRhdGEgaXMgaW50ZWdlciBiaXQgcGF0dGVybnMsIGFuZCBGbG9hdDY0QXJyYXkgc3RvcmVzIG1heVxuICAgICAgICAgICAgLy8gbGVnYWxseSBjYW5vbmljYWxpemUgTmFOLXBhdHRlcm5lZCBsYW5lcyAoU2V0VmFsdWVJbkJ1ZmZlciBpc1xuICAgICAgICAgICAgLy8gaW1wbGVtZW50YXRpb24tZGVmaW5lZCBmb3IgTmFOIGVuY29kaW5ncykuIFRoZSBzLWZpZWxkIG9mZnNldHNcbiAgICAgICAgICAgIC8vIGFyZSA0LWJ5dGUgYWxpZ25lZCAoc0NvZWYgYW5kIHRoZSArOCBvZmZzZXQgYXJlIG11bHRpcGxlcyBvZiA0KS5cbiAgICAgICAgICAgIGNvbnN0IGNodW5rVTMyID0gbmV3IFVpbnQzMkFycmF5KGNvZWZmQ2h1bmsuYnVmZmVyLCBjb2VmZkNodW5rLmJ5dGVPZmZzZXQsIGNvZWZmQ2h1bmsuYnl0ZUxlbmd0aCA+PiAyKTtcbiAgICAgICAgICAgIGNvbnN0IHNTdGVwID0gc0NvZWYgPj4gMjtcbiAgICAgICAgICAgIGNvbnN0IGxhbmVGYXN0ID0gISF3aXRuZXNzLmJ1ZmZlciAmJiAoKHdpdG5lc3MuYnl0ZU9mZnNldCAmIDMpID09PSAwKSAmJiAobjggPT09IDMyKTtcbiAgICAgICAgICAgIGlmIChsYW5lRmFzdCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHdVMzIgPSBuZXcgVWludDMyQXJyYXkod2l0bmVzcy5idWZmZXIsIHdpdG5lc3MuYnl0ZU9mZnNldCwgd2l0bmVzcy5ieXRlTGVuZ3RoID4+IDIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGdVMzIgPSBuZXcgVWludDMyQXJyYXkoZ2F0aGVyZWQuYnVmZmVyKTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IG5Db2VmQ2h1bms7IGorKykge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzaSA9IGNodW5rVTMyW2ogKiBzU3RlcCArIDJdO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzbyA9IHNpIDw8IDMsIGdvID0gaiA8PCAzO1xuICAgICAgICAgICAgICAgICAgICBnVTMyW2dvXSA9IHdVMzJbc29dOyBnVTMyW2dvICsgMV0gPSB3VTMyW3NvICsgMV07XG4gICAgICAgICAgICAgICAgICAgIGdVMzJbZ28gKyAyXSA9IHdVMzJbc28gKyAyXTsgZ1UzMltnbyArIDNdID0gd1UzMltzbyArIDNdO1xuICAgICAgICAgICAgICAgICAgICBnVTMyW2dvICsgNF0gPSB3VTMyW3NvICsgNF07IGdVMzJbZ28gKyA1XSA9IHdVMzJbc28gKyA1XTtcbiAgICAgICAgICAgICAgICAgICAgZ1UzMltnbyArIDZdID0gd1UzMltzbyArIDZdOyBnVTMyW2dvICsgN10gPSB3VTMyW3NvICsgN107XG4gICAgICAgICAgICAgICAgICAgIGNodW5rVTMyW2ogKiBzU3RlcCArIDJdID0gajtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnN0IHdpdG5lc3NJc1ZpZXcgPSAhIXdpdG5lc3MuYnVmZmVyO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgbkNvZWZDaHVuazsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHMgPSBjaHVua1UzMltqICogc1N0ZXAgKyAyXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHdpdG5lc3NJc1ZpZXcpIGdhdGhlcmVkLnNldCh3aXRuZXNzLnN1YmFycmF5KHMgKiBuOCwgKHMgKyAxKSAqIG44KSwgaiAqIG44KTtcbiAgICAgICAgICAgICAgICAgICAgZWxzZSBnYXRoZXJlZC5zZXQod2l0bmVzcy5zbGljZShzICogbjgsIChzICsgMSkgKiBuOCksIGogKiBuOCk7XG4gICAgICAgICAgICAgICAgICAgIGNodW5rVTMyW2ogKiBzU3RlcCArIDJdID0gajtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCB0YXNrID0gW1xuICAgICAgICAgICAgICAgIHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAwLCBidWZmOiBjb2VmZkNodW5rfSxcbiAgICAgICAgICAgICAgICB7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMSwgYnVmZjogZ2F0aGVyZWR9LFxuICAgICAgICAgICAgICAgIHtjbWQ6IFwiQUxMT0NcIiwgdmFyOiAyLCBsZW46IG4gKiBuOH0sXG4gICAgICAgICAgICAgICAge2NtZDogXCJBTExPQ1wiLCB2YXI6IDMsIGxlbjogbiAqIG44fSxcbiAgICAgICAgICAgICAgICB7Y21kOiBcIkFMTE9DXCIsIHZhcjogNCwgbGVuOiBuICogbjh9LFxuICAgICAgICAgICAgICAgIHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IFwicWFwX2J1aWxkQUJDXCIsIHBhcmFtczogW1xuICAgICAgICAgICAgICAgICAgICB7dmFyOiAwfSwge3ZhbDogbkNvZWZDaHVua30sIHt2YXI6IDF9LFxuICAgICAgICAgICAgICAgICAgICB7dmFyOiAyfSwge3ZhcjogM30sIHt2YXI6IDR9LFxuICAgICAgICAgICAgICAgICAgICB7dmFsOiBvdXRPZmZzZXR9LCB7dmFsOiBufSwge3ZhbDogMH0sIHt2YWw6IG5Db2VmQ2h1bmt9LFxuICAgICAgICAgICAgICAgIF19LFxuICAgICAgICAgICAgICAgIHtjbWQ6IFwiR0VUXCIsIG91dDogMCwgdmFyOiAyLCBsZW46IG4gKiBuOH0sXG4gICAgICAgICAgICAgICAge2NtZDogXCJHRVRcIiwgb3V0OiAxLCB2YXI6IDMsIGxlbjogbiAqIG44fSxcbiAgICAgICAgICAgICAgICB7Y21kOiBcIkdFVFwiLCBvdXQ6IDIsIHZhcjogNCwgbGVuOiBuICogbjh9LFxuICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIGNvbnN0IHIgPSBhd2FpdCBjdXJ2ZS50bS5xdWV1ZUFjdGlvbih0YXNrLCBbY29lZmZDaHVuay5idWZmZXIsIGdhdGhlcmVkLmJ1ZmZlcl0pO1xuICAgICAgICAgICAgb3V0QnVmZkEuc2V0KHJbMF0sIG91dE9mZnNldCAqIG44KTtcbiAgICAgICAgICAgIG91dEJ1ZmZCLnNldChyWzFdLCBvdXRPZmZzZXQgKiBuOCk7XG4gICAgICAgICAgICBvdXRCdWZmQy5zZXQoclsyXSwgb3V0T2Zmc2V0ICogbjgpO1xuICAgICAgICB9KSgpO1xuICAgICAgICBjb25zdCBzbG90ID0gb3AuZmluYWxseSgoKSA9PiBpbkZsaWdodC5kZWxldGUoc2xvdCkpO1xuICAgICAgICBpbkZsaWdodC5hZGQoc2xvdCk7XG4gICAgICAgIHRhc2tzLnB1c2goc2xvdCk7XG4gICAgfVxuICAgIGF3YWl0IFByb21pc2UuYWxsKHRhc2tzKTtcbiAgICByZXR1cm4gW291dEJ1ZmZBLCBvdXRCdWZmQiwgb3V0QnVmZkNdO1xufVxuXG5hc3luYyBmdW5jdGlvbiBqb2luQUJDKGN1cnZlLCB6a2V5LCBhLCBiLCBjLCBsb2dnZXIpIHtcbiAgICBjb25zdCBNQVhfQ0hVTktfU0laRSA9IDEgPDwgMTY7XG5cbiAgICBjb25zdCBuOCA9IGN1cnZlLkZyLm44O1xuICAgIGNvbnN0IG5FbGVtZW50cyA9IE1hdGguZmxvb3IoYS5ieXRlTGVuZ3RoIC8gY3VydmUuRnIubjgpO1xuXG4gICAgY29uc3QgcHJvbWlzZXMgPSBbXTtcblxuICAgIGZvciAobGV0IGk9MDsgaTxuRWxlbWVudHM7IGkgKz0gTUFYX0NIVU5LX1NJWkUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBKb2luQUJDOiAke2l9LyR7bkVsZW1lbnRzfWApO1xuICAgICAgICBjb25zdCBuPSBNYXRoLm1pbihuRWxlbWVudHMgLSBpLCBNQVhfQ0hVTktfU0laRSk7XG5cbiAgICAgICAgY29uc3QgdGFzayA9IFtdO1xuXG4gICAgICAgIGNvbnN0IGFDaHVuayA9IGEuc2xpY2UoaSpuOCwgKGkgKyBuKSpuOCApO1xuICAgICAgICBjb25zdCBiQ2h1bmsgPSBiLnNsaWNlKGkqbjgsIChpICsgbikqbjggKTtcbiAgICAgICAgY29uc3QgY0NodW5rID0gYy5zbGljZShpKm44LCAoaSArIG4pKm44ICk7XG5cbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAwLCBidWZmOiBhQ2h1bmt9KTtcbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAxLCBidWZmOiBiQ2h1bmt9KTtcbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAyLCBidWZmOiBjQ2h1bmt9KTtcbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NcIiwgdmFyOiAzLCBsZW46IG4qbjh9KTtcbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IFwicWFwX2pvaW5BQkNcIiwgcGFyYW1zOltcbiAgICAgICAgICAgIHt2YXI6IDB9LFxuICAgICAgICAgICAge3ZhcjogMX0sXG4gICAgICAgICAgICB7dmFyOiAyfSxcbiAgICAgICAgICAgIHt2YWw6IG59LFxuICAgICAgICAgICAge3ZhcjogM30sXG4gICAgICAgIF19KTtcbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IFwiZnJtX2JhdGNoRnJvbU1vbnRnb21lcnlcIiwgcGFyYW1zOltcbiAgICAgICAgICAgIHt2YXI6IDN9LFxuICAgICAgICAgICAge3ZhbDogbn0sXG4gICAgICAgICAgICB7dmFyOiAzfVxuICAgICAgICBdfSk7XG4gICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkdFVFwiLCBvdXQ6IDAsIHZhcjogMywgbGVuOiBuKm44fSk7XG4gICAgICAgIHByb21pc2VzLnB1c2goY3VydmUudG0ucXVldWVBY3Rpb24odGFzaywgW2FDaHVuay5idWZmZXIsIGJDaHVuay5idWZmZXIsIGNDaHVuay5idWZmZXJdKSApO1xuICAgIH1cblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UuYWxsKHByb21pc2VzKTtcblxuICAgIGxldCBvdXRCdWZmO1xuICAgIGlmIChhIGluc3RhbmNlb2YgQmlnQnVmZmVyKSB7XG4gICAgICAgIG91dEJ1ZmYgPSBuZXcgQmlnQnVmZmVyKGEuYnl0ZUxlbmd0aCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgb3V0QnVmZiA9IG5ldyBVaW50OEFycmF5KGEuYnl0ZUxlbmd0aCk7XG4gICAgfVxuXG4gICAgbGV0IHA9MDtcbiAgICBmb3IgKGxldCBpPTA7IGk8cmVzdWx0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIG91dEJ1ZmYuc2V0KHJlc3VsdFtpXVswXSwgcCk7XG4gICAgICAgIHAgKz0gcmVzdWx0W2ldWzBdLmJ5dGVMZW5ndGg7XG4gICAgfVxuXG4gICAgcmV0dXJuIG91dEJ1ZmY7XG59XG5cbmZ1bmN0aW9uIG1lbVVzYWdlKGxvZ2dlcikge1xuICAgIGlmICghbG9nZ2VyKSByZXR1cm47XG4gICAgY29uc3QgdXNlZCA9IHByb2Nlc3MubWVtb3J5VXNhZ2UoKTtcbiAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgXCIgICAgICAgICBcIixcbiAgICAgICAgXCJcXHgxYlswbSBIZWFwOlxceDFiWzMybVwiLCBgJHtNYXRoLnJvdW5kKHVzZWQuaGVhcFVzZWQgLyAxMDI0IC8gMTAyNCAqIDEwMCkgLyAxMDB9IE1CYC5wYWRFbmQoMTIpLFxuICAgICAgICBcIlxceDFiWzBtIC8gXFx4MWJbMzJtXCIsIGAke01hdGgucm91bmQodXNlZC5oZWFwVG90YWwgLyAxMDI0IC8gMTAyNCAqIDEwMCkgLyAxMDB9IE1CYC5wYWRFbmQoMTIpLFxuICAgICAgICBcIlxceDFiWzBtIFJTUzpcXHgxYlszMm1cIiwgYCR7TWF0aC5yb3VuZCh1c2VkLnJzcyAvIDEwMjQgLyAxMDI0ICogMTAwKSAvIDEwMH0gTUJgLnBhZEVuZCgxMiksXG4gICAgICAgIFwiXFx4MWJbMG0gRXh0ZXJuYWw6XFx4MWJbMzJtXCIsIGAke01hdGgucm91bmQodXNlZC5leHRlcm5hbCAvIDEwMjQgLyAxMDI0ICogMTAwKSAvIDEwMH0gTUJgLnBhZEVuZCgxMiksXG4gICAgICAgIFwiXFx4MWJbMG0gQXJyQnVmZmVyczpcXHgxYlszMm1cIiwgYCR7TWF0aC5yb3VuZCh1c2VkLmFycmF5QnVmZmVycyAvIDEwMjQgLyAxMDI0ICogMTAwKSAvIDEwMH0gTUJgLnBhZEVuZCgxMiksXG4gICAgICAgIFwiXFx4MWJbMG1cIlxuICAgICk7XG59XG5cbmZ1bmN0aW9uIG1vbml0b3JNZW1vcnlVc2FnZShsb2dnZXIsIGludGVydmFsID0gNTAwMCkge1xuICAgIHJldHVybiBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgIG1lbVVzYWdlKGxvZ2dlcik7XG4gICAgfSwgaW50ZXJ2YWwpO1xufVxuIiwiXG5pbXBvcnQgZnMgZnJvbVwiZnNcIjtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG9wZW4oZmlsZU5hbWUsIG9wZW5GbGFncywgY2FjaGVTaXplLCBwYWdlU2l6ZSkge1xuICAgIGNhY2hlU2l6ZSA9IGNhY2hlU2l6ZSB8fCA0MDk2KjY0O1xuICAgIGlmICh0eXBlb2Ygb3BlbkZsYWdzICE9PSBcIm51bWJlclwiICYmIFtcIncrXCIsIFwid3grXCIsIFwiclwiLCBcImF4K1wiLCBcImErXCJdLmluZGV4T2Yob3BlbkZsYWdzKSA8MClcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBvcGVuIG9wdGlvblwiKTtcbiAgICBjb25zdCBmZCA9YXdhaXQgZnMucHJvbWlzZXMub3BlbihmaWxlTmFtZSwgb3BlbkZsYWdzKTtcblxuICAgIGNvbnN0IHN0YXRzID0gYXdhaXQgZmQuc3RhdCgpO1xuXG4gICAgcmV0dXJuICBuZXcgRmFzdEZpbGUoZmQsIHN0YXRzLCBjYWNoZVNpemUsIHBhZ2VTaXplLCBmaWxlTmFtZSk7XG59XG5cblxuY2xhc3MgRmFzdEZpbGUge1xuXG4gICAgY29uc3RydWN0b3IoZmQsIHN0YXRzLCBjYWNoZVNpemUsIHBhZ2VTaXplLCBmaWxlTmFtZSkge1xuICAgICAgICB0aGlzLmZpbGVOYW1lID0gZmlsZU5hbWU7XG4gICAgICAgIHRoaXMuZmQgPSBmZDtcbiAgICAgICAgdGhpcy5wb3MgPSAwO1xuICAgICAgICB0aGlzLnBhZ2VTaXplID0gcGFnZVNpemUgfHwgKDEgPDwgOCk7XG4gICAgICAgIHdoaWxlICh0aGlzLnBhZ2VTaXplIDwgc3RhdHMuYmxrc2l6ZSkge1xuICAgICAgICAgICAgdGhpcy5wYWdlU2l6ZSAqPSAyO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudG90YWxTaXplID0gc3RhdHMuc2l6ZTtcbiAgICAgICAgdGhpcy50b3RhbFBhZ2VzID0gTWF0aC5mbG9vcigoc3RhdHMuc2l6ZSAtMSkgLyB0aGlzLnBhZ2VTaXplKSsxO1xuICAgICAgICB0aGlzLm1heFBhZ2VzTG9hZGVkID0gTWF0aC5mbG9vciggY2FjaGVTaXplIC8gdGhpcy5wYWdlU2l6ZSkrMTtcbiAgICAgICAgdGhpcy5wYWdlcyA9IHt9O1xuICAgICAgICB0aGlzLnBlbmRpbmdMb2FkcyA9IFtdO1xuICAgICAgICB0aGlzLndyaXRpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5yZWFkaW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMuYXZCdWZmcyA9IFtdO1xuICAgICAgICB0aGlzLmhpc3RvcnkgPSB7fTtcbiAgICB9XG5cbiAgICBfbG9hZFBhZ2UocCkge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgUCA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpPT4ge1xuICAgICAgICAgICAgc2VsZi5wZW5kaW5nTG9hZHMucHVzaCh7XG4gICAgICAgICAgICAgICAgcGFnZTogcCxcbiAgICAgICAgICAgICAgICByZXNvbHZlOiByZXNvbHZlLFxuICAgICAgICAgICAgICAgIHJlamVjdDogcmVqZWN0XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHNlbGYuX19zdGF0dXNQYWdlKFwiQWZ0ZXIgTG9hZCByZXF1ZXN0OiBcIiwgcCk7XG4gICAgICAgIHJldHVybiBQO1xuICAgIH1cblxuICAgIF9fc3RhdHVzUGFnZShzLCBwKSB7XG4gICAgICAgIGNvbnN0IGxvZ0VudHJ5ID0gW107XG4gICAgICAgIGNvbnN0IHNlbGY9dGhpcztcbiAgICAgICAgaWYgKCFzZWxmLmxvZ0hpc3RvcnkpIHJldHVybjtcbiAgICAgICAgbG9nRW50cnkucHVzaChcIj09XCIgKyBzKyBcIiBcIiArcCk7XG4gICAgICAgIGxldCBTID0gXCJcIjtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHNlbGYucGVuZGluZ0xvYWRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoc2VsZi5wZW5kaW5nTG9hZHNbaV0ucGFnZSA9PSBwKSBTID0gUyArIFwiIFwiICsgaTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoUykgbG9nRW50cnkucHVzaChcIlBlbmRpbmcgbG9hZHM6XCIrUyk7XG4gICAgICAgIGlmICh0eXBlb2Ygc2VsZi5wYWdlc1twXSAhPSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICBjb25zdCBwYWdlID0gc2VsZi5wYWdlc1twXTtcbiAgICAgICAgICAgIGxvZ0VudHJ5LnB1c2goXCJMb2FkZWRcIik7XG4gICAgICAgICAgICBsb2dFbnRyeS5wdXNoKFwicGVuZGluZ09wczogXCIrcGFnZS5wZW5kaW5nT3BzKTtcbiAgICAgICAgICAgIGlmIChwYWdlLmxvYWRpbmcpIGxvZ0VudHJ5LnB1c2goXCJsb2FkaW5nOiBcIitwYWdlLmxvYWRpbmcpO1xuICAgICAgICAgICAgaWYgKHBhZ2Uud3JpdGluZykgbG9nRW50cnkucHVzaChcIndyaXRpbmdcIik7XG4gICAgICAgICAgICBpZiAocGFnZS5kaXJ0eSkgbG9nRW50cnkucHVzaChcImRpcnR5XCIpO1xuICAgICAgICB9XG4gICAgICAgIGxvZ0VudHJ5LnB1c2goXCI9PVwiKTtcblxuICAgICAgICBpZiAoIXNlbGYuaGlzdG9yeVtwXSkgc2VsZi5oaXN0b3J5W3BdID0gW107XG4gICAgICAgIHNlbGYuaGlzdG9yeVtwXS5wdXNoKGxvZ0VudHJ5KTtcbiAgICB9XG5cbiAgICBfX3ByaW50SGlzdG9yeShwKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBpZiAoIXNlbGYuaGlzdG9yeVtwXSkgY29uc29sZS5sb2coXCJFbXB0eSBIaXN0b3J5IFwiLCBwKTtcbiAgICAgICAgY29uc29sZS5sb2coXCJIaXN0b3J5IFwiK3ApO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8c2VsZi5oaXN0b3J5W3BdLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8c2VsZi5oaXN0b3J5W3BdW2ldLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCItPiBcIiArIHNlbGYuaGlzdG9yeVtwXVtpXVtqXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cblxuXG4gICAgX3RyaWdnZXJMb2FkKCkge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICBpZiAoc2VsZi5yZWFkaW5nKSByZXR1cm47XG4gICAgICAgIGlmIChzZWxmLnBlbmRpbmdMb2Fkcy5sZW5ndGg9PTApIHJldHVybjtcblxuICAgICAgICBjb25zdCBwYWdlSWR4cyA9IE9iamVjdC5rZXlzKHNlbGYucGFnZXMpO1xuXG4gICAgICAgIGNvbnN0IGRlbGV0YWJsZVBhZ2VzID0gW107XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxwYWdlSWR4cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgcGFnZSA9IHNlbGYucGFnZXNbcGFyc2VJbnQocGFnZUlkeHNbaV0pXTtcbiAgICAgICAgICAgIGlmICgocGFnZS5kaXJ0eSA9PSBmYWxzZSkmJihwYWdlLnBlbmRpbmdPcHM9PTApJiYoIXBhZ2Uud3JpdGluZykmJighcGFnZS5sb2FkaW5nKSkgZGVsZXRhYmxlUGFnZXMucHVzaChwYXJzZUludChwYWdlSWR4c1tpXSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGZyZWVQYWdlcyA9IHNlbGYubWF4UGFnZXNMb2FkZWQgLSBwYWdlSWR4cy5sZW5ndGg7XG5cbiAgICAgICAgY29uc3Qgb3BzID0gW107XG5cbiAgICAgICAgLy8gd2hpbGUgcGVuZGluZyBsb2FkcyBhbmRcbiAgICAgICAgLy8gICAgIHRoZSBwYWdlIGlzIGxvYWRlZCBvciBJIGNhbiByZWNvdmVyIG9uZS5cbiAgICAgICAgd2hpbGUgKFxuICAgICAgICAgICAgKHNlbGYucGVuZGluZ0xvYWRzLmxlbmd0aD4wKSAmJlxuICAgICAgICAgICAgKCAgICh0eXBlb2Ygc2VsZi5wYWdlc1tzZWxmLnBlbmRpbmdMb2Fkc1swXS5wYWdlXSAhPSBcInVuZGVmaW5lZFwiIClcbiAgICAgICAgICAgICAgfHwoICAoZnJlZVBhZ2VzPjApXG4gICAgICAgICAgICAgICAgIHx8KGRlbGV0YWJsZVBhZ2VzLmxlbmd0aD4wKSkpKSB7XG4gICAgICAgICAgICBjb25zdCBsb2FkID0gc2VsZi5wZW5kaW5nTG9hZHMuc2hpZnQoKTtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygc2VsZi5wYWdlc1tsb2FkLnBhZ2VdICE9IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICBzZWxmLnBhZ2VzW2xvYWQucGFnZV0ucGVuZGluZ09wcyArKztcbiAgICAgICAgICAgICAgICBjb25zdCBpZHggPSBkZWxldGFibGVQYWdlcy5pbmRleE9mKGxvYWQucGFnZSk7XG4gICAgICAgICAgICAgICAgaWYgKGlkeD49MCkgZGVsZXRhYmxlUGFnZXMuc3BsaWNlKGlkeCwgMSk7XG4gICAgICAgICAgICAgICAgaWYgKHNlbGYucGFnZXNbbG9hZC5wYWdlXS5sb2FkaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbbG9hZC5wYWdlXS5sb2FkaW5nLnB1c2gobG9hZCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbG9hZC5yZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHNlbGYuX19zdGF0dXNQYWdlKFwiQWZ0ZXIgTG9hZCAoY2FjaGVkKTogXCIsIGxvYWQucGFnZSk7XG5cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaWYgKGZyZWVQYWdlcykge1xuICAgICAgICAgICAgICAgICAgICBmcmVlUGFnZXMtLTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBmcCA9IGRlbGV0YWJsZVBhZ2VzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuX19zdGF0dXNQYWdlKFwiQmVmb3JlIFVubG9hZDogXCIsIGZwKTtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5hdkJ1ZmZzLnVuc2hpZnQoc2VsZi5wYWdlc1tmcF0pO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgc2VsZi5wYWdlc1tmcF07XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuX19zdGF0dXNQYWdlKFwiQWZ0ZXIgVW5sb2FkOiBcIiwgZnApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChsb2FkLnBhZ2U+PXNlbGYudG90YWxQYWdlcykge1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnBhZ2VzW2xvYWQucGFnZV0gPSBnZXROZXdQYWdlKCk7XG4gICAgICAgICAgICAgICAgICAgIGxvYWQucmVzb2x2ZSgpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIExvYWQgKG5ldyk6IFwiLCBsb2FkLnBhZ2UpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYucmVhZGluZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbbG9hZC5wYWdlXSA9IGdldE5ld1BhZ2UoKTtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5wYWdlc1tsb2FkLnBhZ2VdLmxvYWRpbmcgPSBbbG9hZF07XG4gICAgICAgICAgICAgICAgICAgIG9wcy5wdXNoKHNlbGYuZmQucmVhZChzZWxmLnBhZ2VzW2xvYWQucGFnZV0uYnVmZiwgMCwgc2VsZi5wYWdlU2l6ZSwgbG9hZC5wYWdlKnNlbGYucGFnZVNpemUpLnRoZW4oKHJlcyk9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnBhZ2VzW2xvYWQucGFnZV0uc2l6ZSA9IHJlcy5ieXRlc1JlYWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBsb2FkaW5nID0gc2VsZi5wYWdlc1tsb2FkLnBhZ2VdLmxvYWRpbmc7XG4gICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgc2VsZi5wYWdlc1tsb2FkLnBhZ2VdLmxvYWRpbmc7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBpPTA7IGk8bG9hZGluZy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvYWRpbmdbaV0ucmVzb2x2ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBMb2FkIChsb2FkZWQpOiBcIiwgbG9hZC5wYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICAgICAgICAgIH0sIChlcnIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvYWQucmVqZWN0KGVycik7XG4gICAgICAgICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBMb2FkIChsb2FkaW5nKTogXCIsIGxvYWQucGFnZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIGlmIChvcHMubGVuZ3RoPjEpIGNvbnNvbGUubG9nKG9wcy5sZW5ndGgpO1xuXG4gICAgICAgIFByb21pc2UuYWxsKG9wcykudGhlbiggKCkgPT4ge1xuICAgICAgICAgICAgc2VsZi5yZWFkaW5nID0gZmFsc2U7XG4gICAgICAgICAgICBpZiAoc2VsZi5wZW5kaW5nTG9hZHMubGVuZ3RoPjApIHNldEltbWVkaWF0ZShzZWxmLl90cmlnZ2VyTG9hZC5iaW5kKHNlbGYpKTtcbiAgICAgICAgICAgIHNlbGYuX3RyeUNsb3NlKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGZ1bmN0aW9uIGdldE5ld1BhZ2UoKSB7XG4gICAgICAgICAgICBpZiAoc2VsZi5hdkJ1ZmZzLmxlbmd0aD4wKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcCA9IHNlbGYuYXZCdWZmcy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgIHAuZGlydHkgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBwLnBlbmRpbmdPcHMgPSAxO1xuICAgICAgICAgICAgICAgIHAuc2l6ZSA9MDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgZGlydHk6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBidWZmOiBuZXcgVWludDhBcnJheShzZWxmLnBhZ2VTaXplKSxcbiAgICAgICAgICAgICAgICAgICAgcGVuZGluZ09wczogMSxcbiAgICAgICAgICAgICAgICAgICAgc2l6ZTogMFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgIH1cblxuXG4gICAgX3RyaWdnZXJXcml0ZSgpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmIChzZWxmLndyaXRpbmcpIHJldHVybjtcblxuICAgICAgICBjb25zdCBwYWdlSWR4cyA9IE9iamVjdC5rZXlzKHNlbGYucGFnZXMpO1xuXG4gICAgICAgIGNvbnN0IG9wcyA9IFtdO1xuXG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxwYWdlSWR4cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgcGFnZSA9IHNlbGYucGFnZXNbcGFyc2VJbnQocGFnZUlkeHNbaV0pXTtcbiAgICAgICAgICAgIGlmIChwYWdlLmRpcnR5KSB7XG4gICAgICAgICAgICAgICAgcGFnZS5kaXJ0eSA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHBhZ2Uud3JpdGluZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgc2VsZi53cml0aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBvcHMucHVzaCggc2VsZi5mZC53cml0ZShwYWdlLmJ1ZmYsIDAsIHBhZ2Uuc2l6ZSwgcGFyc2VJbnQocGFnZUlkeHNbaV0pKnNlbGYucGFnZVNpemUpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBwYWdlLndyaXRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH0sIChlcnIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJFUlJPUiBXcml0aW5nOiBcIitlcnIpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLmVycm9yID0gZXJyO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLl90cnlDbG9zZSgpO1xuICAgICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChzZWxmLndyaXRpbmcpIHtcbiAgICAgICAgICAgIFByb21pc2UuYWxsKG9wcykudGhlbiggKCkgPT4ge1xuICAgICAgICAgICAgICAgIHNlbGYud3JpdGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHNldEltbWVkaWF0ZShzZWxmLl90cmlnZ2VyV3JpdGUuYmluZChzZWxmKSk7XG4gICAgICAgICAgICAgICAgc2VsZi5fdHJ5Q2xvc2UoKTtcbiAgICAgICAgICAgICAgICBpZiAoc2VsZi5wZW5kaW5nTG9hZHMubGVuZ3RoPjApIHNldEltbWVkaWF0ZShzZWxmLl90cmlnZ2VyTG9hZC5iaW5kKHNlbGYpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgX2dldERpcnR5UGFnZSgpIHtcbiAgICAgICAgZm9yIChsZXQgcCBpbiB0aGlzLnBhZ2VzKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5wYWdlc1twXS5kaXJ0eSkgcmV0dXJuIHA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cblxuICAgIGFzeW5jIHdyaXRlKGJ1ZmYsIHBvcykge1xuICAgICAgICBpZiAoYnVmZi5ieXRlTGVuZ3RoID09IDApIHJldHVybjtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4vKlxuICAgICAgICBpZiAoYnVmZi5ieXRlTGVuZ3RoID4gc2VsZi5wYWdlU2l6ZSpzZWxmLm1heFBhZ2VzTG9hZGVkKjAuOCkge1xuICAgICAgICAgICAgY29uc3QgY2FjaGVTaXplID0gTWF0aC5mbG9vcihidWZmLmJ5dGVMZW5ndGggKiAxLjEpO1xuICAgICAgICAgICAgdGhpcy5tYXhQYWdlc0xvYWRlZCA9IE1hdGguZmxvb3IoIGNhY2hlU2l6ZSAvIHNlbGYucGFnZVNpemUpKzE7XG4gICAgICAgIH1cbiovXG4gICAgICAgIGlmICh0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIpIHBvcyA9IHNlbGYucG9zO1xuICAgICAgICBzZWxmLnBvcyA9IHBvcytidWZmLmJ5dGVMZW5ndGg7XG4gICAgICAgIGlmIChzZWxmLnRvdGFsU2l6ZSA8IHBvcyArIGJ1ZmYuYnl0ZUxlbmd0aCkgc2VsZi50b3RhbFNpemUgPSBwb3MgKyBidWZmLmJ5dGVMZW5ndGg7XG4gICAgICAgIGlmIChzZWxmLnBlbmRpbmdDbG9zZSlcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIldyaXRpbmcgYSBjbG9zaW5nIGZpbGVcIik7XG4gICAgICAgIGNvbnN0IGZpcnN0UGFnZSA9IE1hdGguZmxvb3IocG9zIC8gc2VsZi5wYWdlU2l6ZSk7XG4gICAgICAgIGNvbnN0IGxhc3RQYWdlID0gTWF0aC5mbG9vcigocG9zICsgYnVmZi5ieXRlTGVuZ3RoIC0xKSAvIHNlbGYucGFnZVNpemUpO1xuXG4gICAgICAgIGNvbnN0IHBhZ2VQcm9taXNlcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpPWZpcnN0UGFnZTsgaTw9bGFzdFBhZ2U7IGkrKykgcGFnZVByb21pc2VzLnB1c2goc2VsZi5fbG9hZFBhZ2UoaSkpO1xuICAgICAgICBzZWxmLl90cmlnZ2VyTG9hZCgpO1xuXG4gICAgICAgIGxldCBwID0gZmlyc3RQYWdlO1xuICAgICAgICBsZXQgbyA9IHBvcyAlIHNlbGYucGFnZVNpemU7XG4gICAgICAgIGxldCByID0gYnVmZi5ieXRlTGVuZ3RoO1xuICAgICAgICB3aGlsZSAocj4wKSB7XG4gICAgICAgICAgICBhd2FpdCBwYWdlUHJvbWlzZXNbcC1maXJzdFBhZ2VdO1xuICAgICAgICAgICAgY29uc3QgbCA9IChvK3IgPiBzZWxmLnBhZ2VTaXplKSA/IChzZWxmLnBhZ2VTaXplIC1vKSA6IHI7XG4gICAgICAgICAgICBjb25zdCBzcmNWaWV3ID0gYnVmZi5zbGljZSggYnVmZi5ieXRlTGVuZ3RoIC0gciwgYnVmZi5ieXRlTGVuZ3RoIC0gciArIGwpO1xuICAgICAgICAgICAgY29uc3QgZHN0VmlldyA9IG5ldyBVaW50OEFycmF5KHNlbGYucGFnZXNbcF0uYnVmZi5idWZmZXIsIG8sIGwpO1xuICAgICAgICAgICAgZHN0Vmlldy5zZXQoc3JjVmlldyk7XG4gICAgICAgICAgICBzZWxmLnBhZ2VzW3BdLmRpcnR5ID0gdHJ1ZTtcbiAgICAgICAgICAgIHNlbGYucGFnZXNbcF0ucGVuZGluZ09wcyAtLTtcbiAgICAgICAgICAgIHNlbGYucGFnZXNbcF0uc2l6ZSA9IE1hdGgubWF4KG8rbCwgc2VsZi5wYWdlc1twXS5zaXplKTtcbiAgICAgICAgICAgIGlmIChwPj1zZWxmLnRvdGFsUGFnZXMpIHtcbiAgICAgICAgICAgICAgICBzZWxmLnRvdGFsUGFnZXMgPSBwKzE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByID0gci1sO1xuICAgICAgICAgICAgcCArKztcbiAgICAgICAgICAgIG8gPSAwO1xuICAgICAgICAgICAgaWYgKCFzZWxmLndyaXRpbmcpIHNldEltbWVkaWF0ZShzZWxmLl90cmlnZ2VyV3JpdGUuYmluZChzZWxmKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyByZWFkKGxlbiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBsZXQgYnVmZiA9IG5ldyBVaW50OEFycmF5KGxlbik7XG4gICAgICAgIGF3YWl0IHNlbGYucmVhZFRvQnVmZmVyKGJ1ZmYsIDAsIGxlbiwgcG9zKTtcblxuICAgICAgICByZXR1cm4gYnVmZjtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkVG9CdWZmZXIoYnVmZkRzdCwgb2Zmc2V0LCBsZW4sIHBvcykge1xuICAgICAgICBpZiAobGVuID09IDApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgaWYgKGxlbiA+IHNlbGYucGFnZVNpemUqc2VsZi5tYXhQYWdlc0xvYWRlZCowLjgpIHtcbiAgICAgICAgICAgIGNvbnN0IGNhY2hlU2l6ZSA9IE1hdGguZmxvb3IobGVuICogMS4xKTtcbiAgICAgICAgICAgIHRoaXMubWF4UGFnZXNMb2FkZWQgPSBNYXRoLmZsb29yKCBjYWNoZVNpemUgLyBzZWxmLnBhZ2VTaXplKSsxO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIpIHBvcyA9IHNlbGYucG9zO1xuICAgICAgICBzZWxmLnBvcyA9IHBvcytsZW47XG4gICAgICAgIGlmIChzZWxmLnBlbmRpbmdDbG9zZSlcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJlYWRpbmcgYSBjbG9zaW5nIGZpbGVcIik7XG4gICAgICAgIGNvbnN0IGZpcnN0UGFnZSA9IE1hdGguZmxvb3IocG9zIC8gc2VsZi5wYWdlU2l6ZSk7XG4gICAgICAgIGNvbnN0IGxhc3RQYWdlID0gTWF0aC5mbG9vcigocG9zICsgbGVuIC0xKSAvIHNlbGYucGFnZVNpemUpO1xuXG4gICAgICAgIGNvbnN0IHBhZ2VQcm9taXNlcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpPWZpcnN0UGFnZTsgaTw9bGFzdFBhZ2U7IGkrKykgcGFnZVByb21pc2VzLnB1c2goc2VsZi5fbG9hZFBhZ2UoaSkpO1xuXG4gICAgICAgIHNlbGYuX3RyaWdnZXJMb2FkKCk7XG5cbiAgICAgICAgbGV0IHAgPSBmaXJzdFBhZ2U7XG4gICAgICAgIGxldCBvID0gcG9zICUgc2VsZi5wYWdlU2l6ZTtcbiAgICAgICAgLy8gUmVtYWluaW5nIGJ5dGVzIHRvIHJlYWRcbiAgICAgICAgbGV0IHIgPSBwb3MgKyBsZW4gPiBzZWxmLnRvdGFsU2l6ZSA/IGxlbiAtIChwb3MgKyBsZW4gLSBzZWxmLnRvdGFsU2l6ZSk6IGxlbjtcbiAgICAgICAgd2hpbGUgKHI+MCkge1xuICAgICAgICAgICAgYXdhaXQgcGFnZVByb21pc2VzW3AgLSBmaXJzdFBhZ2VdO1xuICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBBd2FpdCAocmVhZCk6IFwiLCBwKTtcblxuICAgICAgICAgICAgLy8gYnl0ZXMgdG8gY29weSBmcm9tIHRoaXMgcGFnZVxuICAgICAgICAgICAgY29uc3QgbCA9IChvK3IgPiBzZWxmLnBhZ2VTaXplKSA/IChzZWxmLnBhZ2VTaXplIC1vKSA6IHI7XG4gICAgICAgICAgICBjb25zdCBzcmNWaWV3ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5wYWdlc1twXS5idWZmLmJ1ZmZlciwgc2VsZi5wYWdlc1twXS5idWZmLmJ5dGVPZmZzZXQgKyBvLCBsKTtcbiAgICAgICAgICAgIGJ1ZmZEc3Quc2V0KHNyY1ZpZXcsIG9mZnNldCtsZW4tcik7XG4gICAgICAgICAgICBzZWxmLnBhZ2VzW3BdLnBlbmRpbmdPcHMgLS07XG5cbiAgICAgICAgICAgIHNlbGYuX19zdGF0dXNQYWdlKFwiQWZ0ZXIgT3AgZG9uZTogXCIsIHApO1xuXG4gICAgICAgICAgICByID0gci1sO1xuICAgICAgICAgICAgcCArKztcbiAgICAgICAgICAgIG8gPSAwO1xuICAgICAgICAgICAgaWYgKHNlbGYucGVuZGluZ0xvYWRzLmxlbmd0aD4wKSBzZXRJbW1lZGlhdGUoc2VsZi5fdHJpZ2dlckxvYWQuYmluZChzZWxmKSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnBvcyA9IHBvcyArIGxlbjtcblxuICAgIH1cblxuXG4gICAgX3RyeUNsb3NlKCkge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgaWYgKCFzZWxmLnBlbmRpbmdDbG9zZSkgcmV0dXJuO1xuICAgICAgICBpZiAoc2VsZi5lcnJvcikge1xuICAgICAgICAgICAgc2VsZi5wZW5kaW5nQ2xvc2VSZWplY3Qoc2VsZi5lcnJvcik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcCA9IHNlbGYuX2dldERpcnR5UGFnZSgpO1xuICAgICAgICBpZiAoKHA+PTApIHx8IChzZWxmLndyaXRpbmcpIHx8IChzZWxmLnJlYWRpbmcpIHx8IChzZWxmLnBlbmRpbmdMb2Fkcy5sZW5ndGg+MCkpIHJldHVybjtcbiAgICAgICAgc2VsZi5wZW5kaW5nQ2xvc2UoKTtcbiAgICB9XG5cbiAgICBjbG9zZSgpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmIChzZWxmLnBlbmRpbmdDbG9zZSlcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNsb3NpbmcgdGhlIGZpbGUgdHdpY2VcIik7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICBzZWxmLnBlbmRpbmdDbG9zZSA9IHJlc29sdmU7XG4gICAgICAgICAgICBzZWxmLnBlbmRpbmdDbG9zZVJlamVjdCA9IHJlamVjdDtcbiAgICAgICAgICAgIHNlbGYuX3RyeUNsb3NlKCk7XG4gICAgICAgIH0pLnRoZW4oKCk9PiB7XG4gICAgICAgICAgICBzZWxmLmZkLmNsb3NlKCk7XG4gICAgICAgIH0sIChlcnIpID0+IHtcbiAgICAgICAgICAgIHNlbGYuZmQuY2xvc2UoKTtcbiAgICAgICAgICAgIHRocm93IChlcnIpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBhc3luYyBkaXNjYXJkKCkge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgYXdhaXQgc2VsZi5jbG9zZSgpO1xuICAgICAgICBhd2FpdCBmcy5wcm9taXNlcy51bmxpbmsodGhpcy5maWxlTmFtZSk7XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGVVTEUzMih2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IHRtcEJ1ZmYzMiA9IG5ldyBVaW50OEFycmF5KDQpO1xuICAgICAgICBjb25zdCB0bXBCdWZmMzJ2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmYzMi5idWZmZXIpO1xuXG4gICAgICAgIHRtcEJ1ZmYzMnYuc2V0VWludDMyKDAsIHYsIHRydWUpO1xuXG4gICAgICAgIGF3YWl0IHNlbGYud3JpdGUodG1wQnVmZjMyLCBwb3MpO1xuICAgIH1cblxuICAgIGFzeW5jIHdyaXRlVUJFMzIodiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIGNvbnN0IHRtcEJ1ZmYzMiA9IG5ldyBVaW50OEFycmF5KDQpO1xuICAgICAgICBjb25zdCB0bXBCdWZmMzJ2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmYzMi5idWZmZXIpO1xuXG4gICAgICAgIHRtcEJ1ZmYzMnYuc2V0VWludDMyKDAsIHYsIGZhbHNlKTtcblxuICAgICAgICBhd2FpdCBzZWxmLndyaXRlKHRtcEJ1ZmYzMiwgcG9zKTtcbiAgICB9XG5cblxuICAgIGFzeW5jIHdyaXRlVUxFNjQodiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIGNvbnN0IHRtcEJ1ZmY2NCA9IG5ldyBVaW50OEFycmF5KDgpO1xuICAgICAgICBjb25zdCB0bXBCdWZmNjR2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmY2NC5idWZmZXIpO1xuXG4gICAgICAgIHRtcEJ1ZmY2NHYuc2V0VWludDMyKDAsIHYgJiAweEZGRkZGRkZGLCB0cnVlKTtcbiAgICAgICAgdG1wQnVmZjY0di5zZXRVaW50MzIoNCwgTWF0aC5mbG9vcih2IC8gMHgxMDAwMDAwMDApICwgdHJ1ZSk7XG5cbiAgICAgICAgYXdhaXQgc2VsZi53cml0ZSh0bXBCdWZmNjQsIHBvcyk7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFVMRTMyKHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgYiA9IGF3YWl0IHNlbGYucmVhZCg0LCBwb3MpO1xuXG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgVWludDMyQXJyYXkoYi5idWZmZXIpO1xuXG4gICAgICAgIHJldHVybiB2aWV3WzBdO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRVQkUzMihwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGIgPSBhd2FpdCBzZWxmLnJlYWQoNCwgcG9zKTtcblxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IERhdGFWaWV3KGIuYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gdmlldy5nZXRVaW50MzIoMCwgZmFsc2UpO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRVTEU2NChwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGIgPSBhd2FpdCBzZWxmLnJlYWQoOCwgcG9zKTtcblxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IFVpbnQzMkFycmF5KGIuYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gdmlld1sxXSAqIDB4MTAwMDAwMDAwICsgdmlld1swXTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkU3RyaW5nKHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICBpZiAoc2VsZi5wZW5kaW5nQ2xvc2UpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJlYWRpbmcgYSBjbG9zaW5nIGZpbGVcIik7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgY3VycmVudFBvc2l0aW9uID0gdHlwZW9mIHBvcyA9PSBcInVuZGVmaW5lZFwiID8gc2VsZi5wb3MgOiBwb3M7XG4gICAgICAgIGxldCBjdXJyZW50UGFnZSA9IE1hdGguZmxvb3IoY3VycmVudFBvc2l0aW9uIC8gc2VsZi5wYWdlU2l6ZSk7XG5cbiAgICAgICAgbGV0IGVuZE9mU3RyaW5nRm91bmQgPSBmYWxzZTtcbiAgICAgICAgbGV0IHN0ciA9IFwiXCI7XG5cbiAgICAgICAgd2hpbGUgKCFlbmRPZlN0cmluZ0ZvdW5kKSB7XG4gICAgICAgICAgICAvL1JlYWQgcGFnZVxuICAgICAgICAgICAgbGV0IHBhZ2VQcm9taXNlID0gc2VsZi5fbG9hZFBhZ2UoY3VycmVudFBhZ2UpO1xuICAgICAgICAgICAgc2VsZi5fdHJpZ2dlckxvYWQoKTtcbiAgICAgICAgICAgIGF3YWl0IHBhZ2VQcm9taXNlO1xuICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBBd2FpdCAocmVhZCk6IFwiLCBjdXJyZW50UGFnZSk7XG5cbiAgICAgICAgICAgIGxldCBvZmZzZXRPblBhZ2UgPSBjdXJyZW50UG9zaXRpb24gJSBzZWxmLnBhZ2VTaXplO1xuXG4gICAgICAgICAgICBjb25zdCBkYXRhQXJyYXkgPSBuZXcgVWludDhBcnJheShcbiAgICAgICAgICAgICAgICBzZWxmLnBhZ2VzW2N1cnJlbnRQYWdlXS5idWZmLmJ1ZmZlcixcbiAgICAgICAgICAgICAgICBzZWxmLnBhZ2VzW2N1cnJlbnRQYWdlXS5idWZmLmJ5dGVPZmZzZXQgKyBvZmZzZXRPblBhZ2UsXG4gICAgICAgICAgICAgICAgc2VsZi5wYWdlU2l6ZSAtIG9mZnNldE9uUGFnZVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgbGV0IGluZGV4RW5kT2ZTdHJpbmcgPSBkYXRhQXJyYXkuZmluZEluZGV4KGVsZW1lbnQgPT4gZWxlbWVudCA9PT0gMCk7XG4gICAgICAgICAgICBlbmRPZlN0cmluZ0ZvdW5kID0gaW5kZXhFbmRPZlN0cmluZyAhPT0gLTE7XG5cbiAgICAgICAgICAgIGlmIChlbmRPZlN0cmluZ0ZvdW5kKSB7XG4gICAgICAgICAgICAgICAgc3RyICs9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhQXJyYXkuc2xpY2UoMCwgaW5kZXhFbmRPZlN0cmluZykpO1xuICAgICAgICAgICAgICAgIHNlbGYucG9zID0gY3VycmVudFBhZ2UgKiB0aGlzLnBhZ2VTaXplICsgb2Zmc2V0T25QYWdlICsgaW5kZXhFbmRPZlN0cmluZyArIDE7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHN0ciArPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoZGF0YUFycmF5KTtcbiAgICAgICAgICAgICAgICBzZWxmLnBvcyA9IGN1cnJlbnRQYWdlICogdGhpcy5wYWdlU2l6ZSArIG9mZnNldE9uUGFnZSArIGRhdGFBcnJheS5sZW5ndGg7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNlbGYucGFnZXNbY3VycmVudFBhZ2VdLnBlbmRpbmdPcHMtLTtcbiAgICAgICAgICAgIHNlbGYuX19zdGF0dXNQYWdlKFwiQWZ0ZXIgT3AgZG9uZTogXCIsIGN1cnJlbnRQYWdlKTtcblxuICAgICAgICAgICAgY3VycmVudFBvc2l0aW9uID0gc2VsZi5wb3M7XG4gICAgICAgICAgICBjdXJyZW50UGFnZSsrO1xuXG4gICAgICAgICAgICBpZiAoc2VsZi5wZW5kaW5nTG9hZHMubGVuZ3RoID4gMCkgc2V0SW1tZWRpYXRlKHNlbGYuX3RyaWdnZXJMb2FkLmJpbmQoc2VsZikpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG59XG4iLCJleHBvcnQgZnVuY3Rpb24gY3JlYXRlTmV3KG8pIHtcbiAgICBjb25zdCBpbml0aWFsU2l6ZSA9IG8uaW5pdGlhbFNpemUgfHwgMTw8MjA7XG4gICAgY29uc3QgZmQgPSBuZXcgTWVtRmlsZSgpO1xuICAgIGZkLm8gPSBvO1xuICAgIGZkLm8uZGF0YSA9IG5ldyBVaW50OEFycmF5KGluaXRpYWxTaXplKTtcbiAgICBmZC5hbGxvY1NpemUgPSBpbml0aWFsU2l6ZTtcbiAgICBmZC50b3RhbFNpemUgPSAwO1xuICAgIGZkLnJlYWRPbmx5ID0gZmFsc2U7XG4gICAgZmQucG9zID0gMDtcbiAgICByZXR1cm4gZmQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWFkRXhpc3Rpbmcobykge1xuICAgIGNvbnN0IGZkID0gbmV3IE1lbUZpbGUoKTtcbiAgICBmZC5vID0gbztcbiAgICBmZC5hbGxvY1NpemUgPSBvLmRhdGEuYnl0ZUxlbmd0aDtcbiAgICBmZC50b3RhbFNpemUgPSBvLmRhdGEuYnl0ZUxlbmd0aDtcbiAgICBmZC5yZWFkT25seSA9IHRydWU7XG4gICAgZmQucG9zID0gMDtcbiAgICByZXR1cm4gZmQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWFkV3JpdGVFeGlzdGluZyhvKSB7XG4gICAgY29uc3QgZmQgPSBuZXcgTWVtRmlsZSgpO1xuICAgIGZkLm8gPSBvO1xuICAgIGZkLmFsbG9jU2l6ZSA9IG8uZGF0YS5ieXRlTGVuZ3RoO1xuICAgIGZkLnRvdGFsU2l6ZSA9IG8uZGF0YS5ieXRlTGVuZ3RoO1xuICAgIGZkLnJlYWRPbmx5ID0gZmFsc2U7XG4gICAgZmQucG9zID0gMDtcbiAgICByZXR1cm4gZmQ7XG59XG5cbmNvbnN0IHRtcEJ1ZmYzMiA9IG5ldyBVaW50OEFycmF5KDQpO1xuY29uc3QgdG1wQnVmZjMydiA9IG5ldyBEYXRhVmlldyh0bXBCdWZmMzIuYnVmZmVyKTtcbmNvbnN0IHRtcEJ1ZmY2NCA9IG5ldyBVaW50OEFycmF5KDgpO1xuY29uc3QgdG1wQnVmZjY0diA9IG5ldyBEYXRhVmlldyh0bXBCdWZmNjQuYnVmZmVyKTtcblxuY2xhc3MgTWVtRmlsZSB7XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5wYWdlU2l6ZSA9IDEgPDwgMTQ7ICAvLyBmb3IgY29tcGF0aWJpbGl0eVxuICAgIH1cblxuICAgIF9yZXNpemVJZk5lZWRlZChuZXdMZW4pIHtcbiAgICAgICAgaWYgKG5ld0xlbiA+IHRoaXMuYWxsb2NTaXplKSB7XG4gICAgICAgICAgICBjb25zdCBuZXdBbGxvY1NpemUgPSBNYXRoLm1heChcbiAgICAgICAgICAgICAgICB0aGlzLmFsbG9jU2l6ZSArICgxIDw8IDIwKSxcbiAgICAgICAgICAgICAgICBNYXRoLmZsb29yKHRoaXMuYWxsb2NTaXplICogMS4xKSxcbiAgICAgICAgICAgICAgICBuZXdMZW5cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCBuZXdEYXRhID0gbmV3IFVpbnQ4QXJyYXkobmV3QWxsb2NTaXplKTtcbiAgICAgICAgICAgIG5ld0RhdGEuc2V0KHRoaXMuby5kYXRhKTtcbiAgICAgICAgICAgIHRoaXMuby5kYXRhID0gbmV3RGF0YTtcbiAgICAgICAgICAgIHRoaXMuYWxsb2NTaXplID0gbmV3QWxsb2NTaXplO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGUoYnVmZiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPXRoaXM7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIpIHBvcyA9IHNlbGYucG9zO1xuICAgICAgICBpZiAodGhpcy5yZWFkT25seSkgdGhyb3cgbmV3IEVycm9yKFwiV3JpdGluZyBhIHJlYWQgb25seSBmaWxlXCIpO1xuXG4gICAgICAgIHRoaXMuX3Jlc2l6ZUlmTmVlZGVkKHBvcyArIGJ1ZmYuYnl0ZUxlbmd0aCk7XG5cbiAgICAgICAgdGhpcy5vLmRhdGEuc2V0KGJ1ZmYuc2xpY2UoKSwgcG9zKTtcblxuICAgICAgICBpZiAocG9zICsgYnVmZi5ieXRlTGVuZ3RoID4gdGhpcy50b3RhbFNpemUpIHRoaXMudG90YWxTaXplID0gcG9zICsgYnVmZi5ieXRlTGVuZ3RoO1xuXG4gICAgICAgIHRoaXMucG9zID0gcG9zICsgYnVmZi5ieXRlTGVuZ3RoO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRUb0J1ZmZlcihidWZmRGVzdCwgb2Zmc2V0LCBsZW4sIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgaWYgKHR5cGVvZiBwb3MgPT0gXCJ1bmRlZmluZWRcIikgcG9zID0gc2VsZi5wb3M7XG4gICAgICAgIGlmICh0aGlzLnJlYWRPbmx5KSB7XG4gICAgICAgICAgICBpZiAocG9zICsgbGVuID4gdGhpcy50b3RhbFNpemUpIHRocm93IG5ldyBFcnJvcihcIlJlYWRpbmcgb3V0IG9mIGJvdW5kc1wiKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLl9yZXNpemVJZk5lZWRlZChwb3MgKyBsZW4pO1xuXG4gICAgICAgIGNvbnN0IGJ1ZmZTcmMgPSBuZXcgVWludDhBcnJheSh0aGlzLm8uZGF0YS5idWZmZXIsIHRoaXMuby5kYXRhLmJ5dGVPZmZzZXQgKyBwb3MsIGxlbik7XG5cbiAgICAgICAgYnVmZkRlc3Quc2V0KGJ1ZmZTcmMsIG9mZnNldCk7XG5cbiAgICAgICAgdGhpcy5wb3MgPSBwb3MgKyBsZW47XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZChsZW4sIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkobGVuKTtcbiAgICAgICAgYXdhaXQgc2VsZi5yZWFkVG9CdWZmZXIoYnVmZiwgMCwgbGVuLCBwb3MpO1xuXG4gICAgICAgIHJldHVybiBidWZmO1xuICAgIH1cblxuICAgIGNsb3NlKCkge1xuICAgICAgICBpZiAodGhpcy5vLmRhdGEuYnl0ZUxlbmd0aCAhPSB0aGlzLnRvdGFsU2l6ZSkge1xuICAgICAgICAgICAgdGhpcy5vLmRhdGEgPSB0aGlzLm8uZGF0YS5zbGljZSgwLCB0aGlzLnRvdGFsU2l6ZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBkaXNjYXJkKCkge1xuICAgIH1cblxuXG4gICAgYXN5bmMgd3JpdGVVTEUzMih2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgdHJ1ZSk7XG5cbiAgICAgICAgYXdhaXQgc2VsZi53cml0ZSh0bXBCdWZmMzIsIHBvcyk7XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGVVQkUzMih2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgZmFsc2UpO1xuXG4gICAgICAgIGF3YWl0IHNlbGYud3JpdGUodG1wQnVmZjMyLCBwb3MpO1xuICAgIH1cblxuXG4gICAgYXN5bmMgd3JpdGVVTEU2NCh2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdG1wQnVmZjY0di5zZXRVaW50MzIoMCwgdiAmIDB4RkZGRkZGRkYsIHRydWUpO1xuICAgICAgICB0bXBCdWZmNjR2LnNldFVpbnQzMig0LCBNYXRoLmZsb29yKHYgLyAweDEwMDAwMDAwMCkgLCB0cnVlKTtcblxuICAgICAgICBhd2FpdCBzZWxmLndyaXRlKHRtcEJ1ZmY2NCwgcG9zKTtcbiAgICB9XG5cblxuICAgIGFzeW5jIHJlYWRVTEUzMihwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGIgPSBhd2FpdCBzZWxmLnJlYWQoNCwgcG9zKTtcblxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IFVpbnQzMkFycmF5KGIuYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gdmlld1swXTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkVUJFMzIocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgc2VsZi5yZWFkKDQsIHBvcyk7XG5cbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhiLmJ1ZmZlcik7XG5cbiAgICAgICAgcmV0dXJuIHZpZXcuZ2V0VWludDMyKDAsIGZhbHNlKTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkVUxFNjQocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgc2VsZi5yZWFkKDgsIHBvcyk7XG5cbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBVaW50MzJBcnJheShiLmJ1ZmZlcik7XG5cbiAgICAgICAgcmV0dXJuIHZpZXdbMV0gKiAweDEwMDAwMDAwMCArIHZpZXdbMF07XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFN0cmluZyhwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgbGV0IGN1cnJlbnRQb3NpdGlvbiA9IHR5cGVvZiBwb3MgPT0gXCJ1bmRlZmluZWRcIiA/IHNlbGYucG9zIDogcG9zO1xuXG4gICAgICAgIGlmIChjdXJyZW50UG9zaXRpb24gPiB0aGlzLnRvdGFsU2l6ZSkge1xuICAgICAgICAgICAgaWYgKHRoaXMucmVhZE9ubHkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJSZWFkaW5nIG91dCBvZiBib3VuZHNcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLl9yZXNpemVJZk5lZWRlZChwb3MpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGRhdGFBcnJheSA9IG5ldyBVaW50OEFycmF5KFxuICAgICAgICAgICAgc2VsZi5vLmRhdGEuYnVmZmVyLFxuICAgICAgICAgICAgY3VycmVudFBvc2l0aW9uLFxuICAgICAgICAgICAgdGhpcy50b3RhbFNpemUgLSBjdXJyZW50UG9zaXRpb25cbiAgICAgICAgKTtcblxuICAgICAgICBsZXQgaW5kZXhFbmRPZlN0cmluZyA9IGRhdGFBcnJheS5maW5kSW5kZXgoZWxlbWVudCA9PiBlbGVtZW50ID09PSAwKTtcbiAgICAgICAgbGV0IGVuZE9mU3RyaW5nRm91bmQgPSBpbmRleEVuZE9mU3RyaW5nICE9PSAtMTtcblxuICAgICAgICBsZXQgc3RyID0gXCJcIjtcbiAgICAgICAgaWYgKGVuZE9mU3RyaW5nRm91bmQpIHtcbiAgICAgICAgICAgIHN0ciA9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhQXJyYXkuc2xpY2UoMCwgaW5kZXhFbmRPZlN0cmluZykpO1xuICAgICAgICAgICAgc2VsZi5wb3MgPSBjdXJyZW50UG9zaXRpb24gKyBpbmRleEVuZE9mU3RyaW5nICsgMTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHNlbGYucG9zID0gY3VycmVudFBvc2l0aW9uO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdHI7XG4gICAgfVxufVxuIiwiY29uc3QgUEFHRV9TSVpFID0gMTw8MjI7XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVOZXcobykge1xuICAgIGNvbnN0IGluaXRpYWxTaXplID0gby5pbml0aWFsU2l6ZSB8fCAwO1xuICAgIGNvbnN0IGZkID0gbmV3IEJpZ01lbUZpbGUoKTtcbiAgICBmZC5vID0gbztcbiAgICBjb25zdCBuUGFnZXMgPSBpbml0aWFsU2l6ZSA/IE1hdGguZmxvb3IoKGluaXRpYWxTaXplIC0gMSkgLyBQQUdFX1NJWkUpKzEgOiAwO1xuICAgIGZkLm8uZGF0YSA9IFtdO1xuICAgIGZvciAobGV0IGk9MDsgaTxuUGFnZXMtMTsgaSsrKSB7XG4gICAgICAgIGZkLm8uZGF0YS5wdXNoKCBuZXcgVWludDhBcnJheShQQUdFX1NJWkUpKTtcbiAgICB9XG4gICAgaWYgKG5QYWdlcykgZmQuby5kYXRhLnB1c2goIG5ldyBVaW50OEFycmF5KGluaXRpYWxTaXplIC0gUEFHRV9TSVpFKihuUGFnZXMtMSkpKTtcbiAgICBmZC50b3RhbFNpemUgPSAwO1xuICAgIGZkLnJlYWRPbmx5ID0gZmFsc2U7XG4gICAgZmQucG9zID0gMDtcbiAgICByZXR1cm4gZmQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWFkRXhpc3Rpbmcobykge1xuICAgIGNvbnN0IGZkID0gbmV3IEJpZ01lbUZpbGUoKTtcbiAgICBmZC5vID0gbztcbiAgICBmZC50b3RhbFNpemUgPSAoby5kYXRhLmxlbmd0aC0xKSogUEFHRV9TSVpFICsgby5kYXRhW28uZGF0YS5sZW5ndGgtMV0uYnl0ZUxlbmd0aDtcbiAgICBmZC5yZWFkT25seSA9IHRydWU7XG4gICAgZmQucG9zID0gMDtcbiAgICByZXR1cm4gZmQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWFkV3JpdGVFeGlzdGluZyhvKSB7XG4gICAgY29uc3QgZmQgPSBuZXcgQmlnTWVtRmlsZSgpO1xuICAgIGZkLm8gPSBvO1xuICAgIGZkLnRvdGFsU2l6ZSA9IChvLmRhdGEubGVuZ3RoLTEpKiBQQUdFX1NJWkUgKyBvLmRhdGFbby5kYXRhLmxlbmd0aC0xXS5ieXRlTGVuZ3RoO1xuICAgIGZkLnJlYWRPbmx5ID0gZmFsc2U7XG4gICAgZmQucG9zID0gMDtcbiAgICByZXR1cm4gZmQ7XG59XG5cbmNvbnN0IHRtcEJ1ZmYzMiA9IG5ldyBVaW50OEFycmF5KDQpO1xuY29uc3QgdG1wQnVmZjMydiA9IG5ldyBEYXRhVmlldyh0bXBCdWZmMzIuYnVmZmVyKTtcbmNvbnN0IHRtcEJ1ZmY2NCA9IG5ldyBVaW50OEFycmF5KDgpO1xuY29uc3QgdG1wQnVmZjY0diA9IG5ldyBEYXRhVmlldyh0bXBCdWZmNjQuYnVmZmVyKTtcblxuY2xhc3MgQmlnTWVtRmlsZSB7XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5wYWdlU2l6ZSA9IDEgPDwgMTQ7ICAvLyBmb3IgY29tcGF0aWJpbGl0eVxuICAgIH1cblxuICAgIF9yZXNpemVJZk5lZWRlZChuZXdMZW4pIHtcblxuICAgICAgICBpZiAobmV3TGVuIDw9IHRoaXMudG90YWxTaXplKSByZXR1cm47XG5cbiAgICAgICAgaWYgKHRoaXMucmVhZE9ubHkpIHRocm93IG5ldyBFcnJvcihcIlJlYWRpbmcgb3V0IG9mIGZpbGUgYm91bmRzXCIpO1xuXG4gICAgICAgIGNvbnN0IG5QYWdlcyA9IE1hdGguZmxvb3IoKG5ld0xlbiAtIDEpIC8gUEFHRV9TSVpFKSsxO1xuICAgICAgICBmb3IgKGxldCBpPSBNYXRoLm1heCh0aGlzLm8uZGF0YS5sZW5ndGgtMSwgMCk7IGk8blBhZ2VzOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IG5ld1NpemUgPSBpPG5QYWdlcy0xID8gUEFHRV9TSVpFIDogbmV3TGVuIC0gKG5QYWdlcy0xKSpQQUdFX1NJWkU7XG4gICAgICAgICAgICBjb25zdCBwID0gbmV3IFVpbnQ4QXJyYXkobmV3U2l6ZSk7XG4gICAgICAgICAgICBpZiAoaSA9PSB0aGlzLm8uZGF0YS5sZW5ndGgtMSkgcC5zZXQodGhpcy5vLmRhdGFbaV0pO1xuICAgICAgICAgICAgdGhpcy5vLmRhdGFbaV0gPSBwO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudG90YWxTaXplID0gbmV3TGVuO1xuICAgIH1cblxuICAgIGFzeW5jIHdyaXRlKGJ1ZmYsIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID10aGlzO1xuICAgICAgICBpZiAodHlwZW9mIHBvcyA9PSBcInVuZGVmaW5lZFwiKSBwb3MgPSBzZWxmLnBvcztcbiAgICAgICAgaWYgKHRoaXMucmVhZE9ubHkpIHRocm93IG5ldyBFcnJvcihcIldyaXRpbmcgYSByZWFkIG9ubHkgZmlsZVwiKTtcblxuICAgICAgICB0aGlzLl9yZXNpemVJZk5lZWRlZChwb3MgKyBidWZmLmJ5dGVMZW5ndGgpO1xuXG4gICAgICAgIGNvbnN0IGZpcnN0UGFnZSA9IE1hdGguZmxvb3IocG9zIC8gUEFHRV9TSVpFKTtcblxuICAgICAgICBsZXQgcCA9IGZpcnN0UGFnZTtcbiAgICAgICAgbGV0IG8gPSBwb3MgJSBQQUdFX1NJWkU7XG4gICAgICAgIGxldCByID0gYnVmZi5ieXRlTGVuZ3RoO1xuICAgICAgICB3aGlsZSAocj4wKSB7XG4gICAgICAgICAgICBjb25zdCBsID0gKG8rciA+IFBBR0VfU0laRSkgPyAoUEFHRV9TSVpFIC1vKSA6IHI7XG4gICAgICAgICAgICBjb25zdCBzcmNWaWV3ID0gYnVmZi5zbGljZShidWZmLmJ5dGVMZW5ndGggLSByLCBidWZmLmJ5dGVMZW5ndGggLSByICsgbCk7XG4gICAgICAgICAgICBjb25zdCBkc3RWaWV3ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5vLmRhdGFbcF0uYnVmZmVyLCBvLCBsKTtcbiAgICAgICAgICAgIGRzdFZpZXcuc2V0KHNyY1ZpZXcpO1xuICAgICAgICAgICAgciA9IHItbDtcbiAgICAgICAgICAgIHAgKys7XG4gICAgICAgICAgICBvID0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucG9zID0gcG9zICsgYnVmZi5ieXRlTGVuZ3RoO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRUb0J1ZmZlcihidWZmRHN0LCBvZmZzZXQsIGxlbiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBpZiAodHlwZW9mIHBvcyA9PSBcInVuZGVmaW5lZFwiKSBwb3MgPSBzZWxmLnBvcztcbiAgICAgICAgaWYgKHRoaXMucmVhZE9ubHkpIHtcbiAgICAgICAgICAgIGlmIChwb3MgKyBsZW4gPiB0aGlzLnRvdGFsU2l6ZSkgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBvdXQgb2YgYm91bmRzXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3Jlc2l6ZUlmTmVlZGVkKHBvcyArIGxlbik7XG5cbiAgICAgICAgY29uc3QgZmlyc3RQYWdlID0gTWF0aC5mbG9vcihwb3MgLyBQQUdFX1NJWkUpO1xuXG4gICAgICAgIGxldCBwID0gZmlyc3RQYWdlO1xuICAgICAgICBsZXQgbyA9IHBvcyAlIFBBR0VfU0laRTtcbiAgICAgICAgLy8gUmVtYWluaW5nIGJ5dGVzIHRvIHJlYWRcbiAgICAgICAgbGV0IHIgPSBsZW47XG4gICAgICAgIHdoaWxlIChyPjApIHtcbiAgICAgICAgICAgIC8vIGJ5dGVzIHRvIGNvcHkgZnJvbSB0aGlzIHBhZ2VcbiAgICAgICAgICAgIGNvbnN0IGwgPSAobytyID4gUEFHRV9TSVpFKSA/IChQQUdFX1NJWkUgLW8pIDogcjtcbiAgICAgICAgICAgIGNvbnN0IHNyY1ZpZXcgPSBuZXcgVWludDhBcnJheShzZWxmLm8uZGF0YVtwXS5idWZmZXIsIG8sIGwpO1xuICAgICAgICAgICAgYnVmZkRzdC5zZXQoc3JjVmlldywgb2Zmc2V0K2xlbi1yKTtcbiAgICAgICAgICAgIHIgPSByLWw7XG4gICAgICAgICAgICBwICsrO1xuICAgICAgICAgICAgbyA9IDA7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnBvcyA9IHBvcyArIGxlbjtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkKGxlbiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkobGVuKTtcblxuICAgICAgICBhd2FpdCBzZWxmLnJlYWRUb0J1ZmZlcihidWZmLCAwLCBsZW4sIHBvcyk7XG5cbiAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgfVxuXG4gICAgY2xvc2UoKSB7XG4gICAgfVxuXG4gICAgYXN5bmMgZGlzY2FyZCgpIHtcbiAgICB9XG5cblxuICAgIGFzeW5jIHdyaXRlVUxFMzIodiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIHRtcEJ1ZmYzMnYuc2V0VWludDMyKDAsIHYsIHRydWUpO1xuXG4gICAgICAgIGF3YWl0IHNlbGYud3JpdGUodG1wQnVmZjMyLCBwb3MpO1xuICAgIH1cblxuICAgIGFzeW5jIHdyaXRlVUJFMzIodiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIHRtcEJ1ZmYzMnYuc2V0VWludDMyKDAsIHYsIGZhbHNlKTtcblxuICAgICAgICBhd2FpdCBzZWxmLndyaXRlKHRtcEJ1ZmYzMiwgcG9zKTtcbiAgICB9XG5cblxuICAgIGFzeW5jIHdyaXRlVUxFNjQodiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIHRtcEJ1ZmY2NHYuc2V0VWludDMyKDAsIHYgJiAweEZGRkZGRkZGLCB0cnVlKTtcbiAgICAgICAgdG1wQnVmZjY0di5zZXRVaW50MzIoNCwgTWF0aC5mbG9vcih2IC8gMHgxMDAwMDAwMDApICwgdHJ1ZSk7XG5cbiAgICAgICAgYXdhaXQgc2VsZi53cml0ZSh0bXBCdWZmNjQsIHBvcyk7XG4gICAgfVxuXG5cbiAgICBhc3luYyByZWFkVUxFMzIocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgc2VsZi5yZWFkKDQsIHBvcyk7XG5cbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBVaW50MzJBcnJheShiLmJ1ZmZlcik7XG5cbiAgICAgICAgcmV0dXJuIHZpZXdbMF07XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFVCRTMyKHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgYiA9IGF3YWl0IHNlbGYucmVhZCg0LCBwb3MpO1xuXG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgRGF0YVZpZXcoYi5idWZmZXIpO1xuXG4gICAgICAgIHJldHVybiB2aWV3LmdldFVpbnQzMigwLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFVMRTY0KHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgYiA9IGF3YWl0IHNlbGYucmVhZCg4LCBwb3MpO1xuXG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgVWludDMyQXJyYXkoYi5idWZmZXIpO1xuXG4gICAgICAgIHJldHVybiB2aWV3WzFdICogMHgxMDAwMDAwMDAgKyB2aWV3WzBdO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRTdHJpbmcocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBmaXhlZFNpemUgPSAyMDQ4O1xuXG4gICAgICAgIGxldCBjdXJyZW50UG9zaXRpb24gPSB0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIgPyBzZWxmLnBvcyA6IHBvcztcblxuICAgICAgICBpZiAoY3VycmVudFBvc2l0aW9uID4gdGhpcy50b3RhbFNpemUpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnJlYWRPbmx5KSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBvdXQgb2YgYm91bmRzXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5fcmVzaXplSWZOZWVkZWQocG9zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBlbmRPZlN0cmluZ0ZvdW5kID0gZmFsc2U7XG4gICAgICAgIGxldCBzdHIgPSBcIlwiO1xuXG4gICAgICAgIHdoaWxlICghZW5kT2ZTdHJpbmdGb3VuZCkge1xuICAgICAgICAgICAgbGV0IGN1cnJlbnRQYWdlID0gTWF0aC5mbG9vcihjdXJyZW50UG9zaXRpb24gLyBQQUdFX1NJWkUpO1xuICAgICAgICAgICAgbGV0IG9mZnNldE9uUGFnZSA9IGN1cnJlbnRQb3NpdGlvbiAlIFBBR0VfU0laRTtcblxuICAgICAgICAgICAgaWYgKHNlbGYuby5kYXRhW2N1cnJlbnRQYWdlXSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRVJST1JcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCByZWFkTGVuZ3RoID0gTWF0aC5taW4oZml4ZWRTaXplLCBzZWxmLm8uZGF0YVtjdXJyZW50UGFnZV0ubGVuZ3RoIC0gb2Zmc2V0T25QYWdlKTtcbiAgICAgICAgICAgIGNvbnN0IGRhdGFBcnJheSA9IG5ldyBVaW50OEFycmF5KHNlbGYuby5kYXRhW2N1cnJlbnRQYWdlXS5idWZmZXIsIG9mZnNldE9uUGFnZSwgcmVhZExlbmd0aCk7XG5cbiAgICAgICAgICAgIGxldCBpbmRleEVuZE9mU3RyaW5nID0gZGF0YUFycmF5LmZpbmRJbmRleChlbGVtZW50ID0+IGVsZW1lbnQgPT09IDApO1xuICAgICAgICAgICAgZW5kT2ZTdHJpbmdGb3VuZCA9IGluZGV4RW5kT2ZTdHJpbmcgIT09IC0xO1xuXG4gICAgICAgICAgICBpZiAoZW5kT2ZTdHJpbmdGb3VuZCkge1xuICAgICAgICAgICAgICAgIHN0ciArPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoZGF0YUFycmF5LnNsaWNlKDAsIGluZGV4RW5kT2ZTdHJpbmcpKTtcbiAgICAgICAgICAgICAgICBzZWxmLnBvcyA9IGN1cnJlbnRQYWdlICogUEFHRV9TSVpFICsgb2Zmc2V0T25QYWdlICsgaW5kZXhFbmRPZlN0cmluZyArIDE7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHN0ciArPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoZGF0YUFycmF5KTtcbiAgICAgICAgICAgICAgICBzZWxmLnBvcyA9IGN1cnJlbnRQYWdlICogUEFHRV9TSVpFICsgb2Zmc2V0T25QYWdlICsgZGF0YUFycmF5Lmxlbmd0aDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY3VycmVudFBvc2l0aW9uID0gc2VsZi5wb3M7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG59XG4iLCIvKiBnbG9iYWwgZmV0Y2ggKi9cbmltcG9ydCB7IG9wZW4gfSBmcm9tIFwiLi9vc2ZpbGUuanNcIjtcbmltcG9ydCAqIGFzIG1lbUZpbGUgZnJvbSBcIi4vbWVtZmlsZS5qc1wiO1xuaW1wb3J0ICogYXMgYmlnTWVtRmlsZSBmcm9tIFwiLi9iaWdtZW1maWxlLmpzXCI7XG5pbXBvcnQgeyBPX1RSVU5DLCBPX0NSRUFULCBPX1JEV1IsIE9fRVhDTCwgT19SRE9OTFkgfSBmcm9tIFwiY29uc3RhbnRzXCI7XG5cbmNvbnN0IERFRkFVTFRfQ0FDSEVfU0laRSA9ICgxIDw8IDE2KTtcbmNvbnN0IERFRkFVTFRfUEFHRV9TSVpFID0gKDEgPDwgMTMpO1xuXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVPdmVycmlkZShvLCBiLCBjKSB7XG4gICAgaWYgKHR5cGVvZiBvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG8gPSB7XG4gICAgICAgICAgICB0eXBlOiBcImZpbGVcIixcbiAgICAgICAgICAgIGZpbGVOYW1lOiBvLFxuICAgICAgICAgICAgY2FjaGVTaXplOiBiIHx8IERFRkFVTFRfQ0FDSEVfU0laRSxcbiAgICAgICAgICAgIHBhZ2VTaXplOiBjIHx8IERFRkFVTFRfUEFHRV9TSVpFXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChvLnR5cGUgPT0gXCJmaWxlXCIpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IG9wZW4oby5maWxlTmFtZSwgT19UUlVOQyB8IE9fQ1JFQVQgfCBPX1JEV1IsIG8uY2FjaGVTaXplLCBvLnBhZ2VTaXplKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcIm1lbVwiKSB7XG4gICAgICAgIHJldHVybiBtZW1GaWxlLmNyZWF0ZU5ldyhvKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcImJpZ01lbVwiKSB7XG4gICAgICAgIHJldHVybiBiaWdNZW1GaWxlLmNyZWF0ZU5ldyhvKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIEZhc3RGaWxlIHR5cGU6IFwiK28udHlwZSk7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTm9PdmVycmlkZShvLCBiLCBjKSB7XG4gICAgaWYgKHR5cGVvZiBvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG8gPSB7XG4gICAgICAgICAgICB0eXBlOiBcImZpbGVcIixcbiAgICAgICAgICAgIGZpbGVOYW1lOiBvLFxuICAgICAgICAgICAgY2FjaGVTaXplOiBiIHx8IERFRkFVTFRfQ0FDSEVfU0laRSxcbiAgICAgICAgICAgIHBhZ2VTaXplOiBjIHx8IERFRkFVTFRfUEFHRV9TSVpFXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChvLnR5cGUgPT0gXCJmaWxlXCIpIHtcbiAgICAgICAgcmV0dXJuIG9wZW4oby5maWxlTmFtZSwgT19UUlVOQyB8IE9fQ1JFQVQgfCBPX1JEV1IgfCBPX0VYQ0wsIG8uY2FjaGVTaXplLCBvLnBhZ2VTaXplKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcIm1lbVwiKSB7XG4gICAgICAgIHJldHVybiBtZW1GaWxlLmNyZWF0ZU5ldyhvKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcImJpZ01lbVwiKSB7XG4gICAgICAgIHJldHVybiBiaWdNZW1GaWxlLmNyZWF0ZU5ldyhvKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIEZhc3RGaWxlIHR5cGU6IFwiK28udHlwZSk7XG4gICAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZEV4aXN0aW5nKG8sIGIsIGMpIHtcbiAgICBpZiAobyBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHtcbiAgICAgICAgbyA9IHtcbiAgICAgICAgICAgIHR5cGU6IFwibWVtXCIsXG4gICAgICAgICAgICBkYXRhOiBvXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChwcm9jZXNzLmJyb3dzZXIpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICBjb25zdCBidWZmID0gYXdhaXQgZmV0Y2gobykudGhlbiggZnVuY3Rpb24ocmVzKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcy5hcnJheUJ1ZmZlcigpO1xuICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbiAoYWIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkoYWIpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBvID0ge1xuICAgICAgICAgICAgICAgIHR5cGU6IFwibWVtXCIsXG4gICAgICAgICAgICAgICAgZGF0YTogYnVmZlxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICh0eXBlb2YgbyA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgbyA9IHtcbiAgICAgICAgICAgICAgICB0eXBlOiBcImZpbGVcIixcbiAgICAgICAgICAgICAgICBmaWxlTmFtZTogbyxcbiAgICAgICAgICAgICAgICBjYWNoZVNpemU6IGIgfHwgREVGQVVMVF9DQUNIRV9TSVpFLFxuICAgICAgICAgICAgICAgIHBhZ2VTaXplOiBjIHx8IERFRkFVTFRfUEFHRV9TSVpFXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChvLnR5cGUgPT0gXCJmaWxlXCIpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IG9wZW4oby5maWxlTmFtZSwgT19SRE9OTFksIG8uY2FjaGVTaXplLCBvLnBhZ2VTaXplKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcIm1lbVwiKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBtZW1GaWxlLnJlYWRFeGlzdGluZyhvKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcImJpZ01lbVwiKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBiaWdNZW1GaWxlLnJlYWRFeGlzdGluZyhvKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIEZhc3RGaWxlIHR5cGU6IFwiK28udHlwZSk7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVhZFdyaXRlRXhpc3RpbmcobywgYiwgYykge1xuICAgIGlmICh0eXBlb2YgbyA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICBvID0ge1xuICAgICAgICAgICAgdHlwZTogXCJmaWxlXCIsXG4gICAgICAgICAgICBmaWxlTmFtZTogbyxcbiAgICAgICAgICAgIGNhY2hlU2l6ZTogYiB8fCBERUZBVUxUX0NBQ0hFX1NJWkUsXG4gICAgICAgICAgICBwYWdlU2l6ZTogYyB8fCBERUZBVUxUX1BBR0VfU0laRVxuICAgICAgICB9O1xuICAgIH1cbiAgICBpZiAoby50eXBlID09IFwiZmlsZVwiKSB7XG4gICAgICAgIHJldHVybiBvcGVuKG8uZmlsZU5hbWUsIE9fQ1JFQVQgfCBPX1JEV1IsIG8uY2FjaGVTaXplLCBvLnBhZ2VTaXplKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcIm1lbVwiKSB7XG4gICAgICAgIHJldHVybiBtZW1GaWxlLnJlYWRXcml0ZUV4aXN0aW5nKG8pO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwiYmlnTWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIGJpZ01lbUZpbGUucmVhZFdyaXRlRXhpc3Rpbmcobyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBGYXN0RmlsZSB0eXBlOiBcIitvLnR5cGUpO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRXcml0ZUV4aXN0aW5nT3JDcmVhdGUobywgYiwgYykge1xuICAgIGlmICh0eXBlb2YgbyA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICBvID0ge1xuICAgICAgICAgICAgdHlwZTogXCJmaWxlXCIsXG4gICAgICAgICAgICBmaWxlTmFtZTogbyxcbiAgICAgICAgICAgIGNhY2hlU2l6ZTogYiB8fCBERUZBVUxUX0NBQ0hFX1NJWkUsXG4gICAgICAgICAgICBwYWdlU2l6ZTogYyB8fCBERUZBVUxUX1BBR0VfU0laRVxuICAgICAgICB9O1xuICAgIH1cbiAgICBpZiAoby50eXBlID09IFwiZmlsZVwiKSB7XG4gICAgICAgIHJldHVybiBvcGVuKG8uZmlsZU5hbWUsIE9fQ1JFQVQgfCBPX1JEV1IgfCBPX0VYQ0wsIG8uY2FjaGVTaXplKTtcbiAgICB9IGVsc2UgaWYgKG8udHlwZSA9PSBcIm1lbVwiKSB7XG4gICAgICAgIHJldHVybiBtZW1GaWxlLnJlYWRXcml0ZUV4aXN0aW5nKG8pO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwiYmlnTWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIGJpZ01lbUZpbGUucmVhZFdyaXRlRXhpc3Rpbmcobyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBGYXN0RmlsZSB0eXBlOiBcIitvLnR5cGUpO1xuICAgIH1cbn1cbiIsIi8qXG5cbkNvcHlyaWdodCAyMDIwIDBLSU1TIGFzc29jaWF0aW9uLlxuXG5MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xueW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG5cbiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcblxuVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG5TZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG5saW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cblxuKi9cblxuZXhwb3J0IGZ1bmN0aW9uIGZsYXRBcnJheShhKSB7XG4gICAgbGV0IHJlcyA9IFtdO1xuICAgIGZpbGxBcnJheShyZXMsIGEpO1xuICAgIHJldHVybiByZXM7XG5cbiAgICBmdW5jdGlvbiBmaWxsQXJyYXkocmVzLCBhKSB7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGEpKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBmaWxsQXJyYXkocmVzLCBhW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlcy5wdXNoKGEpO1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vLyBSZWYgaHR0cHM6Ly9naXRodWIuY29tL2lkZW4zL2NpcmNvbS9jb21taXQvZWM2Mzg4Y2Y2ZWI2MjQ2MzUzOWNiNGM0MGNjM2NlYWU5ODI2ZGUxOVxuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZShuLCBwcmltZSkge1xuICAgIGxldCByZXMgPSBCaWdJbnQobikgJSBwcmltZTtcbiAgICBpZiAocmVzIDwgMCkgcmVzICs9IHByaW1lO1xuICAgIHJldHVybiByZXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmbnZIYXNoKHN0cikge1xuICAgIGNvbnN0IHVpbnQ2NF9tYXggPSBCaWdJbnQoMikgKiogQmlnSW50KDY0KTtcbiAgICBsZXQgaGFzaCA9IEJpZ0ludChcIjB4Q0JGMjlDRTQ4NDIyMjMyNVwiKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgICAgICBoYXNoIF49IEJpZ0ludChzdHJbaV0uY2hhckNvZGVBdCgwKSk7XG4gICAgICAgIGhhc2ggKj0gQmlnSW50KDB4MTAwMDAwMDAxQjMpO1xuICAgICAgICBoYXNoICU9IHVpbnQ2NF9tYXg7XG4gICAgfVxuICAgIGxldCBzaGFzaCA9IGhhc2gudG9TdHJpbmcoMTYpO1xuICAgIGxldCBuID0gMTYgLSBzaGFzaC5sZW5ndGg7XG4gICAgc2hhc2ggPSBcIjBcIi5yZXBlYXQobikuY29uY2F0KHNoYXNoKTtcbiAgICByZXR1cm4gc2hhc2g7XG59XG5cbi8vIE5vdGUgdGhhdCB0aGlzIHBhZHMgemVyb3NcbmV4cG9ydCBmdW5jdGlvbiB0b0FycmF5MzIocywgc2l6ZSkge1xuICAgIGNvbnN0IHJlcyA9IFtdOyAvL25ldyBVaW50MzJBcnJheShzaXplKTsgLy9oYXMgbm8gdW5zaGlmdFxuICAgIGxldCByZW0gPSBCaWdJbnQocyk7XG4gICAgY29uc3QgcmFkaXggPSBCaWdJbnQoMHgxMDAwMDAwMDApO1xuICAgIHdoaWxlIChyZW0pIHtcbiAgICAgICAgcmVzLnVuc2hpZnQoTnVtYmVyKHJlbSAlIHJhZGl4KSk7XG4gICAgICAgIHJlbSA9IHJlbSAvIHJhZGl4O1xuICAgIH1cbiAgICBpZiAoc2l6ZSkge1xuICAgICAgICBsZXQgaSA9IHNpemUgLSByZXMubGVuZ3RoO1xuICAgICAgICB3aGlsZSAoaSA+IDApIHtcbiAgICAgICAgICAgIHJlcy51bnNoaWZ0KDApO1xuICAgICAgICAgICAgaS0tO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG4iLCIvKiBnbG9iYWxzIFdlYkFzc2VtYmx5ICovXG4vKlxuXG5Db3B5cmlnaHQgMjAyMCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuXG4gICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG5cblVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxubGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG5cbiovXG5cbmltcG9ydCB7ZmxhdEFycmF5LCBmbnZIYXNoLCB0b0FycmF5MzIsIG5vcm1hbGl6ZX0gZnJvbSBcIi4vdXRpbHMuanNcIjtcbmltcG9ydCB7U2NhbGFyLCBGMUZpZWxkfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIGJ1aWxkZXIoY29kZSwgb3B0aW9ucykge1xuICAgIGxldCBpbnN0YW5jZTtcbiAgICBsZXQgd2M7XG4gICAgbGV0IG1lbW9yeTtcbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgIC8vIE9ubHkgY2lyY29tIDIgaW1wbGVtZW50cyB2ZXJzaW9uIGxvb2t1cCB0aHJvdWdoIGV4cG9ydHMgaW4gdGhlIFdBU01cbiAgICAvLyBXZSBkZWZhdWx0IHRvIGAxYCBhbmQgdXBkYXRlIGlmIHdlIHNlZSB0aGUgYGdldFZlcnNpb25gIGV4cG9ydCAobWFqb3IgdmVyc2lvbilcbiAgICAvLyBUaGVzZSBhcmUgdXBkYXRlZCBhZnRlciB0aGUgaW5zdGFuY2UgaXMgaW5zdGFudGlhdGVkLCBhc3N1bWluZyB0aGUgZnVuY3Rpb25zIGFyZSBhdmFpbGFibGVcbiAgICBsZXQgbWFqb3JWZXJzaW9uID0gMTtcbiAgICAvLyBBZnRlciBDaXJjb20gMi4wLjcsIEJsYWluZSBhZGRlZCBleHBvcnRlZCBmdW5jdGlvbnMgZm9yIGdldHRpbmcgbWlub3IgYW5kIHBhdGNoIHZlcnNpb25zXG4gICAgbGV0IG1pbm9yVmVyc2lvbiA9IDA7XG4gICAgLy8gSWYgd2UgY2FuJ3QgbG9vayB1cCB0aGUgcGF0Y2ggdmVyc2lvbiwgYXNzdW1lIHRoZSBsb3dlc3RcbiAgICBsZXQgcGF0Y2hWZXJzaW9uID0gMDtcblxuICAgIGxldCBjb2RlSXNXZWJBc3NlbWJseUluc3RhbmNlID0gZmFsc2U7XG5cbiAgICAvLyBJZiBjb2RlIGlzIGFscmVhZHkgcHJlcGFyZWQgV2ViQXNzZW1ibHkuSW5zdGFuY2UsIHdlIHVzZSBpdCBkaXJlY3RseVxuICAgIGlmIChjb2RlIGluc3RhbmNlb2YgV2ViQXNzZW1ibHkuSW5zdGFuY2UpIHtcbiAgICAgICAgaW5zdGFuY2UgPSBjb2RlO1xuICAgICAgICBjb2RlSXNXZWJBc3NlbWJseUluc3RhbmNlID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgbWVtb3J5U2l6ZSA9IDMyNzY3O1xuXG4gICAgICAgIGlmIChvcHRpb25zLm1lbW9yeVNpemUpIHtcbiAgICAgICAgICAgIC8vIG1ha2Ugc3VyZSB3ZSBoYXZlIGludFxuICAgICAgICAgICAgbWVtb3J5U2l6ZSA9IHBhcnNlSW50KG9wdGlvbnMubWVtb3J5U2l6ZSk7XG4gICAgICAgICAgICBpZiAobWVtb3J5U2l6ZSA8IDApIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIG1lbW9yeSBzaXplXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG1lbW9yeUFsbG9jYXRlZCA9IGZhbHNlO1xuICAgICAgICB3aGlsZSAoIW1lbW9yeUFsbG9jYXRlZCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBtZW1vcnkgPSBuZXcgV2ViQXNzZW1ibHkuTWVtb3J5KHtpbml0aWFsOiBtZW1vcnlTaXplfSk7XG4gICAgICAgICAgICAgICAgbWVtb3J5QWxsb2NhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIGlmIChtZW1vcnlTaXplIDw9IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXCJDb3VsZCBub3QgYWxsb2NhdGUgXCIgKyBtZW1vcnlTaXplICogMTAyNCAqIDY0ICsgXCIgYnl0ZXMuIFRoaXMgbWF5IGNhdXNlIHNldmVyZSBpbnN0YWJpbGl0eS4gVHJ5aW5nIHdpdGggXCIgKyBtZW1vcnlTaXplICogMTAyNCAqIDY0IC8gMiArIFwiIGJ5dGVzXCIpO1xuICAgICAgICAgICAgICAgIG1lbW9yeVNpemUgPSBNYXRoLmZsb29yKG1lbW9yeVNpemUgLyAyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHdhc21Nb2R1bGUgPSBhd2FpdCBXZWJBc3NlbWJseS5jb21waWxlKGNvZGUpO1xuXG4gICAgICAgIGxldCBlcnJTdHIgPSBcIlwiO1xuICAgICAgICBsZXQgbXNnU3RyID0gXCJcIjtcblxuICAgICAgICBpbnN0YW5jZSA9IGF3YWl0IFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKHdhc21Nb2R1bGUsIHtcbiAgICAgICAgICAgIGVudjoge1xuICAgICAgICAgICAgICAgIFwibWVtb3J5XCI6IG1lbW9yeVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJ1bnRpbWU6IHtcbiAgICAgICAgICAgICAgICBwcmludERlYnVnIDogZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJwcmludERlYnVnOlwiLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBleGNlcHRpb25IYW5kbGVyOiBmdW5jdGlvbiAoY29kZSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgZXJyO1xuICAgICAgICAgICAgICAgICAgICBpZiAoY29kZSA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyID0gXCJTaWduYWwgbm90IGZvdW5kLiBcIjtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChjb2RlID09PSAyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnIgPSBcIlRvbyBtYW55IHNpZ25hbHMgc2V0LiBcIjtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChjb2RlID09PSAzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnIgPSBcIlNpZ25hbCBhbHJlYWR5IHNldC4gXCI7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoY29kZSA9PT0gNCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyID0gXCJBc3NlcnQgRmFpbGVkLiBcIjtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChjb2RlID09PSA1KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnIgPSBcIk5vdCBlbm91Z2ggbWVtb3J5LiBcIjtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChjb2RlID09PSA2KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnIgPSBcIklucHV0IHNpZ25hbCBhcnJheSBhY2Nlc3MgZXhjZWVkcyB0aGUgc2l6ZS4gXCI7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnIgPSBcIlVua25vd24gZXJyb3IuIFwiO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFUlJPUjogXCIsIGNvZGUsIGVyclN0cik7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihlcnIgKyBlcnJTdHIpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgLy8gQSBuZXcgd2F5IG9mIGxvZ2dpbmcgbWVzc2FnZXMgd2FzIGFkZGVkIGluIENpcmNvbSAyLjAuNyB0aGF0IHJlcXVpcmVzIDIgbmV3IGltcG9ydHNcbiAgICAgICAgICAgICAgICAvLyBgcHJpbnRFcnJvck1lc3NhZ2VgIGFuZCBgd3JpdGVCdWZmZXJNZXNzYWdlYC5cbiAgICAgICAgICAgICAgICBwcmludEVycm9yTWVzc2FnZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBlcnJTdHIgKz0gZ2V0TWVzc2FnZSgpICsgXCJcXG5cIjtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHdyaXRlQnVmZmVyTWVzc2FnZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBtc2cgPSBnZXRNZXNzYWdlKCk7XG4gICAgICAgICAgICAgICAgICAgIC8vIEFueSBjYWxscyB0byBgbG9nKClgIHdpbGwgYWx3YXlzIGVuZCB3aXRoIGEgYFxcbmAsIHNvIHRoYXQncyB3aGVuIHdlIHByaW50IGFuZCByZXNldFxuICAgICAgICAgICAgICAgICAgICBpZiAobXNnID09PSBcIlxcblwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhtc2dTdHIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgbXNnU3RyID0gXCJcIjtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHdlJ3ZlIGJ1ZmZlcmVkIG90aGVyIGNvbnRlbnQsIHB1dCBhIHNwYWNlIGluIGJldHdlZW4gdGhlIGl0ZW1zXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAobXNnU3RyICE9PSBcIlwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbXNnU3RyICs9IFwiIFwiO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlbiBhcHBlbmQgdGhlIG1lc3NhZ2UgdG8gdGhlIG1lc3NhZ2Ugd2UgYXJlIGNyZWF0aW5nXG4gICAgICAgICAgICAgICAgICAgICAgICBtc2dTdHIgKz0gbXNnO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBzaG93U2hhcmVkUldNZW1vcnk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2hhcmVkX3J3X21lbW9yeV9zaXplID0gaW5zdGFuY2UuZXhwb3J0cy5nZXRGaWVsZE51bUxlbjMyKCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGFyciA9IG5ldyBVaW50MzJBcnJheShzaGFyZWRfcndfbWVtb3J5X3NpemUpO1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHNoYXJlZF9yd19tZW1vcnlfc2l6ZTsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhcnJbc2hhcmVkX3J3X21lbW9yeV9zaXplIC0gMSAtIGpdID0gaW5zdGFuY2UuZXhwb3J0cy5yZWFkU2hhcmVkUldNZW1vcnkoaik7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBJbiBjaXJjb20gMi4wLjcsIHRoZXkgY2hhbmdlZCB0aGUgbG9nKCkgZnVuY3Rpb24gdG8gYWxsb3cgc3RyaW5ncyBhbmQgY2hhbmdlZCB0aGVcbiAgICAgICAgICAgICAgICAgICAgLy8gb3V0cHV0IEFQSS4gVGhpcyBzbW9vdGhlcyBvdmVyIHRoZSBicmVha2luZyBjaGFuZ2UuXG4gICAgICAgICAgICAgICAgICAgIGlmIChtYWpvclZlcnNpb24gPj0gMiAmJiAobWlub3JWZXJzaW9uID49IDEgfHwgcGF0Y2hWZXJzaW9uID49IDcpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiB3ZSd2ZSBidWZmZXJlZCBvdGhlciBjb250ZW50LCBwdXQgYSBzcGFjZSBpbiBiZXR3ZWVuIHRoZSBpdGVtc1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1zZ1N0ciAhPT0gXCJcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1zZ1N0ciArPSBcIiBcIjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZW4gYXBwZW5kIHRoZSB2YWx1ZSB0byB0aGUgbWVzc2FnZSB3ZSBhcmUgY3JlYXRpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG1zZyA9IChTY2FsYXIuZnJvbUFycmF5KGFyciwgMHgxMDAwMDAwMDApLnRvU3RyaW5nKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgbXNnU3RyICs9IG1zZztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFNjYWxhci5mcm9tQXJyYXkoYXJyLCAweDEwMDAwMDAwMCkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBlcnJvcjogZnVuY3Rpb24gKGNvZGUsIHBzdHIsIGEsIGIsIGMsIGQpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGVyclN0cjtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvZGUgPT09IDcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVyclN0ciA9IHAyc3RyKHBzdHIpICsgXCIgXCIgKyB3Yy5nZXRGcihiKS50b1N0cmluZygpICsgXCIgIT0gXCIgKyB3Yy5nZXRGcihjKS50b1N0cmluZygpICsgXCIgXCIgKyBwMnN0cihkKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChjb2RlID09PSA5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJTdHIgPSBwMnN0cihwc3RyKSArIFwiIFwiICsgd2MuZ2V0RnIoYikudG9TdHJpbmcoKSArIFwiIFwiICsgcDJzdHIoYyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoKGNvZGUgPT09IDUpICYmIChvcHRpb25zLnN5bSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVyclN0ciA9IHAyc3RyKHBzdHIpICsgXCIgXCIgKyBvcHRpb25zLnN5bS5sYWJlbElkeDJOYW1lW2NdO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyU3RyID0gcDJzdHIocHN0cikgKyBcIiBcIiArIGEgKyBcIiBcIiArIGIgKyBcIiBcIiArIGMgKyBcIiBcIiArIGQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJFUlJPUjogXCIsIGNvZGUsIGVyclN0cik7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihlcnJTdHIpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgbG9nOiBmdW5jdGlvbiAoYSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyh3Yy5nZXRGcihhKS50b1N0cmluZygpKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGxvZ0dldFNpZ25hbDogZnVuY3Rpb24gKHNpZ25hbCwgcFZhbCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5sb2dHZXRTaWduYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMubG9nR2V0U2lnbmFsKHNpZ25hbCwgd2MuZ2V0RnIocFZhbCkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBsb2dTZXRTaWduYWw6IGZ1bmN0aW9uIChzaWduYWwsIHBWYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMubG9nU2V0U2lnbmFsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmxvZ1NldFNpZ25hbChzaWduYWwsIHdjLmdldEZyKHBWYWwpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgbG9nU3RhcnRDb21wb25lbnQ6IGZ1bmN0aW9uIChjSWR4KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmxvZ1N0YXJ0Q29tcG9uZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmxvZ1N0YXJ0Q29tcG9uZW50KGNJZHgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBsb2dGaW5pc2hDb21wb25lbnQ6IGZ1bmN0aW9uIChjSWR4KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmxvZ0ZpbmlzaENvbXBvbmVudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5sb2dGaW5pc2hDb21wb25lbnQoY0lkeCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgaW5zdGFuY2UuZXhwb3J0cy5nZXRWZXJzaW9uID09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICBtYWpvclZlcnNpb24gPSBpbnN0YW5jZS5leHBvcnRzLmdldFZlcnNpb24oKTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLmdldE1pbm9yVmVyc2lvbiA9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgbWlub3JWZXJzaW9uID0gaW5zdGFuY2UuZXhwb3J0cy5nZXRNaW5vclZlcnNpb24oKTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLmdldFBhdGNoVmVyc2lvbiA9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgcGF0Y2hWZXJzaW9uID0gaW5zdGFuY2UuZXhwb3J0cy5nZXRQYXRjaFZlcnNpb24oKTtcbiAgICB9XG5cbiAgICBjb25zdCBzYW5pdHlDaGVjayA9XG4gICAgICAgIG9wdGlvbnMgJiZcbiAgICAgICAgKFxuICAgICAgICAgICAgb3B0aW9ucy5zYW5pdHlDaGVjayB8fFxuICAgICAgICAgICAgb3B0aW9ucy5sb2dHZXRTaWduYWwgfHxcbiAgICAgICAgICAgIG9wdGlvbnMubG9nU2V0U2lnbmFsIHx8XG4gICAgICAgICAgICBvcHRpb25zLmxvZ1N0YXJ0Q29tcG9uZW50IHx8XG4gICAgICAgICAgICBvcHRpb25zLmxvZ0ZpbmlzaENvbXBvbmVudFxuICAgICAgICApO1xuXG4gICAgLy8gV2UgZXhwbGljaXRseSBjaGVjayBmb3IgbWFqb3IgdmVyc2lvbiAyIGluIGNhc2UgdGhlcmUncyBhIGNpcmNvbSB2MyBpbiB0aGUgZnV0dXJlXG4gICAgaWYgKG1ham9yVmVyc2lvbiA9PT0gMikge1xuICAgICAgICB3YyA9IG5ldyBXaXRuZXNzQ2FsY3VsYXRvckNpcmNvbTIoaW5zdGFuY2UsIHNhbml0eUNoZWNrKTtcbiAgICB9IGVsc2UgaWYgKG1ham9yVmVyc2lvbiA9PT0gMSkge1xuICAgICAgICBpZiAoY29kZUlzV2ViQXNzZW1ibHlJbnN0YW5jZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdMb2FkaW5nIGNvZGUgZnJvbSBXZWJBc3NlbWJseSBpbnN0YW5jZSBpcyBub3Qgc3VwcG9ydGVkIGZvciBjaXJjb20gdmVyc2lvbiAxJyk7XG4gICAgICAgIH1cbiAgICAgICAgd2MgPSBuZXcgV2l0bmVzc0NhbGN1bGF0b3JDaXJjb20xKG1lbW9yeSwgaW5zdGFuY2UsIHNhbml0eUNoZWNrKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIGNpcmNvbSB2ZXJzaW9uOiAke21ham9yVmVyc2lvbn1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHdjO1xuXG4gICAgZnVuY3Rpb24gZ2V0TWVzc2FnZSgpIHtcbiAgICAgICAgbGV0IG1lc3NhZ2UgPSBcIlwiO1xuICAgICAgICBsZXQgYyA9IGluc3RhbmNlLmV4cG9ydHMuZ2V0TWVzc2FnZUNoYXIoKTtcbiAgICAgICAgd2hpbGUgKGMgIT09IDApIHtcbiAgICAgICAgICAgIG1lc3NhZ2UgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShjKTtcbiAgICAgICAgICAgIGMgPSBpbnN0YW5jZS5leHBvcnRzLmdldE1lc3NhZ2VDaGFyKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG1lc3NhZ2U7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcDJzdHIocCkge1xuICAgICAgICBjb25zdCBpOCA9IG5ldyBVaW50OEFycmF5KG1lbW9yeS5idWZmZXIpO1xuXG4gICAgICAgIGNvbnN0IGJ5dGVzID0gW107XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGk4W3AgKyBpXSA+IDA7IGkrKykgYnl0ZXMucHVzaChpOFtwICsgaV0pO1xuXG4gICAgICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIGJ5dGVzKTtcbiAgICB9XG59XG5cbmNsYXNzIFdpdG5lc3NDYWxjdWxhdG9yQ2lyY29tMSB7XG4gICAgY29uc3RydWN0b3IobWVtb3J5LCBpbnN0YW5jZSwgc2FuaXR5Q2hlY2spIHtcbiAgICAgICAgdGhpcy5tZW1vcnkgPSBtZW1vcnk7XG4gICAgICAgIHRoaXMuaTMyID0gbmV3IFVpbnQzMkFycmF5KG1lbW9yeS5idWZmZXIpO1xuICAgICAgICB0aGlzLmluc3RhbmNlID0gaW5zdGFuY2U7XG5cbiAgICAgICAgdGhpcy5uMzIgPSAodGhpcy5pbnN0YW5jZS5leHBvcnRzLmdldEZyTGVuKCkgPj4gMikgLSAyO1xuICAgICAgICBjb25zdCBwUmF3UHJpbWUgPSB0aGlzLmluc3RhbmNlLmV4cG9ydHMuZ2V0UFJhd1ByaW1lKCk7XG5cbiAgICAgICAgY29uc3QgYXJyID0gbmV3IEFycmF5KHRoaXMubjMyKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm4zMjsgaSsrKSB7XG4gICAgICAgICAgICBhcnJbdGhpcy5uMzIgLSAxIC0gaV0gPSB0aGlzLmkzMlsocFJhd1ByaW1lID4+IDIpICsgaV07XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnByaW1lID0gU2NhbGFyLmZyb21BcnJheShhcnIsIDB4MTAwMDAwMDAwKTtcblxuICAgICAgICB0aGlzLkZyID0gbmV3IEYxRmllbGQodGhpcy5wcmltZSk7XG5cbiAgICAgICAgdGhpcy5tYXNrMzIgPSBTY2FsYXIuZnJvbVN0cmluZyhcIkZGRkZGRkZGXCIsIDE2KTtcbiAgICAgICAgdGhpcy5OVmFycyA9IHRoaXMuaW5zdGFuY2UuZXhwb3J0cy5nZXROVmFycygpO1xuICAgICAgICB0aGlzLm42NCA9IE1hdGguZmxvb3IoKHRoaXMuRnIuYml0TGVuZ3RoIC0gMSkgLyA2NCkgKyAxO1xuICAgICAgICB0aGlzLlIgPSB0aGlzLkZyLmUoU2NhbGFyLnNoaWZ0TGVmdCgxLCB0aGlzLm42NCAqIDY0KSk7XG4gICAgICAgIHRoaXMuUkludiA9IHRoaXMuRnIuaW52KHRoaXMuUik7XG4gICAgICAgIHRoaXMuc2FuaXR5Q2hlY2sgPSBzYW5pdHlDaGVjaztcbiAgICB9XG5cbiAgICBjaXJjb21fdmVyc2lvbigpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgfVxuXG4gICAgYXN5bmMgX2RvQ2FsY3VsYXRlV2l0bmVzcyhpbnB1dCwgc2FuaXR5Q2hlY2spIHtcbiAgICAgICAgdGhpcy5pbnN0YW5jZS5leHBvcnRzLmluaXQoKHRoaXMuc2FuaXR5Q2hlY2sgfHwgc2FuaXR5Q2hlY2spID8gMSA6IDApO1xuICAgICAgICBjb25zdCBwU2lnT2Zmc2V0ID0gdGhpcy5hbGxvY0ludCgpO1xuICAgICAgICBjb25zdCBwRnIgPSB0aGlzLmFsbG9jRnIoKTtcbiAgICAgICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKGlucHV0KTtcbiAgICAgICAga2V5cy5mb3JFYWNoKChrKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBoID0gZm52SGFzaChrKTtcbiAgICAgICAgICAgIGNvbnN0IGhNU0IgPSBwYXJzZUludChoLnNsaWNlKDAsIDgpLCAxNik7XG4gICAgICAgICAgICBjb25zdCBoTFNCID0gcGFyc2VJbnQoaC5zbGljZSg4LCAxNiksIDE2KTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGhpcy5pbnN0YW5jZS5leHBvcnRzLmdldFNpZ25hbE9mZnNldDMyKHBTaWdPZmZzZXQsIDAsIGhNU0IsIGhMU0IpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTaWduYWwgJHtrfSBpcyBub3QgYW4gaW5wdXQgb2YgdGhlIGNpcmN1aXQuYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzaWdPZmZzZXQgPSB0aGlzLmdldEludChwU2lnT2Zmc2V0KTtcbiAgICAgICAgICAgIGNvbnN0IGZBcnIgPSBmbGF0QXJyYXkoaW5wdXRba10pO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBmQXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRGcihwRnIsIGZBcnJbaV0pO1xuICAgICAgICAgICAgICAgIHRoaXMuaW5zdGFuY2UuZXhwb3J0cy5zZXRTaWduYWwoMCwgMCwgc2lnT2Zmc2V0ICsgaSwgcEZyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgYXN5bmMgY2FsY3VsYXRlV2l0bmVzcyhpbnB1dCwgc2FuaXR5Q2hlY2spIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgY29uc3Qgb2xkMCA9IHNlbGYuaTMyWzBdO1xuICAgICAgICBjb25zdCB3ID0gW107XG5cbiAgICAgICAgYXdhaXQgc2VsZi5fZG9DYWxjdWxhdGVXaXRuZXNzKGlucHV0LCBzYW5pdHlDaGVjayk7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmLk5WYXJzOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IHBXaXRuZXNzID0gc2VsZi5pbnN0YW5jZS5leHBvcnRzLmdldFBXaXRuZXNzKGkpO1xuICAgICAgICAgICAgdy5wdXNoKHNlbGYuZ2V0RnIocFdpdG5lc3MpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNlbGYuaTMyWzBdID0gb2xkMDtcbiAgICAgICAgcmV0dXJuIHc7XG4gICAgfVxuXG4gICAgYXN5bmMgY2FsY3VsYXRlQmluV2l0bmVzcyhpbnB1dCwgc2FuaXR5Q2hlY2spIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgY29uc3Qgb2xkMCA9IHNlbGYuaTMyWzBdO1xuXG4gICAgICAgIGF3YWl0IHNlbGYuX2RvQ2FsY3VsYXRlV2l0bmVzcyhpbnB1dCwgc2FuaXR5Q2hlY2spO1xuXG4gICAgICAgIGNvbnN0IHBXaXRuZXNzQnVmZmVyID0gc2VsZi5pbnN0YW5jZS5leHBvcnRzLmdldFdpdG5lc3NCdWZmZXIoKTtcblxuICAgICAgICBzZWxmLmkzMlswXSA9IG9sZDA7XG5cbiAgICAgICAgY29uc3QgYnVmZiA9IHNlbGYubWVtb3J5LmJ1ZmZlci5zbGljZShwV2l0bmVzc0J1ZmZlciwgcFdpdG5lc3NCdWZmZXIgKyAoc2VsZi5OVmFycyAqIHNlbGYubjY0ICogOCkpO1xuICAgICAgICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkoYnVmZik7XG4gICAgfVxuXG4gICAgYWxsb2NJbnQoKSB7XG4gICAgICAgIGNvbnN0IHAgPSB0aGlzLmkzMlswXTtcbiAgICAgICAgdGhpcy5pMzJbMF0gPSBwICsgODtcbiAgICAgICAgcmV0dXJuIHA7XG4gICAgfVxuXG4gICAgYWxsb2NGcigpIHtcbiAgICAgICAgY29uc3QgcCA9IHRoaXMuaTMyWzBdO1xuICAgICAgICB0aGlzLmkzMlswXSA9IHAgKyB0aGlzLm4zMiAqIDQgKyA4O1xuICAgICAgICByZXR1cm4gcDtcbiAgICB9XG5cbiAgICBnZXRJbnQocCkge1xuICAgICAgICByZXR1cm4gdGhpcy5pMzJbcCA+PiAyXTtcbiAgICB9XG5cbiAgICBzZXRJbnQocCwgdikge1xuICAgICAgICB0aGlzLmkzMltwID4+IDJdID0gdjtcbiAgICB9XG5cbiAgICBnZXRGcihwKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBpZHggPSAocCA+PiAyKTtcblxuICAgICAgICBpZiAoc2VsZi5pMzJbaWR4ICsgMV0gJiAweDgwMDAwMDAwKSB7XG4gICAgICAgICAgICBjb25zdCBhcnIgPSBuZXcgQXJyYXkoc2VsZi5uMzIpO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmLm4zMjsgaSsrKSB7XG4gICAgICAgICAgICAgICAgYXJyW3NlbGYubjMyIC0gMSAtIGldID0gc2VsZi5pMzJbaWR4ICsgMiArIGldO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgcmVzID0gc2VsZi5Gci5lKFNjYWxhci5mcm9tQXJyYXkoYXJyLCAweDEwMDAwMDAwMCkpO1xuICAgICAgICAgICAgaWYgKHNlbGYuaTMyW2lkeCArIDFdICYgMHg0MDAwMDAwMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmcm9tTW9udGdvbWVyeShyZXMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoc2VsZi5pMzJbaWR4XSAmIDB4ODAwMDAwMDApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5Gci5lKHNlbGYuaTMyW2lkeF0gLSAweDEwMDAwMDAwMCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBzZWxmLkZyLmUoc2VsZi5pMzJbaWR4XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBmcm9tTW9udGdvbWVyeShuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2VsZi5Gci5tdWwoc2VsZi5SSW52LCBuKTtcbiAgICAgICAgfVxuXG4gICAgfVxuXG5cbiAgICBzZXRGcihwLCB2KSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIHYgPSBzZWxmLkZyLmUodik7XG5cbiAgICAgICAgY29uc3QgbWluU2hvcnQgPSBzZWxmLkZyLm5lZyhzZWxmLkZyLmUoXCI4MDAwMDAwMFwiLCAxNikpO1xuICAgICAgICBjb25zdCBtYXhTaG9ydCA9IHNlbGYuRnIuZShcIjdGRkZGRkZGXCIsIDE2KTtcblxuICAgICAgICBpZiAoKHNlbGYuRnIuZ2VxKHYsIG1pblNob3J0KSlcbiAgICAgICAgICAgICYmIChzZWxmLkZyLmxlcSh2LCBtYXhTaG9ydCkpKSB7XG4gICAgICAgICAgICBsZXQgYTtcbiAgICAgICAgICAgIGlmIChzZWxmLkZyLmdlcSh2LCBzZWxmLkZyLnplcm8pKSB7XG4gICAgICAgICAgICAgICAgYSA9IFNjYWxhci50b051bWJlcih2KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYSA9IFNjYWxhci50b051bWJlcihzZWxmLkZyLnN1Yih2LCBtaW5TaG9ydCkpO1xuICAgICAgICAgICAgICAgIGEgPSBhIC0gMHg4MDAwMDAwMDtcbiAgICAgICAgICAgICAgICBhID0gMHgxMDAwMDAwMDAgKyBhO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VsZi5pMzJbKHAgPj4gMildID0gYTtcbiAgICAgICAgICAgIHNlbGYuaTMyWyhwID4+IDIpICsgMV0gPSAwO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5pMzJbKHAgPj4gMildID0gMDtcbiAgICAgICAgc2VsZi5pMzJbKHAgPj4gMikgKyAxXSA9IDB4ODAwMDAwMDA7XG4gICAgICAgIGNvbnN0IGFyciA9IFNjYWxhci50b0FycmF5KHYsIDB4MTAwMDAwMDAwKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmLm4zMjsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBpZHggPSBhcnIubGVuZ3RoIC0gMSAtIGk7XG5cbiAgICAgICAgICAgIGlmIChpZHggPj0gMCkge1xuICAgICAgICAgICAgICAgIHNlbGYuaTMyWyhwID4+IDIpICsgMiArIGldID0gYXJyW2lkeF07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNlbGYuaTMyWyhwID4+IDIpICsgMiArIGldID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cblxuY2xhc3MgV2l0bmVzc0NhbGN1bGF0b3JDaXJjb20yIHtcbiAgICBjb25zdHJ1Y3RvcihpbnN0YW5jZSwgc2FuaXR5Q2hlY2spIHtcbiAgICAgICAgdGhpcy5pbnN0YW5jZSA9IGluc3RhbmNlO1xuXG4gICAgICAgIHRoaXMudmVyc2lvbiA9IHRoaXMuaW5zdGFuY2UuZXhwb3J0cy5nZXRWZXJzaW9uKCk7XG4gICAgICAgIHRoaXMubjMyID0gdGhpcy5pbnN0YW5jZS5leHBvcnRzLmdldEZpZWxkTnVtTGVuMzIoKTtcblxuICAgICAgICB0aGlzLmluc3RhbmNlLmV4cG9ydHMuZ2V0UmF3UHJpbWUoKTtcbiAgICAgICAgY29uc3QgYXJyID0gbmV3IFVpbnQzMkFycmF5KHRoaXMubjMyKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm4zMjsgaSsrKSB7XG4gICAgICAgICAgICBhcnJbdGhpcy5uMzIgLSAxIC0gaV0gPSB0aGlzLmluc3RhbmNlLmV4cG9ydHMucmVhZFNoYXJlZFJXTWVtb3J5KGkpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucHJpbWUgPSBTY2FsYXIuZnJvbUFycmF5KGFyciwgMHgxMDAwMDAwMDApO1xuXG4gICAgICAgIHRoaXMud2l0bmVzc1NpemUgPSB0aGlzLmluc3RhbmNlLmV4cG9ydHMuZ2V0V2l0bmVzc1NpemUoKTtcblxuICAgICAgICB0aGlzLnNhbml0eUNoZWNrID0gc2FuaXR5Q2hlY2s7XG4gICAgfVxuXG4gICAgY2lyY29tX3ZlcnNpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmluc3RhbmNlLmV4cG9ydHMuZ2V0VmVyc2lvbigpO1xuICAgIH1cblxuICAgIGFzeW5jIF9kb0NhbGN1bGF0ZVdpdG5lc3MoaW5wdXQsIHNhbml0eUNoZWNrKSB7XG4gICAgICAgIC8vaW5wdXQgaXMgYXNzdW1lZCB0byBiZSBhIG1hcCBmcm9tIHNpZ25hbHMgdG8gYXJyYXlzIG9mIGJpZ2ludHNcbiAgICAgICAgdGhpcy5pbnN0YW5jZS5leHBvcnRzLmluaXQoKHRoaXMuc2FuaXR5Q2hlY2sgfHwgc2FuaXR5Q2hlY2spID8gMSA6IDApO1xuICAgICAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoaW5wdXQpO1xuICAgICAgICBsZXQgaW5wdXRfY291bnRlciA9IDA7XG4gICAgICAgIGtleXMuZm9yRWFjaCgoaykgPT4ge1xuICAgICAgICAgICAgY29uc3QgaCA9IGZudkhhc2goayk7XG4gICAgICAgICAgICBjb25zdCBoTVNCID0gcGFyc2VJbnQoaC5zbGljZSgwLCA4KSwgMTYpO1xuICAgICAgICAgICAgY29uc3QgaExTQiA9IHBhcnNlSW50KGguc2xpY2UoOCwgMTYpLCAxNik7XG4gICAgICAgICAgICBjb25zdCBmQXJyID0gZmxhdEFycmF5KGlucHV0W2tdKTtcbiAgICAgICAgICAgIC8vIFNsaWdodCBkZXZpYXRpb24gZnJvbSBodHRwczovL2dpdGh1Yi5jb20vaWRlbjMvY2lyY29tL2Jsb2IvdjIuMS42L2NvZGVfcHJvZHVjZXJzL3NyYy93YXNtX2VsZW1lbnRzL2NvbW1vbi93aXRuZXNzX2NhbGN1bGF0b3IuanNcbiAgICAgICAgICAgIC8vIGJlY2F1c2UgSSBkb24ndCBrbm93IHdoZW4gdGhpcyBleHBvcnRlZCBmdW5jdGlvbiB3YXMgYWRkZWRcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdGhpcy5pbnN0YW5jZS5leHBvcnRzLmdldElucHV0U2lnbmFsU2l6ZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgbGV0IHNpZ25hbFNpemUgPSB0aGlzLmluc3RhbmNlLmV4cG9ydHMuZ2V0SW5wdXRTaWduYWxTaXplKGhNU0IsIGhMU0IpO1xuICAgICAgICAgICAgICAgIGlmIChzaWduYWxTaXplIDwgMCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFNpZ25hbCAke2t9IG5vdCBmb3VuZFxcbmApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoZkFyci5sZW5ndGggPCBzaWduYWxTaXplKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTm90IGVub3VnaCB2YWx1ZXMgZm9yIGlucHV0IHNpZ25hbCAke2t9XFxuYCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChmQXJyLmxlbmd0aCA+IHNpZ25hbFNpemUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUb28gbWFueSB2YWx1ZXMgZm9yIGlucHV0IHNpZ25hbCAke2t9XFxuYCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBmQXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYXJyRnIgPSB0b0FycmF5MzIobm9ybWFsaXplKGZBcnJbaV0sIHRoaXMucHJpbWUpLCB0aGlzLm4zMik7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLm4zMjsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW5zdGFuY2UuZXhwb3J0cy53cml0ZVNoYXJlZFJXTWVtb3J5KGosIGFyckZyW3RoaXMubjMyIC0gMSAtIGpdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pbnN0YW5jZS5leHBvcnRzLnNldElucHV0U2lnbmFsKGhNU0IsIGhMU0IsIGkpO1xuICAgICAgICAgICAgICAgICAgICBpbnB1dF9jb3VudGVyKys7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKGBBZnRlciBhZGRpbmcgc2lnbmFsICR7aX0gb2YgJHtrfWApXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihlcnIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGlucHV0X2NvdW50ZXIgPCB0aGlzLmluc3RhbmNlLmV4cG9ydHMuZ2V0SW5wdXRTaXplKCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTm90IGFsbCBpbnB1dHMgaGF2ZSBiZWVuIHNldC4gT25seSAke2lucHV0X2NvdW50ZXJ9IG91dCBvZiAke3RoaXMuaW5zdGFuY2UuZXhwb3J0cy5nZXRJbnB1dFNpemUoKX1gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGNhbGN1bGF0ZVdpdG5lc3MoaW5wdXQsIHNhbml0eUNoZWNrKSB7XG4gICAgICAgIGNvbnN0IHcgPSBbXTtcblxuICAgICAgICBhd2FpdCB0aGlzLl9kb0NhbGN1bGF0ZVdpdG5lc3MoaW5wdXQsIHNhbml0eUNoZWNrKTtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMud2l0bmVzc1NpemU7IGkrKykge1xuICAgICAgICAgICAgdGhpcy5pbnN0YW5jZS5leHBvcnRzLmdldFdpdG5lc3MoaSk7XG4gICAgICAgICAgICBjb25zdCBhcnIgPSBuZXcgVWludDMyQXJyYXkodGhpcy5uMzIpO1xuICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLm4zMjsgaisrKSB7XG4gICAgICAgICAgICAgICAgYXJyW3RoaXMubjMyIC0gMSAtIGpdID0gdGhpcy5pbnN0YW5jZS5leHBvcnRzLnJlYWRTaGFyZWRSV01lbW9yeShqKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHcucHVzaChTY2FsYXIuZnJvbUFycmF5KGFyciwgMHgxMDAwMDAwMDApKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB3O1xuICAgIH1cblxuICAgIGFzeW5jIGNhbGN1bGF0ZVdUTlNCaW4oaW5wdXQsIHNhbml0eUNoZWNrKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYzMiA9IG5ldyBVaW50MzJBcnJheSh0aGlzLndpdG5lc3NTaXplICogdGhpcy5uMzIgKyB0aGlzLm4zMiArIDExKTtcbiAgICAgICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KGJ1ZmYzMi5idWZmZXIpO1xuICAgICAgICBhd2FpdCB0aGlzLl9kb0NhbGN1bGF0ZVdpdG5lc3MoaW5wdXQsIHNhbml0eUNoZWNrKTtcblxuICAgICAgICAvL1wid3Ruc1wiXG4gICAgICAgIGJ1ZmZbMF0gPSBcIndcIi5jaGFyQ29kZUF0KDApO1xuICAgICAgICBidWZmWzFdID0gXCJ0XCIuY2hhckNvZGVBdCgwKTtcbiAgICAgICAgYnVmZlsyXSA9IFwiblwiLmNoYXJDb2RlQXQoMCk7XG4gICAgICAgIGJ1ZmZbM10gPSBcInNcIi5jaGFyQ29kZUF0KDApO1xuXG4gICAgICAgIC8vdmVyc2lvbiAyXG4gICAgICAgIGJ1ZmYzMlsxXSA9IDI7XG5cbiAgICAgICAgLy9udW1iZXIgb2Ygc2VjdGlvbnM6IDJcbiAgICAgICAgYnVmZjMyWzJdID0gMjtcblxuICAgICAgICAvL2lkIHNlY3Rpb24gMVxuICAgICAgICBidWZmMzJbM10gPSAxO1xuXG4gICAgICAgIGNvbnN0IG44ID0gdGhpcy5uMzIgKiA0O1xuICAgICAgICAvL2lkIHNlY3Rpb24gMSBsZW5ndGggaW4gNjRieXRlc1xuICAgICAgICBjb25zdCBpZFNlY3Rpb24xbGVuZ3RoID0gOCArIG44O1xuICAgICAgICBjb25zdCBpZFNlY3Rpb24xbGVuZ3RoSGV4ID0gaWRTZWN0aW9uMWxlbmd0aC50b1N0cmluZygxNik7XG4gICAgICAgIGJ1ZmYzMls0XSA9IHBhcnNlSW50KGlkU2VjdGlvbjFsZW5ndGhIZXguc2xpY2UoMCwgOCksIDE2KTtcbiAgICAgICAgYnVmZjMyWzVdID0gcGFyc2VJbnQoaWRTZWN0aW9uMWxlbmd0aEhleC5zbGljZSg4LCAxNiksIDE2KTtcblxuICAgICAgICAvL3RoaXMubjMyXG4gICAgICAgIGJ1ZmYzMls2XSA9IG44O1xuXG4gICAgICAgIC8vcHJpbWUgbnVtYmVyXG4gICAgICAgIHRoaXMuaW5zdGFuY2UuZXhwb3J0cy5nZXRSYXdQcmltZSgpO1xuXG4gICAgICAgIGxldCBwb3MgPSA3O1xuICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMubjMyOyBqKyspIHtcbiAgICAgICAgICAgIGJ1ZmYzMltwb3MgKyBqXSA9IHRoaXMuaW5zdGFuY2UuZXhwb3J0cy5yZWFkU2hhcmVkUldNZW1vcnkoaik7XG4gICAgICAgIH1cbiAgICAgICAgcG9zICs9IHRoaXMubjMyO1xuXG4gICAgICAgIC8vIHdpdG5lc3Mgc2l6ZVxuICAgICAgICBidWZmMzJbcG9zXSA9IHRoaXMud2l0bmVzc1NpemU7XG4gICAgICAgIHBvcysrO1xuXG4gICAgICAgIC8vaWQgc2VjdGlvbiAyXG4gICAgICAgIGJ1ZmYzMltwb3NdID0gMjtcbiAgICAgICAgcG9zKys7XG5cbiAgICAgICAgLy8gc2VjdGlvbiAyIGxlbmd0aFxuICAgICAgICBjb25zdCBpZFNlY3Rpb24ybGVuZ3RoID0gbjggKiB0aGlzLndpdG5lc3NTaXplO1xuICAgICAgICBjb25zdCBpZFNlY3Rpb24ybGVuZ3RoSGV4ID0gaWRTZWN0aW9uMmxlbmd0aC50b1N0cmluZygxNik7XG4gICAgICAgIGJ1ZmYzMltwb3NdID0gcGFyc2VJbnQoaWRTZWN0aW9uMmxlbmd0aEhleC5zbGljZSgwLCA4KSwgMTYpO1xuICAgICAgICBidWZmMzJbcG9zICsgMV0gPSBwYXJzZUludChpZFNlY3Rpb24ybGVuZ3RoSGV4LnNsaWNlKDgsIDE2KSwgMTYpO1xuXG4gICAgICAgIHBvcyArPSAyO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMud2l0bmVzc1NpemU7IGkrKykge1xuICAgICAgICAgICAgdGhpcy5pbnN0YW5jZS5leHBvcnRzLmdldFdpdG5lc3MoaSk7XG4gICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMubjMyOyBqKyspIHtcbiAgICAgICAgICAgICAgICBidWZmMzJbcG9zICsgal0gPSB0aGlzLmluc3RhbmNlLmV4cG9ydHMucmVhZFNoYXJlZFJXTWVtb3J5KGopO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcG9zICs9IHRoaXMubjMyO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgfVxuXG59XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgKiBhcyBmYXN0RmlsZSBmcm9tIFwiZmFzdGZpbGVcIjtcbmltcG9ydCB7IFdpdG5lc3NDYWxjdWxhdG9yQnVpbGRlciB9IGZyb20gXCJjaXJjb21fcnVudGltZVwiO1xuaW1wb3J0ICogYXMgd3Ruc1V0aWxzIGZyb20gXCIuL3d0bnNfdXRpbHMuanNcIjtcbmltcG9ydCAqIGFzIGJpbkZpbGVVdGlscyBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuaW1wb3J0IHsgIHV0aWxzIH0gICBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5jb25zdCB7IHVuc3RyaW5naWZ5QmlnSW50c30gPSB1dGlscztcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gd3Ruc0NhbGN1bGF0ZShfaW5wdXQsIHdhc21GaWxlTmFtZSwgd3Ruc0ZpbGVOYW1lLCBvcHRpb25zKSB7XG4gICAgY29uc3QgaW5wdXQgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX2lucHV0KTtcblxuICAgIGNvbnN0IGZkV2FzbSA9IGF3YWl0IGZhc3RGaWxlLnJlYWRFeGlzdGluZyh3YXNtRmlsZU5hbWUpO1xuICAgIGNvbnN0IHdhc20gPSBhd2FpdCBmZFdhc20ucmVhZChmZFdhc20udG90YWxTaXplKTtcbiAgICBhd2FpdCBmZFdhc20uY2xvc2UoKTtcblxuICAgIGNvbnN0IHdjID0gYXdhaXQgV2l0bmVzc0NhbGN1bGF0b3JCdWlsZGVyKHdhc20sIG9wdGlvbnMpO1xuICAgIGlmICh3Yy5jaXJjb21fdmVyc2lvbigpID09PSAxKSB7XG4gICAgICAgIGNvbnN0IHcgPSBhd2FpdCB3Yy5jYWxjdWxhdGVCaW5XaXRuZXNzKGlucHV0KTtcblxuICAgICAgICBjb25zdCBmZFd0bnMgPSBhd2FpdCBiaW5GaWxlVXRpbHMuY3JlYXRlQmluRmlsZSh3dG5zRmlsZU5hbWUsIFwid3Ruc1wiLCAyLCAyKTtcblxuICAgICAgICBhd2FpdCB3dG5zVXRpbHMud3JpdGVCaW4oZmRXdG5zLCB3LCB3Yy5wcmltZSk7XG4gICAgICAgIGF3YWl0IGZkV3Rucy5jbG9zZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGZkV3RucyA9IGF3YWl0IGZhc3RGaWxlLmNyZWF0ZU92ZXJyaWRlKHd0bnNGaWxlTmFtZSk7XG5cbiAgICAgICAgY29uc3QgdyA9IGF3YWl0IHdjLmNhbGN1bGF0ZVdUTlNCaW4oaW5wdXQpO1xuXG4gICAgICAgIGF3YWl0IGZkV3Rucy53cml0ZSh3KTtcbiAgICAgICAgYXdhaXQgZmRXdG5zLmNsb3NlKCk7XG4gICAgfVxufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0IGdyb3RoMTZfcHJvdmUgZnJvbSBcIi4vZ3JvdGgxNl9wcm92ZS5qc1wiO1xuaW1wb3J0IHd0bnNfY2FsY3VsYXRlIGZyb20gXCIuL3d0bnNfY2FsY3VsYXRlLmpzXCI7XG5pbXBvcnQge3V0aWxzfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5jb25zdCB7dW5zdHJpbmdpZnlCaWdJbnRzfSA9IHV0aWxzO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBncm90aDE2RnVsbFByb3ZlKF9pbnB1dCwgd2FzbUZpbGUsIHprZXlGaWxlTmFtZSwgbG9nZ2VyLCB3dG5zQ2FsY09wdGlvbnMsIHByb3Zlck9wdGlvbnMpIHtcbiAgICBjb25zdCBpbnB1dCA9IHVuc3RyaW5naWZ5QmlnSW50cyhfaW5wdXQpO1xuXG4gICAgY29uc3Qgd3Rucz0ge1xuICAgICAgICB0eXBlOiBcIm1lbVwiXG4gICAgfTtcbiAgICBhd2FpdCB3dG5zX2NhbGN1bGF0ZShpbnB1dCwgd2FzbUZpbGUsIHd0bnMsIHd0bnNDYWxjT3B0aW9ucyk7XG4gICAgcmV0dXJuIGF3YWl0IGdyb3RoMTZfcHJvdmUoemtleUZpbGVOYW1lLCB3dG5zLCBsb2dnZXIsIHByb3Zlck9wdGlvbnMpO1xufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwa2ltcyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJranMuXG5cbiAgICBzbmFya2pzIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4gICAgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZVxuICAgIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKVxuICAgIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtqcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvclxuICAgIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGhcbiAgICBzbmFya2pzLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuLyogSW1wbGVtZW50YXRpb24gb2YgdGhpcyBwYXBlcjogaHR0cHM6Ly9lcHJpbnQuaWFjci5vcmcvMjAxNi8yNjAucGRmICovXG5pbXBvcnQgeyBTY2FsYXIgfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5pbXBvcnQgKiBhcyBjdXJ2ZXMgZnJvbSBcIi4vY3VydmVzLmpzXCI7XG5pbXBvcnQgeyAgdXRpbHMgfSAgIGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmNvbnN0IHt1bnN0cmluZ2lmeUJpZ0ludHN9ID0gdXRpbHM7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIGdyb3RoMTZWZXJpZnkoX3ZrX3ZlcmlmaWVyLCBfcHVibGljU2lnbmFscywgX3Byb29mLCBsb2dnZXIpIHtcbi8qXG4gICAgbGV0IGNwdWIgPSB2a192ZXJpZmllci5JQ1swXTtcbiAgICBmb3IgKGxldCBzPSAwOyBzPCB2a192ZXJpZmllci5uUHVibGljOyBzKyspIHtcbiAgICAgICAgY3B1YiAgPSBHMS5hZGQoIGNwdWIsIEcxLnRpbWVzU2NhbGFyKCB2a192ZXJpZmllci5JQ1tzKzFdLCBwdWJsaWNTaWduYWxzW3NdKSk7XG4gICAgfVxuKi9cblxuICAgIGNvbnN0IHZrX3ZlcmlmaWVyID0gdW5zdHJpbmdpZnlCaWdJbnRzKF92a192ZXJpZmllcik7XG4gICAgY29uc3QgcHJvb2YgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX3Byb29mKTtcbiAgICBjb25zdCBwdWJsaWNTaWduYWxzID0gdW5zdHJpbmdpZnlCaWdJbnRzKF9wdWJsaWNTaWduYWxzKTtcblxuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgY3VydmVzLmdldEN1cnZlRnJvbU5hbWUodmtfdmVyaWZpZXIuY3VydmUpO1xuXG4gICAgY29uc3QgSUMwID0gY3VydmUuRzEuZnJvbU9iamVjdCh2a192ZXJpZmllci5JQ1swXSk7XG4gICAgY29uc3QgSUMgPSBuZXcgVWludDhBcnJheShjdXJ2ZS5HMS5GLm44KjIgKiBwdWJsaWNTaWduYWxzLmxlbmd0aCk7XG4gICAgY29uc3QgdyA9IG5ldyBVaW50OEFycmF5KGN1cnZlLkZyLm44ICogcHVibGljU2lnbmFscy5sZW5ndGgpO1xuXG4gICAgaWYgKCFwdWJsaWNJbnB1dHNBcmVWYWxpZChjdXJ2ZSwgcHVibGljU2lnbmFscykpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiUHVibGljIGlucHV0cyBhcmUgbm90IHZhbGlkLlwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGZvciAobGV0IGk9MDsgaTxwdWJsaWNTaWduYWxzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmZQID0gY3VydmUuRzEuZnJvbU9iamVjdCh2a192ZXJpZmllci5JQ1tpKzFdKTtcbiAgICAgICAgSUMuc2V0KGJ1ZmZQLCBpKmN1cnZlLkcxLkYubjgqMik7XG4gICAgICAgIFNjYWxhci50b1JwckxFKHcsIGN1cnZlLkZyLm44KmksIHB1YmxpY1NpZ25hbHNbaV0sIGN1cnZlLkZyLm44KTtcbiAgICB9XG5cbiAgICBsZXQgY3B1YiA9IGF3YWl0IGN1cnZlLkcxLm11bHRpRXhwQWZmaW5lKElDLCB3KTtcbiAgICBjcHViID0gY3VydmUuRzEuYWRkKGNwdWIsIElDMCk7XG5cbiAgICBjb25zdCBwaV9hID0gY3VydmUuRzEuZnJvbU9iamVjdChwcm9vZi5waV9hKTtcbiAgICBjb25zdCBwaV9iID0gY3VydmUuRzIuZnJvbU9iamVjdChwcm9vZi5waV9iKTtcbiAgICBjb25zdCBwaV9jID0gY3VydmUuRzEuZnJvbU9iamVjdChwcm9vZi5waV9jKTtcblxuICAgIGlmICghaXNXZWxsQ29uc3RydWN0ZWQoY3VydmUsIHtwaV9hLCBwaV9iLCBwaV9jfSkpIHtcbiAgICAgICAgaWYobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJQcm9vZiBjb21taXRtZW50cyBhcmUgbm90IHZhbGlkLlwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IHZrX2dhbW1hXzIgPSBjdXJ2ZS5HMi5mcm9tT2JqZWN0KHZrX3ZlcmlmaWVyLnZrX2dhbW1hXzIpO1xuICAgIGNvbnN0IHZrX2RlbHRhXzIgPSBjdXJ2ZS5HMi5mcm9tT2JqZWN0KHZrX3ZlcmlmaWVyLnZrX2RlbHRhXzIpO1xuICAgIGNvbnN0IHZrX2FscGhhXzEgPSBjdXJ2ZS5HMS5mcm9tT2JqZWN0KHZrX3ZlcmlmaWVyLnZrX2FscGhhXzEpO1xuICAgIGNvbnN0IHZrX2JldGFfMiA9IGN1cnZlLkcyLmZyb21PYmplY3QodmtfdmVyaWZpZXIudmtfYmV0YV8yKTtcblxuICAgIGNvbnN0IHJlcyA9IGF3YWl0IGN1cnZlLnBhaXJpbmdFcShcbiAgICAgICAgY3VydmUuRzEubmVnKHBpX2EpICwgcGlfYixcbiAgICAgICAgY3B1YiAsIHZrX2dhbW1hXzIsXG4gICAgICAgIHBpX2MgLCB2a19kZWx0YV8yLFxuXG4gICAgICAgIHZrX2FscGhhXzEsIHZrX2JldGFfMlxuICAgICk7XG5cbiAgICBpZiAoISByZXMpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSW52YWxpZCBwcm9vZlwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiT0shXCIpO1xuICAgIHJldHVybiB0cnVlO1xufVxuXG5mdW5jdGlvbiBpc1dlbGxDb25zdHJ1Y3RlZChjdXJ2ZSwgcHJvb2YpIHtcbiAgICBjb25zdCBHMSA9IGN1cnZlLkcxO1xuICAgIGNvbnN0IEcyID0gY3VydmUuRzI7XG5cbiAgICByZXR1cm4gRzEuaXNWYWxpZChwcm9vZi5waV9hKVxuICAgICAgICAmJiBHMi5pc1ZhbGlkKHByb29mLnBpX2IpXG4gICAgICAgICYmIEcxLmlzVmFsaWQocHJvb2YucGlfYyk7XG59XG5cbmZ1bmN0aW9uIGNoZWNrVmFsdWVCZWxvbmdUb0ZpZWxkKGN1cnZlLCB2YWx1ZSkge1xuICAgIHJldHVybiBTY2FsYXIuZ2VxKHZhbHVlLCAwKSAmJiBTY2FsYXIubHQodmFsdWUsIGN1cnZlLnIpO1xufVxuXG5mdW5jdGlvbiBwdWJsaWNJbnB1dHNBcmVWYWxpZChjdXJ2ZSwgcHVibGljSW5wdXRzKSB7XG4gICAgZm9yKGxldCBpID0gMDsgaSA8IHB1YmxpY0lucHV0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZighY2hlY2tWYWx1ZUJlbG9uZ1RvRmllbGQoY3VydmUsIHB1YmxpY0lucHV0c1tpXSkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5pbXBvcnQgeyAgdXRpbHMgfSAgIGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmNvbnN0IHsgdW5zdHJpbmdpZnlCaWdJbnRzfSA9IHV0aWxzO1xuXG5mdW5jdGlvbiBwMjU2KG4pIHtcbiAgICBsZXQgbnN0ciA9IG4udG9TdHJpbmcoMTYpO1xuICAgIHdoaWxlIChuc3RyLmxlbmd0aCA8IDY0KSBuc3RyID0gXCIwXCIrbnN0cjtcbiAgICBuc3RyID0gYFwiMHgke25zdHJ9XCJgO1xuICAgIHJldHVybiBuc3RyO1xufVxuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBncm90aDE2RXhwb3J0U29saWRpdHlDYWxsRGF0YShfcHJvb2YsIF9wdWIpIHtcbiAgICBjb25zdCBwcm9vZiA9IHVuc3RyaW5naWZ5QmlnSW50cyhfcHJvb2YpO1xuICAgIGNvbnN0IHB1YiA9IHVuc3RyaW5naWZ5QmlnSW50cyhfcHViKTtcblxuICAgIGxldCBpbnB1dHMgPSBcIlwiO1xuICAgIGZvciAobGV0IGk9MDsgaTxwdWIubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKGlucHV0cyAhPSBcIlwiKSBpbnB1dHMgPSBpbnB1dHMgKyBcIixcIjtcbiAgICAgICAgaW5wdXRzID0gaW5wdXRzICsgcDI1NihwdWJbaV0pO1xuICAgIH1cblxuICAgIGxldCBTO1xuICAgIFM9YFske3AyNTYocHJvb2YucGlfYVswXSl9LCAke3AyNTYocHJvb2YucGlfYVsxXSl9XSxgICtcbiAgICAgICAgYFtbJHtwMjU2KHByb29mLnBpX2JbMF1bMV0pfSwgJHtwMjU2KHByb29mLnBpX2JbMF1bMF0pfV0sWyR7cDI1Nihwcm9vZi5waV9iWzFdWzFdKX0sICR7cDI1Nihwcm9vZi5waV9iWzFdWzBdKX1dXSxgICtcbiAgICAgICAgYFske3AyNTYocHJvb2YucGlfY1swXSl9LCAke3AyNTYocHJvb2YucGlfY1sxXSl9XSxgICtcbiAgICAgICAgYFske2lucHV0c31dYDtcblxuICAgIHJldHVybiBTO1xufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuZXhwb3J0IHtkZWZhdWx0IGFzIGZ1bGxQcm92ZX0gZnJvbSBcIi4vZ3JvdGgxNl9mdWxscHJvdmUuanNcIjtcbmV4cG9ydCB7ZGVmYXVsdCBhcyBwcm92ZX0gZnJvbSBcIi4vZ3JvdGgxNl9wcm92ZS5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIHZlcmlmeX0gZnJvbSBcIi4vZ3JvdGgxNl92ZXJpZnkuanNcIjtcbmV4cG9ydCB7ZGVmYXVsdCBhcyBleHBvcnRTb2xpZGl0eUNhbGxEYXRhfSBmcm9tIFwiLi9ncm90aDE2X2V4cG9ydHNvbGlkaXR5Y2FsbGRhdGEuanNcIjtcbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCB7IGJsYWtlMmIgfSBmcm9tIFwiQG5vYmxlL2hhc2hlcy9ibGFrZTIuanNcIjtcblxuaW1wb3J0IHsgQ2hhQ2hhIH0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuXG5leHBvcnQgZnVuY3Rpb24gaGFzaFRvRzIoY3VydmUsIGhhc2gpIHtcbiAgICBjb25zdCBoYXNoViA9IG5ldyBEYXRhVmlldyhoYXNoLmJ1ZmZlciwgaGFzaC5ieXRlT2Zmc2V0LCBoYXNoLmJ5dGVMZW5ndGgpO1xuICAgIGNvbnN0IHNlZWQgPSBbXTtcbiAgICBmb3IgKGxldCBpPTA7IGk8ODsgaSsrKSB7XG4gICAgICAgIHNlZWRbaV0gPSBoYXNoVi5nZXRVaW50MzIoaSo0KTtcbiAgICB9XG5cbiAgICBjb25zdCBybmcgPSBuZXcgQ2hhQ2hhKHNlZWQpO1xuXG4gICAgY29uc3QgZzJfc3AgPSBjdXJ2ZS5HMi5mcm9tUm5nKHJuZyk7XG5cbiAgICByZXR1cm4gZzJfc3A7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRHMnNwKGN1cnZlLCBwZXJzaW5hbGl6YXRpb24sIGNoYWxsZW5nZSwgZzFzLCBnMXN4KSB7XG5cbiAgICBjb25zdCBoID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG4gICAgY29uc3QgYjEgPSBuZXcgVWludDhBcnJheShbcGVyc2luYWxpemF0aW9uXSk7XG4gICAgaC51cGRhdGUoYjEpO1xuICAgIGgudXBkYXRlKGNoYWxsZW5nZSk7XG4gICAgY29uc3QgYjMgPSBjdXJ2ZS5HMS50b1VuY29tcHJlc3NlZChnMXMpO1xuICAgIGgudXBkYXRlKCBiMyk7XG4gICAgY29uc3QgYjQgPSBjdXJ2ZS5HMS50b1VuY29tcHJlc3NlZChnMXN4KTtcbiAgICBoLnVwZGF0ZSggYjQpO1xuICAgIGNvbnN0IGhhc2ggPWguZGlnZXN0KCk7XG5cbiAgICByZXR1cm4gaGFzaFRvRzIoY3VydmUsIGhhc2gpO1xufVxuXG5mdW5jdGlvbiBjYWxjdWxhdGVQdWJLZXkoaywgY3VydmUsIHBlcnNvbmFsaXphdGlvbiwgY2hhbGxlbmdlSGFzaCwgcm5nICkge1xuICAgIGsuZzFfcyA9IGN1cnZlLkcxLnRvQWZmaW5lKGN1cnZlLkcxLmZyb21Sbmcocm5nKSk7XG4gICAgay5nMV9zeCA9IGN1cnZlLkcxLnRvQWZmaW5lKGN1cnZlLkcxLnRpbWVzRnIoay5nMV9zLCBrLnBydktleSkpO1xuICAgIGsuZzJfc3AgPSBjdXJ2ZS5HMi50b0FmZmluZShnZXRHMnNwKGN1cnZlLCBwZXJzb25hbGl6YXRpb24sIGNoYWxsZW5nZUhhc2gsIGsuZzFfcywgay5nMV9zeCkpO1xuICAgIGsuZzJfc3B4ID0gY3VydmUuRzIudG9BZmZpbmUoY3VydmUuRzIudGltZXNGcihrLmcyX3NwLCBrLnBydktleSkpO1xuICAgIHJldHVybiBrO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUFRhdUtleShjdXJ2ZSwgY2hhbGxlbmdlSGFzaCwgcm5nKSB7XG4gICAgY29uc3Qga2V5ID0ge1xuICAgICAgICB0YXU6IHt9LFxuICAgICAgICBhbHBoYToge30sXG4gICAgICAgIGJldGE6IHt9XG4gICAgfTtcbiAgICBrZXkudGF1LnBydktleSA9IGN1cnZlLkZyLmZyb21Sbmcocm5nKTtcbiAgICBrZXkuYWxwaGEucHJ2S2V5ID0gY3VydmUuRnIuZnJvbVJuZyhybmcpO1xuICAgIGtleS5iZXRhLnBydktleSA9IGN1cnZlLkZyLmZyb21Sbmcocm5nKTtcbiAgICBjYWxjdWxhdGVQdWJLZXkoa2V5LnRhdSwgY3VydmUsIDAsIGNoYWxsZW5nZUhhc2gsIHJuZyk7XG4gICAgY2FsY3VsYXRlUHViS2V5KGtleS5hbHBoYSwgY3VydmUsIDEsIGNoYWxsZW5nZUhhc2gsIHJuZyk7XG4gICAgY2FsY3VsYXRlUHViS2V5KGtleS5iZXRhLCBjdXJ2ZSwgMiwgY2hhbGxlbmdlSGFzaCwgcm5nKTtcbiAgICByZXR1cm4ga2V5O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRGVsdGFLZXkoY3VydmUsIHRyYW5zY3JpcHQsIHJuZykge1xuICAgIGNvbnN0IGRlbHRhID0ge307XG4gICAgZGVsdGEucHJ2S2V5ID0gY3VydmUuRnIuZnJvbVJuZyhybmcpO1xuICAgIGRlbHRhLmcxX3MgPSBjdXJ2ZS5HMS50b0FmZmluZShjdXJ2ZS5HMS5mcm9tUm5nKHJuZykpO1xuICAgIGRlbHRhLmcxX3N4ID0gY3VydmUuRzEudG9BZmZpbmUoY3VydmUuRzEudGltZXNTY2FsYXIoZGVsdGEuZzFfcywgZGVsdGEucHJ2S2V5KSk7XG4gICAgZGVsdGEuZzJfc3AgPSBoYXNoVG9HMihjdXJ2ZSwgdHJhbnNjcmlwdCk7XG4gICAgZGVsdGEuZzJfc3B4ID0gY3VydmUuRzIudG9BZmZpbmUoY3VydmUuRzIudGltZXNTY2FsYXIoZGVsdGEuZzJfc3AsIGRlbHRhLnBydktleSkpO1xuICAgIHJldHVybiBkZWx0YTtcbn1cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCB7IFNjYWxhciB9IGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmltcG9ydCB7IGJsYWtlMmIgfSBmcm9tIFwiQG5vYmxlL2hhc2hlcy9ibGFrZTIuanNcIjtcbmltcG9ydCAqIGFzIGtleVBhaXIgZnJvbSBcIi4va2V5cGFpci5qc1wiO1xuaW1wb3J0ICogYXMgbWlzYyBmcm9tIFwiLi9taXNjLmpzXCI7XG5pbXBvcnQgeyBnZXRDdXJ2ZUZyb21RIH0gZnJvbSBcIi4vY3VydmVzLmpzXCI7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZVBUYXVIZWFkZXIoZmQsIGN1cnZlLCBwb3dlciwgY2VyZW1vbnlQb3dlcikge1xuICAgIC8vIFdyaXRlIHRoZSBoZWFkZXJcbiAgICAvLy8vLy8vLy8vL1xuXG4gICAgaWYgKCEgY2VyZW1vbnlQb3dlcikgY2VyZW1vbnlQb3dlciA9IHBvd2VyO1xuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoMSk7IC8vIEhlYWRlciB0eXBlXG4gICAgY29uc3QgcEhlYWRlclNpemUgPSBmZC5wb3M7XG4gICAgYXdhaXQgZmQud3JpdGVVTEU2NCgwKTsgLy8gVGVtcG9yYWxseSBzZXQgdG8gMCBsZW5ndGhcblxuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoY3VydmUuRjEubjY0KjgpO1xuXG4gICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KGN1cnZlLkYxLm44KTtcbiAgICBTY2FsYXIudG9ScHJMRShidWZmLCAwLCBjdXJ2ZS5xLCBjdXJ2ZS5GMS5uOCk7XG4gICAgYXdhaXQgZmQud3JpdGUoYnVmZik7XG4gICAgYXdhaXQgZmQud3JpdGVVTEUzMihwb3dlcik7ICAgICAgICAgICAgICAgICAgICAvLyBwb3dlclxuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoY2VyZW1vbnlQb3dlcik7ICAgICAgICAgICAgICAgLy8gcG93ZXJcblxuICAgIGNvbnN0IGhlYWRlclNpemUgPSBmZC5wb3MgLSBwSGVhZGVyU2l6ZSAtIDg7XG5cbiAgICBjb25zdCBvbGRQb3MgPSBmZC5wb3M7XG5cbiAgICBhd2FpdCBmZC53cml0ZVVMRTY0KGhlYWRlclNpemUsIHBIZWFkZXJTaXplKTtcblxuICAgIGZkLnBvcyA9IG9sZFBvcztcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRQVGF1SGVhZGVyKGZkLCBzZWN0aW9ucykge1xuICAgIGlmICghc2VjdGlvbnNbMV0pICB0aHJvdyBuZXcgRXJyb3IoZmQuZmlsZU5hbWUgKyBcIjogRmlsZSBoYXMgbm8gIGhlYWRlclwiKTtcbiAgICBpZiAoc2VjdGlvbnNbMV0ubGVuZ3RoPjEpIHRocm93IG5ldyBFcnJvcihmZC5maWxlTmFtZSArXCI6IEZpbGUgaGFzIG1vcmUgdGhhbiBvbmUgaGVhZGVyXCIpO1xuXG4gICAgZmQucG9zID0gc2VjdGlvbnNbMV1bMF0ucDtcbiAgICBjb25zdCBuOCA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZC5yZWFkKG44KTtcbiAgICBjb25zdCBxID0gU2NhbGFyLmZyb21ScHJMRShidWZmKTtcblxuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgZ2V0Q3VydmVGcm9tUShxKTtcblxuICAgIGlmIChjdXJ2ZS5GMS5uNjQqOCAhPSBuOCkgdGhyb3cgbmV3IEVycm9yKGZkLmZpbGVOYW1lICtcIjogSW52YWxpZCBzaXplXCIpO1xuXG4gICAgY29uc3QgcG93ZXIgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICBjb25zdCBjZXJlbW9ueVBvd2VyID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG5cbiAgICBpZiAoZmQucG9zLXNlY3Rpb25zWzFdWzBdLnAgIT0gc2VjdGlvbnNbMV1bMF0uc2l6ZSkgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBQVGF1IGhlYWRlciBzaXplXCIpO1xuXG4gICAgcmV0dXJuIHtjdXJ2ZSwgcG93ZXIsIGNlcmVtb255UG93ZXJ9O1xufVxuXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkUHRhdVB1YktleShmZCwgY3VydmUsIG1vbnRnb21lcnkpIHtcblxuICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZC5yZWFkKGN1cnZlLkYxLm44KjIqNiArIGN1cnZlLkYyLm44KjIqMyk7XG5cbiAgICByZXR1cm4gZnJvbVB0YXVQdWJLZXlScHIoYnVmZiwgMCwgY3VydmUsIG1vbnRnb21lcnkpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZnJvbVB0YXVQdWJLZXlScHIoYnVmZiwgcG9zLCBjdXJ2ZSwgbW9udGdvbWVyeSkge1xuXG4gICAgY29uc3Qga2V5ID0ge1xuICAgICAgICB0YXU6IHt9LFxuICAgICAgICBhbHBoYToge30sXG4gICAgICAgIGJldGE6IHt9XG4gICAgfTtcblxuICAgIGtleS50YXUuZzFfcyA9IHJlYWRHMSgpO1xuICAgIGtleS50YXUuZzFfc3ggPSByZWFkRzEoKTtcbiAgICBrZXkuYWxwaGEuZzFfcyA9IHJlYWRHMSgpO1xuICAgIGtleS5hbHBoYS5nMV9zeCA9IHJlYWRHMSgpO1xuICAgIGtleS5iZXRhLmcxX3MgPSByZWFkRzEoKTtcbiAgICBrZXkuYmV0YS5nMV9zeCA9IHJlYWRHMSgpO1xuICAgIGtleS50YXUuZzJfc3B4ID0gcmVhZEcyKCk7XG4gICAga2V5LmFscGhhLmcyX3NweCA9IHJlYWRHMigpO1xuICAgIGtleS5iZXRhLmcyX3NweCA9IHJlYWRHMigpO1xuXG4gICAgcmV0dXJuIGtleTtcblxuICAgIGZ1bmN0aW9uIHJlYWRHMSgpIHtcbiAgICAgICAgbGV0IHA7XG4gICAgICAgIGlmIChtb250Z29tZXJ5KSB7XG4gICAgICAgICAgICBwID0gY3VydmUuRzEuZnJvbVJwckxFTSggYnVmZiwgcG9zICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwID0gY3VydmUuRzEuZnJvbVJwclVuY29tcHJlc3NlZCggYnVmZiwgcG9zICk7XG4gICAgICAgIH1cbiAgICAgICAgcG9zICs9IGN1cnZlLkcxLkYubjgqMjtcbiAgICAgICAgcmV0dXJuIHA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVhZEcyKCkge1xuICAgICAgICBsZXQgcDtcbiAgICAgICAgaWYgKG1vbnRnb21lcnkpIHtcbiAgICAgICAgICAgIHAgPSBjdXJ2ZS5HMi5mcm9tUnByTEVNKCBidWZmLCBwb3MgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHAgPSBjdXJ2ZS5HMi5mcm9tUnByVW5jb21wcmVzc2VkKCBidWZmLCBwb3MgKTtcbiAgICAgICAgfVxuICAgICAgICBwb3MgKz0gY3VydmUuRzIuRi5uOCoyO1xuICAgICAgICByZXR1cm4gcDtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0b1B0YXVQdWJLZXlScHIoYnVmZiwgcG9zLCBjdXJ2ZSwga2V5LCBtb250Z29tZXJ5KSB7XG5cbiAgICB3cml0ZUcxKGtleS50YXUuZzFfcyk7XG4gICAgd3JpdGVHMShrZXkudGF1LmcxX3N4KTtcbiAgICB3cml0ZUcxKGtleS5hbHBoYS5nMV9zKTtcbiAgICB3cml0ZUcxKGtleS5hbHBoYS5nMV9zeCk7XG4gICAgd3JpdGVHMShrZXkuYmV0YS5nMV9zKTtcbiAgICB3cml0ZUcxKGtleS5iZXRhLmcxX3N4KTtcbiAgICB3cml0ZUcyKGtleS50YXUuZzJfc3B4KTtcbiAgICB3cml0ZUcyKGtleS5hbHBoYS5nMl9zcHgpO1xuICAgIHdyaXRlRzIoa2V5LmJldGEuZzJfc3B4KTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlRzEocCkge1xuICAgICAgICBpZiAobW9udGdvbWVyeSkge1xuICAgICAgICAgICAgY3VydmUuRzEudG9ScHJMRU0oYnVmZiwgcG9zLCBwKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGN1cnZlLkcxLnRvUnByVW5jb21wcmVzc2VkKGJ1ZmYsIHBvcywgcCk7XG4gICAgICAgIH1cbiAgICAgICAgcG9zICs9IGN1cnZlLkYxLm44KjI7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gd3JpdGVHMihwKSB7XG4gICAgICAgIGlmIChtb250Z29tZXJ5KSB7XG4gICAgICAgICAgICBjdXJ2ZS5HMi50b1JwckxFTShidWZmLCBwb3MsIHApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY3VydmUuRzIudG9ScHJVbmNvbXByZXNzZWQoYnVmZiwgcG9zLCBwKTtcbiAgICAgICAgfVxuICAgICAgICBwb3MgKz0gY3VydmUuRjIubjgqMjtcbiAgICB9XG5cbiAgICByZXR1cm4gYnVmZjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdyaXRlUHRhdVB1YktleShmZCwgY3VydmUsIGtleSwgbW9udGdvbWVyeSkge1xuICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShjdXJ2ZS5GMS5uOCoyKjYgKyBjdXJ2ZS5GMi5uOCoyKjMpO1xuICAgIHRvUHRhdVB1YktleVJwcihidWZmLCAwLCBjdXJ2ZSwga2V5LCBtb250Z29tZXJ5KTtcbiAgICBhd2FpdCBmZC53cml0ZShidWZmKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZENvbnRyaWJ1dGlvbihmZCwgY3VydmUpIHtcbiAgICBjb25zdCBjID0ge307XG5cbiAgICBjLnRhdUcxID0gYXdhaXQgcmVhZEcxKCk7XG4gICAgYy50YXVHMiA9IGF3YWl0IHJlYWRHMigpO1xuICAgIGMuYWxwaGFHMSA9IGF3YWl0IHJlYWRHMSgpO1xuICAgIGMuYmV0YUcxID0gYXdhaXQgcmVhZEcxKCk7XG4gICAgYy5iZXRhRzIgPSBhd2FpdCByZWFkRzIoKTtcbiAgICBjLmtleSA9IGF3YWl0IHJlYWRQdGF1UHViS2V5KGZkLCBjdXJ2ZSwgdHJ1ZSk7XG4gICAgYy5wYXJ0aWFsSGFzaCA9IGF3YWl0IGZkLnJlYWQoMjE2KTtcbiAgICBjLm5leHRDaGFsbGVuZ2UgPSBhd2FpdCBmZC5yZWFkKDY0KTtcbiAgICBjLnR5cGUgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcblxuICAgIGNvbnN0IGJ1ZmZWICA9IG5ldyBVaW50OEFycmF5KGN1cnZlLkcxLkYubjgqMio2K2N1cnZlLkcyLkYubjgqMiozKTtcbiAgICB0b1B0YXVQdWJLZXlScHIoYnVmZlYsIDAsIGN1cnZlLCBjLmtleSwgZmFsc2UpO1xuXG4gICAgY29uc3QgcmVzcG9uc2VIYXNoZXIgPSAgbWlzYy5mcm9tUGFydGlhbEhhc2goYy5wYXJ0aWFsSGFzaCk7XG4gICAgcmVzcG9uc2VIYXNoZXIudXBkYXRlKGJ1ZmZWKTtcbiAgICBjLnJlc3BvbnNlSGFzaCA9IHJlc3BvbnNlSGFzaGVyLmRpZ2VzdCgpO1xuXG4gICAgY29uc3QgcGFyYW1MZW5ndGggPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICBjb25zdCBjdXJQb3MgPSBmZC5wb3M7XG4gICAgbGV0IGxhc3RUeXBlID0wO1xuICAgIHdoaWxlIChmZC5wb3MtY3VyUG9zIDwgcGFyYW1MZW5ndGgpIHtcbiAgICAgICAgY29uc3QgYnVmZlR5cGUgPSBhd2FpdCByZWFkRFYoMSk7XG4gICAgICAgIGlmIChidWZmVHlwZVswXTw9IGxhc3RUeXBlKSB0aHJvdyBuZXcgRXJyb3IoXCJQYXJhbWV0ZXJzIGluIHRoZSBjb250cmlidXRpb24gbXVzdCBiZSBzb3J0ZWRcIik7XG4gICAgICAgIGxhc3RUeXBlID0gYnVmZlR5cGVbMF07XG4gICAgICAgIGlmIChidWZmVHlwZVswXT09MSkgeyAgICAgLy8gTmFtZVxuICAgICAgICAgICAgY29uc3QgYnVmZkxlbiA9IGF3YWl0IHJlYWREVigxKTtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZTdHIgPSBhd2FpdCByZWFkRFYoYnVmZkxlblswXSk7XG4gICAgICAgICAgICBjLm5hbWUgPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoYnVmZlN0cik7XG4gICAgICAgIH0gZWxzZSBpZiAoYnVmZlR5cGVbMF09PTIpIHtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZFeHAgPSBhd2FpdCByZWFkRFYoMSk7XG4gICAgICAgICAgICBjLm51bUl0ZXJhdGlvbnNFeHAgPSBidWZmRXhwWzBdO1xuICAgICAgICB9IGVsc2UgaWYgKGJ1ZmZUeXBlWzBdPT0zKSB7XG4gICAgICAgICAgICBjb25zdCBidWZmTGVuID0gYXdhaXQgcmVhZERWKDEpO1xuICAgICAgICAgICAgYy5iZWFjb25IYXNoID0gYXdhaXQgcmVhZERWKGJ1ZmZMZW5bMF0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUGFyYW1ldGVyIG5vdCByZWNvZ25pemVkXCIpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChmZC5wb3MgIT0gY3VyUG9zICsgcGFyYW1MZW5ndGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUGFyYW1ldGVycyBkbyBub3QgbWF0Y2hcIik7XG4gICAgfVxuXG4gICAgcmV0dXJuIGM7XG5cbiAgICBhc3luYyBmdW5jdGlvbiByZWFkRzEoKSB7XG4gICAgICAgIGNvbnN0IHBCdWZmID0gYXdhaXQgZmQucmVhZChjdXJ2ZS5HMS5GLm44KjIpO1xuICAgICAgICByZXR1cm4gY3VydmUuRzEuZnJvbVJwckxFTSggcEJ1ZmYgKTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiByZWFkRzIoKSB7XG4gICAgICAgIGNvbnN0IHBCdWZmID0gYXdhaXQgZmQucmVhZChjdXJ2ZS5HMi5GLm44KjIpO1xuICAgICAgICByZXR1cm4gY3VydmUuRzIuZnJvbVJwckxFTSggcEJ1ZmYgKTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiByZWFkRFYobikge1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgZmQucmVhZChuKTtcbiAgICAgICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KGIpO1xuICAgIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRDb250cmlidXRpb25zKGZkLCBjdXJ2ZSwgc2VjdGlvbnMpIHtcbiAgICBpZiAoIXNlY3Rpb25zWzddKSAgdGhyb3cgbmV3IEVycm9yKGZkLmZpbGVOYW1lICsgXCI6IEZpbGUgaGFzIG5vICBjb250cmlidXRpb25zXCIpO1xuICAgIGlmIChzZWN0aW9uc1s3XVswXS5sZW5ndGg+MSkgdGhyb3cgbmV3IEVycm9yKGZkLmZpbGVOYW1lICtcIjogRmlsZSBoYXMgbW9yZSB0aGFuIG9uZSBjb250cmlidXRpb25zIHNlY3Rpb25cIik7XG5cbiAgICBmZC5wb3MgPSBzZWN0aW9uc1s3XVswXS5wO1xuICAgIGNvbnN0IG5Db250cmlidXRpb25zID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgY29uc3QgY29udHJpYnV0aW9ucyA9IFtdO1xuICAgIGZvciAobGV0IGk9MDsgaTxuQ29udHJpYnV0aW9uczsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGMgPSBhd2FpdCByZWFkQ29udHJpYnV0aW9uKGZkLCBjdXJ2ZSk7XG4gICAgICAgIGMuaWQgPSBpKzE7XG4gICAgICAgIGNvbnRyaWJ1dGlvbnMucHVzaChjKTtcbiAgICB9XG5cbiAgICBpZiAoZmQucG9zLXNlY3Rpb25zWzddWzBdLnAgIT0gc2VjdGlvbnNbN11bMF0uc2l6ZSkgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBjb250cmlidXRpb24gc2VjdGlvbiBzaXplXCIpO1xuXG4gICAgcmV0dXJuIGNvbnRyaWJ1dGlvbnM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHdyaXRlQ29udHJpYnV0aW9uKGZkLCBjdXJ2ZSwgY29udHJpYnV0aW9uKSB7XG5cbiAgICBjb25zdCBidWZmRzEgPSBuZXcgVWludDhBcnJheShjdXJ2ZS5GMS5uOCoyKTtcbiAgICBjb25zdCBidWZmRzIgPSBuZXcgVWludDhBcnJheShjdXJ2ZS5GMi5uOCoyKTtcbiAgICBhd2FpdCB3cml0ZUcxKGNvbnRyaWJ1dGlvbi50YXVHMSk7XG4gICAgYXdhaXQgd3JpdGVHMihjb250cmlidXRpb24udGF1RzIpO1xuICAgIGF3YWl0IHdyaXRlRzEoY29udHJpYnV0aW9uLmFscGhhRzEpO1xuICAgIGF3YWl0IHdyaXRlRzEoY29udHJpYnV0aW9uLmJldGFHMSk7XG4gICAgYXdhaXQgd3JpdGVHMihjb250cmlidXRpb24uYmV0YUcyKTtcbiAgICBhd2FpdCB3cml0ZVB0YXVQdWJLZXkoZmQsIGN1cnZlLCBjb250cmlidXRpb24ua2V5LCB0cnVlKTtcbiAgICBhd2FpdCBmZC53cml0ZShjb250cmlidXRpb24ucGFydGlhbEhhc2gpO1xuICAgIGF3YWl0IGZkLndyaXRlKGNvbnRyaWJ1dGlvbi5uZXh0Q2hhbGxlbmdlKTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKGNvbnRyaWJ1dGlvbi50eXBlIHx8IDApO1xuXG4gICAgY29uc3QgcGFyYW1zID0gW107XG4gICAgaWYgKGNvbnRyaWJ1dGlvbi5uYW1lKSB7XG4gICAgICAgIHBhcmFtcy5wdXNoKDEpOyAgICAgIC8vIFBhcmFtIE5hbWVcbiAgICAgICAgY29uc3QgbmFtZURhdGEgPSBuZXcgVGV4dEVuY29kZXIoXCJ1dGYtOFwiKS5lbmNvZGUoY29udHJpYnV0aW9uLm5hbWUuc3Vic3RyaW5nKDAsNjQpKTtcbiAgICAgICAgcGFyYW1zLnB1c2gobmFtZURhdGEuYnl0ZUxlbmd0aCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxuYW1lRGF0YS5ieXRlTGVuZ3RoOyBpKyspIHBhcmFtcy5wdXNoKG5hbWVEYXRhW2ldKTtcbiAgICB9XG4gICAgaWYgKGNvbnRyaWJ1dGlvbi50eXBlID09IDEpIHtcbiAgICAgICAgcGFyYW1zLnB1c2goMik7ICAgICAgLy8gUGFyYW0gbnVtSXRlcmF0aW9uc0V4cFxuICAgICAgICBwYXJhbXMucHVzaChjb250cmlidXRpb24ubnVtSXRlcmF0aW9uc0V4cCk7XG5cbiAgICAgICAgcGFyYW1zLnB1c2goMyk7ICAgICAgLy8gQmVhY29uIEhhc2hcbiAgICAgICAgcGFyYW1zLnB1c2goY29udHJpYnV0aW9uLmJlYWNvbkhhc2guYnl0ZUxlbmd0aCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxjb250cmlidXRpb24uYmVhY29uSGFzaC5ieXRlTGVuZ3RoOyBpKyspIHBhcmFtcy5wdXNoKGNvbnRyaWJ1dGlvbi5iZWFjb25IYXNoW2ldKTtcbiAgICB9XG4gICAgaWYgKHBhcmFtcy5sZW5ndGg+MCkge1xuICAgICAgICBjb25zdCBwYXJhbXNCdWZmID0gbmV3IFVpbnQ4QXJyYXkocGFyYW1zKTtcbiAgICAgICAgYXdhaXQgZmQud3JpdGVVTEUzMihwYXJhbXNCdWZmLmJ5dGVMZW5ndGgpO1xuICAgICAgICBhd2FpdCBmZC53cml0ZShwYXJhbXNCdWZmKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBhd2FpdCBmZC53cml0ZVVMRTMyKDApO1xuICAgIH1cblxuXG4gICAgYXN5bmMgZnVuY3Rpb24gd3JpdGVHMShwKSB7XG4gICAgICAgIGN1cnZlLkcxLnRvUnByTEVNKGJ1ZmZHMSwgMCwgcCk7XG4gICAgICAgIGF3YWl0IGZkLndyaXRlKGJ1ZmZHMSk7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gd3JpdGVHMihwKSB7XG4gICAgICAgIGN1cnZlLkcyLnRvUnByTEVNKGJ1ZmZHMiwgMCwgcCk7XG4gICAgICAgIGF3YWl0IGZkLndyaXRlKGJ1ZmZHMik7XG4gICAgfVxuXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZUNvbnRyaWJ1dGlvbnMoZmQsIGN1cnZlLCBjb250cmlidXRpb25zKSB7XG5cbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKDcpOyAvLyBIZWFkZXIgdHlwZVxuICAgIGNvbnN0IHBDb250cmlidXRpb25zU2l6ZSA9IGZkLnBvcztcbiAgICBhd2FpdCBmZC53cml0ZVVMRTY0KDApOyAvLyBUZW1wb3JhbGx5IHNldCB0byAwIGxlbmd0aFxuXG4gICAgYXdhaXQgZmQud3JpdGVVTEUzMihjb250cmlidXRpb25zLmxlbmd0aCk7XG4gICAgZm9yIChsZXQgaT0wOyBpPCBjb250cmlidXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGF3YWl0IHdyaXRlQ29udHJpYnV0aW9uKGZkLCBjdXJ2ZSwgY29udHJpYnV0aW9uc1tpXSk7XG4gICAgfVxuICAgIGNvbnN0IGNvbnRyaWJ1dGlvbnNTaXplID0gZmQucG9zIC0gcENvbnRyaWJ1dGlvbnNTaXplIC0gODtcblxuICAgIGNvbnN0IG9sZFBvcyA9IGZkLnBvcztcblxuICAgIGF3YWl0IGZkLndyaXRlVUxFNjQoY29udHJpYnV0aW9uc1NpemUsIHBDb250cmlidXRpb25zU2l6ZSk7XG4gICAgZmQucG9zID0gb2xkUG9zO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FsY3VsYXRlRmlyc3RDaGFsbGVuZ2VIYXNoKGN1cnZlLCBwb3dlciwgbG9nZ2VyKSB7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiQ2FsY3VsYXRpbmcgRmlyc3QgQ2hhbGxlbmdlIEhhc2hcIik7XG5cbiAgICBjb25zdCBoYXNoZXIgPSBibGFrZTJiLmNyZWF0ZSh7IGRrTGVuOiA2NCB9KTtcblxuICAgIGNvbnN0IHZHMSA9IG5ldyBVaW50OEFycmF5KGN1cnZlLkcxLkYubjgqMik7XG4gICAgY29uc3QgdkcyID0gbmV3IFVpbnQ4QXJyYXkoY3VydmUuRzIuRi5uOCoyKTtcbiAgICBjdXJ2ZS5HMS50b1JwclVuY29tcHJlc3NlZCh2RzEsIDAsIGN1cnZlLkcxLmcpO1xuICAgIGN1cnZlLkcyLnRvUnByVW5jb21wcmVzc2VkKHZHMiwgMCwgY3VydmUuRzIuZyk7XG5cbiAgICBoYXNoZXIudXBkYXRlKGJsYWtlMmIuY3JlYXRlKHsgZGtMZW46IDY0IH0pLmRpZ2VzdCgpKTtcblxuICAgIGxldCBuO1xuXG4gICAgbj0oMiAqKiBwb3dlcikqMiAtMTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJDYWxjdWxhdGUgSW5pdGlhbCBIYXNoOiB0YXVHMVwiKTtcbiAgICBoYXNoQmxvY2sodkcxLCBuKTtcbiAgICBuPSAyICoqIHBvd2VyO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIkNhbGN1bGF0ZSBJbml0aWFsIEhhc2g6IHRhdUcyXCIpO1xuICAgIGhhc2hCbG9jayh2RzIsIG4pO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIkNhbGN1bGF0ZSBJbml0aWFsIEhhc2g6IGFscGhhVGF1RzFcIik7XG4gICAgaGFzaEJsb2NrKHZHMSwgbik7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiQ2FsY3VsYXRlIEluaXRpYWwgSGFzaDogYmV0YVRhdUcxXCIpO1xuICAgIGhhc2hCbG9jayh2RzEsIG4pO1xuICAgIGhhc2hlci51cGRhdGUodkcyKTtcblxuICAgIHJldHVybiBoYXNoZXIuZGlnZXN0KCk7XG5cbiAgICBmdW5jdGlvbiBoYXNoQmxvY2soYnVmZiwgbikge1xuICAgICAgICAvLyB0aGlzIGJsb2NrIHNpemUgaXMgYSBnb29kIGNvbXByb21pc2UgYmV0d2VlbiBzcGVlZCBhbmQgdGhlIG1heGltdW1cbiAgICAgICAgLy8gaW5wdXQgc2l6ZSBvZiB0aGUgQmxha2UyYiB1cGRhdGUgbWV0aG9kICg2NSw1MzUsNzIwIGJ5dGVzKS5cbiAgICAgICAgY29uc3QgYmxvY2tTaXplID0gMzQxMDAwO1xuICAgICAgICBjb25zdCBuQmxvY2tzID0gTWF0aC5mbG9vcihuIC8gYmxvY2tTaXplKTtcbiAgICAgICAgY29uc3QgcmVtID0gbiAlIGJsb2NrU2l6ZTtcbiAgICAgICAgY29uc3QgYmlnQnVmZiA9IG5ldyBVaW50OEFycmF5KGJsb2NrU2l6ZSAqIGJ1ZmYuYnl0ZUxlbmd0aCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxibG9ja1NpemU7IGkrKykge1xuICAgICAgICAgICAgYmlnQnVmZi5zZXQoYnVmZiwgaSpidWZmLmJ5dGVMZW5ndGgpO1xuICAgICAgICB9XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxuQmxvY2tzOyBpKyspIHtcbiAgICAgICAgICAgIGhhc2hlci51cGRhdGUoYmlnQnVmZik7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJJbml0aWFsIGhhc2g6IFwiICtpKmJsb2NrU2l6ZSk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHJlbTsgaSsrKSB7XG4gICAgICAgICAgICBoYXNoZXIudXBkYXRlKGJ1ZmYpO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBrZXlGcm9tQmVhY29uKGN1cnZlLCBjaGFsbGVuZ2VIYXNoLCBiZWFjb25IYXNoLCBudW1JdGVyYXRpb25zRXhwKSB7XG5cbiAgICBjb25zdCBybmcgPSBhd2FpdCBtaXNjLnJuZ0Zyb21CZWFjb25QYXJhbXMoYmVhY29uSGFzaCwgbnVtSXRlcmF0aW9uc0V4cCk7XG5cbiAgICBjb25zdCBrZXkgPSBrZXlQYWlyLmNyZWF0ZVBUYXVLZXkoY3VydmUsIGNoYWxsZW5nZUhhc2gsIHJuZyk7XG5cbiAgICByZXR1cm4ga2V5O1xufVxuXG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG4vKlxuSGVhZGVyKDEpXG4gICAgbjhcbiAgICBwcmltZVxuICAgIHBvd2VyXG50YXVHMSgyKVxuICAgIHsoMiAqKiBwb3dlcikqMi0xfSBbXG4gICAgICAgIEcxLCB0YXUqRzEsIHRhdV4yICogRzEsIC4uLi5cbiAgICBdXG50YXVHMigzKVxuICAgIHsyICoqIHBvd2VyfVtcbiAgICAgICAgRzIsIHRhdSpHMiwgdGF1XjIgKiBHMiwgLi4uXG4gICAgXVxuYWxwaGFUYXVHMSg0KVxuICAgIHsyICoqIHBvd2VyfVtcbiAgICAgICAgYWxwaGEqRzEsIGFscGhhKnRhdSpHMSwgYWxwaGEqdGF1XjIqRzEsLi4uLlxuICAgIF1cbmJldGFUYXVHMSg1KVxuICAgIHsyICoqIHBvd2VyfSBbXVxuICAgICAgICBiZXRhKkcxLCBiZXRhKnRhdSpHMSwgYmV0YSp0YXVeMipHMSwgLi4uLlxuICAgIF1cbmJldGFHMig2KVxuICAgIHsxfVtcbiAgICAgICAgYmV0YSpHMlxuICAgIF1cbmNvbnRyaWJ1dGlvbnMoNylcbiAgICBOQ29udHJpYnV0aW9uc1xuICAgIHtOQ29udHJpYnV0aW9uc31bXG4gICAgICAgIHRhdSpHMVxuICAgICAgICB0YXUqRzJcbiAgICAgICAgYWxwaGEqRzFcbiAgICAgICAgYmV0YSpHMVxuICAgICAgICBiZXRhKkcyXG4gICAgICAgIHB1YktleVxuICAgICAgICAgICAgdGF1X2cxc1xuICAgICAgICAgICAgdGF1X2cxc3hcbiAgICAgICAgICAgIHRhdV9nMnNweFxuICAgICAgICAgICAgYWxwaGFfZzFzXG4gICAgICAgICAgICBhbHBoYV9nMXN4XG4gICAgICAgICAgICBhbHBoYV9nMXNweFxuICAgICAgICAgICAgYmV0YV9nMXNcbiAgICAgICAgICAgIGJldGFfZzFzeFxuICAgICAgICAgICAgYmV0YV9nMXNweFxuICAgICAgICBwYXJ0aWFsSGFzaCAoMjE2IGJ5dGVzKSBTZWUgaHR0cHM6Ly9naXRodWIuY29tL21hZmludG9zaC9ibGFrZTJiLXdhc20vYmxvYi8yM2JlZTA2OTQ1ODA2MzA5OTc3YWY4MDJiYzM3NDcyNzU0MjYxN2M3L2JsYWtlMmIud2F0I0w5XG4gICAgICAgIGhhc2hOZXdDaGFsbGVuZ2VcbiAgICBdXG4gKi9cblxuaW1wb3J0ICogYXMgcHRhdVV0aWxzIGZyb20gXCIuL3Bvd2Vyc29mdGF1X3V0aWxzLmpzXCI7XG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCB7IGJsYWtlMmIgfSBmcm9tIFwiQG5vYmxlL2hhc2hlcy9ibGFrZTIuanNcIjtcbmltcG9ydCAqIGFzIG1pc2MgZnJvbSBcIi4vbWlzYy5qc1wiO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBuZXdBY2N1bXVsYXRvcihjdXJ2ZSwgcG93ZXIsIGZpbGVOYW1lLCBsb2dnZXIpIHtcblxuICAgIGNvbnN0IGZkID0gYXdhaXQgYmluRmlsZVV0aWxzLmNyZWF0ZUJpbkZpbGUoZmlsZU5hbWUsIFwicHRhdVwiLCAxLCA3KTtcblxuICAgIGF3YWl0IHB0YXVVdGlscy53cml0ZVBUYXVIZWFkZXIoZmQsIGN1cnZlLCBwb3dlciwgMCk7XG5cbiAgICBjb25zdCBidWZmRzEgPSBjdXJ2ZS5HMS5vbmVBZmZpbmU7XG4gICAgY29uc3QgYnVmZkcyID0gY3VydmUuRzIub25lQWZmaW5lO1xuXG4gICAgLy8gV3JpdGUgdGF1RzFcbiAgICAvLy8vLy8vLy8vL1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZCwgMik7XG4gICAgY29uc3QgblRhdUcxID0gKDIgKiogcG93ZXIpICogMiAtMTtcbiAgICBmb3IgKGxldCBpPTA7IGk8IG5UYXVHMTsgaSsrKSB7XG4gICAgICAgIGF3YWl0IGZkLndyaXRlKGJ1ZmZHMSk7XG4gICAgICAgIGlmICgobG9nZ2VyKSYmKChpJTEwMDAwMCkgPT0gMCkmJmkpIGxvZ2dlci5sb2coXCJ0YXVHMTogXCIgKyBpKTtcbiAgICB9XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFdyaXRlU2VjdGlvbihmZCk7XG5cbiAgICAvLyBXcml0ZSB0YXVHMlxuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkLCAzKTtcbiAgICBjb25zdCBuVGF1RzIgPSAoMiAqKiBwb3dlcik7XG4gICAgZm9yIChsZXQgaT0wOyBpPCBuVGF1RzI7IGkrKykge1xuICAgICAgICBhd2FpdCBmZC53cml0ZShidWZmRzIpO1xuICAgICAgICBpZiAoKGxvZ2dlcikmJigoaSUxMDAwMDApID09IDApJiZpKSBsb2dnZXIubG9nKFwidGF1RzI6IFwiICsgaSk7XG4gICAgfVxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmQpO1xuXG4gICAgLy8gV3JpdGUgYWxwaGFUYXVHMVxuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkLCA0KTtcbiAgICBjb25zdCBuQWxmYVRhdUcxID0gKDIgKiogcG93ZXIpO1xuICAgIGZvciAobGV0IGk9MDsgaTwgbkFsZmFUYXVHMTsgaSsrKSB7XG4gICAgICAgIGF3YWl0IGZkLndyaXRlKGJ1ZmZHMSk7XG4gICAgICAgIGlmICgobG9nZ2VyKSYmKChpJTEwMDAwMCkgPT0gMCkmJmkpIGxvZ2dlci5sb2coXCJhbHBoYVRhdUcxOiBcIiArIGkpO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkKTtcblxuICAgIC8vIFdyaXRlIGJldGFUYXVHMVxuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkLCA1KTtcbiAgICBjb25zdCBuQmV0YVRhdUcxID0gKDIgKiogcG93ZXIpO1xuICAgIGZvciAobGV0IGk9MDsgaTwgbkJldGFUYXVHMTsgaSsrKSB7XG4gICAgICAgIGF3YWl0IGZkLndyaXRlKGJ1ZmZHMSk7XG4gICAgICAgIGlmICgobG9nZ2VyKSYmKChpJTEwMDAwMCkgPT0gMCkmJmkpIGxvZ2dlci5sb2coXCJiZXRhVGF1RzE6IFwiICsgaSk7XG4gICAgfVxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmQpO1xuXG4gICAgLy8gV3JpdGUgYmV0YUcyXG4gICAgLy8vLy8vLy8vLy9cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24oZmQsIDYpO1xuICAgIGF3YWl0IGZkLndyaXRlKGJ1ZmZHMik7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFdyaXRlU2VjdGlvbihmZCk7XG5cbiAgICAvLyBDb250cmlidXRpb25zXG4gICAgLy8vLy8vLy8vLy9cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24oZmQsIDcpO1xuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoMCk7IC8vIDAgQ29udHJpYnV0aW9uc1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmQpO1xuXG4gICAgYXdhaXQgZmQuY2xvc2UoKTtcblxuICAgIGNvbnN0IGZpcnN0Q2hhbGxlbmdlSGFzaCA9IHB0YXVVdGlscy5jYWxjdWxhdGVGaXJzdENoYWxsZW5nZUhhc2goY3VydmUsIHBvd2VyLCBsb2dnZXIpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKG1pc2MuZm9ybWF0SGFzaChibGFrZTJiLmNyZWF0ZSh7IGRrTGVuOiA2NCB9KS5kaWdlc3QoKSwgXCJCbGFuayBDb250cmlidXRpb24gSGFzaDpcIikpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKGZpcnN0Q2hhbGxlbmdlSGFzaCwgXCJGaXJzdCBDb250cmlidXRpb24gSGFzaDpcIikpO1xuXG4gICAgcmV0dXJuIGZpcnN0Q2hhbGxlbmdlSGFzaDtcblxufVxuIiwiLy8gRm9ybWF0IG9mIHRoZSBvdXRwdVxuLy8gICAgIEhhc2ggb2YgdGhlIGxhc3QgY29udHJpYnV0aW9uICA2NEJ5dGVzXG4vLyAgICAgMl5OICogMiAtMSAgVGF1RzEgcG9pbnRzICh1bmNvbXByZXNzZWQpXG4vLyAgICAgMl5OICBUYXVHMiBQb2ludHMgKHVuY29tcHJlc3NlZClcbi8vICAgICAyXk4gIEFscGhhVGF1RzEgUG9pbnRzICh1bmNvbXByZXNzZWQpXG4vLyAgICAgMl5OICBCZXRhVGF1RzEgUG9pbnRzICh1bmNvbXByZXNzZWQpXG4vLyAgICAgQmV0YUcyICh1bmNvbXByZXNzZWQpXG5cbmltcG9ydCAqIGFzIGZhc3RGaWxlIGZyb20gXCJmYXN0ZmlsZVwiO1xuaW1wb3J0IHsgYmxha2UyYiB9IGZyb20gXCJAbm9ibGUvaGFzaGVzL2JsYWtlMi5qc1wiO1xuaW1wb3J0ICogYXMgdXRpbHMgZnJvbSBcIi4vcG93ZXJzb2Z0YXVfdXRpbHMuanNcIjtcbmltcG9ydCAqIGFzIGJpbkZpbGVVdGlscyBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuaW1wb3J0ICogYXMgbWlzYyBmcm9tIFwiLi9taXNjLmpzXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIGV4cG9ydENoYWxsZW5nZShwVGF1RmlsZW5hbWUsIGNoYWxsZW5nZUZpbGVuYW1lLCBsb2dnZXIpIHtcbiAgICBjb25zdCB7ZmQ6IGZkRnJvbSwgc2VjdGlvbnN9ID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRCaW5GaWxlKHBUYXVGaWxlbmFtZSwgXCJwdGF1XCIsIDEpO1xuXG4gICAgY29uc3Qge2N1cnZlLCBwb3dlcn0gPSBhd2FpdCB1dGlscy5yZWFkUFRhdUhlYWRlcihmZEZyb20sIHNlY3Rpb25zKTtcblxuICAgIGNvbnN0IGNvbnRyaWJ1dGlvbnMgPSBhd2FpdCB1dGlscy5yZWFkQ29udHJpYnV0aW9ucyhmZEZyb20sIGN1cnZlLCBzZWN0aW9ucyk7XG4gICAgbGV0IGxhc3RSZXNwb25zZUhhc2gsIGN1ckNoYWxsZW5nZUhhc2g7XG4gICAgaWYgKGNvbnRyaWJ1dGlvbnMubGVuZ3RoID09IDApIHtcbiAgICAgICAgbGFzdFJlc3BvbnNlSGFzaCA9IGJsYWtlMmIuY3JlYXRlKHsgZGtMZW46IDY0IH0pLmRpZ2VzdCgpO1xuICAgICAgICBjdXJDaGFsbGVuZ2VIYXNoID0gdXRpbHMuY2FsY3VsYXRlRmlyc3RDaGFsbGVuZ2VIYXNoKGN1cnZlLCBwb3dlcik7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbGFzdFJlc3BvbnNlSGFzaCA9IGNvbnRyaWJ1dGlvbnNbY29udHJpYnV0aW9ucy5sZW5ndGgtMV0ucmVzcG9uc2VIYXNoO1xuICAgICAgICBjdXJDaGFsbGVuZ2VIYXNoID0gY29udHJpYnV0aW9uc1tjb250cmlidXRpb25zLmxlbmd0aC0xXS5uZXh0Q2hhbGxlbmdlO1xuICAgIH1cblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1pc2MuZm9ybWF0SGFzaChsYXN0UmVzcG9uc2VIYXNoLCBcIkxhc3QgUmVzcG9uc2UgSGFzaDogXCIpKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1pc2MuZm9ybWF0SGFzaChjdXJDaGFsbGVuZ2VIYXNoLCBcIk5ldyBDaGFsbGVuZ2UgSGFzaDogXCIpKTtcblxuXG4gICAgY29uc3QgZmRUbyA9IGF3YWl0IGZhc3RGaWxlLmNyZWF0ZU92ZXJyaWRlKGNoYWxsZW5nZUZpbGVuYW1lKTtcblxuICAgIGNvbnN0IHRvSGFzaCA9IGJsYWtlMmIuY3JlYXRlKHsgZGtMZW46IDY0IH0pO1xuICAgIGF3YWl0IGZkVG8ud3JpdGUobGFzdFJlc3BvbnNlSGFzaCk7XG4gICAgdG9IYXNoLnVwZGF0ZShsYXN0UmVzcG9uc2VIYXNoKTtcblxuICAgIGF3YWl0IGV4cG9ydFNlY3Rpb24oMiwgXCJHMVwiLCAoMiAqKiBwb3dlcikgKiAyIC0xLCBcInRhdUcxXCIpO1xuICAgIGF3YWl0IGV4cG9ydFNlY3Rpb24oMywgXCJHMlwiLCAoMiAqKiBwb3dlcikgICAgICAgLCBcInRhdUcyXCIpO1xuICAgIGF3YWl0IGV4cG9ydFNlY3Rpb24oNCwgXCJHMVwiLCAoMiAqKiBwb3dlcikgICAgICAgLCBcImFscGhhVGF1RzFcIik7XG4gICAgYXdhaXQgZXhwb3J0U2VjdGlvbig1LCBcIkcxXCIsICgyICoqIHBvd2VyKSAgICAgICAsIFwiYmV0YVRhdUcxXCIpO1xuICAgIGF3YWl0IGV4cG9ydFNlY3Rpb24oNiwgXCJHMlwiLCAxICAgICAgICAgICAgICAgICAgLCBcImJldGFHMlwiKTtcblxuICAgIGF3YWl0IGZkRnJvbS5jbG9zZSgpO1xuICAgIGF3YWl0IGZkVG8uY2xvc2UoKTtcblxuICAgIGNvbnN0IGNhbGNDdXJDaGFsbGVuZ2VIYXNoID0gdG9IYXNoLmRpZ2VzdCgpO1xuXG4gICAgaWYgKCFtaXNjLmhhc2hJc0VxdWFsIChjdXJDaGFsbGVuZ2VIYXNoLCBjYWxjQ3VyQ2hhbGxlbmdlSGFzaCkpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKGNhbGNDdXJDaGFsbGVuZ2VIYXNoLCBcIkNhbGMgQ3VycmV0IENoYWxsZW5nZSBIYXNoOiBcIikpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIlBUYXUgZmlsZSBpcyBjb3JydXB0ZWQuIENhbGN1bGF0ZWQgbmV3IGNoYWxsZW5nZSBoYXNoIGRvZXMgbm90IG1hdGNoIHdpdGggdGhlIGVjbGFyZWQgb25lXCIpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJQVGF1IGZpbGUgaXMgY29ycnVwdGVkLiBDYWxjdWxhdGVkIG5ldyBjaGFsbGVuZ2UgaGFzaCBkb2VzIG5vdCBtYXRjaCB3aXRoIHRoZSBlY2xhcmVkIG9uZVwiKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY3VyQ2hhbGxlbmdlSGFzaDtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIGV4cG9ydFNlY3Rpb24oc2VjdGlvbklkLCBncm91cE5hbWUsIG5Qb2ludHMsIHNlY3Rpb25OYW1lKSB7XG4gICAgICAgIGNvbnN0IEcgPSBjdXJ2ZVtncm91cE5hbWVdO1xuICAgICAgICBjb25zdCBzRyA9IEcuRi5uOCoyO1xuICAgICAgICBjb25zdCBuUG9pbnRzQ2h1bmsgPSBNYXRoLmZsb29yKCgxPDwyNCkvc0cpO1xuXG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkRnJvbSwgc2VjdGlvbnMsIHNlY3Rpb25JZCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTwgblBvaW50czsgaSs9IG5Qb2ludHNDaHVuaykge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBFeHBvcnRpbmcgJHtzZWN0aW9uTmFtZX06ICR7aX0vJHtuUG9pbnRzfWApO1xuICAgICAgICAgICAgY29uc3QgbiA9IE1hdGgubWluKG5Qb2ludHMtaSwgblBvaW50c0NodW5rKTtcbiAgICAgICAgICAgIGxldCBidWZmO1xuICAgICAgICAgICAgYnVmZiA9IGF3YWl0IGZkRnJvbS5yZWFkKG4qc0cpO1xuICAgICAgICAgICAgYnVmZiA9IGF3YWl0IEcuYmF0Y2hMRU10b1UoYnVmZik7XG4gICAgICAgICAgICBhd2FpdCBmZFRvLndyaXRlKGJ1ZmYpO1xuICAgICAgICAgICAgdG9IYXNoLnVwZGF0ZShidWZmKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmRGcm9tKTtcbiAgICB9XG5cblxufVxuXG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgKiBhcyBmYXN0RmlsZSBmcm9tIFwiZmFzdGZpbGVcIjtcbmltcG9ydCB7IGJsYWtlMmIgfSBmcm9tIFwiQG5vYmxlL2hhc2hlcy9ibGFrZTIuanNcIjtcbmltcG9ydCAqIGFzIHV0aWxzIGZyb20gXCIuL3Bvd2Vyc29mdGF1X3V0aWxzLmpzXCI7XG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCAqIGFzIG1pc2MgZnJvbSBcIi4vbWlzYy5qc1wiO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBpbXBvcnRSZXNwb25zZShvbGRQdGF1RmlsZW5hbWUsIGNvbnRyaWJ1dGlvbkZpbGVuYW1lLCBuZXdQVGF1RmlsZW5hbWUsIG5hbWUsIGltcG9ydFBvaW50cywgbG9nZ2VyKSB7XG5cbiAgICBjb25zdCBub0hhc2ggPSBuZXcgVWludDhBcnJheSg2NCk7XG4gICAgZm9yIChsZXQgaT0wOyBpPDY0OyBpKyspIG5vSGFzaFtpXSA9IDB4RkY7XG5cbiAgICBjb25zdCB7ZmQ6IGZkT2xkLCBzZWN0aW9uc30gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUob2xkUHRhdUZpbGVuYW1lLCBcInB0YXVcIiwgMSk7XG4gICAgY29uc3Qge2N1cnZlLCBwb3dlcn0gPSBhd2FpdCB1dGlscy5yZWFkUFRhdUhlYWRlcihmZE9sZCwgc2VjdGlvbnMpO1xuICAgIGNvbnN0IGNvbnRyaWJ1dGlvbnMgPSBhd2FpdCB1dGlscy5yZWFkQ29udHJpYnV0aW9ucyhmZE9sZCwgY3VydmUsIHNlY3Rpb25zKTtcbiAgICBjb25zdCBjdXJyZW50Q29udHJpYnV0aW9uID0ge307XG5cbiAgICBpZiAobmFtZSkgY3VycmVudENvbnRyaWJ1dGlvbi5uYW1lID0gbmFtZTtcblxuICAgIGNvbnN0IHNHMSA9IGN1cnZlLkYxLm44KjI7XG4gICAgY29uc3Qgc2NHMSA9IGN1cnZlLkYxLm44OyAvLyBDb21wcmVzc2VkIHNpemVcbiAgICBjb25zdCBzRzIgPSBjdXJ2ZS5GMi5uOCoyO1xuICAgIGNvbnN0IHNjRzIgPSBjdXJ2ZS5GMi5uODsgLy8gQ29tcHJlc3NlZCBzaXplXG5cbiAgICBjb25zdCBmZFJlc3BvbnNlID0gYXdhaXQgZmFzdEZpbGUucmVhZEV4aXN0aW5nKGNvbnRyaWJ1dGlvbkZpbGVuYW1lKTtcblxuICAgIGlmICAoZmRSZXNwb25zZS50b3RhbFNpemUgIT1cbiAgICAgICAgNjQgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPbGQgSGFzaFxuICAgICAgICAoKDIgKiogcG93ZXIpKjItMSkqc2NHMSArXG4gICAgICAgICgyICoqIHBvd2VyKSpzY0cyICtcbiAgICAgICAgKDIgKiogcG93ZXIpKnNjRzEgK1xuICAgICAgICAoMiAqKiBwb3dlcikqc2NHMSArXG4gICAgICAgIHNjRzIgK1xuICAgICAgICBzRzEqNiArIHNHMiozKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJTaXplIG9mIHRoZSBjb250cmlidXRpb24gaXMgaW52YWxpZFwiKTtcblxuICAgIGxldCBsYXN0Q2hhbGxlbmdlSGFzaDtcblxuICAgIGlmIChjb250cmlidXRpb25zLmxlbmd0aD4wKSB7XG4gICAgICAgIGxhc3RDaGFsbGVuZ2VIYXNoID0gY29udHJpYnV0aW9uc1tjb250cmlidXRpb25zLmxlbmd0aC0xXS5uZXh0Q2hhbGxlbmdlO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGxhc3RDaGFsbGVuZ2VIYXNoID0gdXRpbHMuY2FsY3VsYXRlRmlyc3RDaGFsbGVuZ2VIYXNoKGN1cnZlLCBwb3dlciwgbG9nZ2VyKTtcbiAgICB9XG5cbiAgICBjb25zdCBmZE5ldyA9IGF3YWl0IGJpbkZpbGVVdGlscy5jcmVhdGVCaW5GaWxlKG5ld1BUYXVGaWxlbmFtZSwgXCJwdGF1XCIsIDEsIGltcG9ydFBvaW50cyA/IDc6IDIpO1xuICAgIGF3YWl0IHV0aWxzLndyaXRlUFRhdUhlYWRlcihmZE5ldywgY3VydmUsIHBvd2VyKTtcblxuICAgIGNvbnN0IGNvbnRyaWJ1dGlvblByZXZpb3VzSGFzaCA9IGF3YWl0IGZkUmVzcG9uc2UucmVhZCg2NCk7XG5cbiAgICBpZiAobWlzYy5oYXNoSXNFcXVhbChub0hhc2gsbGFzdENoYWxsZW5nZUhhc2gpKSB7XG4gICAgICAgIGxhc3RDaGFsbGVuZ2VIYXNoID0gY29udHJpYnV0aW9uUHJldmlvdXNIYXNoO1xuICAgICAgICBjb250cmlidXRpb25zW2NvbnRyaWJ1dGlvbnMubGVuZ3RoLTFdLm5leHRDaGFsbGVuZ2UgPSBsYXN0Q2hhbGxlbmdlSGFzaDtcbiAgICB9XG5cbiAgICBpZighbWlzYy5oYXNoSXNFcXVhbChjb250cmlidXRpb25QcmV2aW91c0hhc2gsbGFzdENoYWxsZW5nZUhhc2gpKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJXcm9uZyBjb250cmlidXRpb24uIFRoaXMgY29udHJpYnV0aW9uIGlzIG5vdCBiYXNlZCBvbiB0aGUgcHJldmlvdXMgaGFzaFwiKTtcblxuICAgIGNvbnN0IGhhc2hlclJlc3BvbnNlID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG4gICAgaGFzaGVyUmVzcG9uc2UudXBkYXRlKGNvbnRyaWJ1dGlvblByZXZpb3VzSGFzaCk7XG5cbiAgICBjb25zdCBzdGFydFNlY3Rpb25zID0gW107XG4gICAgbGV0IHJlcztcbiAgICByZXMgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbihmZFJlc3BvbnNlLCBmZE5ldywgXCJHMVwiLCAyLCAoMiAqKiBwb3dlcikgKiAyIC0xLCBbMV0sIFwidGF1RzFcIik7XG4gICAgY3VycmVudENvbnRyaWJ1dGlvbi50YXVHMSA9IHJlc1swXTtcbiAgICByZXMgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbihmZFJlc3BvbnNlLCBmZE5ldywgXCJHMlwiLCAzLCAoMiAqKiBwb3dlcikgICAgICAgLCBbMV0sIFwidGF1RzJcIik7XG4gICAgY3VycmVudENvbnRyaWJ1dGlvbi50YXVHMiA9IHJlc1swXTtcbiAgICByZXMgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbihmZFJlc3BvbnNlLCBmZE5ldywgXCJHMVwiLCA0LCAoMiAqKiBwb3dlcikgICAgICAgLCBbMF0sIFwiYWxwaGFHMVwiKTtcbiAgICBjdXJyZW50Q29udHJpYnV0aW9uLmFscGhhRzEgPSByZXNbMF07XG4gICAgcmVzID0gYXdhaXQgcHJvY2Vzc1NlY3Rpb24oZmRSZXNwb25zZSwgZmROZXcsIFwiRzFcIiwgNSwgKDIgKiogcG93ZXIpICAgICAgICwgWzBdLCBcImJldGFHMVwiKTtcbiAgICBjdXJyZW50Q29udHJpYnV0aW9uLmJldGFHMSA9IHJlc1swXTtcbiAgICByZXMgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbihmZFJlc3BvbnNlLCBmZE5ldywgXCJHMlwiLCA2LCAxICAgICAgICAgICAgICAgICAgLCBbMF0sIFwiYmV0YUcyXCIpO1xuICAgIGN1cnJlbnRDb250cmlidXRpb24uYmV0YUcyID0gcmVzWzBdO1xuXG4gICAgY3VycmVudENvbnRyaWJ1dGlvbi5wYXJ0aWFsSGFzaCA9IG1pc2MudG9QYXJ0aWFsSGFzaChoYXNoZXJSZXNwb25zZSk7XG5cblxuICAgIGNvbnN0IGJ1ZmZLZXkgPSBhd2FpdCBmZFJlc3BvbnNlLnJlYWQoY3VydmUuRjEubjgqMio2K2N1cnZlLkYyLm44KjIqMyk7XG5cbiAgICBjdXJyZW50Q29udHJpYnV0aW9uLmtleSA9IHV0aWxzLmZyb21QdGF1UHViS2V5UnByKGJ1ZmZLZXksIDAsIGN1cnZlLCBmYWxzZSk7XG5cbiAgICBoYXNoZXJSZXNwb25zZS51cGRhdGUobmV3IFVpbnQ4QXJyYXkoYnVmZktleSkpO1xuICAgIGNvbnN0IGhhc2hSZXNwb25zZSA9IGhhc2hlclJlc3BvbnNlLmRpZ2VzdCgpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKGhhc2hSZXNwb25zZSwgXCJDb250cmlidXRpb24gUmVzcG9uc2UgSGFzaCBpbXBvcnRlZDogXCIpKTtcblxuICAgIGlmIChpbXBvcnRQb2ludHMpIHtcbiAgICAgICAgY29uc3QgbmV4dENoYWxsZW5nZUhhc2hlciA9IGJsYWtlMmIuY3JlYXRlKHsgZGtMZW46IDY0IH0pO1xuICAgICAgICBuZXh0Q2hhbGxlbmdlSGFzaGVyLnVwZGF0ZShoYXNoUmVzcG9uc2UpO1xuXG4gICAgICAgIGF3YWl0IGhhc2hTZWN0aW9uKG5leHRDaGFsbGVuZ2VIYXNoZXIsIGZkTmV3LCBcIkcxXCIsIDIsICgyICoqIHBvd2VyKSAqIDIgLTEsIFwidGF1RzFcIiwgbG9nZ2VyKTtcbiAgICAgICAgYXdhaXQgaGFzaFNlY3Rpb24obmV4dENoYWxsZW5nZUhhc2hlciwgZmROZXcsIFwiRzJcIiwgMywgKDIgKiogcG93ZXIpICAgICAgICwgXCJ0YXVHMlwiLCBsb2dnZXIpO1xuICAgICAgICBhd2FpdCBoYXNoU2VjdGlvbihuZXh0Q2hhbGxlbmdlSGFzaGVyLCBmZE5ldywgXCJHMVwiLCA0LCAoMiAqKiBwb3dlcikgICAgICAgLCBcImFscGhhVGF1RzFcIiwgbG9nZ2VyKTtcbiAgICAgICAgYXdhaXQgaGFzaFNlY3Rpb24obmV4dENoYWxsZW5nZUhhc2hlciwgZmROZXcsIFwiRzFcIiwgNSwgKDIgKiogcG93ZXIpICAgICAgICwgXCJiZXRhVGF1RzFcIiwgbG9nZ2VyKTtcbiAgICAgICAgYXdhaXQgaGFzaFNlY3Rpb24obmV4dENoYWxsZW5nZUhhc2hlciwgZmROZXcsIFwiRzJcIiwgNiwgMSAgICAgICAgICAgICAgICAgICwgXCJiZXRhRzJcIiwgbG9nZ2VyKTtcblxuICAgICAgICBjdXJyZW50Q29udHJpYnV0aW9uLm5leHRDaGFsbGVuZ2UgPSBuZXh0Q2hhbGxlbmdlSGFzaGVyLmRpZ2VzdCgpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1pc2MuZm9ybWF0SGFzaChjdXJyZW50Q29udHJpYnV0aW9uLm5leHRDaGFsbGVuZ2UsIFwiTmV4dCBDaGFsbGVuZ2UgSGFzaDogXCIpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBjdXJyZW50Q29udHJpYnV0aW9uLm5leHRDaGFsbGVuZ2UgPSBub0hhc2g7XG4gICAgfVxuXG4gICAgY29udHJpYnV0aW9ucy5wdXNoKGN1cnJlbnRDb250cmlidXRpb24pO1xuXG4gICAgYXdhaXQgdXRpbHMud3JpdGVDb250cmlidXRpb25zKGZkTmV3LCBjdXJ2ZSwgY29udHJpYnV0aW9ucyk7XG5cbiAgICBhd2FpdCBmZFJlc3BvbnNlLmNsb3NlKCk7XG4gICAgYXdhaXQgZmROZXcuY2xvc2UoKTtcbiAgICBhd2FpdCBmZE9sZC5jbG9zZSgpO1xuXG4gICAgcmV0dXJuIGN1cnJlbnRDb250cmlidXRpb24ubmV4dENoYWxsZW5nZTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIHByb2Nlc3NTZWN0aW9uKGZkRnJvbSwgZmRUbywgZ3JvdXBOYW1lLCBzZWN0aW9uSWQsIG5Qb2ludHMsIHNpbmd1bGFyUG9pbnRJbmRleGVzLCBzZWN0aW9uTmFtZSkge1xuICAgICAgICBpZiAoaW1wb3J0UG9pbnRzKSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgcHJvY2Vzc1NlY3Rpb25JbXBvcnRQb2ludHMoZmRGcm9tLCBmZFRvLCBncm91cE5hbWUsIHNlY3Rpb25JZCwgblBvaW50cywgc2luZ3VsYXJQb2ludEluZGV4ZXMsIHNlY3Rpb25OYW1lKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBwcm9jZXNzU2VjdGlvbk5vSW1wb3J0UG9pbnRzKGZkRnJvbSwgZmRUbywgZ3JvdXBOYW1lLCBzZWN0aW9uSWQsIG5Qb2ludHMsIHNpbmd1bGFyUG9pbnRJbmRleGVzLCBzZWN0aW9uTmFtZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiBwcm9jZXNzU2VjdGlvbkltcG9ydFBvaW50cyhmZEZyb20sIGZkVG8sIGdyb3VwTmFtZSwgc2VjdGlvbklkLCBuUG9pbnRzLCBzaW5ndWxhclBvaW50SW5kZXhlcywgc2VjdGlvbk5hbWUpIHtcblxuICAgICAgICBjb25zdCBHID0gY3VydmVbZ3JvdXBOYW1lXTtcbiAgICAgICAgY29uc3Qgc2NHID0gRy5GLm44O1xuICAgICAgICBjb25zdCBzRyA9IEcuRi5uOCoyO1xuXG4gICAgICAgIGNvbnN0IHNpbmd1bGFyUG9pbnRzID0gW107XG5cbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkVG8sIHNlY3Rpb25JZCk7XG4gICAgICAgIGNvbnN0IG5Qb2ludHNDaHVuayA9IE1hdGguZmxvb3IoKDE8PDI0KS9zRyk7XG5cbiAgICAgICAgc3RhcnRTZWN0aW9uc1tzZWN0aW9uSWRdID0gZmRUby5wb3M7XG5cbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPCBuUG9pbnRzOyBpICs9IG5Qb2ludHNDaHVuaykge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBJbXBvcnRpbmcgJHtzZWN0aW9uTmFtZX06ICR7aX0vJHtuUG9pbnRzfWApO1xuICAgICAgICAgICAgY29uc3QgbiA9IE1hdGgubWluKG5Qb2ludHMtaSwgblBvaW50c0NodW5rKTtcblxuICAgICAgICAgICAgY29uc3QgYnVmZkMgPSBhd2FpdCBmZEZyb20ucmVhZChuICogc2NHKTtcbiAgICAgICAgICAgIGhhc2hlclJlc3BvbnNlLnVwZGF0ZShidWZmQyk7XG5cbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZMRU0gPSBhd2FpdCBHLmJhdGNoQ3RvTEVNKGJ1ZmZDKTtcblxuICAgICAgICAgICAgYXdhaXQgZmRUby53cml0ZShidWZmTEVNKTtcbiAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxzaW5ndWxhclBvaW50SW5kZXhlcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IHNwID0gc2luZ3VsYXJQb2ludEluZGV4ZXNbal07XG4gICAgICAgICAgICAgICAgaWYgKChzcCA+PWkpICYmIChzcCA8IGkrbikpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgUCA9IEcuZnJvbVJwckxFTShidWZmTEVNLCAoc3AtaSkqc0cpO1xuICAgICAgICAgICAgICAgICAgICBzaW5ndWxhclBvaW50cy5wdXNoKFApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmRUbyk7XG5cbiAgICAgICAgcmV0dXJuIHNpbmd1bGFyUG9pbnRzO1xuICAgIH1cblxuXG4gICAgYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc1NlY3Rpb25Ob0ltcG9ydFBvaW50cyhmZEZyb20sIGZkVG8sIGdyb3VwTmFtZSwgc2VjdGlvbklkLCBuUG9pbnRzLCBzaW5ndWxhclBvaW50SW5kZXhlcywgc2VjdGlvbk5hbWUpIHtcblxuICAgICAgICBjb25zdCBHID0gY3VydmVbZ3JvdXBOYW1lXTtcbiAgICAgICAgY29uc3Qgc2NHID0gRy5GLm44O1xuXG4gICAgICAgIGNvbnN0IHNpbmd1bGFyUG9pbnRzID0gW107XG5cbiAgICAgICAgY29uc3QgblBvaW50c0NodW5rID0gTWF0aC5mbG9vcigoMTw8MjQpL3NjRyk7XG5cbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPCBuUG9pbnRzOyBpICs9IG5Qb2ludHNDaHVuaykge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBJbXBvcnRpbmcgJHtzZWN0aW9uTmFtZX06ICR7aX0vJHtuUG9pbnRzfWApO1xuICAgICAgICAgICAgY29uc3QgbiA9IE1hdGgubWluKG5Qb2ludHMtaSwgblBvaW50c0NodW5rKTtcblxuICAgICAgICAgICAgY29uc3QgYnVmZkMgPSBhd2FpdCBmZEZyb20ucmVhZChuICogc2NHKTtcbiAgICAgICAgICAgIGhhc2hlclJlc3BvbnNlLnVwZGF0ZShidWZmQyk7XG5cbiAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxzaW5ndWxhclBvaW50SW5kZXhlcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IHNwID0gc2luZ3VsYXJQb2ludEluZGV4ZXNbal07XG4gICAgICAgICAgICAgICAgaWYgKChzcCA+PWkpICYmIChzcCA8IGkrbikpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgUCA9IEcuZnJvbVJwckNvbXByZXNzZWQoYnVmZkMsIChzcC1pKSpzY0cpO1xuICAgICAgICAgICAgICAgICAgICBzaW5ndWxhclBvaW50cy5wdXNoKFApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBzaW5ndWxhclBvaW50cztcbiAgICB9XG5cblxuICAgIGFzeW5jIGZ1bmN0aW9uIGhhc2hTZWN0aW9uKG5leHRDaGFsbGVuZ2VIYXNoZXIsIGZkVG8sIGdyb3VwTmFtZSwgc2VjdGlvbklkLCBuUG9pbnRzLCBzZWN0aW9uTmFtZSwgbG9nZ2VyKSB7XG5cbiAgICAgICAgY29uc3QgRyA9IGN1cnZlW2dyb3VwTmFtZV07XG4gICAgICAgIGNvbnN0IHNHID0gRy5GLm44KjI7XG4gICAgICAgIGNvbnN0IG5Qb2ludHNDaHVuayA9IE1hdGguZmxvb3IoKDE8PDI0KS9zRyk7XG5cbiAgICAgICAgY29uc3Qgb2xkUG9zID0gZmRUby5wb3M7XG4gICAgICAgIGZkVG8ucG9zID0gc3RhcnRTZWN0aW9uc1tzZWN0aW9uSWRdO1xuXG4gICAgICAgIGZvciAobGV0IGk9MDsgaTwgblBvaW50czsgaSArPSBuUG9pbnRzQ2h1bmspIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgSGFzaGluZyAke3NlY3Rpb25OYW1lfTogJHtpfS8ke25Qb2ludHN9YCk7XG4gICAgICAgICAgICBjb25zdCBuID0gTWF0aC5taW4oblBvaW50cy1pLCBuUG9pbnRzQ2h1bmspO1xuXG4gICAgICAgICAgICBjb25zdCBidWZmTEVNID0gYXdhaXQgZmRUby5yZWFkKG4gKiBzRyk7XG5cbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZVID0gYXdhaXQgRy5iYXRjaExFTXRvVShidWZmTEVNKTtcblxuICAgICAgICAgICAgbmV4dENoYWxsZW5nZUhhc2hlci51cGRhdGUoYnVmZlUpO1xuICAgICAgICB9XG5cbiAgICAgICAgZmRUby5wb3MgPSBvbGRQb3M7XG4gICAgfVxuXG59XG5cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCB7IGJsYWtlMmIgfSBmcm9tIFwiQG5vYmxlL2hhc2hlcy9ibGFrZTIuanNcIjtcbmltcG9ydCAqIGFzIHV0aWxzIGZyb20gXCIuL3Bvd2Vyc29mdGF1X3V0aWxzLmpzXCI7XG5pbXBvcnQgKiBhcyBrZXlQYWlyIGZyb20gXCIuL2tleXBhaXIuanNcIjtcbmltcG9ydCAqIGFzIGJpbkZpbGVVdGlscyBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuaW1wb3J0IHsgQ2hhQ2hhLCBCaWdCdWZmZXIgfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5pbXBvcnQgKiBhcyBtaXNjIGZyb20gXCIuL21pc2MuanNcIjtcbmNvbnN0IHNhbWVSYXRpbyA9IG1pc2Muc2FtZVJhdGlvO1xuXG5hc3luYyBmdW5jdGlvbiB2ZXJpZnlDb250cmlidXRpb24oY3VydmUsIGN1ciwgcHJldiwgbG9nZ2VyKSB7XG4gICAgbGV0IHNyO1xuICAgIGlmIChjdXIudHlwZSA9PSAxKSB7ICAgIC8vIFZlcmlmeSB0aGUgYmVhY29uLlxuICAgICAgICBjb25zdCBiZWFjb25LZXkgPSBhd2FpdCB1dGlscy5rZXlGcm9tQmVhY29uKGN1cnZlLCBwcmV2Lm5leHRDaGFsbGVuZ2UsIGN1ci5iZWFjb25IYXNoLCBjdXIubnVtSXRlcmF0aW9uc0V4cCk7XG5cbiAgICAgICAgaWYgKCFjdXJ2ZS5HMS5lcShjdXIua2V5LnRhdS5nMV9zLCBiZWFjb25LZXkudGF1LmcxX3MpKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYEJFQUNPTiBrZXkgKHRhdUcxX3MpIGlzIG5vdCBnZW5lcmF0ZWQgY29ycmVjdGx5IGluIGNoYWxsZW5nZSAjJHtjdXIuaWR9ICAke2N1ci5uYW1lIHx8IFwiXCJ9YCApO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghY3VydmUuRzEuZXEoY3VyLmtleS50YXUuZzFfc3gsIGJlYWNvbktleS50YXUuZzFfc3gpKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYEJFQUNPTiBrZXkgKHRhdUcxX3N4KSBpcyBub3QgZ2VuZXJhdGVkIGNvcnJlY3RseSBpbiBjaGFsbGVuZ2UgIyR7Y3VyLmlkfSAgJHtjdXIubmFtZSB8fCBcIlwifWAgKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWN1cnZlLkcyLmVxKGN1ci5rZXkudGF1LmcyX3NweCwgYmVhY29uS2V5LnRhdS5nMl9zcHgpKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYEJFQUNPTiBrZXkgKHRhdUcyX3NweCkgaXMgbm90IGdlbmVyYXRlZCBjb3JyZWN0bHkgaW4gY2hhbGxlbmdlICMke2N1ci5pZH0gICR7Y3VyLm5hbWUgfHwgXCJcIn1gICk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWN1cnZlLkcxLmVxKGN1ci5rZXkuYWxwaGEuZzFfcywgYmVhY29uS2V5LmFscGhhLmcxX3MpKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYEJFQUNPTiBrZXkgKGFscGhhRzFfcykgaXMgbm90IGdlbmVyYXRlZCBjb3JyZWN0bHkgaW4gY2hhbGxlbmdlICMke2N1ci5pZH0gICR7Y3VyLm5hbWUgfHwgXCJcIn1gICk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFjdXJ2ZS5HMS5lcShjdXIua2V5LmFscGhhLmcxX3N4LCBiZWFjb25LZXkuYWxwaGEuZzFfc3gpKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYEJFQUNPTiBrZXkgKGFscGhhRzFfc3gpIGlzIG5vdCBnZW5lcmF0ZWQgY29ycmVjdGx5IGluIGNoYWxsZW5nZSAjJHtjdXIuaWR9ICAke2N1ci5uYW1lIHx8IFwiXCJ9YCApO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghY3VydmUuRzIuZXEoY3VyLmtleS5hbHBoYS5nMl9zcHgsIGJlYWNvbktleS5hbHBoYS5nMl9zcHgpKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYEJFQUNPTiBrZXkgKGFscGhhRzJfc3B4KSBpcyBub3QgZ2VuZXJhdGVkIGNvcnJlY3RseSBpbiBjaGFsbGVuZ2UgIyR7Y3VyLmlkfSAgJHtjdXIubmFtZSB8fCBcIlwifWAgKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghY3VydmUuRzEuZXEoY3VyLmtleS5iZXRhLmcxX3MsIGJlYWNvbktleS5iZXRhLmcxX3MpKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYEJFQUNPTiBrZXkgKGJldGFHMV9zKSBpcyBub3QgZ2VuZXJhdGVkIGNvcnJlY3RseSBpbiBjaGFsbGVuZ2UgIyR7Y3VyLmlkfSAgJHtjdXIubmFtZSB8fCBcIlwifWAgKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWN1cnZlLkcxLmVxKGN1ci5rZXkuYmV0YS5nMV9zeCwgYmVhY29uS2V5LmJldGEuZzFfc3gpKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYEJFQUNPTiBrZXkgKGJldGFHMV9zeCkgaXMgbm90IGdlbmVyYXRlZCBjb3JyZWN0bHkgaW4gY2hhbGxlbmdlICMke2N1ci5pZH0gICR7Y3VyLm5hbWUgfHwgXCJcIn1gICk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFjdXJ2ZS5HMi5lcShjdXIua2V5LmJldGEuZzJfc3B4LCBiZWFjb25LZXkuYmV0YS5nMl9zcHgpKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYEJFQUNPTiBrZXkgKGJldGFHMl9zcHgpIGlzIG5vdCBnZW5lcmF0ZWQgY29ycmVjdGx5IGluIGNoYWxsZW5nZSAjJHtjdXIuaWR9ICAke2N1ci5uYW1lIHx8IFwiXCJ9YCApO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgY3VyLmtleS50YXUuZzJfc3AgPSBjdXJ2ZS5HMi50b0FmZmluZShrZXlQYWlyLmdldEcyc3AoY3VydmUsIDAsIHByZXYubmV4dENoYWxsZW5nZSwgY3VyLmtleS50YXUuZzFfcywgY3VyLmtleS50YXUuZzFfc3gpKTtcbiAgICBjdXIua2V5LmFscGhhLmcyX3NwID0gY3VydmUuRzIudG9BZmZpbmUoa2V5UGFpci5nZXRHMnNwKGN1cnZlLCAxLCBwcmV2Lm5leHRDaGFsbGVuZ2UsIGN1ci5rZXkuYWxwaGEuZzFfcywgY3VyLmtleS5hbHBoYS5nMV9zeCkpO1xuICAgIGN1ci5rZXkuYmV0YS5nMl9zcCA9IGN1cnZlLkcyLnRvQWZmaW5lKGtleVBhaXIuZ2V0RzJzcChjdXJ2ZSwgMiwgcHJldi5uZXh0Q2hhbGxlbmdlLCBjdXIua2V5LmJldGEuZzFfcywgY3VyLmtleS5iZXRhLmcxX3N4KSk7XG5cbiAgICBzciA9IGF3YWl0IHNhbWVSYXRpbyhjdXJ2ZSwgY3VyLmtleS50YXUuZzFfcywgY3VyLmtleS50YXUuZzFfc3gsIGN1ci5rZXkudGF1LmcyX3NwLCBjdXIua2V5LnRhdS5nMl9zcHgpO1xuICAgIGlmIChzciAhPT0gdHJ1ZSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJJTlZBTElEIGtleSAodGF1KSBpbiBjaGFsbGVuZ2UgI1wiK2N1ci5pZCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBzciA9IGF3YWl0IHNhbWVSYXRpbyhjdXJ2ZSwgY3VyLmtleS5hbHBoYS5nMV9zLCBjdXIua2V5LmFscGhhLmcxX3N4LCBjdXIua2V5LmFscGhhLmcyX3NwLCBjdXIua2V5LmFscGhhLmcyX3NweCk7XG4gICAgaWYgKHNyICE9PSB0cnVlKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIklOVkFMSUQga2V5IChhbHBoYSkgaW4gY2hhbGxlbmdlICNcIitjdXIuaWQpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgc3IgPSBhd2FpdCBzYW1lUmF0aW8oY3VydmUsIGN1ci5rZXkuYmV0YS5nMV9zLCBjdXIua2V5LmJldGEuZzFfc3gsIGN1ci5rZXkuYmV0YS5nMl9zcCwgY3VyLmtleS5iZXRhLmcyX3NweCk7XG4gICAgaWYgKHNyICE9PSB0cnVlKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIklOVkFMSUQga2V5IChiZXRhKSBpbiBjaGFsbGVuZ2UgI1wiK2N1ci5pZCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBzciA9IGF3YWl0IHNhbWVSYXRpbyhjdXJ2ZSwgcHJldi50YXVHMSwgY3VyLnRhdUcxLCBjdXIua2V5LnRhdS5nMl9zcCwgY3VyLmtleS50YXUuZzJfc3B4KTtcbiAgICBpZiAoc3IgIT09IHRydWUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRCB0YXUqRzEuIGNoYWxsZW5nZSAjXCIrY3VyLmlkK1wiIEl0IGRvZXMgbm90IGZvbGxvdyB0aGUgcHJldmlvdXMgY29udHJpYnV0aW9uXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgc3IgPSBhd2FpdCBzYW1lUmF0aW8oY3VydmUsICBjdXIua2V5LnRhdS5nMV9zLCBjdXIua2V5LnRhdS5nMV9zeCwgcHJldi50YXVHMiwgY3VyLnRhdUcyKTtcbiAgICBpZiAoc3IgIT09IHRydWUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRCB0YXUqRzIuIGNoYWxsZW5nZSAjXCIrY3VyLmlkK1wiIEl0IGRvZXMgbm90IGZvbGxvdyB0aGUgcHJldmlvdXMgY29udHJpYnV0aW9uXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgc3IgPSBhd2FpdCBzYW1lUmF0aW8oY3VydmUsIHByZXYuYWxwaGFHMSwgY3VyLmFscGhhRzEsIGN1ci5rZXkuYWxwaGEuZzJfc3AsIGN1ci5rZXkuYWxwaGEuZzJfc3B4KTtcbiAgICBpZiAoc3IgIT09IHRydWUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRCBhbHBoYSpHMS4gY2hhbGxlbmdlICNcIitjdXIuaWQrXCIgSXQgZG9lcyBub3QgZm9sbG93IHRoZSBwcmV2aW91cyBjb250cmlidXRpb25cIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBzciA9IGF3YWl0IHNhbWVSYXRpbyhjdXJ2ZSwgcHJldi5iZXRhRzEsIGN1ci5iZXRhRzEsIGN1ci5rZXkuYmV0YS5nMl9zcCwgY3VyLmtleS5iZXRhLmcyX3NweCk7XG4gICAgaWYgKHNyICE9PSB0cnVlKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIklOVkFMSUQgYmV0YSpHMS4gY2hhbGxlbmdlICNcIitjdXIuaWQrXCIgSXQgZG9lcyBub3QgZm9sbG93IHRoZSBwcmV2aW91cyBjb250cmlidXRpb25cIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBzciA9IGF3YWl0IHNhbWVSYXRpbyhjdXJ2ZSwgIGN1ci5rZXkuYmV0YS5nMV9zLCBjdXIua2V5LmJldGEuZzFfc3gsIHByZXYuYmV0YUcyLCBjdXIuYmV0YUcyKTtcbiAgICBpZiAoc3IgIT09IHRydWUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRCBiZXRhKkcyLiBjaGFsbGVuZ2UgI1wiK2N1ci5pZCtcIkl0IGRvZXMgbm90IGZvbGxvdyB0aGUgcHJldmlvdXMgY29udHJpYnV0aW9uXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJQb3dlcnMgT2YgdGF1IGZpbGUgT0shXCIpO1xuICAgIHJldHVybiB0cnVlO1xufVxuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiB2ZXJpZnkodGF1RmlsZW5hbWUsIGxvZ2dlcikge1xuICAgIGxldCBzcjtcblxuICAgIGNvbnN0IHtmZCwgc2VjdGlvbnN9ID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRCaW5GaWxlKHRhdUZpbGVuYW1lLCBcInB0YXVcIiwgMSk7XG4gICAgY29uc3Qge2N1cnZlLCBwb3dlciwgY2VyZW1vbnlQb3dlcn0gPSBhd2FpdCB1dGlscy5yZWFkUFRhdUhlYWRlcihmZCwgc2VjdGlvbnMpO1xuICAgIGNvbnN0IGNvbnRycyA9IGF3YWl0IHV0aWxzLnJlYWRDb250cmlidXRpb25zKGZkLCBjdXJ2ZSwgc2VjdGlvbnMpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwicG93ZXI6IDIqKlwiICsgcG93ZXIpO1xuICAgIC8vIFZlcmlmeSBMYXN0IGNvbnRyaWJ1dGlvblxuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiQ29tcHV0aW5nIGluaXRpYWwgY29udHJpYnV0aW9uIGhhc2hcIik7XG4gICAgY29uc3QgaW5pdGlhbENvbnRyaWJ1dGlvbiA9IHtcbiAgICAgICAgdGF1RzE6IGN1cnZlLkcxLmcsXG4gICAgICAgIHRhdUcyOiBjdXJ2ZS5HMi5nLFxuICAgICAgICBhbHBoYUcxOiBjdXJ2ZS5HMS5nLFxuICAgICAgICBiZXRhRzE6IGN1cnZlLkcxLmcsXG4gICAgICAgIGJldGFHMjogY3VydmUuRzIuZyxcbiAgICAgICAgbmV4dENoYWxsZW5nZTogdXRpbHMuY2FsY3VsYXRlRmlyc3RDaGFsbGVuZ2VIYXNoKGN1cnZlLCBjZXJlbW9ueVBvd2VyLCBsb2dnZXIpLFxuICAgICAgICByZXNwb25zZUhhc2g6IGJsYWtlMmIuY3JlYXRlKHsgZGtMZW46IDY0IH0pLmRpZ2VzdCgpXG4gICAgfTtcblxuICAgIGlmIChjb250cnMubGVuZ3RoID09IDApIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiVGhpcyBmaWxlIGhhcyBubyBjb250cmlidXRpb24hIEl0IGNhbm5vdCBiZSB1c2VkIGluIHByb2R1Y3Rpb25cIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBsZXQgcHJldkNvbnRyO1xuICAgIGlmIChjb250cnMubGVuZ3RoPjEpIHtcbiAgICAgICAgcHJldkNvbnRyID0gY29udHJzW2NvbnRycy5sZW5ndGgtMl07XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcHJldkNvbnRyID0gaW5pdGlhbENvbnRyaWJ1dGlvbjtcbiAgICB9XG4gICAgY29uc3QgY3VyQ29udHIgPSBjb250cnNbY29udHJzLmxlbmd0aC0xXTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJWYWxpZGF0aW5nIGNvbnRyaWJ1dGlvbiAjXCIrY29udHJzW2NvbnRycy5sZW5ndGgtMV0uaWQpO1xuICAgIGNvbnN0IHJlcyA9IGF3YWl0IHZlcmlmeUNvbnRyaWJ1dGlvbihjdXJ2ZSwgY3VyQ29udHIsIHByZXZDb250ciwgbG9nZ2VyKTtcbiAgICBpZiAoIXJlcykgcmV0dXJuIGZhbHNlO1xuXG5cbiAgICBjb25zdCBuZXh0Q29udHJpYnV0aW9uSGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG4gICAgbmV4dENvbnRyaWJ1dGlvbkhhc2hlci51cGRhdGUoY3VyQ29udHIucmVzcG9uc2VIYXNoKTtcblxuICAgIC8vIFZlcmlmeSBwb3dlcnMgYW5kIGNvbXB1dGUgbmV4dENoYWxsZW5nZUhhc2hcblxuICAgIC8vIGF3YWl0IHRlc3QoKTtcblxuICAgIC8vIFZlcmlmeSBTZWN0aW9uIHRhdSpHMVxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIlZlcmlmeWluZyBwb3dlcnMgaW4gdGF1KkcxIHNlY3Rpb25cIik7XG4gICAgY29uc3QgclRhdTEgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbigyLCBcIkcxXCIsIFwidGF1RzFcIiwgKDIgKiogcG93ZXIpKjItMSwgWzAsIDFdLCBsb2dnZXIpO1xuICAgIHNyID0gYXdhaXQgc2FtZVJhdGlvKGN1cnZlLCByVGF1MS5SMSwgclRhdTEuUjIsIGN1cnZlLkcyLmcsIGN1ckNvbnRyLnRhdUcyKTtcbiAgICBpZiAoc3IgIT09IHRydWUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwidGF1RzEgc2VjdGlvbi4gUG93ZXJzIGRvIG5vdCBtYXRjaFwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoIWN1cnZlLkcxLmVxKGN1cnZlLkcxLmcsIHJUYXUxLnNpbmd1bGFyUG9pbnRzWzBdKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJGaXJzdCBlbGVtZW50IG9mIHRhdSpHMSBzZWN0aW9uIG11c3QgYmUgdGhlIGdlbmVyYXRvclwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoIWN1cnZlLkcxLmVxKGN1ckNvbnRyLnRhdUcxLCByVGF1MS5zaW5ndWxhclBvaW50c1sxXSkpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiU2Vjb25kIGVsZW1lbnQgb2YgdGF1KkcxIHNlY3Rpb24gZG9lcyBub3QgbWF0Y2ggdGhlIG9uZSBpbiB0aGUgY29udHJpYnV0aW9uIHNlY3Rpb25cIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBhd2FpdCB0ZXN0KCk7XG5cbiAgICAvLyBWZXJpZnkgU2VjdGlvbiB0YXUqRzJcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJWZXJpZnlpbmcgcG93ZXJzIGluIHRhdSpHMiBzZWN0aW9uXCIpO1xuICAgIGNvbnN0IHJUYXUyID0gYXdhaXQgcHJvY2Vzc1NlY3Rpb24oMywgXCJHMlwiLCBcInRhdUcyXCIsIDIgKiogcG93ZXIsIFswLCAxXSwgIGxvZ2dlcik7XG4gICAgc3IgPSBhd2FpdCBzYW1lUmF0aW8oY3VydmUsIGN1cnZlLkcxLmcsIGN1ckNvbnRyLnRhdUcxLCByVGF1Mi5SMSwgclRhdTIuUjIpO1xuICAgIGlmIChzciAhPT0gdHJ1ZSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJ0YXVHMiBzZWN0aW9uLiBQb3dlcnMgZG8gbm90IG1hdGNoXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICghY3VydmUuRzIuZXEoY3VydmUuRzIuZywgclRhdTIuc2luZ3VsYXJQb2ludHNbMF0pKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIkZpcnN0IGVsZW1lbnQgb2YgdGF1KkcyIHNlY3Rpb24gbXVzdCBiZSB0aGUgZ2VuZXJhdG9yXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICghY3VydmUuRzIuZXEoY3VyQ29udHIudGF1RzIsIHJUYXUyLnNpbmd1bGFyUG9pbnRzWzFdKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJTZWNvbmQgZWxlbWVudCBvZiB0YXUqRzIgc2VjdGlvbiBkb2VzIG5vdCBtYXRjaCB0aGUgb25lIGluIHRoZSBjb250cmlidXRpb24gc2VjdGlvblwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIFZlcmlmeSBTZWN0aW9uIGFscGhhKnRhdSpHMVxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIlZlcmlmeWluZyBwb3dlcnMgaW4gYWxwaGEqdGF1KkcxIHNlY3Rpb25cIik7XG4gICAgY29uc3QgckFscGhhVGF1RzEgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbig0LCBcIkcxXCIsIFwiYWxwaGF0YXVHMVwiLCAyICoqIHBvd2VyLCBbMF0sIGxvZ2dlcik7XG4gICAgc3IgPSBhd2FpdCBzYW1lUmF0aW8oY3VydmUsIHJBbHBoYVRhdUcxLlIxLCByQWxwaGFUYXVHMS5SMiwgY3VydmUuRzIuZywgY3VyQ29udHIudGF1RzIpO1xuICAgIGlmIChzciAhPT0gdHJ1ZSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJhbHBoYVRhdUcxIHNlY3Rpb24uIFBvd2VycyBkbyBub3QgbWF0Y2hcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKCFjdXJ2ZS5HMS5lcShjdXJDb250ci5hbHBoYUcxLCByQWxwaGFUYXVHMS5zaW5ndWxhclBvaW50c1swXSkpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiRmlyc3QgZWxlbWVudCBvZiBhbHBoYSp0YXUqRzEgc2VjdGlvbiAoYWxwaGEqRzEpIGRvZXMgbm90IG1hdGNoIHRoZSBvbmUgaW4gdGhlIGNvbnRyaWJ1dGlvbiBzZWN0aW9uXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gVmVyaWZ5IFNlY3Rpb24gYmV0YSp0YXUqRzFcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJWZXJpZnlpbmcgcG93ZXJzIGluIGJldGEqdGF1KkcxIHNlY3Rpb25cIik7XG4gICAgY29uc3QgckJldGFUYXVHMSA9IGF3YWl0IHByb2Nlc3NTZWN0aW9uKDUsIFwiRzFcIiwgXCJiZXRhdGF1RzFcIiwgMiAqKiBwb3dlciwgWzBdLCBsb2dnZXIpO1xuICAgIHNyID0gYXdhaXQgc2FtZVJhdGlvKGN1cnZlLCByQmV0YVRhdUcxLlIxLCByQmV0YVRhdUcxLlIyLCBjdXJ2ZS5HMi5nLCBjdXJDb250ci50YXVHMik7XG4gICAgaWYgKHNyICE9PSB0cnVlKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcImJldGFUYXVHMSBzZWN0aW9uLiBQb3dlcnMgZG8gbm90IG1hdGNoXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICghY3VydmUuRzEuZXEoY3VyQ29udHIuYmV0YUcxLCByQmV0YVRhdUcxLnNpbmd1bGFyUG9pbnRzWzBdKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJGaXJzdCBlbGVtZW50IG9mIGJldGEqdGF1KkcxIHNlY3Rpb24gKGJldGEqRzEpIGRvZXMgbm90IG1hdGNoIHRoZSBvbmUgaW4gdGhlIGNvbnRyaWJ1dGlvbiBzZWN0aW9uXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy9WZXJpZnkgQmV0YSBHMlxuICAgIGNvbnN0IGJldGFHMiA9IGF3YWl0IHByb2Nlc3NTZWN0aW9uQmV0YUcyKGxvZ2dlcik7XG4gICAgaWYgKCFjdXJ2ZS5HMi5lcShjdXJDb250ci5iZXRhRzIsIGJldGFHMikpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiYmV0YUcyIGVsZW1lbnQgaW4gYmV0YUcyIHNlY3Rpb24gZG9lcyBub3QgbWF0Y2ggdGhlIG9uZSBpbiB0aGUgY29udHJpYnV0aW9uIHNlY3Rpb25cIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cblxuICAgIGNvbnN0IG5leHRDb250cmlidXRpb25IYXNoID0gbmV4dENvbnRyaWJ1dGlvbkhhc2hlci5kaWdlc3QoKTtcblxuICAgIC8vIENoZWNrIHRoZSBuZXh0Q2hhbGxlbmdlSGFzaFxuICAgIGlmIChwb3dlciA9PSBjZXJlbW9ueVBvd2VyKSB7XG4gICAgICAgIGlmICghbWlzYy5oYXNoSXNFcXVhbChuZXh0Q29udHJpYnV0aW9uSGFzaCxjdXJDb250ci5uZXh0Q2hhbGxlbmdlKSkge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSGFzaCBvZiB0aGUgdmFsdWVzIGRvZXMgbm90IG1hdGNoIHRoZSBuZXh0IGNoYWxsZW5nZSBvZiB0aGUgbGFzdCBjb250cmlidXRvciBpbiB0aGUgY29udHJpYnV0aW9ucyBzZWN0aW9uXCIpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKG5leHRDb250cmlidXRpb25IYXNoLCBcIk5leHQgY2hhbGxlbmdlIGhhc2g6IFwiKSk7XG5cbiAgICAvLyBWZXJpZnkgUHJldmlvdXMgY29udHJpYnV0aW9uc1xuXG4gICAgcHJpbnRDb250cmlidXRpb24oY3VyQ29udHIsIHByZXZDb250cik7XG4gICAgZm9yIChsZXQgaSA9IGNvbnRycy5sZW5ndGgtMjsgaT49MDsgaS0tKSB7XG4gICAgICAgIGNvbnN0IGN1ckNvbnRyID0gY29udHJzW2ldO1xuICAgICAgICBjb25zdCBwcmV2Q29udHIgPSAgKGk+MCkgPyBjb250cnNbaS0xXSA6IGluaXRpYWxDb250cmlidXRpb247XG4gICAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IHZlcmlmeUNvbnRyaWJ1dGlvbihjdXJ2ZSwgY3VyQ29udHIsIHByZXZDb250ciwgbG9nZ2VyKTtcbiAgICAgICAgaWYgKCFyZXMpIHJldHVybiBmYWxzZTtcbiAgICAgICAgcHJpbnRDb250cmlidXRpb24oY3VyQ29udHIsIHByZXZDb250ciwgbG9nZ2VyKTtcbiAgICB9XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiKTtcblxuICAgIGlmICgoIXNlY3Rpb25zWzEyXSkgfHwgKCFzZWN0aW9uc1sxM10pIHx8ICghc2VjdGlvbnNbMTRdKSB8fCAoIXNlY3Rpb25zWzE1XSkpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLndhcm4oXG4gICAgICAgICAgICBcInRoaXMgZmlsZSBkb2VzIG5vdCBjb250YWluIHBoYXNlMiBwcmVjYWxjdWxhdGVkIHZhbHVlcy4gUGxlYXNlIHJ1bjogXFxuXCIgK1xuICAgICAgICAgICAgXCIgICBzbmFya2pzIFxcXCJwb3dlcnNvZnRhdSBwcmVwYXJlcGhhc2UyXFxcIiB0byBwcmVwYXJlIHRoaXMgZmlsZSB0byBiZSB1c2VkIGluIHRoZSBwaGFzZTIgY2VyZW1vbnkuXCJcbiAgICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgcmVzO1xuICAgICAgICByZXMgPSBhd2FpdCB2ZXJpZnlMYWdyYW5nZUV2YWx1YXRpb25zKFwiRzFcIiwgMiwgMTIsIFwidGF1RzFcIiwgbG9nZ2VyKTtcbiAgICAgICAgaWYgKCFyZXMpIHJldHVybiBmYWxzZTtcbiAgICAgICAgcmVzID0gYXdhaXQgdmVyaWZ5TGFncmFuZ2VFdmFsdWF0aW9ucyhcIkcyXCIsIDMsIDEzLCBcInRhdUcyXCIsIGxvZ2dlcik7XG4gICAgICAgIGlmICghcmVzKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHJlcyA9IGF3YWl0IHZlcmlmeUxhZ3JhbmdlRXZhbHVhdGlvbnMoXCJHMVwiLCA0LCAxNCwgXCJhbHBoYVRhdUcxXCIsIGxvZ2dlcik7XG4gICAgICAgIGlmICghcmVzKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHJlcyA9IGF3YWl0IHZlcmlmeUxhZ3JhbmdlRXZhbHVhdGlvbnMoXCJHMVwiLCA1LCAxNSwgXCJiZXRhVGF1RzFcIiwgbG9nZ2VyKTtcbiAgICAgICAgaWYgKCFyZXMpIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBhd2FpdCBmZC5jbG9zZSgpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJQb3dlcnMgb2YgVGF1IE9rIVwiKTtcblxuICAgIHJldHVybiB0cnVlO1xuXG4gICAgZnVuY3Rpb24gcHJpbnRDb250cmlidXRpb24oY3VyQ29udHIsIHByZXZDb250cikge1xuICAgICAgICBpZiAoIWxvZ2dlcikgcmV0dXJuO1xuICAgICAgICBsb2dnZXIuaW5mbyhcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXCIpO1xuICAgICAgICBsb2dnZXIuaW5mbyhgQ29udHJpYnV0aW9uICMke2N1ckNvbnRyLmlkfTogJHtjdXJDb250ci5uYW1lIHx8XCJcIn1gKTtcblxuICAgICAgICBsb2dnZXIuaW5mbyhtaXNjLmZvcm1hdEhhc2goY3VyQ29udHIubmV4dENoYWxsZW5nZSwgXCJOZXh0IENoYWxsZW5nZTogXCIpKTtcblxuICAgICAgICBjb25zdCBidWZmViAgPSBuZXcgVWludDhBcnJheShjdXJ2ZS5HMS5GLm44KjIqNitjdXJ2ZS5HMi5GLm44KjIqMyk7XG4gICAgICAgIHV0aWxzLnRvUHRhdVB1YktleVJwcihidWZmViwgMCwgY3VydmUsIGN1ckNvbnRyLmtleSwgZmFsc2UpO1xuXG4gICAgICAgIGNvbnN0IHJlc3BvbnNlSGFzaGVyID0gIG1pc2MuZnJvbVBhcnRpYWxIYXNoKGN1ckNvbnRyLnBhcnRpYWxIYXNoKTtcbiAgICAgICAgcmVzcG9uc2VIYXNoZXIudXBkYXRlKGJ1ZmZWKTtcbiAgICAgICAgY29uc3QgcmVzcG9uc2VIYXNoID0gcmVzcG9uc2VIYXNoZXIuZGlnZXN0KCk7XG5cbiAgICAgICAgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKHJlc3BvbnNlSGFzaCwgXCJSZXNwb25zZSBIYXNoOlwiKSk7XG5cbiAgICAgICAgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKHByZXZDb250ci5uZXh0Q2hhbGxlbmdlLCBcIlJlc3BvbnNlIEhhc2g6XCIpKTtcblxuICAgICAgICBpZiAoY3VyQ29udHIudHlwZSA9PSAxKSB7XG4gICAgICAgICAgICBsb2dnZXIuaW5mbyhgQmVhY29uIGdlbmVyYXRvcjogJHttaXNjLmJ5dGVBcnJheTJoZXgoY3VyQ29udHIuYmVhY29uSGFzaCl9YCk7XG4gICAgICAgICAgICBsb2dnZXIuaW5mbyhgQmVhY29uIGl0ZXJhdGlvbnMgRXhwOiAke2N1ckNvbnRyLm51bUl0ZXJhdGlvbnNFeHB9YCk7XG4gICAgICAgIH1cblxuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHByb2Nlc3NTZWN0aW9uQmV0YUcyKGxvZ2dlcikge1xuICAgICAgICBjb25zdCBHID0gY3VydmUuRzI7XG4gICAgICAgIGNvbnN0IHNHID0gRy5GLm44KjI7XG4gICAgICAgIGNvbnN0IGJ1ZmZVdiA9IG5ldyBVaW50OEFycmF5KHNHKTtcblxuICAgICAgICBpZiAoIXNlY3Rpb25zWzZdKSAge1xuICAgICAgICAgICAgbG9nZ2VyLmVycm9yKFwiRmlsZSBoYXMgbm8gQmV0YUcyIHNlY3Rpb25cIik7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGaWxlIGhhcyBubyBCZXRhRzIgc2VjdGlvblwiKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc2VjdGlvbnNbNl0ubGVuZ3RoPjEpIHtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcIkZpbGUgaGFzIG5vIEJldGFHMiBzZWN0aW9uXCIpO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmlsZSBoYXMgbW9yZSB0aGFuIG9uZSBHZXRhRzIgc2VjdGlvblwiKTtcbiAgICAgICAgfVxuICAgICAgICBmZC5wb3MgPSBzZWN0aW9uc1s2XVswXS5wO1xuXG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZC5yZWFkKHNHKTtcbiAgICAgICAgY29uc3QgUCA9IEcuZnJvbVJwckxFTShidWZmKTtcblxuICAgICAgICBHLnRvUnByVW5jb21wcmVzc2VkKGJ1ZmZVdiwgMCwgUCk7XG4gICAgICAgIG5leHRDb250cmlidXRpb25IYXNoZXIudXBkYXRlKGJ1ZmZVdik7XG5cbiAgICAgICAgcmV0dXJuIFA7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc1NlY3Rpb24oaWRTZWN0aW9uLCBncm91cE5hbWUsIHNlY3Rpb25OYW1lLCBuUG9pbnRzLCBzaW5ndWxhclBvaW50SW5kZXhlcywgbG9nZ2VyKSB7XG4gICAgICAgIGNvbnN0IE1BWF9DSFVOS19TSVpFID0gMTw8MTY7XG4gICAgICAgIGNvbnN0IEcgPSBjdXJ2ZVtncm91cE5hbWVdO1xuICAgICAgICBjb25zdCBzRyA9IEcuRi5uOCoyO1xuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIGlkU2VjdGlvbik7XG5cbiAgICAgICAgY29uc3Qgc2luZ3VsYXJQb2ludHMgPSBbXTtcblxuICAgICAgICBsZXQgUjEgPSBHLnplcm87XG4gICAgICAgIGxldCBSMiA9IEcuemVybztcblxuICAgICAgICBsZXQgbGFzdEJhc2UgPSBHLnplcm87XG5cbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPG5Qb2ludHM7IGkgKz0gTUFYX0NIVU5LX1NJWkUpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgcG9pbnRzIHJlbGF0aW9uczogJHtzZWN0aW9uTmFtZX06ICR7aX0vJHtuUG9pbnRzfSBgKTtcbiAgICAgICAgICAgIGNvbnN0IG4gPSBNYXRoLm1pbihuUG9pbnRzIC0gaSwgTUFYX0NIVU5LX1NJWkUpO1xuICAgICAgICAgICAgY29uc3QgYmFzZXMgPSBhd2FpdCBmZC5yZWFkKG4qc0cpO1xuXG4gICAgICAgICAgICBjb25zdCBiYXNlc1UgPSBhd2FpdCBHLmJhdGNoTEVNdG9VKGJhc2VzKTtcbiAgICAgICAgICAgIG5leHRDb250cmlidXRpb25IYXNoZXIudXBkYXRlKGJhc2VzVSk7XG5cbiAgICAgICAgICAgIGNvbnN0IHNjYWxhcnMgPSBtaXNjLmdldFJhbmRvbUJ5dGVzKDQqKG4tMSkpO1xuXG4gICAgICAgICAgICBpZiAoaT4wKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmlyc3RCYXNlID0gRy5mcm9tUnByTEVNKGJhc2VzLCAwKTtcbiAgICAgICAgICAgICAgICBjb25zdCByID0gbWlzYy5yZWFkVUludDMyQkUobWlzYy5nZXRSYW5kb21CeXRlcyg0KSwgMCk7XG5cbiAgICAgICAgICAgICAgICBSMSA9IEcuYWRkKFIxLCBHLnRpbWVzU2NhbGFyKGxhc3RCYXNlLCByKSk7XG4gICAgICAgICAgICAgICAgUjIgPSBHLmFkZChSMiwgRy50aW1lc1NjYWxhcihmaXJzdEJhc2UsIHIpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgcjEgPSBhd2FpdCBHLm11bHRpRXhwQWZmaW5lKGJhc2VzLnNsaWNlKDAsIChuLTEpKnNHKSwgc2NhbGFycyk7XG4gICAgICAgICAgICBjb25zdCByMiA9IGF3YWl0IEcubXVsdGlFeHBBZmZpbmUoYmFzZXMuc2xpY2Uoc0cpLCBzY2FsYXJzKTtcblxuICAgICAgICAgICAgUjEgPSBHLmFkZChSMSwgcjEpO1xuICAgICAgICAgICAgUjIgPSBHLmFkZChSMiwgcjIpO1xuXG4gICAgICAgICAgICBsYXN0QmFzZSA9IEcuZnJvbVJwckxFTSggYmFzZXMsIChuLTEpKnNHKTtcblxuICAgICAgICAgICAgZm9yIChsZXQgaj0wOyBqPHNpbmd1bGFyUG9pbnRJbmRleGVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3AgPSBzaW5ndWxhclBvaW50SW5kZXhlc1tqXTtcbiAgICAgICAgICAgICAgICBpZiAoKHNwID49aSkgJiYgKHNwIDwgaStuKSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBQID0gRy5mcm9tUnByTEVNKGJhc2VzLCAoc3AtaSkqc0cpO1xuICAgICAgICAgICAgICAgICAgICBzaW5ndWxhclBvaW50cy5wdXNoKFApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRSZWFkU2VjdGlvbihmZCk7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIFIxOiBSMSxcbiAgICAgICAgICAgIFIyOiBSMixcbiAgICAgICAgICAgIHNpbmd1bGFyUG9pbnRzOiBzaW5ndWxhclBvaW50c1xuICAgICAgICB9O1xuXG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5TGFncmFuZ2VFdmFsdWF0aW9ucyhnTmFtZSwgdGF1U2VjdGlvbiwgbGFncmFuZ2VTZWN0aW9uLCBzZWN0aW9uTmFtZSwgbG9nZ2VyKSB7XG5cbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBWZXJpZnlpbmcgcGhhc2UyIGNhbGN1bGF0ZWQgdmFsdWVzICR7c2VjdGlvbk5hbWV9Li4uYCk7XG4gICAgICAgIGNvbnN0IEcgPSBjdXJ2ZVtnTmFtZV07XG4gICAgICAgIGNvbnN0IHNHID0gRy5GLm44KjI7XG5cbiAgICAgICAgY29uc3Qgc2VlZD0gbmV3IEFycmF5KDgpO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8ODsgaSsrKSB7XG4gICAgICAgICAgICBzZWVkW2ldID0gbWlzYy5yZWFkVUludDMyQkUobWlzYy5nZXRSYW5kb21CeXRlcyg0KSwgMCk7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGxldCBwPTA7IHA8PSBwb3dlcjsgcCArKykge1xuICAgICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgdmVyaWZ5UG93ZXIocCk7XG4gICAgICAgICAgICBpZiAoIXJlcykgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRhdVNlY3Rpb24gPT0gMikge1xuICAgICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgdmVyaWZ5UG93ZXIocG93ZXIrMSk7XG4gICAgICAgICAgICBpZiAoIXJlcykgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG5cbiAgICAgICAgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5UG93ZXIocCkge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBQb3dlciAke3B9Li4uYCk7XG4gICAgICAgICAgICBjb25zdCBuOHIgPSBjdXJ2ZS5Gci5uODtcbiAgICAgICAgICAgIGNvbnN0IG5Qb2ludHMgPSAyICoqIHA7XG4gICAgICAgICAgICBsZXQgYnVmZl9yID0gbmV3IFVpbnQzMkFycmF5KG5Qb2ludHMpO1xuICAgICAgICAgICAgbGV0IGJ1ZmZHO1xuXG4gICAgICAgICAgICBsZXQgcm5nID0gbmV3IENoYUNoYShzZWVkKTtcblxuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBDcmVhdGluZyByYW5kb20gbnVtYmVycyBQb3dlcnMke3B9Li4uYCk7XG4gICAgICAgICAgICBmb3IgKGxldCBpPTA7IGk8blBvaW50czsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKChwID09IHBvd2VyKzEpJiYoaSA9PSBuUG9pbnRzLTEpKSB7XG4gICAgICAgICAgICAgICAgICAgIGJ1ZmZfcltpXSA9IDA7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgYnVmZl9yW2ldID0gcm5nLm5leHRVMzIoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGJ1ZmZfciA9IG5ldyBVaW50OEFycmF5KGJ1ZmZfci5idWZmZXIsIGJ1ZmZfci5ieXRlT2Zmc2V0LCBidWZmX3IuYnl0ZUxlbmd0aCk7XG5cbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgcmVhZGluZyBwb2ludHMgUG93ZXJzJHtwfS4uLmApO1xuICAgICAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmQsIHNlY3Rpb25zLCB0YXVTZWN0aW9uKTtcbiAgICAgICAgICAgIGJ1ZmZHID0gbmV3IEJpZ0J1ZmZlcihuUG9pbnRzKnNHKTtcbiAgICAgICAgICAgIGlmIChwID09IHBvd2VyKzEpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCBmZC5yZWFkVG9CdWZmZXIoYnVmZkcsIDAsIChuUG9pbnRzLTEpKnNHKTtcbiAgICAgICAgICAgICAgICBidWZmRy5zZXQoY3VydmUuRzEuemVyb0FmZmluZSwgKG5Qb2ludHMtMSkqc0cpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhd2FpdCBmZC5yZWFkVG9CdWZmZXIoYnVmZkcsIDAsIG5Qb2ludHMqc0cpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkLCB0cnVlKTtcblxuICAgICAgICAgICAgY29uc3QgcmVzVGF1ID0gYXdhaXQgRy5tdWx0aUV4cEFmZmluZShidWZmRywgYnVmZl9yLCBsb2dnZXIsIHNlY3Rpb25OYW1lICsgXCJfXCIgKyBwKTtcblxuICAgICAgICAgICAgYnVmZl9yID0gbmV3IEJpZ0J1ZmZlcihuUG9pbnRzICogbjhyKTtcblxuICAgICAgICAgICAgcm5nID0gbmV3IENoYUNoYShzZWVkKTtcblxuICAgICAgICAgICAgY29uc3QgYnVmZjQgPSBuZXcgVWludDhBcnJheSg0KTtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmY0ViA9IG5ldyBEYXRhVmlldyhidWZmNC5idWZmZXIpO1xuXG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYENyZWF0aW5nIHJhbmRvbSBudW1iZXJzIFBvd2VycyR7cH0uLi5gKTtcbiAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaTxuUG9pbnRzOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAoKGkgIT0gblBvaW50cy0xKSB8fCAocCAhPSBwb3dlcisxKSkge1xuICAgICAgICAgICAgICAgICAgICBidWZmNFYuc2V0VWludDMyKDAsIHJuZy5uZXh0VTMyKCksIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICBidWZmX3Iuc2V0KGJ1ZmY0LCBpKm44cik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYGJhdGNoVG9Nb250Z29tZXJ5ICR7cH0uLi5gKTtcbiAgICAgICAgICAgIGJ1ZmZfciA9IGF3YWl0IGN1cnZlLkZyLmJhdGNoVG9Nb250Z29tZXJ5KGJ1ZmZfcik7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYGZmdCAke3B9Li4uYCk7XG4gICAgICAgICAgICBidWZmX3IgPSBhd2FpdCBjdXJ2ZS5Gci5mZnQoYnVmZl9yKTtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgYmF0Y2hGcm9tTW9udGdvbWVyeSAke3B9Li4uYCk7XG4gICAgICAgICAgICBidWZmX3IgPSBhd2FpdCBjdXJ2ZS5Gci5iYXRjaEZyb21Nb250Z29tZXJ5KGJ1ZmZfcik7XG5cbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgcmVhZGluZyBwb2ludHMgTGFncmFuZ2Uke3B9Li4uYCk7XG4gICAgICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIGxhZ3JhbmdlU2VjdGlvbik7XG4gICAgICAgICAgICBmZC5wb3MgKz0gc0cqKCgyICoqIHApLTEpO1xuICAgICAgICAgICAgYXdhaXQgZmQucmVhZFRvQnVmZmVyKGJ1ZmZHLCAwLCBuUG9pbnRzKnNHKTtcbiAgICAgICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRSZWFkU2VjdGlvbihmZCwgdHJ1ZSk7XG5cbiAgICAgICAgICAgIGNvbnN0IHJlc0xhZ3JhbmdlID0gYXdhaXQgRy5tdWx0aUV4cEFmZmluZShidWZmRywgYnVmZl9yLCBsb2dnZXIsIHNlY3Rpb25OYW1lICsgXCJfXCIgKyBwICsgXCJfdHJhbnNmb3JtZWRcIik7XG5cbiAgICAgICAgICAgIGlmICghRy5lcShyZXNUYXUsIHJlc0xhZ3JhbmdlKSkge1xuICAgICAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIlBoYXNlMiBjYWNsdXRhdGlvbiBkb2VzIG5vdCBtYXRjaCB3aXRoIHBvd2VycyBvZiB0YXVcIik7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCAqIGFzIGJpbkZpbGVVdGlscyBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuXG4vKlxuICAgIFRoaXMgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBzZWN0aW9uIGluIHRoZSBmZFRvIGZpbGUgd2l0aCBpZCBpZFNlY3Rpb24uXG4gICAgSXQgbXVsdGlwbGllcyB0aGUgcG9pbnRzIGluIGZkRnJvbSBieSBmaXJzdCwgZmlyc3QqaW5jLCBmaXJzdCppbmNeMiwgLi4uLlxuICAgIG5Qb2ludCBUaW1lcy5cbiAgICBJdCBhbHNvIHVwZGF0ZXMgdGhlIG5ld0NoYWxsZW5nZUhhc2hlciB3aXRoIHRoZSBuZXcgcG9pbnRzXG4qL1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYXBwbHlLZXlUb1NlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgaWRTZWN0aW9uLCBjdXJ2ZSwgZ3JvdXBOYW1lLCBmaXJzdCwgaW5jLCBzZWN0aW9uTmFtZSwgbG9nZ2VyKSB7XG4gICAgY29uc3QgTUFYX0NIVU5LX1NJWkUgPSAxIDw8IDE2O1xuICAgIGNvbnN0IEcgPSBjdXJ2ZVtncm91cE5hbWVdO1xuICAgIGNvbnN0IHNHID0gRy5GLm44KjI7XG4gICAgY29uc3QgblBvaW50cyA9IHNlY3Rpb25zW2lkU2VjdGlvbl1bMF0uc2l6ZSAvIHNHO1xuXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLGlkU2VjdGlvbiApO1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZE5ldywgaWRTZWN0aW9uKTtcblxuICAgIGxldCB0ID0gZmlyc3Q7XG4gICAgZm9yIChsZXQgaT0wOyBpPG5Qb2ludHM7IGkgKz0gTUFYX0NIVU5LX1NJWkUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBBcHBseWluZyBrZXk6ICR7c2VjdGlvbk5hbWV9OiAke2l9LyR7blBvaW50c31gKTtcbiAgICAgICAgY29uc3Qgbj0gTWF0aC5taW4oblBvaW50cyAtIGksIE1BWF9DSFVOS19TSVpFKTtcbiAgICAgICAgbGV0IGJ1ZmY7XG4gICAgICAgIGJ1ZmYgPSBhd2FpdCBmZE9sZC5yZWFkKG4qc0cpO1xuICAgICAgICBidWZmID0gYXdhaXQgRy5iYXRjaEFwcGx5S2V5KGJ1ZmYsIHQsIGluYyk7XG4gICAgICAgIGF3YWl0IGZkTmV3LndyaXRlKGJ1ZmYpO1xuICAgICAgICB0ID0gY3VydmUuRnIubXVsKHQsIGN1cnZlLkZyLmV4cChpbmMsIG4pKTtcbiAgICB9XG5cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkTmV3KTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmRPbGQpO1xufVxuXG5cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFwcGx5S2V5VG9DaGFsbGVuZ2VTZWN0aW9uKGZkT2xkLCBmZE5ldywgcmVzcG9uc2VIYXNoZXIsIGN1cnZlLCBncm91cE5hbWUsIG5Qb2ludHMsIGZpcnN0LCBpbmMsIGZvcm1hdE91dCwgc2VjdGlvbk5hbWUsIGxvZ2dlcikge1xuICAgIGNvbnN0IEcgPSBjdXJ2ZVtncm91cE5hbWVdO1xuICAgIGNvbnN0IHNHID0gRy5GLm44KjI7XG4gICAgY29uc3QgY2h1bmtTaXplID0gTWF0aC5mbG9vcigoMTw8MjApIC8gc0cpOyAgIC8vIDEyOE1iIGNodW5rc1xuICAgIGxldCB0ID0gZmlyc3Q7XG4gICAgZm9yIChsZXQgaT0wIDsgaTxuUG9pbnRzIDsgaSs9IGNodW5rU2l6ZSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYEFwcGx5aW5nIGtleSAke3NlY3Rpb25OYW1lfTogJHtpfS8ke25Qb2ludHN9YCk7XG4gICAgICAgIGNvbnN0IG49IE1hdGgubWluKG5Qb2ludHMtaSwgY2h1bmtTaXplICk7XG4gICAgICAgIGNvbnN0IGJ1ZmZJblUgPSBhd2FpdCBmZE9sZC5yZWFkKG4gKiBzRyk7XG4gICAgICAgIGNvbnN0IGJ1ZmZJbkxFTSA9IGF3YWl0IEcuYmF0Y2hVdG9MRU0oYnVmZkluVSk7XG4gICAgICAgIGNvbnN0IGJ1ZmZPdXRMRU0gPSBhd2FpdCBHLmJhdGNoQXBwbHlLZXkoYnVmZkluTEVNLCB0LCBpbmMpO1xuICAgICAgICBsZXQgYnVmZk91dDtcbiAgICAgICAgaWYgKGZvcm1hdE91dCA9PSBcIkNPTVBSRVNTRURcIikge1xuICAgICAgICAgICAgYnVmZk91dCA9IGF3YWl0IEcuYmF0Y2hMRU10b0MoYnVmZk91dExFTSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBidWZmT3V0ID0gYXdhaXQgRy5iYXRjaExFTXRvVShidWZmT3V0TEVNKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyZXNwb25zZUhhc2hlcikgcmVzcG9uc2VIYXNoZXIudXBkYXRlKGJ1ZmZPdXQpO1xuICAgICAgICBhd2FpdCBmZE5ldy53cml0ZShidWZmT3V0KTtcbiAgICAgICAgdCA9IGN1cnZlLkZyLm11bCh0LCBjdXJ2ZS5Gci5leHAoaW5jLCBuKSk7XG4gICAgfVxufVxuXG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG4vLyBGb3JtYXQgb2YgdGhlIG91dHB1dFxuLy8gICAgICBIYXNoIG9mIHRoZSBsYXN0IGNvbnRyaWJ1dGlvbiAgNjQgQnl0ZXNcbi8vICAgICAgMl5OKjItMSBUYXVHMSBQb2ludHMgKGNvbXByZXNzZWQpXG4vLyAgICAgIDJeTiBUYXVHMiBQb2ludHMgKGNvbXByZXNzZWQpXG4vLyAgICAgIDJeTiBBbHBoYVRhdUcxIFBvaW50cyAoY29tcHJlc3NlZClcbi8vICAgICAgMl5OIEJldGFUYXVHMSBQb2ludHMgKGNvbXByZXNzZWQpXG4vLyAgICAgIFB1YmxpYyBLZXlcbi8vICAgICAgICAgIEJldGFHMiAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcxKnMgKGNvbXByZXNzZWQpXG4vLyAgICAgICAgICBHMSpzKnRhdSAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcxKnQgKGNvbXByZXNzZWQpXG4vLyAgICAgICAgICBHMSp0KmFscGhhIChjb21wcmVzc2VkKVxuLy8gICAgICAgICAgRzEqdSAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcxKnUqYmV0YSAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcyKnNwKnRhdSAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcyKnRwKmFscGhhIChjb21wcmVzc2VkKVxuLy8gICAgICAgICAgRzIqdXAqYmV0YSAoY29tcHJlc3NlZClcblxuaW1wb3J0ICogYXMgZmFzdEZpbGUgZnJvbSBcImZhc3RmaWxlXCI7XG5pbXBvcnQgeyBibGFrZTJiIH0gZnJvbSBcIkBub2JsZS9oYXNoZXMvYmxha2UyLmpzXCI7XG5pbXBvcnQgKiBhcyB1dGlscyBmcm9tIFwiLi9wb3dlcnNvZnRhdV91dGlscy5qc1wiO1xuaW1wb3J0ICogYXMgbWlzYyBmcm9tIFwiLi9taXNjLmpzXCI7XG5pbXBvcnQgeyBhcHBseUtleVRvQ2hhbGxlbmdlU2VjdGlvbiB9IGZyb20gXCIuL21wY19hcHBseWtleS5qc1wiO1xuaW1wb3J0ICogYXMga2V5UGFpciBmcm9tIFwiLi9rZXlwYWlyLmpzXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIGNoYWxsZW5nZUNvbnRyaWJ1dGUoY3VydmUsIGNoYWxsZW5nZUZpbGVuYW1lLCByZXNwb25zZUZpbGVOYW1lLCBlbnRyb3B5LCBsb2dnZXIpIHtcbiAgICBjb25zdCBmZEZyb20gPSBhd2FpdCBmYXN0RmlsZS5yZWFkRXhpc3RpbmcoY2hhbGxlbmdlRmlsZW5hbWUpO1xuXG5cbiAgICBjb25zdCBzRzEgPSBjdXJ2ZS5GMS5uNjQqOCoyO1xuICAgIGNvbnN0IHNHMiA9IGN1cnZlLkYyLm42NCo4KjI7XG4gICAgY29uc3QgZG9tYWluU2l6ZSA9IChmZEZyb20udG90YWxTaXplICsgc0cxIC0gNjQgLSBzRzIpIC8gKDQqc0cxICsgc0cyKTtcbiAgICBsZXQgZSA9IGRvbWFpblNpemU7XG4gICAgbGV0IHBvd2VyID0gMDtcbiAgICB3aGlsZSAoZT4xKSB7XG4gICAgICAgIGUgPSBlIC8yO1xuICAgICAgICBwb3dlciArPSAxO1xuICAgIH1cblxuICAgIGlmICgyICoqIHBvd2VyICE9IGRvbWFpblNpemUpIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgZmlsZSBzaXplXCIpO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIlBvd2VyIHRvIHRhdSBzaXplOiBcIitwb3dlcik7XG5cbiAgICBjb25zdCBybmcgPSBhd2FpdCBtaXNjLmdldFJhbmRvbVJuZyhlbnRyb3B5KTtcblxuICAgIGNvbnN0IGZkVG8gPSBhd2FpdCBmYXN0RmlsZS5jcmVhdGVPdmVycmlkZShyZXNwb25zZUZpbGVOYW1lKTtcblxuICAgIC8vIENhbGN1bGF0ZSB0aGUgaGFzaFxuICAgIGNvbnN0IGNoYWxsZW5nZUhhc2hlciA9IGJsYWtlMmIuY3JlYXRlKHsgZGtMZW46IDY0IH0pO1xuICAgIGZvciAobGV0IGk9MDsgaTxmZEZyb20udG90YWxTaXplOyBpKz0gZmRGcm9tLnBhZ2VTaXplKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgSGFzaGluZyBjaGFsbGVuZ2UgJHtpfS8ke2ZkRnJvbS50b3RhbFNpemV9YCk7XG4gICAgICAgIGNvbnN0IHMgPSBNYXRoLm1pbihmZEZyb20udG90YWxTaXplIC0gaSwgZmRGcm9tLnBhZ2VTaXplKTtcbiAgICAgICAgY29uc3QgYnVmZiA9IGF3YWl0IGZkRnJvbS5yZWFkKHMpO1xuICAgICAgICBjaGFsbGVuZ2VIYXNoZXIudXBkYXRlKGJ1ZmYpO1xuICAgIH1cblxuICAgIGNvbnN0IGNsYWltZWRIYXNoID0gYXdhaXQgZmRGcm9tLnJlYWQoNjQsIDApO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1pc2MuZm9ybWF0SGFzaChjbGFpbWVkSGFzaCwgXCJDbGFpbWVkIFByZXZpb3VzIFJlc3BvbnNlIEhhc2g6IFwiKSk7XG5cbiAgICBjb25zdCBjaGFsbGVuZ2VIYXNoID0gY2hhbGxlbmdlSGFzaGVyLmRpZ2VzdCgpO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1pc2MuZm9ybWF0SGFzaChjaGFsbGVuZ2VIYXNoLCBcIkN1cnJlbnQgQ2hhbGxlbmdlIEhhc2g6IFwiKSk7XG5cbiAgICBjb25zdCBrZXkgPSBrZXlQYWlyLmNyZWF0ZVBUYXVLZXkoY3VydmUsIGNoYWxsZW5nZUhhc2gsIHJuZyk7XG5cbiAgICBpZiAobG9nZ2VyKSB7XG4gICAgICAgIFtcInRhdVwiLCBcImFscGhhXCIsIFwiYmV0YVwiXS5mb3JFYWNoKCAoaykgPT4ge1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKGsgKyBcIi5nMV9zOiBcIiArIGN1cnZlLkcxLnRvU3RyaW5nKGtleVtrXS5nMV9zLCAxNikpO1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKGsgKyBcIi5nMV9zeDogXCIgKyBjdXJ2ZS5HMS50b1N0cmluZyhrZXlba10uZzFfc3gsIDE2KSk7XG4gICAgICAgICAgICBsb2dnZXIuZGVidWcoayArIFwiLmcyX3NwOiBcIiArIGN1cnZlLkcyLnRvU3RyaW5nKGtleVtrXS5nMl9zcCwgMTYpKTtcbiAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhrICsgXCIuZzJfc3B4OiBcIiArIGN1cnZlLkcyLnRvU3RyaW5nKGtleVtrXS5nMl9zcHgsIDE2KSk7XG4gICAgICAgICAgICBsb2dnZXIuZGVidWcoXCJcIik7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IHJlc3BvbnNlSGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG5cbiAgICBhd2FpdCBmZFRvLndyaXRlKGNoYWxsZW5nZUhhc2gpO1xuICAgIHJlc3BvbnNlSGFzaGVyLnVwZGF0ZShjaGFsbGVuZ2VIYXNoKTtcblxuICAgIGF3YWl0IGFwcGx5S2V5VG9DaGFsbGVuZ2VTZWN0aW9uKGZkRnJvbSwgZmRUbywgcmVzcG9uc2VIYXNoZXIsIGN1cnZlLCBcIkcxXCIsICgyICoqIHBvd2VyKSoyLTEsIGN1cnZlLkZyLm9uZSAgICAsIGtleS50YXUucHJ2S2V5LCBcIkNPTVBSRVNTRURcIiwgXCJ0YXVHMVwiICAgICAsIGxvZ2dlciApO1xuICAgIGF3YWl0IGFwcGx5S2V5VG9DaGFsbGVuZ2VTZWN0aW9uKGZkRnJvbSwgZmRUbywgcmVzcG9uc2VIYXNoZXIsIGN1cnZlLCBcIkcyXCIsICgyICoqIHBvd2VyKSAgICAsIGN1cnZlLkZyLm9uZSAgICAsIGtleS50YXUucHJ2S2V5LCBcIkNPTVBSRVNTRURcIiwgXCJ0YXVHMlwiICAgICAsIGxvZ2dlciApO1xuICAgIGF3YWl0IGFwcGx5S2V5VG9DaGFsbGVuZ2VTZWN0aW9uKGZkRnJvbSwgZmRUbywgcmVzcG9uc2VIYXNoZXIsIGN1cnZlLCBcIkcxXCIsICgyICoqIHBvd2VyKSAgICAsIGtleS5hbHBoYS5wcnZLZXksIGtleS50YXUucHJ2S2V5LCBcIkNPTVBSRVNTRURcIiwgXCJhbHBoYVRhdUcxXCIsIGxvZ2dlciApO1xuICAgIGF3YWl0IGFwcGx5S2V5VG9DaGFsbGVuZ2VTZWN0aW9uKGZkRnJvbSwgZmRUbywgcmVzcG9uc2VIYXNoZXIsIGN1cnZlLCBcIkcxXCIsICgyICoqIHBvd2VyKSAgICAsIGtleS5iZXRhLnBydktleSAsIGtleS50YXUucHJ2S2V5LCBcIkNPTVBSRVNTRURcIiwgXCJiZXRhVGF1RzFcIiAsIGxvZ2dlciApO1xuICAgIGF3YWl0IGFwcGx5S2V5VG9DaGFsbGVuZ2VTZWN0aW9uKGZkRnJvbSwgZmRUbywgcmVzcG9uc2VIYXNoZXIsIGN1cnZlLCBcIkcyXCIsIDEgICAgICAgICAgICAgLCBrZXkuYmV0YS5wcnZLZXkgLCBrZXkudGF1LnBydktleSwgXCJDT01QUkVTU0VEXCIsIFwiYmV0YVRhdUcyXCIgLCBsb2dnZXIgKTtcblxuICAgIC8vIFdyaXRlIGFuZCBoYXNoIGtleVxuICAgIGNvbnN0IGJ1ZmZLZXkgPSBuZXcgVWludDhBcnJheShjdXJ2ZS5GMS5uOCoyKjYrY3VydmUuRjIubjgqMiozKTtcbiAgICB1dGlscy50b1B0YXVQdWJLZXlScHIoYnVmZktleSwgMCwgY3VydmUsIGtleSwgZmFsc2UpO1xuICAgIGF3YWl0IGZkVG8ud3JpdGUoYnVmZktleSk7XG4gICAgcmVzcG9uc2VIYXNoZXIudXBkYXRlKGJ1ZmZLZXkpO1xuICAgIGNvbnN0IHJlc3BvbnNlSGFzaCA9IHJlc3BvbnNlSGFzaGVyLmRpZ2VzdCgpO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1pc2MuZm9ybWF0SGFzaChyZXNwb25zZUhhc2gsIFwiQ29udHJpYnV0aW9uIFJlc3BvbnNlIEhhc2g6IFwiKSk7XG5cbiAgICBhd2FpdCBmZFRvLmNsb3NlKCk7XG4gICAgYXdhaXQgZmRGcm9tLmNsb3NlKCk7XG59XG5cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCB7IGJsYWtlMmIgfSBmcm9tIFwiQG5vYmxlL2hhc2hlcy9ibGFrZTIuanNcIjtcbmltcG9ydCAqIGFzIHV0aWxzIGZyb20gXCIuL3Bvd2Vyc29mdGF1X3V0aWxzLmpzXCI7XG5pbXBvcnQgKiBhcyBtaXNjIGZyb20gXCIuL21pc2MuanNcIjtcbmltcG9ydCAqIGFzIGJpbkZpbGVVdGlscyBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBiZWFjb24ob2xkUHRhdUZpbGVuYW1lLCBuZXdQVGF1RmlsZW5hbWUsIG5hbWUsICBiZWFjb25IYXNoU3RyLG51bUl0ZXJhdGlvbnNFeHAsIGxvZ2dlcikge1xuICAgIGNvbnN0IGJlYWNvbkhhc2ggPSBtaXNjLmhleDJCeXRlQXJyYXkoYmVhY29uSGFzaFN0cik7XG4gICAgaWYgKCAgIChiZWFjb25IYXNoLmJ5dGVMZW5ndGggPT0gMClcbiAgICAgICAgfHwgKGJlYWNvbkhhc2guYnl0ZUxlbmd0aCoyICE9YmVhY29uSGFzaFN0ci5sZW5ndGgpKVxuICAgIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSW52YWxpZCBCZWFjb24gSGFzaC4gKEl0IG11c3QgYmUgYSB2YWxpZCBoZXhhZGVjaW1hbCBzZXF1ZW5jZSlcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKGJlYWNvbkhhc2gubGVuZ3RoPj0yNTYpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiTWF4aW11bSBsZW5ndGggb2YgYmVhY29uIGhhc2ggaXMgMjU1IGJ5dGVzXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgbnVtSXRlcmF0aW9uc0V4cCA9IHBhcnNlSW50KG51bUl0ZXJhdGlvbnNFeHApO1xuICAgIGlmICgobnVtSXRlcmF0aW9uc0V4cDwxMCl8fChudW1JdGVyYXRpb25zRXhwPjYzKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJJbnZhbGlkIG51bUl0ZXJhdGlvbnNFeHAuIChNdXN0IGJlIGJldHdlZW4gMTAgYW5kIDYzKVwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuXG4gICAgY29uc3Qge2ZkOiBmZE9sZCwgc2VjdGlvbnN9ID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRCaW5GaWxlKG9sZFB0YXVGaWxlbmFtZSwgXCJwdGF1XCIsIDEpO1xuICAgIGNvbnN0IHtjdXJ2ZSwgcG93ZXIsIGNlcmVtb255UG93ZXJ9ID0gYXdhaXQgdXRpbHMucmVhZFBUYXVIZWFkZXIoZmRPbGQsIHNlY3Rpb25zKTtcbiAgICBpZiAocG93ZXIgIT0gY2VyZW1vbnlQb3dlcikge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJUaGlzIGZpbGUgaGFzIGJlZW4gcmVkdWNlZC4gWW91IGNhbm5vdCBjb250cmlidXRlIGludG8gYSByZWR1Y2VkIGZpbGUuXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChzZWN0aW9uc1sxMl0pIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLndhcm4oXCJDb250cmlidXRpbmcgaW50byBhIGZpbGUgdGhhdCBoYXMgcGhhc2UyIGNhbGN1bGF0ZWQuIFlvdSB3aWxsIGhhdmUgdG8gcHJlcGFyZSBwaGFzZTIgYWdhaW4uXCIpO1xuICAgIH1cbiAgICBjb25zdCBjb250cmlidXRpb25zID0gYXdhaXQgdXRpbHMucmVhZENvbnRyaWJ1dGlvbnMoZmRPbGQsIGN1cnZlLCBzZWN0aW9ucyk7XG4gICAgY29uc3QgY3VyQ29udHJpYnV0aW9uID0ge1xuICAgICAgICBuYW1lOiBuYW1lLFxuICAgICAgICB0eXBlOiAxLCAvLyBCZWFjb25cbiAgICAgICAgbnVtSXRlcmF0aW9uc0V4cDogbnVtSXRlcmF0aW9uc0V4cCxcbiAgICAgICAgYmVhY29uSGFzaDogYmVhY29uSGFzaFxuICAgIH07XG5cbiAgICBsZXQgbGFzdENoYWxsZW5nZUhhc2g7XG5cbiAgICBpZiAoY29udHJpYnV0aW9ucy5sZW5ndGg+MCkge1xuICAgICAgICBsYXN0Q2hhbGxlbmdlSGFzaCA9IGNvbnRyaWJ1dGlvbnNbY29udHJpYnV0aW9ucy5sZW5ndGgtMV0ubmV4dENoYWxsZW5nZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBsYXN0Q2hhbGxlbmdlSGFzaCA9IHV0aWxzLmNhbGN1bGF0ZUZpcnN0Q2hhbGxlbmdlSGFzaChjdXJ2ZSwgcG93ZXIsIGxvZ2dlcik7XG4gICAgfVxuXG4gICAgY3VyQ29udHJpYnV0aW9uLmtleSA9IGF3YWl0IHV0aWxzLmtleUZyb21CZWFjb24oY3VydmUsIGxhc3RDaGFsbGVuZ2VIYXNoLCBiZWFjb25IYXNoLCBudW1JdGVyYXRpb25zRXhwKTtcblxuICAgIGNvbnN0IHJlc3BvbnNlSGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG4gICAgcmVzcG9uc2VIYXNoZXIudXBkYXRlKGxhc3RDaGFsbGVuZ2VIYXNoKTtcblxuICAgIGNvbnN0IGZkTmV3ID0gYXdhaXQgYmluRmlsZVV0aWxzLmNyZWF0ZUJpbkZpbGUobmV3UFRhdUZpbGVuYW1lLCBcInB0YXVcIiwgMSwgNyk7XG4gICAgYXdhaXQgdXRpbHMud3JpdGVQVGF1SGVhZGVyKGZkTmV3LCBjdXJ2ZSwgcG93ZXIpO1xuXG4gICAgY29uc3Qgc3RhcnRTZWN0aW9ucyA9IFtdO1xuXG4gICAgbGV0IGZpcnN0UG9pbnRzO1xuICAgIGZpcnN0UG9pbnRzID0gYXdhaXQgcHJvY2Vzc1NlY3Rpb24oMiwgXCJHMVwiLCAgKDIgKiogcG93ZXIpICogMiAtMSwgY3VydmUuRnIuZSgxKSwgY3VyQ29udHJpYnV0aW9uLmtleS50YXUucHJ2S2V5LCBcInRhdUcxXCIsIGxvZ2dlciApO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi50YXVHMSA9IGZpcnN0UG9pbnRzWzFdO1xuICAgIGZpcnN0UG9pbnRzID0gYXdhaXQgcHJvY2Vzc1NlY3Rpb24oMywgXCJHMlwiLCAgKDIgKiogcG93ZXIpICwgY3VydmUuRnIuZSgxKSwgY3VyQ29udHJpYnV0aW9uLmtleS50YXUucHJ2S2V5LCBcInRhdUcyXCIsIGxvZ2dlciApO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi50YXVHMiA9IGZpcnN0UG9pbnRzWzFdO1xuICAgIGZpcnN0UG9pbnRzID0gYXdhaXQgcHJvY2Vzc1NlY3Rpb24oNCwgXCJHMVwiLCAgKDIgKiogcG93ZXIpICwgY3VyQ29udHJpYnV0aW9uLmtleS5hbHBoYS5wcnZLZXksIGN1ckNvbnRyaWJ1dGlvbi5rZXkudGF1LnBydktleSwgXCJhbHBoYVRhdUcxXCIsIGxvZ2dlciApO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5hbHBoYUcxID0gZmlyc3RQb2ludHNbMF07XG4gICAgZmlyc3RQb2ludHMgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbig1LCBcIkcxXCIsICAoMiAqKiBwb3dlcikgLCBjdXJDb250cmlidXRpb24ua2V5LmJldGEucHJ2S2V5LCBjdXJDb250cmlidXRpb24ua2V5LnRhdS5wcnZLZXksIFwiYmV0YVRhdUcxXCIsIGxvZ2dlciApO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5iZXRhRzEgPSBmaXJzdFBvaW50c1swXTtcbiAgICBmaXJzdFBvaW50cyA9IGF3YWl0IHByb2Nlc3NTZWN0aW9uKDYsIFwiRzJcIiwgIDEsIGN1ckNvbnRyaWJ1dGlvbi5rZXkuYmV0YS5wcnZLZXksIGN1ckNvbnRyaWJ1dGlvbi5rZXkudGF1LnBydktleSwgXCJiZXRhVGF1RzJcIiwgbG9nZ2VyICk7XG4gICAgY3VyQ29udHJpYnV0aW9uLmJldGFHMiA9IGZpcnN0UG9pbnRzWzBdO1xuXG4gICAgY3VyQ29udHJpYnV0aW9uLnBhcnRpYWxIYXNoID0gbWlzYy50b1BhcnRpYWxIYXNoKHJlc3BvbnNlSGFzaGVyKTtcblxuICAgIGNvbnN0IGJ1ZmZLZXkgPSBuZXcgVWludDhBcnJheShjdXJ2ZS5GMS5uOCoyKjYrY3VydmUuRjIubjgqMiozKTtcblxuICAgIHV0aWxzLnRvUHRhdVB1YktleVJwcihidWZmS2V5LCAwLCBjdXJ2ZSwgY3VyQ29udHJpYnV0aW9uLmtleSwgZmFsc2UpO1xuXG4gICAgcmVzcG9uc2VIYXNoZXIudXBkYXRlKG5ldyBVaW50OEFycmF5KGJ1ZmZLZXkpKTtcbiAgICBjb25zdCBoYXNoUmVzcG9uc2UgPSByZXNwb25zZUhhc2hlci5kaWdlc3QoKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1pc2MuZm9ybWF0SGFzaChoYXNoUmVzcG9uc2UsIFwiQ29udHJpYnV0aW9uIFJlc3BvbnNlIEhhc2ggaW1wb3J0ZWQ6IFwiKSk7XG5cbiAgICBjb25zdCBuZXh0Q2hhbGxlbmdlSGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG4gICAgbmV4dENoYWxsZW5nZUhhc2hlci51cGRhdGUoaGFzaFJlc3BvbnNlKTtcblxuICAgIGF3YWl0IGhhc2hTZWN0aW9uKGZkTmV3LCBcIkcxXCIsIDIsICgyICoqIHBvd2VyKSAqIDIgLTEsIFwidGF1RzFcIiwgbG9nZ2VyKTtcbiAgICBhd2FpdCBoYXNoU2VjdGlvbihmZE5ldywgXCJHMlwiLCAzLCAoMiAqKiBwb3dlcikgICAgICAgLCBcInRhdUcyXCIsIGxvZ2dlcik7XG4gICAgYXdhaXQgaGFzaFNlY3Rpb24oZmROZXcsIFwiRzFcIiwgNCwgKDIgKiogcG93ZXIpICAgICAgICwgXCJhbHBoYVRhdUcxXCIsIGxvZ2dlcik7XG4gICAgYXdhaXQgaGFzaFNlY3Rpb24oZmROZXcsIFwiRzFcIiwgNSwgKDIgKiogcG93ZXIpICAgICAgICwgXCJiZXRhVGF1RzFcIiwgbG9nZ2VyKTtcbiAgICBhd2FpdCBoYXNoU2VjdGlvbihmZE5ldywgXCJHMlwiLCA2LCAxICAgICAgICAgICAgICAgICAgLCBcImJldGFHMlwiLCBsb2dnZXIpO1xuXG4gICAgY3VyQ29udHJpYnV0aW9uLm5leHRDaGFsbGVuZ2UgPSBuZXh0Q2hhbGxlbmdlSGFzaGVyLmRpZ2VzdCgpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKGN1ckNvbnRyaWJ1dGlvbi5uZXh0Q2hhbGxlbmdlLCBcIk5leHQgQ2hhbGxlbmdlIEhhc2g6IFwiKSk7XG5cbiAgICBjb250cmlidXRpb25zLnB1c2goY3VyQ29udHJpYnV0aW9uKTtcblxuICAgIGF3YWl0IHV0aWxzLndyaXRlQ29udHJpYnV0aW9ucyhmZE5ldywgY3VydmUsIGNvbnRyaWJ1dGlvbnMpO1xuXG4gICAgYXdhaXQgZmRPbGQuY2xvc2UoKTtcbiAgICBhd2FpdCBmZE5ldy5jbG9zZSgpO1xuXG4gICAgcmV0dXJuIGhhc2hSZXNwb25zZTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIHByb2Nlc3NTZWN0aW9uKHNlY3Rpb25JZCwgZ3JvdXBOYW1lLCBOUG9pbnRzLCBmaXJzdCwgaW5jLCBzZWN0aW9uTmFtZSwgbG9nZ2VyKSB7XG4gICAgICAgIGNvbnN0IHJlcyA9IFtdO1xuICAgICAgICBmZE9sZC5wb3MgPSBzZWN0aW9uc1tzZWN0aW9uSWRdWzBdLnA7XG5cbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkTmV3LCBzZWN0aW9uSWQpO1xuXG4gICAgICAgIHN0YXJ0U2VjdGlvbnNbc2VjdGlvbklkXSA9IGZkTmV3LnBvcztcblxuICAgICAgICBjb25zdCBHID0gY3VydmVbZ3JvdXBOYW1lXTtcbiAgICAgICAgY29uc3Qgc0cgPSBHLkYubjgqMjtcbiAgICAgICAgY29uc3QgY2h1bmtTaXplID0gTWF0aC5mbG9vcigoMTw8MjApIC8gc0cpOyAgIC8vIDEyOE1iIGNodW5rc1xuICAgICAgICBsZXQgdCA9IGZpcnN0O1xuICAgICAgICBmb3IgKGxldCBpPTAgOyBpPE5Qb2ludHMgOyBpKz0gY2h1bmtTaXplKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYGFwcGx5aW5nIGtleSR7c2VjdGlvbk5hbWV9OiAke2l9LyR7TlBvaW50c31gKTtcbiAgICAgICAgICAgIGNvbnN0IG49IE1hdGgubWluKE5Qb2ludHMtaSwgY2h1bmtTaXplICk7XG4gICAgICAgICAgICBjb25zdCBidWZmSW4gPSBhd2FpdCBmZE9sZC5yZWFkKG4gKiBzRyk7XG4gICAgICAgICAgICBjb25zdCBidWZmT3V0TEVNID0gYXdhaXQgRy5iYXRjaEFwcGx5S2V5KGJ1ZmZJbiwgdCwgaW5jKTtcblxuICAgICAgICAgICAgLyogQ29kZSB0byB0ZXN0IHRoZSBjYXNlIHdoZXJlIHdlIGRvbid0IGhhdmUgdGhlIDJebS0yIGNvbXBvbmVudFxuICAgICAgICAgICAgaWYgKHNlY3Rpb25OYW1lPT0gXCJ0YXVHMVwiKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYnogPSBuZXcgVWludDhBcnJheSg2NCk7XG4gICAgICAgICAgICAgICAgYnVmZk91dExFTS5zZXQoYnosIDY0KigoMiAqKiBwb3dlcikgLSAxICkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgKi9cblxuICAgICAgICAgICAgY29uc3QgcHJvbWlzZVdyaXRlID0gZmROZXcud3JpdGUoYnVmZk91dExFTSk7XG4gICAgICAgICAgICBjb25zdCBidWZmT3V0QyA9IGF3YWl0IEcuYmF0Y2hMRU10b0MoYnVmZk91dExFTSk7XG5cbiAgICAgICAgICAgIHJlc3BvbnNlSGFzaGVyLnVwZGF0ZShidWZmT3V0Qyk7XG4gICAgICAgICAgICBhd2FpdCBwcm9taXNlV3JpdGU7XG4gICAgICAgICAgICBpZiAoaT09MCkgICAvLyBSZXR1cm4gdGhlIDIgZmlyc3QgcG9pbnRzLlxuICAgICAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxNYXRoLm1pbigyLCBOUG9pbnRzKTsgaisrKVxuICAgICAgICAgICAgICAgICAgICByZXMucHVzaChHLmZyb21ScHJMRU0oYnVmZk91dExFTSwgaipzRykpO1xuICAgICAgICAgICAgdCA9IGN1cnZlLkZyLm11bCh0LCBjdXJ2ZS5Gci5leHAoaW5jLCBuKSk7XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkTmV3KTtcblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuXG4gICAgYXN5bmMgZnVuY3Rpb24gaGFzaFNlY3Rpb24oZmRUbywgZ3JvdXBOYW1lLCBzZWN0aW9uSWQsIG5Qb2ludHMsIHNlY3Rpb25OYW1lLCBsb2dnZXIpIHtcblxuICAgICAgICBjb25zdCBHID0gY3VydmVbZ3JvdXBOYW1lXTtcbiAgICAgICAgY29uc3Qgc0cgPSBHLkYubjgqMjtcbiAgICAgICAgY29uc3QgblBvaW50c0NodW5rID0gTWF0aC5mbG9vcigoMTw8MjQpL3NHKTtcblxuICAgICAgICBjb25zdCBvbGRQb3MgPSBmZFRvLnBvcztcbiAgICAgICAgZmRUby5wb3MgPSBzdGFydFNlY3Rpb25zW3NlY3Rpb25JZF07XG5cbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPCBuUG9pbnRzOyBpICs9IG5Qb2ludHNDaHVuaykge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGBIYXNoaW5nICR7c2VjdGlvbk5hbWV9OiAke2l9LyR7blBvaW50c31gKTtcbiAgICAgICAgICAgIGNvbnN0IG4gPSBNYXRoLm1pbihuUG9pbnRzLWksIG5Qb2ludHNDaHVuayk7XG5cbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZMRU0gPSBhd2FpdCBmZFRvLnJlYWQobiAqIHNHKTtcblxuICAgICAgICAgICAgY29uc3QgYnVmZlUgPSBhd2FpdCBHLmJhdGNoTEVNdG9VKGJ1ZmZMRU0pO1xuXG4gICAgICAgICAgICBuZXh0Q2hhbGxlbmdlSGFzaGVyLnVwZGF0ZShidWZmVSk7XG4gICAgICAgIH1cblxuICAgICAgICBmZFRvLnBvcyA9IG9sZFBvcztcbiAgICB9XG59XG5cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbi8vIEZvcm1hdCBvZiB0aGUgb3V0cHV0XG4vLyAgICAgIEhhc2ggb2YgdGhlIGxhc3QgY29udHJpYnV0aW9uICA2NCBCeXRlc1xuLy8gICAgICAyXk4qMi0xIFRhdUcxIFBvaW50cyAodW5jb21wcmVzc2VkKVxuLy8gICAgICAyXk4gVGF1RzIgUG9pbnRzICh1bmNvbXByZXNzZWQpXG4vLyAgICAgIDJeTiBBbHBoYVRhdUcxIFBvaW50cyAodW5jb21wcmVzc2VkKVxuLy8gICAgICAyXk4gQmV0YVRhdUcxIFBvaW50cyAodW5jb21wcmVzc2VkKVxuXG5pbXBvcnQgeyBibGFrZTJiIH0gZnJvbSBcIkBub2JsZS9oYXNoZXMvYmxha2UyLmpzXCI7XG5pbXBvcnQgKiBhcyB1dGlscyBmcm9tIFwiLi9wb3dlcnNvZnRhdV91dGlscy5qc1wiO1xuaW1wb3J0ICogYXMga2V5UGFpciBmcm9tIFwiLi9rZXlwYWlyLmpzXCI7XG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCAqIGFzIG1pc2MgZnJvbSBcIi4vbWlzYy5qc1wiO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBjb250cmlidXRlKG9sZFB0YXVGaWxlbmFtZSwgbmV3UFRhdUZpbGVuYW1lLCBuYW1lLCBlbnRyb3B5LCBsb2dnZXIpIHtcblxuICAgIGNvbnN0IHtmZDogZmRPbGQsIHNlY3Rpb25zfSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmluRmlsZShvbGRQdGF1RmlsZW5hbWUsIFwicHRhdVwiLCAxKTtcbiAgICBjb25zdCB7Y3VydmUsIHBvd2VyLCBjZXJlbW9ueVBvd2VyfSA9IGF3YWl0IHV0aWxzLnJlYWRQVGF1SGVhZGVyKGZkT2xkLCBzZWN0aW9ucyk7XG4gICAgaWYgKHBvd2VyICE9IGNlcmVtb255UG93ZXIpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiVGhpcyBmaWxlIGhhcyBiZWVuIHJlZHVjZWQuIFlvdSBjYW5ub3QgY29udHJpYnV0ZSBpbnRvIGEgcmVkdWNlZCBmaWxlLlwiKTtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhpcyBmaWxlIGhhcyBiZWVuIHJlZHVjZWQuIFlvdSBjYW5ub3QgY29udHJpYnV0ZSBpbnRvIGEgcmVkdWNlZCBmaWxlLlwiKTtcbiAgICB9XG4gICAgaWYgKHNlY3Rpb25zWzEyXSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIud2FybihcIldBUk5JTkc6IENvbnRyaWJ1dGluZyBpbnRvIGEgZmlsZSB0aGF0IGhhcyBwaGFzZTIgY2FsY3VsYXRlZC4gWW91IHdpbGwgaGF2ZSB0byBwcmVwYXJlIHBoYXNlMiBhZ2Fpbi5cIik7XG4gICAgfVxuICAgIGNvbnN0IGNvbnRyaWJ1dGlvbnMgPSBhd2FpdCB1dGlscy5yZWFkQ29udHJpYnV0aW9ucyhmZE9sZCwgY3VydmUsIHNlY3Rpb25zKTtcbiAgICBjb25zdCBjdXJDb250cmlidXRpb24gPSB7XG4gICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgIHR5cGU6IDAsIC8vIEJlYWNvblxuICAgIH07XG5cbiAgICBsZXQgbGFzdENoYWxsZW5nZUhhc2g7XG5cbiAgICBjb25zdCBybmcgPSBhd2FpdCBtaXNjLmdldFJhbmRvbVJuZyhlbnRyb3B5KTtcblxuICAgIGlmIChjb250cmlidXRpb25zLmxlbmd0aD4wKSB7XG4gICAgICAgIGxhc3RDaGFsbGVuZ2VIYXNoID0gY29udHJpYnV0aW9uc1tjb250cmlidXRpb25zLmxlbmd0aC0xXS5uZXh0Q2hhbGxlbmdlO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGxhc3RDaGFsbGVuZ2VIYXNoID0gdXRpbHMuY2FsY3VsYXRlRmlyc3RDaGFsbGVuZ2VIYXNoKGN1cnZlLCBwb3dlciwgbG9nZ2VyKTtcbiAgICB9XG5cbiAgICAvLyBHZW5lcmF0ZSBhIHJhbmRvbSBrZXlcblxuXG4gICAgY3VyQ29udHJpYnV0aW9uLmtleSA9IGtleVBhaXIuY3JlYXRlUFRhdUtleShjdXJ2ZSwgbGFzdENoYWxsZW5nZUhhc2gsIHJuZyk7XG5cblxuICAgIGNvbnN0IHJlc3BvbnNlSGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG4gICAgcmVzcG9uc2VIYXNoZXIudXBkYXRlKGxhc3RDaGFsbGVuZ2VIYXNoKTtcblxuICAgIGNvbnN0IGZkTmV3ID0gYXdhaXQgYmluRmlsZVV0aWxzLmNyZWF0ZUJpbkZpbGUobmV3UFRhdUZpbGVuYW1lLCBcInB0YXVcIiwgMSwgNyk7XG4gICAgYXdhaXQgdXRpbHMud3JpdGVQVGF1SGVhZGVyKGZkTmV3LCBjdXJ2ZSwgcG93ZXIpO1xuXG4gICAgY29uc3Qgc3RhcnRTZWN0aW9ucyA9IFtdO1xuXG4gICAgbGV0IGZpcnN0UG9pbnRzO1xuICAgIGZpcnN0UG9pbnRzID0gYXdhaXQgcHJvY2Vzc1NlY3Rpb24oMiwgXCJHMVwiLCAgKDIgKiogcG93ZXIpICogMiAtMSwgY3VydmUuRnIuZSgxKSwgY3VyQ29udHJpYnV0aW9uLmtleS50YXUucHJ2S2V5LCBcInRhdUcxXCIgKTtcbiAgICBjdXJDb250cmlidXRpb24udGF1RzEgPSBmaXJzdFBvaW50c1sxXTtcbiAgICBmaXJzdFBvaW50cyA9IGF3YWl0IHByb2Nlc3NTZWN0aW9uKDMsIFwiRzJcIiwgICgyICoqIHBvd2VyKSAsIGN1cnZlLkZyLmUoMSksIGN1ckNvbnRyaWJ1dGlvbi5rZXkudGF1LnBydktleSwgXCJ0YXVHMlwiICk7XG4gICAgY3VyQ29udHJpYnV0aW9uLnRhdUcyID0gZmlyc3RQb2ludHNbMV07XG4gICAgZmlyc3RQb2ludHMgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbig0LCBcIkcxXCIsICAoMiAqKiBwb3dlcikgLCBjdXJDb250cmlidXRpb24ua2V5LmFscGhhLnBydktleSwgY3VyQ29udHJpYnV0aW9uLmtleS50YXUucHJ2S2V5LCBcImFscGhhVGF1RzFcIiApO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5hbHBoYUcxID0gZmlyc3RQb2ludHNbMF07XG4gICAgZmlyc3RQb2ludHMgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbig1LCBcIkcxXCIsICAoMiAqKiBwb3dlcikgLCBjdXJDb250cmlidXRpb24ua2V5LmJldGEucHJ2S2V5LCBjdXJDb250cmlidXRpb24ua2V5LnRhdS5wcnZLZXksIFwiYmV0YVRhdUcxXCIgKTtcbiAgICBjdXJDb250cmlidXRpb24uYmV0YUcxID0gZmlyc3RQb2ludHNbMF07XG4gICAgZmlyc3RQb2ludHMgPSBhd2FpdCBwcm9jZXNzU2VjdGlvbig2LCBcIkcyXCIsICAxLCBjdXJDb250cmlidXRpb24ua2V5LmJldGEucHJ2S2V5LCBjdXJDb250cmlidXRpb24ua2V5LnRhdS5wcnZLZXksIFwiYmV0YVRhdUcyXCIgKTtcbiAgICBjdXJDb250cmlidXRpb24uYmV0YUcyID0gZmlyc3RQb2ludHNbMF07XG5cbiAgICBjdXJDb250cmlidXRpb24ucGFydGlhbEhhc2ggPSBtaXNjLnRvUGFydGlhbEhhc2gocmVzcG9uc2VIYXNoZXIpO1xuXG4gICAgY29uc3QgYnVmZktleSA9IG5ldyBVaW50OEFycmF5KGN1cnZlLkYxLm44KjIqNitjdXJ2ZS5GMi5uOCoyKjMpO1xuXG4gICAgdXRpbHMudG9QdGF1UHViS2V5UnByKGJ1ZmZLZXksIDAsIGN1cnZlLCBjdXJDb250cmlidXRpb24ua2V5LCBmYWxzZSk7XG5cbiAgICByZXNwb25zZUhhc2hlci51cGRhdGUobmV3IFVpbnQ4QXJyYXkoYnVmZktleSkpO1xuICAgIGNvbnN0IGhhc2hSZXNwb25zZSA9IHJlc3BvbnNlSGFzaGVyLmRpZ2VzdCgpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKGhhc2hSZXNwb25zZSwgXCJDb250cmlidXRpb24gUmVzcG9uc2UgSGFzaCBpbXBvcnRlZDogXCIpKTtcblxuICAgIGNvbnN0IG5leHRDaGFsbGVuZ2VIYXNoZXIgPSBibGFrZTJiLmNyZWF0ZSh7IGRrTGVuOiA2NCB9KTtcbiAgICBuZXh0Q2hhbGxlbmdlSGFzaGVyLnVwZGF0ZShoYXNoUmVzcG9uc2UpO1xuXG4gICAgYXdhaXQgaGFzaFNlY3Rpb24oZmROZXcsIFwiRzFcIiwgMiwgKDIgKiogcG93ZXIpICogMiAtMSwgXCJ0YXVHMVwiKTtcbiAgICBhd2FpdCBoYXNoU2VjdGlvbihmZE5ldywgXCJHMlwiLCAzLCAoMiAqKiBwb3dlcikgICAgICAgLCBcInRhdUcyXCIpO1xuICAgIGF3YWl0IGhhc2hTZWN0aW9uKGZkTmV3LCBcIkcxXCIsIDQsICgyICoqIHBvd2VyKSAgICAgICAsIFwiYWxwaGFUYXVHMVwiKTtcbiAgICBhd2FpdCBoYXNoU2VjdGlvbihmZE5ldywgXCJHMVwiLCA1LCAoMiAqKiBwb3dlcikgICAgICAgLCBcImJldGFUYXVHMVwiKTtcbiAgICBhd2FpdCBoYXNoU2VjdGlvbihmZE5ldywgXCJHMlwiLCA2LCAxICAgICAgICAgICAgICAgICAgLCBcImJldGFHMlwiKTtcblxuICAgIGN1ckNvbnRyaWJ1dGlvbi5uZXh0Q2hhbGxlbmdlID0gbmV4dENoYWxsZW5nZUhhc2hlci5kaWdlc3QoKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1pc2MuZm9ybWF0SGFzaChjdXJDb250cmlidXRpb24ubmV4dENoYWxsZW5nZSwgXCJOZXh0IENoYWxsZW5nZSBIYXNoOiBcIikpO1xuXG4gICAgY29udHJpYnV0aW9ucy5wdXNoKGN1ckNvbnRyaWJ1dGlvbik7XG5cbiAgICBhd2FpdCB1dGlscy53cml0ZUNvbnRyaWJ1dGlvbnMoZmROZXcsIGN1cnZlLCBjb250cmlidXRpb25zKTtcblxuICAgIGF3YWl0IGZkT2xkLmNsb3NlKCk7XG4gICAgYXdhaXQgZmROZXcuY2xvc2UoKTtcblxuICAgIHJldHVybiBoYXNoUmVzcG9uc2U7XG5cbiAgICBhc3luYyBmdW5jdGlvbiBwcm9jZXNzU2VjdGlvbihzZWN0aW9uSWQsIGdyb3VwTmFtZSwgTlBvaW50cywgZmlyc3QsIGluYywgc2VjdGlvbk5hbWUpIHtcbiAgICAgICAgY29uc3QgcmVzID0gW107XG4gICAgICAgIGZkT2xkLnBvcyA9IHNlY3Rpb25zW3NlY3Rpb25JZF1bMF0ucDtcblxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24oZmROZXcsIHNlY3Rpb25JZCk7XG5cbiAgICAgICAgc3RhcnRTZWN0aW9uc1tzZWN0aW9uSWRdID0gZmROZXcucG9zO1xuXG4gICAgICAgIGNvbnN0IEcgPSBjdXJ2ZVtncm91cE5hbWVdO1xuICAgICAgICBjb25zdCBzRyA9IEcuRi5uOCoyO1xuICAgICAgICBjb25zdCBjaHVua1NpemUgPSBNYXRoLmZsb29yKCgxPDwyMCkgLyBzRyk7ICAgLy8gMTI4TWIgY2h1bmtzXG4gICAgICAgIGxldCB0ID0gZmlyc3Q7XG4gICAgICAgIGZvciAobGV0IGk9MCA7IGk8TlBvaW50cyA7IGkrPSBjaHVua1NpemUpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgcHJvY2Vzc2luZzogJHtzZWN0aW9uTmFtZX06ICR7aX0vJHtOUG9pbnRzfWApO1xuICAgICAgICAgICAgY29uc3Qgbj0gTWF0aC5taW4oTlBvaW50cy1pLCBjaHVua1NpemUgKTtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZJbiA9IGF3YWl0IGZkT2xkLnJlYWQobiAqIHNHKTtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZPdXRMRU0gPSBhd2FpdCBHLmJhdGNoQXBwbHlLZXkoYnVmZkluLCB0LCBpbmMpO1xuXG4gICAgICAgICAgICAvKiBDb2RlIHRvIHRlc3QgdGhlIGNhc2Ugd2hlcmUgd2UgZG9uJ3QgaGF2ZSB0aGUgMl5tLTIgY29tcG9uZW50XG4gICAgICAgICAgICBpZiAoc2VjdGlvbk5hbWU9PSBcInRhdUcxXCIpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBieiA9IG5ldyBVaW50OEFycmF5KDY0KTtcbiAgICAgICAgICAgICAgICBidWZmT3V0TEVNLnNldChieiwgNjQqKCgyICoqIHBvd2VyKSAtIDEgKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAqL1xuXG4gICAgICAgICAgICBjb25zdCBwcm9taXNlV3JpdGUgPSBmZE5ldy53cml0ZShidWZmT3V0TEVNKTtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZPdXRDID0gYXdhaXQgRy5iYXRjaExFTXRvQyhidWZmT3V0TEVNKTtcblxuICAgICAgICAgICAgcmVzcG9uc2VIYXNoZXIudXBkYXRlKGJ1ZmZPdXRDKTtcbiAgICAgICAgICAgIGF3YWl0IHByb21pc2VXcml0ZTtcbiAgICAgICAgICAgIGlmIChpPT0wKSAgIC8vIFJldHVybiB0aGUgMiBmaXJzdCBwb2ludHMuXG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaj0wOyBqPE1hdGgubWluKDIsIE5Qb2ludHMpOyBqKyspXG4gICAgICAgICAgICAgICAgICAgIHJlcy5wdXNoKEcuZnJvbVJwckxFTShidWZmT3V0TEVNLCBqKnNHKSk7XG4gICAgICAgICAgICB0ID0gY3VydmUuRnIubXVsKHQsIGN1cnZlLkZyLmV4cChpbmMsIG4pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmROZXcpO1xuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG5cbiAgICBhc3luYyBmdW5jdGlvbiBoYXNoU2VjdGlvbihmZFRvLCBncm91cE5hbWUsIHNlY3Rpb25JZCwgblBvaW50cywgc2VjdGlvbk5hbWUpIHtcblxuICAgICAgICBjb25zdCBHID0gY3VydmVbZ3JvdXBOYW1lXTtcbiAgICAgICAgY29uc3Qgc0cgPSBHLkYubjgqMjtcbiAgICAgICAgY29uc3QgblBvaW50c0NodW5rID0gTWF0aC5mbG9vcigoMTw8MjQpL3NHKTtcblxuICAgICAgICBjb25zdCBvbGRQb3MgPSBmZFRvLnBvcztcbiAgICAgICAgZmRUby5wb3MgPSBzdGFydFNlY3Rpb25zW3NlY3Rpb25JZF07XG5cbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPCBuUG9pbnRzOyBpICs9IG5Qb2ludHNDaHVuaykge1xuICAgICAgICAgICAgaWYgKChsb2dnZXIpJiZpKSBsb2dnZXIuZGVidWcoYEhhc2hpbmcgJHtzZWN0aW9uTmFtZX06IGAgKyBpKTtcbiAgICAgICAgICAgIGNvbnN0IG4gPSBNYXRoLm1pbihuUG9pbnRzLWksIG5Qb2ludHNDaHVuayk7XG5cbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZMRU0gPSBhd2FpdCBmZFRvLnJlYWQobiAqIHNHKTtcblxuICAgICAgICAgICAgY29uc3QgYnVmZlUgPSBhd2FpdCBHLmJhdGNoTEVNdG9VKGJ1ZmZMRU0pO1xuXG4gICAgICAgICAgICBuZXh0Q2hhbGxlbmdlSGFzaGVyLnVwZGF0ZShidWZmVSk7XG4gICAgICAgIH1cblxuICAgICAgICBmZFRvLnBvcyA9IG9sZFBvcztcbiAgICB9XG5cblxufVxuXG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCAqIGFzIHV0aWxzIGZyb20gXCIuL3Bvd2Vyc29mdGF1X3V0aWxzLmpzXCI7XG5pbXBvcnQge0JpZ0J1ZmZlcn0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBwcmVwYXJlUGhhc2UyKG9sZFB0YXVGaWxlbmFtZSwgbmV3UFRhdUZpbGVuYW1lLCBsb2dnZXIpIHtcblxuICAgIGNvbnN0IHtmZDogZmRPbGQsIHNlY3Rpb25zfSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmluRmlsZShvbGRQdGF1RmlsZW5hbWUsIFwicHRhdVwiLCAxKTtcbiAgICBjb25zdCB7Y3VydmUsIHBvd2VyfSA9IGF3YWl0IHV0aWxzLnJlYWRQVGF1SGVhZGVyKGZkT2xkLCBzZWN0aW9ucyk7XG5cbiAgICBjb25zdCBmZE5ldyA9IGF3YWl0IGJpbkZpbGVVdGlscy5jcmVhdGVCaW5GaWxlKG5ld1BUYXVGaWxlbmFtZSwgXCJwdGF1XCIsIDEsIDExKTtcbiAgICBhd2FpdCB1dGlscy53cml0ZVBUYXVIZWFkZXIoZmROZXcsIGN1cnZlLCBwb3dlcik7XG5cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgMik7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDMpO1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5jb3B5U2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCA0KTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgNSk7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDYpO1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5jb3B5U2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCA3KTtcblxuICAgIGF3YWl0IHByb2Nlc3NTZWN0aW9uKDIsIDEyLCBcIkcxXCIsIFwidGF1RzFcIiApO1xuICAgIGF3YWl0IHByb2Nlc3NTZWN0aW9uKDMsIDEzLCBcIkcyXCIsIFwidGF1RzJcIiApO1xuICAgIGF3YWl0IHByb2Nlc3NTZWN0aW9uKDQsIDE0LCBcIkcxXCIsIFwiYWxwaGFUYXVHMVwiICk7XG4gICAgYXdhaXQgcHJvY2Vzc1NlY3Rpb24oNSwgMTUsIFwiRzFcIiwgXCJiZXRhVGF1RzFcIiApO1xuXG4gICAgYXdhaXQgZmRPbGQuY2xvc2UoKTtcbiAgICBhd2FpdCBmZE5ldy5jbG9zZSgpO1xuXG4gICAgLy8gYXdhaXQgZnMucHJvbWlzZXMudW5saW5rKG5ld1BUYXVGaWxlbmFtZSsgXCIudG1wXCIpO1xuXG4gICAgcmV0dXJuO1xuXG4gICAgYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc1NlY3Rpb24ob2xkU2VjdGlvbklkLCBuZXdTZWN0aW9uSWQsIEdzdHIsIHNlY3Rpb25OYW1lKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIlN0YXJ0aW5nIHNlY3Rpb246IFwiK3NlY3Rpb25OYW1lKTtcblxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24oZmROZXcsIG5ld1NlY3Rpb25JZCk7XG5cbiAgICAgICAgZm9yIChsZXQgcD0wOyBwPD1wb3dlcjsgcCsrKSB7XG4gICAgICAgICAgICBhd2FpdCBwcm9jZXNzU2VjdGlvblBvd2VyKHApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG9sZFNlY3Rpb25JZCA9PSAyKSB7XG4gICAgICAgICAgICBhd2FpdCBwcm9jZXNzU2VjdGlvblBvd2VyKHBvd2VyKzEpO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFdyaXRlU2VjdGlvbihmZE5ldyk7XG5cblxuICAgICAgICBhc3luYyBmdW5jdGlvbiBwcm9jZXNzU2VjdGlvblBvd2VyKHApIHtcbiAgICAgICAgICAgIGNvbnN0IG5Qb2ludHMgPSAyICoqIHA7XG4gICAgICAgICAgICBjb25zdCBHID0gY3VydmVbR3N0cl07XG4gICAgICAgICAgICBjb25zdCBzR2luID0gRy5GLm44KjI7XG5cbiAgICAgICAgICAgIGxldCBidWZmO1xuICAgICAgICAgICAgYnVmZiA9IG5ldyBCaWdCdWZmZXIoblBvaW50cypzR2luKTtcblxuICAgICAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBvbGRTZWN0aW9uSWQpO1xuICAgICAgICAgICAgaWYgKChvbGRTZWN0aW9uSWQgPT0gMikmJihwPT1wb3dlcisxKSkge1xuICAgICAgICAgICAgICAgIGF3YWl0IGZkT2xkLnJlYWRUb0J1ZmZlcihidWZmLCAwLChuUG9pbnRzLTEpKnNHaW4gKTtcbiAgICAgICAgICAgICAgICBidWZmLnNldChjdXJ2ZS5HMS56ZXJvQWZmaW5lLCAoblBvaW50cy0xKSpzR2luICk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGF3YWl0IGZkT2xkLnJlYWRUb0J1ZmZlcihidWZmLCAwLG5Qb2ludHMqc0dpbiApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkT2xkLCB0cnVlKTtcblxuXG4gICAgICAgICAgICBidWZmID0gYXdhaXQgRy5sYWdyYW5nZUV2YWx1YXRpb25zKGJ1ZmYsIFwiYWZmaW5lXCIsIFwiYWZmaW5lXCIsIGxvZ2dlciwgc2VjdGlvbk5hbWUpO1xuICAgICAgICAgICAgYXdhaXQgZmROZXcud3JpdGUoYnVmZik7XG5cbiAgICAgICAgICAgIC8qXG4gICAgICAgICAgICBpZiAocCA8PSBjdXJ2ZS5Gci5zKSB7XG4gICAgICAgICAgICAgICAgYnVmZiA9IGF3YWl0IEcuaWZmdChidWZmLCBcImFmZmluZVwiLCBcImFmZmluZVwiLCBsb2dnZXIsIHNlY3Rpb25OYW1lKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBmZE5ldy53cml0ZShidWZmKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAocCA9PSBjdXJ2ZS5Gci5zKzEpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBzbWFsbE0gPSAxPDxjdXJ2ZS5Gci5zO1xuICAgICAgICAgICAgICAgIGxldCB0MCA9IG5ldyBCaWdCdWZmZXIoIHNtYWxsTSAqIHNHbWlkICk7XG4gICAgICAgICAgICAgICAgbGV0IHQxID0gbmV3IEJpZ0J1ZmZlciggc21hbGxNICogc0dtaWQgKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHNoaWZ0X3RvX3NtYWxsX20gPSBGci5leHAoRnIuc2hpZnQsIHNtYWxsTSk7XG4gICAgICAgICAgICAgICAgY29uc3Qgb25lX292ZXJfZGVub20gPSBGci5pbnYoRnIuc3ViKHNoaWZ0X3RvX3NtYWxsX20sIEZyLm9uZSkpO1xuXG4gICAgICAgICAgICAgICAgbGV0IHNJbnZBY2MgPSBGci5vbmU7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpPHNtYWxsTTsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRpID0gIGJ1ZmYuc2xpY2UoaSpzR2luLCAoaSsxKSpzR2luKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdG1pID0gYnVmZi5zbGljZSgoaStzbWFsbE0pKnNHaW4sIChpK3NtYWxsTSsxKSpzR2luKTtcblxuICAgICAgICAgICAgICAgICAgICB0MC5zZXQoXG4gICAgICAgICAgICAgICAgICAgICAgICBHLnRpbWVzRnIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgRy5zdWIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEcudGltZXNGcih0aSAsIHNoaWZ0X3RvX3NtYWxsX20pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0bWlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vdmVyX2Rlbm9tXG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgaSpzR21pZFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB0MS5zZXQoXG4gICAgICAgICAgICAgICAgICAgICAgICBHLnRpbWVzRnIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgRy5zdWIoIHRtaSwgdGkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZyLm11bChzSW52QWNjLCBvbmVfb3Zlcl9kZW5vbSlcbiAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICBpKnNHbWlkXG4gICAgICAgICAgICAgICAgICAgICk7XG5cblxuICAgICAgICAgICAgICAgICAgICBzSW52QWNjID0gRnIubXVsKHNJbnZBY2MsIEZyLnNoaWZ0SW52KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdDAgPSBhd2FpdCBHLmlmZnQodDAsIFwiamFjb2JpYW5cIiwgXCJhZmZpbmVcIiwgbG9nZ2VyLCBzZWN0aW9uTmFtZSArIFwiIHQwXCIpO1xuICAgICAgICAgICAgICAgIGF3YWl0IGZkTmV3LndyaXRlKHQwKTtcbiAgICAgICAgICAgICAgICB0MCA9IG51bGw7XG4gICAgICAgICAgICAgICAgdDEgPSBhd2FpdCBHLmlmZnQodDEsIFwiamFjb2JpYW5cIiwgXCJhZmZpbmVcIiwgbG9nZ2VyLCBzZWN0aW9uTmFtZSArIFwiIHQwXCIpO1xuICAgICAgICAgICAgICAgIGF3YWl0IGZkTmV3LndyaXRlKHQxKTtcblxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJQb3dlciB0b28gYmlnXCIpO1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlBvd2VyIHRvIGJpZ1wiKTtcbiAgICAgICAgICAgIH1cbiovXG4gICAgICAgIH1cbiAgICB9XG59XG5cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCAqIGFzIGJpbkZpbGVVdGlscyBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuaW1wb3J0ICogYXMgdXRpbHMgZnJvbSBcIi4vcG93ZXJzb2Z0YXVfdXRpbHMuanNcIjtcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gdHJ1bmNhdGUocHRhdUZpbGVuYW1lLCB0ZW1wbGF0ZSwgbG9nZ2VyKSB7XG5cbiAgICBjb25zdCB7ZmQ6IGZkT2xkLCBzZWN0aW9uc30gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUocHRhdUZpbGVuYW1lLCBcInB0YXVcIiwgMSk7XG4gICAgY29uc3Qge2N1cnZlLCBwb3dlciwgY2VyZW1vbnlQb3dlcn0gPSBhd2FpdCB1dGlscy5yZWFkUFRhdUhlYWRlcihmZE9sZCwgc2VjdGlvbnMpO1xuXG4gICAgY29uc3Qgc0cxID0gY3VydmUuRzEuRi5uOCoyO1xuICAgIGNvbnN0IHNHMiA9IGN1cnZlLkcyLkYubjgqMjtcblxuICAgIGZvciAobGV0IHA9MTsgcDxwb3dlcjsgcCsrKSB7XG4gICAgICAgIGF3YWl0IGdlbmVyYXRlVHJ1bmNhdGUocCk7XG4gICAgfVxuXG4gICAgYXdhaXQgZmRPbGQuY2xvc2UoKTtcblxuICAgIHJldHVybiB0cnVlO1xuXG4gICAgYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVUcnVuY2F0ZShwKSB7XG5cbiAgICAgICAgbGV0IHNQID0gcC50b1N0cmluZygpO1xuICAgICAgICB3aGlsZSAoc1AubGVuZ3RoPDIpIHNQID0gXCIwXCIgKyBzUDtcblxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJXcml0aW5nIFBvd2VyOiBcIitzUCk7XG5cbiAgICAgICAgY29uc3QgZmROZXcgPSBhd2FpdCBiaW5GaWxlVXRpbHMuY3JlYXRlQmluRmlsZSh0ZW1wbGF0ZSArIHNQICsgXCIucHRhdVwiLCBcInB0YXVcIiwgMSwgMTEpO1xuICAgICAgICBhd2FpdCB1dGlscy53cml0ZVBUYXVIZWFkZXIoZmROZXcsIGN1cnZlLCBwLCBjZXJlbW9ueVBvd2VyKTtcblxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgMiwgKCgyICoqIHApKjItMSkgKiBzRzEgKTsgLy8gdGFnRzFcbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDMsICgyICoqIHApICogc0cyKTsgLy8gdGF1RzJcbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDQsICgyICoqIHApICogc0cxKTsgLy8gYWxmYVRhdUcxXG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5jb3B5U2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCA1LCAoMiAqKiBwKSAqIHNHMSk7IC8vIGJldGFUYXVHMVxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgNiwgIHNHMik7IC8vIGJldGFUYXVHMlxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgNyk7IC8vIGNvbnRyaWJ1dGlvbnNcbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDEyLCAoKDIgKiogKHArMSkpKjIgLTEpICogc0cxKTsgLy8gTF90YXVHMVxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgMTMsICgoMiAqKiBwKSoyIC0xKSAqIHNHMik7IC8vIExfdGF1RzJcbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDE0LCAoKDIgKiogcCkqMiAtMSkgKiBzRzEpOyAvLyBMX2FsZmFUYXVHMVxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgMTUsICgoMiAqKiBwKSoyIC0xKSAqIHNHMSk7IC8vIExfYmV0YVRhdUcxXG5cbiAgICAgICAgYXdhaXQgZmROZXcuY2xvc2UoKTtcbiAgICB9XG5cblxufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0ICogYXMgYmluRmlsZVV0aWxzIGZyb20gXCJAaWRlbjMvYmluZmlsZXV0aWxzXCI7XG5pbXBvcnQgKiBhcyB1dGlscyBmcm9tIFwiLi9wb3dlcnNvZnRhdV91dGlscy5qc1wiO1xuaW1wb3J0IHtCaWdCdWZmZXJ9IGZyb20gXCJmZmphdmFzY3JpcHRcIjtcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gY29udmVydChvbGRQdGF1RmlsZW5hbWUsIG5ld1BUYXVGaWxlbmFtZSwgbG9nZ2VyKSB7XG5cbiAgICBjb25zdCB7ZmQ6IGZkT2xkLCBzZWN0aW9uc30gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUob2xkUHRhdUZpbGVuYW1lLCBcInB0YXVcIiwgMSk7XG4gICAgY29uc3Qge2N1cnZlLCBwb3dlcn0gPSBhd2FpdCB1dGlscy5yZWFkUFRhdUhlYWRlcihmZE9sZCwgc2VjdGlvbnMpO1xuXG4gICAgY29uc3QgZmROZXcgPSBhd2FpdCBiaW5GaWxlVXRpbHMuY3JlYXRlQmluRmlsZShuZXdQVGF1RmlsZW5hbWUsIFwicHRhdVwiLCAxLCAxMSk7XG4gICAgYXdhaXQgdXRpbHMud3JpdGVQVGF1SGVhZGVyKGZkTmV3LCBjdXJ2ZSwgcG93ZXIpO1xuXG4gICAgLy8gY29uc3QgZmRUbXAgPSBhd2FpdCBmYXN0RmlsZS5jcmVhdGVPdmVycmlkZShuZXdQVGF1RmlsZW5hbWUrIFwiLnRtcFwiKTtcblxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5jb3B5U2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCAyKTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgMyk7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDQpO1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5jb3B5U2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCA1KTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgNik7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDcpO1xuXG4gICAgYXdhaXQgcHJvY2Vzc1NlY3Rpb24oMiwgMTIsIFwiRzFcIiwgXCJ0YXVHMVwiICk7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDEzKTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgMTQpO1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5jb3B5U2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCAxNSk7XG5cbiAgICBhd2FpdCBmZE9sZC5jbG9zZSgpO1xuICAgIGF3YWl0IGZkTmV3LmNsb3NlKCk7XG5cbiAgICAvLyBhd2FpdCBmcy5wcm9taXNlcy51bmxpbmsobmV3UFRhdUZpbGVuYW1lKyBcIi50bXBcIik7XG5cbiAgICByZXR1cm47XG5cbiAgICBhc3luYyBmdW5jdGlvbiBwcm9jZXNzU2VjdGlvbihvbGRTZWN0aW9uSWQsIG5ld1NlY3Rpb25JZCwgR3N0ciwgc2VjdGlvbk5hbWUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiU3RhcnRpbmcgc2VjdGlvbjogXCIrc2VjdGlvbk5hbWUpO1xuXG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZE5ldywgbmV3U2VjdGlvbklkKTtcblxuICAgICAgICBjb25zdCBzaXplID0gc2VjdGlvbnNbbmV3U2VjdGlvbklkXVswXS5zaXplO1xuICAgICAgICBjb25zdCBjaHVua1NpemUgPSBmZE9sZC5wYWdlU2l6ZTtcbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBuZXdTZWN0aW9uSWQpO1xuICAgICAgICBmb3IgKGxldCBwPTA7IHA8c2l6ZTsgcCs9Y2h1bmtTaXplKSB7XG4gICAgICAgICAgICBjb25zdCBsID0gTWF0aC5taW4oc2l6ZSAtcCwgY2h1bmtTaXplKTtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZE9sZC5yZWFkKGwpO1xuICAgICAgICAgICAgYXdhaXQgZmROZXcud3JpdGUoYnVmZik7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkT2xkKTtcblxuICAgICAgICBpZiAob2xkU2VjdGlvbklkID09IDIpIHtcbiAgICAgICAgICAgIGF3YWl0IHByb2Nlc3NTZWN0aW9uUG93ZXIocG93ZXIrMSk7XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkTmV3KTtcblxuICAgICAgICBhc3luYyBmdW5jdGlvbiBwcm9jZXNzU2VjdGlvblBvd2VyKHApIHtcbiAgICAgICAgICAgIGNvbnN0IG5Qb2ludHMgPSAyICoqIHA7XG4gICAgICAgICAgICBjb25zdCBHID0gY3VydmVbR3N0cl07XG4gICAgICAgICAgICBjb25zdCBzR2luID0gRy5GLm44KjI7XG5cbiAgICAgICAgICAgIGxldCBidWZmO1xuICAgICAgICAgICAgYnVmZiA9IG5ldyBCaWdCdWZmZXIoblBvaW50cypzR2luKTtcblxuICAgICAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBvbGRTZWN0aW9uSWQpO1xuICAgICAgICAgICAgaWYgKChvbGRTZWN0aW9uSWQgPT0gMikmJihwPT1wb3dlcisxKSkge1xuICAgICAgICAgICAgICAgIGF3YWl0IGZkT2xkLnJlYWRUb0J1ZmZlcihidWZmLCAwLChuUG9pbnRzLTEpKnNHaW4gKTtcbiAgICAgICAgICAgICAgICBidWZmLnNldChjdXJ2ZS5HMS56ZXJvQWZmaW5lLCAoblBvaW50cy0xKSpzR2luICk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGF3YWl0IGZkT2xkLnJlYWRUb0J1ZmZlcihidWZmLCAwLG5Qb2ludHMqc0dpbiApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkT2xkLCB0cnVlKTtcblxuICAgICAgICAgICAgYnVmZiA9IGF3YWl0IEcubGFncmFuZ2VFdmFsdWF0aW9ucyhidWZmLCBcImFmZmluZVwiLCBcImFmZmluZVwiLCBsb2dnZXIsIHNlY3Rpb25OYW1lKTtcbiAgICAgICAgICAgIGF3YWl0IGZkTmV3LndyaXRlKGJ1ZmYpO1xuXG4gICAgICAgICAgICAvKlxuICAgICAgICAgICAgaWYgKHAgPD0gY3VydmUuRnIucykge1xuICAgICAgICAgICAgICAgIGJ1ZmYgPSBhd2FpdCBHLmlmZnQoYnVmZiwgXCJhZmZpbmVcIiwgXCJhZmZpbmVcIiwgbG9nZ2VyLCBzZWN0aW9uTmFtZSk7XG4gICAgICAgICAgICAgICAgYXdhaXQgZmROZXcud3JpdGUoYnVmZik7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHAgPT0gY3VydmUuRnIucysxKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc21hbGxNID0gMTw8Y3VydmUuRnIucztcbiAgICAgICAgICAgICAgICBsZXQgdDAgPSBuZXcgQmlnQnVmZmVyKCBzbWFsbE0gKiBzR21pZCApO1xuICAgICAgICAgICAgICAgIGxldCB0MSA9IG5ldyBCaWdCdWZmZXIoIHNtYWxsTSAqIHNHbWlkICk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBzaGlmdF90b19zbWFsbF9tID0gRnIuZXhwKEZyLnNoaWZ0LCBzbWFsbE0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IG9uZV9vdmVyX2Rlbm9tID0gRnIuaW52KEZyLnN1YihzaGlmdF90b19zbWFsbF9tLCBGci5vbmUpKTtcblxuICAgICAgICAgICAgICAgIGxldCBzSW52QWNjID0gRnIub25lO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaTxzbWFsbE07IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaSUxMDAwMCkgbG9nZ2VyLmRlYnVnKGBzZWN0aW9uTmFtZSBwcmVwYXJlIEwgY2FsYzogJHtzZWN0aW9uTmFtZX0sICR7aX0vJHtzbWFsbE19YCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRpID0gIGJ1ZmYuc2xpY2UoaSpzR2luLCAoaSsxKSpzR2luKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdG1pID0gYnVmZi5zbGljZSgoaStzbWFsbE0pKnNHaW4sIChpK3NtYWxsTSsxKSpzR2luKTtcblxuICAgICAgICAgICAgICAgICAgICB0MC5zZXQoXG4gICAgICAgICAgICAgICAgICAgICAgICBHLnRpbWVzRnIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgRy5zdWIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEcudGltZXNGcih0aSAsIHNoaWZ0X3RvX3NtYWxsX20pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0bWlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vdmVyX2Rlbm9tXG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgaSpzR21pZFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB0MS5zZXQoXG4gICAgICAgICAgICAgICAgICAgICAgICBHLnRpbWVzRnIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgRy5zdWIoIHRtaSwgdGkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZyLm11bChzSW52QWNjLCBvbmVfb3Zlcl9kZW5vbSlcbiAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICBpKnNHbWlkXG4gICAgICAgICAgICAgICAgICAgICk7XG5cblxuICAgICAgICAgICAgICAgICAgICBzSW52QWNjID0gRnIubXVsKHNJbnZBY2MsIEZyLnNoaWZ0SW52KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdDAgPSBhd2FpdCBHLmlmZnQodDAsIFwiamFjb2JpYW5cIiwgXCJhZmZpbmVcIiwgbG9nZ2VyLCBzZWN0aW9uTmFtZSArIFwiIHQwXCIpO1xuICAgICAgICAgICAgICAgIGF3YWl0IGZkTmV3LndyaXRlKHQwKTtcbiAgICAgICAgICAgICAgICB0MCA9IG51bGw7XG4gICAgICAgICAgICAgICAgdDEgPSBhd2FpdCBHLmlmZnQodDEsIFwiamFjb2JpYW5cIiwgXCJhZmZpbmVcIiwgbG9nZ2VyLCBzZWN0aW9uTmFtZSArIFwiIHQxXCIpO1xuICAgICAgICAgICAgICAgIGF3YWl0IGZkTmV3LndyaXRlKHQxKTtcblxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJQb3dlciB0b28gYmlnXCIpO1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlBvd2VyIHRvIGJpZ1wiKTtcbiAgICAgICAgICAgIH1cbiovXG4gICAgICAgIH1cblxuXG4gICAgfVxufVxuXG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgKiBhcyB1dGlscyBmcm9tIFwiLi9wb3dlcnNvZnRhdV91dGlscy5qc1wiO1xuaW1wb3J0ICogYXMgYmluRmlsZVV0aWxzIGZyb20gXCJAaWRlbjMvYmluZmlsZXV0aWxzXCI7XG5pbXBvcnQgeyBzdHJpbmdpZnlCaWdJbnRzV2l0aEZpZWxkIH0gZnJvbSBcIi4vbWlzYy5qc1wiO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBleHBvcnRKc29uKHBUYXVGaWxlbmFtZSwgdmVyYm9zZSkge1xuICAgIGNvbnN0IHtmZCwgc2VjdGlvbnN9ID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRCaW5GaWxlKHBUYXVGaWxlbmFtZSwgXCJwdGF1XCIsIDEpO1xuXG4gICAgY29uc3Qge2N1cnZlLCBwb3dlcn0gPSBhd2FpdCB1dGlscy5yZWFkUFRhdUhlYWRlcihmZCwgc2VjdGlvbnMpO1xuXG4gICAgY29uc3QgcFRhdSA9IHt9O1xuICAgIHBUYXUucSA9IGN1cnZlLnE7XG4gICAgcFRhdS5wb3dlciA9IHBvd2VyO1xuICAgIHBUYXUuY29udHJpYnV0aW9ucyA9IGF3YWl0IHV0aWxzLnJlYWRDb250cmlidXRpb25zKGZkLCBjdXJ2ZSwgc2VjdGlvbnMpO1xuXG4gICAgcFRhdS50YXVHMSA9IGF3YWl0IGV4cG9ydFNlY3Rpb24oMiwgXCJHMVwiLCAoMiAqKiBwb3dlcikqMiAtMSwgXCJ0YXVHMVwiKTtcbiAgICBwVGF1LnRhdUcyID0gYXdhaXQgZXhwb3J0U2VjdGlvbigzLCBcIkcyXCIsICgyICoqIHBvd2VyKSwgXCJ0YXVHMlwiKTtcbiAgICBwVGF1LmFscGhhVGF1RzEgPSBhd2FpdCBleHBvcnRTZWN0aW9uKDQsIFwiRzFcIiwgKDIgKiogcG93ZXIpLCBcImFscGhhVGF1RzFcIik7XG4gICAgcFRhdS5iZXRhVGF1RzEgPSBhd2FpdCBleHBvcnRTZWN0aW9uKDUsIFwiRzFcIiwgKDIgKiogcG93ZXIpLCBcImJldGFUYXVHMVwiKTtcbiAgICBwVGF1LmJldGFHMiA9IGF3YWl0IGV4cG9ydFNlY3Rpb24oNiwgXCJHMlwiLCAxLCBcImJldGFHMlwiKTtcblxuICAgIHBUYXUubFRhdUcxID0gYXdhaXQgZXhwb3J0TGFncmFuZ2UoMTIsIFwiRzFcIiwgXCJsVGF1RzFcIik7XG4gICAgcFRhdS5sVGF1RzIgPSBhd2FpdCBleHBvcnRMYWdyYW5nZSgxMywgXCJHMlwiLCBcImxUYXVHMlwiKTtcbiAgICBwVGF1LmxBbHBoYVRhdUcxID0gYXdhaXQgZXhwb3J0TGFncmFuZ2UoMTQsIFwiRzFcIiwgXCJsQWxwaGFUYXVHMlwiKTtcbiAgICBwVGF1LmxCZXRhVGF1RzEgPSBhd2FpdCBleHBvcnRMYWdyYW5nZSgxNSwgXCJHMVwiLCBcImxCZXRhVGF1RzJcIik7XG5cbiAgICBhd2FpdCBmZC5jbG9zZSgpO1xuXG4gICAgcmV0dXJuIHN0cmluZ2lmeUJpZ0ludHNXaXRoRmllbGQoY3VydmUuRnIsIHBUYXUpO1xuXG5cblxuICAgIGFzeW5jIGZ1bmN0aW9uIGV4cG9ydFNlY3Rpb24oc2VjdGlvbklkLCBncm91cE5hbWUsIG5Qb2ludHMsIHNlY3Rpb25OYW1lKSB7XG4gICAgICAgIGNvbnN0IEcgPSBjdXJ2ZVtncm91cE5hbWVdO1xuICAgICAgICBjb25zdCBzRyA9IEcuRi5uOCoyO1xuXG4gICAgICAgIGNvbnN0IHJlcyA9IFtdO1xuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIHNlY3Rpb25JZCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTwgblBvaW50czsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoKHZlcmJvc2UpJiZpJiYoaSUxMDAwMCA9PSAwKSkgY29uc29sZS5sb2coYCR7c2VjdGlvbk5hbWV9OiBgICsgaSk7XG4gICAgICAgICAgICBjb25zdCBidWZmID0gYXdhaXQgZmQucmVhZChzRyk7XG4gICAgICAgICAgICByZXMucHVzaChHLmZyb21ScHJMRU0oYnVmZiwgMCkpO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRSZWFkU2VjdGlvbihmZCk7XG5cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiBleHBvcnRMYWdyYW5nZShzZWN0aW9uSWQsIGdyb3VwTmFtZSwgc2VjdGlvbk5hbWUpIHtcbiAgICAgICAgY29uc3QgRyA9IGN1cnZlW2dyb3VwTmFtZV07XG4gICAgICAgIGNvbnN0IHNHID0gRy5GLm44KjI7XG5cbiAgICAgICAgY29uc3QgcmVzID0gW107XG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkLCBzZWN0aW9ucywgc2VjdGlvbklkKTtcbiAgICAgICAgZm9yIChsZXQgcD0wOyBwPD1wb3dlcjsgcCsrKSB7XG4gICAgICAgICAgICBpZiAodmVyYm9zZSkgY29uc29sZS5sb2coYCR7c2VjdGlvbk5hbWV9OiBQb3dlcjogJHtwfWApO1xuICAgICAgICAgICAgcmVzW3BdID0gW107XG4gICAgICAgICAgICBjb25zdCBuUG9pbnRzID0gKDIgKiogcCk7XG4gICAgICAgICAgICBmb3IgKGxldCBpPTA7IGk8blBvaW50czsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKCh2ZXJib3NlKSYmaSYmKGklMTAwMDAgPT0gMCkpIGNvbnNvbGUubG9nKGAke3NlY3Rpb25OYW1lfTogJHtpfS8ke25Qb2ludHN9YCk7XG4gICAgICAgICAgICAgICAgY29uc3QgYnVmZiA9IGF3YWl0IGZkLnJlYWQoc0cpO1xuICAgICAgICAgICAgICAgIHJlc1twXS5wdXNoKEcuZnJvbVJwckxFTShidWZmLCAwKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkLCB0cnVlKTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cblxufVxuXG5cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmV4cG9ydCB7ZGVmYXVsdCBhcyBuZXdBY2N1bXVsYXRvcn0gZnJvbSBcIi4vcG93ZXJzb2Z0YXVfbmV3LmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgZXhwb3J0Q2hhbGxlbmdlfSBmcm9tIFwiLi9wb3dlcnNvZnRhdV9leHBvcnRfY2hhbGxlbmdlLmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgaW1wb3J0UmVzcG9uc2V9IGZyb20gXCIuL3Bvd2Vyc29mdGF1X2ltcG9ydC5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIHZlcmlmeX0gZnJvbSBcIi4vcG93ZXJzb2Z0YXVfdmVyaWZ5LmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgY2hhbGxlbmdlQ29udHJpYnV0ZX0gZnJvbSBcIi4vcG93ZXJzb2Z0YXVfY2hhbGxlbmdlX2NvbnRyaWJ1dGUuanNcIjtcbmV4cG9ydCB7ZGVmYXVsdCBhcyBiZWFjb259IGZyb20gXCIuL3Bvd2Vyc29mdGF1X2JlYWNvbi5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIGNvbnRyaWJ1dGV9IGZyb20gXCIuL3Bvd2Vyc29mdGF1X2NvbnRyaWJ1dGUuanNcIjtcbmV4cG9ydCB7ZGVmYXVsdCBhcyBwcmVwYXJlUGhhc2UyfSBmcm9tIFwiLi9wb3dlcnNvZnRhdV9wcmVwYXJlcGhhc2UyLmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgdHJ1bmNhdGV9IGZyb20gXCIuL3Bvd2Vyc29mdGF1X3RydW5jYXRlLmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgY29udmVydH0gZnJvbSBcIi4vcG93ZXJzb2Z0YXVfY29udmVydC5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIGV4cG9ydEpzb259IGZyb20gXCIuL3Bvd2Vyc29mdGF1X2V4cG9ydF9qc29uLmpzXCI7XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByMWNzUHJpbnQocjFjcywgc3ltcywgbG9nZ2VyKSB7XG4gICAgZm9yIChsZXQgaT0wOyBpPHIxY3MuY29uc3RyYWludHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgcHJpbnRDb3N0cmFpbnQocjFjcy5jb25zdHJhaW50c1tpXSk7XG4gICAgfVxuICAgIGZ1bmN0aW9uIHByaW50Q29zdHJhaW50KGMpIHtcbiAgICAgICAgY29uc3QgbGMyc3RyID0gKGxjKSA9PiB7XG4gICAgICAgICAgICBsZXQgUyA9IFwiXCI7XG4gICAgICAgICAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMobGMpO1xuICAgICAgICAgICAga2V5cy5mb3JFYWNoKCAoaykgPT4ge1xuICAgICAgICAgICAgICAgIGxldCBuYW1lID0gc3ltcy52YXJJZHgyTmFtZVtrXTtcbiAgICAgICAgICAgICAgICBpZiAobmFtZSA9PSBcIm9uZVwiKSBuYW1lID0gXCIxXCI7XG5cbiAgICAgICAgICAgICAgICBsZXQgdnMgPSByMWNzLmN1cnZlLkZyLnRvU3RyaW5nKGxjW2tdKTtcbiAgICAgICAgICAgICAgICBpZiAodnMgPT0gXCIxXCIpIHZzID0gXCJcIjsgIC8vIERvIG5vdCBzaG93IG9uZXNcbiAgICAgICAgICAgICAgICBpZiAodnMgPT0gXCItMVwiKSB2cyA9IFwiLVwiOyAgLy8gRG8gbm90IHNob3cgb25lc1xuICAgICAgICAgICAgICAgIGlmICgoUyE9XCJcIikmJih2c1swXSE9XCItXCIpKSB2cyA9IFwiK1wiK3ZzO1xuICAgICAgICAgICAgICAgIGlmIChTIT1cIlwiKSB2cyA9IFwiIFwiK3ZzO1xuICAgICAgICAgICAgICAgIFM9IFMgKyB2cyAgICsgbmFtZTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIFM7XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IFMgPSBgWyAke2xjMnN0cihjWzBdKX0gXSAqIFsgJHtsYzJzdHIoY1sxXSl9IF0gLSBbICR7bGMyc3RyKGNbMl0pfSBdID0gMGA7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFMpO1xuICAgIH1cblxufVxuIiwiY29uc3QgU1VCQVJSQVlfU0laRSA9IDB4NDAwMDA7XG5cbmNvbnN0IEJpZ0FycmF5SGFuZGxlciA9IHtcbiAgICBnZXQ6IGZ1bmN0aW9uKG9iaiwgcHJvcCkge1xuICAgICAgICBpZiAoIWlzTmFOKHByb3ApKSB7XG4gICAgICAgICAgICByZXR1cm4gb2JqLmdldEVsZW1lbnQocHJvcCk7XG4gICAgICAgIH0gZWxzZSByZXR1cm4gb2JqW3Byb3BdO1xuICAgIH0sXG4gICAgc2V0OiBmdW5jdGlvbihvYmosIHByb3AsIHZhbHVlKSB7XG4gICAgICAgIGlmICghaXNOYU4ocHJvcCkpIHtcbiAgICAgICAgICAgIHJldHVybiBvYmouc2V0RWxlbWVudChwcm9wLCB2YWx1ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBvYmpbcHJvcF0gPSB2YWx1ZTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuY2xhc3MgX0JpZ0FycmF5IHtcbiAgICBjb25zdHJ1Y3RvciAoaW5pdFNpemUpIHtcbiAgICAgICAgdGhpcy5sZW5ndGggPSBpbml0U2l6ZSB8fCAwO1xuICAgICAgICB0aGlzLmFyciA9IG5ldyBBcnJheShTVUJBUlJBWV9TSVpFKTtcblxuICAgICAgICBmb3IgKGxldCBpPTA7IGk8aW5pdFNpemU7IGkrPVNVQkFSUkFZX1NJWkUpIHtcbiAgICAgICAgICAgIHRoaXMuYXJyW2kvU1VCQVJSQVlfU0laRV0gPSBuZXcgQXJyYXkoTWF0aC5taW4oU1VCQVJSQVlfU0laRSwgaW5pdFNpemUgLSBpKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIHB1c2ggKCkge1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8YXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB0aGlzLnNldEVsZW1lbnQgKHRoaXMubGVuZ3RoLCBhcmd1bWVudHNbaV0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgc2xpY2UgKGYsIHQpIHtcbiAgICAgICAgY29uc3QgYXJyID0gbmV3IEFycmF5KHQtZik7XG4gICAgICAgIGZvciAobGV0IGk9ZjsgaTwgdDsgaSsrKSBhcnJbaS1mXSA9IHRoaXMuZ2V0RWxlbWVudChpKTtcbiAgICAgICAgcmV0dXJuIGFycjtcbiAgICB9XG4gICAgZ2V0RWxlbWVudChpZHgpIHtcbiAgICAgICAgaWR4ID0gcGFyc2VJbnQoaWR4KTtcbiAgICAgICAgY29uc3QgaWR4MSA9IE1hdGguZmxvb3IoaWR4IC8gU1VCQVJSQVlfU0laRSk7XG4gICAgICAgIGNvbnN0IGlkeDIgPSBpZHggJSBTVUJBUlJBWV9TSVpFO1xuICAgICAgICByZXR1cm4gdGhpcy5hcnJbaWR4MV0gPyB0aGlzLmFycltpZHgxXVtpZHgyXSA6IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgc2V0RWxlbWVudChpZHgsIHZhbHVlKSB7XG4gICAgICAgIGlkeCA9IHBhcnNlSW50KGlkeCk7XG4gICAgICAgIGNvbnN0IGlkeDEgPSBNYXRoLmZsb29yKGlkeCAvIFNVQkFSUkFZX1NJWkUpO1xuICAgICAgICBpZiAoIXRoaXMuYXJyW2lkeDFdKSB7XG4gICAgICAgICAgICB0aGlzLmFycltpZHgxXSA9IG5ldyBBcnJheShTVUJBUlJBWV9TSVpFKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBpZHgyID0gaWR4ICUgU1VCQVJSQVlfU0laRTtcbiAgICAgICAgdGhpcy5hcnJbaWR4MV1baWR4Ml0gPSB2YWx1ZTtcbiAgICAgICAgaWYgKGlkeCA+PSB0aGlzLmxlbmd0aCkgdGhpcy5sZW5ndGggPSBpZHgrMTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGdldEtleXMoKSB7XG4gICAgICAgIGNvbnN0IG5ld0EgPSBuZXcgQmlnQXJyYXkoKTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHRoaXMuYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5hcnJbaV0pIHtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8dGhpcy5hcnJbaV0ubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB0aGlzLmFycltpXVtqXSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgbmV3QS5wdXNoKGkqU1VCQVJSQVlfU0laRStqKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3QTtcbiAgICB9XG59XG5cbmNsYXNzIEJpZ0FycmF5IHtcbiAgICBjb25zdHJ1Y3RvciggaW5pdFNpemUgKSB7XG4gICAgICAgIGNvbnN0IG9iaiA9IG5ldyBfQmlnQXJyYXkoaW5pdFNpemUpO1xuICAgICAgICBjb25zdCBleHRPYmogPSBuZXcgUHJveHkob2JqLCBCaWdBcnJheUhhbmRsZXIpO1xuICAgICAgICByZXR1cm4gZXh0T2JqO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQmlnQXJyYXk7XG4iLCJcbmltcG9ydCBmcyBmcm9tXCJmc1wiO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gb3BlbihmaWxlTmFtZSwgb3BlbkZsYWdzLCBjYWNoZVNpemUsIHBhZ2VTaXplKSB7XG4gICAgY2FjaGVTaXplID0gY2FjaGVTaXplIHx8IDQwOTYqNjQ7XG4gICAgaWYgKHR5cGVvZiBvcGVuRmxhZ3MgIT09IFwibnVtYmVyXCIgJiYgW1widytcIiwgXCJ3eCtcIiwgXCJyXCIsIFwiYXgrXCIsIFwiYStcIl0uaW5kZXhPZihvcGVuRmxhZ3MpIDwwKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIG9wZW4gb3B0aW9uXCIpO1xuICAgIGNvbnN0IGZkID1hd2FpdCBmcy5wcm9taXNlcy5vcGVuKGZpbGVOYW1lLCBvcGVuRmxhZ3MpO1xuXG4gICAgY29uc3Qgc3RhdHMgPSBhd2FpdCBmZC5zdGF0KCk7XG5cbiAgICByZXR1cm4gIG5ldyBGYXN0RmlsZShmZCwgc3RhdHMsIGNhY2hlU2l6ZSwgcGFnZVNpemUsIGZpbGVOYW1lKTtcbn1cblxuXG5jbGFzcyBGYXN0RmlsZSB7XG5cbiAgICBjb25zdHJ1Y3RvcihmZCwgc3RhdHMsIGNhY2hlU2l6ZSwgcGFnZVNpemUsIGZpbGVOYW1lKSB7XG4gICAgICAgIHRoaXMuZmlsZU5hbWUgPSBmaWxlTmFtZTtcbiAgICAgICAgdGhpcy5mZCA9IGZkO1xuICAgICAgICB0aGlzLnBvcyA9IDA7XG4gICAgICAgIHRoaXMucGFnZVNpemUgPSBwYWdlU2l6ZSB8fCAoMSA8PCA4KTtcbiAgICAgICAgd2hpbGUgKHRoaXMucGFnZVNpemUgPCBzdGF0cy5ibGtzaXplKSB7XG4gICAgICAgICAgICB0aGlzLnBhZ2VTaXplICo9IDI7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50b3RhbFNpemUgPSBzdGF0cy5zaXplO1xuICAgICAgICB0aGlzLnRvdGFsUGFnZXMgPSBNYXRoLmZsb29yKChzdGF0cy5zaXplIC0xKSAvIHRoaXMucGFnZVNpemUpKzE7XG4gICAgICAgIHRoaXMubWF4UGFnZXNMb2FkZWQgPSBNYXRoLmZsb29yKCBjYWNoZVNpemUgLyB0aGlzLnBhZ2VTaXplKSsxO1xuICAgICAgICB0aGlzLnBhZ2VzID0ge307XG4gICAgICAgIHRoaXMucGVuZGluZ0xvYWRzID0gW107XG4gICAgICAgIHRoaXMud3JpdGluZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLnJlYWRpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5hdkJ1ZmZzID0gW107XG4gICAgICAgIHRoaXMuaGlzdG9yeSA9IHt9O1xuICAgIH1cblxuICAgIF9sb2FkUGFnZShwKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBQID0gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCk9PiB7XG4gICAgICAgICAgICBzZWxmLnBlbmRpbmdMb2Fkcy5wdXNoKHtcbiAgICAgICAgICAgICAgICBwYWdlOiBwLFxuICAgICAgICAgICAgICAgIHJlc29sdmU6IHJlc29sdmUsXG4gICAgICAgICAgICAgICAgcmVqZWN0OiByZWplY3RcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBMb2FkIHJlcXVlc3Q6IFwiLCBwKTtcbiAgICAgICAgcmV0dXJuIFA7XG4gICAgfVxuXG4gICAgX19zdGF0dXNQYWdlKHMsIHApIHtcbiAgICAgICAgY29uc3QgbG9nRW50cnkgPSBbXTtcbiAgICAgICAgY29uc3Qgc2VsZj10aGlzO1xuICAgICAgICBpZiAoIXNlbGYubG9nSGlzdG9yeSkgcmV0dXJuO1xuICAgICAgICBsb2dFbnRyeS5wdXNoKFwiPT1cIiArIHMrIFwiIFwiICtwKTtcbiAgICAgICAgbGV0IFMgPSBcIlwiO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8c2VsZi5wZW5kaW5nTG9hZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChzZWxmLnBlbmRpbmdMb2Fkc1tpXS5wYWdlID09IHApIFMgPSBTICsgXCIgXCIgKyBpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChTKSBsb2dFbnRyeS5wdXNoKFwiUGVuZGluZyBsb2FkczpcIitTKTtcbiAgICAgICAgaWYgKHR5cGVvZiBzZWxmLnBhZ2VzW3BdICE9IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgIGNvbnN0IHBhZ2UgPSBzZWxmLnBhZ2VzW3BdO1xuICAgICAgICAgICAgbG9nRW50cnkucHVzaChcIkxvYWRlZFwiKTtcbiAgICAgICAgICAgIGxvZ0VudHJ5LnB1c2goXCJwZW5kaW5nT3BzOiBcIitwYWdlLnBlbmRpbmdPcHMpO1xuICAgICAgICAgICAgaWYgKHBhZ2UubG9hZGluZykgbG9nRW50cnkucHVzaChcImxvYWRpbmc6IFwiK3BhZ2UubG9hZGluZyk7XG4gICAgICAgICAgICBpZiAocGFnZS53cml0aW5nKSBsb2dFbnRyeS5wdXNoKFwid3JpdGluZ1wiKTtcbiAgICAgICAgICAgIGlmIChwYWdlLmRpcnR5KSBsb2dFbnRyeS5wdXNoKFwiZGlydHlcIik7XG4gICAgICAgIH1cbiAgICAgICAgbG9nRW50cnkucHVzaChcIj09XCIpO1xuXG4gICAgICAgIGlmICghc2VsZi5oaXN0b3J5W3BdKSBzZWxmLmhpc3RvcnlbcF0gPSBbXTtcbiAgICAgICAgc2VsZi5oaXN0b3J5W3BdLnB1c2gobG9nRW50cnkpO1xuICAgIH1cblxuICAgIF9fcHJpbnRIaXN0b3J5KHApIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmICghc2VsZi5oaXN0b3J5W3BdKSBjb25zb2xlLmxvZyhcIkVtcHR5IEhpc3RvcnkgXCIsIHApO1xuICAgICAgICBjb25zb2xlLmxvZyhcIkhpc3RvcnkgXCIrcCk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxzZWxmLmhpc3RvcnlbcF0ubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGZvciAobGV0IGo9MDsgajxzZWxmLmhpc3RvcnlbcF1baV0ubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIi0+IFwiICsgc2VsZi5oaXN0b3J5W3BdW2ldW2pdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuXG5cbiAgICBfdHJpZ2dlckxvYWQoKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIGlmIChzZWxmLnJlYWRpbmcpIHJldHVybjtcbiAgICAgICAgaWYgKHNlbGYucGVuZGluZ0xvYWRzLmxlbmd0aD09MCkgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IHBhZ2VJZHhzID0gT2JqZWN0LmtleXMoc2VsZi5wYWdlcyk7XG5cbiAgICAgICAgY29uc3QgZGVsZXRhYmxlUGFnZXMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHBhZ2VJZHhzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBwYWdlID0gc2VsZi5wYWdlc1twYXJzZUludChwYWdlSWR4c1tpXSldO1xuICAgICAgICAgICAgaWYgKChwYWdlLmRpcnR5ID09IGZhbHNlKSYmKHBhZ2UucGVuZGluZ09wcz09MCkmJighcGFnZS53cml0aW5nKSYmKCFwYWdlLmxvYWRpbmcpKSBkZWxldGFibGVQYWdlcy5wdXNoKHBhcnNlSW50KHBhZ2VJZHhzW2ldKSk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgZnJlZVBhZ2VzID0gc2VsZi5tYXhQYWdlc0xvYWRlZCAtIHBhZ2VJZHhzLmxlbmd0aDtcblxuICAgICAgICBjb25zdCBvcHMgPSBbXTtcblxuICAgICAgICAvLyB3aGlsZSBwZW5kaW5nIGxvYWRzIGFuZFxuICAgICAgICAvLyAgICAgdGhlIHBhZ2UgaXMgbG9hZGVkIG9yIEkgY2FuIHJlY292ZXIgb25lLlxuICAgICAgICB3aGlsZSAoXG4gICAgICAgICAgICAoc2VsZi5wZW5kaW5nTG9hZHMubGVuZ3RoPjApICYmXG4gICAgICAgICAgICAoICAgKHR5cGVvZiBzZWxmLnBhZ2VzW3NlbGYucGVuZGluZ0xvYWRzWzBdLnBhZ2VdICE9IFwidW5kZWZpbmVkXCIgKVxuICAgICAgICAgICAgICB8fCggIChmcmVlUGFnZXM+MClcbiAgICAgICAgICAgICAgICAgfHwoZGVsZXRhYmxlUGFnZXMubGVuZ3RoPjApKSkpIHtcbiAgICAgICAgICAgIGNvbnN0IGxvYWQgPSBzZWxmLnBlbmRpbmdMb2Fkcy5zaGlmdCgpO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBzZWxmLnBhZ2VzW2xvYWQucGFnZV0gIT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbbG9hZC5wYWdlXS5wZW5kaW5nT3BzICsrO1xuICAgICAgICAgICAgICAgIGNvbnN0IGlkeCA9IGRlbGV0YWJsZVBhZ2VzLmluZGV4T2YobG9hZC5wYWdlKTtcbiAgICAgICAgICAgICAgICBpZiAoaWR4Pj0wKSBkZWxldGFibGVQYWdlcy5zcGxpY2UoaWR4LCAxKTtcbiAgICAgICAgICAgICAgICBpZiAoc2VsZi5wYWdlc1tsb2FkLnBhZ2VdLmxvYWRpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5wYWdlc1tsb2FkLnBhZ2VdLmxvYWRpbmcucHVzaChsb2FkKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBsb2FkLnJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBMb2FkIChjYWNoZWQpOiBcIiwgbG9hZC5wYWdlKTtcblxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoZnJlZVBhZ2VzKSB7XG4gICAgICAgICAgICAgICAgICAgIGZyZWVQYWdlcy0tO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZwID0gZGVsZXRhYmxlUGFnZXMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJCZWZvcmUgVW5sb2FkOiBcIiwgZnApO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLmF2QnVmZnMudW5zaGlmdChzZWxmLnBhZ2VzW2ZwXSk7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBzZWxmLnBhZ2VzW2ZwXTtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBVbmxvYWQ6IFwiLCBmcCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGxvYWQucGFnZT49c2VsZi50b3RhbFBhZ2VzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbbG9hZC5wYWdlXSA9IGdldE5ld1BhZ2UoKTtcbiAgICAgICAgICAgICAgICAgICAgbG9hZC5yZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuX19zdGF0dXNQYWdlKFwiQWZ0ZXIgTG9hZCAobmV3KTogXCIsIGxvYWQucGFnZSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5yZWFkaW5nID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5wYWdlc1tsb2FkLnBhZ2VdID0gZ2V0TmV3UGFnZSgpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnBhZ2VzW2xvYWQucGFnZV0ubG9hZGluZyA9IFtsb2FkXTtcbiAgICAgICAgICAgICAgICAgICAgb3BzLnB1c2goc2VsZi5mZC5yZWFkKHNlbGYucGFnZXNbbG9hZC5wYWdlXS5idWZmLCAwLCBzZWxmLnBhZ2VTaXplLCBsb2FkLnBhZ2Uqc2VsZi5wYWdlU2l6ZSkudGhlbigocmVzKT0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbbG9hZC5wYWdlXS5zaXplID0gcmVzLmJ5dGVzUmVhZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGxvYWRpbmcgPSBzZWxmLnBhZ2VzW2xvYWQucGFnZV0ubG9hZGluZztcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBzZWxmLnBhZ2VzW2xvYWQucGFnZV0ubG9hZGluZztcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaTxsb2FkaW5nLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9hZGluZ1tpXS5yZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIExvYWQgKGxvYWRlZCk6IFwiLCBsb2FkLnBhZ2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgICAgICAgICAgfSwgKGVycikgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbG9hZC5yZWplY3QoZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIExvYWQgKGxvYWRpbmcpOiBcIiwgbG9hZC5wYWdlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gaWYgKG9wcy5sZW5ndGg+MSkgY29uc29sZS5sb2cob3BzLmxlbmd0aCk7XG5cbiAgICAgICAgUHJvbWlzZS5hbGwob3BzKS50aGVuKCAoKSA9PiB7XG4gICAgICAgICAgICBzZWxmLnJlYWRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIGlmIChzZWxmLnBlbmRpbmdMb2Fkcy5sZW5ndGg+MCkgc2V0SW1tZWRpYXRlKHNlbGYuX3RyaWdnZXJMb2FkLmJpbmQoc2VsZikpO1xuICAgICAgICAgICAgc2VsZi5fdHJ5Q2xvc2UoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZnVuY3Rpb24gZ2V0TmV3UGFnZSgpIHtcbiAgICAgICAgICAgIGlmIChzZWxmLmF2QnVmZnMubGVuZ3RoPjApIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwID0gc2VsZi5hdkJ1ZmZzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgcC5kaXJ0eSA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHAucGVuZGluZ09wcyA9IDE7XG4gICAgICAgICAgICAgICAgcC5zaXplID0wO1xuICAgICAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBkaXJ0eTogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIGJ1ZmY6IG5ldyBVaW50OEFycmF5KHNlbGYucGFnZVNpemUpLFxuICAgICAgICAgICAgICAgICAgICBwZW5kaW5nT3BzOiAxLFxuICAgICAgICAgICAgICAgICAgICBzaXplOiAwXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgfVxuXG5cbiAgICBfdHJpZ2dlcldyaXRlKCkge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgaWYgKHNlbGYud3JpdGluZykgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IHBhZ2VJZHhzID0gT2JqZWN0LmtleXMoc2VsZi5wYWdlcyk7XG5cbiAgICAgICAgY29uc3Qgb3BzID0gW107XG5cbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHBhZ2VJZHhzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBwYWdlID0gc2VsZi5wYWdlc1twYXJzZUludChwYWdlSWR4c1tpXSldO1xuICAgICAgICAgICAgaWYgKHBhZ2UuZGlydHkpIHtcbiAgICAgICAgICAgICAgICBwYWdlLmRpcnR5ID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgcGFnZS53cml0aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBzZWxmLndyaXRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgICAgIG9wcy5wdXNoKCBzZWxmLmZkLndyaXRlKHBhZ2UuYnVmZiwgMCwgcGFnZS5zaXplLCBwYXJzZUludChwYWdlSWR4c1tpXSkqc2VsZi5wYWdlU2l6ZSkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHBhZ2Uud3JpdGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSwgKGVycikgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIkVSUk9SIFdyaXRpbmc6IFwiK2Vycik7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuZXJyb3IgPSBlcnI7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuX3RyeUNsb3NlKCk7XG4gICAgICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHNlbGYud3JpdGluZykge1xuICAgICAgICAgICAgUHJvbWlzZS5hbGwob3BzKS50aGVuKCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgc2VsZi53cml0aW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgc2V0SW1tZWRpYXRlKHNlbGYuX3RyaWdnZXJXcml0ZS5iaW5kKHNlbGYpKTtcbiAgICAgICAgICAgICAgICBzZWxmLl90cnlDbG9zZSgpO1xuICAgICAgICAgICAgICAgIGlmIChzZWxmLnBlbmRpbmdMb2Fkcy5sZW5ndGg+MCkgc2V0SW1tZWRpYXRlKHNlbGYuX3RyaWdnZXJMb2FkLmJpbmQoc2VsZikpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBfZ2V0RGlydHlQYWdlKCkge1xuICAgICAgICBmb3IgKGxldCBwIGluIHRoaXMucGFnZXMpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnBhZ2VzW3BdLmRpcnR5KSByZXR1cm4gcDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGUoYnVmZiwgcG9zKSB7XG4gICAgICAgIGlmIChidWZmLmJ5dGVMZW5ndGggPT0gMCkgcmV0dXJuO1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbi8qXG4gICAgICAgIGlmIChidWZmLmJ5dGVMZW5ndGggPiBzZWxmLnBhZ2VTaXplKnNlbGYubWF4UGFnZXNMb2FkZWQqMC44KSB7XG4gICAgICAgICAgICBjb25zdCBjYWNoZVNpemUgPSBNYXRoLmZsb29yKGJ1ZmYuYnl0ZUxlbmd0aCAqIDEuMSk7XG4gICAgICAgICAgICB0aGlzLm1heFBhZ2VzTG9hZGVkID0gTWF0aC5mbG9vciggY2FjaGVTaXplIC8gc2VsZi5wYWdlU2l6ZSkrMTtcbiAgICAgICAgfVxuKi9cbiAgICAgICAgaWYgKHR5cGVvZiBwb3MgPT0gXCJ1bmRlZmluZWRcIikgcG9zID0gc2VsZi5wb3M7XG4gICAgICAgIHNlbGYucG9zID0gcG9zK2J1ZmYuYnl0ZUxlbmd0aDtcbiAgICAgICAgaWYgKHNlbGYudG90YWxTaXplIDwgcG9zICsgYnVmZi5ieXRlTGVuZ3RoKSBzZWxmLnRvdGFsU2l6ZSA9IHBvcyArIGJ1ZmYuYnl0ZUxlbmd0aDtcbiAgICAgICAgaWYgKHNlbGYucGVuZGluZ0Nsb3NlKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiV3JpdGluZyBhIGNsb3NpbmcgZmlsZVwiKTtcbiAgICAgICAgY29uc3QgZmlyc3RQYWdlID0gTWF0aC5mbG9vcihwb3MgLyBzZWxmLnBhZ2VTaXplKTtcbiAgICAgICAgY29uc3QgbGFzdFBhZ2UgPSBNYXRoLmZsb29yKChwb3MgKyBidWZmLmJ5dGVMZW5ndGggLTEpIC8gc2VsZi5wYWdlU2l6ZSk7XG5cbiAgICAgICAgY29uc3QgcGFnZVByb21pc2VzID0gW107XG4gICAgICAgIGZvciAobGV0IGk9Zmlyc3RQYWdlOyBpPD1sYXN0UGFnZTsgaSsrKSBwYWdlUHJvbWlzZXMucHVzaChzZWxmLl9sb2FkUGFnZShpKSk7XG4gICAgICAgIHNlbGYuX3RyaWdnZXJMb2FkKCk7XG5cbiAgICAgICAgbGV0IHAgPSBmaXJzdFBhZ2U7XG4gICAgICAgIGxldCBvID0gcG9zICUgc2VsZi5wYWdlU2l6ZTtcbiAgICAgICAgbGV0IHIgPSBidWZmLmJ5dGVMZW5ndGg7XG4gICAgICAgIHdoaWxlIChyPjApIHtcbiAgICAgICAgICAgIGF3YWl0IHBhZ2VQcm9taXNlc1twLWZpcnN0UGFnZV07XG4gICAgICAgICAgICBjb25zdCBsID0gKG8rciA+IHNlbGYucGFnZVNpemUpID8gKHNlbGYucGFnZVNpemUgLW8pIDogcjtcbiAgICAgICAgICAgIGNvbnN0IHNyY1ZpZXcgPSBidWZmLnNsaWNlKCBidWZmLmJ5dGVMZW5ndGggLSByLCBidWZmLmJ5dGVMZW5ndGggLSByICsgbCk7XG4gICAgICAgICAgICBjb25zdCBkc3RWaWV3ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5wYWdlc1twXS5idWZmLmJ1ZmZlciwgbywgbCk7XG4gICAgICAgICAgICBkc3RWaWV3LnNldChzcmNWaWV3KTtcbiAgICAgICAgICAgIHNlbGYucGFnZXNbcF0uZGlydHkgPSB0cnVlO1xuICAgICAgICAgICAgc2VsZi5wYWdlc1twXS5wZW5kaW5nT3BzIC0tO1xuICAgICAgICAgICAgc2VsZi5wYWdlc1twXS5zaXplID0gTWF0aC5tYXgobytsLCBzZWxmLnBhZ2VzW3BdLnNpemUpO1xuICAgICAgICAgICAgaWYgKHA+PXNlbGYudG90YWxQYWdlcykge1xuICAgICAgICAgICAgICAgIHNlbGYudG90YWxQYWdlcyA9IHArMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHIgPSByLWw7XG4gICAgICAgICAgICBwICsrO1xuICAgICAgICAgICAgbyA9IDA7XG4gICAgICAgICAgICBpZiAoIXNlbGYud3JpdGluZykgc2V0SW1tZWRpYXRlKHNlbGYuX3RyaWdnZXJXcml0ZS5iaW5kKHNlbGYpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIHJlYWQobGVuLCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGxldCBidWZmID0gbmV3IFVpbnQ4QXJyYXkobGVuKTtcbiAgICAgICAgYXdhaXQgc2VsZi5yZWFkVG9CdWZmZXIoYnVmZiwgMCwgbGVuLCBwb3MpO1xuXG4gICAgICAgIHJldHVybiBidWZmO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRUb0J1ZmZlcihidWZmRHN0LCBvZmZzZXQsIGxlbiwgcG9zKSB7XG4gICAgICAgIGlmIChsZW4gPT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBpZiAobGVuID4gc2VsZi5wYWdlU2l6ZSpzZWxmLm1heFBhZ2VzTG9hZGVkKjAuOCkge1xuICAgICAgICAgICAgY29uc3QgY2FjaGVTaXplID0gTWF0aC5mbG9vcihsZW4gKiAxLjEpO1xuICAgICAgICAgICAgdGhpcy5tYXhQYWdlc0xvYWRlZCA9IE1hdGguZmxvb3IoIGNhY2hlU2l6ZSAvIHNlbGYucGFnZVNpemUpKzE7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBwb3MgPT0gXCJ1bmRlZmluZWRcIikgcG9zID0gc2VsZi5wb3M7XG4gICAgICAgIHNlbGYucG9zID0gcG9zK2xlbjtcbiAgICAgICAgaWYgKHNlbGYucGVuZGluZ0Nsb3NlKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBhIGNsb3NpbmcgZmlsZVwiKTtcbiAgICAgICAgY29uc3QgZmlyc3RQYWdlID0gTWF0aC5mbG9vcihwb3MgLyBzZWxmLnBhZ2VTaXplKTtcbiAgICAgICAgY29uc3QgbGFzdFBhZ2UgPSBNYXRoLmZsb29yKChwb3MgKyBsZW4gLTEpIC8gc2VsZi5wYWdlU2l6ZSk7XG5cbiAgICAgICAgY29uc3QgcGFnZVByb21pc2VzID0gW107XG4gICAgICAgIGZvciAobGV0IGk9Zmlyc3RQYWdlOyBpPD1sYXN0UGFnZTsgaSsrKSBwYWdlUHJvbWlzZXMucHVzaChzZWxmLl9sb2FkUGFnZShpKSk7XG5cbiAgICAgICAgc2VsZi5fdHJpZ2dlckxvYWQoKTtcblxuICAgICAgICBsZXQgcCA9IGZpcnN0UGFnZTtcbiAgICAgICAgbGV0IG8gPSBwb3MgJSBzZWxmLnBhZ2VTaXplO1xuICAgICAgICAvLyBSZW1haW5pbmcgYnl0ZXMgdG8gcmVhZFxuICAgICAgICBsZXQgciA9IHBvcyArIGxlbiA+IHNlbGYudG90YWxTaXplID8gbGVuIC0gKHBvcyArIGxlbiAtIHNlbGYudG90YWxTaXplKTogbGVuO1xuICAgICAgICB3aGlsZSAocj4wKSB7XG4gICAgICAgICAgICBhd2FpdCBwYWdlUHJvbWlzZXNbcCAtIGZpcnN0UGFnZV07XG4gICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIEF3YWl0IChyZWFkKTogXCIsIHApO1xuXG4gICAgICAgICAgICAvLyBieXRlcyB0byBjb3B5IGZyb20gdGhpcyBwYWdlXG4gICAgICAgICAgICBjb25zdCBsID0gKG8rciA+IHNlbGYucGFnZVNpemUpID8gKHNlbGYucGFnZVNpemUgLW8pIDogcjtcbiAgICAgICAgICAgIGNvbnN0IHNyY1ZpZXcgPSBuZXcgVWludDhBcnJheShzZWxmLnBhZ2VzW3BdLmJ1ZmYuYnVmZmVyLCBzZWxmLnBhZ2VzW3BdLmJ1ZmYuYnl0ZU9mZnNldCArIG8sIGwpO1xuICAgICAgICAgICAgYnVmZkRzdC5zZXQoc3JjVmlldywgb2Zmc2V0K2xlbi1yKTtcbiAgICAgICAgICAgIHNlbGYucGFnZXNbcF0ucGVuZGluZ09wcyAtLTtcblxuICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBPcCBkb25lOiBcIiwgcCk7XG5cbiAgICAgICAgICAgIHIgPSByLWw7XG4gICAgICAgICAgICBwICsrO1xuICAgICAgICAgICAgbyA9IDA7XG4gICAgICAgICAgICBpZiAoc2VsZi5wZW5kaW5nTG9hZHMubGVuZ3RoPjApIHNldEltbWVkaWF0ZShzZWxmLl90cmlnZ2VyTG9hZC5iaW5kKHNlbGYpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucG9zID0gcG9zICsgbGVuO1xuXG4gICAgfVxuXG5cbiAgICBfdHJ5Q2xvc2UoKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBpZiAoIXNlbGYucGVuZGluZ0Nsb3NlKSByZXR1cm47XG4gICAgICAgIGlmIChzZWxmLmVycm9yKSB7XG4gICAgICAgICAgICBzZWxmLnBlbmRpbmdDbG9zZVJlamVjdChzZWxmLmVycm9yKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBwID0gc2VsZi5fZ2V0RGlydHlQYWdlKCk7XG4gICAgICAgIGlmICgocD49MCkgfHwgKHNlbGYud3JpdGluZykgfHwgKHNlbGYucmVhZGluZykgfHwgKHNlbGYucGVuZGluZ0xvYWRzLmxlbmd0aD4wKSkgcmV0dXJuO1xuICAgICAgICBzZWxmLnBlbmRpbmdDbG9zZSgpO1xuICAgIH1cblxuICAgIGNsb3NlKCkge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgaWYgKHNlbGYucGVuZGluZ0Nsb3NlKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2xvc2luZyB0aGUgZmlsZSB0d2ljZVwiKTtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHNlbGYucGVuZGluZ0Nsb3NlID0gcmVzb2x2ZTtcbiAgICAgICAgICAgIHNlbGYucGVuZGluZ0Nsb3NlUmVqZWN0ID0gcmVqZWN0O1xuICAgICAgICAgICAgc2VsZi5fdHJ5Q2xvc2UoKTtcbiAgICAgICAgfSkudGhlbigoKT0+IHtcbiAgICAgICAgICAgIHNlbGYuZmQuY2xvc2UoKTtcbiAgICAgICAgfSwgKGVycikgPT4ge1xuICAgICAgICAgICAgc2VsZi5mZC5jbG9zZSgpO1xuICAgICAgICAgICAgdGhyb3cgKGVycik7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGFzeW5jIGRpc2NhcmQoKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBhd2FpdCBzZWxmLmNsb3NlKCk7XG4gICAgICAgIGF3YWl0IGZzLnByb21pc2VzLnVubGluayh0aGlzLmZpbGVOYW1lKTtcbiAgICB9XG5cbiAgICBhc3luYyB3cml0ZVVMRTMyKHYsIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgdG1wQnVmZjMyID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG4gICAgICAgIGNvbnN0IHRtcEJ1ZmYzMnYgPSBuZXcgRGF0YVZpZXcodG1wQnVmZjMyLmJ1ZmZlcik7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgdHJ1ZSk7XG5cbiAgICAgICAgYXdhaXQgc2VsZi53cml0ZSh0bXBCdWZmMzIsIHBvcyk7XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGVVQkUzMih2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgY29uc3QgdG1wQnVmZjMyID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG4gICAgICAgIGNvbnN0IHRtcEJ1ZmYzMnYgPSBuZXcgRGF0YVZpZXcodG1wQnVmZjMyLmJ1ZmZlcik7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgZmFsc2UpO1xuXG4gICAgICAgIGF3YWl0IHNlbGYud3JpdGUodG1wQnVmZjMyLCBwb3MpO1xuICAgIH1cblxuXG4gICAgYXN5bmMgd3JpdGVVTEU2NCh2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgY29uc3QgdG1wQnVmZjY0ID0gbmV3IFVpbnQ4QXJyYXkoOCk7XG4gICAgICAgIGNvbnN0IHRtcEJ1ZmY2NHYgPSBuZXcgRGF0YVZpZXcodG1wQnVmZjY0LmJ1ZmZlcik7XG5cbiAgICAgICAgdG1wQnVmZjY0di5zZXRVaW50MzIoMCwgdiAmIDB4RkZGRkZGRkYsIHRydWUpO1xuICAgICAgICB0bXBCdWZmNjR2LnNldFVpbnQzMig0LCBNYXRoLmZsb29yKHYgLyAweDEwMDAwMDAwMCkgLCB0cnVlKTtcblxuICAgICAgICBhd2FpdCBzZWxmLndyaXRlKHRtcEJ1ZmY2NCwgcG9zKTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkVUxFMzIocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgc2VsZi5yZWFkKDQsIHBvcyk7XG5cbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBVaW50MzJBcnJheShiLmJ1ZmZlcik7XG5cbiAgICAgICAgcmV0dXJuIHZpZXdbMF07XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFVCRTMyKHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgYiA9IGF3YWl0IHNlbGYucmVhZCg0LCBwb3MpO1xuXG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgRGF0YVZpZXcoYi5idWZmZXIpO1xuXG4gICAgICAgIHJldHVybiB2aWV3LmdldFVpbnQzMigwLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFVMRTY0KHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgYiA9IGF3YWl0IHNlbGYucmVhZCg4LCBwb3MpO1xuXG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgVWludDMyQXJyYXkoYi5idWZmZXIpO1xuXG4gICAgICAgIHJldHVybiB2aWV3WzFdICogMHgxMDAwMDAwMDAgKyB2aWV3WzBdO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRTdHJpbmcocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIGlmIChzZWxmLnBlbmRpbmdDbG9zZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBhIGNsb3NpbmcgZmlsZVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBjdXJyZW50UG9zaXRpb24gPSB0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIgPyBzZWxmLnBvcyA6IHBvcztcbiAgICAgICAgbGV0IGN1cnJlbnRQYWdlID0gTWF0aC5mbG9vcihjdXJyZW50UG9zaXRpb24gLyBzZWxmLnBhZ2VTaXplKTtcblxuICAgICAgICBsZXQgZW5kT2ZTdHJpbmdGb3VuZCA9IGZhbHNlO1xuICAgICAgICBsZXQgc3RyID0gXCJcIjtcblxuICAgICAgICB3aGlsZSAoIWVuZE9mU3RyaW5nRm91bmQpIHtcbiAgICAgICAgICAgIC8vUmVhZCBwYWdlXG4gICAgICAgICAgICBsZXQgcGFnZVByb21pc2UgPSBzZWxmLl9sb2FkUGFnZShjdXJyZW50UGFnZSk7XG4gICAgICAgICAgICBzZWxmLl90cmlnZ2VyTG9hZCgpO1xuICAgICAgICAgICAgYXdhaXQgcGFnZVByb21pc2U7XG4gICAgICAgICAgICBzZWxmLl9fc3RhdHVzUGFnZShcIkFmdGVyIEF3YWl0IChyZWFkKTogXCIsIGN1cnJlbnRQYWdlKTtcblxuICAgICAgICAgICAgbGV0IG9mZnNldE9uUGFnZSA9IGN1cnJlbnRQb3NpdGlvbiAlIHNlbGYucGFnZVNpemU7XG5cbiAgICAgICAgICAgIGNvbnN0IGRhdGFBcnJheSA9IG5ldyBVaW50OEFycmF5KFxuICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbY3VycmVudFBhZ2VdLmJ1ZmYuYnVmZmVyLFxuICAgICAgICAgICAgICAgIHNlbGYucGFnZXNbY3VycmVudFBhZ2VdLmJ1ZmYuYnl0ZU9mZnNldCArIG9mZnNldE9uUGFnZSxcbiAgICAgICAgICAgICAgICBzZWxmLnBhZ2VTaXplIC0gb2Zmc2V0T25QYWdlXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBsZXQgaW5kZXhFbmRPZlN0cmluZyA9IGRhdGFBcnJheS5maW5kSW5kZXgoZWxlbWVudCA9PiBlbGVtZW50ID09PSAwKTtcbiAgICAgICAgICAgIGVuZE9mU3RyaW5nRm91bmQgPSBpbmRleEVuZE9mU3RyaW5nICE9PSAtMTtcblxuICAgICAgICAgICAgaWYgKGVuZE9mU3RyaW5nRm91bmQpIHtcbiAgICAgICAgICAgICAgICBzdHIgKz0gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKGRhdGFBcnJheS5zbGljZSgwLCBpbmRleEVuZE9mU3RyaW5nKSk7XG4gICAgICAgICAgICAgICAgc2VsZi5wb3MgPSBjdXJyZW50UGFnZSAqIHRoaXMucGFnZVNpemUgKyBvZmZzZXRPblBhZ2UgKyBpbmRleEVuZE9mU3RyaW5nICsgMTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RyICs9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhQXJyYXkpO1xuICAgICAgICAgICAgICAgIHNlbGYucG9zID0gY3VycmVudFBhZ2UgKiB0aGlzLnBhZ2VTaXplICsgb2Zmc2V0T25QYWdlICsgZGF0YUFycmF5Lmxlbmd0aDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2VsZi5wYWdlc1tjdXJyZW50UGFnZV0ucGVuZGluZ09wcy0tO1xuICAgICAgICAgICAgc2VsZi5fX3N0YXR1c1BhZ2UoXCJBZnRlciBPcCBkb25lOiBcIiwgY3VycmVudFBhZ2UpO1xuXG4gICAgICAgICAgICBjdXJyZW50UG9zaXRpb24gPSBzZWxmLnBvcztcbiAgICAgICAgICAgIGN1cnJlbnRQYWdlKys7XG5cbiAgICAgICAgICAgIGlmIChzZWxmLnBlbmRpbmdMb2Fkcy5sZW5ndGggPiAwKSBzZXRJbW1lZGlhdGUoc2VsZi5fdHJpZ2dlckxvYWQuYmluZChzZWxmKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gc3RyO1xuICAgIH1cbn1cbiIsImV4cG9ydCBmdW5jdGlvbiBjcmVhdGVOZXcobykge1xuICAgIGNvbnN0IGluaXRpYWxTaXplID0gby5pbml0aWFsU2l6ZSB8fCAxPDwyMDtcbiAgICBjb25zdCBmZCA9IG5ldyBNZW1GaWxlKCk7XG4gICAgZmQubyA9IG87XG4gICAgZmQuby5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoaW5pdGlhbFNpemUpO1xuICAgIGZkLmFsbG9jU2l6ZSA9IGluaXRpYWxTaXplO1xuICAgIGZkLnRvdGFsU2l6ZSA9IDA7XG4gICAgZmQucmVhZE9ubHkgPSBmYWxzZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRFeGlzdGluZyhvKSB7XG4gICAgY29uc3QgZmQgPSBuZXcgTWVtRmlsZSgpO1xuICAgIGZkLm8gPSBvO1xuICAgIGZkLmFsbG9jU2l6ZSA9IG8uZGF0YS5ieXRlTGVuZ3RoO1xuICAgIGZkLnRvdGFsU2l6ZSA9IG8uZGF0YS5ieXRlTGVuZ3RoO1xuICAgIGZkLnJlYWRPbmx5ID0gdHJ1ZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRXcml0ZUV4aXN0aW5nKG8pIHtcbiAgICBjb25zdCBmZCA9IG5ldyBNZW1GaWxlKCk7XG4gICAgZmQubyA9IG87XG4gICAgZmQuYWxsb2NTaXplID0gby5kYXRhLmJ5dGVMZW5ndGg7XG4gICAgZmQudG90YWxTaXplID0gby5kYXRhLmJ5dGVMZW5ndGg7XG4gICAgZmQucmVhZE9ubHkgPSBmYWxzZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuY29uc3QgdG1wQnVmZjMyID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG5jb25zdCB0bXBCdWZmMzJ2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmYzMi5idWZmZXIpO1xuY29uc3QgdG1wQnVmZjY0ID0gbmV3IFVpbnQ4QXJyYXkoOCk7XG5jb25zdCB0bXBCdWZmNjR2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmY2NC5idWZmZXIpO1xuXG5jbGFzcyBNZW1GaWxlIHtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnBhZ2VTaXplID0gMSA8PCAxNDsgIC8vIGZvciBjb21wYXRpYmlsaXR5XG4gICAgfVxuXG4gICAgX3Jlc2l6ZUlmTmVlZGVkKG5ld0xlbikge1xuICAgICAgICBpZiAobmV3TGVuID4gdGhpcy5hbGxvY1NpemUpIHtcbiAgICAgICAgICAgIGNvbnN0IG5ld0FsbG9jU2l6ZSA9IE1hdGgubWF4KFxuICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NTaXplICsgKDEgPDwgMjApLFxuICAgICAgICAgICAgICAgIE1hdGguZmxvb3IodGhpcy5hbGxvY1NpemUgKiAxLjEpLFxuICAgICAgICAgICAgICAgIG5ld0xlblxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IG5ld0RhdGEgPSBuZXcgVWludDhBcnJheShuZXdBbGxvY1NpemUpO1xuICAgICAgICAgICAgbmV3RGF0YS5zZXQodGhpcy5vLmRhdGEpO1xuICAgICAgICAgICAgdGhpcy5vLmRhdGEgPSBuZXdEYXRhO1xuICAgICAgICAgICAgdGhpcy5hbGxvY1NpemUgPSBuZXdBbGxvY1NpemU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyB3cml0ZShidWZmLCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9dGhpcztcbiAgICAgICAgaWYgKHR5cGVvZiBwb3MgPT0gXCJ1bmRlZmluZWRcIikgcG9zID0gc2VsZi5wb3M7XG4gICAgICAgIGlmICh0aGlzLnJlYWRPbmx5KSB0aHJvdyBuZXcgRXJyb3IoXCJXcml0aW5nIGEgcmVhZCBvbmx5IGZpbGVcIik7XG5cbiAgICAgICAgdGhpcy5fcmVzaXplSWZOZWVkZWQocG9zICsgYnVmZi5ieXRlTGVuZ3RoKTtcblxuICAgICAgICB0aGlzLm8uZGF0YS5zZXQoYnVmZi5zbGljZSgpLCBwb3MpO1xuXG4gICAgICAgIGlmIChwb3MgKyBidWZmLmJ5dGVMZW5ndGggPiB0aGlzLnRvdGFsU2l6ZSkgdGhpcy50b3RhbFNpemUgPSBwb3MgKyBidWZmLmJ5dGVMZW5ndGg7XG5cbiAgICAgICAgdGhpcy5wb3MgPSBwb3MgKyBidWZmLmJ5dGVMZW5ndGg7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFRvQnVmZmVyKGJ1ZmZEZXN0LCBvZmZzZXQsIGxlbiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBpZiAodHlwZW9mIHBvcyA9PSBcInVuZGVmaW5lZFwiKSBwb3MgPSBzZWxmLnBvcztcbiAgICAgICAgaWYgKHRoaXMucmVhZE9ubHkpIHtcbiAgICAgICAgICAgIGlmIChwb3MgKyBsZW4gPiB0aGlzLnRvdGFsU2l6ZSkgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBvdXQgb2YgYm91bmRzXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3Jlc2l6ZUlmTmVlZGVkKHBvcyArIGxlbik7XG5cbiAgICAgICAgY29uc3QgYnVmZlNyYyA9IG5ldyBVaW50OEFycmF5KHRoaXMuby5kYXRhLmJ1ZmZlciwgdGhpcy5vLmRhdGEuYnl0ZU9mZnNldCArIHBvcywgbGVuKTtcblxuICAgICAgICBidWZmRGVzdC5zZXQoYnVmZlNyYywgb2Zmc2V0KTtcblxuICAgICAgICB0aGlzLnBvcyA9IHBvcyArIGxlbjtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkKGxlbiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShsZW4pO1xuICAgICAgICBhd2FpdCBzZWxmLnJlYWRUb0J1ZmZlcihidWZmLCAwLCBsZW4sIHBvcyk7XG5cbiAgICAgICAgcmV0dXJuIGJ1ZmY7XG4gICAgfVxuXG4gICAgY2xvc2UoKSB7XG4gICAgICAgIGlmICh0aGlzLm8uZGF0YS5ieXRlTGVuZ3RoICE9IHRoaXMudG90YWxTaXplKSB7XG4gICAgICAgICAgICB0aGlzLm8uZGF0YSA9IHRoaXMuby5kYXRhLnNsaWNlKDAsIHRoaXMudG90YWxTaXplKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGRpc2NhcmQoKSB7XG4gICAgfVxuXG5cbiAgICBhc3luYyB3cml0ZVVMRTMyKHYsIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICB0bXBCdWZmMzJ2LnNldFVpbnQzMigwLCB2LCB0cnVlKTtcblxuICAgICAgICBhd2FpdCBzZWxmLndyaXRlKHRtcEJ1ZmYzMiwgcG9zKTtcbiAgICB9XG5cbiAgICBhc3luYyB3cml0ZVVCRTMyKHYsIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICB0bXBCdWZmMzJ2LnNldFVpbnQzMigwLCB2LCBmYWxzZSk7XG5cbiAgICAgICAgYXdhaXQgc2VsZi53cml0ZSh0bXBCdWZmMzIsIHBvcyk7XG4gICAgfVxuXG5cbiAgICBhc3luYyB3cml0ZVVMRTY0KHYsIHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICB0bXBCdWZmNjR2LnNldFVpbnQzMigwLCB2ICYgMHhGRkZGRkZGRiwgdHJ1ZSk7XG4gICAgICAgIHRtcEJ1ZmY2NHYuc2V0VWludDMyKDQsIE1hdGguZmxvb3IodiAvIDB4MTAwMDAwMDAwKSAsIHRydWUpO1xuXG4gICAgICAgIGF3YWl0IHNlbGYud3JpdGUodG1wQnVmZjY0LCBwb3MpO1xuICAgIH1cblxuXG4gICAgYXN5bmMgcmVhZFVMRTMyKHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgY29uc3QgYiA9IGF3YWl0IHNlbGYucmVhZCg0LCBwb3MpO1xuXG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgVWludDMyQXJyYXkoYi5idWZmZXIpO1xuXG4gICAgICAgIHJldHVybiB2aWV3WzBdO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRVQkUzMihwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGIgPSBhd2FpdCBzZWxmLnJlYWQoNCwgcG9zKTtcblxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IERhdGFWaWV3KGIuYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gdmlldy5nZXRVaW50MzIoMCwgZmFsc2UpO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWRVTEU2NChwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGIgPSBhd2FpdCBzZWxmLnJlYWQoOCwgcG9zKTtcblxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IFVpbnQzMkFycmF5KGIuYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gdmlld1sxXSAqIDB4MTAwMDAwMDAwICsgdmlld1swXTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkU3RyaW5nKHBvcykge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgICAgICBsZXQgY3VycmVudFBvc2l0aW9uID0gdHlwZW9mIHBvcyA9PSBcInVuZGVmaW5lZFwiID8gc2VsZi5wb3MgOiBwb3M7XG5cbiAgICAgICAgaWYgKGN1cnJlbnRQb3NpdGlvbiA+IHRoaXMudG90YWxTaXplKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5yZWFkT25seSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJlYWRpbmcgb3V0IG9mIGJvdW5kc1wiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuX3Jlc2l6ZUlmTmVlZGVkKHBvcyk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZGF0YUFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoXG4gICAgICAgICAgICBzZWxmLm8uZGF0YS5idWZmZXIsXG4gICAgICAgICAgICBjdXJyZW50UG9zaXRpb24sXG4gICAgICAgICAgICB0aGlzLnRvdGFsU2l6ZSAtIGN1cnJlbnRQb3NpdGlvblxuICAgICAgICApO1xuXG4gICAgICAgIGxldCBpbmRleEVuZE9mU3RyaW5nID0gZGF0YUFycmF5LmZpbmRJbmRleChlbGVtZW50ID0+IGVsZW1lbnQgPT09IDApO1xuICAgICAgICBsZXQgZW5kT2ZTdHJpbmdGb3VuZCA9IGluZGV4RW5kT2ZTdHJpbmcgIT09IC0xO1xuXG4gICAgICAgIGxldCBzdHIgPSBcIlwiO1xuICAgICAgICBpZiAoZW5kT2ZTdHJpbmdGb3VuZCkge1xuICAgICAgICAgICAgc3RyID0gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKGRhdGFBcnJheS5zbGljZSgwLCBpbmRleEVuZE9mU3RyaW5nKSk7XG4gICAgICAgICAgICBzZWxmLnBvcyA9IGN1cnJlbnRQb3NpdGlvbiArIGluZGV4RW5kT2ZTdHJpbmcgKyAxO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc2VsZi5wb3MgPSBjdXJyZW50UG9zaXRpb247XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG59XG4iLCJjb25zdCBQQUdFX1NJWkUgPSAxPDwyMjtcblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU5ldyhvKSB7XG4gICAgY29uc3QgaW5pdGlhbFNpemUgPSBvLmluaXRpYWxTaXplIHx8IDA7XG4gICAgY29uc3QgZmQgPSBuZXcgQmlnTWVtRmlsZSgpO1xuICAgIGZkLm8gPSBvO1xuICAgIGNvbnN0IG5QYWdlcyA9IGluaXRpYWxTaXplID8gTWF0aC5mbG9vcigoaW5pdGlhbFNpemUgLSAxKSAvIFBBR0VfU0laRSkrMSA6IDA7XG4gICAgZmQuby5kYXRhID0gW107XG4gICAgZm9yIChsZXQgaT0wOyBpPG5QYWdlcy0xOyBpKyspIHtcbiAgICAgICAgZmQuby5kYXRhLnB1c2goIG5ldyBVaW50OEFycmF5KFBBR0VfU0laRSkpO1xuICAgIH1cbiAgICBpZiAoblBhZ2VzKSBmZC5vLmRhdGEucHVzaCggbmV3IFVpbnQ4QXJyYXkoaW5pdGlhbFNpemUgLSBQQUdFX1NJWkUqKG5QYWdlcy0xKSkpO1xuICAgIGZkLnRvdGFsU2l6ZSA9IDA7XG4gICAgZmQucmVhZE9ubHkgPSBmYWxzZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRFeGlzdGluZyhvKSB7XG4gICAgY29uc3QgZmQgPSBuZXcgQmlnTWVtRmlsZSgpO1xuICAgIGZkLm8gPSBvO1xuICAgIGZkLnRvdGFsU2l6ZSA9IChvLmRhdGEubGVuZ3RoLTEpKiBQQUdFX1NJWkUgKyBvLmRhdGFbby5kYXRhLmxlbmd0aC0xXS5ieXRlTGVuZ3RoO1xuICAgIGZkLnJlYWRPbmx5ID0gdHJ1ZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRXcml0ZUV4aXN0aW5nKG8pIHtcbiAgICBjb25zdCBmZCA9IG5ldyBCaWdNZW1GaWxlKCk7XG4gICAgZmQubyA9IG87XG4gICAgZmQudG90YWxTaXplID0gKG8uZGF0YS5sZW5ndGgtMSkqIFBBR0VfU0laRSArIG8uZGF0YVtvLmRhdGEubGVuZ3RoLTFdLmJ5dGVMZW5ndGg7XG4gICAgZmQucmVhZE9ubHkgPSBmYWxzZTtcbiAgICBmZC5wb3MgPSAwO1xuICAgIHJldHVybiBmZDtcbn1cblxuY29uc3QgdG1wQnVmZjMyID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG5jb25zdCB0bXBCdWZmMzJ2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmYzMi5idWZmZXIpO1xuY29uc3QgdG1wQnVmZjY0ID0gbmV3IFVpbnQ4QXJyYXkoOCk7XG5jb25zdCB0bXBCdWZmNjR2ID0gbmV3IERhdGFWaWV3KHRtcEJ1ZmY2NC5idWZmZXIpO1xuXG5jbGFzcyBCaWdNZW1GaWxlIHtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnBhZ2VTaXplID0gMSA8PCAxNDsgIC8vIGZvciBjb21wYXRpYmlsaXR5XG4gICAgfVxuXG4gICAgX3Jlc2l6ZUlmTmVlZGVkKG5ld0xlbikge1xuXG4gICAgICAgIGlmIChuZXdMZW4gPD0gdGhpcy50b3RhbFNpemUpIHJldHVybjtcblxuICAgICAgICBpZiAodGhpcy5yZWFkT25seSkgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBvdXQgb2YgZmlsZSBib3VuZHNcIik7XG5cbiAgICAgICAgY29uc3QgblBhZ2VzID0gTWF0aC5mbG9vcigobmV3TGVuIC0gMSkgLyBQQUdFX1NJWkUpKzE7XG4gICAgICAgIGZvciAobGV0IGk9IE1hdGgubWF4KHRoaXMuby5kYXRhLmxlbmd0aC0xLCAwKTsgaTxuUGFnZXM7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgbmV3U2l6ZSA9IGk8blBhZ2VzLTEgPyBQQUdFX1NJWkUgOiBuZXdMZW4gLSAoblBhZ2VzLTEpKlBBR0VfU0laRTtcbiAgICAgICAgICAgIGNvbnN0IHAgPSBuZXcgVWludDhBcnJheShuZXdTaXplKTtcbiAgICAgICAgICAgIGlmIChpID09IHRoaXMuby5kYXRhLmxlbmd0aC0xKSBwLnNldCh0aGlzLm8uZGF0YVtpXSk7XG4gICAgICAgICAgICB0aGlzLm8uZGF0YVtpXSA9IHA7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50b3RhbFNpemUgPSBuZXdMZW47XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGUoYnVmZiwgcG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPXRoaXM7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIpIHBvcyA9IHNlbGYucG9zO1xuICAgICAgICBpZiAodGhpcy5yZWFkT25seSkgdGhyb3cgbmV3IEVycm9yKFwiV3JpdGluZyBhIHJlYWQgb25seSBmaWxlXCIpO1xuXG4gICAgICAgIHRoaXMuX3Jlc2l6ZUlmTmVlZGVkKHBvcyArIGJ1ZmYuYnl0ZUxlbmd0aCk7XG5cbiAgICAgICAgY29uc3QgZmlyc3RQYWdlID0gTWF0aC5mbG9vcihwb3MgLyBQQUdFX1NJWkUpO1xuXG4gICAgICAgIGxldCBwID0gZmlyc3RQYWdlO1xuICAgICAgICBsZXQgbyA9IHBvcyAlIFBBR0VfU0laRTtcbiAgICAgICAgbGV0IHIgPSBidWZmLmJ5dGVMZW5ndGg7XG4gICAgICAgIHdoaWxlIChyPjApIHtcbiAgICAgICAgICAgIGNvbnN0IGwgPSAobytyID4gUEFHRV9TSVpFKSA/IChQQUdFX1NJWkUgLW8pIDogcjtcbiAgICAgICAgICAgIGNvbnN0IHNyY1ZpZXcgPSBidWZmLnNsaWNlKGJ1ZmYuYnl0ZUxlbmd0aCAtIHIsIGJ1ZmYuYnl0ZUxlbmd0aCAtIHIgKyBsKTtcbiAgICAgICAgICAgIGNvbnN0IGRzdFZpZXcgPSBuZXcgVWludDhBcnJheShzZWxmLm8uZGF0YVtwXS5idWZmZXIsIG8sIGwpO1xuICAgICAgICAgICAgZHN0Vmlldy5zZXQoc3JjVmlldyk7XG4gICAgICAgICAgICByID0gci1sO1xuICAgICAgICAgICAgcCArKztcbiAgICAgICAgICAgIG8gPSAwO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5wb3MgPSBwb3MgKyBidWZmLmJ5dGVMZW5ndGg7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFRvQnVmZmVyKGJ1ZmZEc3QsIG9mZnNldCwgbGVuLCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zID09IFwidW5kZWZpbmVkXCIpIHBvcyA9IHNlbGYucG9zO1xuICAgICAgICBpZiAodGhpcy5yZWFkT25seSkge1xuICAgICAgICAgICAgaWYgKHBvcyArIGxlbiA+IHRoaXMudG90YWxTaXplKSB0aHJvdyBuZXcgRXJyb3IoXCJSZWFkaW5nIG91dCBvZiBib3VuZHNcIik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fcmVzaXplSWZOZWVkZWQocG9zICsgbGVuKTtcblxuICAgICAgICBjb25zdCBmaXJzdFBhZ2UgPSBNYXRoLmZsb29yKHBvcyAvIFBBR0VfU0laRSk7XG5cbiAgICAgICAgbGV0IHAgPSBmaXJzdFBhZ2U7XG4gICAgICAgIGxldCBvID0gcG9zICUgUEFHRV9TSVpFO1xuICAgICAgICAvLyBSZW1haW5pbmcgYnl0ZXMgdG8gcmVhZFxuICAgICAgICBsZXQgciA9IGxlbjtcbiAgICAgICAgd2hpbGUgKHI+MCkge1xuICAgICAgICAgICAgLy8gYnl0ZXMgdG8gY29weSBmcm9tIHRoaXMgcGFnZVxuICAgICAgICAgICAgY29uc3QgbCA9IChvK3IgPiBQQUdFX1NJWkUpID8gKFBBR0VfU0laRSAtbykgOiByO1xuICAgICAgICAgICAgY29uc3Qgc3JjVmlldyA9IG5ldyBVaW50OEFycmF5KHNlbGYuby5kYXRhW3BdLmJ1ZmZlciwgbywgbCk7XG4gICAgICAgICAgICBidWZmRHN0LnNldChzcmNWaWV3LCBvZmZzZXQrbGVuLXIpO1xuICAgICAgICAgICAgciA9IHItbDtcbiAgICAgICAgICAgIHAgKys7XG4gICAgICAgICAgICBvID0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucG9zID0gcG9zICsgbGVuO1xuICAgIH1cblxuICAgIGFzeW5jIHJlYWQobGVuLCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShsZW4pO1xuXG4gICAgICAgIGF3YWl0IHNlbGYucmVhZFRvQnVmZmVyKGJ1ZmYsIDAsIGxlbiwgcG9zKTtcblxuICAgICAgICByZXR1cm4gYnVmZjtcbiAgICB9XG5cbiAgICBjbG9zZSgpIHtcbiAgICB9XG5cbiAgICBhc3luYyBkaXNjYXJkKCkge1xuICAgIH1cblxuXG4gICAgYXN5bmMgd3JpdGVVTEUzMih2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgdHJ1ZSk7XG5cbiAgICAgICAgYXdhaXQgc2VsZi53cml0ZSh0bXBCdWZmMzIsIHBvcyk7XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGVVQkUzMih2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdG1wQnVmZjMydi5zZXRVaW50MzIoMCwgdiwgZmFsc2UpO1xuXG4gICAgICAgIGF3YWl0IHNlbGYud3JpdGUodG1wQnVmZjMyLCBwb3MpO1xuICAgIH1cblxuXG4gICAgYXN5bmMgd3JpdGVVTEU2NCh2LCBwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdG1wQnVmZjY0di5zZXRVaW50MzIoMCwgdiAmIDB4RkZGRkZGRkYsIHRydWUpO1xuICAgICAgICB0bXBCdWZmNjR2LnNldFVpbnQzMig0LCBNYXRoLmZsb29yKHYgLyAweDEwMDAwMDAwMCkgLCB0cnVlKTtcblxuICAgICAgICBhd2FpdCBzZWxmLndyaXRlKHRtcEJ1ZmY2NCwgcG9zKTtcbiAgICB9XG5cblxuICAgIGFzeW5jIHJlYWRVTEUzMihwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGIgPSBhd2FpdCBzZWxmLnJlYWQoNCwgcG9zKTtcblxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IFVpbnQzMkFycmF5KGIuYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gdmlld1swXTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkVUJFMzIocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgc2VsZi5yZWFkKDQsIHBvcyk7XG5cbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhiLmJ1ZmZlcik7XG5cbiAgICAgICAgcmV0dXJuIHZpZXcuZ2V0VWludDMyKDAsIGZhbHNlKTtcbiAgICB9XG5cbiAgICBhc3luYyByZWFkVUxFNjQocG9zKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICBjb25zdCBiID0gYXdhaXQgc2VsZi5yZWFkKDgsIHBvcyk7XG5cbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBVaW50MzJBcnJheShiLmJ1ZmZlcik7XG5cbiAgICAgICAgcmV0dXJuIHZpZXdbMV0gKiAweDEwMDAwMDAwMCArIHZpZXdbMF07XG4gICAgfVxuXG4gICAgYXN5bmMgcmVhZFN0cmluZyhwb3MpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGNvbnN0IGZpeGVkU2l6ZSA9IDIwNDg7XG5cbiAgICAgICAgbGV0IGN1cnJlbnRQb3NpdGlvbiA9IHR5cGVvZiBwb3MgPT0gXCJ1bmRlZmluZWRcIiA/IHNlbGYucG9zIDogcG9zO1xuXG4gICAgICAgIGlmIChjdXJyZW50UG9zaXRpb24gPiB0aGlzLnRvdGFsU2l6ZSkge1xuICAgICAgICAgICAgaWYgKHRoaXMucmVhZE9ubHkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJSZWFkaW5nIG91dCBvZiBib3VuZHNcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLl9yZXNpemVJZk5lZWRlZChwb3MpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGVuZE9mU3RyaW5nRm91bmQgPSBmYWxzZTtcbiAgICAgICAgbGV0IHN0ciA9IFwiXCI7XG5cbiAgICAgICAgd2hpbGUgKCFlbmRPZlN0cmluZ0ZvdW5kKSB7XG4gICAgICAgICAgICBsZXQgY3VycmVudFBhZ2UgPSBNYXRoLmZsb29yKGN1cnJlbnRQb3NpdGlvbiAvIFBBR0VfU0laRSk7XG4gICAgICAgICAgICBsZXQgb2Zmc2V0T25QYWdlID0gY3VycmVudFBvc2l0aW9uICUgUEFHRV9TSVpFO1xuXG4gICAgICAgICAgICBpZiAoc2VsZi5vLmRhdGFbY3VycmVudFBhZ2VdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJFUlJPUlwiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IHJlYWRMZW5ndGggPSBNYXRoLm1pbihmaXhlZFNpemUsIHNlbGYuby5kYXRhW2N1cnJlbnRQYWdlXS5sZW5ndGggLSBvZmZzZXRPblBhZ2UpO1xuICAgICAgICAgICAgY29uc3QgZGF0YUFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5vLmRhdGFbY3VycmVudFBhZ2VdLmJ1ZmZlciwgb2Zmc2V0T25QYWdlLCByZWFkTGVuZ3RoKTtcblxuICAgICAgICAgICAgbGV0IGluZGV4RW5kT2ZTdHJpbmcgPSBkYXRhQXJyYXkuZmluZEluZGV4KGVsZW1lbnQgPT4gZWxlbWVudCA9PT0gMCk7XG4gICAgICAgICAgICBlbmRPZlN0cmluZ0ZvdW5kID0gaW5kZXhFbmRPZlN0cmluZyAhPT0gLTE7XG5cbiAgICAgICAgICAgIGlmIChlbmRPZlN0cmluZ0ZvdW5kKSB7XG4gICAgICAgICAgICAgICAgc3RyICs9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhQXJyYXkuc2xpY2UoMCwgaW5kZXhFbmRPZlN0cmluZykpO1xuICAgICAgICAgICAgICAgIHNlbGYucG9zID0gY3VycmVudFBhZ2UgKiBQQUdFX1NJWkUgKyBvZmZzZXRPblBhZ2UgKyBpbmRleEVuZE9mU3RyaW5nICsgMTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RyICs9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhQXJyYXkpO1xuICAgICAgICAgICAgICAgIHNlbGYucG9zID0gY3VycmVudFBhZ2UgKiBQQUdFX1NJWkUgKyBvZmZzZXRPblBhZ2UgKyBkYXRhQXJyYXkubGVuZ3RoO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjdXJyZW50UG9zaXRpb24gPSBzZWxmLnBvcztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3RyO1xuICAgIH1cbn1cbiIsIi8qIGdsb2JhbCBmZXRjaCAqL1xuaW1wb3J0IHsgb3BlbiB9IGZyb20gXCIuL29zZmlsZS5qc1wiO1xuaW1wb3J0ICogYXMgbWVtRmlsZSBmcm9tIFwiLi9tZW1maWxlLmpzXCI7XG5pbXBvcnQgKiBhcyBiaWdNZW1GaWxlIGZyb20gXCIuL2JpZ21lbWZpbGUuanNcIjtcbmltcG9ydCB7IE9fVFJVTkMsIE9fQ1JFQVQsIE9fUkRXUiwgT19FWENMLCBPX1JET05MWSB9IGZyb20gXCJjb25zdGFudHNcIjtcblxuY29uc3QgREVGQVVMVF9DQUNIRV9TSVpFID0gKDEgPDwgMTYpO1xuY29uc3QgREVGQVVMVF9QQUdFX1NJWkUgPSAoMSA8PCAxMyk7XG5cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZU92ZXJyaWRlKG8sIGIsIGMpIHtcbiAgICBpZiAodHlwZW9mIG8gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgbyA9IHtcbiAgICAgICAgICAgIHR5cGU6IFwiZmlsZVwiLFxuICAgICAgICAgICAgZmlsZU5hbWU6IG8sXG4gICAgICAgICAgICBjYWNoZVNpemU6IGIgfHwgREVGQVVMVF9DQUNIRV9TSVpFLFxuICAgICAgICAgICAgcGFnZVNpemU6IGMgfHwgREVGQVVMVF9QQUdFX1NJWkVcbiAgICAgICAgfTtcbiAgICB9XG4gICAgaWYgKG8udHlwZSA9PSBcImZpbGVcIikge1xuICAgICAgICByZXR1cm4gYXdhaXQgb3BlbihvLmZpbGVOYW1lLCBPX1RSVU5DIHwgT19DUkVBVCB8IE9fUkRXUiwgby5jYWNoZVNpemUsIG8ucGFnZVNpemUpO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwibWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIG1lbUZpbGUuY3JlYXRlTmV3KG8pO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwiYmlnTWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIGJpZ01lbUZpbGUuY3JlYXRlTmV3KG8pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgRmFzdEZpbGUgdHlwZTogXCIrby50eXBlKTtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVOb092ZXJyaWRlKG8sIGIsIGMpIHtcbiAgICBpZiAodHlwZW9mIG8gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgbyA9IHtcbiAgICAgICAgICAgIHR5cGU6IFwiZmlsZVwiLFxuICAgICAgICAgICAgZmlsZU5hbWU6IG8sXG4gICAgICAgICAgICBjYWNoZVNpemU6IGIgfHwgREVGQVVMVF9DQUNIRV9TSVpFLFxuICAgICAgICAgICAgcGFnZVNpemU6IGMgfHwgREVGQVVMVF9QQUdFX1NJWkVcbiAgICAgICAgfTtcbiAgICB9XG4gICAgaWYgKG8udHlwZSA9PSBcImZpbGVcIikge1xuICAgICAgICByZXR1cm4gb3BlbihvLmZpbGVOYW1lLCBPX1RSVU5DIHwgT19DUkVBVCB8IE9fUkRXUiB8IE9fRVhDTCwgby5jYWNoZVNpemUsIG8ucGFnZVNpemUpO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwibWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIG1lbUZpbGUuY3JlYXRlTmV3KG8pO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwiYmlnTWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIGJpZ01lbUZpbGUuY3JlYXRlTmV3KG8pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgRmFzdEZpbGUgdHlwZTogXCIrby50eXBlKTtcbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkRXhpc3RpbmcobywgYiwgYykge1xuICAgIGlmIChvIGluc3RhbmNlb2YgVWludDhBcnJheSkge1xuICAgICAgICBvID0ge1xuICAgICAgICAgICAgdHlwZTogXCJtZW1cIixcbiAgICAgICAgICAgIGRhdGE6IG9cbiAgICAgICAgfTtcbiAgICB9XG4gICAgaWYgKHByb2Nlc3MuYnJvd3Nlcikge1xuICAgICAgICBpZiAodHlwZW9mIG8gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZXRjaChvKS50aGVuKCBmdW5jdGlvbihyZXMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzLmFycmF5QnVmZmVyKCk7XG4gICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChhYikge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheShhYik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIG8gPSB7XG4gICAgICAgICAgICAgICAgdHlwZTogXCJtZW1cIixcbiAgICAgICAgICAgICAgICBkYXRhOiBidWZmXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHR5cGVvZiBvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICBvID0ge1xuICAgICAgICAgICAgICAgIHR5cGU6IFwiZmlsZVwiLFxuICAgICAgICAgICAgICAgIGZpbGVOYW1lOiBvLFxuICAgICAgICAgICAgICAgIGNhY2hlU2l6ZTogYiB8fCBERUZBVUxUX0NBQ0hFX1NJWkUsXG4gICAgICAgICAgICAgICAgcGFnZVNpemU6IGMgfHwgREVGQVVMVF9QQUdFX1NJWkVcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKG8udHlwZSA9PSBcImZpbGVcIikge1xuICAgICAgICByZXR1cm4gYXdhaXQgb3BlbihvLmZpbGVOYW1lLCBPX1JET05MWSwgby5jYWNoZVNpemUsIG8ucGFnZVNpemUpO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwibWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IG1lbUZpbGUucmVhZEV4aXN0aW5nKG8pO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwiYmlnTWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGJpZ01lbUZpbGUucmVhZEV4aXN0aW5nKG8pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgRmFzdEZpbGUgdHlwZTogXCIrby50eXBlKTtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWFkV3JpdGVFeGlzdGluZyhvLCBiLCBjKSB7XG4gICAgaWYgKHR5cGVvZiBvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG8gPSB7XG4gICAgICAgICAgICB0eXBlOiBcImZpbGVcIixcbiAgICAgICAgICAgIGZpbGVOYW1lOiBvLFxuICAgICAgICAgICAgY2FjaGVTaXplOiBiIHx8IERFRkFVTFRfQ0FDSEVfU0laRSxcbiAgICAgICAgICAgIHBhZ2VTaXplOiBjIHx8IERFRkFVTFRfUEFHRV9TSVpFXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChvLnR5cGUgPT0gXCJmaWxlXCIpIHtcbiAgICAgICAgcmV0dXJuIG9wZW4oby5maWxlTmFtZSwgT19DUkVBVCB8IE9fUkRXUiwgby5jYWNoZVNpemUsIG8ucGFnZVNpemUpO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwibWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIG1lbUZpbGUucmVhZFdyaXRlRXhpc3Rpbmcobyk7XG4gICAgfSBlbHNlIGlmIChvLnR5cGUgPT0gXCJiaWdNZW1cIikge1xuICAgICAgICByZXR1cm4gYmlnTWVtRmlsZS5yZWFkV3JpdGVFeGlzdGluZyhvKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIEZhc3RGaWxlIHR5cGU6IFwiK28udHlwZSk7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVhZFdyaXRlRXhpc3RpbmdPckNyZWF0ZShvLCBiLCBjKSB7XG4gICAgaWYgKHR5cGVvZiBvID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG8gPSB7XG4gICAgICAgICAgICB0eXBlOiBcImZpbGVcIixcbiAgICAgICAgICAgIGZpbGVOYW1lOiBvLFxuICAgICAgICAgICAgY2FjaGVTaXplOiBiIHx8IERFRkFVTFRfQ0FDSEVfU0laRSxcbiAgICAgICAgICAgIHBhZ2VTaXplOiBjIHx8IERFRkFVTFRfUEFHRV9TSVpFXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChvLnR5cGUgPT0gXCJmaWxlXCIpIHtcbiAgICAgICAgcmV0dXJuIG9wZW4oby5maWxlTmFtZSwgT19DUkVBVCB8IE9fUkRXUiB8IE9fRVhDTCwgby5jYWNoZVNpemUpO1xuICAgIH0gZWxzZSBpZiAoby50eXBlID09IFwibWVtXCIpIHtcbiAgICAgICAgcmV0dXJuIG1lbUZpbGUucmVhZFdyaXRlRXhpc3Rpbmcobyk7XG4gICAgfSBlbHNlIGlmIChvLnR5cGUgPT0gXCJiaWdNZW1cIikge1xuICAgICAgICByZXR1cm4gYmlnTWVtRmlsZS5yZWFkV3JpdGVFeGlzdGluZyhvKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIEZhc3RGaWxlIHR5cGU6IFwiK28udHlwZSk7XG4gICAgfVxufVxuIiwiXG5pbXBvcnQgIHsgU2NhbGFyLCBCaWdCdWZmZXIgfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5pbXBvcnQgKiBhcyBmYXN0RmlsZSBmcm9tIFwiZmFzdGZpbGVcIjtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRCaW5GaWxlKGZpbGVOYW1lLCB0eXBlLCBtYXhWZXJzaW9uLCBjYWNoZVNpemUsIHBhZ2VTaXplKSB7XG5cbiAgICBjb25zdCBmZCA9IGF3YWl0IGZhc3RGaWxlLnJlYWRFeGlzdGluZyhmaWxlTmFtZSwgY2FjaGVTaXplLCBwYWdlU2l6ZSk7XG5cbiAgICBjb25zdCBiID0gYXdhaXQgZmQucmVhZCg0KTtcbiAgICBsZXQgcmVhZGVkVHlwZSA9IFwiXCI7XG4gICAgZm9yIChsZXQgaT0wOyBpPDQ7IGkrKykgcmVhZGVkVHlwZSArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJbaV0pO1xuXG4gICAgaWYgKHJlYWRlZFR5cGUgIT0gdHlwZSkgdGhyb3cgbmV3IEVycm9yKGZpbGVOYW1lICsgXCI6IEludmFsaWQgRmlsZSBmb3JtYXRcIik7XG5cbiAgICBsZXQgdiA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuXG4gICAgaWYgKHY+bWF4VmVyc2lvbikgdGhyb3cgbmV3IEVycm9yKFwiVmVyc2lvbiBub3Qgc3VwcG9ydGVkXCIpO1xuXG4gICAgY29uc3QgblNlY3Rpb25zID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG5cbiAgICAvLyBTY2FuIHNlY3Rpb25zXG4gICAgbGV0IHNlY3Rpb25zID0gW107XG4gICAgZm9yIChsZXQgaT0wOyBpPG5TZWN0aW9uczsgaSsrKSB7XG4gICAgICAgIGxldCBodCA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgICAgICBsZXQgaGwgPSBhd2FpdCBmZC5yZWFkVUxFNjQoKTtcbiAgICAgICAgaWYgKHR5cGVvZiBzZWN0aW9uc1todF0gPT0gXCJ1bmRlZmluZWRcIikgc2VjdGlvbnNbaHRdID0gW107XG4gICAgICAgIHNlY3Rpb25zW2h0XS5wdXNoKHtcbiAgICAgICAgICAgIHA6IGZkLnBvcyxcbiAgICAgICAgICAgIHNpemU6IGhsXG4gICAgICAgIH0pO1xuICAgICAgICBmZC5wb3MgKz0gaGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtmZCwgc2VjdGlvbnN9O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQmluRmlsZShmaWxlTmFtZSwgdHlwZSwgdmVyc2lvbiwgblNlY3Rpb25zLCBjYWNoZVNpemUsIHBhZ2VTaXplKSB7XG5cbiAgICBjb25zdCBmZCA9IGF3YWl0IGZhc3RGaWxlLmNyZWF0ZU92ZXJyaWRlKGZpbGVOYW1lLCBjYWNoZVNpemUsIHBhZ2VTaXplKTtcblxuICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheSg0KTtcbiAgICBmb3IgKGxldCBpPTA7IGk8NDsgaSsrKSBidWZmW2ldID0gdHlwZS5jaGFyQ29kZUF0KGkpO1xuICAgIGF3YWl0IGZkLndyaXRlKGJ1ZmYsIDApOyAvLyBNYWdpYyBcInIxY3NcIlxuXG4gICAgYXdhaXQgZmQud3JpdGVVTEUzMih2ZXJzaW9uKTsgLy8gVmVyc2lvblxuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoblNlY3Rpb25zKTsgLy8gTnVtYmVyIG9mIFNlY3Rpb25zXG5cbiAgICByZXR1cm4gZmQ7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydFdyaXRlU2VjdGlvbihmZCwgaWRTZWN0aW9uKSB7XG4gICAgaWYgKHR5cGVvZiBmZC53cml0aW5nU2VjdGlvbiAhPT0gXCJ1bmRlZmluZWRcIikgdGhyb3cgbmV3IEVycm9yKFwiQWxyZWFkeSB3cml0aW5nIGEgc2VjdGlvblwiKTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKGlkU2VjdGlvbik7IC8vIEhlYWRlciB0eXBlXG4gICAgZmQud3JpdGluZ1NlY3Rpb24gPSB7XG4gICAgICAgIHBTZWN0aW9uU2l6ZTogZmQucG9zXG4gICAgfTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTY0KDApOyAvLyBUZW1wb3JhbGx5IHNldCB0byAwIGxlbmd0aFxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZW5kV3JpdGVTZWN0aW9uKGZkKSB7XG4gICAgaWYgKHR5cGVvZiBmZC53cml0aW5nU2VjdGlvbiA9PT0gXCJ1bmRlZmluZWRcIikgdGhyb3cgbmV3IEVycm9yKFwiTm90IHdyaXRpbmcgYSBzZWN0aW9uXCIpO1xuXG4gICAgY29uc3Qgc2VjdGlvblNpemUgPSBmZC5wb3MgLSBmZC53cml0aW5nU2VjdGlvbi5wU2VjdGlvblNpemUgLSA4O1xuICAgIGNvbnN0IG9sZFBvcyA9IGZkLnBvcztcbiAgICBmZC5wb3MgPSBmZC53cml0aW5nU2VjdGlvbi5wU2VjdGlvblNpemU7XG4gICAgYXdhaXQgZmQud3JpdGVVTEU2NChzZWN0aW9uU2l6ZSk7XG4gICAgZmQucG9zID0gb2xkUG9zO1xuICAgIGRlbGV0ZSBmZC53cml0aW5nU2VjdGlvbjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmQsIHNlY3Rpb25zLCBpZFNlY3Rpb24pIHtcbiAgICBpZiAodHlwZW9mIGZkLnJlYWRpbmdTZWN0aW9uICE9PSBcInVuZGVmaW5lZFwiKSB0aHJvdyBuZXcgRXJyb3IoXCJBbHJlYWR5IHJlYWRpbmcgYSBzZWN0aW9uXCIpO1xuICAgIGlmICghc2VjdGlvbnNbaWRTZWN0aW9uXSkgIHRocm93IG5ldyBFcnJvcihmZC5maWxlTmFtZSArIFwiOiBNaXNzaW5nIHNlY3Rpb24gXCIrIGlkU2VjdGlvbiApO1xuICAgIGlmIChzZWN0aW9uc1tpZFNlY3Rpb25dLmxlbmd0aD4xKSB0aHJvdyBuZXcgRXJyb3IoZmQuZmlsZU5hbWUgK1wiOiBTZWN0aW9uIER1cGxpY2F0ZWQgXCIgK2lkU2VjdGlvbik7XG5cbiAgICBmZC5wb3MgPSBzZWN0aW9uc1tpZFNlY3Rpb25dWzBdLnA7XG5cbiAgICBmZC5yZWFkaW5nU2VjdGlvbiA9IHNlY3Rpb25zW2lkU2VjdGlvbl1bMF07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBlbmRSZWFkU2VjdGlvbihmZCwgbm9DaGVjaykge1xuICAgIGlmICh0eXBlb2YgZmQucmVhZGluZ1NlY3Rpb24gPT09IFwidW5kZWZpbmVkXCIpIHRocm93IG5ldyBFcnJvcihcIk5vdCByZWFkaW5nIGEgc2VjdGlvblwiKTtcbiAgICBpZiAoIW5vQ2hlY2spIHtcbiAgICAgICAgaWYgKGZkLnBvcy1mZC5yZWFkaW5nU2VjdGlvbi5wICE9ICBmZC5yZWFkaW5nU2VjdGlvbi5zaXplKSB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHNlY3Rpb24gc2l6ZSByZWFkaW5nXCIpO1xuICAgIH1cbiAgICBkZWxldGUgZmQucmVhZGluZ1NlY3Rpb247XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZUJpZ0ludChmZCwgbiwgbjgsIHBvcykge1xuICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShuOCk7XG4gICAgU2NhbGFyLnRvUnByTEUoYnVmZiwgMCwgbiwgbjgpO1xuICAgIGF3YWl0IGZkLndyaXRlKGJ1ZmYsIHBvcyk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkQmlnSW50KGZkLCBuOCwgcG9zKSB7XG4gICAgY29uc3QgYnVmZiA9IGF3YWl0IGZkLnJlYWQobjgsIHBvcyk7XG4gICAgcmV0dXJuIFNjYWxhci5mcm9tUnByTEUoYnVmZiwgMCwgbjgpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29weVNlY3Rpb24oZmRGcm9tLCBzZWN0aW9ucywgZmRUbywgc2VjdGlvbklkLCBzaXplKSB7XG4gICAgaWYgKHR5cGVvZiBzaXplID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIHNpemUgPSBzZWN0aW9uc1tzZWN0aW9uSWRdWzBdLnNpemU7XG4gICAgfVxuICAgIGNvbnN0IGNodW5rU2l6ZSA9IGZkRnJvbS5wYWdlU2l6ZTtcbiAgICBhd2FpdCBzdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkRnJvbSwgc2VjdGlvbnMsIHNlY3Rpb25JZCk7XG4gICAgYXdhaXQgc3RhcnRXcml0ZVNlY3Rpb24oZmRUbywgc2VjdGlvbklkKTtcbiAgICBmb3IgKGxldCBwPTA7IHA8c2l6ZTsgcCs9Y2h1bmtTaXplKSB7XG4gICAgICAgIGNvbnN0IGwgPSBNYXRoLm1pbihzaXplIC1wLCBjaHVua1NpemUpO1xuICAgICAgICBjb25zdCBidWZmID0gYXdhaXQgZmRGcm9tLnJlYWQobCk7XG4gICAgICAgIGF3YWl0IGZkVG8ud3JpdGUoYnVmZik7XG4gICAgfVxuICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFRvKTtcbiAgICBhd2FpdCBlbmRSZWFkU2VjdGlvbihmZEZyb20sIHNpemUgIT0gc2VjdGlvbnNbc2VjdGlvbklkXVswXS5zaXplKTtcblxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZFNlY3Rpb24oZmQsIHNlY3Rpb25zLCBpZFNlY3Rpb24sIG9mZnNldCwgbGVuZ3RoKSB7XG5cbiAgICBvZmZzZXQgPSAodHlwZW9mIG9mZnNldCA9PT0gXCJ1bmRlZmluZWRcIikgPyAwIDogb2Zmc2V0O1xuICAgIGxlbmd0aCA9ICh0eXBlb2YgbGVuZ3RoID09PSBcInVuZGVmaW5lZFwiKSA/IHNlY3Rpb25zW2lkU2VjdGlvbl1bMF0uc2l6ZSAtIG9mZnNldCA6IGxlbmd0aDtcblxuICAgIGlmIChvZmZzZXQgKyBsZW5ndGggPiBzZWN0aW9uc1tpZFNlY3Rpb25dWzBdLnNpemUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVhZGluZyBvdXQgb2YgdGhlIHJhbmdlIG9mIHRoZSBzZWN0aW9uXCIpO1xuICAgIH1cblxuICAgIGxldCBidWZmO1xuICAgIGlmIChsZW5ndGggPCAoMSA8PCAzMCkgKSB7XG4gICAgICAgIGJ1ZmYgPSBuZXcgVWludDhBcnJheShsZW5ndGgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGJ1ZmYgPSBuZXcgQmlnQnVmZmVyKGxlbmd0aCk7XG4gICAgfVxuXG4gICAgYXdhaXQgZmQucmVhZFRvQnVmZmVyKGJ1ZmYsIDAsIGxlbmd0aCwgc2VjdGlvbnNbaWRTZWN0aW9uXVswXS5wICsgb2Zmc2V0KTtcbiAgICByZXR1cm4gYnVmZjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlY3Rpb25Jc0VxdWFsKGZkMSwgc2VjdGlvbnMxLCBmZDIsIHNlY3Rpb25zMiwgaWRTZWN0aW9uKSB7XG4gICAgY29uc3QgTUFYX0JVRkZfU0laRSA9IGZkMS5wYWdlU2l6ZSAqIDE2O1xuICAgIGF3YWl0IHN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmQxLCBzZWN0aW9uczEsIGlkU2VjdGlvbik7XG4gICAgYXdhaXQgc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZDIsIHNlY3Rpb25zMiwgaWRTZWN0aW9uKTtcbiAgICBpZiAoc2VjdGlvbnMxW2lkU2VjdGlvbl1bMF0uc2l6ZSAhPSBzZWN0aW9uczJbaWRTZWN0aW9uXVswXS5zaXplKSByZXR1cm4gZmFsc2U7XG4gICAgY29uc3QgdG90YWxCeXRlcz1zZWN0aW9uczFbaWRTZWN0aW9uXVswXS5zaXplO1xuICAgIGZvciAobGV0IGk9MDsgaTx0b3RhbEJ5dGVzOyBpKz0gTUFYX0JVRkZfU0laRSkge1xuICAgICAgICBjb25zdCBuID0gTWF0aC5taW4odG90YWxCeXRlcy1pLCBNQVhfQlVGRl9TSVpFKTtcbiAgICAgICAgY29uc3QgYnVmZjEgPSBhd2FpdCBmZDEucmVhZChuKTtcbiAgICAgICAgY29uc3QgYnVmZjIgPSBhd2FpdCBmZDIucmVhZChuKTtcbiAgICAgICAgZm9yIChsZXQgaj0wOyBqPG47IGorKykgaWYgKGJ1ZmYxW2pdICE9IGJ1ZmYyW2pdKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGF3YWl0IGVuZFJlYWRTZWN0aW9uKGZkMSk7XG4gICAgYXdhaXQgZW5kUmVhZFNlY3Rpb24oZmQyKTtcbiAgICByZXR1cm4gdHJ1ZTtcbn1cbiIsImltcG9ydCB7RjFGaWVsZCwgZ2V0Q3VydmVGcm9tUn0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuaW1wb3J0ICBCaWdBcnJheSBmcm9tIFwiQGlkZW4zL2JpZ2FycmF5XCI7XG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcblxuZXhwb3J0IGNvbnN0IFIxQ1NfRklMRV9IRUFERVJfU0VDVElPTiA9IDE7XG5leHBvcnQgY29uc3QgUjFDU19GSUxFX0NPTlNUUkFJTlRTX1NFQ1RJT04gPSAyO1xuZXhwb3J0IGNvbnN0IFIxQ1NfRklMRV9XSVJFMkxBQkVMSURfU0VDVElPTiA9IDM7XG5leHBvcnQgY29uc3QgUjFDU19GSUxFX0NVU1RPTV9HQVRFU19MSVNUX1NFQ1RJT04gPSA0O1xuZXhwb3J0IGNvbnN0IFIxQ1NfRklMRV9DVVNUT01fR0FURVNfVVNFU19TRUNUSU9OID0gNTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRSMWNzSGVhZGVyKGZkLHNlY3Rpb25zLHNpbmdsZVRocmVhZCkge1xuICAgIGxldCBvcHRpb25zO1xuICAgIGlmICh0eXBlb2Ygc2luZ2xlVGhyZWFkID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIG9wdGlvbnMgPSBzaW5nbGVUaHJlYWQ7XG4gICAgfSBlbHNlIGlmICh0eXBlb2Ygc2luZ2xlVGhyZWFkID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIG9wdGlvbnM9IHtcbiAgICAgICAgICAgIHNpbmdsZVRocmVhZDogZmFsc2UsXG4gICAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgICAgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgIHNpbmdsZVRocmVhZDogc2luZ2xlVGhyZWFkLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IHJlcyA9IHt9O1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkLCBzZWN0aW9ucywgMSk7XG4gICAgLy8gUmVhZCBIZWFkZXJcbiAgICByZXMubjggPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICByZXMucHJpbWUgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpZ0ludChmZCwgcmVzLm44KTtcblxuICAgIGlmIChvcHRpb25zLkYpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuRi5wICE9IHJlcy5wcmltZSkgdGhyb3cgbmV3IEVycm9yKFwiRGlmZmVyZW50IFByaW1lXCIpO1xuICAgICAgICByZXMuRiA9IG9wdGlvbnMuRjtcbiAgICB9IGVsc2UgaWYgKG9wdGlvbnMuZ2V0RmllbGRGcm9tUHJpbWUpIHtcbiAgICAgICAgcmVzLkYgPSBhd2FpdCBvcHRpb25zLmdldEZpZWxkRnJvbVByaW1lKHJlcy5wcmltZSwgb3B0aW9ucy5zaW5nbGVUaHJlYWQpO1xuICAgIH0gZWxzZSBpZiAob3B0aW9ucy5nZXRDdXJ2ZUZyb21QcmltZSkge1xuICAgICAgICByZXMuY3VydmUgPSBhd2FpdCBvcHRpb25zLmdldEN1cnZlRnJvbVByaW1lKHJlcy5wcmltZSwgb3B0aW9ucy5zaW5nbGVUaHJlYWQpO1xuICAgICAgICByZXMuRiA9IHJlcy5jdXJ2ZS5GcjtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVzLmN1cnZlID0gYXdhaXQgZ2V0Q3VydmVGcm9tUihyZXMucHJpbWUsIG9wdGlvbnMuc2luZ2xlVGhyZWFkKTtcbiAgICAgICAgICAgIHJlcy5GID0gcmVzLmN1cnZlLkZyO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIHJlcy5GID0gbmV3IEYxRmllbGQocmVzLnByaW1lKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJlcy5uVmFycyA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHJlcy5uT3V0cHV0cyA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuICAgIHJlcy5uUHViSW5wdXRzID0gYXdhaXQgZmQucmVhZFVMRTMyKCk7XG4gICAgcmVzLm5QcnZJbnB1dHMgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICByZXMubkxhYmVscyA9IGF3YWl0IGZkLnJlYWRVTEU2NCgpO1xuICAgIHJlcy5uQ29uc3RyYWludHMgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcbiAgICByZXMudXNlQ3VzdG9tR2F0ZXMgPSB0eXBlb2Ygc2VjdGlvbnNbUjFDU19GSUxFX0NVU1RPTV9HQVRFU19MSVNUX1NFQ1RJT05dICE9PSBcInVuZGVmaW5lZFwiICYmIHNlY3Rpb25zW1IxQ1NfRklMRV9DVVNUT01fR0FURVNfTElTVF9TRUNUSU9OXSAhPT0gbnVsbFxuICAgICAgICAmJiB0eXBlb2Ygc2VjdGlvbnNbUjFDU19GSUxFX0NVU1RPTV9HQVRFU19VU0VTX1NFQ1RJT05dICE9PSBcInVuZGVmaW5lZFwiICYmIHNlY3Rpb25zW1IxQ1NfRklMRV9DVVNUT01fR0FURVNfVVNFU19TRUNUSU9OXSAhPT0gbnVsbDtcblxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRSZWFkU2VjdGlvbihmZCk7XG5cbiAgICByZXR1cm4gcmVzO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZENvbnN0cmFpbnRzKGZkLHNlY3Rpb25zLCByMWNzLCBsb2dnZXIsIGxvZ2dlckN0eCkge1xuICAgIGxldCBvcHRpb25zO1xuICAgIGlmICh0eXBlb2YgbG9nZ2VyID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIG9wdGlvbnMgPSBsb2dnZXI7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgbG9nZ2VyID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIG9wdGlvbnM9IHt9O1xuICAgIH0gZWxzZSB7XG4gICAgICAgIG9wdGlvbnMgPSB7XG4gICAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICAgIGxvZ2dlckN0eDogbG9nZ2VyQ3R4LFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IGJSMWNzID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRTZWN0aW9uKGZkLCBzZWN0aW9ucywgMik7XG4gICAgbGV0IGJSMWNzUG9zID0gMDtcbiAgICBsZXQgY29uc3RyYWludHM7XG4gICAgaWYgKHIxY3MubkNvbnN0cmFpbnRzPjE8PDIwKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzID0gbmV3IEJpZ0FycmF5KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3RyYWludHMgPSBbXTtcbiAgICB9XG4gICAgZm9yIChsZXQgaT0wOyBpPHIxY3MubkNvbnN0cmFpbnRzOyBpKyspIHtcbiAgICAgICAgaWYgKChvcHRpb25zLmxvZ2dlcikmJihpJTEwMDAwMCA9PSAwKSkgb3B0aW9ucy5sb2dnZXIuaW5mbyhgJHtvcHRpb25zLmxvZ2dlckN0eH06IExvYWRpbmcgY29uc3RyYWludHM6ICR7aX0vJHtyMWNzLm5Db25zdHJhaW50c31gKTtcbiAgICAgICAgY29uc3QgYyA9IHJlYWRDb25zdHJhaW50KCk7XG4gICAgICAgIGNvbnN0cmFpbnRzLnB1c2goYyk7XG4gICAgfVxuICAgIHJldHVybiBjb25zdHJhaW50cztcblxuXG4gICAgZnVuY3Rpb24gcmVhZENvbnN0cmFpbnQoKSB7XG4gICAgICAgIGNvbnN0IGMgPSBbXTtcbiAgICAgICAgY1swXSA9IHJlYWRMQygpO1xuICAgICAgICBjWzFdID0gcmVhZExDKCk7XG4gICAgICAgIGNbMl0gPSByZWFkTEMoKTtcbiAgICAgICAgcmV0dXJuIGM7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVhZExDKCkge1xuICAgICAgICBjb25zdCBsYz0ge307XG5cbiAgICAgICAgY29uc3QgYnVmZlVMMzIgPSBiUjFjcy5zbGljZShiUjFjc1BvcywgYlIxY3NQb3MrNCk7XG4gICAgICAgIGJSMWNzUG9zICs9IDQ7XG4gICAgICAgIGNvbnN0IGJ1ZmZVTDMyViA9IG5ldyBEYXRhVmlldyhidWZmVUwzMi5idWZmZXIpO1xuICAgICAgICBjb25zdCBuSWR4ID0gYnVmZlVMMzJWLmdldFVpbnQzMigwLCB0cnVlKTtcblxuICAgICAgICBjb25zdCBidWZmID0gYlIxY3Muc2xpY2UoYlIxY3NQb3MsIGJSMWNzUG9zICsgKDQrcjFjcy5uOCkqbklkeCApO1xuICAgICAgICBiUjFjc1BvcyArPSAoNCtyMWNzLm44KSpuSWR4O1xuICAgICAgICBjb25zdCBidWZmViA9IG5ldyBEYXRhVmlldyhidWZmLmJ1ZmZlcik7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxuSWR4OyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGlkeCA9IGJ1ZmZWLmdldFVpbnQzMihpKig0K3IxY3MubjgpLCB0cnVlKTtcbiAgICAgICAgICAgIGNvbnN0IHZhbCA9IHIxY3MuRi5mcm9tUnByTEUoYnVmZiwgaSooNCtyMWNzLm44KSs0KTtcbiAgICAgICAgICAgIGxjW2lkeF0gPSB2YWw7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGxjO1xuICAgIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRNYXAoZmQsIHNlY3Rpb25zLCByMWNzLCBsb2dnZXIsIGxvZ2dlckN0eCkge1xuICAgIGxldCBvcHRpb25zO1xuICAgIGlmICh0eXBlb2YgbG9nZ2VyID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIG9wdGlvbnMgPSBsb2dnZXI7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgbG9nZ2VyID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIG9wdGlvbnM9IHt9O1xuICAgIH0gZWxzZSB7XG4gICAgICAgIG9wdGlvbnMgPSB7XG4gICAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICAgIGxvZ2dlckN0eDogbG9nZ2VyQ3R4LFxuICAgICAgICB9O1xuICAgIH1cbiAgICBjb25zdCBiTWFwID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRTZWN0aW9uKGZkLCBzZWN0aW9ucywgMyk7XG4gICAgbGV0IGJNYXBQb3MgPSAwO1xuICAgIGxldCBtYXA7XG5cbiAgICBpZiAocjFjcy5uVmFycz4xPDwyMCkge1xuICAgICAgICBtYXAgPSBuZXcgQmlnQXJyYXkoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBtYXAgPSBbXTtcbiAgICB9XG4gICAgZm9yIChsZXQgaT0wOyBpPHIxY3MublZhcnM7IGkrKykge1xuICAgICAgICBpZiAoKG9wdGlvbnMubG9nZ2VyKSYmKGklMTAwMDAgPT0gMCkpIG9wdGlvbnMubG9nZ2VyLmluZm8oYCR7b3B0aW9ucy5sb2dnZXJDdHh9OiBMb2FkaW5nIG1hcDogJHtpfS8ke3IxY3MublZhcnN9YCk7XG4gICAgICAgIGNvbnN0IGlkeCA9IHJlYWRVTEU2NCgpO1xuICAgICAgICBtYXAucHVzaChpZHgpO1xuICAgIH1cblxuICAgIHJldHVybiBtYXA7XG5cbiAgICBmdW5jdGlvbiByZWFkVUxFNjQoKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmZVTEU2NCA9IGJNYXAuc2xpY2UoYk1hcFBvcywgYk1hcFBvcys4KTtcbiAgICAgICAgYk1hcFBvcyArPSA4O1xuICAgICAgICBjb25zdCBidWZmVUxFNjRWID0gbmV3IERhdGFWaWV3KGJ1ZmZVTEU2NC5idWZmZXIpO1xuICAgICAgICBjb25zdCBMU0IgPSBidWZmVUxFNjRWLmdldFVpbnQzMigwLCB0cnVlKTtcbiAgICAgICAgY29uc3QgTVNCID0gYnVmZlVMRTY0Vi5nZXRVaW50MzIoNCwgdHJ1ZSk7XG5cbiAgICAgICAgcmV0dXJuIE1TQiAqIDB4MTAwMDAwMDAwICsgTFNCO1xuICAgIH1cblxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZFIxY3NGZChmZCwgc2VjdGlvbnMsIG9wdGlvbnMpIHtcbiAgICAvKipcbiAgICAgKiBPcHRpb25zIHByb3BlcnRpZXM6XG4gICAgICogIGxvYWRDb25zdHJhaW50czogPGJvb2w+IHRydWUgYnkgZGVmYXVsdFxuICAgICAqICBsb2FkTWFwOiAgICAgICAgIDxib29sPiBmYWxzZSBieSBkZWZhdWx0XG4gICAgICogIGxvYWRDdXN0b21HYXRlczogPGJvb2w+IHRydWUgYnkgZGVmYXVsdFxuICAgICAqL1xuXG4gICAgaWYodHlwZW9mIG9wdGlvbnMgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwicmVhZFIxY3NGZDogb3B0aW9ucyBtdXN0IGJlIGFuIG9iamVjdFwiKTtcbiAgICB9XG5cbiAgICBvcHRpb25zLmxvYWRDb25zdHJhaW50cyA9IFwibG9hZENvbnN0cmFpbnRzXCIgaW4gb3B0aW9ucyA/IG9wdGlvbnMubG9hZENvbnN0cmFpbnRzIDogdHJ1ZTtcbiAgICBvcHRpb25zLmxvYWRNYXAgPSBcImxvYWRNYXBcIiBpbiBvcHRpb25zID8gb3B0aW9ucy5sb2FkTWFwIDogZmFsc2U7XG4gICAgb3B0aW9ucy5sb2FkQ3VzdG9tR2F0ZXMgPSBcImxvYWRDdXN0b21HYXRlc1wiIGluIG9wdGlvbnMgPyBvcHRpb25zLmxvYWRDdXN0b21HYXRlcyA6IHRydWU7XG5cbiAgICBjb25zdCByZXMgPSBhd2FpdCByZWFkUjFjc0hlYWRlcihmZCwgc2VjdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgaWYgKG9wdGlvbnMubG9hZENvbnN0cmFpbnRzKSB7XG4gICAgICAgIHJlcy5jb25zdHJhaW50cyA9IGF3YWl0IHJlYWRDb25zdHJhaW50cyhmZCwgc2VjdGlvbnMsIHJlcywgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgLy8gUmVhZCBMYWJlbHNcblxuICAgIGlmIChvcHRpb25zLmxvYWRNYXApIHtcbiAgICAgICAgcmVzLm1hcCA9IGF3YWl0IHJlYWRNYXAoZmQsIHNlY3Rpb25zLCByZXMsIG9wdGlvbnMpO1xuICAgIH1cblxuICAgIGlmIChvcHRpb25zLmxvYWRDdXN0b21HYXRlcykge1xuICAgICAgICBpZiAocmVzLnVzZUN1c3RvbUdhdGVzKSB7XG4gICAgICAgICAgICByZXMuY3VzdG9tR2F0ZXMgPSBhd2FpdCByZWFkQ3VzdG9tR2F0ZXNMaXN0U2VjdGlvbihmZCwgc2VjdGlvbnMsIHJlcyk7XG4gICAgICAgICAgICByZXMuY3VzdG9tR2F0ZXNVc2VzID0gYXdhaXQgcmVhZEN1c3RvbUdhdGVzVXNlc1NlY3Rpb24oZmQsIHNlY3Rpb25zLCBvcHRpb25zKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlcy5jdXN0b21HYXRlcyA9IFtdO1xuICAgICAgICAgICAgcmVzLmN1c3RvbUdhdGVzVXNlcyA9IFtdO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkUjFjcyhmaWxlTmFtZSwgbG9hZENvbnN0cmFpbnRzLCBsb2FkTWFwLCBzaW5nbGVUaHJlYWQsIGxvZ2dlciwgbG9nZ2VyQ3R4KSB7XG4gICAgbGV0IG9wdGlvbnM7XG4gICAgaWYgKHR5cGVvZiBsb2FkQ29uc3RyYWludHMgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgb3B0aW9ucyA9IGxvYWRDb25zdHJhaW50cztcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBsb2FkQ29uc3RyYWludHMgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgb3B0aW9ucz0ge1xuICAgICAgICAgICAgbG9hZENvbnN0cmFpbnRzOiB0cnVlLFxuICAgICAgICAgICAgbG9hZE1hcDogZmFsc2UsXG4gICAgICAgICAgICBsb2FkQ3VzdG9tR2F0ZXM6IHRydWVcbiAgICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgbG9hZENvbnN0cmFpbnRzOiBsb2FkQ29uc3RyYWludHMsXG4gICAgICAgICAgICBsb2FkTWFwOiBsb2FkTWFwLFxuICAgICAgICAgICAgc2luZ2xlVGhyZWFkOiBzaW5nbGVUaHJlYWQsXG4gICAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICAgIGxvZ2dlckN0eDogbG9nZ2VyQ3R4XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3Qge2ZkLCBzZWN0aW9uc30gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUoZmlsZU5hbWUsIFwicjFjc1wiLCAxLCAxPDwyNSwgMTw8MjIpO1xuXG4gICAgY29uc3QgcmVzID0gYXdhaXQgcmVhZFIxY3NGZChmZCwgc2VjdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgYXdhaXQgZmQuY2xvc2UoKTtcblxuICAgIHJldHVybiByZXM7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkQ3VzdG9tR2F0ZXNMaXN0U2VjdGlvbihmZCwgc2VjdGlvbnMsIHJlcykge1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkLCBzZWN0aW9ucywgUjFDU19GSUxFX0NVU1RPTV9HQVRFU19MSVNUX1NFQ1RJT04pO1xuXG4gICAgbGV0IG51bSA9IGF3YWl0IGZkLnJlYWRVTEUzMigpO1xuXG4gICAgbGV0IGN1c3RvbUdhdGVzID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW07IGkrKykge1xuICAgICAgICBsZXQgY3VzdG9tR2F0ZSA9IHt9O1xuICAgICAgICBjdXN0b21HYXRlLnRlbXBsYXRlTmFtZSA9IGF3YWl0IGZkLnJlYWRTdHJpbmcoKTtcbiAgICAgICAgbGV0IG51bVBhcmFtZXRlcnMgPSBhd2FpdCBmZC5yZWFkVUxFMzIoKTtcblxuICAgICAgICBjdXN0b21HYXRlLnBhcmFtZXRlcnMgPSBBcnJheShudW1QYXJhbWV0ZXJzKTtcbiAgICAgICAgbGV0IGJ1ZmYgPSBhd2FpdCBmZC5yZWFkKHJlcy5uOCAqIG51bVBhcmFtZXRlcnMpO1xuXG4gICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgbnVtUGFyYW1ldGVyczsgaisrKSB7XG4gICAgICAgICAgICBjdXN0b21HYXRlLnBhcmFtZXRlcnNbal0gPSByZXMuRi5mcm9tUnByTEUoYnVmZiwgaiAqIHJlcy5uOCwgcmVzLm44KTs7XG4gICAgICAgIH1cbiAgICAgICAgY3VzdG9tR2F0ZXMucHVzaChjdXN0b21HYXRlKTtcbiAgICB9XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkKTtcblxuICAgIHJldHVybiBjdXN0b21HYXRlcztcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRDdXN0b21HYXRlc1VzZXNTZWN0aW9uKGZkLHNlY3Rpb25zLCBvcHRpb25zKSB7XG4gICAgY29uc3QgYlIxY3MgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmQsIHNlY3Rpb25zLCBSMUNTX0ZJTEVfQ1VTVE9NX0dBVEVTX1VTRVNfU0VDVElPTik7XG4gICAgY29uc3QgYlIxY3MzMiA9IG5ldyBVaW50MzJBcnJheShiUjFjcy5idWZmZXIsIGJSMWNzLmJ5dGVPZmZzZXQsIGJSMWNzLmJ5dGVMZW5ndGgvNCk7XG4gICAgY29uc3QgbkN1c3RvbUdhdGVVc2VzID0gYlIxY3MzMlswXTtcbiAgICBsZXQgYlIxY3NQb3MgPSAxO1xuICAgIGxldCBjdXN0b21HYXRlc1VzZXM7XG4gICAgaWYgKG5DdXN0b21HYXRlVXNlcz4xPDwyMCkge1xuICAgICAgICBjdXN0b21HYXRlc1VzZXMgPSBuZXcgQmlnQXJyYXkoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBjdXN0b21HYXRlc1VzZXMgPSBbXTtcbiAgICB9XG4gICAgZm9yIChsZXQgaT0wOyBpPG5DdXN0b21HYXRlVXNlczsgaSsrKSB7XG4gICAgICAgIGlmICgob3B0aW9ucy5sb2dnZXIpJiYoaSUxMDAwMDAgPT0gMCkpIG9wdGlvbnMubG9nZ2VyLmluZm8oYCR7b3B0aW9ucy5sb2dnZXJDdHh9OiBMb2FkaW5nIGN1c3RvbSBnYXRlIHVzZXM6ICR7aX0vJHtuQ3VzdG9tR2F0ZVVzZXN9YCk7XG4gICAgICAgIGxldCBjID0ge307XG4gICAgICAgIGMuaWQgPSBiUjFjczMyW2JSMWNzUG9zKytdO1xuICAgICAgICBsZXQgbnVtU2lnbmFscyA9IGJSMWNzMzJbYlIxY3NQb3MrK107XG4gICAgICAgIGMuc2lnbmFscyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IG51bVNpZ25hbHM7IGorKykge1xuICAgICAgICAgICAgY29uc3QgTFNCID0gYlIxY3MzMltiUjFjc1BvcysrXTtcbiAgICAgICAgICAgIGNvbnN0IE1TQiA9IGJSMWNzMzJbYlIxY3NQb3MrK107XG4gICAgICAgICAgICBjLnNpZ25hbHMucHVzaChNU0IgKiAweDEwMDAwMDAwMCArIExTQik7XG4gICAgICAgIH1cbiAgICAgICAgY3VzdG9tR2F0ZXNVc2VzLnB1c2goYyk7XG4gICAgfVxuICAgIHJldHVybiBjdXN0b21HYXRlc1VzZXM7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZVIxY3NIZWFkZXIoZmQsIGNpcikge1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZCwgMSk7XG4gICAgYXdhaXQgZmQud3JpdGVVTEUzMihjaXIubjgpOyAvLyBUZW1wb3JhbGx5IHNldCB0byAwIGxlbmd0aFxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy53cml0ZUJpZ0ludChmZCwgY2lyLnByaW1lLCBjaXIubjgpO1xuXG4gICAgYXdhaXQgZmQud3JpdGVVTEUzMihjaXIublZhcnMpO1xuICAgIGF3YWl0IGZkLndyaXRlVUxFMzIoY2lyLm5PdXRwdXRzKTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKGNpci5uUHViSW5wdXRzKTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKGNpci5uUHJ2SW5wdXRzKTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTY0KGNpci5uTGFiZWxzKTtcbiAgICBhd2FpdCBmZC53cml0ZVVMRTMyKGNpci5jb25zdHJhaW50cy5sZW5ndGgpO1xuXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFdyaXRlU2VjdGlvbihmZCk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZVIxY3NDb25zdHJhaW50cyhmZCwgY2lyLCBsb2dnZXIsIGxvZ2dlckN0eCkge1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFdyaXRlU2VjdGlvbihmZCwgMik7XG5cbiAgICBmb3IgKGxldCBpPTA7IGk8Y2lyLmNvbnN0cmFpbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmICgobG9nZ2VyKSYmKGklMTAwMDAgPT0gMCkpIGxvZ2dlci5pbmZvKGAke2xvZ2dlckN0eH06IHdyaXRpbmcgY29uc3RyYWludDogJHtpfS8ke2Npci5jb25zdHJhaW50cy5sZW5ndGh9YCk7XG4gICAgICAgIGF3YWl0IHdyaXRlQ29uc3RyYWludChjaXIuY29uc3RyYWludHNbaV0pO1xuICAgIH1cblxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmQpO1xuXG5cbiAgICBmdW5jdGlvbiB3cml0ZUNvbnN0cmFpbnQoYykge1xuICAgICAgICBjb25zdCBuOCA9IGNpci5uODtcbiAgICAgICAgY29uc3QgRiA9IGNpci5GIHx8IGNpci5jdXJ2ZS5GcjtcbiAgICAgICAgY29uc3QgaWR4QSA9IE9iamVjdC5rZXlzKGNbMF0pO1xuICAgICAgICBjb25zdCBpZHhCID0gT2JqZWN0LmtleXMoY1sxXSk7XG4gICAgICAgIGNvbnN0IGlkeEMgPSBPYmplY3Qua2V5cyhjWzJdKTtcbiAgICAgICAgY29uc3QgYnVmZiA9IG5ldyBVaW50OEFycmF5KChpZHhBLmxlbmd0aCtpZHhCLmxlbmd0aCtpZHhDLmxlbmd0aCkqKG44KzQpICsgMTIpO1xuICAgICAgICBjb25zdCBidWZmViA9IG5ldyBEYXRhVmlldyhidWZmLmJ1ZmZlcik7XG4gICAgICAgIGxldCBvPTA7XG5cbiAgICAgICAgYnVmZlYuc2V0VWludDMyKG8sIGlkeEEubGVuZ3RoLCB0cnVlKTsgbys9NDtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPGlkeEEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGNvZWYgPSBpZHhBW2ldO1xuICAgICAgICAgICAgYnVmZlYuc2V0VWludDMyKG8sIGNvZWYsIHRydWUpOyBvKz00O1xuICAgICAgICAgICAgRi50b1JwckxFKGJ1ZmYsIG8sIGNbMF1bY29lZl0pOyBvKz1uODtcbiAgICAgICAgfVxuXG4gICAgICAgIGJ1ZmZWLnNldFVpbnQzMihvLCBpZHhCLmxlbmd0aCwgdHJ1ZSk7IG8rPTQ7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxpZHhCLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBjb2VmID0gaWR4QltpXTtcbiAgICAgICAgICAgIGJ1ZmZWLnNldFVpbnQzMihvLCBjb2VmLCB0cnVlKTsgbys9NDtcbiAgICAgICAgICAgIEYudG9ScHJMRShidWZmLCBvLCBjWzFdW2NvZWZdKTsgbys9bjg7XG4gICAgICAgIH1cblxuICAgICAgICBidWZmVi5zZXRVaW50MzIobywgaWR4Qy5sZW5ndGgsIHRydWUpOyBvKz00O1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8aWR4Qy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgY29lZiA9IGlkeENbaV07XG4gICAgICAgICAgICBidWZmVi5zZXRVaW50MzIobywgY29lZiwgdHJ1ZSk7IG8rPTQ7XG4gICAgICAgICAgICBGLnRvUnByTEUoYnVmZiwgbywgY1syXVtjb2VmXSk7IG8rPW44O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZkLndyaXRlKGJ1ZmYpO1xuICAgIH1cblxufVxuXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZVIxY3NNYXAoZmQsIGNpciwgbG9nZ2VyLCBsb2dnZXJDdHgpIHtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24oZmQsIDMpO1xuXG4gICAgaWYgKGNpci5tYXAubGVuZ3RoICE9IGNpci5uVmFycykgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBtYXAgc2l6ZVwiKTtcbiAgICBmb3IgKGxldCBpPTA7IGk8Y2lyLm5WYXJzOyBpKyspIHtcbiAgICAgICAgaWYgKChsb2dnZXIpJiYoaSUxMDAwMCA9PSAwKSkgbG9nZ2VyLmluZm8oYCR7bG9nZ2VyQ3R4fTogd3JpdGluZyBtYXA6ICR7aX0vJHtjaXIublZhcnN9YCk7XG4gICAgICAgIGF3YWl0IGZkLndyaXRlVUxFNjQoY2lyLm1hcFtpXSk7XG4gICAgfVxuXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFdyaXRlU2VjdGlvbihmZCk7XG59XG5cblxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd3JpdGVSMWNzKGZpbGVOYW1lLCBjaXIsIGxvZ2dlciwgbG9nZ2VyQ3R4KSB7XG5cbiAgICBjb25zdCBmZCA9IGF3YWl0IGJpbkZpbGVVdGlscy5jcmVhdGVCaW5GaWxlKGZpbGVOYW1lLCBcInIxY3NcIiwgMSwgMywgMTw8MjUsIDE8PDIyKTtcblxuICAgIGF3YWl0IHdyaXRlUjFjc0hlYWRlcihmZCwgY2lyKTtcblxuICAgIGF3YWl0IHdyaXRlUjFjc0NvbnN0cmFpbnRzKGZkLCBjaXIsIGxvZ2dlciwgbG9nZ2VyQ3R4KTtcblxuICAgIGF3YWl0IHdyaXRlUjFjc01hcChmZCwgY2lyLCBsb2dnZXIsIGxvZ2dlckN0eCk7XG5cbiAgICBhd2FpdCBmZC5jbG9zZSgpO1xufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0IHsgU2NhbGFyIH0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuaW1wb3J0IHsgcmVhZFIxY3MgfSAgZnJvbSBcInIxY3NmaWxlXCI7XG5cbmNvbnN0IGJsczEyMzgxciA9IFNjYWxhci5lKFwiNzNlZGE3NTMyOTlkN2Q0ODMzMzlkODA4MDlhMWQ4MDU1M2JkYTQwMmZmZmU1YmZlZmZmZmZmZmYwMDAwMDAwMVwiLCAxNik7XG5jb25zdCBibjEyOHIgPSBTY2FsYXIuZShcIjIxODg4MjQyODcxODM5Mjc1MjIyMjQ2NDA1NzQ1MjU3Mjc1MDg4NTQ4MzY0NDAwNDE2MDM0MzQzNjk4MjA0MTg2NTc1ODA4NDk1NjE3XCIpO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiByMWNzSW5mbyhyMWNzTmFtZSwgbG9nZ2VyKSB7XG5cbiAgICAvLyBPbmx5IHRoZSBoZWFkZXIgKHNlY3Rpb24gMSkgaXMgbmVlZGVkIGZvciB0aGVzZSBjb3VudHM7IGxvYWRpbmcgdGhlXG4gICAgLy8gY29uc3RyYWludHMgKyB3aXJlLXRvLWxhYmVsIG1hcCB3b3VsZCByZWFkIHRoZSB3aG9sZSAocG90ZW50aWFsbHkgbWFueS1HQilcbiAgICAvLyBmaWxlIGZvciBub3RoaW5nLlxuICAgIGNvbnN0IGNpciA9IGF3YWl0IHJlYWRSMWNzKHIxY3NOYW1lLCB7bG9hZENvbnN0cmFpbnRzOiBmYWxzZSwgbG9hZE1hcDogZmFsc2V9KTtcblxuICAgIGlmIChTY2FsYXIuZXEoY2lyLnByaW1lLCBibjEyOHIpKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiQ3VydmU6IGJuLTEyOFwiKTtcbiAgICB9IGVsc2UgaWYgKFNjYWxhci5lcShjaXIucHJpbWUsIGJsczEyMzgxcikpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJDdXJ2ZTogYmxzMTItMzgxXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGBVbmtub3duIEN1cnZlLiBQcmltZTogJHtTY2FsYXIudG9TdHJpbmcoY2lyLnByaW1lKX1gKTtcbiAgICB9XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oYCMgb2YgV2lyZXM6ICR7Y2lyLm5WYXJzfWApO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGAjIG9mIENvbnN0cmFpbnRzOiAke2Npci5uQ29uc3RyYWludHN9YCk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oYCMgb2YgUHJpdmF0ZSBJbnB1dHM6ICR7Y2lyLm5QcnZJbnB1dHN9YCk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oYCMgb2YgUHVibGljIElucHV0czogJHtjaXIublB1YklucHV0c31gKTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhgIyBvZiBMYWJlbHM6ICR7Y2lyLm5MYWJlbHN9YCk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oYCMgb2YgT3V0cHV0czogJHtjaXIubk91dHB1dHN9YCk7XG5cbiAgICByZXR1cm4gY2lyO1xufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0IHtyZWFkUjFjc30gIGZyb20gXCJyMWNzZmlsZVwiO1xuaW1wb3J0IHsgc3RyaW5naWZ5QmlnSW50c1dpdGhGaWVsZCB9IGZyb20gXCIuL21pc2MuanNcIjtcblxuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiByMWNzRXhwb3J0SnNvbihyMWNzRmlsZU5hbWUsIGxvZ2dlcikge1xuXG4gICAgY29uc3QgY2lyID0gYXdhaXQgcmVhZFIxY3MocjFjc0ZpbGVOYW1lLCB0cnVlLCB0cnVlLCB0cnVlLCBsb2dnZXIpO1xuICAgIGNvbnN0IEZyPWNpci5jdXJ2ZS5GcjtcbiAgICBkZWxldGUgY2lyLmN1cnZlO1xuICAgIGRlbGV0ZSBjaXIuRjtcblxuICAgIHJldHVybiBzdHJpbmdpZnlCaWdJbnRzV2l0aEZpZWxkKEZyLCBjaXIpO1xufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuZXhwb3J0IHtkZWZhdWx0IGFzIHByaW50fSBmcm9tIFwiLi9yMWNzX3ByaW50LmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgaW5mb30gZnJvbSBcIi4vcjFjc19pbmZvLmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgZXhwb3J0SnNvbn0gZnJvbSBcIi4vcjFjc19leHBvcnRfanNvbi5qc1wiO1xuXG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgKiBhcyBmYXN0RmlsZSBmcm9tIFwiZmFzdGZpbGVcIjtcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gbG9hZFN5bWJvbHMoc3ltRmlsZU5hbWUpIHtcbiAgICBjb25zdCBzeW0gPSB7XG4gICAgICAgIGxhYmVsSWR4Mk5hbWU6IFsgXCJvbmVcIiBdLFxuICAgICAgICB2YXJJZHgyTmFtZTogWyBcIm9uZVwiIF0sXG4gICAgICAgIGNvbXBvbmVudElkeDJOYW1lOiBbXVxuICAgIH07XG4gICAgY29uc3QgZmQgPSBhd2FpdCBmYXN0RmlsZS5yZWFkRXhpc3Rpbmcoc3ltRmlsZU5hbWUpO1xuICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZC5yZWFkKGZkLnRvdGFsU2l6ZSk7XG4gICAgY29uc3Qgc3ltc1N0ciA9IG5ldyBUZXh0RGVjb2RlcihcInV0Zi04XCIpLmRlY29kZShidWZmKTtcbiAgICBjb25zdCBsaW5lcyA9IHN5bXNTdHIuc3BsaXQoXCJcXG5cIik7XG4gICAgZm9yIChsZXQgaT0wOyBpPGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGFyciA9IGxpbmVzW2ldLnNwbGl0KFwiLFwiKTtcbiAgICAgICAgaWYgKGFyci5sZW5ndGghPTQpIGNvbnRpbnVlO1xuICAgICAgICBpZiAoc3ltLnZhcklkeDJOYW1lW2FyclsxXV0pIHtcbiAgICAgICAgICAgIHN5bS52YXJJZHgyTmFtZVthcnJbMV1dICs9IFwifFwiICsgYXJyWzNdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc3ltLnZhcklkeDJOYW1lW2FyclsxXV0gPSBhcnJbM107XG4gICAgICAgIH1cbiAgICAgICAgc3ltLmxhYmVsSWR4Mk5hbWVbYXJyWzBdXSA9IGFyclszXTtcbiAgICAgICAgaWYgKCFzeW0uY29tcG9uZW50SWR4Mk5hbWVbYXJyWzJdXSkge1xuICAgICAgICAgICAgc3ltLmNvbXBvbmVudElkeDJOYW1lW2FyclsyXV0gPSBleHRyYWN0Q29tcG9uZW50KGFyclszXSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhd2FpdCBmZC5jbG9zZSgpO1xuXG4gICAgcmV0dXJuIHN5bTtcblxuICAgIGZ1bmN0aW9uIGV4dHJhY3RDb21wb25lbnQobmFtZSkge1xuICAgICAgICBjb25zdCBhcnIgPSBuYW1lLnNwbGl0KFwiLlwiKTtcbiAgICAgICAgYXJyLnBvcCgpOyAvLyBSZW1vdmUgdGhlIGxhc3IgZWxlbWVudFxuICAgICAgICByZXR1cm4gYXJyLmpvaW4oXCIuXCIpO1xuICAgIH1cbn1cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCAqIGFzIGZhc3RGaWxlIGZyb20gXCJmYXN0ZmlsZVwiO1xuaW1wb3J0IHsgV2l0bmVzc0NhbGN1bGF0b3JCdWlsZGVyIH0gZnJvbSBcImNpcmNvbV9ydW50aW1lXCI7XG5pbXBvcnQgKiBhcyB3dG5zVXRpbHMgZnJvbSBcIi4vd3Ruc191dGlscy5qc1wiO1xuaW1wb3J0ICogYXMgYmluRmlsZVV0aWxzIGZyb20gXCJAaWRlbjMvYmluZmlsZXV0aWxzXCI7XG5pbXBvcnQgbG9hZFN5bXMgZnJvbSBcIi4vbG9hZHN5bXMuanNcIjtcbmltcG9ydCB7ICB1dGlscyB9ICAgZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuY29uc3Qge3Vuc3RyaW5naWZ5QmlnSW50c30gPSB1dGlscztcblxuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiB3dG5zRGVidWcoX2lucHV0LCB3YXNtRmlsZU5hbWUsIHd0bnNGaWxlTmFtZSwgc3ltTmFtZSwgb3B0aW9ucywgbG9nZ2VyKSB7XG5cbiAgICBjb25zdCBpbnB1dCA9IHVuc3RyaW5naWZ5QmlnSW50cyhfaW5wdXQpO1xuXG4gICAgY29uc3QgZmRXYXNtID0gYXdhaXQgZmFzdEZpbGUucmVhZEV4aXN0aW5nKHdhc21GaWxlTmFtZSk7XG4gICAgY29uc3Qgd2FzbSA9IGF3YWl0IGZkV2FzbS5yZWFkKGZkV2FzbS50b3RhbFNpemUpO1xuICAgIGF3YWl0IGZkV2FzbS5jbG9zZSgpO1xuXG4gICAgY29uc3Qgd2NPcHMgPSB7Li4ub3B0aW9ucywgc2FuaXR5Q2hlY2s6IHRydWV9O1xuICAgIGxldCBzeW0gPSBhd2FpdCBsb2FkU3ltcyhzeW1OYW1lKTtcbiAgICBpZiAob3B0aW9ucy5zZXQpIHtcbiAgICAgICAgaWYgKCFzeW0pIHN5bSA9IGF3YWl0IGxvYWRTeW1zKHN5bU5hbWUpO1xuICAgICAgICB3Y09wcy5sb2dTZXRTaWduYWw9IGZ1bmN0aW9uKGxhYmVsSWR4LCB2YWx1ZSkge1xuICAgICAgICAgICAgLy8gVGhlIGxpbmUgYmVsb3cgc3BsaXRzIHRoZSBhcnJvdyBsb2cgaW50byAyIHN0cmluZ3MgdG8gYXZvaWQgc29tZSBTZWN1cmUgRUNNQVNjcmlwdCBpc3N1ZXNcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiU0VUIFwiICsgc3ltLmxhYmVsSWR4Mk5hbWVbbGFiZWxJZHhdICsgXCIgPFwiICsgXCItLSBcIiArIHZhbHVlLnRvU3RyaW5nKCkpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5nZXQpIHtcbiAgICAgICAgaWYgKCFzeW0pIHN5bSA9IGF3YWl0IGxvYWRTeW1zKHN5bU5hbWUpO1xuICAgICAgICB3Y09wcy5sb2dHZXRTaWduYWw9IGZ1bmN0aW9uKHZhcklkeCwgdmFsdWUpIHtcbiAgICAgICAgICAgIC8vIFRoZSBsaW5lIGJlbG93IHNwbGl0cyB0aGUgYXJyb3cgbG9nIGludG8gMiBzdHJpbmdzIHRvIGF2b2lkIHNvbWUgU2VjdXJlIEVDTUFTY3JpcHQgaXNzdWVzXG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIkdFVCBcIiArIHN5bS5sYWJlbElkeDJOYW1lW3ZhcklkeF0gKyBcIiAtLVwiICsgXCI+IFwiICsgdmFsdWUudG9TdHJpbmcoKSk7XG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChvcHRpb25zLnRyaWdnZXIpIHtcbiAgICAgICAgaWYgKCFzeW0pIHN5bSA9IGF3YWl0IGxvYWRTeW1zKHN5bU5hbWUpO1xuICAgICAgICB3Y09wcy5sb2dTdGFydENvbXBvbmVudD0gZnVuY3Rpb24oY0lkeCkge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJTVEFSVDogXCIgKyBzeW0uY29tcG9uZW50SWR4Mk5hbWVbY0lkeF0pO1xuICAgICAgICB9O1xuICAgICAgICB3Y09wcy5sb2dGaW5pc2hDb21wb25lbnQ9IGZ1bmN0aW9uKGNJZHgpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiRklOSVNIOiBcIiArIHN5bS5jb21wb25lbnRJZHgyTmFtZVtjSWR4XSk7XG4gICAgICAgIH07XG4gICAgfVxuICAgIHdjT3BzLnN5bSA9IHN5bTtcblxuICAgIGNvbnN0IHdjID0gYXdhaXQgV2l0bmVzc0NhbGN1bGF0b3JCdWlsZGVyKHdhc20sIHdjT3BzKTtcbiAgICBjb25zdCB3ID0gYXdhaXQgd2MuY2FsY3VsYXRlV2l0bmVzcyhpbnB1dCwgdHJ1ZSk7XG5cbiAgICBjb25zdCBmZFd0bnMgPSBhd2FpdCBiaW5GaWxlVXRpbHMuY3JlYXRlQmluRmlsZSh3dG5zRmlsZU5hbWUsIFwid3Ruc1wiLCAyLCAyKTtcblxuICAgIGF3YWl0IHd0bnNVdGlscy53cml0ZShmZFd0bnMsIHcsIHdjLnByaW1lKTtcblxuICAgIGF3YWl0IGZkV3Rucy5jbG9zZSgpO1xufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0IHtyZWFkfSBmcm9tIFwiLi93dG5zX3V0aWxzLmpzXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIHd0bnNFeHBvcnRKc29uKHd0bnNGaWxlTmFtZSkge1xuXG4gICAgY29uc3QgdyA9IGF3YWl0IHJlYWQod3Ruc0ZpbGVOYW1lKTtcblxuICAgIHJldHVybiB3O1xufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0ICogYXMgYmluRmlsZVV0aWxzIGZyb20gXCJAaWRlbjMvYmluZmlsZXV0aWxzXCI7XG5pbXBvcnQgKiBhcyB3dG5zVXRpbHMgZnJvbSBcIi4vd3Ruc191dGlscy5qc1wiO1xuaW1wb3J0IHsgcmVhZFIxY3NGZCB9IGZyb20gXCJyMWNzZmlsZVwiO1xuaW1wb3J0IHsgU2NhbGFyIH0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuaW1wb3J0ICogYXMgY3VydmVzIGZyb20gXCIuL2N1cnZlcy5qc1wiO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiB3dG5zQ2hlY2socjFjc0ZpbGVuYW1lLCB3dG5zRmlsZW5hbWUsIGxvZ2dlcikge1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJXSVRORVNTIENIRUNLSU5HIFNUQVJURURcIik7XG5cbiAgICAvLyBSZWFkIHIxY3MgZmlsZVxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBSZWFkaW5nIHIxY3MgZmlsZVwiKTtcbiAgICBjb25zdCB7XG4gICAgICAgIGZkOiBmZFIxY3MsXG4gICAgICAgIHNlY3Rpb25zOiBzZWN0aW9uc1IxY3NcbiAgICB9ID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRCaW5GaWxlKHIxY3NGaWxlbmFtZSwgXCJyMWNzXCIsIDEsIDEgPDwgMjIsIDEgPDwgMjQpO1xuICAgIGNvbnN0IHIxY3MgPSBhd2FpdCByZWFkUjFjc0ZkKGZkUjFjcywgc2VjdGlvbnNSMWNzLCB7IGxvYWRDb25zdHJhaW50czogZmFsc2UsIGxvYWRDdXN0b21HYXRlczogZmFsc2UgfSk7XG5cbiAgICAvLyBSZWFkIHdpdG5lc3MgZmlsZVxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBSZWFkaW5nIHdpdG5lc3MgZmlsZVwiKTtcbiAgICBjb25zdCB7XG4gICAgICAgIGZkOiBmZFd0bnMsXG4gICAgICAgIHNlY3Rpb25zOiB3dG5zU2VjdGlvbnNcbiAgICB9ID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRCaW5GaWxlKHd0bnNGaWxlbmFtZSwgXCJ3dG5zXCIsIDIsIDEgPDwgMjIsIDEgPDwgMjQpO1xuICAgIGNvbnN0IHd0bnNIZWFkZXIgPSBhd2FpdCB3dG5zVXRpbHMucmVhZEhlYWRlcihmZFd0bnMsIHd0bnNTZWN0aW9ucyk7XG5cbiAgICBpZiAoIVNjYWxhci5lcShyMWNzLnByaW1lLCB3dG5zSGVhZGVyLnEpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkN1cnZlIG9mIHRoZSB3aXRuZXNzIGRvZXMgbm90IG1hdGNoIHRoZSBjdXJ2ZSBvZiB0aGUgcHJvdmluZyBrZXlcIik7XG4gICAgfVxuXG4gICAgY29uc3QgYnVmZldpdG5lc3MgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRXdG5zLCB3dG5zU2VjdGlvbnMsIDIpO1xuICAgIGF3YWl0IGZkV3Rucy5jbG9zZSgpO1xuXG4gICAgY29uc3QgY3VydmUgPSBhd2FpdCBjdXJ2ZXMuZ2V0Q3VydmVGcm9tUihyMWNzLnByaW1lKTtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgIGNvbnN0IHNGciA9IEZyLm44O1xuXG4gICAgY29uc3QgYlIxY3MgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRSMWNzLCBzZWN0aW9uc1IxY3MsIDIpO1xuXG4gICAgaWYgKGxvZ2dlcikge1xuICAgICAgICBsb2dnZXIuaW5mbyhcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIik7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiICBXSVRORVNTIENIRUNLXCIpO1xuICAgICAgICBsb2dnZXIuaW5mbyhgICBDdXJ2ZTogICAgICAgICAgJHtyMWNzLmN1cnZlLm5hbWV9YCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKGAgIFZhcnMgKHdpcmVzKTogICAke3IxY3MublZhcnN9YCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKGAgIE91dHB1dHM6ICAgICAgICAke3IxY3Mubk91dHB1dHN9YCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKGAgIFB1YmxpYyBJbnB1dHM6ICAke3IxY3MublB1YklucHV0c31gKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYCAgUHJpdmF0ZSBJbnB1dHM6ICR7cjFjcy5uUHJ2SW5wdXRzfWApO1xuICAgICAgICBsb2dnZXIuaW5mbyhgICBMYWJlbHM6ICAgICAgICAgJHtyMWNzLm5MYWJlbHN9YCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKGAgIENvbnN0cmFpbnRzOiAgICAke3IxY3MubkNvbnN0cmFpbnRzfWApO1xuICAgICAgICBsb2dnZXIuaW5mbyhgICBDdXN0b20gR2F0ZXM6ICAgJHtyMWNzLnVzZUN1c3RvbUdhdGVzfWApO1xuICAgICAgICBsb2dnZXIuaW5mbyhcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIik7XG4gICAgfVxuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENoZWNraW5nIHdpdG5lc3MgY29ycmVjdG5lc3NcIik7XG5cbiAgICBsZXQgYlIxY3NQb3MgPSAwO1xuICAgIGxldCByZXMgPSB0cnVlO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcjFjcy5uQ29uc3RyYWludHM7IGkrKykge1xuICAgICAgICBpZiAoKGxvZ2dlcikgJiYgKGkgIT09IDApICYmIChpICUgNTAwMDAwID09PSAwKSkge1xuICAgICAgICAgICAgbG9nZ2VyLmluZm8oYMK3wrfCtyBwcm9jZXNzaW5nIHIxY3MgY29uc3RyYWludHMgJHtpfS8ke3IxY3MubkNvbnN0cmFpbnRzfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy9SZWFkIHRoZSB0aHJlZSBsaW5lYXIgY29tYmluYXRpb25zIG9mIHRoZSBjb25zdHJhaW50IHdoZXJlIEEgKiBCIC0gQyA9IDBcbiAgICAgICAgY29uc3QgbGNBID0gcmVhZExDKCk7XG4gICAgICAgIGNvbnN0IGxjQiA9IHJlYWRMQygpO1xuICAgICAgICBjb25zdCBsY0MgPSByZWFkTEMoKTtcblxuICAgICAgICAvLyBFdmFsdWF0ZSB0aGUgbGluZWFyIGNvbWJpbmF0aW9uc1xuICAgICAgICBjb25zdCBldmFsQSA9IEV2YWx1YXRlTGluZWFyQ29tYmluYXRpb24obGNBKTtcbiAgICAgICAgY29uc3QgZXZhbEIgPSBFdmFsdWF0ZUxpbmVhckNvbWJpbmF0aW9uKGxjQik7XG4gICAgICAgIGNvbnN0IGV2YWxDID0gRXZhbHVhdGVMaW5lYXJDb21iaW5hdGlvbihsY0MpO1xuXG4gICAgICAgIC8vIENoZWNrIHRoYXQgQSAqIEIgLSBDID09IDBcbiAgICAgICAgaWYgKCFGci5lcShGci5zdWIoRnIubXVsKGV2YWxBLCBldmFsQiksIGV2YWxDKSwgRnIuemVybykpIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKFwiwrfCt8K3IGFib3J0aW5nIGNoZWNraW5nIHByb2Nlc3MgYXQgY29uc3RyYWludCBcIiArIGkpO1xuICAgICAgICAgICAgcmVzID0gZmFsc2U7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZkUjFjcy5jbG9zZSgpO1xuXG4gICAgaWYgKGxvZ2dlcikge1xuICAgICAgICBpZiAocmVzKSB7XG4gICAgICAgICAgICBsb2dnZXIuaW5mbyhcIldJVE5FU1MgSVMgQ09SUkVDVFwiKTtcbiAgICAgICAgICAgIGxvZ2dlci5pbmZvKFwiV0lUTkVTUyBDSEVDS0lORyBGSU5JU0hFRCBTVUNDRVNTRlVMTFlcIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybihcIldJVE5FU1MgSVMgTk9UIENPUlJFQ1RcIik7XG4gICAgICAgICAgICBsb2dnZXIud2FybihcIldJVE5FU1MgQ0hFQ0tJTkcgRklOSVNIRUQgVU5TVUNDRVNTRlVMTFlcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzO1xuXG4gICAgZnVuY3Rpb24gRXZhbHVhdGVMaW5lYXJDb21iaW5hdGlvbihsYykge1xuICAgICAgICBsZXQgcmVzID0gRnIuemVybztcblxuICAgICAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMobGMpO1xuICAgICAgICBrZXlzLmZvckVhY2goKHNpZ25hbElkKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBzaWduYWxWYWx1ZSA9IGdldFdpdG5lc3NWYWx1ZShzaWduYWxJZCk7XG4gICAgICAgICAgICBjb25zdCBzaWduYWxGYWN0b3IgPSBsY1tzaWduYWxJZF07XG5cbiAgICAgICAgICAgIHJlcyA9IEZyLmFkZChyZXMsIEZyLm11bChzaWduYWxWYWx1ZSwgc2lnbmFsRmFjdG9yKSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVhZExDKCkge1xuICAgICAgICBjb25zdCBsYyA9IHt9O1xuXG4gICAgICAgIGNvbnN0IGJ1ZmZVTDMyID0gYlIxY3Muc2xpY2UoYlIxY3NQb3MsIGJSMWNzUG9zICsgNCk7XG4gICAgICAgIGJSMWNzUG9zICs9IDQ7XG4gICAgICAgIGNvbnN0IGJ1ZmZVTDMyViA9IG5ldyBEYXRhVmlldyhidWZmVUwzMi5idWZmZXIpO1xuICAgICAgICBjb25zdCBuSWR4ID0gYnVmZlVMMzJWLmdldFVpbnQzMigwLCB0cnVlKTtcblxuICAgICAgICBjb25zdCBidWZmID0gYlIxY3Muc2xpY2UoYlIxY3NQb3MsIGJSMWNzUG9zICsgKDQgKyByMWNzLm44KSAqIG5JZHgpO1xuICAgICAgICBiUjFjc1BvcyArPSAoNCArIHIxY3MubjgpICogbklkeDtcbiAgICAgICAgY29uc3QgYnVmZlYgPSBuZXcgRGF0YVZpZXcoYnVmZi5idWZmZXIpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5JZHg7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgaWR4ID0gYnVmZlYuZ2V0VWludDMyKGkgKiAoNCArIHIxY3MubjgpLCB0cnVlKTtcbiAgICAgICAgICAgIGNvbnN0IHZhbCA9IHIxY3MuRi5mcm9tUnByTEUoYnVmZiwgaSAqICg0ICsgcjFjcy5uOCkgKyA0KTtcbiAgICAgICAgICAgIGxjW2lkeF0gPSB2YWw7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGxjO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldFdpdG5lc3NWYWx1ZShzaWduYWxJZCkge1xuICAgICAgICByZXR1cm4gRnIuZnJvbVJwckxFKGJ1ZmZXaXRuZXNzLnNsaWNlKHNpZ25hbElkICogc0ZyLCBzaWduYWxJZCAqIHNGciArIHNGcikpO1xuICAgIH1cbn0iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5leHBvcnQge2RlZmF1bHQgYXMgY2FsY3VsYXRlfSBmcm9tIFwiLi93dG5zX2NhbGN1bGF0ZS5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIGRlYnVnfSBmcm9tIFwiLi93dG5zX2RlYnVnLmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgZXhwb3J0SnNvbn0gZnJvbSBcIi4vd3Ruc19leHBvcnRfanNvbi5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIGNoZWNrfSBmcm9tIFwiLi93dG5zX2NoZWNrLmpzXCI7IiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuY29uc3QgU1VCQVJSQVlfU0laRSA9IDB4NDAwMDA7XG5cbmNvbnN0IEJpZ0FycmF5SGFuZGxlciA9IHtcbiAgICBnZXQ6IGZ1bmN0aW9uKG9iaiwgcHJvcCkge1xuICAgICAgICBpZiAoIWlzTmFOKHByb3ApKSB7XG4gICAgICAgICAgICByZXR1cm4gb2JqLmdldEVsZW1lbnQocHJvcCk7XG4gICAgICAgIH0gZWxzZSByZXR1cm4gb2JqW3Byb3BdO1xuICAgIH0sXG4gICAgc2V0OiBmdW5jdGlvbihvYmosIHByb3AsIHZhbHVlKSB7XG4gICAgICAgIGlmICghaXNOYU4ocHJvcCkpIHtcbiAgICAgICAgICAgIHJldHVybiBvYmouc2V0RWxlbWVudChwcm9wLCB2YWx1ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBvYmpbcHJvcF0gPSB2YWx1ZTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuY2xhc3MgX0JpZ0FycmF5IHtcbiAgICBjb25zdHJ1Y3RvciAoaW5pdFNpemUpIHtcbiAgICAgICAgdGhpcy5sZW5ndGggPSBpbml0U2l6ZSB8fCAwO1xuICAgICAgICB0aGlzLmFyciA9IG5ldyBBcnJheShTVUJBUlJBWV9TSVpFKTtcblxuICAgICAgICBmb3IgKGxldCBpPTA7IGk8aW5pdFNpemU7IGkrPVNVQkFSUkFZX1NJWkUpIHtcbiAgICAgICAgICAgIHRoaXMuYXJyW2kvU1VCQVJSQVlfU0laRV0gPSBuZXcgQXJyYXkoTWF0aC5taW4oU1VCQVJSQVlfU0laRSwgaW5pdFNpemUgLSBpKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIHB1c2ggKCkge1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8YXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB0aGlzLnNldEVsZW1lbnQgKHRoaXMubGVuZ3RoLCBhcmd1bWVudHNbaV0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgc2xpY2UgKGYsIHQpIHtcbiAgICAgICAgY29uc3QgYXJyID0gbmV3IEFycmF5KHQtZik7XG4gICAgICAgIGZvciAobGV0IGk9ZjsgaTwgdDsgaSsrKSBhcnJbaS1mXSA9IHRoaXMuZ2V0RWxlbWVudChpKTtcbiAgICAgICAgcmV0dXJuIGFycjtcbiAgICB9XG4gICAgZ2V0RWxlbWVudChpZHgpIHtcbiAgICAgICAgaWR4ID0gcGFyc2VJbnQoaWR4KTtcbiAgICAgICAgY29uc3QgaWR4MSA9IE1hdGguZmxvb3IoaWR4IC8gU1VCQVJSQVlfU0laRSk7XG4gICAgICAgIGNvbnN0IGlkeDIgPSBpZHggJSBTVUJBUlJBWV9TSVpFO1xuICAgICAgICByZXR1cm4gdGhpcy5hcnJbaWR4MV0gPyB0aGlzLmFycltpZHgxXVtpZHgyXSA6IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgc2V0RWxlbWVudChpZHgsIHZhbHVlKSB7XG4gICAgICAgIGlkeCA9IHBhcnNlSW50KGlkeCk7XG4gICAgICAgIGNvbnN0IGlkeDEgPSBNYXRoLmZsb29yKGlkeCAvIFNVQkFSUkFZX1NJWkUpO1xuICAgICAgICBpZiAoIXRoaXMuYXJyW2lkeDFdKSB7XG4gICAgICAgICAgICB0aGlzLmFycltpZHgxXSA9IG5ldyBBcnJheShTVUJBUlJBWV9TSVpFKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBpZHgyID0gaWR4ICUgU1VCQVJSQVlfU0laRTtcbiAgICAgICAgdGhpcy5hcnJbaWR4MV1baWR4Ml0gPSB2YWx1ZTtcbiAgICAgICAgaWYgKGlkeCA+PSB0aGlzLmxlbmd0aCkgdGhpcy5sZW5ndGggPSBpZHgrMTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGdldEtleXMoKSB7XG4gICAgICAgIGNvbnN0IG5ld0EgPSBuZXcgQmlnQXJyYXkoKTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHRoaXMuYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5hcnJbaV0pIHtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8dGhpcy5hcnJbaV0ubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB0aGlzLmFycltpXVtqXSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgbmV3QS5wdXNoKGkqU1VCQVJSQVlfU0laRStqKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3QTtcbiAgICB9XG59XG5cbmNsYXNzIEJpZ0FycmF5IHtcbiAgICBjb25zdHJ1Y3RvciggaW5pdFNpemUgKSB7XG4gICAgICAgIGNvbnN0IG9iaiA9IG5ldyBfQmlnQXJyYXkoaW5pdFNpemUpO1xuICAgICAgICBjb25zdCBleHRPYmogPSBuZXcgUHJveHkob2JqLCBCaWdBcnJheUhhbmRsZXIpO1xuICAgICAgICByZXR1cm4gZXh0T2JqO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQmlnQXJyYXk7XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQge3JlYWRSMWNzSGVhZGVyfSBmcm9tIFwicjFjc2ZpbGVcIjtcbmltcG9ydCAqIGFzIHV0aWxzIGZyb20gXCIuL3Bvd2Vyc29mdGF1X3V0aWxzLmpzXCI7XG5pbXBvcnQge1xuICAgIHJlYWRCaW5GaWxlLFxuICAgIGNyZWF0ZUJpbkZpbGUsXG4gICAgcmVhZFNlY3Rpb24sXG4gICAgd3JpdGVCaWdJbnQsXG4gICAgc3RhcnRXcml0ZVNlY3Rpb24sXG4gICAgZW5kV3JpdGVTZWN0aW9uLFxufSBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuaW1wb3J0IHsgbG9nMiwgZm9ybWF0SGFzaCB9IGZyb20gXCIuL21pc2MuanNcIjtcbmltcG9ydCB7IFNjYWxhciwgQmlnQnVmZmVyIH0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuaW1wb3J0IHsgYmxha2UyYiB9IGZyb20gXCJAbm9ibGUvaGFzaGVzL2JsYWtlMi5qc1wiO1xuaW1wb3J0IEJpZ0FycmF5IGZyb20gXCIuL2JpZ2FycmF5LmpzXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIG5ld1pLZXkocjFjc05hbWUsIHB0YXVOYW1lLCB6a2V5TmFtZSwgbG9nZ2VyKSB7XG5cbiAgICBjb25zdCBUQVVfRzEgPSAwO1xuICAgIGNvbnN0IFRBVV9HMiA9IDE7XG4gICAgY29uc3QgQUxQSEFUQVVfRzEgPSAyO1xuICAgIGNvbnN0IEJFVEFUQVVfRzEgPSAzO1xuICAgIGNvbnN0IGNzSGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG5cbiAgICBjb25zdCB7ZmQ6IGZkUFRhdSwgc2VjdGlvbnM6IHNlY3Rpb25zUFRhdX0gPSBhd2FpdCByZWFkQmluRmlsZShwdGF1TmFtZSwgXCJwdGF1XCIsIDEsIDE8PDIyLCAxPDwyNCk7XG4gICAgY29uc3Qge2N1cnZlLCBwb3dlcn0gPSBhd2FpdCB1dGlscy5yZWFkUFRhdUhlYWRlcihmZFBUYXUsIHNlY3Rpb25zUFRhdSk7XG4gICAgY29uc3Qge2ZkOiBmZFIxY3MsIHNlY3Rpb25zOiBzZWN0aW9uc1IxY3N9ID0gYXdhaXQgcmVhZEJpbkZpbGUocjFjc05hbWUsIFwicjFjc1wiLCAxLCAxPDwyMiwgMTw8MjQpO1xuICAgIGNvbnN0IHIxY3MgPSBhd2FpdCByZWFkUjFjc0hlYWRlcihmZFIxY3MsIHNlY3Rpb25zUjFjcywgZmFsc2UpO1xuXG4gICAgY29uc3QgZmRaS2V5ID0gYXdhaXQgY3JlYXRlQmluRmlsZSh6a2V5TmFtZSwgXCJ6a2V5XCIsIDEsIDEwLCAxPDwyMiwgMTw8MjQpO1xuXG4gICAgY29uc3Qgc0cxID0gY3VydmUuRzEuRi5uOCoyO1xuICAgIGNvbnN0IHNHMiA9IGN1cnZlLkcyLkYubjgqMjtcblxuICAgIGlmIChyMWNzLnByaW1lICE9IGN1cnZlLnIpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwicjFjcyBjdXJ2ZSBkb2VzIG5vdCBtYXRjaCBwb3dlcnMgb2YgdGF1IGNlcmVtb255IGN1cnZlXCIpO1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuXG4gICAgY29uc3QgY2lyUG93ZXIgPSBsb2cyKHIxY3MubkNvbnN0cmFpbnRzICsgcjFjcy5uUHViSW5wdXRzICsgcjFjcy5uT3V0cHV0cyArMSAtMSkgKzE7XG5cbiAgICBpZiAoY2lyUG93ZXIgPiBwb3dlcikge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYGNpcmN1aXQgdG9vIGJpZyBmb3IgdGhpcyBwb3dlciBvZiB0YXUgY2VyZW1vbnkuICR7cjFjcy5uQ29uc3RyYWludHN9KjIgPiAyKioke3Bvd2VyfWApO1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuXG4gICAgaWYgKCFzZWN0aW9uc1BUYXVbMTJdKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIlBvd2VycyBvZiB0YXUgaXMgbm90IHByZXBhcmVkLlwiKTtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cblxuICAgIGNvbnN0IG5QdWJsaWMgPSByMWNzLm5PdXRwdXRzICsgcjFjcy5uUHViSW5wdXRzO1xuICAgIGNvbnN0IGRvbWFpblNpemUgPSAyICoqIGNpclBvd2VyO1xuXG4gICAgLy8gV3JpdGUgdGhlIGhlYWRlclxuICAgIC8vLy8vLy8vLy8vXG4gICAgYXdhaXQgc3RhcnRXcml0ZVNlY3Rpb24oZmRaS2V5LCAxKTtcbiAgICBhd2FpdCBmZFpLZXkud3JpdGVVTEUzMigxKTsgLy8gR3JvdGhcbiAgICBhd2FpdCBlbmRXcml0ZVNlY3Rpb24oZmRaS2V5KTtcblxuICAgIC8vIFdyaXRlIHRoZSBHcm90aCBoZWFkZXIgc2VjdGlvblxuICAgIC8vLy8vLy8vLy8vXG5cbiAgICBhd2FpdCBzdGFydFdyaXRlU2VjdGlvbihmZFpLZXksIDIpO1xuICAgIGNvbnN0IHByaW1lUSA9IGN1cnZlLnE7XG4gICAgY29uc3QgbjhxID0gKE1hdGguZmxvb3IoIChTY2FsYXIuYml0TGVuZ3RoKHByaW1lUSkgLSAxKSAvIDY0KSArMSkqODtcblxuICAgIGNvbnN0IHByaW1lUiA9IGN1cnZlLnI7XG4gICAgY29uc3QgbjhyID0gKE1hdGguZmxvb3IoIChTY2FsYXIuYml0TGVuZ3RoKHByaW1lUikgLSAxKSAvIDY0KSArMSkqODtcbiAgICBjb25zdCBSciA9IFNjYWxhci5tb2QoU2NhbGFyLnNobCgxLCBuOHIqOCksIHByaW1lUik7XG4gICAgY29uc3QgUjJyID0gY3VydmUuRnIuZShTY2FsYXIubW9kKFNjYWxhci5tdWwoUnIsUnIpLCBwcmltZVIpKTtcblxuICAgIGF3YWl0IGZkWktleS53cml0ZVVMRTMyKG44cSk7XG4gICAgYXdhaXQgd3JpdGVCaWdJbnQoZmRaS2V5LCBwcmltZVEsIG44cSk7XG4gICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIobjhyKTtcbiAgICBhd2FpdCB3cml0ZUJpZ0ludChmZFpLZXksIHByaW1lUiwgbjhyKTtcbiAgICBhd2FpdCBmZFpLZXkud3JpdGVVTEUzMihyMWNzLm5WYXJzKTsgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVG90YWwgbnVtYmVyIG9mIGJhcnNcbiAgICBhd2FpdCBmZFpLZXkud3JpdGVVTEUzMihuUHVibGljKTsgICAgICAgICAgICAgICAgICAgICAgIC8vIFRvdGFsIG51bWJlciBvZiBwdWJsaWMgdmFycyAobm90IGluY2x1ZGluZyBPTkUpXG4gICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIoZG9tYWluU2l6ZSk7ICAgICAgICAgICAgICAgICAgLy8gZG9tYWluU2l6ZVxuXG4gICAgbGV0IGJBbHBoYTE7XG4gICAgYkFscGhhMSA9IGF3YWl0IGZkUFRhdS5yZWFkKHNHMSwgc2VjdGlvbnNQVGF1WzRdWzBdLnApO1xuICAgIGF3YWl0IGZkWktleS53cml0ZShiQWxwaGExKTtcbiAgICBiQWxwaGExID0gYXdhaXQgY3VydmUuRzEuYmF0Y2hMRU10b1UoYkFscGhhMSk7XG4gICAgY3NIYXNoZXIudXBkYXRlKGJBbHBoYTEpO1xuXG4gICAgbGV0IGJCZXRhMTtcbiAgICBiQmV0YTEgPSBhd2FpdCBmZFBUYXUucmVhZChzRzEsIHNlY3Rpb25zUFRhdVs1XVswXS5wKTtcbiAgICBhd2FpdCBmZFpLZXkud3JpdGUoYkJldGExKTtcbiAgICBiQmV0YTEgPSBhd2FpdCBjdXJ2ZS5HMS5iYXRjaExFTXRvVShiQmV0YTEpO1xuICAgIGNzSGFzaGVyLnVwZGF0ZShiQmV0YTEpO1xuXG4gICAgbGV0IGJCZXRhMjtcbiAgICBiQmV0YTIgPSBhd2FpdCBmZFBUYXUucmVhZChzRzIsIHNlY3Rpb25zUFRhdVs2XVswXS5wKTtcbiAgICBhd2FpdCBmZFpLZXkud3JpdGUoYkJldGEyKTtcbiAgICBiQmV0YTIgPSBhd2FpdCBjdXJ2ZS5HMi5iYXRjaExFTXRvVShiQmV0YTIpO1xuICAgIGNzSGFzaGVyLnVwZGF0ZShiQmV0YTIpO1xuXG4gICAgY29uc3QgYmcxID0gbmV3IFVpbnQ4QXJyYXkoc0cxKTtcbiAgICBjdXJ2ZS5HMS50b1JwckxFTShiZzEsIDAsIGN1cnZlLkcxLmcpO1xuICAgIGNvbnN0IGJnMiA9IG5ldyBVaW50OEFycmF5KHNHMik7XG4gICAgY3VydmUuRzIudG9ScHJMRU0oYmcyLCAwLCBjdXJ2ZS5HMi5nKTtcbiAgICBjb25zdCBiZzFVID0gbmV3IFVpbnQ4QXJyYXkoc0cxKTtcbiAgICBjdXJ2ZS5HMS50b1JwclVuY29tcHJlc3NlZChiZzFVLCAwLCBjdXJ2ZS5HMS5nKTtcbiAgICBjb25zdCBiZzJVID0gbmV3IFVpbnQ4QXJyYXkoc0cyKTtcbiAgICBjdXJ2ZS5HMi50b1JwclVuY29tcHJlc3NlZChiZzJVLCAwLCBjdXJ2ZS5HMi5nKTtcblxuICAgIGF3YWl0IGZkWktleS53cml0ZShiZzIpOyAgICAgICAgLy8gZ2FtbWEyXG4gICAgYXdhaXQgZmRaS2V5LndyaXRlKGJnMSk7ICAgICAgICAvLyBkZWx0YTFcbiAgICBhd2FpdCBmZFpLZXkud3JpdGUoYmcyKTsgICAgICAgIC8vIGRlbHRhMlxuICAgIGNzSGFzaGVyLnVwZGF0ZShiZzJVKTsgICAgICAvLyBnYW1tYTJcbiAgICBjc0hhc2hlci51cGRhdGUoYmcxVSk7ICAgICAgLy8gZGVsdGExXG4gICAgY3NIYXNoZXIudXBkYXRlKGJnMlUpOyAgICAgIC8vIGRlbHRhMlxuICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWVtVXNhZ2UoKSk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJSZWFkaW5nIHIxY3NcIik7XG4gICAgbGV0IHNSMWNzID0gYXdhaXQgcmVhZFNlY3Rpb24oZmRSMWNzLCBzZWN0aW9uc1IxY3MsIDIpO1xuICAgIGF3YWl0IGZkUjFjcy5jbG9zZSgpO1xuXG4gICAgbGV0IEEgPSBuZXcgQmlnQXJyYXkocjFjcy5uVmFycyk7XG4gICAgbGV0IEIxID0gbmV3IEJpZ0FycmF5KHIxY3MublZhcnMpO1xuICAgIGxldCBCMiA9IG5ldyBCaWdBcnJheShyMWNzLm5WYXJzKTtcbiAgICBsZXQgQyA9IG5ldyBCaWdBcnJheShyMWNzLm5WYXJzLSBuUHVibGljIC0xKTtcbiAgICBsZXQgSUMgPSBuZXcgQXJyYXkoblB1YmxpYysxKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1lbVVzYWdlKCkpO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiUmVhZGluZyB0YXVHMVwiKTtcbiAgICBsZXQgc1RhdUcxID0gYXdhaXQgcmVhZFNlY3Rpb24oZmRQVGF1LCBzZWN0aW9uc1BUYXUsIDEyLCAoZG9tYWluU2l6ZSAtMSkqc0cxLCBkb21haW5TaXplKnNHMSk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJSZWFkaW5nIHRhdUcyXCIpO1xuICAgIGxldCBzVGF1RzIgPSBhd2FpdCByZWFkU2VjdGlvbihmZFBUYXUsIHNlY3Rpb25zUFRhdSwgMTMsIChkb21haW5TaXplIC0xKSpzRzIsIGRvbWFpblNpemUqc0cyKTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIlJlYWRpbmcgYWxwaGF0YXVHMVwiKTtcbiAgICBsZXQgc0FscGhhVGF1RzEgPSBhd2FpdCByZWFkU2VjdGlvbihmZFBUYXUsIHNlY3Rpb25zUFRhdSwgMTQsIChkb21haW5TaXplIC0xKSpzRzEsIGRvbWFpblNpemUqc0cxKTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIlJlYWRpbmcgYmV0YXRhdUcxXCIpO1xuICAgIGxldCBzQmV0YVRhdUcxID0gYXdhaXQgcmVhZFNlY3Rpb24oZmRQVGF1LCBzZWN0aW9uc1BUYXUsIDE1LCAoZG9tYWluU2l6ZSAtMSkqc0cxLCBkb21haW5TaXplKnNHMSk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhtZW1Vc2FnZSgpKTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcInByb2Nlc3NDb25zdHJhaW50c1wiKTtcbiAgICBhd2FpdCBwcm9jZXNzQ29uc3RyYWludHMoKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1lbVVzYWdlKCkpO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiY29tcG9zZUFuZFdyaXRlUG9pbnRzXCIpO1xuICAgIGF3YWl0IGNvbXBvc2VBbmRXcml0ZVBvaW50cygzLCBcIkcxXCIsIElDLCBcIklDXCIpO1xuXG4gICAgSUMgPSBudWxsO1xuICAgIC8vIGNvbnN0IGdjID0gcnVuSW5OZXdDb250ZXh0KFwiZ2NcIik7IC8vIG5vY29tbWl0XG4gICAgLy8gZ2MoKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1lbVVzYWdlKCkpO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwid3JpdGVIc1wiKTtcbiAgICBhd2FpdCB3cml0ZUhzKCk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhtZW1Vc2FnZSgpKTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcImhhc2hIUG9pbnRzXCIpO1xuICAgIGF3YWl0IGhhc2hIUG9pbnRzKCk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhtZW1Vc2FnZSgpKTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcImNvbXBvc2VBbmRXcml0ZVBvaW50cyA4IEcxIENcIik7XG4gICAgYXdhaXQgY29tcG9zZUFuZFdyaXRlUG9pbnRzKDgsIFwiRzFcIiwgQywgXCJDXCIpO1xuXG4gICAgQyA9IG51bGw7XG4gICAgLy8gZ2MoKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1lbVVzYWdlKCkpO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiY29tcG9zZUFuZFdyaXRlUG9pbnRzIDUgRzEgQVwiKTtcbiAgICBhd2FpdCBjb21wb3NlQW5kV3JpdGVQb2ludHMoNSwgXCJHMVwiLCBBLCBcIkFcIik7XG5cbiAgICBBID0gbnVsbDtcbiAgICAvLyBnYygpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWVtVXNhZ2UoKSk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJjb21wb3NlQW5kV3JpdGVQb2ludHMgNiBHMSBCMVwiKTtcbiAgICBhd2FpdCBjb21wb3NlQW5kV3JpdGVQb2ludHMoNiwgXCJHMVwiLCBCMSwgXCJCMVwiKTtcblxuICAgIEIxID0gbnVsbDtcbiAgICAvLyBnYygpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWVtVXNhZ2UoKSk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJjb21wb3NlQW5kV3JpdGVQb2ludHMgNyBHMiBCMlwiKTtcbiAgICBhd2FpdCBjb21wb3NlQW5kV3JpdGVQb2ludHMoNywgXCJHMlwiLCBCMiwgXCJCMlwiKTtcblxuICAgIEIyID0gbnVsbDtcbiAgICAvLyBnYygpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWVtVXNhZ2UoKSk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJDb250cmlidXRpb25zIHNlY3Rpb25cIik7XG4gICAgY29uc3QgY3NIYXNoID0gY3NIYXNoZXIuZGlnZXN0KCk7XG4gICAgLy8gQ29udHJpYnV0aW9ucyBzZWN0aW9uXG4gICAgYXdhaXQgc3RhcnRXcml0ZVNlY3Rpb24oZmRaS2V5LCAxMCk7XG4gICAgYXdhaXQgZmRaS2V5LndyaXRlKGNzSGFzaCk7XG4gICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIoMCk7XG4gICAgYXdhaXQgZW5kV3JpdGVTZWN0aW9uKGZkWktleSk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhmb3JtYXRIYXNoKGNzSGFzaCwgXCJDaXJjdWl0IGhhc2g6IFwiKSk7XG5cblxuICAgIGF3YWl0IGZkWktleS5jbG9zZSgpO1xuICAgIGF3YWl0IGZkUFRhdS5jbG9zZSgpO1xuXG4gICAgcmV0dXJuIGNzSGFzaDtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlSHMoKSB7XG4gICAgICAgIGF3YWl0IHN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleSwgOSk7XG4gICAgICAgIGNvbnN0IGJ1ZmZPdXQgPSBuZXcgQmlnQnVmZmVyKGRvbWFpblNpemUqc0cxKTtcbiAgICAgICAgaWYgKGNpclBvd2VyIDwgY3VydmUuRnIucykge1xuICAgICAgICAgICAgbGV0IHNUYXVHMSA9IGF3YWl0IHJlYWRTZWN0aW9uKGZkUFRhdSwgc2VjdGlvbnNQVGF1LCAxMiwgKGRvbWFpblNpemUqMi0xKSpzRzEsIGRvbWFpblNpemUqMipzRzEpO1xuICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpPCBkb21haW5TaXplOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAoKGxvZ2dlcikmJihpJTEwMDAwID09IDApKSBsb2dnZXIuZGVidWcoYHNwbGl0dGluZyBidWZmZXI6ICR7aX0vJHtkb21haW5TaXplfWApO1xuICAgICAgICAgICAgICAgIGNvbnN0IGJ1ZmYgPSBzVGF1RzEuc2xpY2UoIChpKjIrMSkqc0cxLCAoaSoyKzEpKnNHMSArIHNHMSApO1xuICAgICAgICAgICAgICAgIGJ1ZmZPdXQuc2V0KGJ1ZmYsIGkqc0cxKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChjaXJQb3dlciA9PSBjdXJ2ZS5Gci5zKSB7XG4gICAgICAgICAgICBjb25zdCBvID0gc2VjdGlvbnNQVGF1WzEyXVswXS5wICsgKCgyICoqIChjaXJQb3dlcisxKSkgLTEpKnNHMTtcbiAgICAgICAgICAgIGF3YWl0IGZkUFRhdS5yZWFkVG9CdWZmZXIoYnVmZk91dCwgMCwgZG9tYWluU2l6ZSpzRzEsIG8gKyBkb21haW5TaXplKnNHMSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJDaXJjdWl0IHRvbyBiaWdcIik7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDaXJjdWl0IHRvbyBiaWcgZm9yIHRoaXMgY3VydmVcIik7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKGJ1ZmZPdXQpO1xuICAgICAgICBhd2FpdCBlbmRXcml0ZVNlY3Rpb24oZmRaS2V5KTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiBwcm9jZXNzQ29uc3RyYWludHMoKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmZDb2VmZiA9IG5ldyBVaW50OEFycmF5KDEyICsgY3VydmUuRnIubjgpO1xuICAgICAgICBjb25zdCBidWZmQ29lZmZWID0gbmV3IERhdGFWaWV3KGJ1ZmZDb2VmZi5idWZmZXIpO1xuICAgICAgICBjb25zdCBiT25lID0gbmV3IFVpbnQ4QXJyYXkoY3VydmUuRnIubjgpO1xuICAgICAgICBjdXJ2ZS5Gci50b1JwckxFKGJPbmUsIDAsIGN1cnZlLkZyLmUoMSkpO1xuXG4gICAgICAgIGxldCByMWNzUG9zID0gMDtcblxuICAgICAgICBmdW5jdGlvbiByMWNzX3JlYWRVTEUzMigpIHtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmYgPSBzUjFjcy5zbGljZShyMWNzUG9zLCByMWNzUG9zKzQpO1xuICAgICAgICAgICAgcjFjc1BvcyArPSA0O1xuICAgICAgICAgICAgY29uc3QgYnVmZlYgPSBuZXcgRGF0YVZpZXcoYnVmZi5idWZmZXIpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1ZmZWLmdldFVpbnQzMigwLCB0cnVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNvZWZzID0gbmV3IEJpZ0FycmF5KCk7XG4gICAgICAgIGZvciAobGV0IGM9MDsgYzxyMWNzLm5Db25zdHJhaW50czsgYysrKSB7XG4gICAgICAgICAgICBpZiAoKGxvZ2dlcikmJihjJTEwMDAwID09IDApKSBsb2dnZXIuZGVidWcoYHByb2Nlc3NpbmcgY29uc3RyYWludHM6ICR7Y30vJHtyMWNzLm5Db25zdHJhaW50c31gKTtcbiAgICAgICAgICAgIGNvbnN0IG5BID0gcjFjc19yZWFkVUxFMzIoKTtcbiAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaTxuQTsgaSsrKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcyA9IHIxY3NfcmVhZFVMRTMyKCk7XG4gICAgICAgICAgICAgICAgY29uc3QgY29lZnAgPSByMWNzUG9zO1xuICAgICAgICAgICAgICAgIHIxY3NQb3MgKz0gY3VydmUuRnIubjg7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBsMXQgPSBUQVVfRzE7XG4gICAgICAgICAgICAgICAgY29uc3QgbDEgPSBzRzEqYztcbiAgICAgICAgICAgICAgICBjb25zdCBsMnQgPSBCRVRBVEFVX0cxO1xuICAgICAgICAgICAgICAgIGNvbnN0IGwyID0gc0cxKmM7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBBW3NdID09PSBcInVuZGVmaW5lZFwiKSBBW3NdID0gW107XG4gICAgICAgICAgICAgICAgQVtzXS5wdXNoKFtsMXQsIGwxLCBjb2VmcF0pO1xuXG4gICAgICAgICAgICAgICAgaWYgKHMgPD0gblB1YmxpYykge1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIElDW3NdID09PSBcInVuZGVmaW5lZFwiKSBJQ1tzXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICBJQ1tzXS5wdXNoKFtsMnQsIGwyLCBjb2VmcF0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgQ1tzLSBuUHVibGljIC0xXSA9PT0gXCJ1bmRlZmluZWRcIikgQ1tzLSBuUHVibGljIC0xXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICBDW3MgLSBuUHVibGljIC0xXS5wdXNoKFtsMnQsIGwyLCBjb2VmcF0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb2Vmcy5wdXNoKFswLCBjLCBzLCBjb2VmcF0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBuQiA9IHIxY3NfcmVhZFVMRTMyKCk7XG4gICAgICAgICAgICBmb3IgKGxldCBpPTA7IGk8bkI7IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IHMgPSByMWNzX3JlYWRVTEUzMigpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGNvZWZwID0gcjFjc1BvcztcbiAgICAgICAgICAgICAgICByMWNzUG9zICs9IGN1cnZlLkZyLm44O1xuXG4gICAgICAgICAgICAgICAgY29uc3QgbDF0ID0gVEFVX0cxO1xuICAgICAgICAgICAgICAgIGNvbnN0IGwxID0gc0cxKmM7XG4gICAgICAgICAgICAgICAgY29uc3QgbDJ0ID0gVEFVX0cyO1xuICAgICAgICAgICAgICAgIGNvbnN0IGwyID0gc0cyKmM7XG4gICAgICAgICAgICAgICAgY29uc3QgbDN0ID0gQUxQSEFUQVVfRzE7XG4gICAgICAgICAgICAgICAgY29uc3QgbDMgPSBzRzEqYztcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIEIxW3NdID09PSBcInVuZGVmaW5lZFwiKSBCMVtzXSA9IFtdO1xuICAgICAgICAgICAgICAgIEIxW3NdLnB1c2goW2wxdCwgbDEsIGNvZWZwXSk7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBCMltzXSA9PT0gXCJ1bmRlZmluZWRcIikgQjJbc10gPSBbXTtcbiAgICAgICAgICAgICAgICBCMltzXS5wdXNoKFtsMnQsIGwyLCBjb2VmcF0pO1xuXG4gICAgICAgICAgICAgICAgaWYgKHMgPD0gblB1YmxpYykge1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIElDW3NdID09PSBcInVuZGVmaW5lZFwiKSBJQ1tzXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICBJQ1tzXS5wdXNoKFtsM3QsIGwzLCBjb2VmcF0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgQ1tzLSBuUHVibGljIC0xXSA9PT0gXCJ1bmRlZmluZWRcIikgQ1tzLSBuUHVibGljIC0xXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICBDW3MtIG5QdWJsaWMgLTFdLnB1c2goW2wzdCwgbDMsIGNvZWZwXSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29lZnMucHVzaChbMSwgYywgcywgY29lZnBdKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbkMgPSByMWNzX3JlYWRVTEUzMigpO1xuICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpPG5DOyBpKyspIHtcbiAgICAgICAgICAgICAgICBjb25zdCBzID0gcjFjc19yZWFkVUxFMzIoKTtcbiAgICAgICAgICAgICAgICBjb25zdCBjb2VmcCA9IHIxY3NQb3M7XG4gICAgICAgICAgICAgICAgcjFjc1BvcyArPSBjdXJ2ZS5Gci5uODtcblxuICAgICAgICAgICAgICAgIGNvbnN0IGwxdCA9IFRBVV9HMTtcbiAgICAgICAgICAgICAgICBjb25zdCBsMSA9IHNHMSpjO1xuICAgICAgICAgICAgICAgIGlmIChzIDw9IG5QdWJsaWMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBJQ1tzXSA9PT0gXCJ1bmRlZmluZWRcIikgSUNbc10gPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgSUNbc10ucHVzaChbbDF0LCBsMSwgY29lZnBdKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIENbcy0gblB1YmxpYyAtMV0gPT09IFwidW5kZWZpbmVkXCIpIENbcy0gblB1YmxpYyAtMV0gPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgQ1tzLSBuUHVibGljIC0xXS5wdXNoKFtsMXQsIGwxLCBjb2VmcF0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAobGV0IHMgPSAwOyBzIDw9IG5QdWJsaWMgOyBzKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGwxdCA9IFRBVV9HMTtcbiAgICAgICAgICAgIGNvbnN0IGwxID0gc0cxKihyMWNzLm5Db25zdHJhaW50cyArIHMpO1xuICAgICAgICAgICAgY29uc3QgbDJ0ID0gQkVUQVRBVV9HMTtcbiAgICAgICAgICAgIGNvbnN0IGwyID0gc0cxKihyMWNzLm5Db25zdHJhaW50cyArIHMpO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBBW3NdID09PSBcInVuZGVmaW5lZFwiKSBBW3NdID0gW107XG4gICAgICAgICAgICBBW3NdLnB1c2goW2wxdCwgbDEsIC0xXSk7XG4gICAgICAgICAgICBpZiAodHlwZW9mIElDW3NdID09PSBcInVuZGVmaW5lZFwiKSBJQ1tzXSA9IFtdO1xuICAgICAgICAgICAgSUNbc10ucHVzaChbbDJ0LCBsMiwgLTFdKTtcbiAgICAgICAgICAgIGNvZWZzLnB1c2goWzAsIHIxY3MubkNvbnN0cmFpbnRzICsgcywgcywgLTFdKTtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgYXdhaXQgc3RhcnRXcml0ZVNlY3Rpb24oZmRaS2V5LCA0KTtcblxuICAgICAgICBjb25zdCBidWZmU2VjdGlvbiA9IG5ldyBCaWdCdWZmZXIoY29lZnMubGVuZ3RoKigxMitjdXJ2ZS5Gci5uOCkgKyA0KTtcblxuICAgICAgICBjb25zdCBidWZmNCA9IG5ldyBVaW50OEFycmF5KDQpO1xuICAgICAgICBjb25zdCBidWZmNFYgPSBuZXcgRGF0YVZpZXcoYnVmZjQuYnVmZmVyKTtcbiAgICAgICAgYnVmZjRWLnNldFVpbnQzMigwLCBjb2Vmcy5sZW5ndGgsIHRydWUpO1xuICAgICAgICBidWZmU2VjdGlvbi5zZXQoYnVmZjQpO1xuICAgICAgICBsZXQgY29lZnNQb3MgPSA0O1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8Y29lZnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmICgobG9nZ2VyKSYmKGklMTAwMDAwID09IDApKSBsb2dnZXIuZGVidWcoYHdyaXRpbmcgY29lZmZzOiAke2l9LyR7Y29lZnMubGVuZ3RofWApO1xuICAgICAgICAgICAgd3JpdGVDb2VmKGNvZWZzW2ldKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZShidWZmU2VjdGlvbik7XG4gICAgICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuXG4gICAgICAgIGZ1bmN0aW9uIHdyaXRlQ29lZihjKSB7XG4gICAgICAgICAgICBidWZmQ29lZmZWLnNldFVpbnQzMigwLCBjWzBdLCB0cnVlKTtcbiAgICAgICAgICAgIGJ1ZmZDb2VmZlYuc2V0VWludDMyKDQsIGNbMV0sIHRydWUpO1xuICAgICAgICAgICAgYnVmZkNvZWZmVi5zZXRVaW50MzIoOCwgY1syXSwgdHJ1ZSk7XG4gICAgICAgICAgICBsZXQgbjtcbiAgICAgICAgICAgIGlmIChjWzNdPj0wKSB7XG4gICAgICAgICAgICAgICAgbiA9IGN1cnZlLkZyLmZyb21ScHJMRShzUjFjcy5zbGljZShjWzNdLCBjWzNdICsgY3VydmUuRnIubjgpLCAwKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbiA9IGN1cnZlLkZyLmZyb21ScHJMRShiT25lLCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IG5SMiA9IGN1cnZlLkZyLm11bChuLCBSMnIpO1xuICAgICAgICAgICAgY3VydmUuRnIudG9ScHJMRShidWZmQ29lZmYsIDEyLCBuUjIpO1xuICAgICAgICAgICAgYnVmZlNlY3Rpb24uc2V0KGJ1ZmZDb2VmZiwgY29lZnNQb3MpO1xuICAgICAgICAgICAgY29lZnNQb3MgKz0gYnVmZkNvZWZmLmxlbmd0aDtcbiAgICAgICAgfVxuXG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gY29tcG9zZUFuZFdyaXRlUG9pbnRzKGlkU2VjdGlvbiwgZ3JvdXBOYW1lLCBhcnIsIHNlY3Rpb25OYW1lKSB7XG4gICAgICAgIGNvbnN0IENIVU5LX1NJWkU9IDE8PDE1O1xuICAgICAgICBjb25zdCBHID0gY3VydmVbZ3JvdXBOYW1lXTtcblxuICAgICAgICBoYXNoVTMyKGFyci5sZW5ndGgpO1xuICAgICAgICBhd2FpdCBzdGFydFdyaXRlU2VjdGlvbihmZFpLZXksIGlkU2VjdGlvbik7XG5cbiAgICAgICAgbGV0IG9wUHJvbWlzZXMgPSBbXTtcblxuICAgICAgICBsZXQgaT0wO1xuICAgICAgICB3aGlsZSAoaTxhcnIubGVuZ3RoKSB7XG5cbiAgICAgICAgICAgIGxldCB0PTA7XG4gICAgICAgICAgICB3aGlsZSAoKGk8YXJyLmxlbmd0aCkmJih0PGN1cnZlLnRtLmNvbmN1cnJlbmN5KSkge1xuICAgICAgICAgICAgICAgIGlmIChsb2dnZXIpICBsb2dnZXIuZGVidWcoYFdyaXRpbmcgcG9pbnRzIHN0YXJ0ICR7c2VjdGlvbk5hbWV9OiAke2l9LyR7YXJyLmxlbmd0aH1gKTtcbiAgICAgICAgICAgICAgICBsZXQgbiA9IDE7XG4gICAgICAgICAgICAgICAgbGV0IG5QID0gKGFycltpXSA/IGFycltpXS5sZW5ndGggOiAwKTtcbiAgICAgICAgICAgICAgICB3aGlsZSAoKGkgKyBuIDwgYXJyLmxlbmd0aCkgJiYgKG5QICsgKGFycltpK25dID8gYXJyW2krbl0ubGVuZ3RoIDogMCkgPCBDSFVOS19TSVpFKSAmJiAobjxDSFVOS19TSVpFKSkge1xuICAgICAgICAgICAgICAgICAgICBuUCArPSAoYXJyW2krbl0gPyBhcnJbaStuXS5sZW5ndGggOiAwKTtcbiAgICAgICAgICAgICAgICAgICAgbiArKztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcImJlZm9yZSBzbGljZTpcIik7XG4gICAgICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWVtVXNhZ2UoKSk7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3ViQXJyID0gYXJyLnNsaWNlKGksIGkgKyBuKTtcbiAgICAgICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcImFmdGVyIHNsaWNlOlwiKTtcbiAgICAgICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhtZW1Vc2FnZSgpKTtcbiAgICAgICAgICAgICAgICBjb25zdCBfaSA9IGk7XG4gICAgICAgICAgICAgICAgb3BQcm9taXNlcy5wdXNoKGNvbXBvc2VBbmRXcml0ZVBvaW50c1RocmVhZChncm91cE5hbWUsIHN1YkFyciwgbG9nZ2VyLCBzZWN0aW9uTmFtZSkudGhlbiggKHIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGxvZ2dlcikgIGxvZ2dlci5kZWJ1ZyhgV3JpdGluZyBwb2ludHMgZW5kICR7c2VjdGlvbk5hbWV9OiAke19pfS8ke2Fyci5sZW5ndGh9YCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByO1xuICAgICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgICAgICBpICs9IG47XG4gICAgICAgICAgICAgICAgdCsrO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBQcm9taXNlLmFsbChvcFByb21pc2VzKTtcblxuICAgICAgICAgICAgZm9yIChsZXQgaz0wOyBrPHJlc3VsdC5sZW5ndGg7IGsrKykge1xuICAgICAgICAgICAgICAgIGF3YWl0IGZkWktleS53cml0ZShyZXN1bHRba11bMF0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBHLmJhdGNoTEVNdG9VKHJlc3VsdFtrXVswXSk7XG4gICAgICAgICAgICAgICAgY3NIYXNoZXIudXBkYXRlKGJ1ZmYpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgb3BQcm9taXNlcyA9IFtdO1xuXG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgZW5kV3JpdGVTZWN0aW9uKGZkWktleSk7XG5cbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiBjb21wb3NlQW5kV3JpdGVQb2ludHNUaHJlYWQoZ3JvdXBOYW1lLCBhcnIsIGxvZ2dlciwgc2VjdGlvbk5hbWUpIHtcbiAgICAgICAgY29uc3QgRyA9IGN1cnZlW2dyb3VwTmFtZV07XG4gICAgICAgIGNvbnN0IHNHaW4gPSBHLkYubjgqMjtcbiAgICAgICAgY29uc3Qgc0dtaWQgPSBHLkYubjgqMztcbiAgICAgICAgY29uc3Qgc0dvdXQgPSBHLkYubjgqMjtcbiAgICAgICAgbGV0IGZuRXhwLCBmbk11bHRpRXhwLCBmbkJhdGNoVG9BZmZpbmUsIGZuWmVybztcbiAgICAgICAgaWYgKGdyb3VwTmFtZSA9PSBcIkcxXCIpIHtcbiAgICAgICAgICAgIGZuRXhwID0gXCJnMW1fdGltZXNTY2FsYXJBZmZpbmVcIjtcbiAgICAgICAgICAgIGZuTXVsdGlFeHAgPSBcImcxbV9tdWx0aWV4cEFmZmluZVwiO1xuICAgICAgICAgICAgZm5CYXRjaFRvQWZmaW5lID0gXCJnMW1fYmF0Y2hUb0FmZmluZVwiO1xuICAgICAgICAgICAgZm5aZXJvID0gXCJnMW1femVyb1wiO1xuICAgICAgICB9IGVsc2UgaWYgKGdyb3VwTmFtZSA9PSBcIkcyXCIpIHtcbiAgICAgICAgICAgIGZuRXhwID0gXCJnMm1fdGltZXNTY2FsYXJBZmZpbmVcIjtcbiAgICAgICAgICAgIGZuTXVsdGlFeHAgPSBcImcybV9tdWx0aWV4cEFmZmluZVwiO1xuICAgICAgICAgICAgZm5CYXRjaFRvQWZmaW5lID0gXCJnMm1fYmF0Y2hUb0FmZmluZVwiO1xuICAgICAgICAgICAgZm5aZXJvID0gXCJnMm1femVyb1wiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBncm91cFwiKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgYWNjID0wO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8YXJyLmxlbmd0aDsgaSsrKSBhY2MgKz0gYXJyW2ldID8gYXJyW2ldLmxlbmd0aCA6IDA7XG4gICAgICAgIGxldCBiQmFzZXMsIGJTY2FsYXJzO1xuICAgICAgICBpZiAoYWNjPiAyPDwxNCkge1xuICAgICAgICAgICAgYkJhc2VzID0gbmV3IEJpZ0J1ZmZlcihhY2Mqc0dpbik7XG4gICAgICAgICAgICBiU2NhbGFycyA9IG5ldyBCaWdCdWZmZXIoYWNjKmN1cnZlLkZyLm44KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGJCYXNlcyA9IG5ldyBVaW50OEFycmF5KGFjYypzR2luKTtcbiAgICAgICAgICAgIGJTY2FsYXJzID0gbmV3IFVpbnQ4QXJyYXkoYWNjKmN1cnZlLkZyLm44KTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcEIgPTA7XG4gICAgICAgIGxldCBwUyA9MDtcblxuICAgICAgICBjb25zdCBzQnVmZnMgPSBbXG4gICAgICAgICAgICBzVGF1RzEsXG4gICAgICAgICAgICBzVGF1RzIsXG4gICAgICAgICAgICBzQWxwaGFUYXVHMSxcbiAgICAgICAgICAgIHNCZXRhVGF1RzFcbiAgICAgICAgXTtcblxuICAgICAgICBjb25zdCBiT25lID0gbmV3IFVpbnQ4QXJyYXkoY3VydmUuRnIubjgpO1xuICAgICAgICBjdXJ2ZS5Gci50b1JwckxFKGJPbmUsIDAsIGN1cnZlLkZyLmUoMSkpO1xuXG4gICAgICAgIGxldCBvZmZzZXQgPSAwO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8YXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoIWFycltpXSkgY29udGludWU7XG4gICAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8YXJyW2ldLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgaWYgKChsb2dnZXIpJiYoaikmJihqJTEwMDAwID09IDApKSAgbG9nZ2VyLmRlYnVnKGBDb25maWd1cmluZyBiaWcgYXJyYXkgJHtzZWN0aW9uTmFtZX06ICR7an0vJHthcnJbaV0ubGVuZ3RofWApO1xuICAgICAgICAgICAgICAgIGJCYXNlcy5zZXQoXG4gICAgICAgICAgICAgICAgICAgIHNCdWZmc1thcnJbaV1bal1bMF1dLnNsaWNlKFxuICAgICAgICAgICAgICAgICAgICAgICAgYXJyW2ldW2pdWzFdLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXJyW2ldW2pdWzFdICsgc0dpblxuICAgICAgICAgICAgICAgICAgICApLCBvZmZzZXQqc0dpblxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgaWYgKGFycltpXVtqXVsyXT49MCkge1xuICAgICAgICAgICAgICAgICAgICBiU2NhbGFycy5zZXQoXG4gICAgICAgICAgICAgICAgICAgICAgICBzUjFjcy5zbGljZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcnJbaV1bal1bMl0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyW2ldW2pdWzJdICsgY3VydmUuRnIubjhcbiAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQqY3VydmUuRnIubjhcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBiU2NhbGFycy5zZXQoYk9uZSwgb2Zmc2V0KmN1cnZlLkZyLm44KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgb2Zmc2V0ICsrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGFyci5sZW5ndGg+MSkge1xuICAgICAgICAgICAgY29uc3QgdGFzayA9IFtdO1xuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAwLCBidWZmOiBiQmFzZXN9KTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMSwgYnVmZjogYlNjYWxhcnN9KTtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DXCIsIHZhcjogMiwgbGVuOiBhcnIubGVuZ3RoKnNHbWlkfSk7XG4gICAgICAgICAgICBwQiA9IDA7XG4gICAgICAgICAgICBwUyA9IDA7XG4gICAgICAgICAgICBsZXQgcEQgPTA7XG4gICAgICAgICAgICBmb3IgKGxldCBpPTA7IGk8YXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFhcnJbaV0pIHtcbiAgICAgICAgICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IGZuWmVybywgcGFyYW1zOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFyOiAyLCBvZmZzZXQ6IHBEfVxuICAgICAgICAgICAgICAgICAgICBdfSk7XG4gICAgICAgICAgICAgICAgICAgIHBEICs9IHNHbWlkO1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGFycltpXS5sZW5ndGggPT0gMSkge1xuICAgICAgICAgICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJDQUxMXCIsIGZuTmFtZTogZm5FeHAsIHBhcmFtczogW1xuICAgICAgICAgICAgICAgICAgICAgICAge3ZhcjogMCwgb2Zmc2V0OiBwQn0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFyOiAxLCBvZmZzZXQ6IHBTfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHt2YWw6IGN1cnZlLkZyLm44fSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHt2YXI6IDIsIG9mZnNldDogcER9XG4gICAgICAgICAgICAgICAgICAgIF19KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJDQUxMXCIsIGZuTmFtZTogZm5NdWx0aUV4cCwgcGFyYW1zOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFyOiAwLCBvZmZzZXQ6IHBCfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHt2YXI6IDEsIG9mZnNldDogcFN9LFxuICAgICAgICAgICAgICAgICAgICAgICAge3ZhbDogY3VydmUuRnIubjh9LFxuICAgICAgICAgICAgICAgICAgICAgICAge3ZhbDogYXJyW2ldLmxlbmd0aH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7dmFyOiAyLCBvZmZzZXQ6IHBEfVxuICAgICAgICAgICAgICAgICAgICBdfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHBCICs9IHNHaW4qYXJyW2ldLmxlbmd0aDtcbiAgICAgICAgICAgICAgICBwUyArPSBjdXJ2ZS5Gci5uOCphcnJbaV0ubGVuZ3RoO1xuICAgICAgICAgICAgICAgIHBEICs9IHNHbWlkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IGZuQmF0Y2hUb0FmZmluZSwgcGFyYW1zOiBbXG4gICAgICAgICAgICAgICAge3ZhcjogMn0sXG4gICAgICAgICAgICAgICAge3ZhbDogYXJyLmxlbmd0aH0sXG4gICAgICAgICAgICAgICAge3ZhcjogMn0sXG4gICAgICAgICAgICBdfSk7XG4gICAgICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJHRVRcIiwgb3V0OiAwLCB2YXI6IDIsIGxlbjogYXJyLmxlbmd0aCpzR291dH0pO1xuXG4gICAgICAgICAgICBjb25zdCByZXMgPSBhd2FpdCBjdXJ2ZS50bS5xdWV1ZUFjdGlvbih0YXNrKTtcbiAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZXQgcmVzID0gYXdhaXQgRy5tdWx0aUV4cEFmZmluZShiQmFzZXMsIGJTY2FsYXJzLCBsb2dnZXIsIHNlY3Rpb25OYW1lKTtcbiAgICAgICAgICAgIHJlcyA9IFsgRy50b0FmZmluZShyZXMpIF07XG4gICAgICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICBhc3luYyBmdW5jdGlvbiBoYXNoSFBvaW50cygpIHtcbiAgICAgICAgY29uc3QgQ0hVTktfU0laRSA9IDE8PDE0O1xuXG4gICAgICAgIGhhc2hVMzIoZG9tYWluU2l6ZS0xKTtcblxuICAgICAgICBmb3IgKGxldCBpPTA7IGk8ZG9tYWluU2l6ZS0xOyBpKz0gQ0hVTktfU0laRSkge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgIGxvZ2dlci5kZWJ1ZyhgSGFzaGluZ0hQb2ludHM6ICR7aX0vJHtkb21haW5TaXplfWApO1xuICAgICAgICAgICAgY29uc3QgbiA9IE1hdGgubWluKGRvbWFpblNpemUtMSwgQ0hVTktfU0laRSk7XG4gICAgICAgICAgICBhd2FpdCBoYXNoSFBvaW50c0NodW5rKGksIG4pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gaGFzaEhQb2ludHNDaHVuayhvZmZzZXQsIG5Qb2ludHMpIHtcbiAgICAgICAgY29uc3QgYnVmZjEgPSBhd2FpdCBmZFBUYXUucmVhZChuUG9pbnRzICpzRzEsIHNlY3Rpb25zUFRhdVsyXVswXS5wICsgKG9mZnNldCArIGRvbWFpblNpemUpKnNHMSk7XG4gICAgICAgIGNvbnN0IGJ1ZmYyID0gYXdhaXQgZmRQVGF1LnJlYWQoblBvaW50cyAqc0cxLCBzZWN0aW9uc1BUYXVbMl1bMF0ucCArIG9mZnNldCpzRzEpO1xuICAgICAgICBjb25zdCBjb25jdXJyZW5jeT0gY3VydmUudG0uY29uY3VycmVuY3k7XG4gICAgICAgIGNvbnN0IG5Qb2ludHNQZXJUaHJlYWQgPSBNYXRoLmZsb29yKG5Qb2ludHMgLyBjb25jdXJyZW5jeSk7XG4gICAgICAgIGNvbnN0IG9wUHJvbWlzZXMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPGNvbmN1cnJlbmN5OyBpKyspIHtcbiAgICAgICAgICAgIGxldCBuO1xuICAgICAgICAgICAgaWYgKGk8IGNvbmN1cnJlbmN5LTEpIHtcbiAgICAgICAgICAgICAgICBuID0gblBvaW50c1BlclRocmVhZDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbiA9IG5Qb2ludHMgLSBpKm5Qb2ludHNQZXJUaHJlYWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobj09MCkgY29udGludWU7XG5cbiAgICAgICAgICAgIGNvbnN0IHN1YkJ1ZmYxID0gYnVmZjEuc2xpY2UoaSpuUG9pbnRzUGVyVGhyZWFkKnNHMSwgKGkqblBvaW50c1BlclRocmVhZCtuKSpzRzEpO1xuICAgICAgICAgICAgY29uc3Qgc3ViQnVmZjIgPSBidWZmMi5zbGljZShpKm5Qb2ludHNQZXJUaHJlYWQqc0cxLCAoaSpuUG9pbnRzUGVyVGhyZWFkK24pKnNHMSk7XG4gICAgICAgICAgICBvcFByb21pc2VzLnB1c2goaGFzaEhQb2ludHNUaHJlYWQoc3ViQnVmZjEsIHN1YkJ1ZmYyKSk7XG4gICAgICAgIH1cblxuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UuYWxsKG9wUHJvbWlzZXMpO1xuXG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxyZXN1bHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNzSGFzaGVyLnVwZGF0ZShyZXN1bHRbaV1bMF0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gaGFzaEhQb2ludHNUaHJlYWQoYnVmZjEsIGJ1ZmYyKSB7XG4gICAgICAgIGNvbnN0IG5Qb2ludHMgPSBidWZmMS5ieXRlTGVuZ3RoL3NHMTtcbiAgICAgICAgY29uc3Qgc0dtaWQgPSBjdXJ2ZS5HMS5GLm44KjM7XG4gICAgICAgIGNvbnN0IHRhc2sgPSBbXTtcbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAwLCBidWZmOiBidWZmMX0pO1xuICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1NFVFwiLCB2YXI6IDEsIGJ1ZmY6IGJ1ZmYyfSk7XG4gICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DXCIsIHZhcjogMiwgbGVuOiBuUG9pbnRzKnNHbWlkfSk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxuUG9pbnRzOyBpKyspIHtcbiAgICAgICAgICAgIHRhc2sucHVzaCh7XG4gICAgICAgICAgICAgICAgY21kOiBcIkNBTExcIixcbiAgICAgICAgICAgICAgICBmbk5hbWU6IFwiZzFtX3N1YkFmZmluZVwiLFxuICAgICAgICAgICAgICAgIHBhcmFtczogW1xuICAgICAgICAgICAgICAgICAgICB7dmFyOiAwLCBvZmZzZXQ6IGkqc0cxfSxcbiAgICAgICAgICAgICAgICAgICAge3ZhcjogMSwgb2Zmc2V0OiBpKnNHMX0sXG4gICAgICAgICAgICAgICAgICAgIHt2YXI6IDIsIG9mZnNldDogaSpzR21pZH0sXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IFwiZzFtX2JhdGNoVG9BZmZpbmVcIiwgcGFyYW1zOiBbXG4gICAgICAgICAgICB7dmFyOiAyfSxcbiAgICAgICAgICAgIHt2YWw6IG5Qb2ludHN9LFxuICAgICAgICAgICAge3ZhcjogMn0sXG4gICAgICAgIF19KTtcbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQ0FMTFwiLCBmbk5hbWU6IFwiZzFtX2JhdGNoTEVNdG9VXCIsIHBhcmFtczogW1xuICAgICAgICAgICAge3ZhcjogMn0sXG4gICAgICAgICAgICB7dmFsOiBuUG9pbnRzfSxcbiAgICAgICAgICAgIHt2YXI6IDJ9LFxuICAgICAgICBdfSk7XG4gICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkdFVFwiLCBvdXQ6IDAsIHZhcjogMiwgbGVuOiBuUG9pbnRzKnNHMX0pO1xuXG4gICAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IGN1cnZlLnRtLnF1ZXVlQWN0aW9uKHRhc2spO1xuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaGFzaFUzMihuKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheSg0KTtcbiAgICAgICAgY29uc3QgYnVmZlYgPSBuZXcgRGF0YVZpZXcoYnVmZi5idWZmZXIsIGJ1ZmYuYnl0ZU9mZnNldCwgYnVmZi5ieXRlTGVuZ3RoKTtcbiAgICAgICAgYnVmZlYuc2V0VWludDMyKDAsIG4sIGZhbHNlKTtcbiAgICAgICAgY3NIYXNoZXIudXBkYXRlKGJ1ZmYpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1lbVVzYWdlKCkge1xuICAgICAgICBsZXQgbSA9IHByb2Nlc3MubWVtb3J5VXNhZ2UoKTtcbiAgICAgICAgZm9yIChjb25zdCBpIGluIG0pIHtcbiAgICAgICAgICAgIG1baV0gPSBNYXRoLnJvdW5kKG1baV0gLyAoMTAyNCoxMDI0KSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG07XG4gICAgfVxuXG59XG5cblxuIiwiXG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCAqIGFzIHprZXlVdGlscyBmcm9tIFwiLi96a2V5X3V0aWxzLmpzXCI7XG5pbXBvcnQgKiBhcyBmYXN0RmlsZSBmcm9tIFwiZmFzdGZpbGVcIjtcbmltcG9ydCB7IGdldEN1cnZlRnJvbVEgYXMgZ2V0Q3VydmUgfSBmcm9tIFwiLi9jdXJ2ZXMuanNcIjtcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gcGhhc2UyZXhwb3J0TVBDUGFyYW1zKHprZXlOYW1lLCBtcGNwYXJhbXNOYW1lLCBsb2dnZXIpIHtcblxuICAgIGNvbnN0IHtmZDogZmRaS2V5LCBzZWN0aW9uczogc2VjdGlvbnNaS2V5fSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmluRmlsZSh6a2V5TmFtZSwgXCJ6a2V5XCIsIDIpO1xuICAgIGNvbnN0IHprZXkgPSBhd2FpdCB6a2V5VXRpbHMucmVhZEhlYWRlcihmZFpLZXksIHNlY3Rpb25zWktleSk7XG4gICAgaWYgKHprZXkucHJvdG9jb2wgIT0gXCJncm90aDE2XCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiemtleSBmaWxlIGlzIG5vdCBncm90aDE2XCIpO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgZ2V0Q3VydmUoemtleS5xKTtcbiAgICBjb25zdCBzRzEgPSBjdXJ2ZS5HMS5GLm44KjI7XG4gICAgY29uc3Qgc0cyID0gY3VydmUuRzIuRi5uOCoyO1xuXG4gICAgY29uc3QgbXBjUGFyYW1zID0gYXdhaXQgemtleVV0aWxzLnJlYWRNUENQYXJhbXMoZmRaS2V5LCBjdXJ2ZSwgc2VjdGlvbnNaS2V5KTtcblxuICAgIGNvbnN0IGZkTVBDUGFyYW1zID0gYXdhaXQgZmFzdEZpbGUuY3JlYXRlT3ZlcnJpZGUobXBjcGFyYW1zTmFtZSk7XG5cbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgICAvLyBWZXJpZmljYXRpb24gS2V5IFNlY3Rpb25cbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgICBhd2FpdCB3cml0ZUcxKHprZXkudmtfYWxwaGFfMSk7XG4gICAgYXdhaXQgd3JpdGVHMSh6a2V5LnZrX2JldGFfMSk7XG4gICAgYXdhaXQgd3JpdGVHMih6a2V5LnZrX2JldGFfMik7XG4gICAgYXdhaXQgd3JpdGVHMih6a2V5LnZrX2dhbW1hXzIpO1xuICAgIGF3YWl0IHdyaXRlRzEoemtleS52a19kZWx0YV8xKTtcbiAgICBhd2FpdCB3cml0ZUcyKHprZXkudmtfZGVsdGFfMik7XG5cbiAgICAvLyBJQ1xuICAgIGxldCBidWZmQmFzZXNJQztcbiAgICBidWZmQmFzZXNJQyA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkU2VjdGlvbihmZFpLZXksIHNlY3Rpb25zWktleSwgMyk7XG4gICAgYnVmZkJhc2VzSUMgPSBhd2FpdCBjdXJ2ZS5HMS5iYXRjaExFTXRvVShidWZmQmFzZXNJQyk7XG5cbiAgICBhd2FpdCB3cml0ZVBvaW50QXJyYXkoXCJHMVwiLCBidWZmQmFzZXNJQyk7XG5cbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgICAvLyBoIFNlY3Rpb25cbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgICBjb25zdCBidWZmQmFzZXNIX0xvZGQgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRaS2V5LCBzZWN0aW9uc1pLZXksIDkpO1xuXG4gICAgbGV0IGJ1ZmZCYXNlc0hfVGF1O1xuICAgIGJ1ZmZCYXNlc0hfVGF1ID0gYXdhaXQgY3VydmUuRzEuZmZ0KGJ1ZmZCYXNlc0hfTG9kZCwgXCJhZmZpbmVcIiwgXCJqYWNvYmlhblwiLCBsb2dnZXIpO1xuICAgIGJ1ZmZCYXNlc0hfVGF1ID0gYXdhaXQgY3VydmUuRzEuYmF0Y2hBcHBseUtleShidWZmQmFzZXNIX1RhdSwgY3VydmUuRnIubmVnKGN1cnZlLkZyLmUoMikpLCBjdXJ2ZS5Gci53W3prZXkucG93ZXIrMV0sIFwiamFjb2JpYW5cIiwgXCJhZmZpbmVcIiwgbG9nZ2VyKTtcblxuICAgIC8vIFJlbW92ZSBsYXN0IGVsZW1lbnQuICAoVGhlIGRlZ3JlZSBvZiBIIHdpbGwgYmUgYWx3YXlzIG0tMilcbiAgICBidWZmQmFzZXNIX1RhdSA9IGJ1ZmZCYXNlc0hfVGF1LnNsaWNlKDAsIGJ1ZmZCYXNlc0hfVGF1LmJ5dGVMZW5ndGggLSBzRzEpO1xuICAgIGJ1ZmZCYXNlc0hfVGF1ID0gYXdhaXQgY3VydmUuRzEuYmF0Y2hMRU10b1UoYnVmZkJhc2VzSF9UYXUpO1xuICAgIGF3YWl0IHdyaXRlUG9pbnRBcnJheShcIkcxXCIsIGJ1ZmZCYXNlc0hfVGF1KTtcblxuICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgIC8vIEwgc2VjdGlvblxuICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgIGxldCBidWZmQmFzZXNDO1xuICAgIGJ1ZmZCYXNlc0MgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRaS2V5LCBzZWN0aW9uc1pLZXksIDgpO1xuICAgIGJ1ZmZCYXNlc0MgPSBhd2FpdCBjdXJ2ZS5HMS5iYXRjaExFTXRvVShidWZmQmFzZXNDKTtcbiAgICBhd2FpdCB3cml0ZVBvaW50QXJyYXkoXCJHMVwiLCBidWZmQmFzZXNDKTtcblxuICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgIC8vIEEgU2VjdGlvbiAoQyBzZWN0aW9uKVxuICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgIGxldCBidWZmQmFzZXNBO1xuICAgIGJ1ZmZCYXNlc0EgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRaS2V5LCBzZWN0aW9uc1pLZXksIDUpO1xuICAgIGJ1ZmZCYXNlc0EgPSBhd2FpdCBjdXJ2ZS5HMS5iYXRjaExFTXRvVShidWZmQmFzZXNBKTtcbiAgICBhd2FpdCB3cml0ZVBvaW50QXJyYXkoXCJHMVwiLCBidWZmQmFzZXNBKTtcblxuICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgIC8vIEIxIFNlY3Rpb25cbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgICBsZXQgYnVmZkJhc2VzQjE7XG4gICAgYnVmZkJhc2VzQjEgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRaS2V5LCBzZWN0aW9uc1pLZXksIDYpO1xuICAgIGJ1ZmZCYXNlc0IxID0gYXdhaXQgY3VydmUuRzEuYmF0Y2hMRU10b1UoYnVmZkJhc2VzQjEpO1xuICAgIGF3YWl0IHdyaXRlUG9pbnRBcnJheShcIkcxXCIsIGJ1ZmZCYXNlc0IxKTtcblxuICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgIC8vIEIyIFNlY3Rpb25cbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgICBsZXQgYnVmZkJhc2VzQjI7XG4gICAgYnVmZkJhc2VzQjIgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRaS2V5LCBzZWN0aW9uc1pLZXksIDcpO1xuICAgIGJ1ZmZCYXNlc0IyID0gYXdhaXQgY3VydmUuRzIuYmF0Y2hMRU10b1UoYnVmZkJhc2VzQjIpO1xuICAgIGF3YWl0IHdyaXRlUG9pbnRBcnJheShcIkcyXCIsIGJ1ZmZCYXNlc0IyKTtcblxuICAgIGF3YWl0IGZkTVBDUGFyYW1zLndyaXRlKG1wY1BhcmFtcy5jc0hhc2gpO1xuICAgIGF3YWl0IHdyaXRlVTMyKG1wY1BhcmFtcy5jb250cmlidXRpb25zLmxlbmd0aCk7XG5cbiAgICBmb3IgKGxldCBpPTA7IGk8bXBjUGFyYW1zLmNvbnRyaWJ1dGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY29uc3QgYyA9IG1wY1BhcmFtcy5jb250cmlidXRpb25zW2ldO1xuICAgICAgICBhd2FpdCB3cml0ZUcxKGMuZGVsdGFBZnRlcik7XG4gICAgICAgIGF3YWl0IHdyaXRlRzEoYy5kZWx0YS5nMV9zKTtcbiAgICAgICAgYXdhaXQgd3JpdGVHMShjLmRlbHRhLmcxX3N4KTtcbiAgICAgICAgYXdhaXQgd3JpdGVHMihjLmRlbHRhLmcyX3NweCk7XG4gICAgICAgIGF3YWl0IGZkTVBDUGFyYW1zLndyaXRlKGMudHJhbnNjcmlwdCk7XG4gICAgfVxuXG4gICAgYXdhaXQgZmRaS2V5LmNsb3NlKCk7XG4gICAgYXdhaXQgZmRNUENQYXJhbXMuY2xvc2UoKTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlRzEoUCkge1xuICAgICAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkoc0cxKTtcbiAgICAgICAgY3VydmUuRzEudG9ScHJVbmNvbXByZXNzZWQoYnVmZiwgMCwgUCk7XG4gICAgICAgIGF3YWl0IGZkTVBDUGFyYW1zLndyaXRlKGJ1ZmYpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlRzIoUCkge1xuICAgICAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkoc0cyKTtcbiAgICAgICAgY3VydmUuRzIudG9ScHJVbmNvbXByZXNzZWQoYnVmZiwgMCwgUCk7XG4gICAgICAgIGF3YWl0IGZkTVBDUGFyYW1zLndyaXRlKGJ1ZmYpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlUG9pbnRBcnJheShncm91cE5hbWUsIGJ1ZmYpIHtcbiAgICAgICAgbGV0IHNHO1xuICAgICAgICBpZiAoZ3JvdXBOYW1lID09IFwiRzFcIikge1xuICAgICAgICAgICAgc0cgPSBzRzE7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzRyA9IHNHMjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJ1ZmZTaXplID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG4gICAgICAgIGNvbnN0IGJ1ZmZTaXplViA9IG5ldyBEYXRhVmlldyhidWZmU2l6ZS5idWZmZXIsIGJ1ZmZTaXplLmJ5dGVPZmZzZXQsIGJ1ZmZTaXplLmJ5dGVMZW5ndGgpO1xuICAgICAgICBidWZmU2l6ZVYuc2V0VWludDMyKDAsIGJ1ZmYuYnl0ZUxlbmd0aCAvIHNHLCBmYWxzZSk7XG5cbiAgICAgICAgYXdhaXQgZmRNUENQYXJhbXMud3JpdGUoYnVmZlNpemUpO1xuICAgICAgICBhd2FpdCBmZE1QQ1BhcmFtcy53cml0ZShidWZmKTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiB3cml0ZVUzMihuKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmZTaXplID0gbmV3IFVpbnQ4QXJyYXkoNCk7XG4gICAgICAgIGNvbnN0IGJ1ZmZTaXplViA9IG5ldyBEYXRhVmlldyhidWZmU2l6ZS5idWZmZXIsIGJ1ZmZTaXplLmJ5dGVPZmZzZXQsIGJ1ZmZTaXplLmJ5dGVMZW5ndGgpO1xuICAgICAgICBidWZmU2l6ZVYuc2V0VWludDMyKDAsIG4sIGZhbHNlKTtcblxuICAgICAgICBhd2FpdCBmZE1QQ1BhcmFtcy53cml0ZShidWZmU2l6ZSk7XG4gICAgfVxuXG5cblxufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0ICogYXMgemtleVV0aWxzIGZyb20gXCIuL3prZXlfdXRpbHMuanNcIjtcbmltcG9ydCAqIGFzIGJpbkZpbGVVdGlscyBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuaW1wb3J0ICogYXMgZmFzdEZpbGUgZnJvbSBcImZhc3RmaWxlXCI7XG5pbXBvcnQgeyBnZXRDdXJ2ZUZyb21RIGFzIGdldEN1cnZlIH0gZnJvbSBcIi4vY3VydmVzLmpzXCI7XG5pbXBvcnQgKiBhcyBtaXNjIGZyb20gXCIuL21pc2MuanNcIjtcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gcGhhc2UyaW1wb3J0TVBDUGFyYW1zKHprZXlOYW1lT2xkLCBtcGNwYXJhbXNOYW1lLCB6a2V5TmFtZU5ldywgbmFtZSwgbG9nZ2VyKSB7XG5cbiAgICBjb25zdCB7ZmQ6IGZkWktleU9sZCwgc2VjdGlvbnM6IHNlY3Rpb25zWktleU9sZH0gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUoemtleU5hbWVPbGQsIFwiemtleVwiLCAyKTtcbiAgICBjb25zdCB6a2V5SGVhZGVyID0gYXdhaXQgemtleVV0aWxzLnJlYWRIZWFkZXIoZmRaS2V5T2xkLCBzZWN0aW9uc1pLZXlPbGQsIGZhbHNlKTtcbiAgICBpZiAoemtleUhlYWRlci5wcm90b2NvbCAhPSBcImdyb3RoMTZcIikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJ6a2V5IGZpbGUgaXMgbm90IGdyb3RoMTZcIik7XG4gICAgfVxuXG4gICAgY29uc3QgY3VydmUgPSBhd2FpdCBnZXRDdXJ2ZSh6a2V5SGVhZGVyLnEpO1xuICAgIGNvbnN0IHNHMSA9IGN1cnZlLkcxLkYubjgqMjtcbiAgICBjb25zdCBzRzIgPSBjdXJ2ZS5HMi5GLm44KjI7XG5cbiAgICBjb25zdCBvbGRNUENQYXJhbXMgPSBhd2FpdCB6a2V5VXRpbHMucmVhZE1QQ1BhcmFtcyhmZFpLZXlPbGQsIGN1cnZlLCBzZWN0aW9uc1pLZXlPbGQpO1xuICAgIGNvbnN0IG5ld01QQ1BhcmFtcyA9IHt9O1xuXG4gICAgY29uc3QgZmRNUENQYXJhbXMgPSBhd2FpdCBmYXN0RmlsZS5yZWFkRXhpc3RpbmcobXBjcGFyYW1zTmFtZSk7XG5cbiAgICBmZE1QQ1BhcmFtcy5wb3MgPVxuICAgICAgICBzRzEqMyArIHNHMiozICsgICAgICAgICAgICAgICAgICAgICAvLyB2S2V5XG4gICAgICAgIDggKyBzRzEqemtleUhlYWRlci5uVmFycyArICAgICAgICAgICAgICAvLyBJQyArIENcbiAgICAgICAgNCArIHNHMSooemtleUhlYWRlci5kb21haW5TaXplLTEpICsgICAgIC8vIEhcbiAgICAgICAgNCArIHNHMSp6a2V5SGVhZGVyLm5WYXJzICsgICAgICAgICAgICAgIC8vIEFcbiAgICAgICAgNCArIHNHMSp6a2V5SGVhZGVyLm5WYXJzICsgICAgICAgICAgICAgIC8vIEIxXG4gICAgICAgIDQgKyBzRzIqemtleUhlYWRlci5uVmFyczsgICAgICAgICAgICAgICAvLyBCMlxuXG4gICAgLy8gY3NIYXNoXG4gICAgbmV3TVBDUGFyYW1zLmNzSGFzaCA9ICBhd2FpdCBmZE1QQ1BhcmFtcy5yZWFkKDY0KTtcblxuICAgIGNvbnN0IG5Db250cmlidXRpb25zID0gYXdhaXQgZmRNUENQYXJhbXMucmVhZFVCRTMyKCk7XG4gICAgbmV3TVBDUGFyYW1zLmNvbnRyaWJ1dGlvbnMgPSBbXTtcbiAgICBmb3IgKGxldCBpPTA7IGk8bkNvbnRyaWJ1dGlvbnM7IGkrKykge1xuICAgICAgICBjb25zdCBjID0geyBkZWx0YTp7fSB9O1xuICAgICAgICBjLmRlbHRhQWZ0ZXIgPSBhd2FpdCByZWFkRzEoZmRNUENQYXJhbXMpO1xuICAgICAgICBjLmRlbHRhLmcxX3MgPSBhd2FpdCByZWFkRzEoZmRNUENQYXJhbXMpO1xuICAgICAgICBjLmRlbHRhLmcxX3N4ID0gYXdhaXQgcmVhZEcxKGZkTVBDUGFyYW1zKTtcbiAgICAgICAgYy5kZWx0YS5nMl9zcHggPSBhd2FpdCByZWFkRzIoZmRNUENQYXJhbXMpO1xuICAgICAgICBjLnRyYW5zY3JpcHQgPSBhd2FpdCBmZE1QQ1BhcmFtcy5yZWFkKDY0KTtcbiAgICAgICAgaWYgKGk8b2xkTVBDUGFyYW1zLmNvbnRyaWJ1dGlvbnMubGVuZ3RoKSB7XG4gICAgICAgICAgICBjLnR5cGUgPSBvbGRNUENQYXJhbXMuY29udHJpYnV0aW9uc1tpXS50eXBlO1xuICAgICAgICAgICAgaWYgKGMudHlwZT09MSkge1xuICAgICAgICAgICAgICAgIGMuYmVhY29uSGFzaCA9IG9sZE1QQ1BhcmFtcy5jb250cmlidXRpb25zW2ldLmJlYWNvbkhhc2g7XG4gICAgICAgICAgICAgICAgYy5udW1JdGVyYXRpb25zRXhwID0gb2xkTVBDUGFyYW1zLmNvbnRyaWJ1dGlvbnNbaV0ubnVtSXRlcmF0aW9uc0V4cDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChvbGRNUENQYXJhbXMuY29udHJpYnV0aW9uc1tpXS5uYW1lKSB7XG4gICAgICAgICAgICAgICAgYy5uYW1lID0gb2xkTVBDUGFyYW1zLmNvbnRyaWJ1dGlvbnNbaV0ubmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBuZXdNUENQYXJhbXMuY29udHJpYnV0aW9ucy5wdXNoKGMpO1xuICAgIH1cblxuICAgIGlmICghbWlzYy5oYXNoSXNFcXVhbChuZXdNUENQYXJhbXMuY3NIYXNoLCBvbGRNUENQYXJhbXMuY3NIYXNoKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJIYXNoIG9mIHRoZSBvcmlnaW5hbCBjaXJjdWl0IGRvZXMgbm90IG1hdGNoIHdpdGggdGhlIE1QQyBvbmVcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAob2xkTVBDUGFyYW1zLmNvbnRyaWJ1dGlvbnMubGVuZ3RoID4gbmV3TVBDUGFyYW1zLmNvbnRyaWJ1dGlvbnMubGVuZ3RoKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIlRoZSBpbXBvZXJ0ZWQgZmlsZSBkb2VzIG5vdCBpbmNsdWRlIG5ldyBjb250cmlidXRpb25zXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaT0wOyBpPG9sZE1QQ1BhcmFtcy5jb250cmlidXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmICghY29udHJpYnV0aW9uSXNFcXVhbChvbGRNUENQYXJhbXMuY29udHJpYnV0aW9uc1tpXSwgbmV3TVBDUGFyYW1zLmNvbnRyaWJ1dGlvbnNbaV0pKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoYFByZXZpb3VzIGNvbnRyaWJ1dGlvbiAke2l9IGRvZXMgbm90IG1hdGNoYCk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cblxuICAgIC8vIFNldCB0aGUgc2FtZSBuYW1lIHRvIGFsbCBuZXcgY29udHJpYnV0aW9uc1xuICAgIGlmIChuYW1lKSB7XG4gICAgICAgIGZvciAobGV0IGk9b2xkTVBDUGFyYW1zLmNvbnRyaWJ1dGlvbnMubGVuZ3RoOyBpPG5ld01QQ1BhcmFtcy5jb250cmlidXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBuZXdNUENQYXJhbXMuY29udHJpYnV0aW9uc1tpXS5uYW1lID0gbmFtZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGZkWktleU5ldyA9IGF3YWl0IGJpbkZpbGVVdGlscy5jcmVhdGVCaW5GaWxlKHprZXlOYW1lTmV3LCBcInprZXlcIiwgMSwgMTApO1xuICAgIGZkTVBDUGFyYW1zLnBvcyA9IDA7XG5cbiAgICAvLyBIZWFkZXJcbiAgICBmZE1QQ1BhcmFtcy5wb3MgKz0gc0cxOyAgLy8gaWdub3JlIGFscGhhMSAoa2VlcCBvcmlnaW5hbClcbiAgICBmZE1QQ1BhcmFtcy5wb3MgKz0gc0cxOyAgLy8gaWdub3JlIGJldGExXG4gICAgZmRNUENQYXJhbXMucG9zICs9IHNHMjsgIC8vIGlnbm9yZSBiZXRhMlxuICAgIGZkTVBDUGFyYW1zLnBvcyArPSBzRzI7ICAvLyBpZ25vcmUgZ2FtbWEyXG4gICAgemtleUhlYWRlci52a19kZWx0YV8xID0gYXdhaXQgcmVhZEcxKGZkTVBDUGFyYW1zKTtcbiAgICB6a2V5SGVhZGVyLnZrX2RlbHRhXzIgPSBhd2FpdCByZWFkRzIoZmRNUENQYXJhbXMpO1xuICAgIGF3YWl0IHprZXlVdGlscy53cml0ZUhlYWRlcihmZFpLZXlOZXcsIHprZXlIZWFkZXIpO1xuXG4gICAgLy8gSUMgKEtlZXAgb3JpZ2luYWwpXG4gICAgY29uc3QgbklDID0gYXdhaXQgZmRNUENQYXJhbXMucmVhZFVCRTMyKCk7XG4gICAgaWYgKG5JQyAhPSB6a2V5SGVhZGVyLm5QdWJsaWMgKzEpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSW52YWxpZCBudW1iZXIgb2YgcG9pbnRzIGluIElDXCIpO1xuICAgICAgICBhd2FpdCBmZFpLZXlOZXcuZGlzY2FyZCgpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGZkTVBDUGFyYW1zLnBvcyArPSBzRzEqKHprZXlIZWFkZXIublB1YmxpYysxKTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRaS2V5T2xkLCBzZWN0aW9uc1pLZXlPbGQsIGZkWktleU5ldywgMyk7XG5cbiAgICAvLyBDb2VmZnMgKEtlZXAgb3JpZ2luYWwpXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkWktleU9sZCwgc2VjdGlvbnNaS2V5T2xkLCBmZFpLZXlOZXcsIDQpO1xuXG4gICAgLy8gSCBTZWN0aW9uXG4gICAgY29uc3QgbkggPSBhd2FpdCBmZE1QQ1BhcmFtcy5yZWFkVUJFMzIoKTtcbiAgICBpZiAobkggIT0gemtleUhlYWRlci5kb21haW5TaXplLTEpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSW52YWxpZCBudW1iZXIgb2YgcG9pbnRzIGluIEhcIik7XG4gICAgICAgIGF3YWl0IGZkWktleU5ldy5kaXNjYXJkKCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgbGV0IGJ1ZmZIO1xuICAgIGNvbnN0IGJ1ZmZUYXVVID0gYXdhaXQgZmRNUENQYXJhbXMucmVhZChzRzEqKHprZXlIZWFkZXIuZG9tYWluU2l6ZS0xKSk7XG4gICAgY29uc3QgYnVmZlRhdUxFTSA9IGF3YWl0IGN1cnZlLkcxLmJhdGNoVXRvTEVNKGJ1ZmZUYXVVKTtcbiAgICBidWZmSCA9IG5ldyBVaW50OEFycmF5KHprZXlIZWFkZXIuZG9tYWluU2l6ZSpzRzEpO1xuICAgIGJ1ZmZILnNldChidWZmVGF1TEVNKTsgICAvLyBMZXQgdGhlIGxhc3Qgb25lIHRvIHplcm8uXG4gICAgY3VydmUuRzEudG9ScHJMRU0oYnVmZkgsIHNHMSooemtleUhlYWRlci5kb21haW5TaXplLTEpLCBjdXJ2ZS5HMS56ZXJvQWZmaW5lKTtcbiAgICBjb25zdCBuMkludiA9IGN1cnZlLkZyLm5lZyhjdXJ2ZS5Gci5pbnYoY3VydmUuRnIuZSgyKSkpO1xuICAgIGNvbnN0IHdJbnYgPSBjdXJ2ZS5Gci5pbnYoY3VydmUuRnIud1t6a2V5SGVhZGVyLnBvd2VyKzFdKTtcbiAgICBidWZmSCA9IGF3YWl0IGN1cnZlLkcxLmJhdGNoQXBwbHlLZXkoYnVmZkgsIG4ySW52LCB3SW52LCBcImFmZmluZVwiLCBcImphY29iaWFuXCIsIGxvZ2dlcik7XG4gICAgYnVmZkggPSBhd2FpdCBjdXJ2ZS5HMS5pZmZ0KGJ1ZmZILCBcImphY29iaWFuXCIsIFwiYWZmaW5lXCIsIGxvZ2dlcik7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleU5ldywgOSk7XG4gICAgYXdhaXQgZmRaS2V5TmV3LndyaXRlKGJ1ZmZIKTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uKGZkWktleU5ldyk7XG5cbiAgICAvLyBDIFNlY3Rpb24gKEwgc2VjdGlvbilcbiAgICBjb25zdCBuTCA9IGF3YWl0IGZkTVBDUGFyYW1zLnJlYWRVQkUzMigpO1xuICAgIGlmIChuTCAhPSAoemtleUhlYWRlci5uVmFycy16a2V5SGVhZGVyLm5QdWJsaWMtMSkpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSW52YWxpZCBudW1iZXIgb2YgcG9pbnRzIGluIExcIik7XG4gICAgICAgIGF3YWl0IGZkWktleU5ldy5kaXNjYXJkKCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgbGV0IGJ1ZmZMO1xuICAgIGJ1ZmZMID0gYXdhaXQgZmRNUENQYXJhbXMucmVhZChzRzEqKHprZXlIZWFkZXIublZhcnMtemtleUhlYWRlci5uUHVibGljLTEpKTtcbiAgICBidWZmTCA9IGF3YWl0IGN1cnZlLkcxLmJhdGNoVXRvTEVNKGJ1ZmZMKTtcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24oZmRaS2V5TmV3LCA4KTtcbiAgICBhd2FpdCBmZFpLZXlOZXcud3JpdGUoYnVmZkwpO1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRXcml0ZVNlY3Rpb24oZmRaS2V5TmV3KTtcblxuICAgIC8vIEEgU2VjdGlvblxuICAgIGNvbnN0IG5BID0gYXdhaXQgZmRNUENQYXJhbXMucmVhZFVCRTMyKCk7XG4gICAgaWYgKG5BICE9IHprZXlIZWFkZXIublZhcnMpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSW52YWxpZCBudW1iZXIgb2YgcG9pbnRzIGluIEFcIik7XG4gICAgICAgIGF3YWl0IGZkWktleU5ldy5kaXNjYXJkKCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgZmRNUENQYXJhbXMucG9zICs9IHNHMSooemtleUhlYWRlci5uVmFycyk7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkWktleU9sZCwgc2VjdGlvbnNaS2V5T2xkLCBmZFpLZXlOZXcsIDUpO1xuXG4gICAgLy8gQjEgU2VjdGlvblxuICAgIGNvbnN0IG5CMSA9IGF3YWl0IGZkTVBDUGFyYW1zLnJlYWRVQkUzMigpO1xuICAgIGlmIChuQjEgIT0gemtleUhlYWRlci5uVmFycykge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJJbnZhbGlkIG51bWJlciBvZiBwb2ludHMgaW4gQjFcIik7XG4gICAgICAgIGF3YWl0IGZkWktleU5ldy5kaXNjYXJkKCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgZmRNUENQYXJhbXMucG9zICs9IHNHMSooemtleUhlYWRlci5uVmFycyk7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkWktleU9sZCwgc2VjdGlvbnNaS2V5T2xkLCBmZFpLZXlOZXcsIDYpO1xuXG4gICAgLy8gQjIgU2VjdGlvblxuICAgIGNvbnN0IG5CMiA9IGF3YWl0IGZkTVBDUGFyYW1zLnJlYWRVQkUzMigpO1xuICAgIGlmIChuQjIgIT0gemtleUhlYWRlci5uVmFycykge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJJbnZhbGlkIG51bWJlciBvZiBwb2ludHMgaW4gQjJcIik7XG4gICAgICAgIGF3YWl0IGZkWktleU5ldy5kaXNjYXJkKCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgZmRNUENQYXJhbXMucG9zICs9IHNHMiooemtleUhlYWRlci5uVmFycyk7XG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkWktleU9sZCwgc2VjdGlvbnNaS2V5T2xkLCBmZFpLZXlOZXcsIDcpO1xuXG4gICAgYXdhaXQgemtleVV0aWxzLndyaXRlTVBDUGFyYW1zKGZkWktleU5ldywgY3VydmUsIG5ld01QQ1BhcmFtcyk7XG5cbiAgICBhd2FpdCBmZE1QQ1BhcmFtcy5jbG9zZSgpO1xuICAgIGF3YWl0IGZkWktleU5ldy5jbG9zZSgpO1xuICAgIGF3YWl0IGZkWktleU9sZC5jbG9zZSgpO1xuXG4gICAgcmV0dXJuIHRydWU7XG5cbiAgICBhc3luYyBmdW5jdGlvbiByZWFkRzEoZmQpIHtcbiAgICAgICAgY29uc3QgYnVmZiA9IGF3YWl0IGZkLnJlYWQoY3VydmUuRzEuRi5uOCoyKTtcbiAgICAgICAgcmV0dXJuIGN1cnZlLkcxLmZyb21ScHJVbmNvbXByZXNzZWQoYnVmZiwgMCk7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gcmVhZEcyKGZkKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZC5yZWFkKGN1cnZlLkcyLkYubjgqMik7XG4gICAgICAgIHJldHVybiBjdXJ2ZS5HMi5mcm9tUnByVW5jb21wcmVzc2VkKGJ1ZmYsIDApO1xuICAgIH1cblxuXG4gICAgZnVuY3Rpb24gY29udHJpYnV0aW9uSXNFcXVhbChjMSwgYzIpIHtcbiAgICAgICAgaWYgKCFjdXJ2ZS5HMS5lcShjMS5kZWx0YUFmdGVyICAgLCBjMi5kZWx0YUFmdGVyKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgICBpZiAoIWN1cnZlLkcxLmVxKGMxLmRlbHRhLmcxX3MgICAsIGMyLmRlbHRhLmcxX3MpKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIGlmICghY3VydmUuRzEuZXEoYzEuZGVsdGEuZzFfc3ggICwgYzIuZGVsdGEuZzFfc3gpKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIGlmICghY3VydmUuRzIuZXEoYzEuZGVsdGEuZzJfc3B4ICwgYzIuZGVsdGEuZzJfc3B4KSkgcmV0dXJuIGZhbHNlO1xuICAgICAgICBpZiAoIW1pc2MuaGFzaElzRXF1YWwoYzEudHJhbnNjcmlwdCwgYzIudHJhbnNjcmlwdCkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG5cbn1cblxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0ICogYXMgYmluRmlsZVV0aWxzIGZyb20gXCJAaWRlbjMvYmluZmlsZXV0aWxzXCI7XG5pbXBvcnQgKiBhcyB6a2V5VXRpbHMgZnJvbSBcIi4vemtleV91dGlscy5qc1wiO1xuaW1wb3J0IHsgZ2V0Q3VydmVGcm9tUSBhcyBnZXRDdXJ2ZSB9IGZyb20gXCIuL2N1cnZlcy5qc1wiO1xuaW1wb3J0IHsgYmxha2UyYiB9IGZyb20gXCJAbm9ibGUvaGFzaGVzL2JsYWtlMi5qc1wiO1xuaW1wb3J0ICogYXMgbWlzYyBmcm9tIFwiLi9taXNjLmpzXCI7XG5pbXBvcnQgeyBoYXNoVG9HMiBhcyBoYXNoVG9HMiB9IGZyb20gXCIuL2tleXBhaXIuanNcIjtcbmNvbnN0IHNhbWVSYXRpbyA9IG1pc2Muc2FtZVJhdGlvO1xuaW1wb3J0IHtoYXNoRzEsIGhhc2hQdWJLZXl9IGZyb20gXCIuL3prZXlfdXRpbHMuanNcIjtcbmltcG9ydCB7IFNjYWxhciwgQ2hhQ2hhLCBCaWdCdWZmZXIgfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5cblxuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBwaGFzZTJ2ZXJpZnlGcm9tSW5pdChpbml0RmlsZU5hbWUsIHBUYXVGaWxlTmFtZSwgemtleUZpbGVOYW1lLCBsb2dnZXIpIHtcblxuICAgIGxldCBzcjtcbiAgICBjb25zdCB7ZmQsIHNlY3Rpb25zfSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmluRmlsZSh6a2V5RmlsZU5hbWUsIFwiemtleVwiLCAyKTtcbiAgICBjb25zdCB6a2V5ID0gYXdhaXQgemtleVV0aWxzLnJlYWRIZWFkZXIoZmQsIHNlY3Rpb25zLCBmYWxzZSk7XG4gICAgaWYgKHprZXkucHJvdG9jb2wgIT0gXCJncm90aDE2XCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiemtleSBmaWxlIGlzIG5vdCBncm90aDE2XCIpO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgZ2V0Q3VydmUoemtleS5xKTtcbiAgICBjb25zdCBzRzEgPSBjdXJ2ZS5HMS5GLm44KjI7XG5cbiAgICBjb25zdCBtcGNQYXJhbXMgPSBhd2FpdCB6a2V5VXRpbHMucmVhZE1QQ1BhcmFtcyhmZCwgY3VydmUsIHNlY3Rpb25zKTtcblxuICAgIGNvbnN0IGFjY3VtdWxhdGVkSGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG4gICAgYWNjdW11bGF0ZWRIYXNoZXIudXBkYXRlKG1wY1BhcmFtcy5jc0hhc2gpO1xuICAgIGxldCBjdXJEZWx0YSA9IGN1cnZlLkcxLmc7XG4gICAgZm9yIChsZXQgaT0wOyBpPG1wY1BhcmFtcy5jb250cmlidXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGMgPSBtcGNQYXJhbXMuY29udHJpYnV0aW9uc1tpXTtcbiAgICAgICAgY29uc3Qgb3VySGFzaGVyID0gbWlzYy5jbG9uZUhhc2hlcihhY2N1bXVsYXRlZEhhc2hlcik7XG5cbiAgICAgICAgaGFzaEcxKG91ckhhc2hlciwgY3VydmUsIGMuZGVsdGEuZzFfcyk7XG4gICAgICAgIGhhc2hHMShvdXJIYXNoZXIsIGN1cnZlLCBjLmRlbHRhLmcxX3N4KTtcblxuICAgICAgICBpZiAoIW1pc2MuaGFzaElzRXF1YWwob3VySGFzaGVyLmRpZ2VzdCgpLCBjLnRyYW5zY3JpcHQpKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgSU5WQUxJRCgke2l9KTogSW5jb25zaXN0ZW50IHRyYW5zY3JpcHQgYCk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBkZWx0YV9nMl9zcCA9IGhhc2hUb0cyKGN1cnZlLCBjLnRyYW5zY3JpcHQpO1xuXG4gICAgICAgIHNyID0gYXdhaXQgc2FtZVJhdGlvKGN1cnZlLCBjLmRlbHRhLmcxX3MsIGMuZGVsdGEuZzFfc3gsIGRlbHRhX2cyX3NwLCBjLmRlbHRhLmcyX3NweCk7XG4gICAgICAgIGlmIChzciAhPT0gdHJ1ZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coYElOVkFMSUQoJHtpfSk6IHB1YmxpYyBrZXkgRzEgYW5kIEcyIGRvIG5vdCBoYXZlIHRoZSBzYW1lIHJhdGlvbiBgKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNyID0gYXdhaXQgc2FtZVJhdGlvKGN1cnZlLCBjdXJEZWx0YSwgYy5kZWx0YUFmdGVyLCBkZWx0YV9nMl9zcCwgYy5kZWx0YS5nMl9zcHgpO1xuICAgICAgICBpZiAoc3IgIT09IHRydWUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBJTlZBTElEKCR7aX0pOiBkZWx0YUFmdGVyIGRvZXMgbm90IGZpbGxvdyB0aGUgcHVibGljIGtleSBgKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjLnR5cGUgPT0gMSkge1xuICAgICAgICAgICAgY29uc3Qgcm5nID0gYXdhaXQgbWlzYy5ybmdGcm9tQmVhY29uUGFyYW1zKGMuYmVhY29uSGFzaCwgYy5udW1JdGVyYXRpb25zRXhwKTtcbiAgICAgICAgICAgIGNvbnN0IGV4cGVjdGVkX3BydktleSA9IGN1cnZlLkZyLmZyb21Sbmcocm5nKTtcbiAgICAgICAgICAgIGNvbnN0IGV4cGVjdGVkX2cxX3MgPSBjdXJ2ZS5HMS50b0FmZmluZShjdXJ2ZS5HMS5mcm9tUm5nKHJuZykpO1xuICAgICAgICAgICAgY29uc3QgZXhwZWN0ZWRfZzFfc3ggPSBjdXJ2ZS5HMS50b0FmZmluZShjdXJ2ZS5HMS50aW1lc0ZyKGV4cGVjdGVkX2cxX3MsIGV4cGVjdGVkX3BydktleSkpO1xuICAgICAgICAgICAgaWYgKGN1cnZlLkcxLmVxKGV4cGVjdGVkX2cxX3MsIGMuZGVsdGEuZzFfcykgIT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgSU5WQUxJRCgke2l9KTogS2V5IG9mIHRoZSBiZWFjb24gZG9lcyBub3QgbWF0Y2guIGcxX3MgYCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGN1cnZlLkcxLmVxKGV4cGVjdGVkX2cxX3N4LCBjLmRlbHRhLmcxX3N4KSAhPT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBJTlZBTElEKCR7aX0pOiBLZXkgb2YgdGhlIGJlYWNvbiBkb2VzIG5vdCBtYXRjaC4gZzFfc3ggYCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaGFzaFB1YktleShhY2N1bXVsYXRlZEhhc2hlciwgY3VydmUsIGMpO1xuXG4gICAgICAgIGNvbnN0IGNvbnRyaWJ1dGlvbkhhc2hlciA9IGJsYWtlMmIuY3JlYXRlKHsgZGtMZW46IDY0IH0pO1xuICAgICAgICBoYXNoUHViS2V5KGNvbnRyaWJ1dGlvbkhhc2hlciwgY3VydmUsIGMpO1xuXG4gICAgICAgIGMuY29udHJpYnV0aW9uSGFzaCA9IGNvbnRyaWJ1dGlvbkhhc2hlci5kaWdlc3QoKTtcblxuICAgICAgICBjdXJEZWx0YSA9IGMuZGVsdGFBZnRlcjtcbiAgICB9XG5cblxuICAgIGNvbnN0IHtmZDogZmRJbml0LCBzZWN0aW9uczogc2VjdGlvbnNJbml0fSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmluRmlsZShpbml0RmlsZU5hbWUsIFwiemtleVwiLCAyKTtcbiAgICBjb25zdCB6a2V5SW5pdCA9IGF3YWl0IHprZXlVdGlscy5yZWFkSGVhZGVyKGZkSW5pdCwgc2VjdGlvbnNJbml0LCBmYWxzZSk7XG5cbiAgICBpZiAoemtleUluaXQucHJvdG9jb2wgIT0gXCJncm90aDE2XCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiemtleWluaXQgZmlsZSBpcyBub3QgZ3JvdGgxNlwiKTtcbiAgICB9XG5cbiAgICBpZiAoICAoIVNjYWxhci5lcSh6a2V5SW5pdC5xLCB6a2V5LnEpKVxuICAgICAgICB8fCghU2NhbGFyLmVxKHprZXlJbml0LnIsIHprZXkucikpXG4gICAgICAgIHx8KHprZXlJbml0Lm44cSAhPSB6a2V5Lm44cSlcbiAgICAgICAgfHwoemtleUluaXQubjhyICE9IHprZXkubjhyKSlcbiAgICB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIklOVkFMSUQ6ICBEaWZmZXJlbnQgY3VydmVzXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKCAgKHprZXlJbml0Lm5WYXJzICE9IHprZXkublZhcnMpXG4gICAgICAgIHx8KHprZXlJbml0Lm5QdWJsaWMgIT0gIHprZXkublB1YmxpYylcbiAgICAgICAgfHwoemtleUluaXQuZG9tYWluU2l6ZSAhPSB6a2V5LmRvbWFpblNpemUpKVxuICAgIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRDogIERpZmZlcmVudCBjaXJjdWl0IHBhcmFtZXRlcnNcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoIWN1cnZlLkcxLmVxKHprZXkudmtfYWxwaGFfMSwgemtleUluaXQudmtfYWxwaGFfMSkpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRDogIEludmFsaWQgYWxwaGExXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICghY3VydmUuRzEuZXEoemtleS52a19iZXRhXzEsIHprZXlJbml0LnZrX2JldGFfMSkpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRDogIEludmFsaWQgYmV0YTFcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKCFjdXJ2ZS5HMi5lcSh6a2V5LnZrX2JldGFfMiwgemtleUluaXQudmtfYmV0YV8yKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJJTlZBTElEOiAgSW52YWxpZCBiZXRhMlwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoIWN1cnZlLkcyLmVxKHprZXkudmtfZ2FtbWFfMiwgemtleUluaXQudmtfZ2FtbWFfMikpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRDogIEludmFsaWQgZ2FtbWEyXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICghY3VydmUuRzEuZXEoemtleS52a19kZWx0YV8xLCBjdXJEZWx0YSkpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRDogIEludmFsaWQgZGVsdGExXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHNyID0gYXdhaXQgc2FtZVJhdGlvKGN1cnZlLCBjdXJ2ZS5HMS5nLCBjdXJEZWx0YSwgY3VydmUuRzIuZywgemtleS52a19kZWx0YV8yKTtcbiAgICBpZiAoc3IgIT09IHRydWUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSU5WQUxJRDogIEludmFsaWQgZGVsdGEyXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgY29uc3QgbXBjUGFyYW1zSW5pdCA9IGF3YWl0IHprZXlVdGlscy5yZWFkTVBDUGFyYW1zKGZkSW5pdCwgY3VydmUsIHNlY3Rpb25zSW5pdCk7XG4gICAgaWYgKCFtaXNjLmhhc2hJc0VxdWFsKG1wY1BhcmFtcy5jc0hhc2gsIG1wY1BhcmFtc0luaXQuY3NIYXNoKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJJTlZBTElEOiAgQ2lyY3VpdCBkb2VzIG5vdCBtYXRjaFwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIENoZWNrIHNpemVzIG9mIHNlY3Rpb25zXG4gICAgaWYgKHNlY3Rpb25zWzhdWzBdLnNpemUgIT0gc0cxKih6a2V5Lm5WYXJzLXprZXkublB1YmxpYy0xKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJJTlZBTElEOiAgSW52YWxpZCBMIHNlY3Rpb24gc2l6ZVwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChzZWN0aW9uc1s5XVswXS5zaXplICE9IHNHMSooemtleS5kb21haW5TaXplKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJJTlZBTElEOiAgSW52YWxpZCBIIHNlY3Rpb24gc2l6ZVwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGxldCBzcztcbiAgICBzcyA9IGF3YWl0IGJpbkZpbGVVdGlscy5zZWN0aW9uSXNFcXVhbChmZCwgc2VjdGlvbnMsIGZkSW5pdCwgc2VjdGlvbnNJbml0LCAzKTtcbiAgICBpZiAoIXNzKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIklOVkFMSUQ6ICBJQyBzZWN0aW9uIGlzIG5vdCBpZGVudGljYWxcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBzcyA9IGF3YWl0IGJpbkZpbGVVdGlscy5zZWN0aW9uSXNFcXVhbChmZCwgc2VjdGlvbnMsIGZkSW5pdCwgc2VjdGlvbnNJbml0LCA0KTtcbiAgICBpZiAoIXNzKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIkNvZWZmcyBzZWN0aW9uIGlzIG5vdCBpZGVudGljYWxcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBzcyA9IGF3YWl0IGJpbkZpbGVVdGlscy5zZWN0aW9uSXNFcXVhbChmZCwgc2VjdGlvbnMsIGZkSW5pdCwgc2VjdGlvbnNJbml0LCA1KTtcbiAgICBpZiAoIXNzKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIkEgc2VjdGlvbiBpcyBub3QgaWRlbnRpY2FsXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgc3MgPSBhd2FpdCBiaW5GaWxlVXRpbHMuc2VjdGlvbklzRXF1YWwoZmQsIHNlY3Rpb25zLCBmZEluaXQsIHNlY3Rpb25zSW5pdCwgNik7XG4gICAgaWYgKCFzcykge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJCMSBzZWN0aW9uIGlzIG5vdCBpZGVudGljYWxcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBzcyA9IGF3YWl0IGJpbkZpbGVVdGlscy5zZWN0aW9uSXNFcXVhbChmZCwgc2VjdGlvbnMsIGZkSW5pdCwgc2VjdGlvbnNJbml0LCA3KTtcbiAgICBpZiAoIXNzKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIkIyIHNlY3Rpb24gaXMgbm90IGlkZW50aWNhbFwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIENoZWNrIExcbiAgICBzciA9IGF3YWl0IHNlY3Rpb25IYXNTYW1lUmF0aW8oXCJHMVwiLCBmZEluaXQsIHNlY3Rpb25zSW5pdCwgZmQsIHNlY3Rpb25zLCA4LCB6a2V5LnZrX2RlbHRhXzIsIHprZXlJbml0LnZrX2RlbHRhXzIsIFwiTCBzZWN0aW9uXCIpO1xuICAgIGlmIChzciE9PXRydWUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiTCBzZWN0aW9uIGRvZXMgbm90IG1hdGNoXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgSFxuICAgIHNyID0gYXdhaXQgc2FtZVJhdGlvSCgpO1xuICAgIGlmIChzciE9PXRydWUpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSCBzZWN0aW9uIGRvZXMgbm90IG1hdGNoXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKG1wY1BhcmFtcy5jc0hhc2gsIFwiQ2lyY3VpdCBIYXNoOiBcIikpO1xuXG4gICAgYXdhaXQgZmQuY2xvc2UoKTtcbiAgICBhd2FpdCBmZEluaXQuY2xvc2UoKTtcblxuICAgIGZvciAobGV0IGk9bXBjUGFyYW1zLmNvbnRyaWJ1dGlvbnMubGVuZ3RoLTE7IGk+PTA7IGktLSkge1xuICAgICAgICBjb25zdCBjID0gbXBjUGFyYW1zLmNvbnRyaWJ1dGlvbnNbaV07XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiKTtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKGMuY29udHJpYnV0aW9uSGFzaCwgYGNvbnRyaWJ1dGlvbiAjJHtpKzF9ICR7Yy5uYW1lID8gYy5uYW1lIDogXCJcIn06YCkpO1xuICAgICAgICBpZiAoYy50eXBlID09IDEpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGBCZWFjb24gZ2VuZXJhdG9yOiAke21pc2MuYnl0ZUFycmF5MmhleChjLmJlYWNvbkhhc2gpfWApO1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oYEJlYWNvbiBpdGVyYXRpb25zIEV4cDogJHtjLm51bUl0ZXJhdGlvbnNFeHB9YCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXCIpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJaS2V5IE9rIVwiKTtcblxuICAgIHJldHVybiB0cnVlO1xuXG5cbiAgICBhc3luYyBmdW5jdGlvbiBzZWN0aW9uSGFzU2FtZVJhdGlvKGdyb3VwTmFtZSwgZmQxLCBzZWN0aW9uczEsIGZkMiwgc2VjdGlvbnMyLCBpZFNlY3Rpb24sIGcyc3AsIGcyc3B4LCBzZWN0aW9uTmFtZSkge1xuICAgICAgICBjb25zdCBNQVhfQ0hVTktfU0laRSA9IDE8PDIwO1xuICAgICAgICBjb25zdCBHID0gY3VydmVbZ3JvdXBOYW1lXTtcbiAgICAgICAgY29uc3Qgc0cgPSBHLkYubjgqMjtcbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24oZmQxLCBzZWN0aW9uczEsIGlkU2VjdGlvbik7XG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkMiwgc2VjdGlvbnMyLCBpZFNlY3Rpb24pO1xuXG4gICAgICAgIGxldCBSMSA9IEcuemVybztcbiAgICAgICAgbGV0IFIyID0gRy56ZXJvO1xuXG4gICAgICAgIGNvbnN0IG5Qb2ludHMgPSBzZWN0aW9uczFbaWRTZWN0aW9uXVswXS5zaXplIC8gc0c7XG5cbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPG5Qb2ludHM7IGkgKz0gTUFYX0NIVU5LX1NJWkUpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgU2FtZSByYXRpbyBjaGVjayAke3NlY3Rpb25OYW1lfTogICR7aX0vJHtuUG9pbnRzfWApO1xuICAgICAgICAgICAgY29uc3QgbiA9IE1hdGgubWluKG5Qb2ludHMgLSBpLCBNQVhfQ0hVTktfU0laRSk7XG4gICAgICAgICAgICBjb25zdCBiYXNlczEgPSBhd2FpdCBmZDEucmVhZChuKnNHKTtcbiAgICAgICAgICAgIGNvbnN0IGJhc2VzMiA9IGF3YWl0IGZkMi5yZWFkKG4qc0cpO1xuXG4gICAgICAgICAgICBjb25zdCBzY2FsYXJzID0gbWlzYy5nZXRSYW5kb21CeXRlcyg0Km4pO1xuXG4gICAgICAgICAgICBjb25zdCByMSA9IGF3YWl0IEcubXVsdGlFeHBBZmZpbmUoYmFzZXMxLCBzY2FsYXJzKTtcbiAgICAgICAgICAgIGNvbnN0IHIyID0gYXdhaXQgRy5tdWx0aUV4cEFmZmluZShiYXNlczIsIHNjYWxhcnMpO1xuXG4gICAgICAgICAgICBSMSA9IEcuYWRkKFIxLCByMSk7XG4gICAgICAgICAgICBSMiA9IEcuYWRkKFIyLCByMik7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgYmluRmlsZVV0aWxzLmVuZFJlYWRTZWN0aW9uKGZkMSk7XG4gICAgICAgIGF3YWl0IGJpbkZpbGVVdGlscy5lbmRSZWFkU2VjdGlvbihmZDIpO1xuXG4gICAgICAgIGlmIChuUG9pbnRzID09IDApIHJldHVybiB0cnVlO1xuXG4gICAgICAgIHNyID0gYXdhaXQgc2FtZVJhdGlvKGN1cnZlLCBSMSwgUjIsIGcyc3AsIGcyc3B4KTtcbiAgICAgICAgaWYgKHNyICE9PSB0cnVlKSByZXR1cm4gZmFsc2U7XG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gc2FtZVJhdGlvSCgpIHtcbiAgICAgICAgY29uc3QgTUFYX0NIVU5LX1NJWkUgPSAxPDwyMDtcbiAgICAgICAgY29uc3QgRyA9IGN1cnZlLkcxO1xuICAgICAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgICAgICBjb25zdCBzRyA9IEcuRi5uOCoyO1xuXG4gICAgICAgIGNvbnN0IHtmZDogZmRQVGF1LCBzZWN0aW9uczogc2VjdGlvbnNQVGF1fSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmluRmlsZShwVGF1RmlsZU5hbWUsIFwicHRhdVwiLCAxKTtcblxuICAgICAgICBsZXQgYnVmZl9yID0gbmV3IEJpZ0J1ZmZlcih6a2V5LmRvbWFpblNpemUgKiB6a2V5Lm44cik7XG5cbiAgICAgICAgY29uc3Qgc2VlZD0gbmV3IEFycmF5KDgpO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8ODsgaSsrKSB7XG4gICAgICAgICAgICBzZWVkW2ldID0gbWlzYy5yZWFkVUludDMyQkUobWlzYy5nZXRSYW5kb21CeXRlcyg0KSwgMCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgcm5nID0gbmV3IENoYUNoYShzZWVkKTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHprZXkuZG9tYWluU2l6ZS0xOyBpKyspIHsgICAvLyBOb3RlIHRoYXQgbGFzdCBvbmUgaXMgemVyb1xuICAgICAgICAgICAgY29uc3QgZSA9IEZyLmZyb21Sbmcocm5nKTtcbiAgICAgICAgICAgIEZyLnRvUnByTEUoYnVmZl9yLCBpKnprZXkubjhyLCBlKTtcbiAgICAgICAgfVxuICAgICAgICBGci50b1JwckxFKGJ1ZmZfciwgKHprZXkuZG9tYWluU2l6ZS0xKSp6a2V5Lm44ciwgRnIuemVybyk7XG5cbiAgICAgICAgbGV0IFIxID0gRy56ZXJvO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8emtleS5kb21haW5TaXplOyBpICs9IE1BWF9DSFVOS19TSVpFKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoYEggVmVyaWZpY2F0aW9uKHRhdSk6ICAke2l9LyR7emtleS5kb21haW5TaXplfWApO1xuICAgICAgICAgICAgY29uc3QgbiA9IE1hdGgubWluKHprZXkuZG9tYWluU2l6ZSAtIGksIE1BWF9DSFVOS19TSVpFKTtcblxuICAgICAgICAgICAgY29uc3QgYnVmZjEgPSBhd2FpdCBmZFBUYXUucmVhZChzRypuLCBzZWN0aW9uc1BUYXVbMl1bMF0ucCArIHprZXkuZG9tYWluU2l6ZSpzRyArIGkqc0cpO1xuICAgICAgICAgICAgY29uc3QgYnVmZjIgPSBhd2FpdCBmZFBUYXUucmVhZChzRypuLCBzZWN0aW9uc1BUYXVbMl1bMF0ucCArIGkqc0cpO1xuXG4gICAgICAgICAgICBjb25zdCBidWZmQiA9IGF3YWl0IGJhdGNoU3VidHJhY3QoYnVmZjEsIGJ1ZmYyKTtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZTID0gYnVmZl9yLnNsaWNlKGkqemtleS5uOHIsIChpK24pKnprZXkubjhyKTtcbiAgICAgICAgICAgIGNvbnN0IHIgPSBhd2FpdCBHLm11bHRpRXhwQWZmaW5lKGJ1ZmZCLCBidWZmUyk7XG5cbiAgICAgICAgICAgIFIxID0gRy5hZGQoUjEsIHIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2FsY3VsYXRlIG9kZCBjb2VmZmljaWVudHMgaW4gdHJhbnNmb3JtZWQgZG9tYWluXG5cbiAgICAgICAgYnVmZl9yID0gYXdhaXQgRnIuYmF0Y2hUb01vbnRnb21lcnkoYnVmZl9yKTtcbiAgICAgICAgLy8gY29uc3QgZmlyc3QgPSBjdXJ2ZS5Gci5uZWcoY3VydmUuRnIuaW52KGN1cnZlLkZyLmUoMikpKTtcbiAgICAgICAgLy8gV29ya3MqMiAgIGNvbnN0IGZpcnN0ID0gY3VydmUuRnIubmVnKGN1cnZlLkZyLmUoMikpO1xuXG5cbiAgICAgICAgbGV0IGZpcnN0O1xuXG4gICAgICAgIGlmICh6a2V5LnBvd2VyIDwgRnIucykge1xuICAgICAgICAgICAgZmlyc3QgPSBGci5uZWcoRnIuZSgyKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBzbWFsbF9tICA9IDIgKiogRnIucztcbiAgICAgICAgICAgIGNvbnN0IHNoaWZ0X3RvX3NtYWxsX20gPSBGci5leHAoRnIuc2hpZnQsIHNtYWxsX20pO1xuICAgICAgICAgICAgZmlyc3QgPSBGci5zdWIoIHNoaWZ0X3RvX3NtYWxsX20sIEZyLm9uZSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBjb25zdCBpbmMgPSBjdXJ2ZS5Gci5pbnYoY3VydmUuUEZyLndbemtleS5wb3dlcisxXSk7XG4gICAgICAgIGNvbnN0IGluYyA9IHprZXkucG93ZXIgPCBGci5zID8gRnIud1t6a2V5LnBvd2VyKzFdIDogRnIuc2hpZnQ7XG4gICAgICAgIGJ1ZmZfciA9IGF3YWl0IEZyLmJhdGNoQXBwbHlLZXkoYnVmZl9yLCBmaXJzdCwgaW5jKTtcbiAgICAgICAgYnVmZl9yID0gYXdhaXQgRnIuZmZ0KGJ1ZmZfcik7XG4gICAgICAgIGJ1ZmZfciA9IGF3YWl0IEZyLmJhdGNoRnJvbU1vbnRnb21lcnkoYnVmZl9yKTtcblxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuc3RhcnRSZWFkVW5pcXVlU2VjdGlvbihmZCwgc2VjdGlvbnMsIDkpO1xuICAgICAgICBsZXQgUjIgPSBHLnplcm87XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTx6a2V5LmRvbWFpblNpemU7IGkgKz0gTUFYX0NIVU5LX1NJWkUpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgSCBWZXJpZmljYXRpb24obGFncmFuZ2UpOiAgJHtpfS8ke3prZXkuZG9tYWluU2l6ZX1gKTtcbiAgICAgICAgICAgIGNvbnN0IG4gPSBNYXRoLm1pbih6a2V5LmRvbWFpblNpemUgLSBpLCBNQVhfQ0hVTktfU0laRSk7XG5cbiAgICAgICAgICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZC5yZWFkKHNHKm4pO1xuICAgICAgICAgICAgY29uc3QgYnVmZlMgPSBidWZmX3Iuc2xpY2UoaSp6a2V5Lm44ciwgKGkrbikqemtleS5uOHIpO1xuICAgICAgICAgICAgY29uc3QgciA9IGF3YWl0IEcubXVsdGlFeHBBZmZpbmUoYnVmZiwgYnVmZlMpO1xuXG4gICAgICAgICAgICBSMiA9IEcuYWRkKFIyLCByKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmQpO1xuXG4gICAgICAgIHNyID0gYXdhaXQgc2FtZVJhdGlvKGN1cnZlLCBSMSwgUjIsIHprZXkudmtfZGVsdGFfMiwgemtleUluaXQudmtfZGVsdGFfMik7XG4gICAgICAgIGlmIChzciAhPT0gdHJ1ZSkgcmV0dXJuIGZhbHNlO1xuXG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG5cbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiBiYXRjaFN1YnRyYWN0KGJ1ZmYxLCBidWZmMikge1xuICAgICAgICBjb25zdCBzRyA9IGN1cnZlLkcxLkYubjgqMjtcbiAgICAgICAgY29uc3QgblBvaW50cyA9IGJ1ZmYxLmJ5dGVMZW5ndGggLyBzRztcbiAgICAgICAgY29uc3QgY29uY3VycmVuY3k9IGN1cnZlLnRtLmNvbmN1cnJlbmN5O1xuICAgICAgICBjb25zdCBuUG9pbnRzUGVyVGhyZWFkID0gTWF0aC5mbG9vcihuUG9pbnRzIC8gY29uY3VycmVuY3kpO1xuICAgICAgICBjb25zdCBvcFByb21pc2VzID0gW107XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxjb25jdXJyZW5jeTsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgbjtcbiAgICAgICAgICAgIGlmIChpPCBjb25jdXJyZW5jeS0xKSB7XG4gICAgICAgICAgICAgICAgbiA9IG5Qb2ludHNQZXJUaHJlYWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG4gPSBuUG9pbnRzIC0gaSpuUG9pbnRzUGVyVGhyZWFkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG49PTApIGNvbnRpbnVlO1xuXG4gICAgICAgICAgICBjb25zdCBzdWJCdWZmMSA9IGJ1ZmYxLnNsaWNlKGkqblBvaW50c1BlclRocmVhZCpzRzEsIChpKm5Qb2ludHNQZXJUaHJlYWQrbikqc0cxKTtcbiAgICAgICAgICAgIGNvbnN0IHN1YkJ1ZmYyID0gYnVmZjIuc2xpY2UoaSpuUG9pbnRzUGVyVGhyZWFkKnNHMSwgKGkqblBvaW50c1BlclRocmVhZCtuKSpzRzEpO1xuICAgICAgICAgICAgb3BQcm9taXNlcy5wdXNoKGJhdGNoU3VidHJhY3RUaHJlYWQoc3ViQnVmZjEsIHN1YkJ1ZmYyKSk7XG4gICAgICAgIH1cblxuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UuYWxsKG9wUHJvbWlzZXMpO1xuXG4gICAgICAgIGNvbnN0IGZ1bGxCdWZmT3V0ID0gbmV3IFVpbnQ4QXJyYXkoblBvaW50cypzRyk7XG4gICAgICAgIGxldCBwID0wO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8cmVzdWx0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBmdWxsQnVmZk91dC5zZXQocmVzdWx0W2ldWzBdLCBwKTtcbiAgICAgICAgICAgIHArPXJlc3VsdFtpXVswXS5ieXRlTGVuZ3RoO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZ1bGxCdWZmT3V0O1xuICAgIH1cblxuXG4gICAgYXN5bmMgZnVuY3Rpb24gYmF0Y2hTdWJ0cmFjdFRocmVhZChidWZmMSwgYnVmZjIpIHtcbiAgICAgICAgY29uc3Qgc0cxID0gY3VydmUuRzEuRi5uOCoyO1xuICAgICAgICBjb25zdCBzR21pZCA9IGN1cnZlLkcxLkYubjgqMztcbiAgICAgICAgY29uc3QgblBvaW50cyA9IGJ1ZmYxLmJ5dGVMZW5ndGgvc0cxO1xuICAgICAgICBjb25zdCB0YXNrID0gW107XG4gICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkFMTE9DU0VUXCIsIHZhcjogMCwgYnVmZjogYnVmZjF9KTtcbiAgICAgICAgdGFzay5wdXNoKHtjbWQ6IFwiQUxMT0NTRVRcIiwgdmFyOiAxLCBidWZmOiBidWZmMn0pO1xuICAgICAgICB0YXNrLnB1c2goe2NtZDogXCJBTExPQ1wiLCB2YXI6IDIsIGxlbjogblBvaW50cypzR21pZH0pO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8blBvaW50czsgaSsrKSB7XG4gICAgICAgICAgICB0YXNrLnB1c2goe1xuICAgICAgICAgICAgICAgIGNtZDogXCJDQUxMXCIsXG4gICAgICAgICAgICAgICAgZm5OYW1lOiBcImcxbV9zdWJBZmZpbmVcIixcbiAgICAgICAgICAgICAgICBwYXJhbXM6IFtcbiAgICAgICAgICAgICAgICAgICAge3ZhcjogMCwgb2Zmc2V0OiBpKnNHMX0sXG4gICAgICAgICAgICAgICAgICAgIHt2YXI6IDEsIG9mZnNldDogaSpzRzF9LFxuICAgICAgICAgICAgICAgICAgICB7dmFyOiAyLCBvZmZzZXQ6IGkqc0dtaWR9LFxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkNBTExcIiwgZm5OYW1lOiBcImcxbV9iYXRjaFRvQWZmaW5lXCIsIHBhcmFtczogW1xuICAgICAgICAgICAge3ZhcjogMn0sXG4gICAgICAgICAgICB7dmFsOiBuUG9pbnRzfSxcbiAgICAgICAgICAgIHt2YXI6IDJ9LFxuICAgICAgICBdfSk7XG4gICAgICAgIHRhc2sucHVzaCh7Y21kOiBcIkdFVFwiLCBvdXQ6IDAsIHZhcjogMiwgbGVuOiBuUG9pbnRzKnNHMX0pO1xuXG4gICAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IGN1cnZlLnRtLnF1ZXVlQWN0aW9uKHRhc2spO1xuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG59XG5cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCBuZXdaS2V5IGZyb20gXCIuL3prZXlfbmV3LmpzXCI7XG5pbXBvcnQgcGhhc2UydmVyaWZ5RnJvbUluaXQgZnJvbSBcIi4vemtleV92ZXJpZnlfZnJvbWluaXQuanNcIjtcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gcGhhc2UydmVyaWZ5RnJvbVIxY3MocjFjc0ZpbGVOYW1lLCBwVGF1RmlsZU5hbWUsIHprZXlGaWxlTmFtZSwgbG9nZ2VyKSB7XG5cbiAgICAvLyBjb25zdCBpbml0RmlsZU5hbWUgPSBcIn5cIiArIHprZXlGaWxlTmFtZSArIFwiLmluaXRcIjtcbiAgICBjb25zdCBpbml0RmlsZU5hbWUgPSB7dHlwZTogXCJiaWdNZW1cIn07XG4gICAgYXdhaXQgbmV3WktleShyMWNzRmlsZU5hbWUsIHBUYXVGaWxlTmFtZSwgaW5pdEZpbGVOYW1lLCBsb2dnZXIpO1xuXG4gICAgcmV0dXJuIGF3YWl0IHBoYXNlMnZlcmlmeUZyb21Jbml0KGluaXRGaWxlTmFtZSwgcFRhdUZpbGVOYW1lLCB6a2V5RmlsZU5hbWUsIGxvZ2dlcik7XG59XG5cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCAqIGFzIGJpbkZpbGVVdGlscyBmcm9tIFwiQGlkZW4zL2JpbmZpbGV1dGlsc1wiO1xuaW1wb3J0ICogYXMgemtleVV0aWxzIGZyb20gXCIuL3prZXlfdXRpbHMuanNcIjtcbmltcG9ydCB7IGdldEN1cnZlRnJvbVEgYXMgZ2V0Q3VydmUgfSBmcm9tIFwiLi9jdXJ2ZXMuanNcIjtcbmltcG9ydCAqIGFzIG1pc2MgZnJvbSBcIi4vbWlzYy5qc1wiO1xuaW1wb3J0IHsgYmxha2UyYiB9IGZyb20gXCJAbm9ibGUvaGFzaGVzL2JsYWtlMi5qc1wiO1xuaW1wb3J0ICogYXMgdXRpbHMgZnJvbSBcIi4vemtleV91dGlscy5qc1wiO1xuaW1wb3J0IHsgaGFzaFRvRzIgYXMgaGFzaFRvRzIgfSBmcm9tIFwiLi9rZXlwYWlyLmpzXCI7XG5pbXBvcnQgeyBhcHBseUtleVRvU2VjdGlvbiB9IGZyb20gXCIuL21wY19hcHBseWtleS5qc1wiO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBwaGFzZTJjb250cmlidXRlKHprZXlOYW1lT2xkLCB6a2V5TmFtZU5ldywgbmFtZSwgZW50cm9weSwgbG9nZ2VyKSB7XG5cbiAgICBjb25zdCB7ZmQ6IGZkT2xkLCBzZWN0aW9uczogc2VjdGlvbnN9ID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRCaW5GaWxlKHprZXlOYW1lT2xkLCBcInprZXlcIiwgMik7XG4gICAgY29uc3QgemtleSA9IGF3YWl0IHprZXlVdGlscy5yZWFkSGVhZGVyKGZkT2xkLCBzZWN0aW9ucyk7XG4gICAgaWYgKHprZXkucHJvdG9jb2wgIT0gXCJncm90aDE2XCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiemtleSBmaWxlIGlzIG5vdCBncm90aDE2XCIpO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgZ2V0Q3VydmUoemtleS5xKTtcblxuICAgIGNvbnN0IG1wY1BhcmFtcyA9IGF3YWl0IHprZXlVdGlscy5yZWFkTVBDUGFyYW1zKGZkT2xkLCBjdXJ2ZSwgc2VjdGlvbnMpO1xuXG4gICAgY29uc3QgZmROZXcgPSBhd2FpdCBiaW5GaWxlVXRpbHMuY3JlYXRlQmluRmlsZSh6a2V5TmFtZU5ldywgXCJ6a2V5XCIsIDEsIDEwKTtcblxuXG4gICAgY29uc3Qgcm5nID0gYXdhaXQgbWlzYy5nZXRSYW5kb21SbmcoZW50cm9weSk7XG5cbiAgICBjb25zdCB0cmFuc2NyaXB0SGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7XG4gICAgdHJhbnNjcmlwdEhhc2hlci51cGRhdGUobXBjUGFyYW1zLmNzSGFzaCk7XG4gICAgZm9yIChsZXQgaT0wOyBpPG1wY1BhcmFtcy5jb250cmlidXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHV0aWxzLmhhc2hQdWJLZXkodHJhbnNjcmlwdEhhc2hlciwgY3VydmUsIG1wY1BhcmFtcy5jb250cmlidXRpb25zW2ldKTtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJDb250cmlidXRpb24gPSB7fTtcbiAgICBjdXJDb250cmlidXRpb24uZGVsdGEgPSB7fTtcbiAgICBjdXJDb250cmlidXRpb24uZGVsdGEucHJ2S2V5ID0gY3VydmUuRnIuZnJvbVJuZyhybmcpO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMV9zID0gY3VydmUuRzEudG9BZmZpbmUoY3VydmUuRzEuZnJvbVJuZyhybmcpKTtcbiAgICBjdXJDb250cmlidXRpb24uZGVsdGEuZzFfc3ggPSBjdXJ2ZS5HMS50b0FmZmluZShjdXJ2ZS5HMS50aW1lc0ZyKGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMV9zLCBjdXJDb250cmlidXRpb24uZGVsdGEucHJ2S2V5KSk7XG4gICAgdXRpbHMuaGFzaEcxKHRyYW5zY3JpcHRIYXNoZXIsIGN1cnZlLCBjdXJDb250cmlidXRpb24uZGVsdGEuZzFfcyk7XG4gICAgdXRpbHMuaGFzaEcxKHRyYW5zY3JpcHRIYXNoZXIsIGN1cnZlLCBjdXJDb250cmlidXRpb24uZGVsdGEuZzFfc3gpO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi50cmFuc2NyaXB0ID0gdHJhbnNjcmlwdEhhc2hlci5kaWdlc3QoKTtcbiAgICBjdXJDb250cmlidXRpb24uZGVsdGEuZzJfc3AgPSBoYXNoVG9HMihjdXJ2ZSwgY3VyQ29udHJpYnV0aW9uLnRyYW5zY3JpcHQpO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMl9zcHggPSBjdXJ2ZS5HMi50b0FmZmluZShjdXJ2ZS5HMi50aW1lc0ZyKGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMl9zcCwgY3VyQ29udHJpYnV0aW9uLmRlbHRhLnBydktleSkpO1xuXG4gICAgemtleS52a19kZWx0YV8xID0gY3VydmUuRzEudGltZXNGcih6a2V5LnZrX2RlbHRhXzEsIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5wcnZLZXkpO1xuICAgIHprZXkudmtfZGVsdGFfMiA9IGN1cnZlLkcyLnRpbWVzRnIoemtleS52a19kZWx0YV8yLCBjdXJDb250cmlidXRpb24uZGVsdGEucHJ2S2V5KTtcblxuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YUFmdGVyID0gemtleS52a19kZWx0YV8xO1xuXG4gICAgY3VyQ29udHJpYnV0aW9uLnR5cGUgPSAwO1xuICAgIGlmIChuYW1lKSBjdXJDb250cmlidXRpb24ubmFtZSA9IG5hbWU7XG5cbiAgICBtcGNQYXJhbXMuY29udHJpYnV0aW9ucy5wdXNoKGN1ckNvbnRyaWJ1dGlvbik7XG5cbiAgICBhd2FpdCB6a2V5VXRpbHMud3JpdGVIZWFkZXIoZmROZXcsIHprZXkpO1xuXG4gICAgLy8gSUNcbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgMyk7XG5cbiAgICAvLyBDb2VmZnMgKEtlZXAgb3JpZ2luYWwpXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDQpO1xuXG4gICAgLy8gQSBTZWN0aW9uXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDUpO1xuXG4gICAgLy8gQjEgU2VjdGlvblxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5jb3B5U2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCA2KTtcblxuICAgIC8vIEIyIFNlY3Rpb25cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgNyk7XG5cbiAgICBjb25zdCBpbnZEZWx0YSA9IGN1cnZlLkZyLmludihjdXJDb250cmlidXRpb24uZGVsdGEucHJ2S2V5KTtcbiAgICBhd2FpdCBhcHBseUtleVRvU2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCA4LCBjdXJ2ZSwgXCJHMVwiLCBpbnZEZWx0YSwgY3VydmUuRnIuZSgxKSwgXCJMIFNlY3Rpb25cIiwgbG9nZ2VyKTtcbiAgICBhd2FpdCBhcHBseUtleVRvU2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCA5LCBjdXJ2ZSwgXCJHMVwiLCBpbnZEZWx0YSwgY3VydmUuRnIuZSgxKSwgXCJIIFNlY3Rpb25cIiwgbG9nZ2VyKTtcblxuICAgIGF3YWl0IHprZXlVdGlscy53cml0ZU1QQ1BhcmFtcyhmZE5ldywgY3VydmUsIG1wY1BhcmFtcyk7XG5cbiAgICBhd2FpdCBmZE9sZC5jbG9zZSgpO1xuICAgIGF3YWl0IGZkTmV3LmNsb3NlKCk7XG5cbiAgICBjb25zdCBjb250cmlidXRpb25IYXNoZXIgPSBibGFrZTJiLmNyZWF0ZSh7IGRrTGVuOiA2NCB9KTtcbiAgICB1dGlscy5oYXNoUHViS2V5KGNvbnRyaWJ1dGlvbkhhc2hlciwgY3VydmUsIGN1ckNvbnRyaWJ1dGlvbik7XG5cbiAgICBjb25zdCBjb250cmlidXRpb25IYXNoID0gY29udHJpYnV0aW9uSGFzaGVyLmRpZ2VzdCgpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKG1wY1BhcmFtcy5jc0hhc2gsIFwiQ2lyY3VpdCBIYXNoOiBcIikpO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKG1pc2MuZm9ybWF0SGFzaChjb250cmlidXRpb25IYXNoLCBcIkNvbnRyaWJ1dGlvbiBIYXNoOiBcIikpO1xuXG4gICAgcmV0dXJuIGNvbnRyaWJ1dGlvbkhhc2g7XG59XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCAqIGFzIHprZXlVdGlscyBmcm9tIFwiLi96a2V5X3V0aWxzLmpzXCI7XG5pbXBvcnQgeyBnZXRDdXJ2ZUZyb21RIGFzIGdldEN1cnZlIH0gZnJvbSBcIi4vY3VydmVzLmpzXCI7XG5pbXBvcnQgKiBhcyBtaXNjIGZyb20gXCIuL21pc2MuanNcIjtcbmltcG9ydCB7IGJsYWtlMmIgfSBmcm9tIFwiQG5vYmxlL2hhc2hlcy9ibGFrZTIuanNcIjtcbmltcG9ydCAqIGFzIHV0aWxzIGZyb20gXCIuL3prZXlfdXRpbHMuanNcIjtcbmltcG9ydCB7IGhhc2hUb0cyIGFzIGhhc2hUb0cyIH0gZnJvbSBcIi4va2V5cGFpci5qc1wiO1xuaW1wb3J0IHsgYXBwbHlLZXlUb1NlY3Rpb24gfSBmcm9tIFwiLi9tcGNfYXBwbHlrZXkuanNcIjtcblxuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBiZWFjb24oemtleU5hbWVPbGQsIHprZXlOYW1lTmV3LCBuYW1lLCBiZWFjb25IYXNoU3RyLCBudW1JdGVyYXRpb25zRXhwLCBsb2dnZXIpIHtcbiAgICBjb25zdCBiZWFjb25IYXNoID0gbWlzYy5oZXgyQnl0ZUFycmF5KGJlYWNvbkhhc2hTdHIpO1xuICAgIGlmICggICAoYmVhY29uSGFzaC5ieXRlTGVuZ3RoID09IDApXG4gICAgICAgIHx8IChiZWFjb25IYXNoLmJ5dGVMZW5ndGgqMiAhPWJlYWNvbkhhc2hTdHIubGVuZ3RoKSlcbiAgICB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIkludmFsaWQgQmVhY29uIEhhc2guIChJdCBtdXN0IGJlIGEgdmFsaWQgaGV4YWRlY2ltYWwgc2VxdWVuY2UpXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChiZWFjb25IYXNoLmxlbmd0aD49MjU2KSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIk1heGltdW0gbGVuZ3RoIG9mIGJlYWNvbiBoYXNoIGlzIDI1NSBieXRlc1wiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIG51bUl0ZXJhdGlvbnNFeHAgPSBwYXJzZUludChudW1JdGVyYXRpb25zRXhwKTtcbiAgICBpZiAoKG51bUl0ZXJhdGlvbnNFeHA8MTApfHwobnVtSXRlcmF0aW9uc0V4cD42MykpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiSW52YWxpZCBudW1JdGVyYXRpb25zRXhwLiAoTXVzdCBiZSBiZXR3ZWVuIDEwIGFuZCA2MylcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cblxuICAgIGNvbnN0IHtmZDogZmRPbGQsIHNlY3Rpb25zOiBzZWN0aW9uc30gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUoemtleU5hbWVPbGQsIFwiemtleVwiLCAyKTtcbiAgICBjb25zdCB6a2V5ID0gYXdhaXQgemtleVV0aWxzLnJlYWRIZWFkZXIoZmRPbGQsIHNlY3Rpb25zKTtcblxuICAgIGlmICh6a2V5LnByb3RvY29sICE9IFwiZ3JvdGgxNlwiKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcInprZXkgZmlsZSBpcyBub3QgZ3JvdGgxNlwiKTtcbiAgICB9XG5cblxuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgZ2V0Q3VydmUoemtleS5xKTtcblxuICAgIGNvbnN0IG1wY1BhcmFtcyA9IGF3YWl0IHprZXlVdGlscy5yZWFkTVBDUGFyYW1zKGZkT2xkLCBjdXJ2ZSwgc2VjdGlvbnMpO1xuXG4gICAgY29uc3QgZmROZXcgPSBhd2FpdCBiaW5GaWxlVXRpbHMuY3JlYXRlQmluRmlsZSh6a2V5TmFtZU5ldywgXCJ6a2V5XCIsIDEsIDEwKTtcblxuICAgIGNvbnN0IHJuZyA9IGF3YWl0IG1pc2Mucm5nRnJvbUJlYWNvblBhcmFtcyhiZWFjb25IYXNoLCBudW1JdGVyYXRpb25zRXhwKTtcblxuICAgIGNvbnN0IHRyYW5zY3JpcHRIYXNoZXIgPSBibGFrZTJiLmNyZWF0ZSh7IGRrTGVuOiA2NCB9KTs7XG4gICAgdHJhbnNjcmlwdEhhc2hlci51cGRhdGUobXBjUGFyYW1zLmNzSGFzaCk7XG4gICAgZm9yIChsZXQgaT0wOyBpPG1wY1BhcmFtcy5jb250cmlidXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHV0aWxzLmhhc2hQdWJLZXkodHJhbnNjcmlwdEhhc2hlciwgY3VydmUsIG1wY1BhcmFtcy5jb250cmlidXRpb25zW2ldKTtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJDb250cmlidXRpb24gPSB7fTtcbiAgICBjdXJDb250cmlidXRpb24uZGVsdGEgPSB7fTtcbiAgICBjdXJDb250cmlidXRpb24uZGVsdGEucHJ2S2V5ID0gY3VydmUuRnIuZnJvbVJuZyhybmcpO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMV9zID0gY3VydmUuRzEudG9BZmZpbmUoY3VydmUuRzEuZnJvbVJuZyhybmcpKTtcbiAgICBjdXJDb250cmlidXRpb24uZGVsdGEuZzFfc3ggPSBjdXJ2ZS5HMS50b0FmZmluZShjdXJ2ZS5HMS50aW1lc0ZyKGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMV9zLCBjdXJDb250cmlidXRpb24uZGVsdGEucHJ2S2V5KSk7XG4gICAgdXRpbHMuaGFzaEcxKHRyYW5zY3JpcHRIYXNoZXIsIGN1cnZlLCBjdXJDb250cmlidXRpb24uZGVsdGEuZzFfcyk7XG4gICAgdXRpbHMuaGFzaEcxKHRyYW5zY3JpcHRIYXNoZXIsIGN1cnZlLCBjdXJDb250cmlidXRpb24uZGVsdGEuZzFfc3gpO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi50cmFuc2NyaXB0ID0gdHJhbnNjcmlwdEhhc2hlci5kaWdlc3QoKTtcbiAgICBjdXJDb250cmlidXRpb24uZGVsdGEuZzJfc3AgPSBoYXNoVG9HMihjdXJ2ZSwgY3VyQ29udHJpYnV0aW9uLnRyYW5zY3JpcHQpO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMl9zcHggPSBjdXJ2ZS5HMi50b0FmZmluZShjdXJ2ZS5HMi50aW1lc0ZyKGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMl9zcCwgY3VyQ29udHJpYnV0aW9uLmRlbHRhLnBydktleSkpO1xuXG4gICAgemtleS52a19kZWx0YV8xID0gY3VydmUuRzEudGltZXNGcih6a2V5LnZrX2RlbHRhXzEsIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5wcnZLZXkpO1xuICAgIHprZXkudmtfZGVsdGFfMiA9IGN1cnZlLkcyLnRpbWVzRnIoemtleS52a19kZWx0YV8yLCBjdXJDb250cmlidXRpb24uZGVsdGEucHJ2S2V5KTtcblxuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YUFmdGVyID0gemtleS52a19kZWx0YV8xO1xuXG4gICAgY3VyQ29udHJpYnV0aW9uLnR5cGUgPSAxO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5udW1JdGVyYXRpb25zRXhwID0gbnVtSXRlcmF0aW9uc0V4cDtcbiAgICBjdXJDb250cmlidXRpb24uYmVhY29uSGFzaCA9IGJlYWNvbkhhc2g7XG5cbiAgICBpZiAobmFtZSkgY3VyQ29udHJpYnV0aW9uLm5hbWUgPSBuYW1lO1xuXG4gICAgbXBjUGFyYW1zLmNvbnRyaWJ1dGlvbnMucHVzaChjdXJDb250cmlidXRpb24pO1xuXG4gICAgYXdhaXQgemtleVV0aWxzLndyaXRlSGVhZGVyKGZkTmV3LCB6a2V5KTtcblxuICAgIC8vIElDXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDMpO1xuXG4gICAgLy8gQ29lZmZzIChLZWVwIG9yaWdpbmFsKVxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5jb3B5U2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCA0KTtcblxuICAgIC8vIEEgU2VjdGlvblxuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5jb3B5U2VjdGlvbihmZE9sZCwgc2VjdGlvbnMsIGZkTmV3LCA1KTtcblxuICAgIC8vIEIxIFNlY3Rpb25cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuY29weVNlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgNik7XG5cbiAgICAvLyBCMiBTZWN0aW9uXG4gICAgYXdhaXQgYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uKGZkT2xkLCBzZWN0aW9ucywgZmROZXcsIDcpO1xuXG4gICAgY29uc3QgaW52RGVsdGEgPSBjdXJ2ZS5Gci5pbnYoY3VyQ29udHJpYnV0aW9uLmRlbHRhLnBydktleSk7XG4gICAgYXdhaXQgYXBwbHlLZXlUb1NlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgOCwgY3VydmUsIFwiRzFcIiwgaW52RGVsdGEsIGN1cnZlLkZyLmUoMSksIFwiTCBTZWN0aW9uXCIsIGxvZ2dlcik7XG4gICAgYXdhaXQgYXBwbHlLZXlUb1NlY3Rpb24oZmRPbGQsIHNlY3Rpb25zLCBmZE5ldywgOSwgY3VydmUsIFwiRzFcIiwgaW52RGVsdGEsIGN1cnZlLkZyLmUoMSksIFwiSCBTZWN0aW9uXCIsIGxvZ2dlcik7XG5cbiAgICBhd2FpdCB6a2V5VXRpbHMud3JpdGVNUENQYXJhbXMoZmROZXcsIGN1cnZlLCBtcGNQYXJhbXMpO1xuXG4gICAgYXdhaXQgZmRPbGQuY2xvc2UoKTtcbiAgICBhd2FpdCBmZE5ldy5jbG9zZSgpO1xuXG4gICAgY29uc3QgY29udHJpYnV0aW9uSGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7O1xuICAgIHV0aWxzLmhhc2hQdWJLZXkoY29udHJpYnV0aW9uSGFzaGVyLCBjdXJ2ZSwgY3VyQ29udHJpYnV0aW9uKTtcblxuICAgIGNvbnN0IGNvbnRyaWJ1dGlvbkhhc2ggPSBjb250cmlidXRpb25IYXNoZXIuZGlnZXN0KCk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhtaXNjLmZvcm1hdEhhc2goY29udHJpYnV0aW9uSGFzaCwgXCJDb250cmlidXRpb24gSGFzaDogXCIpKTtcblxuICAgIHJldHVybiBjb250cmlidXRpb25IYXNoO1xufVxuIiwiaW1wb3J0IHsgcmVhZFpLZXkgYXMgcmVhZFpLZXkgfSBmcm9tIFwiLi96a2V5X3V0aWxzLmpzXCI7XG5pbXBvcnQgeyB1dGlscyB9IGZyb20gXCJmZmphdmFzY3JpcHRcIjtcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gemtleUV4cG9ydEpzb24oemtleUZpbGVOYW1lKSB7XG5cbiAgICBjb25zdCB6S2V5ID0gYXdhaXQgcmVhZFpLZXkoemtleUZpbGVOYW1lLCB0cnVlKTtcbiAgICBkZWxldGUgektleS5jdXJ2ZTtcbiAgICBkZWxldGUgektleS5GO1xuXG4gICAgcmV0dXJuIHV0aWxzLnN0cmluZ2lmeUJpZ0ludHMoektleSk7XG59XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDE4IDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG4vLyBGb3JtYXQgb2YgdGhlIG91dHB1dFxuLy8gICAgICBIYXNoIG9mIHRoZSBsYXN0IGNvbnRyaWJ1dGlvbiAgNjQgQnl0ZXNcbi8vICAgICAgMl5OKjItMSBUYXVHMSBQb2ludHMgKGNvbXByZXNzZWQpXG4vLyAgICAgIDJeTiBUYXVHMiBQb2ludHMgKGNvbXByZXNzZWQpXG4vLyAgICAgIDJeTiBBbHBoYVRhdUcxIFBvaW50cyAoY29tcHJlc3NlZClcbi8vICAgICAgMl5OIEJldGFUYXVHMSBQb2ludHMgKGNvbXByZXNzZWQpXG4vLyAgICAgIFB1YmxpYyBLZXlcbi8vICAgICAgICAgIEJldGFHMiAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcxKnMgKGNvbXByZXNzZWQpXG4vLyAgICAgICAgICBHMSpzKnRhdSAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcxKnQgKGNvbXByZXNzZWQpXG4vLyAgICAgICAgICBHMSp0KmFscGhhIChjb21wcmVzc2VkKVxuLy8gICAgICAgICAgRzEqdSAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcxKnUqYmV0YSAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcyKnNwKnRhdSAoY29tcHJlc3NlZClcbi8vICAgICAgICAgIEcyKnRwKmFscGhhIChjb21wcmVzc2VkKVxuLy8gICAgICAgICAgRzIqdXAqYmV0YSAoY29tcHJlc3NlZClcblxuaW1wb3J0ICogYXMgZmFzdEZpbGUgZnJvbSBcImZhc3RmaWxlXCI7XG5pbXBvcnQgeyBibGFrZTJiIH0gZnJvbSBcIkBub2JsZS9oYXNoZXMvYmxha2UyLmpzXCI7XG5pbXBvcnQgKiBhcyB1dGlscyBmcm9tIFwiLi96a2V5X3V0aWxzLmpzXCI7XG5pbXBvcnQgKiBhcyBtaXNjIGZyb20gXCIuL21pc2MuanNcIjtcbmltcG9ydCB7IGFwcGx5S2V5VG9DaGFsbGVuZ2VTZWN0aW9uIH0gZnJvbSBcIi4vbXBjX2FwcGx5a2V5LmpzXCI7XG5pbXBvcnQgeyBoYXNoUHViS2V5IH0gZnJvbSBcIi4vemtleV91dGlscy5qc1wiO1xuaW1wb3J0IHsgaGFzaFRvRzIgYXMgaGFzaFRvRzIgfSBmcm9tIFwiLi9rZXlwYWlyLmpzXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIGJlbGxtYW5Db250cmlidXRlKGN1cnZlLCBjaGFsbGVuZ2VGaWxlbmFtZSwgcmVzcG9uc2VGaWxlTmFtZSwgZW50cm9weSwgbG9nZ2VyKSB7XG4gICAgY29uc3Qgcm5nID0gYXdhaXQgbWlzYy5nZXRSYW5kb21SbmcoZW50cm9weSk7XG5cbiAgICBjb25zdCBkZWx0YSA9IGN1cnZlLkZyLmZyb21Sbmcocm5nKTtcbiAgICBjb25zdCBpbnZEZWx0YSA9IGN1cnZlLkZyLmludihkZWx0YSk7XG5cbiAgICBjb25zdCBzRzEgPSBjdXJ2ZS5HMS5GLm44KjI7XG4gICAgY29uc3Qgc0cyID0gY3VydmUuRzIuRi5uOCoyO1xuXG4gICAgY29uc3QgZmRGcm9tID0gYXdhaXQgZmFzdEZpbGUucmVhZEV4aXN0aW5nKGNoYWxsZW5nZUZpbGVuYW1lKTtcbiAgICBjb25zdCBmZFRvID0gYXdhaXQgZmFzdEZpbGUuY3JlYXRlT3ZlcnJpZGUocmVzcG9uc2VGaWxlTmFtZSk7XG5cblxuICAgIGF3YWl0IGNvcHkoc0cxKTsgLy8gYWxwaGExXG4gICAgYXdhaXQgY29weShzRzEpOyAvLyBiZXRhMVxuICAgIGF3YWl0IGNvcHkoc0cyKTsgLy8gYmV0YTJcbiAgICBhd2FpdCBjb3B5KHNHMik7IC8vIGdhbW1hMlxuICAgIGNvbnN0IG9sZERlbHRhMSA9IGF3YWl0IHJlYWRHMSgpO1xuICAgIGNvbnN0IGRlbHRhMSA9IGN1cnZlLkcxLnRpbWVzRnIob2xkRGVsdGExLCBkZWx0YSk7XG4gICAgYXdhaXQgd3JpdGVHMShkZWx0YTEpO1xuICAgIGNvbnN0IG9sZERlbHRhMiA9IGF3YWl0IHJlYWRHMigpO1xuICAgIGNvbnN0IGRlbHRhMiA9IGN1cnZlLkcyLnRpbWVzRnIob2xkRGVsdGEyLCBkZWx0YSk7XG4gICAgYXdhaXQgd3JpdGVHMihkZWx0YTIpO1xuXG4gICAgLy8gSUNcbiAgICBjb25zdCBuSUMgPSBhd2FpdCBmZEZyb20ucmVhZFVCRTMyKCk7XG4gICAgYXdhaXQgZmRUby53cml0ZVVCRTMyKG5JQyk7XG4gICAgYXdhaXQgY29weShuSUMqc0cxKTtcblxuICAgIC8vIEhcbiAgICBjb25zdCBuSCA9IGF3YWl0IGZkRnJvbS5yZWFkVUJFMzIoKTtcbiAgICBhd2FpdCBmZFRvLndyaXRlVUJFMzIobkgpO1xuICAgIGF3YWl0IGFwcGx5S2V5VG9DaGFsbGVuZ2VTZWN0aW9uKGZkRnJvbSwgZmRUbywgbnVsbCwgY3VydmUsIFwiRzFcIiwgbkgsIGludkRlbHRhLCBjdXJ2ZS5Gci5lKDEpLCBcIlVOQ09NUFJFU1NFRFwiLCBcIkhcIiwgbG9nZ2VyKTtcblxuICAgIC8vIExcbiAgICBjb25zdCBuTCA9IGF3YWl0IGZkRnJvbS5yZWFkVUJFMzIoKTtcbiAgICBhd2FpdCBmZFRvLndyaXRlVUJFMzIobkwpO1xuICAgIGF3YWl0IGFwcGx5S2V5VG9DaGFsbGVuZ2VTZWN0aW9uKGZkRnJvbSwgZmRUbywgbnVsbCwgY3VydmUsIFwiRzFcIiwgbkwsIGludkRlbHRhLCBjdXJ2ZS5Gci5lKDEpLCBcIlVOQ09NUFJFU1NFRFwiLCBcIkxcIiwgbG9nZ2VyKTtcblxuICAgIC8vIEFcbiAgICBjb25zdCBuQSA9IGF3YWl0IGZkRnJvbS5yZWFkVUJFMzIoKTtcbiAgICBhd2FpdCBmZFRvLndyaXRlVUJFMzIobkEpO1xuICAgIGF3YWl0IGNvcHkobkEqc0cxKTtcblxuICAgIC8vIEIxXG4gICAgY29uc3QgbkIxID0gYXdhaXQgZmRGcm9tLnJlYWRVQkUzMigpO1xuICAgIGF3YWl0IGZkVG8ud3JpdGVVQkUzMihuQjEpO1xuICAgIGF3YWl0IGNvcHkobkIxKnNHMSk7XG5cbiAgICAvLyBCMlxuICAgIGNvbnN0IG5CMiA9IGF3YWl0IGZkRnJvbS5yZWFkVUJFMzIoKTtcbiAgICBhd2FpdCBmZFRvLndyaXRlVUJFMzIobkIyKTtcbiAgICBhd2FpdCBjb3B5KG5CMipzRzIpO1xuXG5cbiAgICAvLy8vLy8vLy8vXG4gICAgLy8vIFJlYWQgY29udHJpYnV0aW9uc1xuICAgIC8vLy8vLy8vLy9cbiAgICBjb25zdCB0cmFuc2NyaXB0SGFzaGVyID0gYmxha2UyYi5jcmVhdGUoeyBka0xlbjogNjQgfSk7O1xuXG4gICAgY29uc3QgbXBjUGFyYW1zID0ge307XG4gICAgLy8gY3NIYXNoXG4gICAgbXBjUGFyYW1zLmNzSGFzaCA9ICBhd2FpdCBmZEZyb20ucmVhZCg2NCk7XG4gICAgdHJhbnNjcmlwdEhhc2hlci51cGRhdGUobXBjUGFyYW1zLmNzSGFzaCk7XG5cbiAgICBjb25zdCBuQ29udHJpYnV0aW9ucyA9IGF3YWl0IGZkRnJvbS5yZWFkVUJFMzIoKTtcbiAgICBtcGNQYXJhbXMuY29udHJpYnV0aW9ucyA9IFtdO1xuICAgIGZvciAobGV0IGk9MDsgaTxuQ29udHJpYnV0aW9uczsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGMgPSB7IGRlbHRhOnt9IH07XG4gICAgICAgIGMuZGVsdGFBZnRlciA9IGF3YWl0IHJlYWRHMSgpO1xuICAgICAgICBjLmRlbHRhLmcxX3MgPSBhd2FpdCByZWFkRzEoKTtcbiAgICAgICAgYy5kZWx0YS5nMV9zeCA9IGF3YWl0IHJlYWRHMSgpO1xuICAgICAgICBjLmRlbHRhLmcyX3NweCA9IGF3YWl0IHJlYWRHMigpO1xuICAgICAgICBjLnRyYW5zY3JpcHQgPSBhd2FpdCBmZEZyb20ucmVhZCg2NCk7XG4gICAgICAgIG1wY1BhcmFtcy5jb250cmlidXRpb25zLnB1c2goYyk7XG4gICAgICAgIGhhc2hQdWJLZXkodHJhbnNjcmlwdEhhc2hlciwgY3VydmUsIGMpO1xuICAgIH1cblxuICAgIGNvbnN0IGN1ckNvbnRyaWJ1dGlvbiA9IHt9O1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YSA9IHt9O1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5wcnZLZXkgPSBkZWx0YTtcbiAgICBjdXJDb250cmlidXRpb24uZGVsdGEuZzFfcyA9IGN1cnZlLkcxLnRvQWZmaW5lKGN1cnZlLkcxLmZyb21Sbmcocm5nKSk7XG4gICAgY3VyQ29udHJpYnV0aW9uLmRlbHRhLmcxX3N4ID0gY3VydmUuRzEudG9BZmZpbmUoY3VydmUuRzEudGltZXNGcihjdXJDb250cmlidXRpb24uZGVsdGEuZzFfcywgZGVsdGEpKTtcbiAgICB1dGlscy5oYXNoRzEodHJhbnNjcmlwdEhhc2hlciwgY3VydmUsIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMV9zKTtcbiAgICB1dGlscy5oYXNoRzEodHJhbnNjcmlwdEhhc2hlciwgY3VydmUsIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMV9zeCk7XG4gICAgY3VyQ29udHJpYnV0aW9uLnRyYW5zY3JpcHQgPSB0cmFuc2NyaXB0SGFzaGVyLmRpZ2VzdCgpO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YS5nMl9zcCA9IGhhc2hUb0cyKGN1cnZlLCBjdXJDb250cmlidXRpb24udHJhbnNjcmlwdCk7XG4gICAgY3VyQ29udHJpYnV0aW9uLmRlbHRhLmcyX3NweCA9IGN1cnZlLkcyLnRvQWZmaW5lKGN1cnZlLkcyLnRpbWVzRnIoY3VyQ29udHJpYnV0aW9uLmRlbHRhLmcyX3NwLCBkZWx0YSkpO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi5kZWx0YUFmdGVyID0gZGVsdGExO1xuICAgIGN1ckNvbnRyaWJ1dGlvbi50eXBlID0gMDtcbiAgICBtcGNQYXJhbXMuY29udHJpYnV0aW9ucy5wdXNoKGN1ckNvbnRyaWJ1dGlvbik7XG5cblxuICAgIC8vLy8vLy8vLy9cbiAgICAvLy8gV3JpdGUgQ29udHJpYnV0aW9uXG4gICAgLy8vLy8vLy8vL1xuXG4gICAgYXdhaXQgZmRUby53cml0ZShtcGNQYXJhbXMuY3NIYXNoKTtcbiAgICBhd2FpdCBmZFRvLndyaXRlVUJFMzIobXBjUGFyYW1zLmNvbnRyaWJ1dGlvbnMubGVuZ3RoKTtcblxuICAgIGZvciAobGV0IGk9MDsgaTxtcGNQYXJhbXMuY29udHJpYnV0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCBjID0gbXBjUGFyYW1zLmNvbnRyaWJ1dGlvbnNbaV07XG4gICAgICAgIGF3YWl0IHdyaXRlRzEoYy5kZWx0YUFmdGVyKTtcbiAgICAgICAgYXdhaXQgd3JpdGVHMShjLmRlbHRhLmcxX3MpO1xuICAgICAgICBhd2FpdCB3cml0ZUcxKGMuZGVsdGEuZzFfc3gpO1xuICAgICAgICBhd2FpdCB3cml0ZUcyKGMuZGVsdGEuZzJfc3B4KTtcbiAgICAgICAgYXdhaXQgZmRUby53cml0ZShjLnRyYW5zY3JpcHQpO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbnRyaWJ1dGlvbkhhc2hlciA9IGJsYWtlMmIuY3JlYXRlKHsgZGtMZW46IDY0IH0pOztcbiAgICBoYXNoUHViS2V5KGNvbnRyaWJ1dGlvbkhhc2hlciwgY3VydmUsIGN1ckNvbnRyaWJ1dGlvbik7XG5cbiAgICBjb25zdCBjb250cmlidXRpb25IYXNoID0gY29udHJpYnV0aW9uSGFzaGVyLmRpZ2VzdCgpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8obWlzYy5mb3JtYXRIYXNoKGNvbnRyaWJ1dGlvbkhhc2gsIFwiQ29udHJpYnV0aW9uIEhhc2g6IFwiKSk7XG5cbiAgICBhd2FpdCBmZFRvLmNsb3NlKCk7XG4gICAgYXdhaXQgZmRGcm9tLmNsb3NlKCk7XG5cbiAgICByZXR1cm4gY29udHJpYnV0aW9uSGFzaDtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIGNvcHkobkJ5dGVzKSB7XG4gICAgICAgIGNvbnN0IENIVU5LX1NJWkUgPSBmZEZyb20ucGFnZVNpemUqMjtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPG5CeXRlczsgaSs9IENIVU5LX1NJWkUpIHtcbiAgICAgICAgICAgIGNvbnN0IG4gPSBNYXRoLm1pbihuQnl0ZXMgLWksIENIVU5LX1NJWkUpO1xuICAgICAgICAgICAgY29uc3QgYnVmZiA9IGF3YWl0IGZkRnJvbS5yZWFkKG4pO1xuICAgICAgICAgICAgYXdhaXQgZmRUby53cml0ZShidWZmKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHJlYWRHMSgpIHtcbiAgICAgICAgY29uc3QgYnVmZiA9IGF3YWl0IGZkRnJvbS5yZWFkKGN1cnZlLkcxLkYubjgqMik7XG4gICAgICAgIHJldHVybiBjdXJ2ZS5HMS5mcm9tUnByVW5jb21wcmVzc2VkKGJ1ZmYsIDApO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHJlYWRHMigpIHtcbiAgICAgICAgY29uc3QgYnVmZiA9IGF3YWl0IGZkRnJvbS5yZWFkKGN1cnZlLkcyLkYubjgqMik7XG4gICAgICAgIHJldHVybiBjdXJ2ZS5HMi5mcm9tUnByVW5jb21wcmVzc2VkKGJ1ZmYsIDApO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlRzEoUCkge1xuICAgICAgICBjb25zdCBidWZmID0gbmV3IFVpbnQ4QXJyYXkoc0cxKTtcbiAgICAgICAgY3VydmUuRzEudG9ScHJVbmNvbXByZXNzZWQoYnVmZiwgMCwgUCk7XG4gICAgICAgIGF3YWl0IGZkVG8ud3JpdGUoYnVmZik7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gd3JpdGVHMihQKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBuZXcgVWludDhBcnJheShzRzIpO1xuICAgICAgICBjdXJ2ZS5HMi50b1JwclVuY29tcHJlc3NlZChidWZmLCAwLCBQKTtcbiAgICAgICAgYXdhaXQgZmRUby53cml0ZShidWZmKTtcbiAgICB9XG5cblxufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuaW1wb3J0ICogYXMgYmluRmlsZVV0aWxzIGZyb20gXCJAaWRlbjMvYmluZmlsZXV0aWxzXCI7XG5pbXBvcnQgKiBhcyB6a2V5VXRpbHMgZnJvbSBcIi4vemtleV91dGlscy5qc1wiO1xuaW1wb3J0IHtnZXRDdXJ2ZUZyb21RIGFzIGdldEN1cnZlfSBmcm9tIFwiLi9jdXJ2ZXMuanNcIjtcbmltcG9ydCB7dXRpbHN9IGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmltcG9ydCB7RkZMT05LX1BST1RPQ09MX0lEfSBmcm9tIFwiLi96a2V5X2NvbnN0YW50cy5qc1wiO1xuXG5jb25zdCB7c3RyaW5naWZ5QmlnSW50c30gPSB1dGlscztcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gemtleUV4cG9ydFZlcmlmaWNhdGlvbktleSh6a2V5TmFtZSwgbG9nZ2VyKSB7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJFWFBPUlQgVkVSSUZJQ0FUSU9OIEtFWSBTVEFSVEVEXCIpO1xuXG4gICAgY29uc3Qge2ZkLCBzZWN0aW9uc30gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUoemtleU5hbWUsIFwiemtleVwiLCAyKTtcbiAgICBjb25zdCB6a2V5ID0gYXdhaXQgemtleVV0aWxzLnJlYWRIZWFkZXIoZmQsIHNlY3Rpb25zKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBEZXRlY3RlZCBwcm90b2NvbDogXCIgKyB6a2V5LnByb3RvY29sKTtcblxuICAgIGxldCByZXM7XG4gICAgaWYgKHprZXkucHJvdG9jb2wgPT09IFwiZ3JvdGgxNlwiKSB7XG4gICAgICAgIHJlcyA9IGF3YWl0IGdyb3RoMTZWayh6a2V5LCBmZCwgc2VjdGlvbnMpO1xuICAgIH0gZWxzZSBpZiAoemtleS5wcm90b2NvbCA9PT0gXCJwbG9ua1wiKSB7XG4gICAgICAgIHJlcyA9IGF3YWl0IHBsb25rVmsoemtleSk7XG4gICAgfSBlbHNlIGlmICh6a2V5LnByb3RvY29sSWQgJiYgemtleS5wcm90b2NvbElkID09PSBGRkxPTktfUFJPVE9DT0xfSUQpIHtcbiAgICAgICAgcmVzID0gYXdhaXQgZXhwb3J0RkZsb25rVmsoemtleSwgbG9nZ2VyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJ6a2V5IGZpbGUgcHJvdG9jb2wgdW5yZWNvZ25pemVkXCIpO1xuICAgIH1cblxuICAgIGF3YWl0IGZkLmNsb3NlKCk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIkVYUE9SVCBWRVJJRklDQVRJT04gS0VZIEZJTklTSEVEXCIpO1xuXG4gICAgcmV0dXJuIHJlcztcbn1cblxuXG5hc3luYyBmdW5jdGlvbiBncm90aDE2VmsoemtleSwgZmQsIHNlY3Rpb25zKSB7XG4gICAgY29uc3QgY3VydmUgPSBhd2FpdCBnZXRDdXJ2ZSh6a2V5LnEpO1xuICAgIGNvbnN0IHNHMSA9IGN1cnZlLkcxLkYubjggKiAyO1xuXG4gICAgY29uc3QgYWxwaGFCZXRhID0gYXdhaXQgY3VydmUucGFpcmluZyh6a2V5LnZrX2FscGhhXzEsIHprZXkudmtfYmV0YV8yKTtcblxuICAgIGxldCB2S2V5ID0ge1xuICAgICAgICBwcm90b2NvbDogemtleS5wcm90b2NvbCxcbiAgICAgICAgY3VydmU6IGN1cnZlLm5hbWUsXG4gICAgICAgIG5QdWJsaWM6IHprZXkublB1YmxpYyxcblxuICAgICAgICB2a19hbHBoYV8xOiBjdXJ2ZS5HMS50b09iamVjdCh6a2V5LnZrX2FscGhhXzEpLFxuXG4gICAgICAgIHZrX2JldGFfMjogY3VydmUuRzIudG9PYmplY3QoemtleS52a19iZXRhXzIpLFxuICAgICAgICB2a19nYW1tYV8yOiBjdXJ2ZS5HMi50b09iamVjdCh6a2V5LnZrX2dhbW1hXzIpLFxuICAgICAgICB2a19kZWx0YV8yOiBjdXJ2ZS5HMi50b09iamVjdCh6a2V5LnZrX2RlbHRhXzIpLFxuXG4gICAgICAgIHZrX2FscGhhYmV0YV8xMjogY3VydmUuR3QudG9PYmplY3QoYWxwaGFCZXRhKVxuICAgIH07XG5cbiAgICAvLyBSZWFkIElDIFNlY3Rpb25cbiAgICAvLy8vLy8vLy8vL1xuICAgIGF3YWl0IGJpbkZpbGVVdGlscy5zdGFydFJlYWRVbmlxdWVTZWN0aW9uKGZkLCBzZWN0aW9ucywgMyk7XG4gICAgdktleS5JQyA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDw9IHprZXkublB1YmxpYzsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmYgPSBhd2FpdCBmZC5yZWFkKHNHMSk7XG4gICAgICAgIGNvbnN0IFAgPSBjdXJ2ZS5HMS50b09iamVjdChidWZmKTtcbiAgICAgICAgdktleS5JQy5wdXNoKFApO1xuICAgIH1cbiAgICBhd2FpdCBiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24oZmQpO1xuXG4gICAgdktleSA9IHN0cmluZ2lmeUJpZ0ludHModktleSk7XG5cbiAgICByZXR1cm4gdktleTtcbn1cblxuXG5hc3luYyBmdW5jdGlvbiBwbG9ua1ZrKHprZXkpIHtcbiAgICBjb25zdCBjdXJ2ZSA9IGF3YWl0IGdldEN1cnZlKHprZXkucSk7XG5cbiAgICBsZXQgdktleSA9IHtcbiAgICAgICAgcHJvdG9jb2w6IHprZXkucHJvdG9jb2wsXG4gICAgICAgIGN1cnZlOiBjdXJ2ZS5uYW1lLFxuICAgICAgICBuUHVibGljOiB6a2V5Lm5QdWJsaWMsXG4gICAgICAgIHBvd2VyOiB6a2V5LnBvd2VyLFxuXG4gICAgICAgIGsxOiBjdXJ2ZS5Gci50b09iamVjdCh6a2V5LmsxKSxcbiAgICAgICAgazI6IGN1cnZlLkZyLnRvT2JqZWN0KHprZXkuazIpLFxuXG4gICAgICAgIFFtOiBjdXJ2ZS5HMS50b09iamVjdCh6a2V5LlFtKSxcbiAgICAgICAgUWw6IGN1cnZlLkcxLnRvT2JqZWN0KHprZXkuUWwpLFxuICAgICAgICBRcjogY3VydmUuRzEudG9PYmplY3QoemtleS5RciksXG4gICAgICAgIFFvOiBjdXJ2ZS5HMS50b09iamVjdCh6a2V5LlFvKSxcbiAgICAgICAgUWM6IGN1cnZlLkcxLnRvT2JqZWN0KHprZXkuUWMpLFxuICAgICAgICBTMTogY3VydmUuRzEudG9PYmplY3QoemtleS5TMSksXG4gICAgICAgIFMyOiBjdXJ2ZS5HMS50b09iamVjdCh6a2V5LlMyKSxcbiAgICAgICAgUzM6IGN1cnZlLkcxLnRvT2JqZWN0KHprZXkuUzMpLFxuXG4gICAgICAgIFhfMjogY3VydmUuRzIudG9PYmplY3QoemtleS5YXzIpLFxuXG4gICAgICAgIHc6IGN1cnZlLkZyLnRvT2JqZWN0KGN1cnZlLkZyLndbemtleS5wb3dlcl0pXG4gICAgfTtcblxuICAgIHZLZXkgPSBzdHJpbmdpZnlCaWdJbnRzKHZLZXkpO1xuXG4gICAgcmV0dXJuIHZLZXk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGV4cG9ydEZGbG9ua1ZrKHprZXksIGxvZ2dlcikge1xuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgZ2V0Q3VydmUoemtleS5xKTtcblxuICAgIGxldCB2S2V5ID0ge1xuICAgICAgICBwcm90b2NvbDogemtleS5wcm90b2NvbCxcbiAgICAgICAgY3VydmU6IGN1cnZlLm5hbWUsXG4gICAgICAgIG5QdWJsaWM6IHprZXkublB1YmxpYyxcbiAgICAgICAgcG93ZXI6IHprZXkucG93ZXIsXG5cbiAgICAgICAgazE6IGN1cnZlLkZyLnRvT2JqZWN0KHprZXkuazEpLFxuICAgICAgICBrMjogY3VydmUuRnIudG9PYmplY3QoemtleS5rMiksXG5cbiAgICAgICAgdzogY3VydmUuRnIudG9PYmplY3QoY3VydmUuRnIud1t6a2V5LnBvd2VyXSksXG4gICAgICAgIC8vd1c6IGN1cnZlLkZyLnRvT2JqZWN0KGN1cnZlLkZyLndbemtleS5wb3dlciArIDFdKSxcbiAgICAgICAgdzM6IGN1cnZlLkZyLnRvT2JqZWN0KHprZXkudzMpLFxuICAgICAgICB3NDogY3VydmUuRnIudG9PYmplY3QoemtleS53NCksXG4gICAgICAgIHc4OiBjdXJ2ZS5Gci50b09iamVjdCh6a2V5Lnc4KSxcbiAgICAgICAgd3I6IGN1cnZlLkZyLnRvT2JqZWN0KHprZXkud3IpLFxuXG4gICAgICAgIFhfMjogY3VydmUuRzIudG9PYmplY3QoemtleS5YXzIpLFxuXG4gICAgICAgIEMwOiBjdXJ2ZS5HMS50b09iamVjdCh6a2V5LkMwKSxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHN0cmluZ2lmeUJpZ0ludHModktleSk7XG59XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDIxIDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQge2dldEN1cnZlRnJvbU5hbWV9IGZyb20gXCIuL2N1cnZlcy5qc1wiO1xuaW1wb3J0IHt1dGlsc30gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuXG5jb25zdCB7dW5zdHJpbmdpZnlCaWdJbnRzLCBzdHJpbmdpZnlCaWdJbnRzfSA9IHV0aWxzO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBmZmxvbmtFeHBvcnRTb2xpZGl0eVZlcmlmaWVyKHZrLCB0ZW1wbGF0ZXMsIGxvZ2dlcikge1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiRkZMT05LIEVYUE9SVCBTT0xJRElUWSBWRVJJRklFUiBTVEFSVEVEXCIpO1xuXG4gICAgY29uc3QgY3VydmUgPSBhd2FpdCBnZXRDdXJ2ZUZyb21OYW1lKHZrLmN1cnZlKTtcblxuICAgIC8vIFByZWNvbXB1dGUgdzNfMiwgdzRfMiBhbmQgdzRfM1xuICAgIGxldCB3MyA9IGZyb21Wa2V5KHZrLnczKTtcbiAgICB2ay53M18yID0gdG9Wa2V5KGN1cnZlLkZyLnNxdWFyZSh3MykpO1xuXG4gICAgbGV0IHc0ID0gZnJvbVZrZXkodmsudzQpO1xuICAgIHZrLnc0XzIgPSB0b1ZrZXkoY3VydmUuRnIuc3F1YXJlKHc0KSk7XG4gICAgdmsudzRfMyA9IHRvVmtleShjdXJ2ZS5Gci5tdWwoY3VydmUuRnIuc3F1YXJlKHc0KSwgdzQpKTtcblxuICAgIGxldCB3OCA9IGZyb21Wa2V5KHZrLnc4KTtcbiAgICBsZXQgYWNjID0gY3VydmUuRnIub25lO1xuXG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPCA4OyBpKyspIHtcbiAgICAgICAgYWNjID0gY3VydmUuRnIubXVsKGFjYywgdzgpO1xuICAgICAgICB2a1tcInc4X1wiICsgaV0gPSB0b1ZrZXkoYWNjKTtcbiAgICB9XG5cbiAgICBsZXQgdGVtcGxhdGUgPSB0ZW1wbGF0ZXNbdmsucHJvdG9jb2xdO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJGRkxPTksgRVhQT1JUIFNPTElESVRZIFZFUklGSUVSIEZJTklTSEVEXCIpO1xuXG4gICAgY29uc3Qge2RlZmF1bHQ6IGVqc30gPSBhd2FpdCBpbXBvcnQoXCJlanNcIik7XG4gICAgcmV0dXJuIGVqcy5yZW5kZXIodGVtcGxhdGUsIHZrKTtcblxuICAgIGZ1bmN0aW9uIGZyb21Wa2V5KHN0cikge1xuICAgICAgICBjb25zdCB2YWwgPSB1bnN0cmluZ2lmeUJpZ0ludHMoc3RyKTtcbiAgICAgICAgcmV0dXJuIGN1cnZlLkZyLmZyb21PYmplY3QodmFsKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB0b1ZrZXkodmFsKSB7XG4gICAgICAgIGNvbnN0IHN0ciA9IGN1cnZlLkZyLnRvT2JqZWN0KHZhbCk7XG4gICAgICAgIHJldHVybiBzdHJpbmdpZnlCaWdJbnRzKHN0cik7XG4gICAgfVxufVxuXG4iLCJpbXBvcnQgZXhwb3J0VmVyaWZpY2F0aW9uS2V5IGZyb20gXCIuL3prZXlfZXhwb3J0X3ZlcmlmaWNhdGlvbmtleS5qc1wiO1xuaW1wb3J0IGZmbG9ua0V4cG9ydFNvbGlkaXR5VmVyaWZpZXJDbWQgZnJvbSBcIi4vZmZsb25rX2V4cG9ydF9zb2xpZGl0eV92ZXJpZmllci5qc1wiO1xuLy8gTm90IHJlYWR5IHlldFxuLy8gbW9kdWxlLmV4cG9ydHMuZ2VuZXJhdGVWZXJpZmllcl9raW1sZWVvaCA9IGdlbmVyYXRlVmVyaWZpZXJfa2ltbGVlb2g7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIGV4cG9ydFNvbGlkaXR5VmVyaWZpZXIoektleU5hbWUsIHRlbXBsYXRlcywgbG9nZ2VyKSB7XG5cbiAgICBjb25zdCB2ZXJpZmljYXRpb25LZXkgPSBhd2FpdCBleHBvcnRWZXJpZmljYXRpb25LZXkoektleU5hbWUsIGxvZ2dlcik7XG5cbiAgICBpZiAoXCJmZmxvbmtcIiA9PT0gdmVyaWZpY2F0aW9uS2V5LnByb3RvY29sKSB7XG4gICAgICAgIHJldHVybiBmZmxvbmtFeHBvcnRTb2xpZGl0eVZlcmlmaWVyQ21kKHZlcmlmaWNhdGlvbktleSwgdGVtcGxhdGVzLCBsb2dnZXIpO1xuICAgIH1cblxuICAgIGxldCB0ZW1wbGF0ZSA9IHRlbXBsYXRlc1t2ZXJpZmljYXRpb25LZXkucHJvdG9jb2xdO1xuXG4gICAgY29uc3Qge2RlZmF1bHQ6IGVqc30gPSBhd2FpdCBpbXBvcnQoXCJlanNcIik7XG5cbiAgICByZXR1cm4gZWpzLnJlbmRlcih0ZW1wbGF0ZSwgdmVyaWZpY2F0aW9uS2V5KTtcbn1cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMTggMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cblxuZXhwb3J0IHtkZWZhdWx0IGFzIG5ld1pLZXl9IGZyb20gXCIuL3prZXlfbmV3LmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgZXhwb3J0QmVsbG1hbn0gZnJvbSBcIi4vemtleV9leHBvcnRfYmVsbG1hbi5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIGltcG9ydEJlbGxtYW59IGZyb20gXCIuL3prZXlfaW1wb3J0X2JlbGxtYW4uanNcIjtcbmV4cG9ydCB7ZGVmYXVsdCBhcyB2ZXJpZnlGcm9tUjFjc30gZnJvbSBcIi4vemtleV92ZXJpZnlfZnJvbXIxY3MuanNcIjtcbmV4cG9ydCB7ZGVmYXVsdCBhcyB2ZXJpZnlGcm9tSW5pdH0gZnJvbSBcIi4vemtleV92ZXJpZnlfZnJvbWluaXQuanNcIjtcbmV4cG9ydCB7ZGVmYXVsdCBhcyBjb250cmlidXRlfSBmcm9tIFwiLi96a2V5X2NvbnRyaWJ1dGUuanNcIjtcbmV4cG9ydCB7ZGVmYXVsdCBhcyBiZWFjb259IGZyb20gXCIuL3prZXlfYmVhY29uLmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgZXhwb3J0SnNvbn0gZnJvbSBcIi4vemtleV9leHBvcnRfanNvbi5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIGJlbGxtYW5Db250cmlidXRlfSBmcm9tIFwiLi96a2V5X2JlbGxtYW5fY29udHJpYnV0ZS5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIGV4cG9ydFZlcmlmaWNhdGlvbktleX0gZnJvbSBcIi4vemtleV9leHBvcnRfdmVyaWZpY2F0aW9ua2V5LmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgZXhwb3J0U29saWRpdHlWZXJpZmllcn0gZnJvbSBcIi4vemtleV9leHBvcnRfc29saWRpdHl2ZXJpZmllci5qc1wiO1xuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAyMSAwa2ltcyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJranMuXG5cbiAgICBzbmFya2pzIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4gICAgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZVxuICAgIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKVxuICAgIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtqcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvclxuICAgIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGhcbiAgICBzbmFya2pzLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuLyogSW1wbGVtZW50YXRpb24gb2YgdGhpcyBwYXBlcjogaHR0cHM6Ly9lcHJpbnQuaWFjci5vcmcvMjAxOS85NTMucGRmICovXG5cbmltcG9ydCB7cmVhZFIxY3NGZH0gZnJvbSBcInIxY3NmaWxlXCI7XG5pbXBvcnQgKiBhcyB1dGlscyBmcm9tIFwiLi9wb3dlcnNvZnRhdV91dGlscy5qc1wiO1xuaW1wb3J0IHtcbiAgICByZWFkQmluRmlsZSxcbiAgICBjcmVhdGVCaW5GaWxlLFxuICAgIHdyaXRlQmlnSW50LFxuICAgIHN0YXJ0V3JpdGVTZWN0aW9uLFxuICAgIGVuZFdyaXRlU2VjdGlvbixcbn0gZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCB7IGxvZzIgIH0gZnJvbSBcIi4vbWlzYy5qc1wiO1xuaW1wb3J0IHsgU2NhbGFyLCBCaWdCdWZmZXIgfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5pbXBvcnQgQmlnQXJyYXkgZnJvbSBcIi4vYmlnYXJyYXkuanNcIjtcblxuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBwbG9ua1NldHVwKHIxY3NOYW1lLCBwdGF1TmFtZSwgemtleU5hbWUsIGxvZ2dlcikge1xuXG4gICAgaWYgKGdsb2JhbFRoaXMuZ2MpIHtnbG9iYWxUaGlzLmdjKCk7fVxuXG4gICAgY29uc3Qge2ZkOiBmZFBUYXUsIHNlY3Rpb25zOiBzZWN0aW9uc1BUYXV9ID0gYXdhaXQgcmVhZEJpbkZpbGUocHRhdU5hbWUsIFwicHRhdVwiLCAxLCAxPDwyMiwgMTw8MjQpO1xuICAgIGNvbnN0IHtjdXJ2ZSwgcG93ZXJ9ID0gYXdhaXQgdXRpbHMucmVhZFBUYXVIZWFkZXIoZmRQVGF1LCBzZWN0aW9uc1BUYXUpO1xuICAgIGNvbnN0IHtmZDogZmRSMWNzLCBzZWN0aW9uczogc2VjdGlvbnNSMWNzfSA9IGF3YWl0IHJlYWRCaW5GaWxlKHIxY3NOYW1lLCBcInIxY3NcIiwgMSwgMTw8MjIsIDE8PDI0KTtcblxuICAgIGNvbnN0IHIxY3MgPSBhd2FpdCByZWFkUjFjc0ZkKGZkUjFjcywgc2VjdGlvbnNSMWNzLCB7bG9hZENvbnN0cmFpbnRzOiB0cnVlLCBsb2FkQ3VzdG9tR2F0ZXM6IHRydWV9KTtcblxuICAgIGNvbnN0IHNHMSA9IGN1cnZlLkcxLkYubjgqMjtcbiAgICBjb25zdCBHMSA9IGN1cnZlLkcxO1xuICAgIGNvbnN0IHNHMiA9IGN1cnZlLkcyLkYubjgqMjtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgIGNvbnN0IG44ciA9IGN1cnZlLkZyLm44O1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJSZWFkaW5nIHIxY3NcIik7XG5cbiAgICBjb25zdCBwbG9ua0NvbnN0cmFpbnRzID0gbmV3IEJpZ0FycmF5KCk7XG4gICAgY29uc3QgcGxvbmtBZGRpdGlvbnMgPSBuZXcgQmlnQXJyYXkoKTtcbiAgICBsZXQgcGxvbmtOVmFycyA9IHIxY3MublZhcnM7XG5cbiAgICBjb25zdCBuUHVibGljID0gcjFjcy5uT3V0cHV0cyArIHIxY3MublB1YklucHV0cztcblxuICAgIGF3YWl0IHByb2Nlc3NDb25zdHJhaW50cyhjdXJ2ZS5GciwgcjFjcywgbG9nZ2VyKTtcblxuICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cblxuICAgIGNvbnN0IGZkWktleSA9IGF3YWl0IGNyZWF0ZUJpbkZpbGUoemtleU5hbWUsIFwiemtleVwiLCAxLCAxNCwgMTw8MjIsIDE8PDI0KTtcblxuXG4gICAgaWYgKHIxY3MucHJpbWUgIT0gY3VydmUucikge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJyMWNzIGN1cnZlIGRvZXMgbm90IG1hdGNoIHBvd2VycyBvZiB0YXUgY2VyZW1vbnkgY3VydmVcIik7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICB9XG5cbiAgICBsZXQgY2lyUG93ZXIgPSBsb2cyKHBsb25rQ29uc3RyYWludHMubGVuZ3RoIC0xKSArMTtcbiAgICBpZiAoY2lyUG93ZXIgPCAzKSBjaXJQb3dlciA9IDM7ICAgLy8gQXMgdGhlIHQgcG9seW5vbWlhbCBpcyBuKzUgd2UgbmVlZCBhdCBsZWFzdCBhIHBvd2VyIG9mIDRcbiAgICBjb25zdCBkb21haW5TaXplID0gMiAqKiBjaXJQb3dlcjtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiUGxvbmsgY29uc3RyYWludHM6IFwiICsgcGxvbmtDb25zdHJhaW50cy5sZW5ndGgpO1xuICAgIGlmIChjaXJQb3dlciA+IHBvd2VyKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihgY2lyY3VpdCB0b28gYmlnIGZvciB0aGlzIHBvd2VyIG9mIHRhdSBjZXJlbW9ueS4gJHtwbG9ua0NvbnN0cmFpbnRzLmxlbmd0aH0gPiAyKioke3Bvd2VyfWApO1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuXG4gICAgaWYgKCFzZWN0aW9uc1BUYXVbMTJdKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIlBvd2VycyBvZiB0YXUgaXMgbm90IHByZXBhcmVkLlwiKTtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cblxuXG4gICAgY29uc3QgTFBvaW50cyA9IG5ldyBCaWdCdWZmZXIoZG9tYWluU2l6ZSpzRzEpO1xuICAgIGNvbnN0IG8gPSBzZWN0aW9uc1BUYXVbMTJdWzBdLnAgKyAoKDIgKiogKGNpclBvd2VyKSkgLTEpKnNHMTtcbiAgICBhd2FpdCBmZFBUYXUucmVhZFRvQnVmZmVyKExQb2ludHMsIDAsIGRvbWFpblNpemUqc0cxLCBvKTtcblxuICAgIGNvbnN0IFtrMSwgazJdID0gZ2V0SzFLMigpO1xuXG4gICAgY29uc3QgdmsgPSB7fTtcblxuXG4gICAgYXdhaXQgd3JpdGVBZGRpdGlvbnMoMywgXCJBZGRpdGlvbnNcIik7XG4gICAgaWYgKGdsb2JhbFRoaXMuZ2MpIHtnbG9iYWxUaGlzLmdjKCk7fVxuICAgIGF3YWl0IHdyaXRlV2l0bmVzc01hcCg0LCAwLCBcIkFtYXBcIik7XG4gICAgaWYgKGdsb2JhbFRoaXMuZ2MpIHtnbG9iYWxUaGlzLmdjKCk7fVxuICAgIGF3YWl0IHdyaXRlV2l0bmVzc01hcCg1LCAxLCBcIkJtYXBcIik7XG4gICAgaWYgKGdsb2JhbFRoaXMuZ2MpIHtnbG9iYWxUaGlzLmdjKCk7fVxuICAgIGF3YWl0IHdyaXRlV2l0bmVzc01hcCg2LCAyLCBcIkNtYXBcIik7XG4gICAgaWYgKGdsb2JhbFRoaXMuZ2MpIHtnbG9iYWxUaGlzLmdjKCk7fVxuICAgIGF3YWl0IHdyaXRlUU1hcCg3LCAzLCBcIlFtXCIpO1xuICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cbiAgICBhd2FpdCB3cml0ZVFNYXAoOCwgNCwgXCJRbFwiKTtcbiAgICBpZiAoZ2xvYmFsVGhpcy5nYykge2dsb2JhbFRoaXMuZ2MoKTt9XG4gICAgYXdhaXQgd3JpdGVRTWFwKDksIDUsIFwiUXJcIik7XG4gICAgaWYgKGdsb2JhbFRoaXMuZ2MpIHtnbG9iYWxUaGlzLmdjKCk7fVxuICAgIGF3YWl0IHdyaXRlUU1hcCgxMCwgNiwgXCJRb1wiKTtcbiAgICBpZiAoZ2xvYmFsVGhpcy5nYykge2dsb2JhbFRoaXMuZ2MoKTt9XG4gICAgYXdhaXQgd3JpdGVRTWFwKDExLCA3LCBcIlFjXCIpO1xuICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cbiAgICBhd2FpdCB3cml0ZVNpZ21hKDEyLCBcInNpZ21hXCIpO1xuICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cbiAgICBhd2FpdCB3cml0ZUxzKDEzLCBcImxhZ3JhbmdlIHBvbHlub21pYWxzXCIpO1xuICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cblxuICAgIC8vIFdyaXRlIFBUYXUgcG9pbnRzXG4gICAgLy8vLy8vLy8vLy8vXG5cbiAgICBhd2FpdCBzdGFydFdyaXRlU2VjdGlvbihmZFpLZXksIDE0KTtcbiAgICBjb25zdCBidWZmT3V0ID0gbmV3IEJpZ0J1ZmZlcigoZG9tYWluU2l6ZSs2KSpzRzEpO1xuICAgIGF3YWl0IGZkUFRhdS5yZWFkVG9CdWZmZXIoYnVmZk91dCwgMCwgKGRvbWFpblNpemUrNikqc0cxLCBzZWN0aW9uc1BUYXVbMl1bMF0ucCk7XG4gICAgYXdhaXQgZmRaS2V5LndyaXRlKGJ1ZmZPdXQpO1xuICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cblxuXG4gICAgYXdhaXQgd3JpdGVIZWFkZXJzKCk7XG5cbiAgICBhd2FpdCBmZFpLZXkuY2xvc2UoKTtcbiAgICBhd2FpdCBmZFIxY3MuY2xvc2UoKTtcbiAgICBhd2FpdCBmZFBUYXUuY2xvc2UoKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiU2V0dXAgRmluaXNoZWRcIik7XG5cbiAgICByZXR1cm4gO1xuXG4gICAgYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0NvbnN0cmFpbnRzKEZyLCByMWNzLCBsb2dnZXIpIHtcblxuICAgICAgICBmdW5jdGlvbiBub3JtYWxpemUobGluZWFyQ29tYikge1xuICAgICAgICAgICAgY29uc3Qgc3MgPSBPYmplY3Qua2V5cyhsaW5lYXJDb21iKTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAobGluZWFyQ29tYltzc1tpXV0gPT0gMG4pIGRlbGV0ZSBsaW5lYXJDb21iW3NzW2ldXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGpvaW4obGluZWFyQ29tYjEsIGssIGxpbmVhckNvbWIyKSB7XG4gICAgICAgICAgICBjb25zdCByZXMgPSB7fTtcblxuICAgICAgICAgICAgZm9yIChsZXQgcyBpbiBsaW5lYXJDb21iMSkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcmVzW3NdID09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzW3NdID0gRnIubXVsKGssIGxpbmVhckNvbWIxW3NdKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXNbc10gPSBGci5hZGQocmVzW3NdLCBGci5tdWwoaywgbGluZWFyQ29tYjFbc10pKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGZvciAobGV0IHMgaW4gbGluZWFyQ29tYjIpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHJlc1tzXSA9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc1tzXSA9IGxpbmVhckNvbWIyW3NdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc1tzXSA9IEZyLmFkZChyZXNbc10sIGxpbmVhckNvbWIyW3NdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBub3JtYWxpemUocmVzKTtcbiAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiByZWR1Y2VDb2VmcyhsaW5lYXJDb21iLCBtYXhDKSB7XG4gICAgICAgICAgICBjb25zdCByZXMgPSB7XG4gICAgICAgICAgICAgICAgazogRnIuemVybyxcbiAgICAgICAgICAgICAgICBzOiBbXSxcbiAgICAgICAgICAgICAgICBjb2VmczogW11cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCBjcyA9IFtdO1xuXG4gICAgICAgICAgICBmb3IgKGxldCBzIGluIGxpbmVhckNvbWIpIHtcbiAgICAgICAgICAgICAgICBpZiAocyA9PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5rID0gRnIuYWRkKHJlcy5rLCBsaW5lYXJDb21iW3NdKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGxpbmVhckNvbWJbc10gIT0gMG4pIHtcbiAgICAgICAgICAgICAgICAgICAgY3MucHVzaChbTnVtYmVyKHMpLCBsaW5lYXJDb21iW3NdXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgd2hpbGUgKGNzLmxlbmd0aCA+IG1heEMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBjMSA9IGNzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgY29uc3QgYzIgPSBjcy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgY29uc3Qgc2wgPSBjMVswXTtcbiAgICAgICAgICAgICAgICBjb25zdCBzciA9IGMyWzBdO1xuICAgICAgICAgICAgICAgIGNvbnN0IHNvID0gcGxvbmtOVmFycysrO1xuICAgICAgICAgICAgICAgIGNvbnN0IHFtID0gRnIuemVybztcbiAgICAgICAgICAgICAgICBjb25zdCBxbCA9IEZyLm5lZyhjMVsxXSk7XG4gICAgICAgICAgICAgICAgY29uc3QgcXIgPSBGci5uZWcoYzJbMV0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IHFvID0gRnIub25lO1xuICAgICAgICAgICAgICAgIGNvbnN0IHFjID0gRnIuemVybztcblxuICAgICAgICAgICAgICAgIHBsb25rQ29uc3RyYWludHMucHVzaChbc2wsIHNyLCBzbywgcW0sIHFsLCBxciwgcW8sIHFjXSk7XG5cbiAgICAgICAgICAgICAgICBwbG9ua0FkZGl0aW9ucy5wdXNoKFtzbCwgc3IsIGMxWzFdLCBjMlsxXV0pO1xuXG4gICAgICAgICAgICAgICAgY3MucHVzaChbc28sIEZyLm9uZV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHJlcy5zW2ldID0gY3NbaV1bMF07XG4gICAgICAgICAgICAgICAgcmVzLmNvZWZzW2ldID0gY3NbaV1bMV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB3aGlsZSAocmVzLmNvZWZzLmxlbmd0aCA8IG1heEMpIHtcbiAgICAgICAgICAgICAgICByZXMucy5wdXNoKDApO1xuICAgICAgICAgICAgICAgIHJlcy5jb2Vmcy5wdXNoKEZyLnplcm8pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGFkZENvbnN0cmFpbnRTdW0obGMpIHtcbiAgICAgICAgICAgIGNvbnN0IEMgPSByZWR1Y2VDb2VmcyhsYywgMyk7XG4gICAgICAgICAgICBjb25zdCBzbCA9IEMuc1swXTtcbiAgICAgICAgICAgIGNvbnN0IHNyID0gQy5zWzFdO1xuICAgICAgICAgICAgY29uc3Qgc28gPSBDLnNbMl07XG4gICAgICAgICAgICBjb25zdCBxbSA9IEZyLnplcm87XG4gICAgICAgICAgICBjb25zdCBxbCA9IEMuY29lZnNbMF07XG4gICAgICAgICAgICBjb25zdCBxciA9IEMuY29lZnNbMV07XG4gICAgICAgICAgICBjb25zdCBxbyA9IEMuY29lZnNbMl07XG4gICAgICAgICAgICBjb25zdCBxYyA9IEMuaztcbiAgICAgICAgICAgIHBsb25rQ29uc3RyYWludHMucHVzaChbc2wsIHNyLCBzbywgcW0sIHFsLCBxciwgcW8sIHFjXSk7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBhZGRDb25zdHJhaW50TXVsKGxjQSwgbGNCLCBsY0MpIHtcbiAgICAgICAgICAgIGNvbnN0IEEgPSByZWR1Y2VDb2VmcyhsY0EsIDEpO1xuICAgICAgICAgICAgY29uc3QgQiA9IHJlZHVjZUNvZWZzKGxjQiwgMSk7XG4gICAgICAgICAgICBjb25zdCBDID0gcmVkdWNlQ29lZnMobGNDLCAxKTtcblxuXG4gICAgICAgICAgICBjb25zdCBzbCA9IEEuc1swXTtcbiAgICAgICAgICAgIGNvbnN0IHNyID0gQi5zWzBdO1xuICAgICAgICAgICAgY29uc3Qgc28gPSBDLnNbMF07XG4gICAgICAgICAgICBjb25zdCBxbSA9IEZyLm11bChBLmNvZWZzWzBdLCBCLmNvZWZzWzBdKTtcbiAgICAgICAgICAgIGNvbnN0IHFsID0gRnIubXVsKEEuY29lZnNbMF0sIEIuayk7XG4gICAgICAgICAgICBjb25zdCBxciA9IEZyLm11bChBLmssIEIuY29lZnNbMF0pO1xuICAgICAgICAgICAgY29uc3QgcW8gPSBGci5uZWcoQy5jb2Vmc1swXSk7XG4gICAgICAgICAgICBjb25zdCBxYyA9IEZyLnN1YihGci5tdWwoQS5rLCBCLmspLCBDLmspO1xuICAgICAgICAgICAgcGxvbmtDb25zdHJhaW50cy5wdXNoKFtzbCwgc3IsIHNvLCBxbSwgcWwsIHFyLCBxbywgcWNdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGdldExpbmVhckNvbWJpbmF0aW9uVHlwZShsYykge1xuICAgICAgICAgICAgbGV0IGsgPSBGci56ZXJvO1xuICAgICAgICAgICAgbGV0IG4gPSAwO1xuICAgICAgICAgICAgY29uc3Qgc3MgPSBPYmplY3Qua2V5cyhsYyk7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKGxjW3NzW2ldXSA9PSAwbikge1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgbGNbc3NbaV1dO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoc3NbaV0gPT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBrID0gRnIuYWRkKGssIGxjW3NzW2ldXSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbisrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChuID4gMCkgcmV0dXJuIG4udG9TdHJpbmcoKTtcbiAgICAgICAgICAgIGlmIChrICE9IEZyLnplcm8pIHJldHVybiBcImtcIjtcbiAgICAgICAgICAgIHJldHVybiBcIjBcIjtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIHByb2Nlc3MobGNBLCBsY0IsIGxjQykge1xuICAgICAgICAgICAgY29uc3QgbGN0QSA9IGdldExpbmVhckNvbWJpbmF0aW9uVHlwZShsY0EpO1xuICAgICAgICAgICAgY29uc3QgbGN0QiA9IGdldExpbmVhckNvbWJpbmF0aW9uVHlwZShsY0IpO1xuICAgICAgICAgICAgaWYgKChsY3RBID09PSBcIjBcIikgfHwgKGxjdEIgPT09IFwiMFwiKSkge1xuICAgICAgICAgICAgICAgIG5vcm1hbGl6ZShsY0MpO1xuICAgICAgICAgICAgICAgIGFkZENvbnN0cmFpbnRTdW0obGNDKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAobGN0QSA9PT0gXCJrXCIpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBsY0NDID0gam9pbihsY0IsIGxjQVswXSwgbGNDKTtcbiAgICAgICAgICAgICAgICBhZGRDb25zdHJhaW50U3VtKGxjQ0MpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChsY3RCID09PSBcImtcIikge1xuICAgICAgICAgICAgICAgIGNvbnN0IGxjQ0MgPSBqb2luKGxjQSwgbGNCWzBdLCBsY0MpO1xuICAgICAgICAgICAgICAgIGFkZENvbnN0cmFpbnRTdW0obGNDQyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGFkZENvbnN0cmFpbnRNdWwobGNBLCBsY0IsIGxjQyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGxldCBzID0gMTsgcyA8PSBuUHVibGljOyBzKyspIHtcbiAgICAgICAgICAgIGNvbnN0IHNsID0gcztcbiAgICAgICAgICAgIGNvbnN0IHNyID0gMDtcbiAgICAgICAgICAgIGNvbnN0IHNvID0gMDtcbiAgICAgICAgICAgIGNvbnN0IHFtID0gRnIuemVybztcbiAgICAgICAgICAgIGNvbnN0IHFsID0gRnIub25lO1xuICAgICAgICAgICAgY29uc3QgcXIgPSBGci56ZXJvO1xuICAgICAgICAgICAgY29uc3QgcW8gPSBGci56ZXJvO1xuICAgICAgICAgICAgY29uc3QgcWMgPSBGci56ZXJvO1xuXG4gICAgICAgICAgICBwbG9ua0NvbnN0cmFpbnRzLnB1c2goW3NsLCBzciwgc28sIHFtLCBxbCwgcXIsIHFvLCBxY10pO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChsZXQgYyA9IDA7IGMgPCByMWNzLmNvbnN0cmFpbnRzLmxlbmd0aDsgYysrKSB7XG4gICAgICAgICAgICBpZiAoKGxvZ2dlcikgJiYgKGMgJSAxMDAwMCA9PT0gMCkpIGxvZ2dlci5kZWJ1ZyhgcHJvY2Vzc2luZyBjb25zdHJhaW50czogJHtjfS8ke3IxY3MubkNvbnN0cmFpbnRzfWApO1xuICAgICAgICAgICAgcHJvY2VzcyguLi5yMWNzLmNvbnN0cmFpbnRzW2NdKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlV2l0bmVzc01hcChzZWN0aW9uTnVtLCBwb3NDb25zdHJhaW50LCBuYW1lKSB7XG4gICAgICAgIGF3YWl0IHN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleSwgc2VjdGlvbk51bSk7XG4gICAgICAgIGZvciAobGV0IGk9MDsgaTxwbG9ua0NvbnN0cmFpbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGVVTEUzMihwbG9ua0NvbnN0cmFpbnRzW2ldW3Bvc0NvbnN0cmFpbnRdKTtcbiAgICAgICAgICAgIGlmICgobG9nZ2VyKSYmKGklMTAwMDAwMCA9PSAwKSkgbG9nZ2VyLmRlYnVnKGB3cml0aW5nICR7bmFtZX06ICR7aX0vJHtwbG9ua0NvbnN0cmFpbnRzLmxlbmd0aH1gKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBlbmRXcml0ZVNlY3Rpb24oZmRaS2V5KTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiB3cml0ZVFNYXAoc2VjdGlvbk51bSwgcG9zQ29uc3RyYWludCwgbmFtZSkge1xuICAgICAgICBsZXQgUSA9IG5ldyBCaWdCdWZmZXIoZG9tYWluU2l6ZSpuOHIpO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8cGxvbmtDb25zdHJhaW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgUS5zZXQocGxvbmtDb25zdHJhaW50c1tpXVtwb3NDb25zdHJhaW50XSwgaSpuOHIpO1xuICAgICAgICAgICAgaWYgKChsb2dnZXIpJiYoaSUxMDAwMDAwID09IDApKSBsb2dnZXIuZGVidWcoYHdyaXRpbmcgJHtuYW1lfTogJHtpfS8ke3Bsb25rQ29uc3RyYWludHMubGVuZ3RofWApO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleSwgc2VjdGlvbk51bSk7XG4gICAgICAgIGF3YWl0IHdyaXRlUDQoUSk7XG4gICAgICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuICAgICAgICBRID0gYXdhaXQgRnIuYmF0Y2hGcm9tTW9udGdvbWVyeShRKTtcbiAgICAgICAgdmtbbmFtZV09IGF3YWl0IGN1cnZlLkcxLm11bHRpRXhwQWZmaW5lKExQb2ludHMsIFEsIGxvZ2dlciwgXCJtdWx0aWV4cCBcIituYW1lKTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiB3cml0ZVA0KGJ1ZmYpIHtcbiAgICAgICAgY29uc3QgcSA9IGF3YWl0IEZyLmlmZnQoYnVmZik7XG4gICAgICAgIGNvbnN0IHE0ID0gbmV3IEJpZ0J1ZmZlcihkb21haW5TaXplKm44cio0KTtcbiAgICAgICAgcTQuc2V0KHEsIDApO1xuICAgICAgICBjb25zdCBRNCA9IGF3YWl0IEZyLmZmdChxNCk7XG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZShxKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKFE0KTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiB3cml0ZUFkZGl0aW9ucyhzZWN0aW9uTnVtLCBuYW1lKSB7XG4gICAgICAgIGF3YWl0IHN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleSwgc2VjdGlvbk51bSk7XG4gICAgICAgIGNvbnN0IGJ1ZmZPdXQgPSBuZXcgVWludDhBcnJheSgoMio0KzIqbjhyKSk7XG4gICAgICAgIGNvbnN0IGJ1ZmZPdXRWID0gbmV3IERhdGFWaWV3KGJ1ZmZPdXQuYnVmZmVyKTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHBsb25rQWRkaXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBhZGRpdGlvbj1wbG9ua0FkZGl0aW9uc1tpXTtcbiAgICAgICAgICAgIGxldCBvPTA7XG4gICAgICAgICAgICBidWZmT3V0Vi5zZXRVaW50MzIobywgYWRkaXRpb25bMF0sIHRydWUpOyBvKz00O1xuICAgICAgICAgICAgYnVmZk91dFYuc2V0VWludDMyKG8sIGFkZGl0aW9uWzFdLCB0cnVlKTsgbys9NDtcbiAgICAgICAgICAgIC8vIFRoZSB2YWx1ZSBpcyBzdG9yZWQgaW4gTW9udGdvbWVyeS4gc3RvcmVkID0gdipSXG4gICAgICAgICAgICAvLyBzbyB3aGVuIG1vbnRnb21lcnkgbXVsdGlwbGllZCBieSB0aGUgd2l0bmVzcywgaXQncyByZXN1bHQgPSB2KlIqdy9SID0gdip3XG4gICAgICAgICAgICBidWZmT3V0LnNldChhZGRpdGlvblsyXSwgbyk7IG8rPSBuOHI7XG4gICAgICAgICAgICBidWZmT3V0LnNldChhZGRpdGlvblszXSwgbyk7IG8rPSBuOHI7XG4gICAgICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUoYnVmZk91dCk7XG4gICAgICAgICAgICBpZiAoKGxvZ2dlcikmJihpJTEwMDAwMDAgPT0gMCkpIGxvZ2dlci5kZWJ1Zyhgd3JpdGluZyAke25hbWV9OiAke2l9LyR7cGxvbmtBZGRpdGlvbnMubGVuZ3RofWApO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlU2lnbWEoc2VjdGlvbk51bSwgbmFtZSkge1xuICAgICAgICBjb25zdCBzaWdtYSA9IG5ldyBCaWdCdWZmZXIobjhyKmRvbWFpblNpemUqMyk7XG4gICAgICAgIGNvbnN0IGxhc3RBcGFyZW5jZSA9ICBuZXcgQmlnQXJyYXkocGxvbmtOVmFycyk7XG4gICAgICAgIGNvbnN0IGZpcnN0UG9zID0gbmV3IEJpZ0FycmF5KHBsb25rTlZhcnMpO1xuICAgICAgICBsZXQgdyA9IEZyLm9uZTtcbiAgICAgICAgZm9yIChsZXQgaT0wOyBpPGRvbWFpblNpemU7aSsrKSB7XG4gICAgICAgICAgICBpZiAoaTxwbG9ua0NvbnN0cmFpbnRzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGJ1aWxkU2lnbWEocGxvbmtDb25zdHJhaW50c1tpXVswXSwgaSk7XG4gICAgICAgICAgICAgICAgYnVpbGRTaWdtYShwbG9ua0NvbnN0cmFpbnRzW2ldWzFdLCBkb21haW5TaXplICsgaSk7XG4gICAgICAgICAgICAgICAgYnVpbGRTaWdtYShwbG9ua0NvbnN0cmFpbnRzW2ldWzJdLCBkb21haW5TaXplKjIgKyBpKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYnVpbGRTaWdtYSgwLCBpKTtcbiAgICAgICAgICAgICAgICBidWlsZFNpZ21hKDAsIGRvbWFpblNpemUgKyBpKTtcbiAgICAgICAgICAgICAgICBidWlsZFNpZ21hKDAsIGRvbWFpblNpemUqMiArIGkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdyA9IEZyLm11bCh3LCBGci53W2NpclBvd2VyXSk7XG4gICAgICAgICAgICBpZiAoKGxvZ2dlcikmJihpJTEwMDAwMDAgPT0gMCkpIGxvZ2dlci5kZWJ1Zyhgd3JpdGluZyAke25hbWV9IHBoYXNlMTogJHtpfS8ke3Bsb25rQ29uc3RyYWludHMubGVuZ3RofWApO1xuICAgICAgICB9XG4gICAgICAgIGZvciAobGV0IHM9MDsgczxwbG9ua05WYXJzOyBzKyspIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgZmlyc3RQb3Nbc10gIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICBzaWdtYS5zZXQobGFzdEFwYXJlbmNlW3NdLCBmaXJzdFBvc1tzXSpuOHIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyB0aHJvdyBuZXcgRXJyb3IoXCJWYXJpYWJsZSBub3QgdXNlZFwiKTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIlZhcmlhYmxlIG5vdCB1c2VkXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKChsb2dnZXIpJiYocyUxMDAwMDAwID09IDApKSBsb2dnZXIuZGVidWcoYHdyaXRpbmcgJHtuYW1lfSBwaGFzZTI6ICR7c30vJHtwbG9ua05WYXJzfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGdsb2JhbFRoaXMuZ2MpIHtnbG9iYWxUaGlzLmdjKCk7fVxuICAgICAgICBhd2FpdCBzdGFydFdyaXRlU2VjdGlvbihmZFpLZXksIHNlY3Rpb25OdW0pO1xuICAgICAgICBsZXQgUzEgPSBzaWdtYS5zbGljZSgwLCBkb21haW5TaXplKm44cik7XG4gICAgICAgIGF3YWl0IHdyaXRlUDQoUzEpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykge2dsb2JhbFRoaXMuZ2MoKTt9XG4gICAgICAgIGxldCBTMiA9IHNpZ21hLnNsaWNlKGRvbWFpblNpemUqbjhyLCBkb21haW5TaXplKm44cioyKTtcbiAgICAgICAgYXdhaXQgd3JpdGVQNChTMik7XG4gICAgICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cbiAgICAgICAgbGV0IFMzID0gc2lnbWEuc2xpY2UoZG9tYWluU2l6ZSpuOHIqMiwgZG9tYWluU2l6ZSpuOHIqMyk7XG4gICAgICAgIGF3YWl0IHdyaXRlUDQoUzMpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykge2dsb2JhbFRoaXMuZ2MoKTt9XG4gICAgICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuXG4gICAgICAgIFMxID0gYXdhaXQgRnIuYmF0Y2hGcm9tTW9udGdvbWVyeShTMSk7XG4gICAgICAgIFMyID0gYXdhaXQgRnIuYmF0Y2hGcm9tTW9udGdvbWVyeShTMik7XG4gICAgICAgIFMzID0gYXdhaXQgRnIuYmF0Y2hGcm9tTW9udGdvbWVyeShTMyk7XG5cbiAgICAgICAgdmsuUzE9IGF3YWl0IGN1cnZlLkcxLm11bHRpRXhwQWZmaW5lKExQb2ludHMsIFMxLCBsb2dnZXIsIFwibXVsdGlleHAgUzFcIik7XG4gICAgICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cbiAgICAgICAgdmsuUzI9IGF3YWl0IGN1cnZlLkcxLm11bHRpRXhwQWZmaW5lKExQb2ludHMsIFMyLCBsb2dnZXIsIFwibXVsdGlleHAgUzJcIik7XG4gICAgICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cbiAgICAgICAgdmsuUzM9IGF3YWl0IGN1cnZlLkcxLm11bHRpRXhwQWZmaW5lKExQb2ludHMsIFMzLCBsb2dnZXIsIFwibXVsdGlleHAgUzNcIik7XG4gICAgICAgIGlmIChnbG9iYWxUaGlzLmdjKSB7Z2xvYmFsVGhpcy5nYygpO31cblxuICAgICAgICBmdW5jdGlvbiBidWlsZFNpZ21hKHMsIHApIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgbGFzdEFwYXJlbmNlW3NdID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgZmlyc3RQb3Nbc10gPSBwO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzaWdtYS5zZXQobGFzdEFwYXJlbmNlW3NdLCBwKm44cik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsZXQgdjtcbiAgICAgICAgICAgIGlmIChwPGRvbWFpblNpemUpIHtcbiAgICAgICAgICAgICAgICB2ID0gdztcbiAgICAgICAgICAgIH0gZWxzZSBpZiAocDwyKmRvbWFpblNpemUpIHtcbiAgICAgICAgICAgICAgICB2ID0gRnIubXVsKHcsIGsxKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdiA9IEZyLm11bCh3LCBrMik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsYXN0QXBhcmVuY2Vbc109djtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlTHMoc2VjdGlvbk51bSwgbmFtZSkge1xuICAgICAgICBhd2FpdCBzdGFydFdyaXRlU2VjdGlvbihmZFpLZXksIHNlY3Rpb25OdW0pO1xuICAgICAgICBjb25zdCBsPU1hdGgubWF4KG5QdWJsaWMsIDEpO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8bDsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgYnVmZiA9IG5ldyBCaWdCdWZmZXIoZG9tYWluU2l6ZSpuOHIpO1xuICAgICAgICAgICAgYnVmZi5zZXQoRnIub25lLCBpKm44cik7XG4gICAgICAgICAgICBhd2FpdCB3cml0ZVA0KGJ1ZmYpO1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGB3cml0aW5nICR7bmFtZX0gJHtpfS8ke2x9YCk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgZW5kV3JpdGVTZWN0aW9uKGZkWktleSk7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gd3JpdGVIZWFkZXJzKCkge1xuXG4gICAgICAgIC8vIFdyaXRlIHRoZSBoZWFkZXJcbiAgICAgICAgLy8vLy8vLy8vLy9cbiAgICAgICAgYXdhaXQgc3RhcnRXcml0ZVNlY3Rpb24oZmRaS2V5LCAxKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIoMik7IC8vIFBsb25rXG4gICAgICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuXG4gICAgICAgIC8vIFdyaXRlIHRoZSBQbG9uayBoZWFkZXIgc2VjdGlvblxuICAgICAgICAvLy8vLy8vLy8vL1xuXG4gICAgICAgIGF3YWl0IHN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleSwgMik7XG4gICAgICAgIGNvbnN0IHByaW1lUSA9IGN1cnZlLnE7XG4gICAgICAgIGNvbnN0IG44cSA9IChNYXRoLmZsb29yKCAoU2NhbGFyLmJpdExlbmd0aChwcmltZVEpIC0gMSkgLyA2NCkgKzEpKjg7XG5cbiAgICAgICAgY29uc3QgcHJpbWVSID0gY3VydmUucjtcbiAgICAgICAgY29uc3QgbjhyID0gKE1hdGguZmxvb3IoIChTY2FsYXIuYml0TGVuZ3RoKHByaW1lUikgLSAxKSAvIDY0KSArMSkqODtcblxuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGVVTEUzMihuOHEpO1xuICAgICAgICBhd2FpdCB3cml0ZUJpZ0ludChmZFpLZXksIHByaW1lUSwgbjhxKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIobjhyKTtcbiAgICAgICAgYXdhaXQgd3JpdGVCaWdJbnQoZmRaS2V5LCBwcmltZVIsIG44cik7XG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZVVMRTMyKHBsb25rTlZhcnMpOyAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUb3RhbCBudW1iZXIgb2YgYmFyc1xuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGVVTEUzMihuUHVibGljKTsgICAgICAgICAgICAgICAgICAgICAgIC8vIFRvdGFsIG51bWJlciBvZiBwdWJsaWMgdmFycyAobm90IGluY2x1ZGluZyBPTkUpXG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZVVMRTMyKGRvbWFpblNpemUpOyAgICAgICAgICAgICAgICAgIC8vIGRvbWFpblNpemVcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIocGxvbmtBZGRpdGlvbnMubGVuZ3RoKTsgICAgICAgICAgICAgICAgICAvLyBkb21haW5TaXplXG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZVVMRTMyKHBsb25rQ29uc3RyYWludHMubGVuZ3RoKTsgXG5cbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKGsxKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKGsyKTtcblxuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUoRzEudG9BZmZpbmUodmsuUW0pKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKEcxLnRvQWZmaW5lKHZrLlFsKSk7XG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZShHMS50b0FmZmluZSh2ay5RcikpO1xuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUoRzEudG9BZmZpbmUodmsuUW8pKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKEcxLnRvQWZmaW5lKHZrLlFjKSk7XG5cbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKEcxLnRvQWZmaW5lKHZrLlMxKSk7XG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZShHMS50b0FmZmluZSh2ay5TMikpO1xuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUoRzEudG9BZmZpbmUodmsuUzMpKTtcblxuICAgICAgICBsZXQgYlhfMjtcbiAgICAgICAgYlhfMiA9IGF3YWl0IGZkUFRhdS5yZWFkKHNHMiwgc2VjdGlvbnNQVGF1WzNdWzBdLnAgKyBzRzIpO1xuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUoYlhfMik7XG5cbiAgICAgICAgYXdhaXQgZW5kV3JpdGVTZWN0aW9uKGZkWktleSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0SzFLMigpIHtcbiAgICAgICAgbGV0IGsxID0gRnIudHdvO1xuICAgICAgICB3aGlsZSAoaXNJbmNsdWRlZChrMSwgW10sIGNpclBvd2VyKSkgRnIuYWRkKGsxLCBGci5vbmUpO1xuICAgICAgICBsZXQgazIgPSBGci5hZGQoazEsIEZyLm9uZSk7XG4gICAgICAgIHdoaWxlIChpc0luY2x1ZGVkKGsyLCBbazFdLCBjaXJQb3dlcikpIEZyLmFkZChrMiwgRnIub25lKTtcbiAgICAgICAgcmV0dXJuIFtrMSwgazJdO1xuXG5cbiAgICAgICAgZnVuY3Rpb24gaXNJbmNsdWRlZChrLCBrQXJyLCBwb3cpIHtcbiAgICAgICAgICAgIGNvbnN0IGRvbWFpblNpemU9IDIqKnBvdztcbiAgICAgICAgICAgIGxldCB3ID0gRnIub25lO1xuICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpPGRvbWFpblNpemU7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmIChGci5lcShrLCB3KSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaj0wOyBqPGtBcnIubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKEZyLmVxKGssIEZyLm11bChrQXJyW2pdLCB3KSkpIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB3ID0gRnIubXVsKHcsIEZyLndbcG93XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG59XG5cblxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAyMiBpZGVuMyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJranMuXG5cbiAgICBzbmFya2pzIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4gICAgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZVxuICAgIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKVxuICAgIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtqcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvclxuICAgIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGhcbiAgICBzbmFya2pzLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuZXhwb3J0IGNsYXNzIFByb29mIHtcbiAgICBjb25zdHJ1Y3RvcihjdXJ2ZSwgbG9nZ2VyKSB7XG4gICAgICAgIHRoaXMuY3VydmUgPSBjdXJ2ZTtcbiAgICAgICAgdGhpcy5sb2dnZXIgPSBsb2dnZXI7XG5cbiAgICAgICAgdGhpcy5yZXNldFByb29mKCk7XG4gICAgfVxuXG4gICAgcmVzZXRQcm9vZigpIHtcbiAgICAgICAgdGhpcy5wb2x5bm9taWFscyA9IHt9O1xuICAgICAgICB0aGlzLmV2YWx1YXRpb25zID0ge307XG4gICAgfVxuXG4gICAgYWRkUG9seW5vbWlhbChrZXksIHBvbHlub21pYWwpIHtcbiAgICAgICAgaWYgKGtleSBpbiB0aGlzLnBvbHlub21pYWxzKSB7XG4gICAgICAgICAgICB0aGlzLmxvZ2dlci53YXJuKGBwcm9vZjogcG9seW5vbWlhbC4ke2tleX0gYWxyZWFkeSBleGlzdCBpbiBwcm9vZmApO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucG9seW5vbWlhbHNba2V5XSA9IHBvbHlub21pYWw7XG4gICAgfVxuXG4gICAgZ2V0UG9seW5vbWlhbChrZXkpIHtcbiAgICAgICAgaWYgKCEoa2V5IGluIHRoaXMucG9seW5vbWlhbHMpKSB7XG4gICAgICAgICAgICB0aGlzLmxvZ2dlci53YXJuKGBwcm9vZjogcG9seW5vbWlhbCAke2tleX0gZG9lcyBub3QgZXhpc3QgaW4gcHJvb2ZgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5wb2x5bm9taWFsc1trZXldO1xuICAgIH1cblxuICAgIGFkZEV2YWx1YXRpb24oa2V5LCBldmFsdWF0aW9uKSB7XG4gICAgICAgIGlmIChrZXkgaW4gdGhpcy5ldmFsdWF0aW9ucykge1xuICAgICAgICAgICAgdGhpcy5sb2dnZXIud2FybihgcHJvb2Y6IGV2YWx1YXRpb25zLiR7a2V5fSBhbHJlYWR5IGV4aXN0IGluIHByb29mYCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5ldmFsdWF0aW9uc1trZXldID0gZXZhbHVhdGlvbjtcbiAgICB9XG5cbiAgICBnZXRFdmFsdWF0aW9uKGtleSkge1xuICAgICAgICBpZiAoIShrZXkgaW4gdGhpcy5ldmFsdWF0aW9ucykpIHtcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLndhcm4oYHByb29mOiBldmFsdWF0aW9uICR7a2V5fSBkb2VzIG5vdCBleGlzdCBpbiBwcm9vZmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmV2YWx1YXRpb25zW2tleV07XG4gICAgfVxuXG4gICAgdG9PYmplY3RQcm9vZihzcGxpdEZpZWxkcyA9IHRydWUpIHtcbiAgICAgICAgbGV0IHJlcyA9IHNwbGl0RmllbGRzID8ge3BvbHlub21pYWxzOiB7fSwgZXZhbHVhdGlvbnM6IHt9fSA6IHt9O1xuXG4gICAgICAgIE9iamVjdC5rZXlzKHRoaXMucG9seW5vbWlhbHMpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5jdXJ2ZS5HMS50b09iamVjdCh0aGlzLnBvbHlub21pYWxzW2tleV0pO1xuICAgICAgICAgICAgaWYoc3BsaXRGaWVsZHMpIHtcbiAgICAgICAgICAgICAgICByZXMucG9seW5vbWlhbHNba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXNba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBPYmplY3Qua2V5cyh0aGlzLmV2YWx1YXRpb25zKS5mb3JFYWNoKGtleSA9PiB7XG4gICAgICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMuY3VydmUuRnIudG9PYmplY3QodGhpcy5ldmFsdWF0aW9uc1trZXldKTtcbiAgICAgICAgICAgIGlmKHNwbGl0RmllbGRzKSB7XG4gICAgICAgICAgICAgICAgcmVzLmV2YWx1YXRpb25zW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVzW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICBmcm9tT2JqZWN0UHJvb2Yob2JqZWN0UHJvb2YpIHtcbiAgICAgICAgdGhpcy5yZXNldFByb29mKCk7XG5cbiAgICAgICAgT2JqZWN0LmtleXMob2JqZWN0UHJvb2YucG9seW5vbWlhbHMpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgICAgICAgIHRoaXMucG9seW5vbWlhbHNba2V5XSA9IHRoaXMuY3VydmUuRzEuZnJvbU9iamVjdChvYmplY3RQcm9vZi5wb2x5bm9taWFsc1trZXldKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgT2JqZWN0LmtleXMob2JqZWN0UHJvb2YuZXZhbHVhdGlvbnMpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgICAgICAgIHRoaXMuZXZhbHVhdGlvbnNba2V5XSA9IHRoaXMuY3VydmUuRnIuZnJvbU9iamVjdChvYmplY3RQcm9vZi5ldmFsdWF0aW9uc1trZXldKTtcbiAgICAgICAgfSk7XG4gICAgfVxufSIsIi8qKlxuICogU0hBMyAoa2VjY2FrKSBoYXNoIGZ1bmN0aW9uLCBiYXNlZCBvbiBhIG5ldyBcIlNwb25nZSBmdW5jdGlvblwiIGRlc2lnbi5cbiAqIERpZmZlcmVudCBmcm9tIG9sZGVyIGhhc2hlcywgdGhlIGludGVybmFsIHN0YXRlIGlzIGJpZ2dlciB0aGFuIG91dHB1dCBzaXplLlxuICpcbiAqIENoZWNrIG91dFxuICoge0BsaW5rIGh0dHBzOi8vbnZscHVicy5uaXN0Lmdvdi9uaXN0cHVicy9GSVBTL05JU1QuRklQUy4yMDIucGRmIHwgRklQUy0yMDJ9LFxuICoge0BsaW5rIGh0dHBzOi8va2VjY2FrLnRlYW0va2VjY2FrLmh0bWwgfCBXZWJzaXRlfSwgYW5kXG4gKiB7QGxpbmsgaHR0cHM6Ly9jcnlwdG8uc3RhY2tleGNoYW5nZS5jb20vcS8xNTcyNyB8IHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuXG4gKiBTSEEtMyBhbmQgS2VjY2FrfS5cbiAqXG4gKiBDaGVjayBvdXQgYHNoYTMtYWRkb25zYCBtb2R1bGUgZm9yIGNTSEFLRSwgazEyLCBhbmQgb3RoZXJzLlxuICogQG1vZHVsZVxuICovXG5pbXBvcnQgeyByb3RsQkgsIHJvdGxCTCwgcm90bFNILCByb3RsU0wsIHNwbGl0IH0gZnJvbSBcIi4vX3U2NC5qc1wiO1xuLy8gcHJldHRpZXItaWdub3JlXG5pbXBvcnQgeyBhYnl0ZXMsIGFleGlzdHMsIGFudW1iZXIsIGFvdXRwdXQsIGNsZWFuLCBjcmVhdGVIYXNoZXIsIG9pZE5pc3QsIHN3YXAzMklmQkUsIHUzMiB9IGZyb20gXCIuL3V0aWxzLmpzXCI7XG4vLyBObyBfX1BVUkVfXyBhbm5vdGF0aW9ucyBpbiBzaGEzIGhlYWRlcjpcbi8vIEVWRVJZVEhJTkcgaXMgaW4gZmFjdCB1c2VkIG9uIGV2ZXJ5IGV4cG9ydC5cbi8vIFZhcmlvdXMgcGVyIHJvdW5kIGNvbnN0YW50cyBjYWxjdWxhdGlvbnNcbmNvbnN0IF8wbiA9IEJpZ0ludCgwKTtcbmNvbnN0IF8xbiA9IEJpZ0ludCgxKTtcbmNvbnN0IF8ybiA9IEJpZ0ludCgyKTtcbmNvbnN0IF83biA9IEJpZ0ludCg3KTtcbmNvbnN0IF8yNTZuID0gQmlnSW50KDI1Nik7XG4vLyBGSVBTIDIwMiBBbGdvcml0aG0gNSByYygpOiB3aGVuIHRoZSBvdXRnb2luZyBiaXQgaXMgMSwgdGhlIDgtYml0IExGU1IgeG9yc1xuLy8gdGFwcyAwLCA0LCA1LCBhbmQgNiwgd2hpY2ggY29tcHJlc3NlcyB0byB0aGUgZmVlZGJhY2sgbWFzayBgMHg3MWAuXG5jb25zdCBfMHg3MW4gPSBCaWdJbnQoMHg3MSk7XG5jb25zdCBTSEEzX1BJID0gW107XG5jb25zdCBTSEEzX1JPVEwgPSBbXTtcbmNvbnN0IF9TSEEzX0lPVEEgPSBbXTsgLy8gbm8gcHVyZSBhbm5vdGF0aW9uOiB2YXIgaXMgYWx3YXlzIHVzZWRcbmZvciAobGV0IHJvdW5kID0gMCwgUiA9IF8xbiwgeCA9IDEsIHkgPSAwOyByb3VuZCA8IDI0OyByb3VuZCsrKSB7XG4gICAgLy8gUGlcbiAgICBbeCwgeV0gPSBbeSwgKDIgKiB4ICsgMyAqIHkpICUgNV07XG4gICAgU0hBM19QSS5wdXNoKDIgKiAoNSAqIHkgKyB4KSk7XG4gICAgLy8gUm90YXRpb25hbFxuICAgIFNIQTNfUk9UTC5wdXNoKCgoKHJvdW5kICsgMSkgKiAocm91bmQgKyAyKSkgLyAyKSAlIDY0KTtcbiAgICAvLyBJb3RhXG4gICAgbGV0IHQgPSBfMG47XG4gICAgZm9yIChsZXQgaiA9IDA7IGogPCA3OyBqKyspIHtcbiAgICAgICAgUiA9ICgoUiA8PCBfMW4pIF4gKChSID4+IF83bikgKiBfMHg3MW4pKSAlIF8yNTZuO1xuICAgICAgICBpZiAoUiAmIF8ybilcbiAgICAgICAgICAgIHQgXj0gXzFuIDw8ICgoXzFuIDw8IEJpZ0ludChqKSkgLSBfMW4pO1xuICAgIH1cbiAgICBfU0hBM19JT1RBLnB1c2godCk7XG59XG5jb25zdCBJT1RBUyA9IHNwbGl0KF9TSEEzX0lPVEEsIHRydWUpO1xuLy8gYHNwbGl0KC4uLiwgdHJ1ZSlgIGtlZXBzIHRoZSBsb2NhbCBsaXR0bGUtZW5kaWFuIGxhbmUtd29yZCBsYXlvdXQgdXNlZCBieVxuLy8gYHN0YXRlMzJgLCBzbyB0aGVzZSBgSGAgLyBgTGAgdGFibGVzIGZvbGxvdyB0aGUgZmlsZSdzIGZpcnN0LXdvcmQgL1xuLy8gc2Vjb25kLXdvcmQgbGFuZSBzbG90cyByYXRoZXIgdGhhbiBgX3U2NC50c2AncyB1c3VhbCBoaWdoL2xvdyBuYW1pbmcuXG5jb25zdCBTSEEzX0lPVEFfSCA9IElPVEFTWzBdO1xuY29uc3QgU0hBM19JT1RBX0wgPSBJT1RBU1sxXTtcbi8vIExlZnQgcm90YXRpb24gKHdpdGhvdXQgMCwgMzIsIDY0KVxuY29uc3Qgcm90bEggPSAoaCwgbCwgcykgPT4gKHMgPiAzMiA/IHJvdGxCSChoLCBsLCBzKSA6IHJvdGxTSChoLCBsLCBzKSk7XG5jb25zdCByb3RsTCA9IChoLCBsLCBzKSA9PiAocyA+IDMyID8gcm90bEJMKGgsIGwsIHMpIDogcm90bFNMKGgsIGwsIHMpKTtcbi8qKlxuICogYGtlY2Nha2YxNjAwYCBpbnRlcm5hbCBwZXJtdXRhdGlvbiwgYWRkaXRpb25hbGx5IGFsbG93cyBhZGp1c3RpbmcgdGhlIHJvdW5kIGNvdW50LlxuICogQHBhcmFtIHMgLSA1eDUgS2VjY2FrIHN0YXRlIGVuY29kZWQgYXMgMjUgbGFuZXMgc3BsaXQgaW50byA1MCB1aW50MzIgd29yZHNcbiAqICAgaW4gdGhpcyBmaWxlJ3MgbG9jYWwgbGl0dGxlLWVuZGlhbiBsYW5lLXdvcmQgb3JkZXJcbiAqIEBwYXJhbSByb3VuZHMgLSBudW1iZXIgb2Ygcm91bmRzIHRvIGV4ZWN1dGVcbiAqIEB0aHJvd3MgSWYgYHJvdW5kc2AgaXMgb3V0c2lkZSB0aGUgc3VwcG9ydGVkIGAxLi4yNGAgcmFuZ2UuIHtAbGluayBFcnJvcn1cbiAqIEBleGFtcGxlXG4gKiBQZXJtdXRlIGEgS2VjY2FrIHN0YXRlIHdpdGggdGhlIGRlZmF1bHQgMjQgcm91bmRzLlxuICogYGBgdHNcbiAqIGtlY2Nha1AobmV3IFVpbnQzMkFycmF5KDUwKSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGtlY2Nha1Aocywgcm91bmRzID0gMjQpIHtcbiAgICBhbnVtYmVyKHJvdW5kcywgJ3JvdW5kcycpO1xuICAgIC8vIFRoaXMgaW1wbGVtZW50YXRpb24gcHJlY29tcHV0ZXMgb25seSB0aGUgc3RhbmRhcmQgS2VjY2FrLWZbMTYwMF0gMjQtcm91bmQgSW90YSB0YWJsZS5cbiAgICBpZiAocm91bmRzIDwgMSB8fCByb3VuZHMgPiAyNClcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdcInJvdW5kc1wiIGV4cGVjdGVkIGludGVnZXIgMS4uMjQnKTtcbiAgICBjb25zdCBCID0gbmV3IFVpbnQzMkFycmF5KDUgKiAyKTtcbiAgICAvLyBOT1RFOiBhbGwgaW5kaWNlcyBhcmUgeDIgc2luY2Ugd2Ugc3RvcmUgc3RhdGUgYXMgdTMyIGluc3RlYWQgb2YgdTY0IChiaWdpbnRzIHRvIHNsb3cgaW4ganMpXG4gICAgZm9yIChsZXQgcm91bmQgPSAyNCAtIHJvdW5kczsgcm91bmQgPCAyNDsgcm91bmQrKykge1xuICAgICAgICAvLyBUaGV0YSDOuFxuICAgICAgICBmb3IgKGxldCB4ID0gMDsgeCA8IDEwOyB4KyspXG4gICAgICAgICAgICBCW3hdID0gc1t4XSBeIHNbeCArIDEwXSBeIHNbeCArIDIwXSBeIHNbeCArIDMwXSBeIHNbeCArIDQwXTtcbiAgICAgICAgZm9yIChsZXQgeCA9IDA7IHggPCAxMDsgeCArPSAyKSB7XG4gICAgICAgICAgICBjb25zdCBpZHgxID0gKHggKyA4KSAlIDEwO1xuICAgICAgICAgICAgY29uc3QgaWR4MCA9ICh4ICsgMikgJSAxMDtcbiAgICAgICAgICAgIGNvbnN0IEIwID0gQltpZHgwXTtcbiAgICAgICAgICAgIGNvbnN0IEIxID0gQltpZHgwICsgMV07XG4gICAgICAgICAgICBjb25zdCBUaCA9IHJvdGxIKEIwLCBCMSwgMSkgXiBCW2lkeDFdO1xuICAgICAgICAgICAgY29uc3QgVGwgPSByb3RsTChCMCwgQjEsIDEpIF4gQltpZHgxICsgMV07XG4gICAgICAgICAgICBmb3IgKGxldCB5ID0gMDsgeSA8IDUwOyB5ICs9IDEwKSB7XG4gICAgICAgICAgICAgICAgc1t4ICsgeV0gXj0gVGg7XG4gICAgICAgICAgICAgICAgc1t4ICsgeSArIDFdIF49IFRsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIFJobyAoz4EpIGFuZCBQaSAoz4ApXG4gICAgICAgIGxldCBjdXJIID0gc1syXTtcbiAgICAgICAgbGV0IGN1ckwgPSBzWzNdO1xuICAgICAgICBmb3IgKGxldCB0ID0gMDsgdCA8IDI0OyB0KyspIHtcbiAgICAgICAgICAgIGNvbnN0IHNoaWZ0ID0gU0hBM19ST1RMW3RdO1xuICAgICAgICAgICAgY29uc3QgVGggPSByb3RsSChjdXJILCBjdXJMLCBzaGlmdCk7XG4gICAgICAgICAgICBjb25zdCBUbCA9IHJvdGxMKGN1ckgsIGN1ckwsIHNoaWZ0KTtcbiAgICAgICAgICAgIGNvbnN0IFBJID0gU0hBM19QSVt0XTtcbiAgICAgICAgICAgIGN1ckggPSBzW1BJXTtcbiAgICAgICAgICAgIGN1ckwgPSBzW1BJICsgMV07XG4gICAgICAgICAgICBzW1BJXSA9IFRoO1xuICAgICAgICAgICAgc1tQSSArIDFdID0gVGw7XG4gICAgICAgIH1cbiAgICAgICAgLy8gQ2hpICjPhylcbiAgICAgICAgLy8gU2FtZSBhczpcbiAgICAgICAgLy8gZm9yIChsZXQgeCA9IDA7IHggPCAxMDsgeCsrKSBCW3hdID0gc1t5ICsgeF07XG4gICAgICAgIC8vIGZvciAobGV0IHggPSAwOyB4IDwgMTA7IHgrKykgc1t5ICsgeF0gXj0gfkJbKHggKyAyKSAlIDEwXSAmIEJbKHggKyA0KSAlIDEwXTtcbiAgICAgICAgZm9yIChsZXQgeSA9IDA7IHkgPCA1MDsgeSArPSAxMCkge1xuICAgICAgICAgICAgY29uc3QgYjAgPSBzW3ldLCBiMSA9IHNbeSArIDFdLCBiMiA9IHNbeSArIDJdLCBiMyA9IHNbeSArIDNdO1xuICAgICAgICAgICAgc1t5XSBePSB+c1t5ICsgMl0gJiBzW3kgKyA0XTtcbiAgICAgICAgICAgIHNbeSArIDFdIF49IH5zW3kgKyAzXSAmIHNbeSArIDVdO1xuICAgICAgICAgICAgc1t5ICsgMl0gXj0gfnNbeSArIDRdICYgc1t5ICsgNl07XG4gICAgICAgICAgICBzW3kgKyAzXSBePSB+c1t5ICsgNV0gJiBzW3kgKyA3XTtcbiAgICAgICAgICAgIHNbeSArIDRdIF49IH5zW3kgKyA2XSAmIHNbeSArIDhdO1xuICAgICAgICAgICAgc1t5ICsgNV0gXj0gfnNbeSArIDddICYgc1t5ICsgOV07XG4gICAgICAgICAgICBzW3kgKyA2XSBePSB+c1t5ICsgOF0gJiBiMDtcbiAgICAgICAgICAgIHNbeSArIDddIF49IH5zW3kgKyA5XSAmIGIxO1xuICAgICAgICAgICAgc1t5ICsgOF0gXj0gfmIwICYgYjI7XG4gICAgICAgICAgICBzW3kgKyA5XSBePSB+YjEgJiBiMztcbiAgICAgICAgfVxuICAgICAgICAvLyBJb3RhICjOuSlcbiAgICAgICAgc1swXSBePSBTSEEzX0lPVEFfSFtyb3VuZF07XG4gICAgICAgIHNbMV0gXj0gU0hBM19JT1RBX0xbcm91bmRdO1xuICAgIH1cbiAgICBjbGVhbihCKTtcbn1cbi8qKlxuICogS2VjY2FrIHNwb25nZSBmdW5jdGlvbi5cbiAqIEBwYXJhbSBibG9ja0xlbiAtIGFic29yYi9zcXVlZXplIHJhdGUgaW4gYnl0ZXNcbiAqIEBwYXJhbSBzdWZmaXggLSBkb21haW4gc2VwYXJhdGlvbiBzdWZmaXggYnl0ZVxuICogQHBhcmFtIG91dHB1dExlbiAtIGRlZmF1bHQgZGlnZXN0IGxlbmd0aCBpbiBieXRlcy4gVGhpcyBiYXNlIHNwb25nZSBvbmx5XG4gKiAgIHJlcXVpcmVzIGEgbm9uLW5lZ2F0aXZlIGludGVnZXI7IHdyYXBwZXJzIHRoYXQgbmVlZCBwb3NpdGl2ZSBvdXRwdXRcbiAqICAgbGVuZ3RocyBtdXN0IGVuZm9yY2UgdGhhdCB0aGVtc2VsdmVzLlxuICogQHBhcmFtIGVuYWJsZVhPRiAtIHdoZXRoZXIgWE9GIG91dHB1dCBpcyBhbGxvd2VkXG4gKiBAcGFyYW0gcm91bmRzIC0gbnVtYmVyIG9mIEtlY2Nhay1mIHJvdW5kc1xuICogQGV4YW1wbGVcbiAqIEJ1aWxkIGEgc3BvbmdlIHN0YXRlLCBhYnNvcmIgYnl0ZXMsIHRoZW4gZmluYWxpemUgYSBkaWdlc3QuXG4gKiBgYGB0c1xuICogY29uc3QgaGFzaCA9IG5ldyBLZWNjYWsoMTM2LCAweDA2LCAzMik7XG4gKiBoYXNoLnVwZGF0ZShuZXcgVWludDhBcnJheShbMSwgMiwgM10pKTtcbiAqIGhhc2guZGlnZXN0KCk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIEtlY2NhayB7XG4gICAgc3RhdGU7XG4gICAgcG9zID0gMDtcbiAgICBwb3NPdXQgPSAwO1xuICAgIGZpbmlzaGVkID0gZmFsc2U7XG4gICAgc3RhdGUzMjtcbiAgICBkZXN0cm95ZWQgPSBmYWxzZTtcbiAgICBibG9ja0xlbjtcbiAgICBzdWZmaXg7XG4gICAgb3V0cHV0TGVuO1xuICAgIGNhblhPRjtcbiAgICBlbmFibGVYT0YgPSBmYWxzZTtcbiAgICByb3VuZHM7XG4gICAgLy8gTk9URTogd2UgYWNjZXB0IGFyZ3VtZW50cyBpbiBieXRlcyBpbnN0ZWFkIG9mIGJpdHMgaGVyZS5cbiAgICBjb25zdHJ1Y3RvcihibG9ja0xlbiwgc3VmZml4LCBvdXRwdXRMZW4sIGVuYWJsZVhPRiA9IGZhbHNlLCByb3VuZHMgPSAyNCkge1xuICAgICAgICB0aGlzLmJsb2NrTGVuID0gYmxvY2tMZW47XG4gICAgICAgIHRoaXMuc3VmZml4ID0gc3VmZml4O1xuICAgICAgICB0aGlzLm91dHB1dExlbiA9IG91dHB1dExlbjtcbiAgICAgICAgdGhpcy5lbmFibGVYT0YgPSBlbmFibGVYT0Y7XG4gICAgICAgIHRoaXMuY2FuWE9GID0gZW5hYmxlWE9GO1xuICAgICAgICB0aGlzLnJvdW5kcyA9IHJvdW5kcztcbiAgICAgICAgLy8gQ2FuIGJlIHBhc3NlZCBmcm9tIHVzZXIgYXMgZGtMZW5cbiAgICAgICAgYW51bWJlcihvdXRwdXRMZW4sICdvdXRwdXRMZW4nKTtcbiAgICAgICAgLy8gMTYwMCA9IDV4NSBtYXRyaXggb2YgNjRiaXQuICAxNjAwIGJpdHMgPT09IDIwMCBieXRlc1xuICAgICAgICAvLyAwIDwgYmxvY2tMZW4gPCAyMDBcbiAgICAgICAgaWYgKCEoMCA8IGJsb2NrTGVuICYmIGJsb2NrTGVuIDwgMjAwKSlcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignb25seSBrZWNjYWstZjE2MDAgZnVuY3Rpb24gaXMgc3VwcG9ydGVkJyk7XG4gICAgICAgIHRoaXMuc3RhdGUgPSBuZXcgVWludDhBcnJheSgyMDApO1xuICAgICAgICB0aGlzLnN0YXRlMzIgPSB1MzIodGhpcy5zdGF0ZSk7XG4gICAgfVxuICAgIGNsb25lKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fY2xvbmVJbnRvKCk7XG4gICAgfVxuICAgIGtlY2NhaygpIHtcbiAgICAgICAgc3dhcDMySWZCRSh0aGlzLnN0YXRlMzIpO1xuICAgICAgICBrZWNjYWtQKHRoaXMuc3RhdGUzMiwgdGhpcy5yb3VuZHMpO1xuICAgICAgICBzd2FwMzJJZkJFKHRoaXMuc3RhdGUzMik7XG4gICAgICAgIHRoaXMucG9zT3V0ID0gMDtcbiAgICAgICAgdGhpcy5wb3MgPSAwO1xuICAgIH1cbiAgICB1cGRhdGUoZGF0YSkge1xuICAgICAgICBhZXhpc3RzKHRoaXMpO1xuICAgICAgICBhYnl0ZXMoZGF0YSk7XG4gICAgICAgIGNvbnN0IHsgYmxvY2tMZW4sIHN0YXRlIH0gPSB0aGlzO1xuICAgICAgICBjb25zdCBsZW4gPSBkYXRhLmxlbmd0aDtcbiAgICAgICAgZm9yIChsZXQgcG9zID0gMDsgcG9zIDwgbGVuOykge1xuICAgICAgICAgICAgY29uc3QgdGFrZSA9IE1hdGgubWluKGJsb2NrTGVuIC0gdGhpcy5wb3MsIGxlbiAtIHBvcyk7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRha2U7IGkrKylcbiAgICAgICAgICAgICAgICBzdGF0ZVt0aGlzLnBvcysrXSBePSBkYXRhW3BvcysrXTtcbiAgICAgICAgICAgIGlmICh0aGlzLnBvcyA9PT0gYmxvY2tMZW4pXG4gICAgICAgICAgICAgICAgdGhpcy5rZWNjYWsoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG4gICAgZmluaXNoKCkge1xuICAgICAgICBpZiAodGhpcy5maW5pc2hlZClcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgdGhpcy5maW5pc2hlZCA9IHRydWU7XG4gICAgICAgIGNvbnN0IHsgc3RhdGUsIHN1ZmZpeCwgcG9zLCBibG9ja0xlbiB9ID0gdGhpcztcbiAgICAgICAgLy8gRklQUyAyMDIgYXBwZW5kcyB0aGUgU0hBMy9TSEFLRSBkb21haW4tc2VwYXJhdGlvbiBzdWZmaXggYmVmb3JlIHBhZDEwKjEuXG4gICAgICAgIC8vIFRoZXNlIGJ5dGUgdmFsdWVzIGFscmVhZHkgaW5jbHVkZSB0aGUgZmlyc3QgcGFkZGluZyBiaXQsIHdoaWxlIHRoZVxuICAgICAgICAvLyBmaW5hbCBgMHg4MGAgYmVsb3cgc3VwcGxpZXMgdGhlIGNsb3NpbmcgYDFgIGJpdCBpbiB0aGUgbGFzdCByYXRlIGJ5dGUuXG4gICAgICAgIHN0YXRlW3Bvc10gXj0gc3VmZml4O1xuICAgICAgICAvLyBJZiB0aGF0IGNvbWJpbmVkIHN1ZmZpeCBsYW5kcyBpbiB0aGUgbGFzdCByYXRlIGJ5dGUgYW5kIGFscmVhZHkgc2V0c1xuICAgICAgICAvLyBiaXQgNywgYWJzb3JiIGl0IGZpcnN0IHNvIHRoZSBmaW5hbCBwYWQxMCoxIGJpdCBjYW4gYmUgeG9yZWQgaW50byBhXG4gICAgICAgIC8vIGZyZXNoIGJsb2NrLlxuICAgICAgICBpZiAoKHN1ZmZpeCAmIDB4ODApICE9PSAwICYmIHBvcyA9PT0gYmxvY2tMZW4gLSAxKVxuICAgICAgICAgICAgdGhpcy5rZWNjYWsoKTtcbiAgICAgICAgc3RhdGVbYmxvY2tMZW4gLSAxXSBePSAweDgwO1xuICAgICAgICB0aGlzLmtlY2NhaygpO1xuICAgIH1cbiAgICB3cml0ZUludG8ob3V0KSB7XG4gICAgICAgIGFleGlzdHModGhpcywgZmFsc2UpO1xuICAgICAgICBhYnl0ZXMob3V0KTtcbiAgICAgICAgdGhpcy5maW5pc2goKTtcbiAgICAgICAgY29uc3QgYnVmZmVyT3V0ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgY29uc3QgeyBibG9ja0xlbiB9ID0gdGhpcztcbiAgICAgICAgZm9yIChsZXQgcG9zID0gMCwgbGVuID0gb3V0Lmxlbmd0aDsgcG9zIDwgbGVuOykge1xuICAgICAgICAgICAgaWYgKHRoaXMucG9zT3V0ID49IGJsb2NrTGVuKVxuICAgICAgICAgICAgICAgIHRoaXMua2VjY2FrKCk7XG4gICAgICAgICAgICBjb25zdCB0YWtlID0gTWF0aC5taW4oYmxvY2tMZW4gLSB0aGlzLnBvc091dCwgbGVuIC0gcG9zKTtcbiAgICAgICAgICAgIG91dC5zZXQoYnVmZmVyT3V0LnN1YmFycmF5KHRoaXMucG9zT3V0LCB0aGlzLnBvc091dCArIHRha2UpLCBwb3MpO1xuICAgICAgICAgICAgdGhpcy5wb3NPdXQgKz0gdGFrZTtcbiAgICAgICAgICAgIHBvcyArPSB0YWtlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvdXQ7XG4gICAgfVxuICAgIHhvZkludG8ob3V0KSB7XG4gICAgICAgIC8vIFBsYWluIFNIQTMvS2VjY2FrIHVzYWdlIHdpdGggWE9GIGlzIHByb2JhYmx5IGEgbWlzdGFrZSwgYnV0IHRoaXMgYmFzZVxuICAgICAgICAvLyBjbGFzcyBpcyBhbHNvIHJldXNlZCBieSBTSEFLRS9jU0hBS0UvS01BQy9UdXBsZUhhc2gvUGFyYWxsZWxIYXNoL1xuICAgICAgICAvLyBUdXJib1NIQUtFL0thbmdhcm9vVHdlbHZlIHdyYXBwZXJzIHRoYXQgaW50ZW50aW9uYWxseSBlbmFibGUgWE9GLlxuICAgICAgICBpZiAoIXRoaXMuZW5hYmxlWE9GKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdYT0YgaXMgbm90IHBvc3NpYmxlIGZvciB0aGlzIGluc3RhbmNlJyk7XG4gICAgICAgIHJldHVybiB0aGlzLndyaXRlSW50byhvdXQpO1xuICAgIH1cbiAgICB4b2YoYnl0ZXMpIHtcbiAgICAgICAgYW51bWJlcihieXRlcyk7XG4gICAgICAgIHJldHVybiB0aGlzLnhvZkludG8obmV3IFVpbnQ4QXJyYXkoYnl0ZXMpKTtcbiAgICB9XG4gICAgZGlnZXN0SW50byhvdXQpIHtcbiAgICAgICAgYW91dHB1dChvdXQsIHRoaXMpO1xuICAgICAgICBpZiAodGhpcy5maW5pc2hlZClcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZGlnZXN0KCkgd2FzIGFscmVhZHkgY2FsbGVkJyk7XG4gICAgICAgIC8vIGBhb3V0cHV0KC4uLilgIGFsbG93cyBvdmVyc2l6ZWQgYnVmZmVyczsgZGlnZXN0SW50bygpIG11c3QgZmlsbCBvbmx5IHRoZSBhZHZlcnRpc2VkIGRpZ2VzdC5cbiAgICAgICAgdGhpcy53cml0ZUludG8ob3V0LnN1YmFycmF5KDAsIHRoaXMub3V0cHV0TGVuKSk7XG4gICAgICAgIHRoaXMuZGVzdHJveSgpO1xuICAgIH1cbiAgICBkaWdlc3QoKSB7XG4gICAgICAgIGNvbnN0IG91dCA9IG5ldyBVaW50OEFycmF5KHRoaXMub3V0cHV0TGVuKTtcbiAgICAgICAgdGhpcy5kaWdlc3RJbnRvKG91dCk7XG4gICAgICAgIHJldHVybiBvdXQ7XG4gICAgfVxuICAgIGRlc3Ryb3koKSB7XG4gICAgICAgIHRoaXMuZGVzdHJveWVkID0gdHJ1ZTtcbiAgICAgICAgY2xlYW4odGhpcy5zdGF0ZSk7XG4gICAgfVxuICAgIF9jbG9uZUludG8odG8pIHtcbiAgICAgICAgY29uc3QgeyBibG9ja0xlbiwgc3VmZml4LCBvdXRwdXRMZW4sIHJvdW5kcywgZW5hYmxlWE9GIH0gPSB0aGlzO1xuICAgICAgICB0byB8fD0gbmV3IEtlY2NhayhibG9ja0xlbiwgc3VmZml4LCBvdXRwdXRMZW4sIGVuYWJsZVhPRiwgcm91bmRzKTtcbiAgICAgICAgLy8gUmV1c2VkIGRlc3RpbmF0aW9ucyBjYW4gY29tZSBmcm9tIGEgZGlmZmVyZW50IHJhdGUvY2FwYWNpdHkgdmFyaWFudCwgc28gY2xvbmUgbXVzdCByZXdyaXRlXG4gICAgICAgIC8vIHRoZSBzcG9uZ2UgZ2VvbWV0cnkgYXMgd2VsbCBhcyB0aGUgc3RhdGUgd29yZHMuXG4gICAgICAgIHRvLmJsb2NrTGVuID0gYmxvY2tMZW47XG4gICAgICAgIHRvLnN0YXRlMzIuc2V0KHRoaXMuc3RhdGUzMik7XG4gICAgICAgIHRvLnBvcyA9IHRoaXMucG9zO1xuICAgICAgICB0by5wb3NPdXQgPSB0aGlzLnBvc091dDtcbiAgICAgICAgdG8uZmluaXNoZWQgPSB0aGlzLmZpbmlzaGVkO1xuICAgICAgICB0by5yb3VuZHMgPSByb3VuZHM7XG4gICAgICAgIC8vIFN1ZmZpeCBjYW4gY2hhbmdlIGluIGNTSEFLRVxuICAgICAgICB0by5zdWZmaXggPSBzdWZmaXg7XG4gICAgICAgIHRvLm91dHB1dExlbiA9IG91dHB1dExlbjtcbiAgICAgICAgdG8uZW5hYmxlWE9GID0gZW5hYmxlWE9GO1xuICAgICAgICAvLyBDbG9uZXMgbXVzdCBwcmVzZXJ2ZSB0aGUgcHVibGljIGNhcGFiaWxpdHkgYml0IHRvbzsgYF9LTUFDYCByZXVzZXMgdGhpcyBwYXRoIGFuZCBkZWVwIGNsb25lXG4gICAgICAgIC8vIHRlc3RzIGNvbXBhcmUgaW5zdGFuY2UgZmllbGRzIGRpcmVjdGx5LCBzbyBsZWF2aW5nIGBjYW5YT0ZgIGJlaGluZCBtYWtlcyB0aGUgY2xvbmUgbGllLlxuICAgICAgICB0by5jYW5YT0YgPSB0aGlzLmNhblhPRjtcbiAgICAgICAgdG8uZGVzdHJveWVkID0gdGhpcy5kZXN0cm95ZWQ7XG4gICAgICAgIHJldHVybiB0bztcbiAgICB9XG59XG5jb25zdCBnZW5LZWNjYWsgPSAoc3VmZml4LCBibG9ja0xlbiwgb3V0cHV0TGVuLCBpbmZvID0ge30pID0+IGNyZWF0ZUhhc2hlcigoKSA9PiBuZXcgS2VjY2FrKGJsb2NrTGVuLCBzdWZmaXgsIG91dHB1dExlbiksIGluZm8pO1xuLyoqXG4gKiBTSEEzLTIyNCBoYXNoIGZ1bmN0aW9uLlxuICogQHBhcmFtIG1zZyAtIG1lc3NhZ2UgYnl0ZXMgdG8gaGFzaFxuICogQHJldHVybnMgRGlnZXN0IGJ5dGVzLlxuICogQGV4YW1wbGVcbiAqIEhhc2ggYSBtZXNzYWdlIHdpdGggU0hBMy0yMjQuXG4gKiBgYGB0c1xuICogc2hhM18yMjQobmV3IFVpbnQ4QXJyYXkoWzk3LCA5OCwgOTldKSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IHNoYTNfMjI0ID0gLyogQF9fUFVSRV9fICovIGdlbktlY2NhaygweDA2LCAxNDQsIDI4LCBcbi8qIEBfX1BVUkVfXyAqLyBvaWROaXN0KDB4MDcpKTtcbi8qKlxuICogU0hBMy0yNTYgaGFzaCBmdW5jdGlvbi4gRGlmZmVyZW50IGZyb20ga2VjY2FrLTI1Ni5cbiAqIEBwYXJhbSBtc2cgLSBtZXNzYWdlIGJ5dGVzIHRvIGhhc2hcbiAqIEByZXR1cm5zIERpZ2VzdCBieXRlcy5cbiAqIEBleGFtcGxlXG4gKiBIYXNoIGEgbWVzc2FnZSB3aXRoIFNIQTMtMjU2LlxuICogYGBgdHNcbiAqIHNoYTNfMjU2KG5ldyBVaW50OEFycmF5KFs5NywgOTgsIDk5XSkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBzaGEzXzI1NiA9IC8qIEBfX1BVUkVfXyAqLyBnZW5LZWNjYWsoMHgwNiwgMTM2LCAzMiwgXG4vKiBAX19QVVJFX18gKi8gb2lkTmlzdCgweDA4KSk7XG4vKipcbiAqIFNIQTMtMzg0IGhhc2ggZnVuY3Rpb24uXG4gKiBAcGFyYW0gbXNnIC0gbWVzc2FnZSBieXRlcyB0byBoYXNoXG4gKiBAcmV0dXJucyBEaWdlc3QgYnl0ZXMuXG4gKiBAZXhhbXBsZVxuICogSGFzaCBhIG1lc3NhZ2Ugd2l0aCBTSEEzLTM4NC5cbiAqIGBgYHRzXG4gKiBzaGEzXzM4NChuZXcgVWludDhBcnJheShbOTcsIDk4LCA5OV0pKTtcbiAqIGBgYFxuICovXG5leHBvcnQgY29uc3Qgc2hhM18zODQgPSAvKiBAX19QVVJFX18gKi8gZ2VuS2VjY2FrKDB4MDYsIDEwNCwgNDgsIFxuLyogQF9fUFVSRV9fICovIG9pZE5pc3QoMHgwOSkpO1xuLyoqXG4gKiBTSEEzLTUxMiBoYXNoIGZ1bmN0aW9uLlxuICogQHBhcmFtIG1zZyAtIG1lc3NhZ2UgYnl0ZXMgdG8gaGFzaFxuICogQHJldHVybnMgRGlnZXN0IGJ5dGVzLlxuICogQGV4YW1wbGVcbiAqIEhhc2ggYSBtZXNzYWdlIHdpdGggU0hBMy01MTIuXG4gKiBgYGB0c1xuICogc2hhM181MTIobmV3IFVpbnQ4QXJyYXkoWzk3LCA5OCwgOTldKSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IHNoYTNfNTEyID0gLyogQF9fUFVSRV9fICovIGdlbktlY2NhaygweDA2LCA3MiwgNjQsIFxuLyogQF9fUFVSRV9fICovIG9pZE5pc3QoMHgwYSkpO1xuLyoqXG4gKiBLZWNjYWstMjI0IGhhc2ggZnVuY3Rpb24uXG4gKiBAcGFyYW0gbXNnIC0gbWVzc2FnZSBieXRlcyB0byBoYXNoXG4gKiBAcmV0dXJucyBEaWdlc3QgYnl0ZXMuXG4gKiBAZXhhbXBsZVxuICogSGFzaCBhIG1lc3NhZ2Ugd2l0aCBLZWNjYWstMjI0LlxuICogYGBgdHNcbiAqIGtlY2Nha18yMjQobmV3IFVpbnQ4QXJyYXkoWzk3LCA5OCwgOTldKSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IGtlY2Nha18yMjQgPSAvKiBAX19QVVJFX18gKi8gZ2VuS2VjY2FrKDB4MDEsIDE0NCwgMjgpO1xuLyoqXG4gKiBLZWNjYWstMjU2IGhhc2ggZnVuY3Rpb24uIERpZmZlcmVudCBmcm9tIFNIQTMtMjU2LlxuICogQHBhcmFtIG1zZyAtIG1lc3NhZ2UgYnl0ZXMgdG8gaGFzaFxuICogQHJldHVybnMgRGlnZXN0IGJ5dGVzLlxuICogQGV4YW1wbGVcbiAqIEhhc2ggYSBtZXNzYWdlIHdpdGggS2VjY2FrLTI1Ni5cbiAqIGBgYHRzXG4gKiBrZWNjYWtfMjU2KG5ldyBVaW50OEFycmF5KFs5NywgOTgsIDk5XSkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBrZWNjYWtfMjU2ID0gLyogQF9fUFVSRV9fICovIGdlbktlY2NhaygweDAxLCAxMzYsIDMyKTtcbi8qKlxuICogS2VjY2FrLTM4NCBoYXNoIGZ1bmN0aW9uLlxuICogQHBhcmFtIG1zZyAtIG1lc3NhZ2UgYnl0ZXMgdG8gaGFzaFxuICogQHJldHVybnMgRGlnZXN0IGJ5dGVzLlxuICogQGV4YW1wbGVcbiAqIEhhc2ggYSBtZXNzYWdlIHdpdGggS2VjY2FrLTM4NC5cbiAqIGBgYHRzXG4gKiBrZWNjYWtfMzg0KG5ldyBVaW50OEFycmF5KFs5NywgOTgsIDk5XSkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBrZWNjYWtfMzg0ID0gLyogQF9fUFVSRV9fICovIGdlbktlY2NhaygweDAxLCAxMDQsIDQ4KTtcbi8qKlxuICogS2VjY2FrLTUxMiBoYXNoIGZ1bmN0aW9uLlxuICogQHBhcmFtIG1zZyAtIG1lc3NhZ2UgYnl0ZXMgdG8gaGFzaFxuICogQHJldHVybnMgRGlnZXN0IGJ5dGVzLlxuICogQGV4YW1wbGVcbiAqIEhhc2ggYSBtZXNzYWdlIHdpdGggS2VjY2FrLTUxMi5cbiAqIGBgYHRzXG4gKiBrZWNjYWtfNTEyKG5ldyBVaW50OEFycmF5KFs5NywgOTgsIDk5XSkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBrZWNjYWtfNTEyID0gLyogQF9fUFVSRV9fICovIGdlbktlY2NhaygweDAxLCA3MiwgNjQpO1xuY29uc3QgZ2VuU2hha2UgPSAoc3VmZml4LCBibG9ja0xlbiwgb3V0cHV0TGVuLCBpbmZvID0ge30pID0+IGNyZWF0ZUhhc2hlcigob3B0cyA9IHt9KSA9PiBuZXcgS2VjY2FrKGJsb2NrTGVuLCBzdWZmaXgsIG9wdHMuZGtMZW4gPT09IHVuZGVmaW5lZCA/IG91dHB1dExlbiA6IG9wdHMuZGtMZW4sIHRydWUpLCBpbmZvKTtcbi8qKlxuICogU0hBS0UxMjggWE9GIHdpdGggMTI4LWJpdCBzZWN1cml0eSBhbmQgYSAxNi1ieXRlIGRlZmF1bHQgb3V0cHV0LlxuICogQHBhcmFtIG1zZyAtIG1lc3NhZ2UgYnl0ZXMgdG8gaGFzaFxuICogQHBhcmFtIG9wdHMgLSBPcHRpb25hbCBvdXRwdXQtbGVuZ3RoIG92ZXJyaWRlLiBTZWUge0BsaW5rIFNoYWtlT3B0c30uXG4gKiBAcmV0dXJucyBEaWdlc3QgYnl0ZXMuXG4gKiBAZXhhbXBsZVxuICogSGFzaCBhIG1lc3NhZ2Ugd2l0aCBTSEFLRTEyOC5cbiAqIGBgYHRzXG4gKiBzaGFrZTEyOChuZXcgVWludDhBcnJheShbOTcsIDk4LCA5OV0pLCB7IGRrTGVuOiAzMiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgY29uc3Qgc2hha2UxMjggPSBcbi8qIEBfX1BVUkVfXyAqL1xuZ2VuU2hha2UoMHgxZiwgMTY4LCAxNiwgLyogQF9fUFVSRV9fICovIG9pZE5pc3QoMHgwYikpO1xuLyoqXG4gKiBTSEFLRTI1NiBYT0Ygd2l0aCAyNTYtYml0IHNlY3VyaXR5IGFuZCBhIDMyLWJ5dGUgZGVmYXVsdCBvdXRwdXQuXG4gKiBAcGFyYW0gbXNnIC0gbWVzc2FnZSBieXRlcyB0byBoYXNoXG4gKiBAcGFyYW0gb3B0cyAtIE9wdGlvbmFsIG91dHB1dC1sZW5ndGggb3ZlcnJpZGUuIFNlZSB7QGxpbmsgU2hha2VPcHRzfS5cbiAqIEByZXR1cm5zIERpZ2VzdCBieXRlcy5cbiAqIEBleGFtcGxlXG4gKiBIYXNoIGEgbWVzc2FnZSB3aXRoIFNIQUtFMjU2LlxuICogYGBgdHNcbiAqIHNoYWtlMjU2KG5ldyBVaW50OEFycmF5KFs5NywgOTgsIDk5XSksIHsgZGtMZW46IDY0IH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBzaGFrZTI1NiA9IFxuLyogQF9fUFVSRV9fICovXG5nZW5TaGFrZSgweDFmLCAxMzYsIDMyLCAvKiBAX19QVVJFX18gKi8gb2lkTmlzdCgweDBjKSk7XG4vKipcbiAqIFNIQUtFMTI4IFhPRiB3aXRoIDI1Ni1iaXQgb3V0cHV0IChOSVNUIHZlcnNpb24pLlxuICogQHBhcmFtIG1zZyAtIG1lc3NhZ2UgYnl0ZXMgdG8gaGFzaFxuICogQHBhcmFtIG9wdHMgLSBPcHRpb25hbCBvdXRwdXQtbGVuZ3RoIG92ZXJyaWRlLiBTZWUge0BsaW5rIFNoYWtlT3B0c30uXG4gKiBAcmV0dXJucyBEaWdlc3QgYnl0ZXMuXG4gKiBAZXhhbXBsZVxuICogSGFzaCBhIG1lc3NhZ2Ugd2l0aCBTSEFLRTEyOCB1c2luZyBhIDMyLWJ5dGUgZGVmYXVsdCBvdXRwdXQuXG4gKiBgYGB0c1xuICogc2hha2UxMjhfMzIobmV3IFVpbnQ4QXJyYXkoWzk3LCA5OCwgOTldKSwgeyBka0xlbjogMzIgfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IHNoYWtlMTI4XzMyID0gXG4vKiBAX19QVVJFX18gKi9cbmdlblNoYWtlKDB4MWYsIDE2OCwgMzIsIC8qIEBfX1BVUkVfXyAqLyBvaWROaXN0KDB4MGIpKTtcbi8qKlxuICogU0hBS0UyNTYgWE9GIHdpdGggNTEyLWJpdCBvdXRwdXQgKE5JU1QgdmVyc2lvbikuXG4gKiBAcGFyYW0gbXNnIC0gbWVzc2FnZSBieXRlcyB0byBoYXNoXG4gKiBAcGFyYW0gb3B0cyAtIE9wdGlvbmFsIG91dHB1dC1sZW5ndGggb3ZlcnJpZGUuIFNlZSB7QGxpbmsgU2hha2VPcHRzfS5cbiAqIEByZXR1cm5zIERpZ2VzdCBieXRlcy5cbiAqIEBleGFtcGxlXG4gKiBIYXNoIGEgbWVzc2FnZSB3aXRoIFNIQUtFMjU2IHVzaW5nIGEgNjQtYnl0ZSBkZWZhdWx0IG91dHB1dC5cbiAqIGBgYHRzXG4gKiBzaGFrZTI1Nl82NChuZXcgVWludDhBcnJheShbOTcsIDk4LCA5OV0pLCB7IGRrTGVuOiA2NCB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgY29uc3Qgc2hha2UyNTZfNjQgPSBcbi8qIEBfX1BVUkVfXyAqL1xuZ2VuU2hha2UoMHgxZiwgMTM2LCA2NCwgLyogQF9fUFVSRV9fICovIG9pZE5pc3QoMHgwYykpO1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9c2hhMy5qcy5tYXAiLCIvKlxuICAgIENvcHlyaWdodCAyMDIyIGlkZW4zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQge1NjYWxhcn0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuaW1wb3J0IHtrZWNjYWtfMjU2fSBmcm9tIFwiQG5vYmxlL2hhc2hlcy9zaGEzLmpzXCI7XG5cbmNvbnN0IFBPTFlOT01JQUwgPSAwO1xuY29uc3QgU0NBTEFSID0gMTtcblxuZXhwb3J0IGNsYXNzIEtlY2NhazI1NlRyYW5zY3JpcHQge1xuICAgIGNvbnN0cnVjdG9yKGN1cnZlKSB7XG4gICAgICAgIHRoaXMuRzEgPSBjdXJ2ZS5HMTtcbiAgICAgICAgdGhpcy5GciA9IGN1cnZlLkZyO1xuXG4gICAgICAgIHRoaXMucmVzZXQoKTtcbiAgICB9XG5cbiAgICByZXNldCgpIHtcbiAgICAgICAgdGhpcy5kYXRhID0gW107XG4gICAgfVxuXG4gICAgYWRkUG9sQ29tbWl0bWVudChwb2x5bm9taWFsQ29tbWl0bWVudCkge1xuICAgICAgICB0aGlzLmRhdGEucHVzaCh7dHlwZTogUE9MWU5PTUlBTCwgZGF0YTogcG9seW5vbWlhbENvbW1pdG1lbnR9KTtcbiAgICB9XG5cbiAgICBhZGRTY2FsYXIoc2NhbGFyKSB7XG4gICAgICAgIHRoaXMuZGF0YS5wdXNoKHt0eXBlOiBTQ0FMQVIsIGRhdGE6IHNjYWxhcn0pO1xuICAgIH1cblxuICAgIGdldENoYWxsZW5nZSgpIHtcbiAgICAgICAgaWYoMCA9PT0gdGhpcy5kYXRhLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiS2VjY2FrMjU2VHJhbnNjcmlwdDogTm8gZGF0YSB0byBnZW5lcmF0ZSBhIHRyYW5zY3JpcHRcIik7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgblBvbHlub21pYWxzID0gMDtcbiAgICAgICAgbGV0IG5TY2FsYXJzID0gMDtcblxuICAgICAgICB0aGlzLmRhdGEuZm9yRWFjaChlbGVtZW50ID0+IFBPTFlOT01JQUwgPT09IGVsZW1lbnQudHlwZSA/IG5Qb2x5bm9taWFscysrIDogblNjYWxhcnMrKyk7XG5cbiAgICAgICAgbGV0IGJ1ZmZlciA9IG5ldyBVaW50OEFycmF5KG5TY2FsYXJzICogdGhpcy5Gci5uOCArIG5Qb2x5bm9taWFscyAqIHRoaXMuRzEuRi5uOCAqIDIpO1xuICAgICAgICBsZXQgb2Zmc2V0ID0gMDtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuZGF0YS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKFBPTFlOT01JQUwgPT09IHRoaXMuZGF0YVtpXS50eXBlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5HMS50b1JwclVuY29tcHJlc3NlZChidWZmZXIsIG9mZnNldCwgdGhpcy5kYXRhW2ldLmRhdGEpO1xuICAgICAgICAgICAgICAgIG9mZnNldCArPSB0aGlzLkcxLkYubjggKiAyO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLkZyLnRvUnByQkUoYnVmZmVyLCBvZmZzZXQsIHRoaXMuZGF0YVtpXS5kYXRhKTtcbiAgICAgICAgICAgICAgICBvZmZzZXQgKz0gdGhpcy5Gci5uODtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHZhbHVlID0gU2NhbGFyLmZyb21ScHJCRShrZWNjYWtfMjU2KGJ1ZmZlcikpO1xuICAgICAgICByZXR1cm4gdGhpcy5Gci5lKHZhbHVlKTtcbiAgICB9XG59IiwiLypcbiAgICBDb3B5cmlnaHQgMjAyMiBpZGVuMyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJranMuXG5cbiAgICBzbmFya2pzIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4gICAgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZVxuICAgIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKVxuICAgIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtqcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvclxuICAgIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGhcbiAgICBzbmFya2pzLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuZXhwb3J0IGNsYXNzIE11bFoge1xuICAgIHN0YXRpYyBnZXRaMShGcikge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgRnIuemVybyxcbiAgICAgICAgICAgIEZyLmFkZChGci5lKC0xKSwgRnIud1syXSksXG4gICAgICAgICAgICBGci5lKC0yKSxcbiAgICAgICAgICAgIEZyLnN1YihGci5lKC0xKSwgRnIud1syXSksXG4gICAgICAgIF07XG4gICAgfVxuXG4gICAgc3RhdGljIGdldFoyKEZyKSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBGci56ZXJvLFxuICAgICAgICAgICAgRnIuYWRkKEZyLnplcm8sIEZyLm11bChGci5lKC0yKSwgRnIud1syXSkpLFxuICAgICAgICAgICAgRnIuZSg0KSxcbiAgICAgICAgICAgIEZyLnN1YihGci56ZXJvLCBGci5tdWwoRnIuZSgtMiksIEZyLndbMl0pKSxcbiAgICAgICAgXTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZ2V0WjMoRnIpIHtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIEZyLnplcm8sXG4gICAgICAgICAgICBGci5hZGQoRnIuZSgyKSwgRnIubXVsKEZyLmUoMiksIEZyLndbMl0pKSxcbiAgICAgICAgICAgIEZyLmUoLTgpLFxuICAgICAgICAgICAgRnIuc3ViKEZyLmUoMiksIEZyLm11bChGci5lKDIpLCBGci53WzJdKSksXG4gICAgICAgIF07XG5cbiAgICB9XG5cbiAgICBzdGF0aWMgbXVsMihhLCBiLCBhcCwgYnAsIHAsIEZyKSB7XG4gICAgICAgIGNvbnN0IFoxID0gdGhpcy5nZXRaMShGcik7XG4gICAgICAgIGxldCByLCByejtcblxuICAgICAgICBjb25zdCBhX2IgPSBGci5tdWwoYSwgYik7XG4gICAgICAgIGNvbnN0IGFfYnAgPSBGci5tdWwoYSwgYnApO1xuICAgICAgICBjb25zdCBhcF9iID0gRnIubXVsKGFwLCBiKTtcbiAgICAgICAgY29uc3QgYXBfYnAgPSBGci5tdWwoYXAsIGJwKTtcblxuICAgICAgICByID0gYV9iO1xuXG4gICAgICAgIGxldCBhMCA9IEZyLmFkZChhX2JwLCBhcF9iKTtcblxuICAgICAgICBsZXQgYTEgPSBhcF9icDtcblxuICAgICAgICByeiA9IGEwO1xuICAgICAgICBpZiAocCkge1xuICAgICAgICAgICAgcnogPSBGci5hZGQocnosIEZyLm11bChaMVtwXSwgYTEpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbciwgcnpdO1xuICAgIH1cblxuICAgIHN0YXRpYyBtdWwzKGEsIGIsIGMsIGFwLCBicCwgY3AsIHAsIEZyKSB7XG4gICAgICAgIGNvbnN0IFoxID0gdGhpcy5nZXRaMShGcik7XG4gICAgICAgIGNvbnN0IFoyID0gdGhpcy5nZXRaMihGcik7XG4gICAgICAgIGxldCByLCByejtcblxuICAgICAgICBjb25zdCBhX2IgPSBGci5tdWwoYSwgYik7XG4gICAgICAgIGNvbnN0IGFfYnAgPSBGci5tdWwoYSwgYnApO1xuICAgICAgICBjb25zdCBhcF9iID0gRnIubXVsKGFwLCBiKTtcbiAgICAgICAgY29uc3QgYXBfYnAgPSBGci5tdWwoYXAsIGJwKTtcblxuICAgICAgICByID0gRnIubXVsKGFfYiwgYyk7XG5cbiAgICAgICAgbGV0IGEwID0gRnIubXVsKGFwX2IsIGMpO1xuICAgICAgICBhMCA9IEZyLmFkZChhMCwgRnIubXVsKGFfYnAsIGMpKTtcbiAgICAgICAgYTAgPSBGci5hZGQoYTAsIEZyLm11bChhX2IsIGNwKSk7XG5cbiAgICAgICAgbGV0IGExID0gRnIubXVsKGFwX2JwLCBjKTtcbiAgICAgICAgYTEgPSBGci5hZGQoYTEsIEZyLm11bChhX2JwLCBjcCkpO1xuICAgICAgICBhMSA9IEZyLmFkZChhMSwgRnIubXVsKGFwX2IsIGNwKSk7XG5cbiAgICAgICAgcnogPSBhMDtcbiAgICAgICAgaWYgKHApIHtcbiAgICAgICAgICAgIGNvbnN0IGEyID0gRnIubXVsKGFwX2JwLCBjcCk7XG4gICAgICAgICAgICByeiA9IEZyLmFkZChyeiwgRnIubXVsKFoxW3BdLCBhMSkpO1xuICAgICAgICAgICAgcnogPSBGci5hZGQocnosIEZyLm11bChaMltwXSwgYTIpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbciwgcnpdO1xuICAgIH1cblxuICAgIHN0YXRpYyBtdWw0KGEsIGIsIGMsIGQsIGFwLCBicCwgY3AsIGRwLCBwLCBGcikge1xuICAgICAgICBjb25zdCBaMSA9IHRoaXMuZ2V0WjEoRnIpO1xuICAgICAgICBjb25zdCBaMiA9IHRoaXMuZ2V0WjIoRnIpO1xuICAgICAgICBjb25zdCBaMyA9IHRoaXMuZ2V0WjMoRnIpO1xuXG4gICAgICAgIGxldCByLCByejtcblxuICAgICAgICBjb25zdCBhX2IgPSBGci5tdWwoYSwgYik7XG4gICAgICAgIGNvbnN0IGFfYnAgPSBGci5tdWwoYSwgYnApO1xuICAgICAgICBjb25zdCBhcF9iID0gRnIubXVsKGFwLCBiKTtcbiAgICAgICAgY29uc3QgYXBfYnAgPSBGci5tdWwoYXAsIGJwKTtcblxuICAgICAgICBjb25zdCBjX2QgPSBGci5tdWwoYywgZCk7XG4gICAgICAgIGNvbnN0IGNfZHAgPSBGci5tdWwoYywgZHApO1xuICAgICAgICBjb25zdCBjcF9kID0gRnIubXVsKGNwLCBkKTtcbiAgICAgICAgY29uc3QgY3BfZHAgPSBGci5tdWwoY3AsIGRwKTtcblxuICAgICAgICByID0gRnIubXVsKGFfYiwgY19kKTtcblxuICAgICAgICBsZXQgYTAgPSBGci5tdWwoYXBfYiwgY19kKTtcbiAgICAgICAgYTAgPSBGci5hZGQoYTAsIEZyLm11bChhX2JwLCBjX2QpKTtcbiAgICAgICAgYTAgPSBGci5hZGQoYTAsIEZyLm11bChhX2IsIGNwX2QpKTtcbiAgICAgICAgYTAgPSBGci5hZGQoYTAsIEZyLm11bChhX2IsIGNfZHApKTtcblxuICAgICAgICBsZXQgYTEgPSBGci5tdWwoYXBfYnAsIGNfZCk7XG4gICAgICAgIGExID0gRnIuYWRkKGExLCBGci5tdWwoYXBfYiwgY3BfZCkpO1xuICAgICAgICBhMSA9IEZyLmFkZChhMSwgRnIubXVsKGFwX2IsIGNfZHApKTtcbiAgICAgICAgYTEgPSBGci5hZGQoYTEsIEZyLm11bChhX2JwLCBjcF9kKSk7XG4gICAgICAgIGExID0gRnIuYWRkKGExLCBGci5tdWwoYV9icCwgY19kcCkpO1xuICAgICAgICBhMSA9IEZyLmFkZChhMSwgRnIubXVsKGFfYiwgY3BfZHApKTtcblxuICAgICAgICBsZXQgYTIgPSBGci5tdWwoYV9icCwgY3BfZHApO1xuICAgICAgICBhMiA9IEZyLmFkZChhMiwgRnIubXVsKGFwX2IsIGNwX2RwKSk7XG4gICAgICAgIGEyID0gRnIuYWRkKGEyLCBGci5tdWwoYXBfYnAsIGNfZHApKTtcbiAgICAgICAgYTIgPSBGci5hZGQoYTIsIEZyLm11bChhcF9icCwgY3BfZCkpO1xuXG4gICAgICAgIGxldCBhMyA9IEZyLm11bChhcF9icCwgY3BfZHApO1xuXG4gICAgICAgIHJ6ID0gYTA7XG4gICAgICAgIGlmIChwKSB7XG4gICAgICAgICAgICByeiA9IEZyLmFkZChyeiwgRnIubXVsKFoxW3BdLCBhMSkpO1xuICAgICAgICAgICAgcnogPSBGci5hZGQocnosIEZyLm11bChaMltwXSwgYTIpKTtcbiAgICAgICAgICAgIHJ6ID0gRnIuYWRkKHJ6LCBGci5tdWwoWjNbcF0sIGEzKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gW3IsIHJ6XTtcbiAgICB9XG59IiwiZXhwb3J0IGNvbnN0IFpLRVlfUExfTlNFQ1RJT05TID0gMTM7XG5cbmV4cG9ydCBjb25zdCBaS0VZX1BMX0hFQURFUl9TRUNUSU9OID0gMjtcbmV4cG9ydCBjb25zdCBaS0VZX1BMX0FERElUSU9OU19TRUNUSU9OID0gMztcbmV4cG9ydCBjb25zdCBaS0VZX1BMX0FfTUFQX1NFQ1RJT04gPSA0O1xuZXhwb3J0IGNvbnN0IFpLRVlfUExfQl9NQVBfU0VDVElPTiA9IDU7XG5leHBvcnQgY29uc3QgWktFWV9QTF9DX01BUF9TRUNUSU9OID0gNjtcbmV4cG9ydCBjb25zdCBaS0VZX1BMX1FNX1NFQ1RJT04gPSA3O1xuZXhwb3J0IGNvbnN0IFpLRVlfUExfUUxfU0VDVElPTiA9IDg7XG5leHBvcnQgY29uc3QgWktFWV9QTF9RUl9TRUNUSU9OID0gOTtcbmV4cG9ydCBjb25zdCBaS0VZX1BMX1FPX1NFQ1RJT04gPSAxMDtcbmV4cG9ydCBjb25zdCBaS0VZX1BMX1FDX1NFQ1RJT04gPSAxMTtcbmV4cG9ydCBjb25zdCBaS0VZX1BMX1NJR01BX1NFQ1RJT04gPSAxMjtcbmV4cG9ydCBjb25zdCBaS0VZX1BMX0xBR1JBTkdFX1NFQ1RJT04gPSAxMztcbmV4cG9ydCBjb25zdCBaS0VZX1BMX1BUQVVfU0VDVElPTiA9IDE0O1xuXG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDIyIGlkZW4zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQge0JpZ0J1ZmZlcn0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuXG5leHBvcnQgY2xhc3MgUG9seW5vbWlhbCB7XG4gICAgY29uc3RydWN0b3IoY29lZmZpY2llbnRzLCBjdXJ2ZSwgbG9nZ2VyKSB7XG4gICAgICAgIHRoaXMuY29lZiA9IGNvZWZmaWNpZW50cztcbiAgICAgICAgdGhpcy5jdXJ2ZSA9IGN1cnZlO1xuICAgICAgICB0aGlzLkZyID0gY3VydmUuRnI7XG4gICAgICAgIHRoaXMuRzEgPSBjdXJ2ZS5HMTtcbiAgICAgICAgdGhpcy5sb2dnZXIgPSBsb2dnZXI7XG4gICAgfVxuXG4gICAgc3RhdGljIGFzeW5jIGZyb21FdmFsdWF0aW9ucyhidWZmZXIsIGN1cnZlLCBsb2dnZXIpIHtcbiAgICAgICAgbGV0IGNvZWZmaWNpZW50cyA9IGF3YWl0IGN1cnZlLkZyLmlmZnQoYnVmZmVyKTtcblxuICAgICAgICByZXR1cm4gbmV3IFBvbHlub21pYWwoY29lZmZpY2llbnRzLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZnJvbUNvZWZmaWNpZW50c0FycmF5KGFycmF5LCBjdXJ2ZSwgbG9nZ2VyKSB7XG4gICAgICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG4gICAgICAgIGxldCBidWZmID0gYXJyYXkubGVuZ3RoID4gMiA8PCAxNCA/XG4gICAgICAgICAgICBuZXcgQmlnQnVmZmVyKGFycmF5Lmxlbmd0aCAqIEZyLm44KSA6IG5ldyBVaW50OEFycmF5KGFycmF5Lmxlbmd0aCAqIEZyLm44KTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkrKykgYnVmZi5zZXQoYXJyYXlbaV0sIGkgKiBGci5uOCk7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBQb2x5bm9taWFsKGJ1ZmYsIGN1cnZlLCBsb2dnZXIpO1xuICAgIH1cblxuICAgIHN0YXRpYyBmcm9tUG9seW5vbWlhbChwb2x5bm9taWFsLCBjdXJ2ZSwgbG9nZ2VyKSB7XG4gICAgICAgIGxldCBsZW5ndGggPSBwb2x5bm9taWFsLmxlbmd0aCgpO1xuICAgICAgICBsZXQgRnIgPSBjdXJ2ZS5GcjtcblxuICAgICAgICBsZXQgYnVmZiA9IGxlbmd0aCA+IDIgPDwgMTQgP1xuICAgICAgICAgICAgbmV3IEJpZ0J1ZmZlcihsZW5ndGggKiBGci5uOCkgOiBuZXcgVWludDhBcnJheShsZW5ndGggKiBGci5uOCk7XG4gICAgICAgIGJ1ZmYuc2V0KHBvbHlub21pYWwuY29lZi5zbGljZSgpLCAwKTtcblxuICAgICAgICByZXR1cm4gbmV3IFBvbHlub21pYWwoYnVmZiwgY3VydmUsIGxvZ2dlcik7XG4gICAgfVxuXG4gICAgaXNFcXVhbChwb2x5bm9taWFsKSB7XG4gICAgICAgIGNvbnN0IGRlZ3JlZSA9IHRoaXMuZGVncmVlKCk7XG4gICAgICAgIGlmIChkZWdyZWUgIT09IHBvbHlub21pYWwuZGVncmVlKCkpIHJldHVybiBmYWxzZTtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRlZ3JlZSArIDE7IGkrKykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLkZyLmVxKHRoaXMuZ2V0Q29lZihpKSwgcG9seW5vbWlhbC5nZXRDb2VmKGkpKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgYmxpbmRDb2VmZmljaWVudHMoYmxpbmRpbmdGYWN0b3JzKSB7XG4gICAgICAgIGJsaW5kaW5nRmFjdG9ycyA9IGJsaW5kaW5nRmFjdG9ycyB8fCBbXTtcblxuICAgICAgICBjb25zdCBibGluZGVkQ29lZmZpY2llbnRzID0gKHRoaXMubGVuZ3RoKCkgKyBibGluZGluZ0ZhY3RvcnMubGVuZ3RoKSA+IDIgPDwgMTQgP1xuICAgICAgICAgICAgbmV3IEJpZ0J1ZmZlcigodGhpcy5sZW5ndGgoKSArIGJsaW5kaW5nRmFjdG9ycy5sZW5ndGgpICogdGhpcy5Gci5uOCkgOlxuICAgICAgICAgICAgbmV3IFVpbnQ4QXJyYXkoKHRoaXMubGVuZ3RoKCkgKyBibGluZGluZ0ZhY3RvcnMubGVuZ3RoKSAqIHRoaXMuRnIubjgpO1xuXG4gICAgICAgIGJsaW5kZWRDb2VmZmljaWVudHMuc2V0KHRoaXMuY29lZiwgMCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYmxpbmRpbmdGYWN0b3JzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBibGluZGVkQ29lZmZpY2llbnRzLnNldChcbiAgICAgICAgICAgICAgICB0aGlzLkZyLmFkZChcbiAgICAgICAgICAgICAgICAgICAgYmxpbmRlZENvZWZmaWNpZW50cy5zbGljZSgodGhpcy5sZW5ndGgoKSArIGkpICogdGhpcy5Gci5uOCwgKHRoaXMubGVuZ3RoKCkgKyBpICsgMSkgKiB0aGlzLkZyLm44KSxcbiAgICAgICAgICAgICAgICAgICAgYmxpbmRpbmdGYWN0b3JzW2ldXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAodGhpcy5sZW5ndGgoKSArIGkpICogdGhpcy5Gci5uOFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGJsaW5kZWRDb2VmZmljaWVudHMuc2V0KFxuICAgICAgICAgICAgICAgIHRoaXMuRnIuc3ViKFxuICAgICAgICAgICAgICAgICAgICBibGluZGVkQ29lZmZpY2llbnRzLnNsaWNlKGkgKiB0aGlzLkZyLm44LCAoaSArIDEpICogdGhpcy5Gci5uOCksXG4gICAgICAgICAgICAgICAgICAgIGJsaW5kaW5nRmFjdG9yc1tpXVxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgaSAqIHRoaXMuRnIubjhcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5jb2VmID0gYmxpbmRlZENvZWZmaWNpZW50cztcbiAgICB9XG5cbiAgICBnZXRDb2VmKGluZGV4KSB7XG4gICAgICAgIGNvbnN0IGlfbjggPSBpbmRleCAqIHRoaXMuRnIubjg7XG5cbiAgICAgICAgaWYgKGlfbjggKyB0aGlzLkZyLm44ID4gdGhpcy5jb2VmLmJ5dGVMZW5ndGgpIHJldHVybiB0aGlzLkZyLnplcm87XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuY29lZi5zbGljZShpX244LCBpX244ICsgdGhpcy5Gci5uOCk7XG4gICAgfVxuXG4gICAgc2V0Q29lZihpbmRleCwgdmFsdWUpIHtcbiAgICAgICAgaWYgKGluZGV4ID4gKHRoaXMubGVuZ3RoKCkgLSAxKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29lZiBpbmRleCBpcyBub3QgYXZhaWxhYmxlXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jb2VmLnNldCh2YWx1ZSwgaW5kZXggKiB0aGlzLkZyLm44KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgYXN5bmMgdG80VChidWZmZXIsIGRvbWFpblNpemUsIGJsaW5kaW5nRmFjdG9ycywgRnIpIHtcbiAgICAgICAgYmxpbmRpbmdGYWN0b3JzID0gYmxpbmRpbmdGYWN0b3JzIHx8IFtdO1xuICAgICAgICBsZXQgYSA9IGF3YWl0IEZyLmlmZnQoYnVmZmVyKTtcblxuICAgICAgICBjb25zdCBhNCA9IChkb21haW5TaXplICogNCkgPiAyIDw8IDE0ID9cbiAgICAgICAgICAgIG5ldyBCaWdCdWZmZXIoZG9tYWluU2l6ZSAqIDQgKiBGci5uOCkgOiBuZXcgVWludDhBcnJheShkb21haW5TaXplICogNCAqIEZyLm44KTtcbiAgICAgICAgYTQuc2V0KGEsIDApO1xuXG4gICAgICAgIGNvbnN0IEE0ID0gYXdhaXQgRnIuZmZ0KGE0KTtcblxuICAgICAgICBpZiAoYmxpbmRpbmdGYWN0b3JzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIFthLCBBNF07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBhMSA9IGRvbWFpblNpemUgKyBibGluZGluZ0ZhY3RvcnMubGVuZ3RoID4gMiA8PCAxNCA/XG4gICAgICAgICAgICBuZXcgQmlnQnVmZmVyKChkb21haW5TaXplICsgYmxpbmRpbmdGYWN0b3JzLmxlbmd0aCkgKiBGci5uOCkgOlxuICAgICAgICAgICAgbmV3IFVpbnQ4QXJyYXkoKGRvbWFpblNpemUgKyBibGluZGluZ0ZhY3RvcnMubGVuZ3RoKSAqIEZyLm44KTtcblxuICAgICAgICBhMS5zZXQoYSwgMCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYmxpbmRpbmdGYWN0b3JzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBhMS5zZXQoXG4gICAgICAgICAgICAgICAgRnIuYWRkKFxuICAgICAgICAgICAgICAgICAgICBhMS5zbGljZSgoZG9tYWluU2l6ZSArIGkpICogRnIubjgsIChkb21haW5TaXplICsgaSArIDEpICogRnIubjgpLFxuICAgICAgICAgICAgICAgICAgICBibGluZGluZ0ZhY3RvcnNbaV1cbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgIChkb21haW5TaXplICsgaSkgKiBGci5uOFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGExLnNldChcbiAgICAgICAgICAgICAgICBGci5zdWIoXG4gICAgICAgICAgICAgICAgICAgIGExLnNsaWNlKGkgKiBGci5uOCwgKGkgKyAxKSAqIEZyLm44KSxcbiAgICAgICAgICAgICAgICAgICAgYmxpbmRpbmdGYWN0b3JzW2ldXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICBpICogRnIubjhcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gW2ExLCBBNF07XG4gICAgfVxuXG4gICAgbGVuZ3RoKCkge1xuICAgICAgICBsZXQgbGVuZ3RoID0gdGhpcy5jb2VmLmJ5dGVMZW5ndGggLyB0aGlzLkZyLm44O1xuICAgICAgICBpZiAobGVuZ3RoICE9PSBNYXRoLmZsb29yKHRoaXMuY29lZi5ieXRlTGVuZ3RoIC8gdGhpcy5Gci5uOCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlBvbHlub21pYWwgY29lZmZpY2llbnRzIGJ1ZmZlciBoYXMgaW5jb3JyZWN0IHNpemVcIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKDAgPT09IGxlbmd0aCkge1xuICAgICAgICAgICAgaWYgKHRoaXMubG9nZ2VyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2dnZXIud2FybihcIlBvbHlub21pYWwgaGFzIGxlbmd0aCB6ZXJvXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBsZW5ndGg7XG4gICAgfVxuXG4gICAgZGVncmVlKCkge1xuICAgICAgICBmb3IgKGxldCBpID0gdGhpcy5sZW5ndGgoKSAtIDE7IGkgPiAwOyBpLS0pIHtcbiAgICAgICAgICAgIGNvbnN0IGlfbjggPSBpICogdGhpcy5Gci5uODtcbiAgICAgICAgICAgIGlmICghdGhpcy5Gci5lcSh0aGlzLkZyLnplcm8sIHRoaXMuY29lZi5zbGljZShpX244LCBpX244ICsgdGhpcy5Gci5uOCkpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICBldmFsdWF0ZShwb2ludCkge1xuICAgICAgICBsZXQgcmVzID0gdGhpcy5Gci56ZXJvO1xuXG4gICAgICAgIGZvciAobGV0IGkgPSB0aGlzLmRlZ3JlZSgpICsgMTsgaSA+IDA7IGktLSkge1xuICAgICAgICAgICAgbGV0IGlfbjggPSBpICogdGhpcy5Gci5uODtcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRDb2VmZmljaWVudCA9IHRoaXMuY29lZi5zbGljZShpX244IC0gdGhpcy5Gci5uOCwgaV9uOCk7XG4gICAgICAgICAgICByZXMgPSB0aGlzLkZyLmFkZChjdXJyZW50Q29lZmZpY2llbnQsIHRoaXMuRnIubXVsKHJlcywgcG9pbnQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgZmFzdEV2YWx1YXRlKHBvaW50KSB7XG4gICAgICAgIGNvbnN0IEZyID0gdGhpcy5GcjtcbiAgICAgICAgbGV0IG5UaHJlYWRzID0gMztcblxuICAgICAgICBsZXQgbkNvZWZzID0gdGhpcy5kZWdyZWUoKSArIDE7XG4gICAgICAgIGxldCBjb2Vmc1RocmVhZCA9IHBhcnNlSW50KG5Db2VmcyAvIG5UaHJlYWRzKTtcbiAgICAgICAgbGV0IHJlc2lkdWFsQ29lZnMgPSBuQ29lZnMgLSBjb2Vmc1RocmVhZCAqIG5UaHJlYWRzO1xuXG4gICAgICAgIGxldCByZXMgPSBbXTtcbiAgICAgICAgbGV0IHhOID0gW107XG5cbiAgICAgICAgeE5bMF0gPSBGci5vbmU7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuVGhyZWFkczsgaSsrKSB7XG4gICAgICAgICAgICByZXNbaV0gPSBGci56ZXJvO1xuXG4gICAgICAgICAgICBsZXQgbkNvZWZzID0gaSA9PT0gKG5UaHJlYWRzIC0gMSkgPyBjb2Vmc1RocmVhZCArIHJlc2lkdWFsQ29lZnMgOiBjb2Vmc1RocmVhZDtcbiAgICAgICAgICAgIGZvciAobGV0IGogPSBuQ29lZnM7IGogPiAwOyBqLS0pIHtcbiAgICAgICAgICAgICAgICByZXNbaV0gPSBGci5hZGQodGhpcy5nZXRDb2VmKChpICogY29lZnNUaHJlYWQpICsgaiAtIDEpLCBGci5tdWwocmVzW2ldLCBwb2ludCkpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGkgPT09IDApIHhOWzBdID0gRnIubXVsKHhOWzBdLCBwb2ludCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGxldCBpID0gMTsgaSA8IG5UaHJlYWRzOyBpKyspIHtcbiAgICAgICAgICAgIHJlc1swXSA9IEZyLmFkZChyZXNbMF0sIEZyLm11bCh4TltpIC0gMV0sIHJlc1tpXSkpO1xuICAgICAgICAgICAgeE5baV0gPSBGci5tdWwoeE5baSAtIDFdLCB4TlswXSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzWzBdO1xuICAgIH1cblxuICAgIGFkZChwb2x5bm9taWFsLCBibGluZGluZ1ZhbHVlKSB7XG4gICAgICAgIGxldCBvdGhlciA9IGZhbHNlO1xuXG4gICAgICAgIGlmIChwb2x5bm9taWFsLmxlbmd0aCgpID4gdGhpcy5sZW5ndGgoKSkge1xuICAgICAgICAgICAgb3RoZXIgPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdGhpc0xlbmd0aCA9IHRoaXMubGVuZ3RoKCk7XG4gICAgICAgIGNvbnN0IHBvbHlMZW5ndGggPSBwb2x5bm9taWFsLmxlbmd0aCgpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IE1hdGgubWF4KHRoaXNMZW5ndGgsIHBvbHlMZW5ndGgpOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGlfbjggPSBpICogdGhpcy5Gci5uODtcblxuICAgICAgICAgICAgY29uc3QgYSA9IGkgPCB0aGlzTGVuZ3RoID8gdGhpcy5jb2VmLnNsaWNlKGlfbjgsIGlfbjggKyB0aGlzLkZyLm44KSA6IHRoaXMuRnIuemVybztcbiAgICAgICAgICAgIGxldCBiID0gaSA8IHBvbHlMZW5ndGggPyBwb2x5bm9taWFsLmNvZWYuc2xpY2UoaV9uOCwgaV9uOCArIHRoaXMuRnIubjgpIDogdGhpcy5Gci56ZXJvO1xuXG4gICAgICAgICAgICBpZiAoYmxpbmRpbmdWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgYiA9IHRoaXMuRnIubXVsKGIsIGJsaW5kaW5nVmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG90aGVyKSB7XG4gICAgICAgICAgICAgICAgcG9seW5vbWlhbC5jb2VmLnNldCh0aGlzLkZyLmFkZChhLCBiKSwgaV9uOCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuY29lZi5zZXQodGhpcy5Gci5hZGQoYSwgYiksIGlfbjgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChvdGhlcikge1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMuY29lZjtcbiAgICAgICAgICAgIHRoaXMuY29lZiA9IHBvbHlub21pYWwuY29lZjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHN1Yihwb2x5bm9taWFsLCBibGluZGluZ1ZhbHVlKSB7XG4gICAgICAgIGxldCBvdGhlciA9IGZhbHNlO1xuXG4gICAgICAgIGlmIChwb2x5bm9taWFsLmxlbmd0aCgpID4gdGhpcy5sZW5ndGgoKSkge1xuICAgICAgICAgICAgb3RoZXIgPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdGhpc0xlbmd0aCA9IHRoaXMubGVuZ3RoKCk7XG4gICAgICAgIGNvbnN0IHBvbHlMZW5ndGggPSBwb2x5bm9taWFsLmxlbmd0aCgpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IE1hdGgubWF4KHRoaXNMZW5ndGgsIHBvbHlMZW5ndGgpOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGlfbjggPSBpICogdGhpcy5Gci5uODtcblxuICAgICAgICAgICAgY29uc3QgYSA9IGkgPCB0aGlzTGVuZ3RoID8gdGhpcy5jb2VmLnNsaWNlKGlfbjgsIGlfbjggKyB0aGlzLkZyLm44KSA6IHRoaXMuRnIuemVybztcbiAgICAgICAgICAgIGxldCBiID0gaSA8IHBvbHlMZW5ndGggPyBwb2x5bm9taWFsLmNvZWYuc2xpY2UoaV9uOCwgaV9uOCArIHRoaXMuRnIubjgpIDogdGhpcy5Gci56ZXJvO1xuXG4gICAgICAgICAgICBpZiAoYmxpbmRpbmdWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgYiA9IHRoaXMuRnIubXVsKGIsIGJsaW5kaW5nVmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG90aGVyKSB7XG4gICAgICAgICAgICAgICAgcG9seW5vbWlhbC5jb2VmLnNldCh0aGlzLkZyLnN1YihhLCBiKSwgaV9uOCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuY29lZi5zZXQodGhpcy5Gci5zdWIoYSwgYiksIGlfbjgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChvdGhlcikge1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMuY29lZjtcbiAgICAgICAgICAgIHRoaXMuY29lZiA9IHBvbHlub21pYWwuY29lZjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG11bFNjYWxhcih2YWx1ZSkge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubGVuZ3RoKCk7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgaV9uOCA9IGkgKiB0aGlzLkZyLm44O1xuXG4gICAgICAgICAgICB0aGlzLmNvZWYuc2V0KHRoaXMuRnIubXVsKHRoaXMuY29lZi5zbGljZShpX244LCBpX244ICsgdGhpcy5Gci5uOCksIHZhbHVlKSwgaV9uOCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhZGRTY2FsYXIodmFsdWUpIHtcbiAgICAgICAgY29uc3QgY3VycmVudFZhbHVlID0gMCA9PT0gdGhpcy5sZW5ndGgoKSA/IHRoaXMuRnIuemVybyA6IHRoaXMuY29lZi5zbGljZSgwLCB0aGlzLkZyLm44KTtcbiAgICAgICAgdGhpcy5jb2VmLnNldCh0aGlzLkZyLmFkZChjdXJyZW50VmFsdWUsIHZhbHVlKSwgMCk7XG4gICAgfVxuXG4gICAgc3ViU2NhbGFyKHZhbHVlKSB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRWYWx1ZSA9IDAgPT09IHRoaXMubGVuZ3RoKCkgPyB0aGlzLkZyLnplcm8gOiB0aGlzLmNvZWYuc2xpY2UoMCwgdGhpcy5Gci5uOCk7XG4gICAgICAgIHRoaXMuY29lZi5zZXQodGhpcy5Gci5zdWIoY3VycmVudFZhbHVlLCB2YWx1ZSksIDApO1xuICAgIH1cblxuICAgIC8vIE11bHRpcGx5IGN1cnJlbnQgcG9seW5vbWlhbCBieSB0aGUgcG9seW5vbWlhbCAoWCAtIHZhbHVlKVxuICAgIGJ5WFN1YlZhbHVlKHZhbHVlKSB7XG4gICAgICAgIGNvbnN0IEZyID0gdGhpcy5GcjtcbiAgICAgICAgY29uc3QgcmVzaXplID0gIUZyLmVxKEZyLnplcm8sIHRoaXMuZ2V0Q29lZih0aGlzLmxlbmd0aCgpIC0gMSkpO1xuXG4gICAgICAgIGNvbnN0IGxlbmd0aCA9IHJlc2l6ZSA/IHRoaXMubGVuZ3RoKCkgKyAxIDogdGhpcy5sZW5ndGgoKTtcbiAgICAgICAgY29uc3QgYnVmZiA9IGxlbmd0aCA+IDIgPDwgMTQgPyBuZXcgQmlnQnVmZmVyKGxlbmd0aCAqIEZyLm44KSA6IG5ldyBVaW50OEFycmF5KGxlbmd0aCAqIEZyLm44KTtcbiAgICAgICAgbGV0IHBvbCA9IG5ldyBQb2x5bm9taWFsKGJ1ZmYsIHRoaXMuY3VydmUsIHRoaXMubG9nZ2VyKTtcblxuICAgICAgICAvLyBTdGVwIDA6IFNldCBjdXJyZW50IGNvZWZmaWNpZW50cyB0byB0aGUgbmV3IGJ1ZmZlciBzaGlmdGVkIG9uZSBwb3NpdGlvblxuICAgICAgICBwb2wuY29lZi5zZXQodGhpcy5jb2VmLnNsaWNlKDAsIChsZW5ndGggLSAxKSAqIEZyLm44KSwgMzIpO1xuXG4gICAgICAgIC8vIFN0ZXAgMTogbXVsdGlwbHkgZWFjaCBjb2VmZmljaWVudCBieSAoLXZhbHVlKVxuICAgICAgICB0aGlzLm11bFNjYWxhcihGci5uZWcodmFsdWUpKTtcblxuICAgICAgICAvLyBTdGVwIDI6IEFkZCBjdXJyZW50IHBvbHlub21pYWwgdG8gZGVzdGluYXRpb24gcG9seW5vbWlhbFxuICAgICAgICBwb2wuYWRkKHRoaXMpO1xuXG4gICAgICAgIC8vIFN3YXAgYnVmZmVyc1xuICAgICAgICB0aGlzLmNvZWYgPSBwb2wuY29lZjtcbiAgICB9XG5cbiAgICAvLyBNdWx0aXBseSBjdXJyZW50IHBvbHlub21pYWwgYnkgdGhlIHBvbHlub21pYWwgKFhebiArIHZhbHVlKVxuICAgIGJ5WE5TdWJWYWx1ZShuLCB2YWx1ZSkge1xuICAgICAgICBjb25zdCBGciA9IHRoaXMuRnI7XG4gICAgICAgIGNvbnN0IHJlc2l6ZSA9ICEodGhpcy5sZW5ndGgoKSAtIG4gLSAxID49IHRoaXMuZGVncmVlKCkpO1xuXG4gICAgICAgIGNvbnN0IGxlbmd0aCA9IHJlc2l6ZSA/IHRoaXMubGVuZ3RoKCkgKyBuIDogdGhpcy5sZW5ndGgoKTtcbiAgICAgICAgY29uc3QgYnVmZiA9IGxlbmd0aCA+IDIgPDwgMTQgPyBuZXcgQmlnQnVmZmVyKGxlbmd0aCAqIEZyLm44KSA6IG5ldyBVaW50OEFycmF5KGxlbmd0aCAqIEZyLm44KTtcbiAgICAgICAgbGV0IHBvbCA9IG5ldyBQb2x5bm9taWFsKGJ1ZmYsIHRoaXMuY3VydmUsIHRoaXMubG9nZ2VyKTtcblxuICAgICAgICAvLyBTdGVwIDA6IFNldCBjdXJyZW50IGNvZWZmaWNpZW50cyB0byB0aGUgbmV3IGJ1ZmZlciBzaGlmdGVkIG9uZSBwb3NpdGlvblxuICAgICAgICBwb2wuY29lZi5zZXQodGhpcy5jb2VmLnNsaWNlKDAsICh0aGlzLmRlZ3JlZSgpICsgMSkgKiAzMiwgKSwgbiAqIDMyKTtcblxuICAgICAgICAvLyBTdGVwIDE6IG11bHRpcGx5IGVhY2ggY29lZmZpY2llbnQgYnkgKC0gdmFsdWUpXG4gICAgICAgIHRoaXMubXVsU2NhbGFyKHZhbHVlKTtcblxuICAgICAgICAvLyBTdGVwIDI6IEFkZCBjdXJyZW50IHBvbHlub21pYWwgdG8gZGVzdGluYXRpb24gcG9seW5vbWlhbFxuICAgICAgICBwb2wuYWRkKHRoaXMpO1xuXG4gICAgICAgIC8vIFN3YXAgYnVmZmVyc1xuICAgICAgICB0aGlzLmNvZWYgPSBwb2wuY29lZjtcbiAgICB9XG5cbiAgICAvLyBFdWNsaWRlYW4gZGl2aXNpb25cbiAgICBkaXZCeShwb2x5bm9taWFsKSB7XG4gICAgICAgIGNvbnN0IEZyID0gdGhpcy5GcjtcbiAgICAgICAgY29uc3QgZGVncmVlQSA9IHRoaXMuZGVncmVlKCk7XG4gICAgICAgIGNvbnN0IGRlZ3JlZUIgPSBwb2x5bm9taWFsLmRlZ3JlZSgpO1xuXG4gICAgICAgIGxldCBwb2xSID0gbmV3IFBvbHlub21pYWwodGhpcy5jb2VmLCB0aGlzLmN1cnZlLCB0aGlzLmxvZ2dlcik7XG5cbiAgICAgICAgdGhpcy5jb2VmID0gdGhpcy5sZW5ndGgoKSA+IDIgPDwgMTQgP1xuICAgICAgICAgICAgbmV3IEJpZ0J1ZmZlcih0aGlzLmxlbmd0aCgpICogRnIubjgpIDogbmV3IFVpbnQ4QXJyYXkodGhpcy5sZW5ndGgoKSAqIEZyLm44KTtcblxuICAgICAgICBmb3IgKGxldCBpID0gZGVncmVlQSAtIGRlZ3JlZUI7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgICAgICB0aGlzLnNldENvZWYoaSwgRnIuZGl2KHBvbFIuZ2V0Q29lZihpICsgZGVncmVlQiksIHBvbHlub21pYWwuZ2V0Q29lZihkZWdyZWVCKSkpO1xuICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPD0gZGVncmVlQjsgaisrKSB7XG4gICAgICAgICAgICAgICAgcG9sUi5zZXRDb2VmKGkgKyBqLCBGci5zdWIocG9sUi5nZXRDb2VmKGkgKyBqKSwgRnIubXVsKHRoaXMuZ2V0Q29lZihpKSwgcG9seW5vbWlhbC5nZXRDb2VmKGopKSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHBvbFI7XG4gICAgfVxuXG4gICAgLy8gRGl2aXNpb24gYnkgYSBQb2x5bm9taWFsIG9mIHRoZSBmb3JtICh4Xm0gLSBiZXRhKVxuICAgIGRpdkJ5TW9uaWMobSwgYmV0YSkge1xuICAgICAgICBjb25zdCBGciA9IHRoaXMuRnI7XG5cbiAgICAgICAgbGV0IGQgPSB0aGlzLmRlZ3JlZSgpO1xuXG4gICAgICAgIGxldCBidWZmZXIgPSB0aGlzLmxlbmd0aCgpID4gMiA8PCAxNCA/XG4gICAgICAgICAgICBuZXcgQmlnQnVmZmVyKHRoaXMubGVuZ3RoKCkgKiBGci5uOCkgOiBuZXcgVWludDhBcnJheSh0aGlzLmxlbmd0aCgpICogRnIubjgpO1xuICAgICAgICBsZXQgcXVvdGllbnQgPSBuZXcgUG9seW5vbWlhbChidWZmZXIsIHRoaXMuY3VydmUsIHRoaXMubG9nZ2VyKTtcblxuICAgICAgICBsZXQgYkFyciA9IFtdO1xuXG4gICAgICAgIC8vIEFkZCB0aGUgbSBsZWFkaW5nIGNvZWZmaWNpZW50cyBvZiB0aGlzIHRvIHF1b3RpZW50XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbTsgaSsrKSB7XG4gICAgICAgICAgICBxdW90aWVudC5zZXRDb2VmKChkIC0gaSkgLSBtLCB0aGlzLmdldENvZWYoZCAtIGkpKTtcbiAgICAgICAgICAgIGJBcnJbaV0gPSB0aGlzLmdldENvZWYoZCAtIGkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG5UaHJlYWRzID0gbTtcblxuICAgICAgICBsZXQgaiA9IDA7XG4gICAgICAgIGZvciAobGV0IGsgPSAwOyBrIDwgblRocmVhZHM7IGsrKykge1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IGQgLSAyICogbSAtIGs7IGkgPj0gMDsgaSA9IGkgLSBuVGhyZWFkcykge1xuICAgICAgICAgICAgICAgIGlmIChpIDwgMCkgYnJlYWs7XG4gICAgICAgICAgICAgICAgbGV0IGlkeCA9IGs7XG4gICAgICAgICAgICAgICAgYkFycltpZHhdID0gRnIuYWRkKHRoaXMuZ2V0Q29lZihpICsgbSksIEZyLm11bChiQXJyW2lkeF0sIGJldGEpKTtcblxuICAgICAgICAgICAgICAgIHF1b3RpZW50LnNldENvZWYoaSwgYkFycltpZHhdKTtcbiAgICAgICAgICAgICAgICBqID0gKGogKyAxKSAlIG07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNvZWYgPSBxdW90aWVudC5jb2VmO1xuICAgIH1cblxuICAgIGRpdkJ5VmFuaXNoaW5nKG4sIGJldGEpIHtcbiAgICAgICAgaWYgKHRoaXMuZGVncmVlKCkgPCBuKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJkaXZCeVZhbmlzaGluZyBwb2x5bm9taWFsIGRpdmlzb3IgbXVzdCBiZSBvZiBkZWdyZWUgbG93ZXIgdGhhbiB0aGUgZGl2aWRlbmQgcG9seW5vbWlhbFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IEZyID0gdGhpcy5GcjtcblxuICAgICAgICBsZXQgcG9sUiA9IG5ldyBQb2x5bm9taWFsKHRoaXMuY29lZiwgdGhpcy5jdXJ2ZSwgdGhpcy5sb2dnZXIpO1xuXG4gICAgICAgIHRoaXMuY29lZiA9IHRoaXMubGVuZ3RoKCkgPiAyIDw8IDE0ID9cbiAgICAgICAgICAgIG5ldyBCaWdCdWZmZXIodGhpcy5sZW5ndGgoKSAqIEZyLm44KSA6IG5ldyBVaW50OEFycmF5KHRoaXMubGVuZ3RoKCkgKiBGci5uOCk7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IHRoaXMubGVuZ3RoKCkgLSAxOyBpID49IG47IGktLSkge1xuICAgICAgICAgICAgbGV0IGxlYWRpbmdDb2VmID0gcG9sUi5nZXRDb2VmKGkpO1xuICAgICAgICAgICAgaWYgKEZyLmVxKEZyLnplcm8sIGxlYWRpbmdDb2VmKSkgY29udGludWU7XG5cbiAgICAgICAgICAgIHBvbFIuc2V0Q29lZihpLCBGci56ZXJvKTtcbiAgICAgICAgICAgIHBvbFIuc2V0Q29lZihpIC0gbiwgRnIuYWRkKHBvbFIuZ2V0Q29lZihpIC0gbiksIEZyLm11bChiZXRhLCBsZWFkaW5nQ29lZikpKTtcbiAgICAgICAgICAgIHRoaXMuc2V0Q29lZihpIC0gbiwgRnIuYWRkKHRoaXMuZ2V0Q29lZihpIC0gbiksIGxlYWRpbmdDb2VmKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcG9sUjtcbiAgICB9XG5cbiAgICBkaXZCeVZhbmlzaGluZzIobSwgYmV0YSkge1xuICAgICAgICBpZiAodGhpcy5kZWdyZWUoKSA8IG0pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImRpdkJ5VmFuaXNoaW5nIHBvbHlub21pYWwgZGl2aXNvciBtdXN0IGJlIG9mIGRlZ3JlZSBsb3dlciB0aGFuIHRoZSBkaXZpZGVuZCBwb2x5bm9taWFsXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgRnIgPSB0aGlzLkZyO1xuXG4gICAgICAgIGxldCBwb2xSID0gbmV3IFBvbHlub21pYWwodGhpcy5jb2VmLCB0aGlzLmN1cnZlLCB0aGlzLmxvZ2dlcik7XG5cbiAgICAgICAgdGhpcy5jb2VmID0gdGhpcy5sZW5ndGgoKSA+IDIgPDwgMTQgP1xuICAgICAgICAgICAgbmV3IEJpZ0J1ZmZlcih0aGlzLmxlbmd0aCgpICogRnIubjgpIDogbmV3IFVpbnQ4QXJyYXkodGhpcy5sZW5ndGgoKSAqIEZyLm44KTtcblxuICAgICAgICBsZXQgblRocmVhZHMgPSAzO1xuICAgICAgICBsZXQgblRvdGFsID0gdGhpcy5sZW5ndGgoKSAtIG07XG4gICAgICAgIGxldCBuRWxlbWVudHNDaHVuayA9IE1hdGguZmxvb3IoblRvdGFsIC8gblRocmVhZHMpO1xuICAgICAgICBsZXQgbkVsZW1lbnRzTGFzdCA9IG5Ub3RhbCAtIChuVGhyZWFkcyAtIDEpICogbkVsZW1lbnRzQ2h1bms7XG5cbiAgICAgICAgY29uc29sZS5sb2coblRvdGFsKTtcbiAgICAgICAgY29uc29sZS5sb2cobkVsZW1lbnRzQ2h1bmsgKyBcIiAgXCIgKyBuRWxlbWVudHNMYXN0KTtcbiAgICAgICAgZm9yIChsZXQgayA9IDA7IGsgPCBuVGhyZWFkczsgaysrKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIj4gVGhyZWFkIFwiICsgayk7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gKGsgPT09IDAgPyBuRWxlbWVudHNMYXN0IDogbkVsZW1lbnRzQ2h1bmspOyBpID4gMDsgaS0tKSB7XG4gICAgICAgICAgICAgICAgbGV0IGlkeERzdCA9IGkgLSAxO1xuICAgICAgICAgICAgICAgIGlmIChrICE9PSAwKSBpZHhEc3QgKz0gKGsgLSAxKSAqIG5FbGVtZW50c0NodW5rICsgbkVsZW1lbnRzTGFzdDtcbiAgICAgICAgICAgICAgICBsZXQgaWR4U3JjID0gaWR4RHN0ICsgbTtcblxuICAgICAgICAgICAgICAgIGxldCBsZWFkaW5nQ29lZiA9IHBvbFIuZ2V0Q29lZihpZHhTcmMpO1xuICAgICAgICAgICAgICAgIGlmIChGci5lcShGci56ZXJvLCBsZWFkaW5nQ29lZikpIGNvbnRpbnVlO1xuXG4gICAgICAgICAgICAgICAgcG9sUi5zZXRDb2VmKGlkeFNyYywgRnIuemVybyk7XG4gICAgICAgICAgICAgICAgcG9sUi5zZXRDb2VmKGlkeERzdCwgRnIuYWRkKHBvbFIuZ2V0Q29lZihpZHhEc3QpLCBGci5tdWwoYmV0YSwgbGVhZGluZ0NvZWYpKSk7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRDb2VmKGlkeERzdCwgRnIuYWRkKHRoaXMuZ2V0Q29lZihpZHhEc3QpLCBsZWFkaW5nQ29lZikpO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGlkeERzdCArIFwiIDwtLSBcIiArIGlkeFNyYyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnByaW50KCk7XG4gICAgICAgIHJldHVybiBwb2xSO1xuICAgIH1cblxuICAgIGZhc3REaXZCeVZhbmlzaGluZyhkYXRhKSB7XG4gICAgICAgIGNvbnN0IEZyID0gdGhpcy5GcjtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRhdGEubGVuZ3RoOyBpKyspIHtcblxuICAgICAgICAgICAgbGV0IG0gPSBkYXRhW2ldWzBdO1xuICAgICAgICAgICAgbGV0IGJldGEgPSBkYXRhW2ldWzFdO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5kZWdyZWUoKSA8IG0pIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJkaXZCeVZhbmlzaGluZyBwb2x5bm9taWFsIGRpdmlzb3IgbXVzdCBiZSBvZiBkZWdyZWUgbG93ZXIgdGhhbiB0aGUgZGl2aWRlbmQgcG9seW5vbWlhbFwiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IG5UaHJlYWRzID0gNTtcbiAgICAgICAgICAgIGxldCBuRWxlbWVudHMgPSB0aGlzLmxlbmd0aCgpIC0gbTtcbiAgICAgICAgICAgIGxldCBuRWxlbWVudHNCdWNrZXQgPSBNYXRoLmZsb29yKG5FbGVtZW50cyAvIG5UaHJlYWRzIC8gbSk7XG4gICAgICAgICAgICBsZXQgbkVsZW1lbnRzQ2h1bmsgPSBuRWxlbWVudHNCdWNrZXQgKiBtO1xuICAgICAgICAgICAgbGV0IG5FbGVtZW50c0xhc3QgPSBuRWxlbWVudHMgLSBuVGhyZWFkcyAqIG5FbGVtZW50c0NodW5rO1xuXG4gICAgICAgICAgICAvL0luIEMrKyBpbXBsZW1lbnRhdGlvbiB0aGlzIGJ1ZmZlciB3aWxsIGJlIGFsbG9jYXRlZCBvbmx5IG9uY2Ugb3V0c2lkZSB0aGUgbG9vcFxuICAgICAgICAgICAgbGV0IHBvbFRtcCA9IG5ldyBQb2x5bm9taWFsKHRoaXMubGVuZ3RoKCkgPiAyIDw8IDE0ID9cbiAgICAgICAgICAgICAgICBuZXcgQmlnQnVmZmVyKHRoaXMubGVuZ3RoKCkgKiBGci5uOCkgOiBuZXcgVWludDhBcnJheSh0aGlzLmxlbmd0aCgpICogRnIubjgpLCB0aGlzLmN1cnZlLCB0aGlzLmxvZ2dlcik7XG5cbiAgICAgICAgICAgIGxldCBwdHIgPSB0aGlzLmNvZWY7XG4gICAgICAgICAgICB0aGlzLmNvZWYgPSBwb2xUbXAuY29lZjtcbiAgICAgICAgICAgIHBvbFRtcC5jb2VmID0gcHRyO1xuXG4gICAgICAgICAgICAvLyBTVEVQIDE6IFNldGVqYXIgZWxzIG0gdmFsb3JzIGRlbCBzZWfDvGVudCBidWNrZXQgYWwgY2h1bmsgYWN0dWFsLCBQQVJBTEVMwrdMSVRaQVJcbiAgICAgICAgICAgIGZvciAobGV0IGsgPSAwOyBrIDwgblRocmVhZHM7IGsrKykge1xuICAgICAgICAgICAgICAgIGxldCBpZHgwID0gKGsgKyAxKSAqIG5FbGVtZW50c0NodW5rICsgbkVsZW1lbnRzTGFzdDtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG07IGkrKykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNldENvZWYoaWR4MCArIGkgLSBtLCBwb2xUbXAuZ2V0Q29lZihpZHgwICsgaSkpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbkVsZW1lbnRzQ2h1bmsgLSBtOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IG9mZnNldCA9IGlkeDAgLSBpIC0gMTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHZhbCA9IEZyLmFkZChwb2xUbXAuZ2V0Q29lZihvZmZzZXQpLCBGci5tdWwoYmV0YSwgdGhpcy5nZXRDb2VmKG9mZnNldCkpKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRDb2VmKG9mZnNldCAtIG0sIHZhbCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvL1NURVAgMjogU2V0ZWphciBlbHMgdmFsb3JzIGRlbCBlbGVtZW50cyBsYXN0IE5PIFBBUkFMwrdMRUxJVFpBUlxuICAgICAgICAgICAgbGV0IGlkeDAgPSBuRWxlbWVudHNMYXN0O1xuICAgICAgICAgICAgbGV0IHBlbmRpbmcgPSBuRWxlbWVudHNMYXN0O1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtICYmIHBlbmRpbmc7IGkrKykge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0Q29lZihpZHgwIC0gaSAtIDEsIHBvbFRtcC5nZXRDb2VmKGlkeDAgKyBtIC0gaSAtIDEpKTtcbiAgICAgICAgICAgICAgICBwZW5kaW5nLS07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGVuZGluZzsgaSsrKSB7XG4gICAgICAgICAgICAgICAgbGV0IG9mZnNldCA9IGlkeDAgLSBpIC0gMTtcbiAgICAgICAgICAgICAgICBsZXQgdmFsID0gRnIuYWRkKHBvbFRtcC5nZXRDb2VmKG9mZnNldCksIEZyLm11bChiZXRhLCB0aGlzLmdldENvZWYob2Zmc2V0KSkpO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0Q29lZihvZmZzZXQgLSBtLCB2YWwpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvL1N0ZXAgMzogY2FsY3VsYXIgYWN1bXVsYXRzIE5PICBQQVJBTEVMwrdMSVRaQVJcblxuICAgICAgICAgICAgbGV0IGFjYyA9IFtdO1xuICAgICAgICAgICAgbGV0IGJldGFQb3cgPSBGci5vbmU7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5FbGVtZW50c0J1Y2tldDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgYmV0YVBvdyA9IEZyLm11bChiZXRhUG93LCBiZXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBjdXJyZW50QmV0YSA9IEZyLm9uZTtcblxuICAgICAgICAgICAgZm9yIChsZXQgayA9IG5UaHJlYWRzOyBrID4gMDsgay0tKSB7XG4gICAgICAgICAgICAgICAgbGV0IGlkVGhyZWFkID0gayAtIDE7XG4gICAgICAgICAgICAgICAgbGV0IGlkeDAgPSBpZFRocmVhZCAqIG5FbGVtZW50c0NodW5rICsgbkVsZW1lbnRzTGFzdDtcbiAgICAgICAgICAgICAgICBhY2NbaWRUaHJlYWRdID0gW107XG5cbiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG07IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBhY2NbaWRUaHJlYWRdW2ldID0gdGhpcy5nZXRDb2VmKGlkeDAgKyBpKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoayAhPT0gblRocmVhZHMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjY1tpZFRocmVhZF1baV0gPSBGci5hZGQoYWNjW2lkVGhyZWFkXVtpXSwgRnIubXVsKGJldGFQb3csIGFjY1tpZFRocmVhZCArIDFdW2ldKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY3VycmVudEJldGEgPSBGci5tdWwoY3VycmVudEJldGEsIGJldGFQb3cpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvL1NURVAgNCByZWNhbGN1bGFyICBQQVJBTEVMwrdMSVRaQVJcbiAgICAgICAgICAgIGZvciAobGV0IGsgPSAwOyBrIDwgblRocmVhZHM7IGsrKykge1xuXG4gICAgICAgICAgICAgICAgbGV0IGlkeDAgPSBrICogbkVsZW1lbnRzQ2h1bmsgKyBuRWxlbWVudHNMYXN0O1xuICAgICAgICAgICAgICAgIGxldCBjdXJyZW50QmV0YSA9IGJldGE7IC8vUXVhbiBob3Bhc3NlbSBhIEMrKyBpIGhvIHBhcmFsZWxpdHplbSBhcXVlc3RhIHZhcmlhYmxlIGhhIGRlIHNlciBwcml2YWRhXG4gICAgICAgICAgICAgICAgbGV0IGN1cnJlbnRNID0gbSAtIDE7XG5cbiAgICAgICAgICAgICAgICBsZXQgbGltaXQgPSBrID09PSAwID8gbkVsZW1lbnRzTGFzdCA6IG5FbGVtZW50c0NodW5rO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGltaXQ7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBsZXQgb2Zmc2V0ID0gaWR4MCAtIGkgLSAxO1xuICAgICAgICAgICAgICAgICAgICBsZXQgdmFsID0gRnIuYWRkKHRoaXMuZ2V0Q29lZihvZmZzZXQpLCBGci5tdWwoY3VycmVudEJldGEsIGFjY1trXVtjdXJyZW50TV0pKTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNldENvZWYob2Zmc2V0LCB2YWwpO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFRvIGF2b2lkIG1vZHVsYXIgb3BlcmF0aW9ucyBpbiBlYWNoIGxvb3AuLi5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRNID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50TSA9IG0gLSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudEJldGEgPSBGci5tdWwoY3VycmVudEJldGEsIGJldGEpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudE0tLTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgLy8gRGl2aWRlIHBvbHlub21pYWwgYnkgWCAtIHZhbHVlXG4gICAgZGl2QnlYU3ViVmFsdWUodmFsdWUpIHtcbiAgICAgICAgY29uc3QgY29lZnMgPSB0aGlzLmxlbmd0aCgpID4gMiA8PCAxNCA/XG4gICAgICAgICAgICBuZXcgQmlnQnVmZmVyKHRoaXMubGVuZ3RoKCkgKiB0aGlzLkZyLm44KSA6IG5ldyBVaW50OEFycmF5KHRoaXMubGVuZ3RoKCkgKiB0aGlzLkZyLm44KTtcblxuICAgICAgICBjb2Vmcy5zZXQodGhpcy5Gci56ZXJvLCAodGhpcy5sZW5ndGgoKSAtIDEpICogdGhpcy5Gci5uOCk7XG4gICAgICAgIGNvZWZzLnNldCh0aGlzLmNvZWYuc2xpY2UoKHRoaXMubGVuZ3RoKCkgLSAxKSAqIHRoaXMuRnIubjgsIHRoaXMubGVuZ3RoKCkgKiB0aGlzLkZyLm44KSwgKHRoaXMubGVuZ3RoKCkgLSAyKSAqIHRoaXMuRnIubjgpO1xuICAgICAgICBmb3IgKGxldCBpID0gdGhpcy5sZW5ndGgoKSAtIDM7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgICAgICBsZXQgaV9uOCA9IGkgKiB0aGlzLkZyLm44O1xuICAgICAgICAgICAgY29lZnMuc2V0KFxuICAgICAgICAgICAgICAgIHRoaXMuRnIuYWRkKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvZWYuc2xpY2UoaV9uOCArIHRoaXMuRnIubjgsIGlfbjggKyAyICogdGhpcy5Gci5uOCksXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuRnIubXVsKHZhbHVlLCBjb2Vmcy5zbGljZShpX244ICsgdGhpcy5Gci5uOCwgaV9uOCArIDIgKiB0aGlzLkZyLm44KSlcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgIGkgKiB0aGlzLkZyLm44XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5Gci5lcShcbiAgICAgICAgICAgIHRoaXMuY29lZi5zbGljZSgwLCB0aGlzLkZyLm44KSxcbiAgICAgICAgICAgIHRoaXMuRnIubXVsKHRoaXMuRnIubmVnKHZhbHVlKSwgY29lZnMuc2xpY2UoMCwgdGhpcy5Gci5uOCkpXG4gICAgICAgICkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlBvbHlub21pYWwgZG9lcyBub3QgZGl2aWRlXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jb2VmID0gY29lZnM7XG4gICAgfVxuXG4gICAgZGl2WmgoZG9tYWluU2l6ZSwgZXh0ZW5zaW9ucyA9IDQpIHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBkb21haW5TaXplOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGlfbjggPSBpICogdGhpcy5Gci5uODtcbiAgICAgICAgICAgIHRoaXMuY29lZi5zZXQodGhpcy5Gci5uZWcodGhpcy5jb2VmLnNsaWNlKGlfbjgsIGlfbjggKyB0aGlzLkZyLm44KSksIGlfbjgpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdXBwZXJCb3VuZCA9IHRoaXMuY29lZi5ieXRlTGVuZ3RoIC8gdGhpcy5Gci5uODtcbiAgICAgICAgZm9yIChsZXQgaSA9IGRvbWFpblNpemU7IGkgPCB1cHBlckJvdW5kOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGlfbjggPSBpICogdGhpcy5Gci5uODtcblxuICAgICAgICAgICAgY29uc3QgYSA9IHRoaXMuRnIuc3ViKFxuICAgICAgICAgICAgICAgIHRoaXMuY29lZi5zbGljZSgoaSAtIGRvbWFpblNpemUpICogdGhpcy5Gci5uOCwgKGkgLSBkb21haW5TaXplKSAqIHRoaXMuRnIubjggKyB0aGlzLkZyLm44KSxcbiAgICAgICAgICAgICAgICB0aGlzLmNvZWYuc2xpY2UoaV9uOCwgaV9uOCArIHRoaXMuRnIubjgpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5jb2VmLnNldChhLCBpX244KTtcbiAgICAgICAgICAgIGlmIChpID4gKGRvbWFpblNpemUgKiAoZXh0ZW5zaW9ucy0xKSAtIGV4dGVuc2lvbnMpKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLkZyLmlzWmVybyhhKSkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJQb2x5bm9taWFsIGlzIG5vdCBkaXZpc2libGVcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgZGl2QnlaZXJvZmllcihuLCBiZXRhKSB7XG4gICAgICAgIGxldCBGciA9IHRoaXMuRnI7XG4gICAgICAgIGNvbnN0IGludkJldGEgPSBGci5pbnYoYmV0YSk7XG4gICAgICAgIGNvbnN0IGludkJldGFOZWcgPSBGci5uZWcoaW52QmV0YSk7XG5cbiAgICAgICAgbGV0IGlzT25lID0gRnIuZXEoRnIub25lLCBpbnZCZXRhTmVnKTtcbiAgICAgICAgbGV0IGlzTmVnT25lID0gRnIuZXEoRnIubmVnb25lLCBpbnZCZXRhTmVnKTtcblxuICAgICAgICBpZiAoIWlzT25lKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGlfbjggPSBpICogdGhpcy5Gci5uODtcbiAgICAgICAgICAgICAgICBsZXQgZWxlbWVudDtcblxuICAgICAgICAgICAgICAgIC8vIElmIGludkJldGFOZWcgPT09IC0xIHdlJ2xsIHNhdmUgYSBtdWx0aXBsaWNhdGlvbiBjaGFuZ2luZyBpdCBieSBhIG5lZyBmdW5jdGlvbiBjYWxsXG4gICAgICAgICAgICAgICAgaWYgKGlzTmVnT25lKSB7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQgPSBGci5uZWcodGhpcy5jb2VmLnNsaWNlKGlfbjgsIGlfbjggKyB0aGlzLkZyLm44KSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudCA9IEZyLm11bChpbnZCZXRhTmVnLCB0aGlzLmNvZWYuc2xpY2UoaV9uOCwgaV9uOCArIHRoaXMuRnIubjgpKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLmNvZWYuc2V0KGVsZW1lbnQsIGlfbjgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaXNPbmUgPSBGci5lcShGci5vbmUsIGludkJldGEpO1xuICAgICAgICBpc05lZ09uZSA9IEZyLmVxKEZyLm5lZ29uZSwgaW52QmV0YSk7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IG47IGkgPCB0aGlzLmxlbmd0aCgpOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGlfbjggPSBpICogdGhpcy5Gci5uODtcbiAgICAgICAgICAgIGNvbnN0IGlfcHJldl9uOCA9IChpIC0gbikgKiB0aGlzLkZyLm44O1xuXG4gICAgICAgICAgICBsZXQgZWxlbWVudCA9IHRoaXMuRnIuc3ViKFxuICAgICAgICAgICAgICAgIHRoaXMuY29lZi5zbGljZShpX3ByZXZfbjgsIGlfcHJldl9uOCArIHRoaXMuRnIubjgpLFxuICAgICAgICAgICAgICAgIHRoaXMuY29lZi5zbGljZShpX244LCBpX244ICsgdGhpcy5Gci5uOClcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIC8vIElmIGludkJldGEgPT09IDEgd2UnbGwgbm90IGRvIGFueXRoaW5nXG4gICAgICAgICAgICBpZighaXNPbmUpIHtcbiAgICAgICAgICAgICAgICAvLyBJZiBpbnZCZXRhID09PSAtMSB3ZSdsbCBzYXZlIGEgbXVsdGlwbGljYXRpb24gY2hhbmdpbmcgaXQgYnkgYSBuZWcgZnVuY3Rpb24gY2FsbFxuICAgICAgICAgICAgICAgIGlmKGlzTmVnT25lKSB7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQgPSBGci5uZWcoZWxlbWVudCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudCA9IEZyLm11bChpbnZCZXRhLCBlbGVtZW50KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuY29lZi5zZXQoZWxlbWVudCwgaV9uOCk7XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHBvbHlub21pYWwgaXMgZGl2aXNpYmxlIGJ5IGNoZWNraW5nIGlmIG4gaGlnaCBjb2VmZmljaWVudHMgYXJlIHplcm9cbiAgICAgICAgICAgIGlmIChpID4gdGhpcy5sZW5ndGgoKSAtIG4gLSAxKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLkZyLmlzWmVybyhlbGVtZW50KSkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJQb2x5bm9taWFsIGlzIG5vdCBkaXZpc2libGVcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgLy8gZnVuY3Rpb24gZGl2aWRlQnlWYW5pc2hpbmcoZiwgbiwgcCkge1xuICAgIC8vICAgICAvLyBwb2x5bm9taWFsIGRpdmlzaW9uIGYoWCkgLyAoWF5uIC0gMSkgd2l0aCByZW1haW5kZXJcbiAgICAvLyAgICAgLy8gdmVyeSBjaGVhcCwgMCBtdWx0aXBsaWNhdGlvbnNcbiAgICAvLyAgICAgLy8gc3RyYXRlZ3k6XG4gICAgLy8gICAgIC8vIHN0YXJ0IHdpdGggcShYKSA9IDAsIHIoWCkgPSBmKFgpXG4gICAgLy8gICAgIC8vIHRoZW4gc3RhcnQgY2hhbmdpbmcgcSwgciB3aGlsZSBwcmVzZXJ2aW5nIHRoZSBpZGVudGl0eTpcbiAgICAvLyAgICAgLy8gZihYKSA9IHEoWCkgKiAoWF5uIC0gMSkgKyByKFgpXG4gICAgLy8gICAgIC8vIGluIGV2ZXJ5IHN0ZXAsIG1vdmUgaGlnaGVzdC1kZWdyZWUgdGVybSBvZiByIGludG8gdGhlIHByb2R1Y3RcbiAgICAvLyAgICAgLy8gPT4gciBldmVudHVhbGx5IGhhcyBkZWdyZWUgPCBuIGFuZCB3ZSdyZSBkb25lXG4gICAgLy8gICAgIGxldCBxID0gQXJyYXkoZi5sZW5ndGgpLmZpbGwoMG4pO1xuICAgIC8vICAgICBsZXQgciA9IFsuLi5mXTtcbiAgICAvLyAgICAgZm9yIChsZXQgaSA9IGYubGVuZ3RoIC0gMTsgaSA+PSBuOyBpLS0pIHtcbiAgICAvLyAgICAgICAgIGxldCBsZWFkaW5nQ29lZmYgPSByW2ldO1xuICAgIC8vICAgICAgICAgaWYgKGxlYWRpbmdDb2VmZiA9PT0gMG4pIGNvbnRpbnVlO1xuICAgIC8vICAgICAgICAgcltpXSA9IDBuO1xuICAgIC8vICAgICAgICAgcltpIC0gbl0gPSBtb2QocltpIC0gbl0gKyBsZWFkaW5nQ29lZmYsIHApO1xuICAgIC8vICAgICAgICAgcVtpIC0gbl0gPSBtb2QocVtpIC0gbl0gKyBsZWFkaW5nQ29lZmYsIHApO1xuICAgIC8vICAgICB9XG4gICAgLy8gICAgIHJldHVybiBbcSwgcl07XG4gICAgLy8gfVxuXG4gICAgYnlYKCkge1xuICAgICAgICBjb25zdCBjb2VmcyA9ICh0aGlzLmxlbmd0aCgpICsgMSkgPiAyIDw8IDE0ID9cbiAgICAgICAgICAgIG5ldyBCaWdCdWZmZXIodGhpcy5jb2VmLmJ5dGVMZW5ndGggKyB0aGlzLkZyLm44KSA6IG5ldyBVaW50OEFycmF5KHRoaXMuY29lZi5ieXRlTGVuZ3RoICsgdGhpcy5Gci5uOCk7XG4gICAgICAgIGNvZWZzLnNldCh0aGlzLkZyLnplcm8sIDApO1xuICAgICAgICBjb2Vmcy5zZXQodGhpcy5jb2VmLCB0aGlzLkZyLm44KTtcblxuICAgICAgICB0aGlzLmNvZWYgPSBjb2VmcztcbiAgICB9XG5cbiAgICAvLyBDb21wdXRlIGEgbmV3IHBvbHlub21pYWwgZih4Xm4pIGZyb20gZih4KVxuICAgIC8vIGYoeCkgICA9IGFfMCArIGFfMcK3eCArIGFfMsK3eF4yICsgLi4uICsgYV9qwrd4XmpcbiAgICAvLyBmKHhebikgPSBhXzAgKyBhXzHCt3hebiArIGFfMsK3eF4ybiArIC4uLiArIGFfasK3eF5qblxuICAgIHN0YXRpY1xuICAgIGFzeW5jIGV4cFgocG9seW5vbWlhbCwgbiwgdHJ1bmNhdGUgPSBmYWxzZSkge1xuICAgICAgICBjb25zdCBGciA9IHBvbHlub21pYWwuRnI7XG5cbiAgICAgICAgaWYgKG4gPCAxKSB7XG4gICAgICAgICAgICAvLyBuID09IDAgbm90IGFsbG93ZWQgYmVjYXVzZSBpdCBoYXMgbm8gc2Vuc2UsIGJ1dCBpZiBpdCdzIG5lY2Vzc2FyeSB3ZSBoYXZlIHRvIHJldHVyblxuICAgICAgICAgICAgLy8gYSB6ZXJvIGRlZ3JlZSBwb2x5bm9taWFsIHdpdGggYSBjb25zdGFudCBjb2VmZmljaWVudCBlcXVhbHMgdG8gdGhlIHN1bSBvZiBhbGwgdGhlIG9yaWdpbmFsIGNvZWZmaWNpZW50c1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29tcHV0ZSBhIG5ldyBwb2x5bm9taWFsIHRvIGEgemVybyBvciBuZWdhdGl2ZSBudW1iZXIgaXMgbm90IGFsbG93ZWRcIik7XG4gICAgICAgIH0gZWxzZSBpZiAoMSA9PT0gbikge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IFBvbHlub21pYWwuZnJvbUV2YWx1YXRpb25zKHBvbHlub21pYWwuY29lZiwgcG9seW5vbWlhbC5jdXJ2ZSwgcG9seW5vbWlhbC5sb2dnZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gbGVuZ3RoIGlzIHRoZSBsZW5ndGggb2Ygbm9uLWNvbnN0YW50IGNvZWZmaWNpZW50c1xuICAgICAgICAvLyBpZiB0cnVuY2F0ZSA9PT0gdHJ1ZSwgdGhlIGhpZ2hlc3QgemVybyBjb2VmZmljaWVudHMgKGlmIGV4aXN0KSB3aWxsIGJlIHJlbW92ZWRcbiAgICAgICAgY29uc3QgbGVuZ3RoID0gdHJ1bmNhdGUgPyBwb2x5bm9taWFsLmRlZ3JlZSgpIDogKHBvbHlub21pYWwubGVuZ3RoKCkgLSAxKTtcbiAgICAgICAgY29uc3QgYnVmZmVyRHN0ID0gKGxlbmd0aCAqIG4gKyAxKSA+IDIgPDwgMTQgP1xuICAgICAgICAgICAgbmV3IEJpZ0J1ZmZlcigobGVuZ3RoICogbiArIDEpICogRnIubjgpIDogbmV3IFVpbnQ4QXJyYXkoKGxlbmd0aCAqIG4gKyAxKSAqIEZyLm44KTtcblxuICAgICAgICAvLyBDb3B5IGNvbnN0YW50IGNvZWZmaWNpZW50IGFzIGlzIGJlY2F1c2UgaXMgbm90IHJlbGF0ZWQgdG8geFxuICAgICAgICBidWZmZXJEc3Quc2V0KHBvbHlub21pYWwuZ2V0Q29lZigwKSwgMCk7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPD0gbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGlfc0ZyID0gaSAqIEZyLm44O1xuXG4gICAgICAgICAgICBjb25zdCBjb2VmID0gcG9seW5vbWlhbC5nZXRDb2VmKGkpO1xuICAgICAgICAgICAgYnVmZmVyRHN0LnNldChjb2VmLCBpX3NGciAqIG4pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyBQb2x5bm9taWFsKGJ1ZmZlckRzdCwgcG9seW5vbWlhbC5jdXJ2ZSwgcG9seW5vbWlhbC5sb2dnZXIpO1xuICAgIH1cblxuICAgIHNwbGl0KG51bVBvbHMsIGRlZ1BvbHMsIGJsaW5kaW5nRmFjdG9ycykge1xuICAgICAgICBpZiAobnVtUG9scyA8IDEpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgUG9seW5vbWlhbHMgY2FuJ3QgYmUgc3BsaXQgaW4gJHtudW1Qb2xzfSBwYXJ0c2ApO1xuICAgICAgICB9IGVsc2UgaWYgKDEgPT09IG51bVBvbHMpIHtcbiAgICAgICAgICAgIHJldHVybiBbdGhpc107XG4gICAgICAgIH1cblxuICAgICAgICAvL2JsaW5kaW5nIGZhY3RvcnMgY2FuIGJlIHZvaWQgb3IgbXVzdCBoYXZlIGEgbGVuZ3RoIG9mIG51bVBvbHMgLSAxXG4gICAgICAgIGlmICgwICE9PSBibGluZGluZ0ZhY3RvcnMubGVuZ3RoICYmIGJsaW5kaW5nRmFjdG9ycy5sZW5ndGggPCBudW1Qb2xzIC0gMSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBCbGluZGluZyBmYWN0b3JzIGxlbmd0aCBtdXN0IGJlICR7bnVtUG9scyAtIDF9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjaHVua0J5dGVMZW5ndGggPSAoZGVnUG9scyArIDEpICogdGhpcy5Gci5uODtcbiAgICAgICAgbGV0IHJlcyA9IFtdO1xuXG4gICAgICAgIC8vIENoZWNrIHBvbHlub21pYWwgY2FuIGJlIHNwbGl0IGluIG51bUNodW5rcyBwYXJ0cyBvZiBjaHVua1NpemUgYnl0ZXMuLi5cbiAgICAgICAgY29uc3QgbnVtUmVhbFBvbHMgPSBNYXRoLmNlaWwoKHRoaXMuZGVncmVlKCkgKyAxKSAqIHRoaXMuRnIubjggLyBjaHVua0J5dGVMZW5ndGgpO1xuICAgICAgICBpZiAobnVtUmVhbFBvbHMgPCBudW1Qb2xzKSB7XG4gICAgICAgICAgICAvL3Rocm93IG5ldyBFcnJvcihgUG9seW5vbWlhbCBpcyBzaG9ydCB0byBiZSBzcGxpdCBpbiAke251bVBvbHN9IHBhcnRzIG9mICR7ZGVnUG9sc30gY29lZmZpY2llbnRzIGVhY2guYCk7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gbnVtUmVhbFBvbHM7IGkgPCBudW1Qb2xzOyBpKyspIHtcbiAgICAgICAgICAgICAgICByZXNbaV0gPSBuZXcgUG9seW5vbWlhbChuZXcgVWludDhBcnJheSh0aGlzLkZyLm44KSwgdGhpcy5jdXJ2ZSwgdGhpcy5sb2dnZXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbnVtUG9scyA9IE1hdGgubWluKG51bVBvbHMsIG51bVJlYWxQb2xzKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1Qb2xzOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGlzTGFzdCA9IChudW1Qb2xzIC0gMSkgPT09IGk7XG4gICAgICAgICAgICBjb25zdCBieXRlTGVuZ3RoID0gaXNMYXN0ID8gdGhpcy5jb2VmLmJ5dGVMZW5ndGggLSAoKG51bVBvbHMgLSAxKSAqIGNodW5rQnl0ZUxlbmd0aCkgOiBjaHVua0J5dGVMZW5ndGggKyB0aGlzLkZyLm44O1xuXG4gICAgICAgICAgICBsZXQgYnVmZiA9IChieXRlTGVuZ3RoIC8gdGhpcy5Gci5uOCkgPiAyIDw8IDE0ID8gbmV3IEJpZ0J1ZmZlcihieXRlTGVuZ3RoKSA6IG5ldyBVaW50OEFycmF5KGJ5dGVMZW5ndGgpO1xuICAgICAgICAgICAgcmVzW2ldID0gbmV3IFBvbHlub21pYWwoYnVmZiwgdGhpcy5jdXJ2ZSwgdGhpcy5sb2dnZXIpO1xuXG4gICAgICAgICAgICBjb25zdCBmciA9IGkgKiBjaHVua0J5dGVMZW5ndGg7XG4gICAgICAgICAgICBjb25zdCB0byA9IGlzTGFzdCA/IHRoaXMuY29lZi5ieXRlTGVuZ3RoIDogKGkgKyAxKSAqIGNodW5rQnl0ZUxlbmd0aDtcbiAgICAgICAgICAgIHJlc1tpXS5jb2VmLnNldCh0aGlzLmNvZWYuc2xpY2UoZnIsIHRvKSwgMCk7XG5cbiAgICAgICAgICAgIC8vIEFkZCBhIGJsaW5kaW5nIGZhY3RvciBhcyBoaWdoZXIgZGVncmVlXG4gICAgICAgICAgICBpZiAoIWlzTGFzdCkge1xuICAgICAgICAgICAgICAgIHJlc1tpXS5jb2VmLnNldChibGluZGluZ0ZhY3RvcnNbaV0sIGNodW5rQnl0ZUxlbmd0aCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFN1YiBibGluZGluZyBmYWN0b3IgdG8gdGhlIGxvd2VzdCBkZWdyZWVcbiAgICAgICAgICAgIGlmICgwICE9PSBpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgbG93ZXN0RGVncmVlID0gdGhpcy5Gci5zdWIocmVzW2ldLmNvZWYuc2xpY2UoMCwgdGhpcy5Gci5uOCksIGJsaW5kaW5nRmFjdG9yc1tpIC0gMV0pO1xuICAgICAgICAgICAgICAgIHJlc1tpXS5jb2VmLnNldChsb3dlc3REZWdyZWUsIDApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoaXNMYXN0KSB7XG4gICAgICAgICAgICAgICAgcmVzW2ldLnRydW5jYXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzO1xuXG4gICAgICAgIC8vIC8vIGNvbXB1dGUgdF9sb3coWClcbiAgICAgICAgLy8gbGV0IHBvbFRMb3cgPSBuZXcgQmlnQnVmZmVyKChjaHVua1NpemUgKyAxKSAqIG44cik7XG4gICAgICAgIC8vIHBvbFRMb3cuc2V0KHQuc2xpY2UoMCwgemtleS5kb21haW5TaXplICogbjhyKSwgMCk7XG4gICAgICAgIC8vIC8vIEFkZCBibGluZGluZyBzY2FsYXIgYl8xMCBhcyBhIG5ldyBjb2VmZmljaWVudCBuXG4gICAgICAgIC8vIHBvbFRMb3cuc2V0KGNoLmJbMTBdLCB6a2V5LmRvbWFpblNpemUgKiBuOHIpO1xuICAgICAgICAvL1xuICAgICAgICAvLyAvLyBjb21wdXRlIHRfbWlkKFgpXG4gICAgICAgIC8vIGxldCBwb2xUTWlkID0gbmV3IEJpZ0J1ZmZlcigoemtleS5kb21haW5TaXplICsgMSkgKiBuOHIpO1xuICAgICAgICAvLyBwb2xUTWlkLnNldCh0LnNsaWNlKHprZXkuZG9tYWluU2l6ZSAqIG44ciwgemtleS5kb21haW5TaXplICogMiAqIG44ciksIDApO1xuICAgICAgICAvLyAvLyBTdWJ0cmFjdCBibGluZGluZyBzY2FsYXIgYl8xMCB0byB0aGUgbG93ZXN0IGNvZWZmaWNpZW50IG9mIHRfbWlkXG4gICAgICAgIC8vIGNvbnN0IGxvd2VzdE1pZCA9IEZyLnN1Yihwb2xUTWlkLnNsaWNlKDAsIG44ciksIGNoLmJbMTBdKTtcbiAgICAgICAgLy8gcG9sVE1pZC5zZXQobG93ZXN0TWlkLCAwKTtcbiAgICAgICAgLy8gLy8gQWRkIGJsaW5kaW5nIHNjYWxhciBiXzExIGFzIGEgbmV3IGNvZWZmaWNpZW50IG5cbiAgICAgICAgLy8gcG9sVE1pZC5zZXQoY2guYlsxMV0sIHprZXkuZG9tYWluU2l6ZSAqIG44cik7XG4gICAgICAgIC8vXG4gICAgICAgIC8vIC8vIGNvbXB1dGUgdF9oaWdoKFgpXG4gICAgICAgIC8vIGxldCBwb2xUSGlnaCA9IG5ldyBCaWdCdWZmZXIoKHprZXkuZG9tYWluU2l6ZSArIDYpICogbjhyKTtcbiAgICAgICAgLy8gcG9sVEhpZ2guc2V0KHQuc2xpY2UoemtleS5kb21haW5TaXplICogMiAqIG44ciwgKHprZXkuZG9tYWluU2l6ZSAqIDMgKyA2KSAqIG44ciksIDApO1xuICAgICAgICAvLyAvL1N1YnRyYWN0IGJsaW5kaW5nIHNjYWxhciBiXzExIHRvIHRoZSBsb3dlc3QgY29lZmZpY2llbnQgb2YgdF9oaWdoXG4gICAgICAgIC8vIGNvbnN0IGxvd2VzdEhpZ2ggPSBGci5zdWIocG9sVEhpZ2guc2xpY2UoMCwgbjhyKSwgY2guYlsxMV0pO1xuICAgICAgICAvLyBwb2xUSGlnaC5zZXQobG93ZXN0SGlnaCwgMCk7XG4gICAgICAgIC8vXG4gICAgICAgIC8vIHByb29mLlQxID0gYXdhaXQgZXhwVGF1KHBvbFRMb3csIFwibXVsdGlleHAgVDFcIik7XG4gICAgICAgIC8vIHByb29mLlQyID0gYXdhaXQgZXhwVGF1KHBvbFRNaWQsIFwibXVsdGlleHAgVDJcIik7XG4gICAgICAgIC8vIHByb29mLlQzID0gYXdhaXQgZXhwVGF1KHBvbFRIaWdoLCBcIm11bHRpZXhwIFQzXCIpO1xuICAgIH1cblxuICAgIC8vIHNwbGl0MihkZWdQb2xzLCBibGluZGluZ0ZhY3RvcnMpIHtcbiAgICAvLyAgICAgbGV0IGN1cnJlbnREZWdyZWUgPSB0aGlzLmRlZ3JlZSgpO1xuICAgIC8vICAgICBjb25zdCBudW1GaWxsZWRQb2xzID0gTWF0aC5jZWlsKChjdXJyZW50RGVncmVlICsgMSkgLyAoZGVnUG9scyArIDEpKTtcbiAgICAvL1xuICAgIC8vICAgICAvL2JsaW5kaW5nIGZhY3RvcnMgY2FuIGJlIHZvaWQgb3IgbXVzdCBoYXZlIGEgbGVuZ3RoIG9mIG51bVBvbHMgLSAxXG4gICAgLy8gICAgIGlmICgwICE9PSBibGluZGluZ0ZhY3RvcnMubGVuZ3RoICYmIGJsaW5kaW5nRmFjdG9ycy5sZW5ndGggPCBudW1GaWxsZWRQb2xzIC0gMSkge1xuICAgIC8vICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBCbGluZGluZyBmYWN0b3JzIGxlbmd0aCBtdXN0IGJlICR7bnVtRmlsbGVkUG9scyAtIDF9YCk7XG4gICAgLy8gICAgIH1cbiAgICAvL1xuICAgIC8vICAgICBjb25zdCBjaHVua0J5dGVMZW5ndGggPSAoZGVnUG9scyArIDEpICogdGhpcy5Gci5uODtcbiAgICAvL1xuICAgIC8vICAgICAvLyBDaGVjayBwb2x5bm9taWFsIGNhbiBiZSBzcGxpdCBpbiBudW1DaHVua3MgcGFydHMgb2YgY2h1bmtTaXplIGJ5dGVzLi4uXG4gICAgLy8gICAgIGlmICh0aGlzLmNvZWYuYnl0ZUxlbmd0aCAvIGNodW5rQnl0ZUxlbmd0aCA8PSBudW1GaWxsZWRQb2xzIC0gMSkge1xuICAgIC8vICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBQb2x5bm9taWFsIGlzIHNob3J0IHRvIGJlIHNwbGl0IGluICR7bnVtRmlsbGVkUG9sc30gcGFydHMgb2YgJHtkZWdQb2xzfSBjb2VmZmljaWVudHMgZWFjaC5gKTtcbiAgICAvLyAgICAgfVxuICAgIC8vXG4gICAgLy8gICAgIGxldCByZXMgPSBbXTtcbiAgICAvLyAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1GaWxsZWRQb2xzOyBpKyspIHtcbiAgICAvLyAgICAgICAgIGNvbnN0IGlzTGFzdCA9IChudW1GaWxsZWRQb2xzIC0gMSkgPT09IGk7XG4gICAgLy8gICAgICAgICBjb25zdCBieXRlTGVuZ3RoID0gaXNMYXN0ID8gKGN1cnJlbnREZWdyZWUgKyAxKSAqIHRoaXMuRnIubjggLSAoKG51bUZpbGxlZFBvbHMgLSAxKSAqIGNodW5rQnl0ZUxlbmd0aCkgOiBjaHVua0J5dGVMZW5ndGggKyB0aGlzLkZyLm44O1xuICAgIC8vXG4gICAgLy8gICAgICAgICByZXNbaV0gPSBuZXcgUG9seW5vbWlhbChuZXcgQmlnQnVmZmVyKGJ5dGVMZW5ndGgpLCB0aGlzLkZyLCB0aGlzLmxvZ2dlcik7XG4gICAgLy8gICAgICAgICBjb25zdCBmciA9IGkgKiBjaHVua0J5dGVMZW5ndGg7XG4gICAgLy8gICAgICAgICBjb25zdCB0byA9IGlzTGFzdCA/IChjdXJyZW50RGVncmVlICsgMSkgKiB0aGlzLkZyLm44IDogKGkgKyAxKSAqIGNodW5rQnl0ZUxlbmd0aDtcbiAgICAvLyAgICAgICAgIHJlc1tpXS5jb2VmLnNldCh0aGlzLmNvZWYuc2xpY2UoZnIsIHRvKSwgMCk7XG4gICAgLy9cbiAgICAvLyAgICAgICAgIC8vIEFkZCBhIGJsaW5kaW5nIGZhY3RvciBhcyBoaWdoZXIgZGVncmVlXG4gICAgLy8gICAgICAgICBpZiAoIWlzTGFzdCkge1xuICAgIC8vICAgICAgICAgICAgIHJlc1tpXS5jb2VmLnNldChibGluZGluZ0ZhY3RvcnNbaV0sIGNodW5rQnl0ZUxlbmd0aCk7XG4gICAgLy8gICAgICAgICB9XG4gICAgLy9cbiAgICAvLyAgICAgICAgIC8vIFN1YiBibGluZGluZyBmYWN0b3IgdG8gdGhlIGxvd2VzdCBkZWdyZWVcbiAgICAvLyAgICAgICAgIGlmICgwICE9PSBpKSB7XG4gICAgLy8gICAgICAgICAgICAgY29uc3QgbG93ZXN0RGVncmVlID0gdGhpcy5Gci5zdWIocmVzW2ldLmNvZWYuc2xpY2UoMCwgdGhpcy5Gci5uOCksIGJsaW5kaW5nRmFjdG9yc1tpIC0gMV0pO1xuICAgIC8vICAgICAgICAgICAgIHJlc1tpXS5jb2VmLnNldChsb3dlc3REZWdyZWUsIDApO1xuICAgIC8vICAgICAgICAgfVxuICAgIC8vICAgICB9XG4gICAgLy9cbiAgICAvLyAgICAgcmV0dXJuIHJlcztcbiAgICAvLyB9XG5cbiAgICAvLyBtZXJnZShwb2xzLCBvdmVybGFwID0gdHJ1ZSkge1xuICAgIC8vICAgICBsZXQgbGVuZ3RoID0gMDtcbiAgICAvLyAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb2xzLmxlbmd0aDsgaSsrKSB7XG4gICAgLy8gICAgICAgICBsZW5ndGggKz0gcG9sc1tpXS5sZW5ndGgoKTtcbiAgICAvLyAgICAgfVxuICAgIC8vXG4gICAgLy8gICAgIGlmIChvdmVybGFwKSB7XG4gICAgLy8gICAgICAgICBsZW5ndGggLT0gcG9scy5sZW5ndGggLSAxO1xuICAgIC8vICAgICB9XG4gICAgLy9cbiAgICAvLyAgICAgbGV0IHJlcyA9IG5ldyBQb2x5bm9taWFsKG5ldyBCaWdCdWZmZXIobGVuZ3RoICogdGhpcy5Gci5uOCkpO1xuICAgIC8vICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvbHMubGVuZ3RoOyBpKyspIHtcbiAgICAvLyAgICAgICAgIGNvbnN0IGJ5dGVMZW5ndGggPSBwb2xzW2ldLmNvZWYuYnl0ZUxlbmd0aDtcbiAgICAvLyAgICAgICAgIGlmICgwID09PSBpKSB7XG4gICAgLy8gICAgICAgICAgICAgcmVzLmNvZWYuc2V0KHBvbHNbaV0uY29lZiwgMCk7XG4gICAgLy8gICAgICAgICB9IGVsc2Uge1xuICAgIC8vXG4gICAgLy8gICAgICAgICB9XG4gICAgLy8gICAgIH1cbiAgICAvL1xuICAgIC8vICAgICByZXR1cm4gcmVzO1xuICAgIC8vIH1cblxuICAgIHRydW5jYXRlKCkge1xuICAgICAgICBjb25zdCBkZWcgPSB0aGlzLmRlZ3JlZSgpO1xuICAgICAgICBpZiAoZGVnICsgMSA8IHRoaXMuY29lZi5ieXRlTGVuZ3RoIC8gdGhpcy5Gci5uOCkge1xuICAgICAgICAgICAgY29uc3QgbmV3Q29lZnMgPSAoZGVnICsgMSkgPiAyIDw8IDE0ID9cbiAgICAgICAgICAgICAgICBuZXcgQmlnQnVmZmVyKChkZWcgKyAxKSAqIHRoaXMuRnIubjgpIDogbmV3IFVpbnQ4QXJyYXkoKGRlZyArIDEpICogdGhpcy5Gci5uOCk7XG5cbiAgICAgICAgICAgIG5ld0NvZWZzLnNldCh0aGlzLmNvZWYuc2xpY2UoMCwgKGRlZyArIDEpICogdGhpcy5Gci5uOCksIDApO1xuICAgICAgICAgICAgdGhpcy5jb2VmID0gbmV3Q29lZnM7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzdGF0aWMgbGFncmFuZ2VQb2x5bm9taWFsSW50ZXJwb2xhdGlvbih4QXJyLCB5QXJyLCBjdXJ2ZSkge1xuICAgICAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgICAgICBsZXQgcG9seW5vbWlhbCA9IGNvbXB1dGVMYWdyYW5nZVBvbHlub21pYWwoMCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAxOyBpIDwgeEFyci5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgcG9seW5vbWlhbC5hZGQoY29tcHV0ZUxhZ3JhbmdlUG9seW5vbWlhbChpKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcG9seW5vbWlhbDtcblxuICAgICAgICBmdW5jdGlvbiBjb21wdXRlTGFncmFuZ2VQb2x5bm9taWFsKGkpIHtcbiAgICAgICAgICAgIGxldCBwb2x5bm9taWFsO1xuXG4gICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHhBcnIubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICBpZiAoaiA9PT0gaSkgY29udGludWU7XG5cbiAgICAgICAgICAgICAgICBpZiAocG9seW5vbWlhbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBidWZmID0gKHhBcnIubGVuZ3RoKSA+IDIgPDwgMTQgP1xuICAgICAgICAgICAgICAgICAgICAgICAgbmV3IEJpZ0J1ZmZlcigoeEFyci5sZW5ndGgpICogRnIubjgpIDogbmV3IFVpbnQ4QXJyYXkoKHhBcnIubGVuZ3RoKSAqIEZyLm44KTtcbiAgICAgICAgICAgICAgICAgICAgcG9seW5vbWlhbCA9IG5ldyBQb2x5bm9taWFsKGJ1ZmYsIGN1cnZlKTtcbiAgICAgICAgICAgICAgICAgICAgcG9seW5vbWlhbC5zZXRDb2VmKDAsIEZyLm5lZyh4QXJyW2pdKSk7XG4gICAgICAgICAgICAgICAgICAgIHBvbHlub21pYWwuc2V0Q29lZigxLCBGci5vbmUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHBvbHlub21pYWwuYnlYU3ViVmFsdWUoeEFycltqXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgZGVub21pbmF0b3IgPSBwb2x5bm9taWFsLmV2YWx1YXRlKHhBcnJbaV0pO1xuICAgICAgICAgICAgZGVub21pbmF0b3IgPSBGci5pbnYoZGVub21pbmF0b3IpO1xuICAgICAgICAgICAgY29uc3QgbXVsRmFjdG9yID0gRnIubXVsKHlBcnJbaV0sIGRlbm9taW5hdG9yKTtcblxuICAgICAgICAgICAgcG9seW5vbWlhbC5tdWxTY2FsYXIobXVsRmFjdG9yKTtcblxuICAgICAgICAgICAgcmV0dXJuIHBvbHlub21pYWw7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzdGF0aWMgemVyb2ZpZXJQb2x5bm9taWFsKHhBcnIsIGN1cnZlKSB7XG4gICAgICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG4gICAgICAgIGxldCBidWZmID0gKHhBcnIubGVuZ3RoICsgMSkgPiAyIDw8IDE0ID9cbiAgICAgICAgICAgIG5ldyBCaWdCdWZmZXIoKHhBcnIubGVuZ3RoICsgMSkgKiBGci5uOCkgOiBuZXcgVWludDhBcnJheSgoeEFyci5sZW5ndGggKyAxKSAqIEZyLm44KTtcbiAgICAgICAgbGV0IHBvbHlub21pYWwgPSBuZXcgUG9seW5vbWlhbChidWZmLCBjdXJ2ZSk7XG5cbiAgICAgICAgLy8gQnVpbGQgYSB6ZXJvZmllciBwb2x5bm9taWFsIHdpdGggdGhlIGZvbGxvd2luZyBmb3JtOlxuICAgICAgICAvLyB6ZXJvZmllcihYKSA9IChYLXhBcnJbMF0pKFgteEFyclsxXSkuLi4oWC14QXJyW25dKVxuICAgICAgICBwb2x5bm9taWFsLnNldENvZWYoMCwgRnIubmVnKHhBcnJbMF0pKTtcbiAgICAgICAgcG9seW5vbWlhbC5zZXRDb2VmKDEsIEZyLm9uZSk7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPCB4QXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBwb2x5bm9taWFsLmJ5WFN1YlZhbHVlKHhBcnJbaV0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHBvbHlub21pYWw7XG4gICAgfVxuXG4gICAgcHJpbnQoKSB7XG4gICAgICAgIGNvbnN0IEZyID0gdGhpcy5GcjtcbiAgICAgICAgbGV0IHJlcyA9IFwiXCI7XG4gICAgICAgIGZvciAobGV0IGkgPSB0aGlzLmRlZ3JlZSgpOyBpID49IDA7IGktLSkge1xuICAgICAgICAgICAgY29uc3QgY29lZiA9IHRoaXMuZ2V0Q29lZihpKTtcbiAgICAgICAgICAgIGlmICghRnIuZXEoRnIuemVybywgY29lZikpIHtcbiAgICAgICAgICAgICAgICBpZiAoRnIuaXNOZWdhdGl2ZShjb2VmKSkge1xuICAgICAgICAgICAgICAgICAgICByZXMgKz0gXCIgLSBcIjtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGkgIT09IHRoaXMuZGVncmVlKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzICs9IFwiICsgXCI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJlcyArPSBGci50b1N0cmluZyhjb2VmKTtcbiAgICAgICAgICAgICAgICBpZiAoaSA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzICs9IGkgPiAxID8gXCJ4XlwiICsgaSA6IFwieFwiO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZyhyZXMpO1xuICAgIH1cblxuICAgIGFzeW5jIG11bHRpRXhwb25lbnRpYXRpb24oUFRhdSwgbmFtZSkge1xuICAgICAgICBjb25zdCBuID0gdGhpcy5jb2VmLmJ5dGVMZW5ndGggLyB0aGlzLkZyLm44O1xuICAgICAgICBjb25zdCBQVGF1TiA9IFBUYXUuc2xpY2UoMCwgbiAqIHRoaXMuRzEuRi5uOCAqIDIpO1xuICAgICAgICBjb25zdCBibSA9IGF3YWl0IHRoaXMuRnIuYmF0Y2hGcm9tTW9udGdvbWVyeSh0aGlzLmNvZWYpO1xuICAgICAgICBsZXQgcmVzID0gYXdhaXQgdGhpcy5HMS5tdWx0aUV4cEFmZmluZShQVGF1TiwgYm0sIHRoaXMubG9nZ2VyLCBuYW1lKTtcbiAgICAgICAgcmVzID0gdGhpcy5HMS50b0FmZmluZShyZXMpO1xuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cbn0iLCIvKlxuICAgIENvcHlyaWdodCAyMDIyIGlkZW4zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQge0JpZ0J1ZmZlcn0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuXG5leHBvcnQgY2xhc3MgRXZhbHVhdGlvbnMge1xuICAgIGNvbnN0cnVjdG9yKGV2YWx1YXRpb25zLCBjdXJ2ZSwgbG9nZ2VyKSB7XG4gICAgICAgIHRoaXMuZXZhbCA9IGV2YWx1YXRpb25zO1xuICAgICAgICB0aGlzLmN1cnZlID0gY3VydmU7XG4gICAgICAgIHRoaXMuRnIgPSBjdXJ2ZS5GcjtcbiAgICAgICAgdGhpcy5sb2dnZXIgPSBsb2dnZXI7XG4gICAgfVxuXG4gICAgc3RhdGljIGFzeW5jIGZyb21Qb2x5bm9taWFsKHBvbHlub21pYWwsIGV4dGVuc2lvbiwgY3VydmUsIGxvZ2dlcikge1xuICAgICAgICBjb25zdCBjb2VmZmljaWVudHNOID0gbmV3IEJpZ0J1ZmZlcihwb2x5bm9taWFsLmxlbmd0aCgpICogZXh0ZW5zaW9uICogY3VydmUuRnIubjgpO1xuICAgICAgICBjb2VmZmljaWVudHNOLnNldChwb2x5bm9taWFsLmNvZWYsIDApO1xuXG4gICAgICAgIGNvbnN0IGV2YWx1YXRpb25zID0gYXdhaXQgY3VydmUuRnIuZmZ0KGNvZWZmaWNpZW50c04pO1xuXG4gICAgICAgIHJldHVybiBuZXcgRXZhbHVhdGlvbnMoZXZhbHVhdGlvbnMsIGN1cnZlLCBsb2dnZXIpO1xuICAgIH1cblxuICAgIGdldEV2YWx1YXRpb24oaW5kZXgpIHtcbiAgICAgICAgY29uc3QgaV9uOCA9IGluZGV4ICogdGhpcy5Gci5uODtcblxuICAgICAgICBpZiAoaV9uOCArIHRoaXMuRnIubjggPiB0aGlzLmV2YWwuYnl0ZUxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRXZhbHVhdGlvbnMuZ2V0RXZhbHVhdGlvbigpIG91dCBvZiBib3VuZHNcIik7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5ldmFsLnNsaWNlKGlfbjgsIGlfbjggKyB0aGlzLkZyLm44KTtcbiAgICB9XG5cbiAgICBsZW5ndGgoKSB7XG4gICAgICAgIGxldCBsZW5ndGggPSB0aGlzLmV2YWwuYnl0ZUxlbmd0aCAvIHRoaXMuRnIubjg7XG4gICAgICAgIGlmIChsZW5ndGggIT09IE1hdGguZmxvb3IodGhpcy5ldmFsLmJ5dGVMZW5ndGggLyB0aGlzLkZyLm44KSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUG9seW5vbWlhbCBldmFsdWF0aW9ucyBidWZmZXIgaGFzIGluY29ycmVjdCBzaXplXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmICgwID09PSBsZW5ndGgpIHtcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLndhcm4oXCJQb2x5bm9taWFsIGhhcyBsZW5ndGggemVyb1wiKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbGVuZ3RoO1xuICAgIH1cbn0iLCIvKlxuICAgIENvcHlyaWdodCAyMDIxIDBraW1zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG4vKiBJbXBsZW1lbnRhdGlvbiBvZiB0aGlzIHBhcGVyOiBodHRwczovL2VwcmludC5pYWNyLm9yZy8yMDE5Lzk1My5wZGYgc2VjdGlvbiA4LjQgKi9cblxuaW1wb3J0ICogYXMgYmluRmlsZVV0aWxzIGZyb20gXCJAaWRlbjMvYmluZmlsZXV0aWxzXCI7XG5pbXBvcnQgKiBhcyB6a2V5VXRpbHMgZnJvbSBcIi4vemtleV91dGlscy5qc1wiO1xuaW1wb3J0ICogYXMgd3Ruc1V0aWxzIGZyb20gXCIuL3d0bnNfdXRpbHMuanNcIjtcbmltcG9ydCB7IFNjYWxhciwgdXRpbHMsIEJpZ0J1ZmZlciB9IGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmNvbnN0IHtzdHJpbmdpZnlCaWdJbnRzfSA9IHV0aWxzO1xuaW1wb3J0IHsgUHJvb2YgfSBmcm9tIFwiLi9wcm9vZi5qc1wiO1xuaW1wb3J0IHsgS2VjY2FrMjU2VHJhbnNjcmlwdCB9IGZyb20gXCIuL0tlY2NhazI1NlRyYW5zY3JpcHQuanNcIjtcbmltcG9ydCB7IE11bFogfSBmcm9tIFwiLi9tdWxfei5qc1wiO1xuaW1wb3J0IHsgIFpLRVlfUExfQURESVRJT05TX1NFQ1RJT04sXG4gICAgWktFWV9QTF9BX01BUF9TRUNUSU9OLFxuICAgIFpLRVlfUExfQl9NQVBfU0VDVElPTixcbiAgICBaS0VZX1BMX0NfTUFQX1NFQ1RJT04sXG4gICAgWktFWV9QTF9RTV9TRUNUSU9OLFxuICAgIFpLRVlfUExfUUxfU0VDVElPTixcbiAgICBaS0VZX1BMX1FSX1NFQ1RJT04sXG4gICAgWktFWV9QTF9RT19TRUNUSU9OLFxuICAgIFpLRVlfUExfUUNfU0VDVElPTixcbiAgICBaS0VZX1BMX1NJR01BX1NFQ1RJT04sXG4gICAgWktFWV9QTF9MQUdSQU5HRV9TRUNUSU9OLFxuICAgIFpLRVlfUExfUFRBVV9TRUNUSU9OLFxufSBmcm9tIFwiLi9wbG9ua19jb25zdGFudHMuanNcIjtcbmltcG9ydCB7IFBvbHlub21pYWwgfSBmcm9tIFwiLi9wb2x5bm9taWFsL3BvbHlub21pYWwuanNcIjtcbmltcG9ydCB7IEV2YWx1YXRpb25zIH0gZnJvbSBcIi4vcG9seW5vbWlhbC9ldmFsdWF0aW9ucy5qc1wiO1xuICAgIFxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gcGxvbmsxNlByb3ZlKHprZXlGaWxlTmFtZSwgd2l0bmVzc0ZpbGVOYW1lLCBsb2dnZXIsIG9wdGlvbnMpIHtcbiAgICBjb25zdCB7ZmQ6IGZkV3Rucywgc2VjdGlvbnM6IHNlY3Rpb25zV3Ruc30gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUod2l0bmVzc0ZpbGVOYW1lLCBcInd0bnNcIiwgMiwgMTw8MjUsIDE8PDIzKTtcblxuICAgIC8vIFJlYWQgd2l0bmVzcyBmaWxlXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiPiBSZWFkaW5nIHdpdG5lc3MgZmlsZVwiKTtcbiAgICBjb25zdCB3dG5zID0gYXdhaXQgd3Ruc1V0aWxzLnJlYWRIZWFkZXIoZmRXdG5zLCBzZWN0aW9uc1d0bnMpO1xuXG4gICAgLy8gUmVhZCB6a2V5IGZpbGVcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IFJlYWRpbmcgemtleSBmaWxlXCIpO1xuICAgIGNvbnN0IHtmZDogZmRaS2V5LCBzZWN0aW9uczogemtleVNlY3Rpb25zfSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmluRmlsZSh6a2V5RmlsZU5hbWUsIFwiemtleVwiLCAyLCAxPDwyNSwgMTw8MjMpO1xuXG4gICAgY29uc3QgemtleSA9IGF3YWl0IHprZXlVdGlscy5yZWFkSGVhZGVyKGZkWktleSwgemtleVNlY3Rpb25zLCB1bmRlZmluZWQsIG9wdGlvbnMpO1xuICAgIGlmICh6a2V5LnByb3RvY29sICE9IFwicGxvbmtcIikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJ6a2V5IGZpbGUgaXMgbm90IHBsb25rXCIpO1xuICAgIH1cblxuICAgIGlmICghU2NhbGFyLmVxKHprZXkuciwgIHd0bnMucSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ3VydmUgb2YgdGhlIHdpdG5lc3MgZG9lcyBub3QgbWF0Y2ggdGhlIGN1cnZlIG9mIHRoZSBwcm92aW5nIGtleVwiKTtcbiAgICB9XG5cbiAgICBpZiAod3Rucy5uV2l0bmVzcyAhPSB6a2V5Lm5WYXJzIC16a2V5Lm5BZGRpdGlvbnMpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHdpdG5lc3MgbGVuZ3RoLiBDaXJjdWl0OiAke3prZXkublZhcnN9LCB3aXRuZXNzOiAke3d0bnMubldpdG5lc3N9LCAke3prZXkubkFkZGl0aW9uc31gKTtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJ2ZSA9IHprZXkuY3VydmU7XG5cbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgIGNvbnN0IG44ciA9IGN1cnZlLkZyLm44O1xuICAgIGNvbnN0IHNEb21haW4gPSB6a2V5LmRvbWFpblNpemUgKiBuOHI7XG5cbiAgICBpZiAobG9nZ2VyKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIik7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcIiAgUExPTksgUFJPVkUgU0VUVElOR1NcIik7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgICBDdXJ2ZTogICAgICAgICAke2N1cnZlLm5hbWV9YCk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgICBDaXJjdWl0IHBvd2VyOiAke3prZXkucG93ZXJ9YCk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgICBEb21haW4gc2l6ZTogICAke3prZXkuZG9tYWluU2l6ZX1gKTtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGAgIFZhcnM6ICAgICAgICAgICR7emtleS5uVmFyc31gKTtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGAgIFB1YmxpYyB2YXJzOiAgICR7emtleS5uUHVibGljfWApO1xuICAgICAgICBsb2dnZXIuZGVidWcoYCAgQ29uc3RyYWludHM6ICAgJHt6a2V5Lm5Db25zdHJhaW50c31gKTtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGAgIEFkZGl0aW9uczogICAgICR7emtleS5uQWRkaXRpb25zfWApO1xuICAgICAgICBsb2dnZXIuZGVidWcoXCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXCIpO1xuICAgIH1cblxuICAgIC8vUmVhZCB3aXRuZXNzIGRhdGFcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IFJlYWRpbmcgd2l0bmVzcyBmaWxlIGRhdGFcIik7XG4gICAgY29uc3QgYnVmZldpdG5lc3MgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRXdG5zLCBzZWN0aW9uc1d0bnMsIDIpO1xuXG4gICAgLy8gRmlyc3QgZWxlbWVudCBpbiBwbG9uayBpcyBub3QgdXNlZCBhbmQgY2FuIGJlIGFueSB2YWx1ZS4gKEJ1dCBhbHdheXMgdGhlIHNhbWUpLlxuICAgIC8vIFdlIHNldCBpdCB0byB6ZXJvIHRvIGdvIGZhc3RlciBpbiB0aGUgZXhwb25lbnRpYXRpb25zLlxuICAgIGJ1ZmZXaXRuZXNzLnNldChGci56ZXJvLCAwKTtcbiAgICBjb25zdCBidWZmSW50ZXJuYWxXaXRuZXNzID0gbmV3IEJpZ0J1ZmZlcihuOHIqemtleS5uQWRkaXRpb25zKTtcblxuICAgIGxldCBidWZmZXJzID0ge307XG4gICAgbGV0IHBvbHlub21pYWxzID0ge307XG4gICAgbGV0IGV2YWx1YXRpb25zID0ge307XG5cbiAgICBsZXQgY2hhbGxlbmdlcyA9IHt9O1xuICAgIGxldCBwcm9vZiA9IG5ldyBQcm9vZihjdXJ2ZSwgbG9nZ2VyKTtcbiAgICBjb25zdCB0cmFuc2NyaXB0ID0gbmV3IEtlY2NhazI1NlRyYW5zY3JpcHQoY3VydmUpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKGA+IFJlYWRpbmcgU2VjdGlvbiAke1pLRVlfUExfQURESVRJT05TX1NFQ1RJT059LiBBZGRpdGlvbnNgKTtcbiAgICBhd2FpdCBjYWxjdWxhdGVBZGRpdGlvbnMoKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgPiBSZWFkaW5nIFNlY3Rpb24gJHtaS0VZX1BMX1NJR01BX1NFQ1RJT059LiBTaWdtYTEsIFNpZ21hMiAmIFNpZ21hIDNgKTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCLCt8K3wrcgUmVhZGluZyBTaWdtYSBwb2x5bm9taWFscyBcIik7XG4gICAgcG9seW5vbWlhbHMuU2lnbWExID0gbmV3IFBvbHlub21pYWwobmV3IEJpZ0J1ZmZlcihzRG9tYWluKSwgY3VydmUsIGxvZ2dlcik7XG4gICAgcG9seW5vbWlhbHMuU2lnbWEyID0gbmV3IFBvbHlub21pYWwobmV3IEJpZ0J1ZmZlcihzRG9tYWluKSwgY3VydmUsIGxvZ2dlcik7XG4gICAgcG9seW5vbWlhbHMuU2lnbWEzID0gbmV3IFBvbHlub21pYWwobmV3IEJpZ0J1ZmZlcihzRG9tYWluKSwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKHBvbHlub21pYWxzLlNpZ21hMS5jb2VmLCAwLCBzRG9tYWluLCB6a2V5U2VjdGlvbnNbWktFWV9QTF9TSUdNQV9TRUNUSU9OXVswXS5wKTtcbiAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKHBvbHlub21pYWxzLlNpZ21hMi5jb2VmLCAwLCBzRG9tYWluLCB6a2V5U2VjdGlvbnNbWktFWV9QTF9TSUdNQV9TRUNUSU9OXVswXS5wICsgNSAqIHNEb21haW4pO1xuICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIocG9seW5vbWlhbHMuU2lnbWEzLmNvZWYsIDAsIHNEb21haW4sIHprZXlTZWN0aW9uc1taS0VZX1BMX1NJR01BX1NFQ1RJT05dWzBdLnAgKyAxMCAqIHNEb21haW4pO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiwrfCt8K3IFJlYWRpbmcgU2lnbWEgZXZhbHVhdGlvbnNcIik7XG4gICAgZXZhbHVhdGlvbnMuU2lnbWExID0gbmV3IEV2YWx1YXRpb25zKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICBldmFsdWF0aW9ucy5TaWdtYTIgPSBuZXcgRXZhbHVhdGlvbnMobmV3IEJpZ0J1ZmZlcihzRG9tYWluICogNCksIGN1cnZlLCBsb2dnZXIpO1xuICAgIGV2YWx1YXRpb25zLlNpZ21hMyA9IG5ldyBFdmFsdWF0aW9ucyhuZXcgQmlnQnVmZmVyKHNEb21haW4gKiA0KSwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKGV2YWx1YXRpb25zLlNpZ21hMS5ldmFsLCAwLCBzRG9tYWluICogNCwgemtleVNlY3Rpb25zW1pLRVlfUExfU0lHTUFfU0VDVElPTl1bMF0ucCArIHNEb21haW4pO1xuICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIoZXZhbHVhdGlvbnMuU2lnbWEyLmV2YWwsIDAsIHNEb21haW4gKiA0LCB6a2V5U2VjdGlvbnNbWktFWV9QTF9TSUdNQV9TRUNUSU9OXVswXS5wICsgNiAqIHNEb21haW4pO1xuICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIoZXZhbHVhdGlvbnMuU2lnbWEzLmV2YWwsIDAsIHNEb21haW4gKiA0LCB6a2V5U2VjdGlvbnNbWktFWV9QTF9TSUdNQV9TRUNUSU9OXVswXS5wICsgMTEgKiBzRG9tYWluKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhgPiBSZWFkaW5nIFNlY3Rpb24gJHtaS0VZX1BMX1BUQVVfU0VDVElPTn0uIFBvd2VycyBvZiBUYXVgKTtcbiAgICBjb25zdCBQVGF1ID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRTZWN0aW9uKGZkWktleSwgemtleVNlY3Rpb25zLCBaS0VZX1BMX1BUQVVfU0VDVElPTik7XG5cbiAgICBsZXQgcHVibGljU2lnbmFscyA9IFtdO1xuXG4gICAgZm9yIChsZXQgaT0xOyBpPD0gemtleS5uUHVibGljOyBpKyspIHtcbiAgICAgICAgY29uc3QgcHViID0gYnVmZldpdG5lc3Muc2xpY2UoaSpGci5uOCwgaSpGci5uOCtGci5uOCk7XG4gICAgICAgIHB1YmxpY1NpZ25hbHMucHVzaChTY2FsYXIuZnJvbVJwckxFKHB1YikpO1xuICAgIH1cblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIlwiKTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IFJPVU5EIDFcIik7XG4gICAgYXdhaXQgcm91bmQxKCk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IFJPVU5EIDJcIik7XG4gICAgYXdhaXQgcm91bmQyKCk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IFJPVU5EIDNcIik7XG4gICAgYXdhaXQgcm91bmQzKCk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IFJPVU5EIDRcIik7XG4gICAgYXdhaXQgcm91bmQ0KCk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IFJPVU5EIDVcIik7XG4gICAgYXdhaXQgcm91bmQ1KCk7XG5cbiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgIC8vIEZpbmFsIGFkanVzdG1lbnRzIC8vXG4gICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuICAgIGF3YWl0IGZkWktleS5jbG9zZSgpO1xuICAgIGF3YWl0IGZkV3Rucy5jbG9zZSgpO1xuXG4gICAgLy8gUHJlcGFyZSBwcm9vZlxuICAgIGxldCBfcHJvb2YgPSBwcm9vZi50b09iamVjdFByb29mKGZhbHNlKTtcbiAgICBfcHJvb2YucHJvdG9jb2wgPSBcInBsb25rXCI7XG4gICAgX3Byb29mLmN1cnZlID0gY3VydmUubmFtZTtcbiAgICBcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJQTE9OSyBQUk9WRVIgRklOSVNIRURcIik7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICBwcm9vZjogc3RyaW5naWZ5QmlnSW50cyhfcHJvb2YpLFxuICAgICAgICBwdWJsaWNTaWduYWxzOiBzdHJpbmdpZnlCaWdJbnRzKHB1YmxpY1NpZ25hbHMpXG4gICAgfTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIGNhbGN1bGF0ZUFkZGl0aW9ucygpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiwrfCt8K3IENvbXB1dGluZyBhZGRpdGlvbnNcIik7XG4gICAgICAgIGNvbnN0IGFkZGl0aW9uc0J1ZmYgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRaS2V5LCB6a2V5U2VjdGlvbnMsIFpLRVlfUExfQURESVRJT05TX1NFQ1RJT04pO1xuXG4gICAgICAgIC8vIHNpemVzOiB3aXJlSWRfeCA9IDQgYnl0ZXMgKDMyIGJpdHMpLCBmYWN0b3JfeCA9IGZpZWxkIHNpemUgYml0c1xuICAgICAgICAvLyBBZGRpdGlvbiBmb3JtOiB3aXJlSWRfYSB3aXJlSWRfYiBmYWN0b3JfYSBmYWN0b3JfYiAoc2l6ZSBpcyA0ICsgNCArIHNGciArIHNGcilcbiAgICAgICAgY29uc3Qgc1N1bSA9IDggKyBuOHIgKiAyO1xuXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgemtleS5uQWRkaXRpb25zOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIgJiYgKDAgIT09IGkpICYmIChpICUgMTAwMDAwID09PSAwKSkgbG9nZ2VyLmRlYnVnKGAgICAgYWRkaXRpb24gJHtpfS8ke3prZXkubkFkZGl0aW9uc31gKTtcblxuICAgICAgICAgICAgLy8gUmVhZCBhZGRpdGlvbiB2YWx1ZXNcbiAgICAgICAgICAgIGxldCBvZmZzZXQgPSBpICogc1N1bTtcbiAgICAgICAgICAgIGNvbnN0IHNpZ25hbElkMSA9IHJlYWRVSW50MzIoYWRkaXRpb25zQnVmZiwgb2Zmc2V0KTtcbiAgICAgICAgICAgIG9mZnNldCArPSA0O1xuICAgICAgICAgICAgY29uc3Qgc2lnbmFsSWQyID0gcmVhZFVJbnQzMihhZGRpdGlvbnNCdWZmLCBvZmZzZXQpO1xuICAgICAgICAgICAgb2Zmc2V0ICs9IDQ7XG4gICAgICAgICAgICBjb25zdCBmYWN0b3IxID0gYWRkaXRpb25zQnVmZi5zbGljZShvZmZzZXQsIG9mZnNldCArIG44cik7XG4gICAgICAgICAgICBvZmZzZXQgKz0gbjhyO1xuICAgICAgICAgICAgY29uc3QgZmFjdG9yMiA9IGFkZGl0aW9uc0J1ZmYuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyBuOHIpO1xuXG4gICAgICAgICAgICAvLyBHZXQgd2l0bmVzcyB2YWx1ZVxuICAgICAgICAgICAgY29uc3Qgd2l0bmVzczEgPSBnZXRXaXRuZXNzKHNpZ25hbElkMSk7XG4gICAgICAgICAgICBjb25zdCB3aXRuZXNzMiA9IGdldFdpdG5lc3Moc2lnbmFsSWQyKTtcblxuICAgICAgICAgICAgLy9DYWxjdWxhdGUgZmluYWwgcmVzdWx0XG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSBGci5hZGQoRnIubXVsKGZhY3RvcjEsIHdpdG5lc3MxKSwgRnIubXVsKGZhY3RvcjIsIHdpdG5lc3MyKSk7XG5cbiAgICAgICAgICAgIGJ1ZmZJbnRlcm5hbFdpdG5lc3Muc2V0KHJlc3VsdCwgbjhyICogaSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZWFkVUludDMyKGIsIG8pIHtcbiAgICAgICAgY29uc3QgYnVmZiA9IGIuc2xpY2Uobywgbys0KTtcbiAgICAgICAgY29uc3QgYnVmZlYgPSBuZXcgRGF0YVZpZXcoYnVmZi5idWZmZXIsIGJ1ZmYuYnl0ZU9mZnNldCwgYnVmZi5ieXRlTGVuZ3RoKTtcbiAgICAgICAgcmV0dXJuIGJ1ZmZWLmdldFVpbnQzMigwLCB0cnVlKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRXaXRuZXNzKGlkeCkge1xuICAgICAgICBpZiAoaWR4IDwgemtleS5uVmFycy16a2V5Lm5BZGRpdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBidWZmV2l0bmVzcy5zbGljZShpZHgqbjhyLCBpZHgqbjhyK244cik7XG4gICAgICAgIH0gZWxzZSBpZiAoaWR4IDwgemtleS5uVmFycykge1xuICAgICAgICAgICAgcmV0dXJuIGJ1ZmZJbnRlcm5hbFdpdG5lc3Muc2xpY2UoKGlkeCAtICh6a2V5Lm5WYXJzLXprZXkubkFkZGl0aW9ucykpKm44ciwgKGlkeC0oemtleS5uVmFycy16a2V5Lm5BZGRpdGlvbnMpKSpuOHIgKyBuOHIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGN1cnZlLkZyLnplcm87XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiByb3VuZDEoKSB7XG4gICAgICAgIC8vIFNURVAgMS4xIC0gR2VuZXJhdGUgcmFuZG9tIGJsaW5kaW5nIHNjYWxhcnMgKGIxLCAuLi4sIGIxMSkg4oiIIEZcbiAgICAgICAgY2hhbGxlbmdlcy5iID0gW107XG4gICAgICAgIGZvciAobGV0IGk9MTsgaTw9MTE7IGkrKykge1xuICAgICAgICAgICAgY2hhbGxlbmdlcy5iW2ldID0gY3VydmUuRnIucmFuZG9tKCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTVEVQIDEuMiAtIENvbXB1dGUgd2lyZSBwb2x5bm9taWFscyBhKFgpLCBiKFgpIGFuZCBjKFgpXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIj4gQ29tcHV0aW5nIEEsIEIsIEMgd2lyZSBwb2x5bm9taWFsc1wiKTtcbiAgICAgICAgYXdhaXQgY29tcHV0ZVdpcmVQb2x5bm9taWFscygpO1xuXG4gICAgICAgIC8vIFNURVAgMS4zIC0gQ29tcHV0ZSBbYV1fMSwgW2JdXzEsIFtjXV8xXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIj4gQ29tcHV0aW5nIEEsIEIsIEMgTVNNXCIpO1xuICAgICAgICBsZXQgY29tbWl0QSA9IGF3YWl0IHBvbHlub21pYWxzLkEubXVsdGlFeHBvbmVudGlhdGlvbihQVGF1LCBcIkFcIik7XG4gICAgICAgIGxldCBjb21taXRCID0gYXdhaXQgcG9seW5vbWlhbHMuQi5tdWx0aUV4cG9uZW50aWF0aW9uKFBUYXUsIFwiQlwiKTtcbiAgICAgICAgbGV0IGNvbW1pdEMgPSBhd2FpdCBwb2x5bm9taWFscy5DLm11bHRpRXhwb25lbnRpYXRpb24oUFRhdSwgXCJDXCIpO1xuXG4gICAgICAgIC8vIEZpcnN0IG91dHB1dCBvZiB0aGUgcHJvdmVyIGlzIChbQV1fMSwgW0JdXzEsIFtDXV8xKVxuICAgICAgICBwcm9vZi5hZGRQb2x5bm9taWFsKFwiQVwiLCBjb21taXRBKTtcbiAgICAgICAgcHJvb2YuYWRkUG9seW5vbWlhbChcIkJcIiwgY29tbWl0Qik7XG4gICAgICAgIHByb29mLmFkZFBvbHlub21pYWwoXCJDXCIsIGNvbW1pdEMpO1xuXG4gICAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIGNvbXB1dGVXaXJlUG9seW5vbWlhbHMoKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIsK3wrfCtyBSZWFkaW5nIGRhdGEgZnJvbSB6a2V5IGZpbGVcIik7XG5cbiAgICAgICAgLy8gQnVpbGQgQSwgQiBhbmQgQyBldmFsdWF0aW9ucyBidWZmZXIgZnJvbSB6a2V5IGFuZCB3aXRuZXNzIGZpbGVzXG4gICAgICAgIGJ1ZmZlcnMuQSA9IG5ldyBCaWdCdWZmZXIoc0RvbWFpbik7XG4gICAgICAgIGJ1ZmZlcnMuQiA9IG5ldyBCaWdCdWZmZXIoc0RvbWFpbik7XG4gICAgICAgIGJ1ZmZlcnMuQyA9IG5ldyBCaWdCdWZmZXIoc0RvbWFpbik7XG5cbiAgICAgICAgLy8gUmVhZCB6a2V5IGZpbGUgdG8gdGhlIGJ1ZmZlcnNcbiAgICAgICAgY29uc3QgYU1hcEJ1ZmYgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRaS2V5LCB6a2V5U2VjdGlvbnMsIFpLRVlfUExfQV9NQVBfU0VDVElPTik7XG4gICAgICAgIGNvbnN0IGJNYXBCdWZmID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRTZWN0aW9uKGZkWktleSwgemtleVNlY3Rpb25zLCBaS0VZX1BMX0JfTUFQX1NFQ1RJT04pO1xuICAgICAgICBjb25zdCBjTWFwQnVmZiA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkU2VjdGlvbihmZFpLZXksIHprZXlTZWN0aW9ucywgWktFWV9QTF9DX01BUF9TRUNUSU9OKTtcblxuICAgICAgICAvLyBDb21wdXRlIGFsbCB3aXRuZXNzIGZyb20gc2lnbmFsIGlkcyBhbmQgc2V0IHRoZW0gdG8gQSxCICYgQyBidWZmZXJzXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgemtleS5uQ29uc3RyYWludHM7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgaV9zRnIgPSBpICogbjhyO1xuICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gaSAqIDQ7XG5cbiAgICAgICAgICAgIC8vIENvbXB1dGUgQSB2YWx1ZSBmcm9tIGEgc2lnbmFsIGlkXG4gICAgICAgICAgICBjb25zdCBzaWduYWxJZEEgPSByZWFkVUludDMyKGFNYXBCdWZmLCBvZmZzZXQpO1xuICAgICAgICAgICAgYnVmZmVycy5BLnNldChnZXRXaXRuZXNzKHNpZ25hbElkQSksIGlfc0ZyKTtcblxuICAgICAgICAgICAgLy8gQ29tcHV0ZSBCIHZhbHVlIGZyb20gYSBzaWduYWwgaWRcbiAgICAgICAgICAgIGNvbnN0IHNpZ25hbElkQiA9IHJlYWRVSW50MzIoYk1hcEJ1ZmYsIG9mZnNldCk7XG4gICAgICAgICAgICBidWZmZXJzLkIuc2V0KGdldFdpdG5lc3Moc2lnbmFsSWRCKSwgaV9zRnIpO1xuXG4gICAgICAgICAgICAvLyBDb21wdXRlIEMgdmFsdWUgZnJvbSBhIHNpZ25hbCBpZFxuICAgICAgICAgICAgY29uc3Qgc2lnbmFsSWRDID0gcmVhZFVJbnQzMihjTWFwQnVmZiwgb2Zmc2V0KTtcbiAgICAgICAgICAgIGJ1ZmZlcnMuQy5zZXQoZ2V0V2l0bmVzcyhzaWduYWxJZEMpLCBpX3NGcik7XG4gICAgICAgIH1cblxuICAgICAgICBidWZmZXJzLkEgPSBhd2FpdCBGci5iYXRjaFRvTW9udGdvbWVyeShidWZmZXJzLkEpO1xuICAgICAgICBidWZmZXJzLkIgPSBhd2FpdCBGci5iYXRjaFRvTW9udGdvbWVyeShidWZmZXJzLkIpO1xuICAgICAgICBidWZmZXJzLkMgPSBhd2FpdCBGci5iYXRjaFRvTW9udGdvbWVyeShidWZmZXJzLkMpO1xuXG4gICAgICAgIC8vIENvbXB1dGUgdGhlIGNvZWZmaWNpZW50cyBvZiB0aGUgd2lyZSBwb2x5bm9taWFscyBhKFgpLCBiKFgpIGFuZCBjKFgpIGZyb20gQSxCICYgQyBidWZmZXJzXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIsK3wrfCtyBDb21wdXRpbmcgQSBpZmZ0XCIpO1xuICAgICAgICBwb2x5bm9taWFscy5BID0gYXdhaXQgUG9seW5vbWlhbC5mcm9tRXZhbHVhdGlvbnMoYnVmZmVycy5BLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiwrfCt8K3IENvbXB1dGluZyBCIGlmZnRcIik7XG4gICAgICAgIHBvbHlub21pYWxzLkIgPSBhd2FpdCBQb2x5bm9taWFsLmZyb21FdmFsdWF0aW9ucyhidWZmZXJzLkIsIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCLCt8K3wrcgQ29tcHV0aW5nIEMgaWZmdFwiKTtcbiAgICAgICAgcG9seW5vbWlhbHMuQyA9IGF3YWl0IFBvbHlub21pYWwuZnJvbUV2YWx1YXRpb25zKGJ1ZmZlcnMuQywgY3VydmUsIGxvZ2dlcik7XG5cbiAgICAgICAgLy8gQ29tcHV0ZSBleHRlbmRlZCBldmFsdWF0aW9ucyBvZiBhKFgpLCBiKFgpIGFuZCBjKFgpIHBvbHlub21pYWxzXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIsK3wrfCtyBDb21wdXRpbmcgQSBmZnRcIik7XG4gICAgICAgIGV2YWx1YXRpb25zLkEgPSBhd2FpdCBFdmFsdWF0aW9ucy5mcm9tUG9seW5vbWlhbChwb2x5bm9taWFscy5BLCA0LCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiwrfCt8K3IENvbXB1dGluZyBCIGZmdFwiKTtcbiAgICAgICAgZXZhbHVhdGlvbnMuQiA9IGF3YWl0IEV2YWx1YXRpb25zLmZyb21Qb2x5bm9taWFsKHBvbHlub21pYWxzLkIsIDQsIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCLCt8K3wrcgQ29tcHV0aW5nIEMgZmZ0XCIpO1xuICAgICAgICBldmFsdWF0aW9ucy5DID0gYXdhaXQgRXZhbHVhdGlvbnMuZnJvbVBvbHlub21pYWwocG9seW5vbWlhbHMuQywgNCwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICAgICAgLy8gQmxpbmQgYShYKSwgYihYKSBhbmQgYyhYKSBwb2x5bm9taWFscyBjb2VmZmljaWVudHMgd2l0aCBibGluZGluZyBzY2FsYXJzIGJcbiAgICAgICAgcG9seW5vbWlhbHMuQS5ibGluZENvZWZmaWNpZW50cyhbY2hhbGxlbmdlcy5iWzJdLCBjaGFsbGVuZ2VzLmJbMV1dKTtcbiAgICAgICAgcG9seW5vbWlhbHMuQi5ibGluZENvZWZmaWNpZW50cyhbY2hhbGxlbmdlcy5iWzRdLCBjaGFsbGVuZ2VzLmJbM11dKTtcbiAgICAgICAgcG9seW5vbWlhbHMuQy5ibGluZENvZWZmaWNpZW50cyhbY2hhbGxlbmdlcy5iWzZdLCBjaGFsbGVuZ2VzLmJbNV1dKTtcblxuICAgICAgICAvLyBDaGVjayBkZWdyZWVzXG4gICAgICAgIGlmIChwb2x5bm9taWFscy5BLmRlZ3JlZSgpID49IHprZXkuZG9tYWluU2l6ZSArIDIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkEgUG9seW5vbWlhbCBpcyBub3Qgd2VsbCBjYWxjdWxhdGVkXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwb2x5bm9taWFscy5CLmRlZ3JlZSgpID49IHprZXkuZG9tYWluU2l6ZSArIDIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkIgUG9seW5vbWlhbCBpcyBub3Qgd2VsbCBjYWxjdWxhdGVkXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwb2x5bm9taWFscy5DLmRlZ3JlZSgpID49IHprZXkuZG9tYWluU2l6ZSArIDIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkMgUG9seW5vbWlhbCBpcyBub3Qgd2VsbCBjYWxjdWxhdGVkXCIpO1xuICAgICAgICB9ICAgICAgICBcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiByb3VuZDIoKSB7XG4gICAgICAgIC8vIFNURVAgMi4xIC0gQ29tcHV0ZSBwZXJtdXRhdGlvbiBjaGFsbGVuZ2UgYmV0YSBhbmQgZ2FtbWEg4oiIIEZcbiAgICAgICAgLy8gQ29tcHV0ZSBwZXJtdXRhdGlvbiBjaGFsbGVuZ2UgYmV0YVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IENvbXB1dGluZyBjaGFsbGVuZ2VzIGJldGEgYW5kIGdhbW1hXCIpO1xuICAgICAgICB0cmFuc2NyaXB0LnJlc2V0KCk7XG5cbiAgICAgICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHprZXkuUW0pO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQoemtleS5RbCk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudCh6a2V5LlFyKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHprZXkuUW8pO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQoemtleS5RYyk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudCh6a2V5LlMxKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHprZXkuUzIpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQoemtleS5TMyk7XG5cbiAgICAgICAgLy8gQWRkIEEgdG8gdGhlIHRyYW5zY3JpcHRcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB6a2V5Lm5QdWJsaWM7IGkrKykge1xuICAgICAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIoYnVmZmVycy5BLnNsaWNlKGkgKiBuOHIsIGkgKiBuOHIgKyBuOHIpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFkZCBBLCBCLCBDIHRvIHRoZSB0cmFuc2NyaXB0XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5nZXRQb2x5bm9taWFsKFwiQVwiKSk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5nZXRQb2x5bm9taWFsKFwiQlwiKSk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5nZXRQb2x5bm9taWFsKFwiQ1wiKSk7XG5cbiAgICAgICAgY2hhbGxlbmdlcy5iZXRhID0gdHJhbnNjcmlwdC5nZXRDaGFsbGVuZ2UoKTtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiwrfCt8K3IGNoYWxsZW5nZXMuYmV0YTogXCIgKyBGci50b1N0cmluZyhjaGFsbGVuZ2VzLmJldGEsIDE2KSk7XG5cbiAgICAgICAgLy8gQ29tcHV0ZSBwZXJtdXRhdGlvbiBjaGFsbGVuZ2UgZ2FtbWFcbiAgICAgICAgdHJhbnNjcmlwdC5yZXNldCgpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihjaGFsbGVuZ2VzLmJldGEpO1xuICAgICAgICBjaGFsbGVuZ2VzLmdhbW1hID0gdHJhbnNjcmlwdC5nZXRDaGFsbGVuZ2UoKTtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiwrfCt8K3IGNoYWxsZW5nZXMuZ2FtbWE6IFwiICsgRnIudG9TdHJpbmcoY2hhbGxlbmdlcy5nYW1tYSwgMTYpKTtcbiAgICBcbiAgICAgICAgLy8gU1RFUCAyLjIgLSBDb21wdXRlIHBlcm11dGF0aW9uIHBvbHlub21pYWwgeihYKVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IENvbXB1dGluZyBaIHBvbHlub21pYWxcIik7XG4gICAgICAgIGF3YWl0IGNvbXB1dGVaKCk7XG5cbiAgICAgICAgLy8gU1RFUCAyLjMgLSBDb21wdXRlIHBlcm11dGF0aW9uIFt6XV8xXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIj4gQ29tcHV0aW5nIFogTVNNXCIpO1xuICAgICAgICBsZXQgY29tbWl0WiA9IGF3YWl0IHBvbHlub21pYWxzLloubXVsdGlFeHBvbmVudGlhdGlvbihQVGF1LCBcIlpcIik7XG5cbiAgICAgICAgLy8gU2Vjb25kIG91dHB1dCBvZiB0aGUgcHJvdmVyIGlzIChbWl1fMSlcbiAgICAgICAgcHJvb2YuYWRkUG9seW5vbWlhbChcIlpcIiwgY29tbWl0Wik7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gY29tcHV0ZVooKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIsK3wrfCtyBDb21wdXRpbmcgWiBldmFsdWF0aW9uc1wiKTtcblxuICAgICAgICBsZXQgbnVtQXJyID0gbmV3IEJpZ0J1ZmZlcihzRG9tYWluKTtcbiAgICAgICAgbGV0IGRlbkFyciA9IG5ldyBCaWdCdWZmZXIoc0RvbWFpbik7XG5cbiAgICAgICAgLy8gU2V0IHRoZSBmaXJzdCB2YWx1ZXMgdG8gMVxuICAgICAgICBudW1BcnIuc2V0KEZyLm9uZSwgMCk7XG4gICAgICAgIGRlbkFyci5zZXQoRnIub25lLCAwKTtcblxuICAgICAgICAvLyBTZXQgaW5pdGlhbCBvbWVnYVxuICAgICAgICBsZXQgdyA9IEZyLm9uZTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB6a2V5LmRvbWFpblNpemU7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgaV9uOHIgPSBpICogbjhyO1xuICAgICAgICAgICAgXG4gICAgICAgICAgICBjb25zdCBhID0gYnVmZmVycy5BLnNsaWNlKGlfbjhyLCBpX244ciArIG44cik7XG4gICAgICAgICAgICBjb25zdCBiID0gYnVmZmVycy5CLnNsaWNlKGlfbjhyLCBpX244ciArIG44cik7XG4gICAgICAgICAgICBjb25zdCBjID0gYnVmZmVycy5DLnNsaWNlKGlfbjhyLCBpX244ciArIG44cik7XG5cbiAgICAgICAgICAgIC8vIFooWCkgOj0gbnVtQXJyIC8gZGVuQXJyXG4gICAgICAgICAgICAvLyBudW1BcnIgOj0gKGEgKyBiZXRhwrfPiSArIGdhbW1hKShiICsgYmV0YcK3z4nCt2sxICsgZ2FtbWEpKGMgKyBiZXRhwrfPicK3azIgKyBnYW1tYSlcbiAgICAgICAgICAgIGNvbnN0IGJldGF3ID0gRnIubXVsKGNoYWxsZW5nZXMuYmV0YSwgdyk7XG5cbiAgICAgICAgICAgIGxldCBuMSA9IEZyLmFkZChhLCBiZXRhdyk7XG4gICAgICAgICAgICBuMSA9IEZyLmFkZChuMSwgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgICAgIGxldCBuMiA9IEZyLmFkZChiLCBGci5tdWwoemtleS5rMSwgYmV0YXcpKTtcbiAgICAgICAgICAgIG4yID0gRnIuYWRkKG4yLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICAgICAgbGV0IG4zID0gRnIuYWRkKGMsIEZyLm11bCh6a2V5LmsyLCBiZXRhdykpO1xuICAgICAgICAgICAgbjMgPSBGci5hZGQobjMsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgICAgICAgICBsZXQgbnVtID0gRnIubXVsKG4xLCBGci5tdWwobjIsIG4zKSk7XG5cbiAgICAgICAgICAgIC8vIGRlbkFyciA6PSAoYSArIGJldGHCt3NpZ21hMSArIGdhbW1hKShiICsgYmV0YcK3c2lnbWEyICsgZ2FtbWEpKGMgKyBiZXRhwrdzaWdtYTMgKyBnYW1tYSlcbiAgICAgICAgICAgIGxldCBkMSA9IEZyLmFkZChhLCBGci5tdWwoZXZhbHVhdGlvbnMuU2lnbWExLmdldEV2YWx1YXRpb24oaSAqIDQpLCBjaGFsbGVuZ2VzLmJldGEpKTtcbiAgICAgICAgICAgIGQxID0gRnIuYWRkKGQxLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICAgICAgbGV0IGQyID0gRnIuYWRkKGIsIEZyLm11bChldmFsdWF0aW9ucy5TaWdtYTIuZ2V0RXZhbHVhdGlvbihpICogNCksIGNoYWxsZW5nZXMuYmV0YSkpO1xuICAgICAgICAgICAgZDIgPSBGci5hZGQoZDIsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgICAgICAgICBsZXQgZDMgPSBGci5hZGQoYywgRnIubXVsKGV2YWx1YXRpb25zLlNpZ21hMy5nZXRFdmFsdWF0aW9uKGkgKiA0KSwgY2hhbGxlbmdlcy5iZXRhKSk7XG4gICAgICAgICAgICBkMyA9IEZyLmFkZChkMywgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgICAgIGxldCBkZW4gPSBGci5tdWwoZDEsIEZyLm11bChkMiwgZDMpKTtcblxuICAgICAgICAgICAgLy8gTXVsdGlwbHkgY3VycmVudCBudW0gdmFsdWUgd2l0aCB0aGUgcHJldmlvdXMgb25lIHNhdmVkIGluIG51bUFyclxuICAgICAgICAgICAgbnVtID0gRnIubXVsKG51bUFyci5zbGljZShpX244ciwgaV9uOHIgKyBuOHIpLCBudW0pO1xuICAgICAgICAgICAgbnVtQXJyLnNldChudW0sICgoaSArIDEpICUgemtleS5kb21haW5TaXplKSAqIG44cik7XG5cbiAgICAgICAgICAgIC8vIE11bHRpcGx5IGN1cnJlbnQgZGVuIHZhbHVlIHdpdGggdGhlIHByZXZpb3VzIG9uZSBzYXZlZCBpbiBkZW5BcnJcbiAgICAgICAgICAgIGRlbiA9IEZyLm11bChkZW5BcnIuc2xpY2UoaV9uOHIsIGlfbjhyICsgbjhyKSwgZGVuKTtcbiAgICAgICAgICAgIGRlbkFyci5zZXQoZGVuLCAoKGkgKyAxKSAlIHprZXkuZG9tYWluU2l6ZSkgKiBuOHIpO1xuXG4gICAgICAgICAgICB3ID0gRnIubXVsKHcsIEZyLndbemtleS5wb3dlcl0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29tcHV0ZSB0aGUgaW52ZXJzZSBvZiBkZW5BcnIgdG8gY29tcHV0ZSBpbiB0aGUgbmV4dCBjb21tYW5kIHRoZVxuICAgICAgICAvLyBkaXZpc2lvbiBudW1BcnIvZGVuQXJyIGJ5IG11bHRpcGx5aW5nIG51bSDCtyAxL2RlbkFyclxuICAgICAgICBkZW5BcnIgPSBhd2FpdCBGci5iYXRjaEludmVyc2UoZGVuQXJyKTtcblxuICAgICAgICAvLyBUT0RPOiBEbyBpdCBpbiBhc3NlbWJseSBhbmQgaW4gcGFyYWxsZWxcbiAgICAgICAgLy8gTXVsdGlwbHkgbnVtQXJyIMK3IGRlbkFyciB3aGVyZSBkZW5BcnIgd2FzIGludmVydGVkIGluIHRoZSBwcmV2aW91cyBjb21tYW5kXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgemtleS5kb21haW5TaXplOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGlfc0ZyID0gaSAqIG44cjtcblxuICAgICAgICAgICAgY29uc3QgeiA9IEZyLm11bChudW1BcnIuc2xpY2UoaV9zRnIsIGlfc0ZyICsgbjhyKSwgZGVuQXJyLnNsaWNlKGlfc0ZyLCBpX3NGciArIG44cikpO1xuICAgICAgICAgICAgbnVtQXJyLnNldCh6LCBpX3NGcik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBGcm9tIG5vdyBvbiB0aGUgdmFsdWVzIHNhdmVkIG9uIG51bUFyciB3aWxsIGJlIFooWCkgYnVmZmVyXG4gICAgICAgIGJ1ZmZlcnMuWiA9IG51bUFycjtcblxuICAgICAgICBpZiAoIUZyLmVxKG51bUFyci5zbGljZSgwLCBuOHIpLCBGci5vbmUpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3B5IGNvbnN0cmFpbnRzIGRvZXMgbm90IG1hdGNoXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29tcHV0ZSBwb2x5bm9taWFsIGNvZWZmaWNpZW50cyB6KFgpIGZyb20gYnVmZmVycy5aXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIsK3wrfCtyBDb21wdXRpbmcgWiBpZmZ0XCIpO1xuICAgICAgICBwb2x5bm9taWFscy5aID0gYXdhaXQgUG9seW5vbWlhbC5mcm9tRXZhbHVhdGlvbnMoYnVmZmVycy5aLCBjdXJ2ZSwgbG9nZ2VyKTtcblxuICAgICAgICAvLyBDb21wdXRlIGV4dGVuZGVkIGV2YWx1YXRpb25zIG9mIHooWCkgcG9seW5vbWlhbFxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCLCt8K3wrcgQ29tcHV0aW5nIFogZmZ0XCIpO1xuICAgICAgICBldmFsdWF0aW9ucy5aID0gYXdhaXQgRXZhbHVhdGlvbnMuZnJvbVBvbHlub21pYWwocG9seW5vbWlhbHMuWiwgNCwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICAgICAgLy8gQmxpbmQgeihYKSBwb2x5bm9taWFsIGNvZWZmaWNpZW50cyB3aXRoIGJsaW5kaW5nIHNjYWxhcnMgYlxuICAgICAgICBwb2x5bm9taWFscy5aLmJsaW5kQ29lZmZpY2llbnRzKFtjaGFsbGVuZ2VzLmJbOV0sIGNoYWxsZW5nZXMuYls4XSwgY2hhbGxlbmdlcy5iWzddXSk7XG5cbiAgICAgICAgLy8gQ2hlY2sgZGVncmVlXG4gICAgICAgIGlmIChwb2x5bm9taWFscy5aLmRlZ3JlZSgpID49IHprZXkuZG9tYWluU2l6ZSArIDMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlogUG9seW5vbWlhbCBpcyBub3Qgd2VsbCBjYWxjdWxhdGVkXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVsZXRlIGJ1ZmZlcnMuWjtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiByb3VuZDMoKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIj4gQ29tcHV0aW5nIGNoYWxsZW5nZSBhbHBoYVwiKTtcblxuICAgICAgICAvLyBTVEVQIDMuMSAtIENvbXB1dGUgZXZhbHVhdGlvbiBjaGFsbGVuZ2UgYWxwaGEg4oiIIEZcbiAgICAgICAgdHJhbnNjcmlwdC5yZXNldCgpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihjaGFsbGVuZ2VzLmJldGEpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihjaGFsbGVuZ2VzLmdhbW1hKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHByb29mLmdldFBvbHlub21pYWwoXCJaXCIpKTtcblxuICAgICAgICBjaGFsbGVuZ2VzLmFscGhhID0gdHJhbnNjcmlwdC5nZXRDaGFsbGVuZ2UoKTtcbiAgICAgICAgY2hhbGxlbmdlcy5hbHBoYTIgPSBGci5zcXVhcmUoY2hhbGxlbmdlcy5hbHBoYSk7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIsK3wrfCtyBjaGFsbGVuZ2VzLmFscGhhOiBcIiArIEZyLnRvU3RyaW5nKGNoYWxsZW5nZXMuYWxwaGEsIDE2KSk7XG5cbiAgICAgICAgLy8gQ29tcHV0ZSBxdW90aWVudCBwb2x5bm9taWFsIFQoWClcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiPiBDb21wdXRpbmcgVCBwb2x5bm9taWFsXCIpO1xuICAgICAgICBhd2FpdCBjb21wdXRlVCgpO1xuXG4gICAgICAgIC8vIENvbXB1dGUgW1QxXV8xLCBbVDJdXzEsIFtUM11fMVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IENvbXB1dGluZyBUIE1TTVwiKTtcbiAgICAgICAgbGV0IGNvbW1pdFQxID0gYXdhaXQgcG9seW5vbWlhbHMuVDEubXVsdGlFeHBvbmVudGlhdGlvbihQVGF1LCBcIlQxXCIpO1xuICAgICAgICBsZXQgY29tbWl0VDIgPSBhd2FpdCBwb2x5bm9taWFscy5UMi5tdWx0aUV4cG9uZW50aWF0aW9uKFBUYXUsIFwiVDJcIik7XG4gICAgICAgIGxldCBjb21taXRUMyA9IGF3YWl0IHBvbHlub21pYWxzLlQzLm11bHRpRXhwb25lbnRpYXRpb24oUFRhdSwgXCJUM1wiKTtcblxuICAgICAgICAvLyBUaGlyZCBvdXRwdXQgb2YgdGhlIHByb3ZlciBpcyAoW1QxXV8xLCBbVDJdXzEsIFtUM11fMSlcbiAgICAgICAgcHJvb2YuYWRkUG9seW5vbWlhbChcIlQxXCIsIGNvbW1pdFQxKTtcbiAgICAgICAgcHJvb2YuYWRkUG9seW5vbWlhbChcIlQyXCIsIGNvbW1pdFQyKTtcbiAgICAgICAgcHJvb2YuYWRkUG9seW5vbWlhbChcIlQzXCIsIGNvbW1pdFQzKTsgICAgICAgIFxuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIGNvbXB1dGVUKCkge1xuICAgICAgICBpZiAobG9nZ2VyKVxuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKGDCt8K3wrcgUmVhZGluZyBzZWN0aW9ucyAke1pLRVlfUExfUUxfU0VDVElPTn0sICR7WktFWV9QTF9RUl9TRUNUSU9OfWAgK1xuICAgICAgICAgICAgICAgIGAsICR7WktFWV9QTF9RTV9TRUNUSU9OfSwgJHtaS0VZX1BMX1FPX1NFQ1RJT059LCAke1pLRVlfUExfUUNfU0VDVElPTn0uIFEgc2VsZWN0b3JzYCk7XG4gICAgICAgIC8vIFJlc2VydmUgbWVtb3J5IGZvciBRJ3MgZXZhbHVhdGlvbnNcbiAgICAgICAgZXZhbHVhdGlvbnMuUUwgPSBuZXcgRXZhbHVhdGlvbnMobmV3IEJpZ0J1ZmZlcihzRG9tYWluICogNCksIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBldmFsdWF0aW9ucy5RUiA9IG5ldyBFdmFsdWF0aW9ucyhuZXcgQmlnQnVmZmVyKHNEb21haW4gKiA0KSwgY3VydmUsIGxvZ2dlcik7XG4gICAgICAgIGV2YWx1YXRpb25zLlFNID0gbmV3IEV2YWx1YXRpb25zKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgZXZhbHVhdGlvbnMuUU8gPSBuZXcgRXZhbHVhdGlvbnMobmV3IEJpZ0J1ZmZlcihzRG9tYWluICogNCksIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBldmFsdWF0aW9ucy5RQyA9IG5ldyBFdmFsdWF0aW9ucyhuZXcgQmlnQnVmZmVyKHNEb21haW4gKiA0KSwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICAgICAgLy8gUmVhZCBRJ3MgZXZhbHVhdGlvbnMgZnJvbSB6a2V5IGZpbGVcbiAgICAgICAgYXdhaXQgZmRaS2V5LnJlYWRUb0J1ZmZlcihldmFsdWF0aW9ucy5RTC5ldmFsLCAwLCBzRG9tYWluICogNCwgemtleVNlY3Rpb25zW1pLRVlfUExfUUxfU0VDVElPTl1bMF0ucCArIHNEb21haW4pO1xuICAgICAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKGV2YWx1YXRpb25zLlFSLmV2YWwsIDAsIHNEb21haW4gKiA0LCB6a2V5U2VjdGlvbnNbWktFWV9QTF9RUl9TRUNUSU9OXVswXS5wICsgc0RvbWFpbik7XG4gICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIoZXZhbHVhdGlvbnMuUU0uZXZhbCwgMCwgc0RvbWFpbiAqIDQsIHprZXlTZWN0aW9uc1taS0VZX1BMX1FNX1NFQ1RJT05dWzBdLnAgKyBzRG9tYWluKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LnJlYWRUb0J1ZmZlcihldmFsdWF0aW9ucy5RTy5ldmFsLCAwLCBzRG9tYWluICogNCwgemtleVNlY3Rpb25zW1pLRVlfUExfUU9fU0VDVElPTl1bMF0ucCArIHNEb21haW4pO1xuICAgICAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKGV2YWx1YXRpb25zLlFDLmV2YWwsIDAsIHNEb21haW4gKiA0LCB6a2V5U2VjdGlvbnNbWktFWV9QTF9RQ19TRUNUSU9OXVswXS5wICsgc0RvbWFpbik7XG5cbiAgICAgICAgLy8gUmVhZCBMYWdyYW5nZSBwb2x5bm9taWFscyAmIGV2YWx1YXRpb25zIGZyb20gemtleSBmaWxlXG4gICAgICAgIGV2YWx1YXRpb25zLkxhZ3JhbmdlID0gbmV3IEV2YWx1YXRpb25zKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQgKiB6a2V5Lm5QdWJsaWMpLCBjdXJ2ZSwgbG9nZ2VyKTtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHprZXkublB1YmxpYzsgaSsrKSB7XG4gICAgICAgICAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKGV2YWx1YXRpb25zLkxhZ3JhbmdlLmV2YWwsIGkgKiBzRG9tYWluICogNCwgc0RvbWFpbiAqIDQsIHprZXlTZWN0aW9uc1taS0VZX1BMX0xBR1JBTkdFX1NFQ1RJT05dWzBdLnAgKyBpICogNSAqIHNEb21haW4gKyBzRG9tYWluKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGJ1ZmZlcnMuVCA9IG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpO1xuICAgICAgICBidWZmZXJzLlR6ID0gbmV3IEJpZ0J1ZmZlcihzRG9tYWluICogNCk7XG5cbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiwrfCt8K3IENvbXB1dGluZyBUIGV2YWx1YXRpb25zXCIpO1xuXG4gICAgICAgIGxldCB3ID0gRnIub25lO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHprZXkuZG9tYWluU2l6ZSAqIDQ7IGkrKykge1xuICAgICAgICAgICAgaWYgKGxvZ2dlciAmJiAoMCAhPT0gaSkgJiYgKGkgJSAxMDAwMDAgPT09IDApKVxuICAgICAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhgICAgICAgVCBldmFsdWF0aW9uICR7aX0vJHt6a2V5LmRvbWFpblNpemUgKiA0fWApO1xuXG4gICAgICAgICAgICBjb25zdCBhID0gZXZhbHVhdGlvbnMuQS5nZXRFdmFsdWF0aW9uKGkpO1xuICAgICAgICAgICAgY29uc3QgYiA9IGV2YWx1YXRpb25zLkIuZ2V0RXZhbHVhdGlvbihpKTtcbiAgICAgICAgICAgIGNvbnN0IGMgPSBldmFsdWF0aW9ucy5DLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICBjb25zdCB6ID0gZXZhbHVhdGlvbnMuWi5nZXRFdmFsdWF0aW9uKGkpO1xuICAgICAgICAgICAgY29uc3QgencgPSBldmFsdWF0aW9ucy5aLmdldEV2YWx1YXRpb24oKHprZXkuZG9tYWluU2l6ZSAqIDQgKyA0ICsgaSkgJSAoemtleS5kb21haW5TaXplICogNCkpO1xuXG4gICAgICAgICAgICBjb25zdCBxbSA9IGV2YWx1YXRpb25zLlFNLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICBjb25zdCBxbCA9IGV2YWx1YXRpb25zLlFMLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICBjb25zdCBxciA9IGV2YWx1YXRpb25zLlFSLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICBjb25zdCBxbyA9IGV2YWx1YXRpb25zLlFPLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICBjb25zdCBxYyA9IGV2YWx1YXRpb25zLlFDLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICBjb25zdCBzMSA9IGV2YWx1YXRpb25zLlNpZ21hMS5nZXRFdmFsdWF0aW9uKGkpO1xuICAgICAgICAgICAgY29uc3QgczIgPSBldmFsdWF0aW9ucy5TaWdtYTIuZ2V0RXZhbHVhdGlvbihpKTtcbiAgICAgICAgICAgIGNvbnN0IHMzID0gZXZhbHVhdGlvbnMuU2lnbWEzLmdldEV2YWx1YXRpb24oaSk7XG5cbiAgICAgICAgICAgIGNvbnN0IGFwID0gRnIuYWRkKGNoYWxsZW5nZXMuYlsyXSwgRnIubXVsKGNoYWxsZW5nZXMuYlsxXSwgdykpO1xuICAgICAgICAgICAgY29uc3QgYnAgPSBGci5hZGQoY2hhbGxlbmdlcy5iWzRdLCBGci5tdWwoY2hhbGxlbmdlcy5iWzNdLCB3KSk7XG4gICAgICAgICAgICBjb25zdCBjcCA9IEZyLmFkZChjaGFsbGVuZ2VzLmJbNl0sIEZyLm11bChjaGFsbGVuZ2VzLmJbNV0sIHcpKTtcblxuICAgICAgICAgICAgY29uc3QgdzIgPSBGci5zcXVhcmUodyk7XG4gICAgICAgICAgICBjb25zdCB6cCA9IEZyLmFkZChGci5hZGQoRnIubXVsKGNoYWxsZW5nZXMuYls3XSwgdzIpLCBGci5tdWwoY2hhbGxlbmdlcy5iWzhdLCB3KSksIGNoYWxsZW5nZXMuYls5XSk7XG4gICAgICAgICAgICBjb25zdCB3VyA9IEZyLm11bCh3LCBGci53W3prZXkucG93ZXJdKTtcbiAgICAgICAgICAgIGNvbnN0IHdXMiA9IEZyLnNxdWFyZSh3Vyk7XG4gICAgICAgICAgICBjb25zdCB6V3AgPSBGci5hZGQoRnIuYWRkKEZyLm11bChjaGFsbGVuZ2VzLmJbN10sIHdXMiksIEZyLm11bChjaGFsbGVuZ2VzLmJbOF0sIHdXKSksIGNoYWxsZW5nZXMuYls5XSk7XG5cbiAgICAgICAgICAgIGxldCBwaSA9IEZyLnplcm87XG4gICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHprZXkublB1YmxpYzsgaisrKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gKGogKiA0ICogemtleS5kb21haW5TaXplKSArIGk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBsUG9sID0gZXZhbHVhdGlvbnMuTGFncmFuZ2UuZ2V0RXZhbHVhdGlvbihvZmZzZXQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGFWYWwgPSBidWZmZXJzLkEuc2xpY2UoaiAqIG44ciwgKGogKyAxKSAqIG44cik7XG5cbiAgICAgICAgICAgICAgICBwaSA9IEZyLnN1YihwaSwgRnIubXVsKGxQb2wsIGFWYWwpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gZTEgOj0gYShYKWIoWClxTShYKSArIGEoWClxTChYKSArIGIoWClxUihYKSArIGMoWClxTyhYKSArIFBJKFgpICsgcUMoWClcbiAgICAgICAgICAgIGxldCBbZTEsIGUxel0gPSBNdWxaLm11bDIoYSwgYiwgYXAsIGJwLCBpICUgNCwgRnIpO1xuICAgICAgICAgICAgZTEgPSBGci5tdWwoZTEsIHFtKTtcbiAgICAgICAgICAgIGUxeiA9IEZyLm11bChlMXosIHFtKTtcblxuICAgICAgICAgICAgZTEgPSBGci5hZGQoZTEsIEZyLm11bChhLCBxbCkpO1xuICAgICAgICAgICAgZTF6ID0gRnIuYWRkKGUxeiwgRnIubXVsKGFwLCBxbCkpO1xuXG4gICAgICAgICAgICBlMSA9IEZyLmFkZChlMSwgRnIubXVsKGIsIHFyKSk7XG4gICAgICAgICAgICBlMXogPSBGci5hZGQoZTF6LCBGci5tdWwoYnAsIHFyKSk7XG5cbiAgICAgICAgICAgIGUxID0gRnIuYWRkKGUxLCBGci5tdWwoYywgcW8pKTtcbiAgICAgICAgICAgIGUxeiA9IEZyLmFkZChlMXosIEZyLm11bChjcCwgcW8pKTtcblxuICAgICAgICAgICAgZTEgPSBGci5hZGQoZTEsIHBpKTtcbiAgICAgICAgICAgIGUxID0gRnIuYWRkKGUxLCBxYyk7XG5cbiAgICAgICAgICAgIC8vIGUyIDo9IM6xWyhhKFgpICsgzrJYICsgzrMpKGIoWCkgKyDOsmsxWCArIM6zKShjKFgpICsgzrJrMlggKyDOsyl6KFgpXVxuICAgICAgICAgICAgY29uc3QgYmV0YXcgPSBGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCB3KTtcbiAgICAgICAgICAgIGxldCBlMmEgPSBhO1xuICAgICAgICAgICAgZTJhID0gRnIuYWRkKGUyYSwgYmV0YXcpO1xuICAgICAgICAgICAgZTJhID0gRnIuYWRkKGUyYSwgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgICAgIGxldCBlMmIgPSBiO1xuICAgICAgICAgICAgZTJiID0gRnIuYWRkKGUyYiwgRnIubXVsKGJldGF3LCB6a2V5LmsxKSk7XG4gICAgICAgICAgICBlMmIgPSBGci5hZGQoZTJiLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICAgICAgbGV0IGUyYyA9IGM7XG4gICAgICAgICAgICBlMmMgPSBGci5hZGQoZTJjLCBGci5tdWwoYmV0YXcsIHprZXkuazIpKTtcbiAgICAgICAgICAgIGUyYyA9IEZyLmFkZChlMmMsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgICAgICAgICBsZXQgZTJkID0gejtcblxuICAgICAgICAgICAgbGV0IFtlMiwgZTJ6XSA9IE11bFoubXVsNChlMmEsIGUyYiwgZTJjLCBlMmQsIGFwLCBicCwgY3AsIHpwLCBpICUgNCwgRnIpO1xuICAgICAgICAgICAgZTIgPSBGci5tdWwoZTIsIGNoYWxsZW5nZXMuYWxwaGEpO1xuICAgICAgICAgICAgZTJ6ID0gRnIubXVsKGUyeiwgY2hhbGxlbmdlcy5hbHBoYSk7XG5cbiAgICAgICAgICAgIC8vIGUzIDo9IM6xWyhhKFgpICsgzrJTz4MxKFgpICsgzrMpKGIoWCkgKyDOslPPgzIoWCkgKyDOsykoYyhYKSArIM6yU8+DMyhYKSArIM6zKXooWM+JKV1cbiAgICAgICAgICAgIGxldCBlM2EgPSBhO1xuICAgICAgICAgICAgZTNhID0gRnIuYWRkKGUzYSwgRnIubXVsKGNoYWxsZW5nZXMuYmV0YSwgczEpKTtcbiAgICAgICAgICAgIGUzYSA9IEZyLmFkZChlM2EsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgICAgICAgICBsZXQgZTNiID0gYjtcbiAgICAgICAgICAgIGUzYiA9IEZyLmFkZChlM2IsIEZyLm11bChjaGFsbGVuZ2VzLmJldGEsIHMyKSk7XG4gICAgICAgICAgICBlM2IgPSBGci5hZGQoZTNiLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICAgICAgbGV0IGUzYyA9IGM7XG4gICAgICAgICAgICBlM2MgPSBGci5hZGQoZTNjLCBGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCBzMykpO1xuICAgICAgICAgICAgZTNjID0gRnIuYWRkKGUzYywgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgICAgIGxldCBlM2QgPSB6dztcbiAgICAgICAgICAgIGxldCBbZTMsIGUzel0gPSBNdWxaLm11bDQoZTNhLCBlM2IsIGUzYywgZTNkLCBhcCwgYnAsIGNwLCB6V3AsIGkgJSA0LCBGcik7XG5cbiAgICAgICAgICAgIGUzID0gRnIubXVsKGUzLCBjaGFsbGVuZ2VzLmFscGhhKTtcbiAgICAgICAgICAgIGUzeiA9IEZyLm11bChlM3osIGNoYWxsZW5nZXMuYWxwaGEpO1xuXG4gICAgICAgICAgICAvLyBlNCA6PSDOsV4yKHooWCniiJIxKUwxKFgpXG4gICAgICAgICAgICBsZXQgZTQgPSBGci5zdWIoeiwgRnIub25lKTtcbiAgICAgICAgICAgIGU0ID0gRnIubXVsKGU0LCBldmFsdWF0aW9ucy5MYWdyYW5nZS5nZXRFdmFsdWF0aW9uKGkpKTtcbiAgICAgICAgICAgIGU0ID0gRnIubXVsKGU0LCBjaGFsbGVuZ2VzLmFscGhhMik7XG5cbiAgICAgICAgICAgIGxldCBlNHogPSBGci5tdWwoenAsIGV2YWx1YXRpb25zLkxhZ3JhbmdlLmdldEV2YWx1YXRpb24oaSkpO1xuICAgICAgICAgICAgZTR6ID0gRnIubXVsKGU0eiwgY2hhbGxlbmdlcy5hbHBoYTIpO1xuXG5cbiAgICAgICAgICAgIGxldCB0ID0gRnIuYWRkKEZyLnN1YihGci5hZGQoZTEsIGUyKSwgZTMpLCBlNCk7XG4gICAgICAgICAgICBsZXQgdHogPSBGci5hZGQoRnIuc3ViKEZyLmFkZChlMXosIGUyeiksIGUzeiksIGU0eik7XG5cbiAgICAgICAgICAgIGJ1ZmZlcnMuVC5zZXQodCwgaSAqIG44cik7XG4gICAgICAgICAgICBidWZmZXJzLlR6LnNldCh0eiwgaSAqIG44cik7XG5cbiAgICAgICAgICAgIHcgPSBGci5tdWwodywgRnIud1t6a2V5LnBvd2VyICsgMl0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29tcHV0ZSB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBwb2x5bm9taWFsIFQwKFgpIGZyb20gYnVmZmVycy5UMFxuICAgICAgICBpZiAobG9nZ2VyKVxuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFwiwrfCt8K3IENvbXB1dGluZyBUIGlmZnRcIik7XG4gICAgICAgIHBvbHlub21pYWxzLlQgPSBhd2FpdCBQb2x5bm9taWFsLmZyb21FdmFsdWF0aW9ucyhidWZmZXJzLlQsIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgICAgIC8vIERpdmlkZSB0aGUgcG9seW5vbWlhbCBUMCBieSBaX0goWClcbiAgICAgICAgaWYgKGxvZ2dlcilcbiAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcIsK3wrfCtyBDb21wdXRpbmcgVCAvIFpIXCIpO1xuICAgICAgICBwb2x5bm9taWFscy5ULmRpdlpoKHprZXkuZG9tYWluU2l6ZSwgNCk7XG5cbiAgICAgICAgLy8gQ29tcHV0ZSB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBwb2x5bm9taWFsIFR6KFgpIGZyb20gYnVmZmVycy5UelxuICAgICAgICBpZiAobG9nZ2VyKVxuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFwiwrfCt8K3IENvbXB1dGluZyBUeiBpZmZ0XCIpO1xuICAgICAgICBwb2x5bm9taWFscy5UeiA9IGF3YWl0IFBvbHlub21pYWwuZnJvbUV2YWx1YXRpb25zKGJ1ZmZlcnMuVHosIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgICAgIC8vIEFkZCB0aGUgcG9seW5vbWlhbCBUMXogdG8gVDEgdG8gZ2V0IHRoZSBmaW5hbCBwb2x5bm9taWFsIFQxXG4gICAgICAgIHBvbHlub21pYWxzLlQuYWRkKHBvbHlub21pYWxzLlR6KTtcblxuICAgICAgICAvLyBDaGVjayBkZWdyZWVcbiAgICAgICAgaWYgKHBvbHlub21pYWxzLlQuZGVncmVlKCkgPj0gemtleS5kb21haW5TaXplICogMyArIDYpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlQgUG9seW5vbWlhbCBpcyBub3Qgd2VsbCBjYWxjdWxhdGVkXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gdCh4KSBoYXMgZGVncmVlIDNuICsgNSwgd2UgYXJlIGdvaW5nIHRvIHNwbGl0IHQoeCkgaW50byB0aHJlZSBzbWFsbGVyIHBvbHlub21pYWxzOlxuICAgICAgICAvLyBUMScgYW5kIFQyJyAgd2l0aCBhIGRlZ3JlZSA8IG4gYW5kIFQzJyB3aXRoIGEgZGVncmVlIG4rNVxuICAgICAgICAvLyBzdWNoIHRoYXQgdCh4KSA9IFQxJyhYKSArIFhebiBUMicoWCkgKyBYXnsybn0gVDMnKFgpXG4gICAgICAgIC8vIFRvIHJhbmRvbWl6ZSB0aGUgcGFydHMgd2UgdXNlIGJsaW5kaW5nIHNjYWxhcnMgYl8xMCBhbmQgYl8xMSBpbiBhIHdheSB0aGF0IGRvZXNuJ3QgY2hhbmdlIHQoWCk6XG4gICAgICAgIC8vIFQxKFgpID0gVDEnKFgpICsgYl8xMCBYXm5cbiAgICAgICAgLy8gVDIoWCkgPSBUMicoWCkgLSBiXzEwICsgYl8xMSBYXm5cbiAgICAgICAgLy8gVDMoWCkgPSBUMycoWCkgLSBiXzExXG4gICAgICAgIC8vIHN1Y2ggdGhhdFxuICAgICAgICAvLyB0KFgpID0gVDEoWCkgKyBYXm4gVDIoWCkgKyBYXjJuIFQzKFgpXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIsK3wrfCtyBDb21wdXRpbmcgVDEsIFQyLCBUMyBwb2x5bm9taWFsc1wiKTtcbiAgICAgICAgcG9seW5vbWlhbHMuVDEgPSBuZXcgUG9seW5vbWlhbChuZXcgQmlnQnVmZmVyKCh6a2V5LmRvbWFpblNpemUgKyAxKSAqIG44ciksIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBwb2x5bm9taWFscy5UMiA9IG5ldyBQb2x5bm9taWFsKG5ldyBCaWdCdWZmZXIoKHprZXkuZG9tYWluU2l6ZSArIDEpICogbjhyKSwgY3VydmUsIGxvZ2dlcik7XG4gICAgICAgIHBvbHlub21pYWxzLlQzID0gbmV3IFBvbHlub21pYWwobmV3IEJpZ0J1ZmZlcigoemtleS5kb21haW5TaXplICsgNikgKiBuOHIpLCBjdXJ2ZSwgbG9nZ2VyKTtcblxuICAgICAgICBwb2x5bm9taWFscy5UMS5jb2VmLnNldChwb2x5bm9taWFscy5ULmNvZWYuc2xpY2UoMCwgc0RvbWFpbiksIDApO1xuICAgICAgICBwb2x5bm9taWFscy5UMi5jb2VmLnNldChwb2x5bm9taWFscy5ULmNvZWYuc2xpY2Uoc0RvbWFpbiwgc0RvbWFpbiAqIDIpLCAwKTtcbiAgICAgICAgcG9seW5vbWlhbHMuVDMuY29lZi5zZXQocG9seW5vbWlhbHMuVC5jb2VmLnNsaWNlKHNEb21haW4gKiAyLCBzRG9tYWluICogMyArIDYgKiBuOHIpLCAwKTtcblxuICAgICAgICAvLyBBZGQgYmxpbmRpbmcgc2NhbGFyIGJfMTAgYXMgYSBuZXcgY29lZmZpY2llbnQgblxuICAgICAgICBwb2x5bm9taWFscy5UMS5zZXRDb2VmKHprZXkuZG9tYWluU2l6ZSwgY2hhbGxlbmdlcy5iWzEwXSk7XG5cbiAgICAgICAgLy8gY29tcHV0ZSB0X21pZChYKVxuICAgICAgICAvLyBTdWJ0cmFjdCBibGluZGluZyBzY2FsYXIgYl8xMCB0byB0aGUgbG93ZXN0IGNvZWZmaWNpZW50IG9mIHRfbWlkXG4gICAgICAgIGNvbnN0IGxvd2VzdE1pZCA9IEZyLnN1Yihwb2x5bm9taWFscy5UMi5nZXRDb2VmKDApLCBjaGFsbGVuZ2VzLmJbMTBdKTtcbiAgICAgICAgcG9seW5vbWlhbHMuVDIuc2V0Q29lZigwLCBsb3dlc3RNaWQpO1xuICAgICAgICBwb2x5bm9taWFscy5UMi5zZXRDb2VmKHprZXkuZG9tYWluU2l6ZSwgY2hhbGxlbmdlcy5iWzExXSk7XG5cbiAgICAgICAgLy8gY29tcHV0ZSB0X2hpZ2goWClcbiAgICAgICAgLy9TdWJ0cmFjdCBibGluZGluZyBzY2FsYXIgYl8xMSB0byB0aGUgbG93ZXN0IGNvZWZmaWNpZW50IG9mIHRfaGlnaFxuICAgICAgICBjb25zdCBsb3dlc3RIaWdoID0gRnIuc3ViKHBvbHlub21pYWxzLlQzLmdldENvZWYoMCksIGNoYWxsZW5nZXMuYlsxMV0pO1xuICAgICAgICBwb2x5bm9taWFscy5UMy5zZXRDb2VmKDAsIGxvd2VzdEhpZ2gpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHJvdW5kNCgpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiPiBDb21wdXRpbmcgY2hhbGxlbmdlIHhpXCIpO1xuXG4gICAgICAgIC8vIFNURVAgNC4xIC0gQ29tcHV0ZSBldmFsdWF0aW9uIGNoYWxsZW5nZSB4aSDiiIggRlxuICAgICAgICB0cmFuc2NyaXB0LnJlc2V0KCk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKGNoYWxsZW5nZXMuYWxwaGEpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQocHJvb2YuZ2V0UG9seW5vbWlhbChcIlQxXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHByb29mLmdldFBvbHlub21pYWwoXCJUMlwiKSk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5nZXRQb2x5bm9taWFsKFwiVDNcIikpO1xuXG4gICAgICAgIGNoYWxsZW5nZXMueGkgPSB0cmFuc2NyaXB0LmdldENoYWxsZW5nZSgpO1xuICAgICAgICBjaGFsbGVuZ2VzLnhpdyA9IEZyLm11bChjaGFsbGVuZ2VzLnhpLCBGci53W3prZXkucG93ZXJdKTtcbiAgICAgICAgXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIsK3wrfCtyBjaGFsbGVuZ2VzLnhpOiBcIiArIEZyLnRvU3RyaW5nKGNoYWxsZW5nZXMueGksIDE2KSk7ICBcblxuICAgICAgICAvLyBGb3VydGggb3V0cHV0IG9mIHRoZSBwcm92ZXIgaXMgKCBhKHhpKSwgYih4aSksIGMoeGkpLCBzMSh4aSksIHMyKHhpKSwgeih4aXcpIClcbiAgICAgICAgcHJvb2YuYWRkRXZhbHVhdGlvbihcImV2YWxfYVwiLCBwb2x5bm9taWFscy5BLmV2YWx1YXRlKGNoYWxsZW5nZXMueGkpKTtcbiAgICAgICAgcHJvb2YuYWRkRXZhbHVhdGlvbihcImV2YWxfYlwiLCBwb2x5bm9taWFscy5CLmV2YWx1YXRlKGNoYWxsZW5nZXMueGkpKTtcbiAgICAgICAgcHJvb2YuYWRkRXZhbHVhdGlvbihcImV2YWxfY1wiLCBwb2x5bm9taWFscy5DLmV2YWx1YXRlKGNoYWxsZW5nZXMueGkpKTtcbiAgICAgICAgcHJvb2YuYWRkRXZhbHVhdGlvbihcImV2YWxfczFcIiwgcG9seW5vbWlhbHMuU2lnbWExLmV2YWx1YXRlKGNoYWxsZW5nZXMueGkpKTtcbiAgICAgICAgcHJvb2YuYWRkRXZhbHVhdGlvbihcImV2YWxfczJcIiwgcG9seW5vbWlhbHMuU2lnbWEyLmV2YWx1YXRlKGNoYWxsZW5nZXMueGkpKTtcbiAgICAgICAgcHJvb2YuYWRkRXZhbHVhdGlvbihcImV2YWxfendcIiwgcG9seW5vbWlhbHMuWi5ldmFsdWF0ZShjaGFsbGVuZ2VzLnhpdykpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHJvdW5kNSgpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmRlYnVnKFwiPiBDb21wdXRpbmcgY2hhbGxlbmdlIHZcIik7XG4gICAgICAgIFxuICAgICAgICAvLyBTVEVQIDUuMSAtIENvbXB1dGUgZXZhbHVhdGlvbiBjaGFsbGVuZ2UgdiDiiIggRlxuICAgICAgICB0cmFuc2NyaXB0LnJlc2V0KCk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKGNoYWxsZW5nZXMueGkpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5nZXRFdmFsdWF0aW9uKFwiZXZhbF9hXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcImV2YWxfYlwiKSk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHByb29mLmdldEV2YWx1YXRpb24oXCJldmFsX2NcIikpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5nZXRFdmFsdWF0aW9uKFwiZXZhbF9zMVwiKSk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHByb29mLmdldEV2YWx1YXRpb24oXCJldmFsX3MyXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcImV2YWxfendcIikpO1xuXG4gICAgICAgIGNoYWxsZW5nZXMudiA9IFtdO1xuICAgICAgICBjaGFsbGVuZ2VzLnZbMV0gPSB0cmFuc2NyaXB0LmdldENoYWxsZW5nZSgpO1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCLCt8K3wrcgY2hhbGxlbmdlcy52OiBcIiArIEZyLnRvU3RyaW5nKGNoYWxsZW5nZXMudlsxXSwgMTYpKTtcblxuICAgICAgICBmb3IgKGxldCBpID0gMjsgaSA8IDY7IGkrKykge1xuICAgICAgICAgICAgY2hhbGxlbmdlcy52W2ldID0gRnIubXVsKGNoYWxsZW5nZXMudltpIC0gMV0sIGNoYWxsZW5nZXMudlsxXSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTVEVQIDUuMiBDb21wdXRlIGxpbmVhcmlzYXRpb24gcG9seW5vbWlhbCByKFgpXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIj4gQ29tcHV0aW5nIGxpbmVhcmlzYXRpb24gcG9seW5vbWlhbCBSKFgpXCIpO1xuICAgICAgICBhd2FpdCBjb21wdXRlUigpO1xuXG4gICAgICAgIC8vU1RFUCA1LjMgQ29tcHV0ZSBvcGVuaW5nIHByb29mIHBvbHlub21pYWwgV3hpKFgpXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIj4gQ29tcHV0aW5nIG9wZW5pbmcgcHJvb2YgcG9seW5vbWlhbCBXeGkoWCkgcG9seW5vbWlhbFwiKTtcbiAgICAgICAgY29tcHV0ZVd4aSgpO1xuXG4gICAgICAgIC8vU1RFUCA1LjQgQ29tcHV0ZSBvcGVuaW5nIHByb29mIHBvbHlub21pYWwgV3hpdyhYKVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCI+IENvbXB1dGluZyBvcGVuaW5nIHByb29mIHBvbHlub21pYWwgV3hpdyhYKSBwb2x5bm9taWFsXCIpO1xuICAgICAgICBjb21wdXRlV3hpdygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIj4gQ29tcHV0aW5nIFd4aSwgV3hpdyBNU01cIik7XG4gICAgICAgIGxldCBjb21taXRXeGkgPSBhd2FpdCBwb2x5bm9taWFscy5XeGkubXVsdGlFeHBvbmVudGlhdGlvbihQVGF1LCBcIld4aVwiKTtcbiAgICAgICAgbGV0IGNvbW1pdFd4aXcgPSBhd2FpdCBwb2x5bm9taWFscy5XeGl3Lm11bHRpRXhwb25lbnRpYXRpb24oUFRhdSwgXCJXeGl3XCIpO1xuXG4gICAgICAgIC8vIEZpZnRoIG91dHB1dCBvZiB0aGUgcHJvdmVyIGlzIChbV3hpXV8xLCBbV3hpd11fMSlcbiAgICAgICAgcHJvb2YuYWRkUG9seW5vbWlhbChcIld4aVwiLCBjb21taXRXeGkpO1xuICAgICAgICBwcm9vZi5hZGRQb2x5bm9taWFsKFwiV3hpd1wiLCBjb21taXRXeGl3KTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiBjb21wdXRlUigpIHtcbiAgICAgICAgY29uc3QgRnIgPSBjdXJ2ZS5GcjtcbiAgICBcbiAgICAgICAgLy8gUmVzZXJ2ZSBtZW1vcnkgZm9yIFEncyBwb2x5bm9taWFsc1xuICAgICAgICBwb2x5bm9taWFscy5RTCA9IG5ldyBQb2x5bm9taWFsKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiksIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBwb2x5bm9taWFscy5RUiA9IG5ldyBQb2x5bm9taWFsKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiksIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBwb2x5bm9taWFscy5RTSA9IG5ldyBQb2x5bm9taWFsKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiksIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBwb2x5bm9taWFscy5RTyA9IG5ldyBQb2x5bm9taWFsKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiksIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBwb2x5bm9taWFscy5RQyA9IG5ldyBQb2x5bm9taWFsKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiksIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgICAgIC8vIFJlYWQgUSdzIGV2YWx1YXRpb25zIGZyb20gemtleSBmaWxlXG4gICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIocG9seW5vbWlhbHMuUUwuY29lZiwgMCwgc0RvbWFpbiwgemtleVNlY3Rpb25zW1pLRVlfUExfUUxfU0VDVElPTl1bMF0ucCk7XG4gICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIocG9seW5vbWlhbHMuUVIuY29lZiwgMCwgc0RvbWFpbiwgemtleVNlY3Rpb25zW1pLRVlfUExfUVJfU0VDVElPTl1bMF0ucCk7XG4gICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIocG9seW5vbWlhbHMuUU0uY29lZiwgMCwgc0RvbWFpbiwgemtleVNlY3Rpb25zW1pLRVlfUExfUU1fU0VDVElPTl1bMF0ucCk7XG4gICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIocG9seW5vbWlhbHMuUU8uY29lZiwgMCwgc0RvbWFpbiwgemtleVNlY3Rpb25zW1pLRVlfUExfUU9fU0VDVElPTl1bMF0ucCk7XG4gICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIocG9seW5vbWlhbHMuUUMuY29lZiwgMCwgc0RvbWFpbiwgemtleVNlY3Rpb25zW1pLRVlfUExfUUNfU0VDVElPTl1bMF0ucCk7ICAgXG4gICAgICAgIFxuICAgICAgICBjaGFsbGVuZ2VzLnhpbiA9IGNoYWxsZW5nZXMueGk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgemtleS5wb3dlcjsgaSsrKSB7XG4gICAgICAgICAgICBjaGFsbGVuZ2VzLnhpbiA9IEZyLnNxdWFyZShjaGFsbGVuZ2VzLnhpbik7XG4gICAgICAgIH1cblxuICAgICAgICBjaGFsbGVuZ2VzLnpoID0gRnIuc3ViKGNoYWxsZW5nZXMueGluLCBGci5vbmUpO1xuXG4gICAgICAgIGNvbnN0IEwgPSBbXTtcblxuICAgICAgICBjb25zdCBuID0gRnIuZSh6a2V5LmRvbWFpblNpemUpO1xuICAgICAgICBsZXQgdyA9IEZyLm9uZTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPD0gTWF0aC5tYXgoMSwgemtleS5uUHVibGljKTsgaSsrKSB7XG4gICAgICAgICAgICBMW2ldID0gRnIuZGl2KEZyLm11bCh3LCBjaGFsbGVuZ2VzLnpoKSwgRnIubXVsKG4sIEZyLnN1YihjaGFsbGVuZ2VzLnhpLCB3KSkpO1xuICAgICAgICAgICAgdyA9IEZyLm11bCh3LCBGci53W3prZXkucG93ZXJdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGV2YWxfbDEgPSBGci5kaXYoXG4gICAgICAgICAgICBGci5zdWIoY2hhbGxlbmdlcy54aW4sIEZyLm9uZSksXG4gICAgICAgICAgICBGci5tdWwobiwgRnIuc3ViKGNoYWxsZW5nZXMueGksIEZyLm9uZSkpXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKGxvZ2dlcikge1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFwiTGFncmFuZ2UgRXZhbHVhdGlvbnM6IFwiKTtcbiAgICAgICAgICAgIGZvciAobGV0IGk9MTsgaTxMLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKGBMJHtpfSh4aSk9YCArIEZyLnRvU3RyaW5nKExbaV0sIDE2KSk7ICAgIFxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGV2YWxfcGkgPSBGci56ZXJvO1xuICAgICAgICBmb3IgKGxldCBpPTA7IGk8cHVibGljU2lnbmFscy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgdyA9IEZyLmUocHVibGljU2lnbmFsc1tpXSk7XG4gICAgICAgICAgICBldmFsX3BpID0gRnIuc3ViKGV2YWxfcGksIEZyLm11bCh3LCBMW2krMV0pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5kZWJ1ZyhcIlBJOiBcIiArIEZyLnRvU3RyaW5nKGV2YWxfcGksIDE2KSk7XG5cbiAgICAgICAgLy8gQ29tcHV0ZSBjb25zdGFudCBwYXJ0cyBvZiBSKFgpXG4gICAgICAgIGNvbnN0IGNvZWZfYWIgPSBGci5tdWwocHJvb2YuZXZhbHVhdGlvbnMuZXZhbF9hLCBwcm9vZi5ldmFsdWF0aW9ucy5ldmFsX2IpO1xuXG4gICAgICAgIGxldCBlMmEgPSBwcm9vZi5ldmFsdWF0aW9ucy5ldmFsX2E7XG4gICAgICAgIGNvbnN0IGJldGF4aSA9IEZyLm11bChjaGFsbGVuZ2VzLmJldGEsIGNoYWxsZW5nZXMueGkpO1xuICAgICAgICBlMmEgPSBGci5hZGQoZTJhLCBiZXRheGkpO1xuICAgICAgICBlMmEgPSBGci5hZGQoZTJhLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICBsZXQgZTJiID0gcHJvb2YuZXZhbHVhdGlvbnMuZXZhbF9iO1xuICAgICAgICBlMmIgPSBGci5hZGQoZTJiLCBGci5tdWwoYmV0YXhpLCB6a2V5LmsxKSk7XG4gICAgICAgIGUyYiA9IEZyLmFkZChlMmIsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgICAgIGxldCBlMmMgPSBwcm9vZi5ldmFsdWF0aW9ucy5ldmFsX2M7XG4gICAgICAgIGUyYyA9IEZyLmFkZChlMmMsIEZyLm11bChiZXRheGksIHprZXkuazIpKTtcbiAgICAgICAgZTJjID0gRnIuYWRkKGUyYywgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgY29uc3QgZTIgPSBGci5tdWwoRnIubXVsKEZyLm11bChlMmEsIGUyYiksIGUyYyksIGNoYWxsZW5nZXMuYWxwaGEpO1xuXG4gICAgICAgIGxldCBlM2EgPSBwcm9vZi5ldmFsdWF0aW9ucy5ldmFsX2E7XG4gICAgICAgIGUzYSA9IEZyLmFkZChlM2EsIEZyLm11bChjaGFsbGVuZ2VzLmJldGEsIHByb29mLmV2YWx1YXRpb25zLmV2YWxfczEpKTtcbiAgICAgICAgZTNhID0gRnIuYWRkKGUzYSwgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgbGV0IGUzYiA9IHByb29mLmV2YWx1YXRpb25zLmV2YWxfYjtcbiAgICAgICAgZTNiID0gRnIuYWRkKGUzYiwgRnIubXVsKGNoYWxsZW5nZXMuYmV0YSwgcHJvb2YuZXZhbHVhdGlvbnMuZXZhbF9zMikpO1xuICAgICAgICBlM2IgPSBGci5hZGQoZTNiLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICBsZXQgZTMgPSBGci5tdWwoZTNhLCBlM2IpO1xuICAgICAgICBlMyA9IEZyLm11bChlMywgcHJvb2YuZXZhbHVhdGlvbnMuZXZhbF96dyk7XG4gICAgICAgIGUzID0gRnIubXVsKGUzLCBjaGFsbGVuZ2VzLmFscGhhKTtcblxuICAgICAgICBjb25zdCBlNCA9IEZyLm11bChldmFsX2wxLCBjaGFsbGVuZ2VzLmFscGhhMik7XG5cbiAgICAgICAgcG9seW5vbWlhbHMuUiA9IG5ldyBQb2x5bm9taWFsKG5ldyBCaWdCdWZmZXIoKHprZXkuZG9tYWluU2l6ZSArIDYpICogbjhyKSwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICAgICAgcG9seW5vbWlhbHMuUi5hZGQocG9seW5vbWlhbHMuUU0sIGNvZWZfYWIpO1xuICAgICAgICBwb2x5bm9taWFscy5SLmFkZChwb2x5bm9taWFscy5RTCwgcHJvb2YuZXZhbHVhdGlvbnMuZXZhbF9hKTtcbiAgICAgICAgcG9seW5vbWlhbHMuUi5hZGQocG9seW5vbWlhbHMuUVIsIHByb29mLmV2YWx1YXRpb25zLmV2YWxfYik7XG4gICAgICAgIHBvbHlub21pYWxzLlIuYWRkKHBvbHlub21pYWxzLlFPLCBwcm9vZi5ldmFsdWF0aW9ucy5ldmFsX2MpO1xuICAgICAgICBwb2x5bm9taWFscy5SLmFkZChwb2x5bm9taWFscy5RQyk7XG4gICAgICAgIHBvbHlub21pYWxzLlIuYWRkKHBvbHlub21pYWxzLlosIGUyKTtcbiAgICAgICAgcG9seW5vbWlhbHMuUi5zdWIocG9seW5vbWlhbHMuU2lnbWEzLCBGci5tdWwoZTMsIGNoYWxsZW5nZXMuYmV0YSkpO1xuICAgICAgICBwb2x5bm9taWFscy5SLmFkZChwb2x5bm9taWFscy5aLCBlNCk7XG5cbiAgICAgICAgbGV0IHRtcCA9IFBvbHlub21pYWwuZnJvbVBvbHlub21pYWwocG9seW5vbWlhbHMuVDMsIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICB0bXAubXVsU2NhbGFyKEZyLnNxdWFyZShjaGFsbGVuZ2VzLnhpbikpO1xuICAgICAgICB0bXAuYWRkKHBvbHlub21pYWxzLlQyLCBjaGFsbGVuZ2VzLnhpbik7XG4gICAgICAgIHRtcC5hZGQocG9seW5vbWlhbHMuVDEpO1xuICAgICAgICB0bXAubXVsU2NhbGFyKGNoYWxsZW5nZXMuemgpO1xuXG4gICAgICAgIHBvbHlub21pYWxzLlIuc3ViKHRtcCk7XG5cbiAgICAgICAgbGV0IHIwID0gRnIuc3ViKGV2YWxfcGksIEZyLm11bChlMywgRnIuYWRkKHByb29mLmV2YWx1YXRpb25zLmV2YWxfYywgY2hhbGxlbmdlcy5nYW1tYSkpKTtcbiAgICAgICAgcjAgPSBGci5zdWIocjAsIGU0KTtcblxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJyMDogXCIgKyBGci50b1N0cmluZyhyMCwgMTYpKTtcblxuICAgICAgICBwb2x5bm9taWFscy5SLmFkZFNjYWxhcihyMCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY29tcHV0ZVd4aSgpIHtcbiAgICAgICAgcG9seW5vbWlhbHMuV3hpID0gbmV3IFBvbHlub21pYWwobmV3IEJpZ0J1ZmZlcihzRG9tYWluICsgNiAqIG44ciksIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgICAgIHBvbHlub21pYWxzLld4aS5hZGQocG9seW5vbWlhbHMuUik7XG4gICAgICAgIHBvbHlub21pYWxzLld4aS5hZGQocG9seW5vbWlhbHMuQSwgY2hhbGxlbmdlcy52WzFdKTtcbiAgICAgICAgcG9seW5vbWlhbHMuV3hpLmFkZChwb2x5bm9taWFscy5CLCBjaGFsbGVuZ2VzLnZbMl0pO1xuICAgICAgICBwb2x5bm9taWFscy5XeGkuYWRkKHBvbHlub21pYWxzLkMsIGNoYWxsZW5nZXMudlszXSk7XG4gICAgICAgIHBvbHlub21pYWxzLld4aS5hZGQocG9seW5vbWlhbHMuU2lnbWExLCBjaGFsbGVuZ2VzLnZbNF0pO1xuICAgICAgICBwb2x5bm9taWFscy5XeGkuYWRkKHBvbHlub21pYWxzLlNpZ21hMiwgY2hhbGxlbmdlcy52WzVdKTtcblxuICAgICAgICBwb2x5bm9taWFscy5XeGkuc3ViU2NhbGFyKEZyLm11bChjaGFsbGVuZ2VzLnZbMV0sIHByb29mLmV2YWx1YXRpb25zLmV2YWxfYSkpO1xuICAgICAgICBwb2x5bm9taWFscy5XeGkuc3ViU2NhbGFyKEZyLm11bChjaGFsbGVuZ2VzLnZbMl0sIHByb29mLmV2YWx1YXRpb25zLmV2YWxfYikpO1xuICAgICAgICBwb2x5bm9taWFscy5XeGkuc3ViU2NhbGFyKEZyLm11bChjaGFsbGVuZ2VzLnZbM10sIHByb29mLmV2YWx1YXRpb25zLmV2YWxfYykpO1xuICAgICAgICBwb2x5bm9taWFscy5XeGkuc3ViU2NhbGFyKEZyLm11bChjaGFsbGVuZ2VzLnZbNF0sIHByb29mLmV2YWx1YXRpb25zLmV2YWxfczEpKTtcbiAgICAgICAgcG9seW5vbWlhbHMuV3hpLnN1YlNjYWxhcihGci5tdWwoY2hhbGxlbmdlcy52WzVdLCBwcm9vZi5ldmFsdWF0aW9ucy5ldmFsX3MyKSk7XG5cbiAgICAgICAgcG9seW5vbWlhbHMuV3hpLmRpdkJ5WmVyb2ZpZXIoMSwgY2hhbGxlbmdlcy54aSk7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gY29tcHV0ZVd4aXcoKSB7XG4gICAgICAgIHBvbHlub21pYWxzLld4aXcgPSBQb2x5bm9taWFsLmZyb21Qb2x5bm9taWFsKHBvbHlub21pYWxzLlosIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICBwb2x5bm9taWFscy5XeGl3LnN1YlNjYWxhcihwcm9vZi5ldmFsdWF0aW9ucy5ldmFsX3p3KTtcblxuICAgICAgICBwb2x5bm9taWFscy5XeGl3LmRpdkJ5WmVyb2ZpZXIoMSwgY2hhbGxlbmdlcy54aXcpO1xuICAgIH1cbn1cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMjEgMEtJTVMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya0pTLlxuXG4gICAgc25hcmtKUyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXRcbiAgICB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJrSlMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVRcbiAgICBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWNcbiAgICBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggc25hcmtKUy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCBwbG9ua19wcm92ZSBmcm9tIFwiLi9wbG9ua19wcm92ZS5qc1wiO1xuaW1wb3J0IHd0bnNfY2FsY3VsYXRlIGZyb20gXCIuL3d0bnNfY2FsY3VsYXRlLmpzXCI7XG5pbXBvcnQge3V0aWxzfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5jb25zdCB7dW5zdHJpbmdpZnlCaWdJbnRzfSA9IHV0aWxzO1xuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBwbG9ua0Z1bGxQcm92ZShfaW5wdXQsIHdhc21GaWxlLCB6a2V5RmlsZU5hbWUsIGxvZ2dlciwgd3Ruc0NhbGNPcHRpb25zLCBwcm92ZXJPcHRpb25zKSB7XG4gICAgY29uc3QgaW5wdXQgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX2lucHV0KTtcblxuICAgIGNvbnN0IHd0bnM9IHtcbiAgICAgICAgdHlwZTogXCJtZW1cIlxuICAgIH07XG4gICAgYXdhaXQgd3Ruc19jYWxjdWxhdGUoaW5wdXQsIHdhc21GaWxlLCB3dG5zLCB3dG5zQ2FsY09wdGlvbnMpO1xuICAgIHJldHVybiBhd2FpdCBwbG9ua19wcm92ZSh6a2V5RmlsZU5hbWUsIHd0bnMsIGxvZ2dlciwgcHJvdmVyT3B0aW9ucyk7XG59XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDIxIDBraW1zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG4vKiBJbXBsZW1lbnRhdGlvbiBvZiB0aGlzIHBhcGVyOiBodHRwczovL2VwcmludC5pYWNyLm9yZy8yMDE5Lzk1My5wZGYgKi9cblxuaW1wb3J0ICogYXMgY3VydmVzIGZyb20gXCIuL2N1cnZlcy5qc1wiO1xuaW1wb3J0IHsgdXRpbHMgfSAgIGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmltcG9ydCB7IEtlY2NhazI1NlRyYW5zY3JpcHQgfSBmcm9tIFwiLi9LZWNjYWsyNTZUcmFuc2NyaXB0LmpzXCI7XG5pbXBvcnQgeyBTY2FsYXIgfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5cbmNvbnN0IHsgdW5zdHJpbmdpZnlCaWdJbnRzIH0gPSB1dGlscztcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gcGxvbmtWZXJpZnkoX3ZrX3ZlcmlmaWVyLCBfcHVibGljU2lnbmFscywgX3Byb29mLCBsb2dnZXIpIHtcbiAgICBsZXQgdmtfdmVyaWZpZXIgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX3ZrX3ZlcmlmaWVyKTtcbiAgICBfcHJvb2YgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX3Byb29mKTtcbiAgICBsZXQgcHVibGljU2lnbmFscyA9IHVuc3RyaW5naWZ5QmlnSW50cyhfcHVibGljU2lnbmFscyk7XG5cbiAgICBjb25zdCBjdXJ2ZSA9IGF3YWl0IGN1cnZlcy5nZXRDdXJ2ZUZyb21OYW1lKHZrX3ZlcmlmaWVyLmN1cnZlKTtcblxuICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG4gICAgY29uc3QgRzEgPSBjdXJ2ZS5HMTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiUExPTksgVkVSSUZJRVIgU1RBUlRFRFwiKTtcblxuICAgIGxldCBwcm9vZiA9IGZyb21PYmplY3RQcm9vZihjdXJ2ZSxfcHJvb2YpO1xuICAgIHZrX3ZlcmlmaWVyID0gZnJvbU9iamVjdFZrKGN1cnZlLCB2a192ZXJpZmllcik7XG5cbiAgICBpZiAoIWlzV2VsbENvbnN0cnVjdGVkKGN1cnZlLCBwcm9vZikpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKFwiUHJvb2YgY29tbWl0bWVudHMgYXJlIG5vdCB2YWxpZC5cIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAocHVibGljU2lnbmFscy5sZW5ndGggIT0gdmtfdmVyaWZpZXIublB1YmxpYykge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJJbnZhbGlkIG51bWJlciBvZiBwdWJsaWMgaW5wdXRzXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKCFldmFsdWF0aW9uc0FyZVZhbGlkKGN1cnZlLCBwcm9vZikpIHtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmVycm9yKFwiUHJvb2YgZXZhbHVhdGlvbnMgYXJlIG5vdCB2YWxpZFwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmICghcHVibGljSW5wdXRzQXJlVmFsaWQoY3VydmUsIHB1YmxpY1NpZ25hbHMpKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIlB1YmxpYyBpbnB1dHMgYXJlIG5vdCB2YWxpZC5cIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBjaGFsbGVuZ2VzID0gY2FsY3VsYXRlY2hhbGxlbmdlcyhjdXJ2ZSwgcHJvb2YsIHB1YmxpY1NpZ25hbHMsIHZrX3ZlcmlmaWVyKTtcbiAgICBpZiAobG9nZ2VyKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcImJldGE6IFwiICsgRnIudG9TdHJpbmcoY2hhbGxlbmdlcy5iZXRhLCAxNikpOyAgICBcbiAgICAgICAgbG9nZ2VyLmRlYnVnKFwiZ2FtbWE6IFwiICsgRnIudG9TdHJpbmcoY2hhbGxlbmdlcy5nYW1tYSwgMTYpKTsgICAgXG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcImFscGhhOiBcIiArIEZyLnRvU3RyaW5nKGNoYWxsZW5nZXMuYWxwaGEsIDE2KSk7ICAgIFxuICAgICAgICBsb2dnZXIuZGVidWcoXCJ4aTogXCIgKyBGci50b1N0cmluZyhjaGFsbGVuZ2VzLnhpLCAxNikpO1xuICAgICAgICBmb3IobGV0IGk9MTtpPDY7aSsrKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZGVidWcoXCJ2OiBcIiArIEZyLnRvU3RyaW5nKGNoYWxsZW5nZXMudltpXSwgMTYpKTtcbiAgICAgICAgfVxuICAgICAgICBsb2dnZXIuZGVidWcoXCJ1OiBcIiArIEZyLnRvU3RyaW5nKGNoYWxsZW5nZXMudSwgMTYpKTsgICAgXG4gICAgfVxuICAgIGNvbnN0IEwgPSBjYWxjdWxhdGVMYWdyYW5nZUV2YWx1YXRpb25zKGN1cnZlLCBjaGFsbGVuZ2VzLCB2a192ZXJpZmllcik7XG4gICAgaWYgKGxvZ2dlcikge1xuICAgICAgICBmb3IgKGxldCBpPTE7IGk8TC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKGBMJHtpfSh4aSk9YCArIEZyLnRvU3RyaW5nKExbaV0sIDE2KSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgaWYgKHB1YmxpY1NpZ25hbHMubGVuZ3RoICE9IHZrX3ZlcmlmaWVyLm5QdWJsaWMpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKFwiTnVtYmVyIG9mIHB1YmxpYyBzaWduYWxzIGRvZXMgbm90IG1hdGNoIHdpdGggdmtcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBwaSA9IGNhbGN1bGF0ZVBJKGN1cnZlLCBwdWJsaWNTaWduYWxzLCBMKTtcbiAgICBpZiAobG9nZ2VyKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcIlBJKHhpKTogXCIgKyBGci50b1N0cmluZyhwaSwgMTYpKTtcbiAgICB9XG4gICAgXG4gICAgY29uc3QgcjAgPSBjYWxjdWxhdGVSMChjdXJ2ZSwgcHJvb2YsIGNoYWxsZW5nZXMsIHBpLCBMWzFdKTtcbiAgICBpZiAobG9nZ2VyKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcInIwOiBcIiArIEZyLnRvU3RyaW5nKHIwLCAxNikpO1xuICAgIH1cblxuICAgIGNvbnN0IEQgPSBjYWxjdWxhdGVEKGN1cnZlLCBwcm9vZiwgY2hhbGxlbmdlcywgdmtfdmVyaWZpZXIsIExbMV0pO1xuICAgIGlmIChsb2dnZXIpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKFwiRDogXCIgKyBHMS50b1N0cmluZyhHMS50b0FmZmluZShEKSwgMTYpKTtcbiAgICB9XG5cbiAgICBjb25zdCBGID0gY2FsY3VsYXRlRihjdXJ2ZSwgcHJvb2YsIGNoYWxsZW5nZXMsIHZrX3ZlcmlmaWVyLCBEKTtcbiAgICBpZiAobG9nZ2VyKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcIkY6IFwiICsgRzEudG9TdHJpbmcoRzEudG9BZmZpbmUoRiksIDE2KSk7XG4gICAgfVxuXG4gICAgY29uc3QgRSA9IGNhbGN1bGF0ZUUoY3VydmUsIHByb29mLCBjaGFsbGVuZ2VzLCByMCk7XG4gICAgaWYgKGxvZ2dlcikge1xuICAgICAgICBsb2dnZXIuZGVidWcoXCJFOiBcIiArIEcxLnRvU3RyaW5nKEcxLnRvQWZmaW5lKEUpLCAxNikpO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcyA9IGF3YWl0IGlzVmFsaWRQYWlyaW5nKGN1cnZlLCBwcm9vZiwgY2hhbGxlbmdlcywgdmtfdmVyaWZpZXIsIEUsIEYpO1xuXG4gICAgaWYgKGxvZ2dlcikge1xuICAgICAgICBpZiAocmVzKSB7XG4gICAgICAgICAgICBsb2dnZXIuaW5mbyhcIk9LIVwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKFwiSW52YWxpZCBQcm9vZlwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cblxuZnVuY3Rpb24gZnJvbU9iamVjdFByb29mKGN1cnZlLCBwcm9vZikge1xuICAgIGNvbnN0IEcxID0gY3VydmUuRzE7XG4gICAgY29uc3QgRnIgPSBjdXJ2ZS5GcjtcbiAgICBjb25zdCByZXMgPSB7fTtcbiAgICByZXMuQSA9IEcxLmZyb21PYmplY3QocHJvb2YuQSk7XG4gICAgcmVzLkIgPSBHMS5mcm9tT2JqZWN0KHByb29mLkIpO1xuICAgIHJlcy5DID0gRzEuZnJvbU9iamVjdChwcm9vZi5DKTtcbiAgICByZXMuWiA9IEcxLmZyb21PYmplY3QocHJvb2YuWik7XG4gICAgcmVzLlQxID0gRzEuZnJvbU9iamVjdChwcm9vZi5UMSk7XG4gICAgcmVzLlQyID0gRzEuZnJvbU9iamVjdChwcm9vZi5UMik7XG4gICAgcmVzLlQzID0gRzEuZnJvbU9iamVjdChwcm9vZi5UMyk7XG4gICAgcmVzLmV2YWxfYSA9IEZyLmZyb21PYmplY3QocHJvb2YuZXZhbF9hKTtcbiAgICByZXMuZXZhbF9iID0gRnIuZnJvbU9iamVjdChwcm9vZi5ldmFsX2IpO1xuICAgIHJlcy5ldmFsX2MgPSBGci5mcm9tT2JqZWN0KHByb29mLmV2YWxfYyk7XG4gICAgcmVzLmV2YWxfencgPSBGci5mcm9tT2JqZWN0KHByb29mLmV2YWxfencpO1xuICAgIHJlcy5ldmFsX3MxID0gRnIuZnJvbU9iamVjdChwcm9vZi5ldmFsX3MxKTtcbiAgICByZXMuZXZhbF9zMiA9IEZyLmZyb21PYmplY3QocHJvb2YuZXZhbF9zMik7XG4gICAgcmVzLld4aSA9IEcxLmZyb21PYmplY3QocHJvb2YuV3hpKTtcbiAgICByZXMuV3hpdyA9IEcxLmZyb21PYmplY3QocHJvb2YuV3hpdyk7XG4gICAgcmV0dXJuIHJlcztcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdFZrKGN1cnZlLCB2aykge1xuICAgIGNvbnN0IEcxID0gY3VydmUuRzE7XG4gICAgY29uc3QgRzIgPSBjdXJ2ZS5HMjtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgIGNvbnN0IHJlcyA9IHZrO1xuICAgIHJlcy5RbSA9IEcxLmZyb21PYmplY3QodmsuUW0pO1xuICAgIHJlcy5RbCA9IEcxLmZyb21PYmplY3QodmsuUWwpO1xuICAgIHJlcy5RciA9IEcxLmZyb21PYmplY3QodmsuUXIpO1xuICAgIHJlcy5RbyA9IEcxLmZyb21PYmplY3QodmsuUW8pO1xuICAgIHJlcy5RYyA9IEcxLmZyb21PYmplY3QodmsuUWMpO1xuICAgIHJlcy5TMSA9IEcxLmZyb21PYmplY3QodmsuUzEpO1xuICAgIHJlcy5TMiA9IEcxLmZyb21PYmplY3QodmsuUzIpO1xuICAgIHJlcy5TMyA9IEcxLmZyb21PYmplY3QodmsuUzMpO1xuICAgIHJlcy5rMSA9IEZyLmZyb21PYmplY3QodmsuazEpO1xuICAgIHJlcy5rMiA9IEZyLmZyb21PYmplY3QodmsuazIpO1xuICAgIHJlcy5YXzIgPSBHMi5mcm9tT2JqZWN0KHZrLlhfMik7XG5cbiAgICByZXR1cm4gcmVzO1xufVxuXG5mdW5jdGlvbiBpc1dlbGxDb25zdHJ1Y3RlZChjdXJ2ZSwgcHJvb2YpIHtcbiAgICBjb25zdCBHMSA9IGN1cnZlLkcxO1xuICAgIGlmICghRzEuaXNWYWxpZChwcm9vZi5BKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICghRzEuaXNWYWxpZChwcm9vZi5CKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICghRzEuaXNWYWxpZChwcm9vZi5DKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICghRzEuaXNWYWxpZChwcm9vZi5aKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICghRzEuaXNWYWxpZChwcm9vZi5UMSkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAoIUcxLmlzVmFsaWQocHJvb2YuVDIpKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKCFHMS5pc1ZhbGlkKHByb29mLlQzKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICghRzEuaXNWYWxpZChwcm9vZi5XeGkpKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKCFHMS5pc1ZhbGlkKHByb29mLld4aXcpKSByZXR1cm4gZmFsc2U7XG4gICAgcmV0dXJuIHRydWU7XG59XG5cbmZ1bmN0aW9uIGNoZWNrVmFsdWVCZWxvbmdUb0ZpZWxkKGN1cnZlLCB2YWx1ZSkge1xuICAgIHJldHVybiBTY2FsYXIuZ2VxKHZhbHVlLCAwKSAmJiBTY2FsYXIubHQodmFsdWUsIGN1cnZlLnIpO1xufVxuXG5mdW5jdGlvbiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBldmFsdWF0aW9uKSB7XG4gICAgcmV0dXJuIGNoZWNrVmFsdWVCZWxvbmdUb0ZpZWxkKGN1cnZlLCBTY2FsYXIuZnJvbVJwckxFKGV2YWx1YXRpb24pKTtcbn1cblxuZnVuY3Rpb24gZXZhbHVhdGlvbnNBcmVWYWxpZChjdXJ2ZSwgcHJvb2YpIHtcbiAgICByZXR1cm4gY2hlY2tFdmFsdWF0aW9uSXNWYWxpZChjdXJ2ZSwgcHJvb2YuZXZhbF9hKVxuICAgICAgICAmJiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBwcm9vZi5ldmFsX2IpXG4gICAgICAgICYmIGNoZWNrRXZhbHVhdGlvbklzVmFsaWQoY3VydmUsIHByb29mLmV2YWxfYylcbiAgICAgICAgJiYgY2hlY2tFdmFsdWF0aW9uSXNWYWxpZChjdXJ2ZSwgcHJvb2YuZXZhbF9zMSlcbiAgICAgICAgJiYgY2hlY2tFdmFsdWF0aW9uSXNWYWxpZChjdXJ2ZSwgcHJvb2YuZXZhbF9zMilcbiAgICAgICAgJiYgY2hlY2tFdmFsdWF0aW9uSXNWYWxpZChjdXJ2ZSwgcHJvb2YuZXZhbF96dyk7XG59XG5cbmZ1bmN0aW9uIHB1YmxpY0lucHV0c0FyZVZhbGlkKGN1cnZlLCBwdWJsaWNJbnB1dHMpIHtcbiAgICBmb3IobGV0IGkgPSAwOyBpIDwgcHVibGljSW5wdXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmKCFjaGVja1ZhbHVlQmVsb25nVG9GaWVsZChjdXJ2ZSwgcHVibGljSW5wdXRzW2ldKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufVxuXG5mdW5jdGlvbiBjYWxjdWxhdGVjaGFsbGVuZ2VzKGN1cnZlLCBwcm9vZiwgcHVibGljU2lnbmFscywgdmspIHtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgIGNvbnN0IHJlcyA9IHt9O1xuICAgIGNvbnN0IHRyYW5zY3JpcHQgPSBuZXcgS2VjY2FrMjU2VHJhbnNjcmlwdChjdXJ2ZSk7XG5cbiAgICAvLyBDaGFsbGVuZ2Ugcm91bmQgMjogYmV0YSBhbmQgZ2FtbWFcbiAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQodmsuUW0pO1xuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudCh2ay5RbCk7XG4gICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHZrLlFyKTtcbiAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQodmsuUW8pO1xuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudCh2ay5RYyk7XG4gICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHZrLlMxKTtcbiAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQodmsuUzIpO1xuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudCh2ay5TMyk7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHB1YmxpY1NpZ25hbHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIoRnIuZShwdWJsaWNTaWduYWxzW2ldKSk7XG4gICAgfVxuXG4gICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHByb29mLkEpO1xuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5CKTtcbiAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQocHJvb2YuQyk7XG5cbiAgICByZXMuYmV0YSA9IHRyYW5zY3JpcHQuZ2V0Q2hhbGxlbmdlKCk7XG5cbiAgICB0cmFuc2NyaXB0LnJlc2V0KCk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocmVzLmJldGEpO1xuICAgIHJlcy5nYW1tYSA9IHRyYW5zY3JpcHQuZ2V0Q2hhbGxlbmdlKCk7XG5cbiAgICAvLyBDaGFsbGVuZ2Ugcm91bmQgMzogYWxwaGFcbiAgICB0cmFuc2NyaXB0LnJlc2V0KCk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocmVzLmJldGEpO1xuICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHJlcy5nYW1tYSk7XG4gICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHByb29mLlopO1xuICAgIHJlcy5hbHBoYSA9IHRyYW5zY3JpcHQuZ2V0Q2hhbGxlbmdlKCk7XG5cbiAgICAvLyBDaGFsbGVuZ2Ugcm91bmQgNDogeGlcbiAgICB0cmFuc2NyaXB0LnJlc2V0KCk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocmVzLmFscGhhKTtcbiAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQocHJvb2YuVDEpO1xuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5UMik7XG4gICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHByb29mLlQzKTtcbiAgICByZXMueGkgPSB0cmFuc2NyaXB0LmdldENoYWxsZW5nZSgpO1xuICAgIFxuICAgIC8vIENoYWxsZW5nZSByb3VuZCA1OiB2XG4gICAgdHJhbnNjcmlwdC5yZXNldCgpO1xuICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHJlcy54aSk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZXZhbF9hKTtcbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5ldmFsX2IpO1xuICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHByb29mLmV2YWxfYyk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZXZhbF9zMSk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZXZhbF9zMik7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZXZhbF96dyk7XG4gICAgcmVzLnYgPSBbXTtcbiAgICByZXMudlsxXSA9IHRyYW5zY3JpcHQuZ2V0Q2hhbGxlbmdlKCk7XG5cbiAgICBmb3IgKGxldCBpPTI7IGk8NjsgaSsrICkgcmVzLnZbaV0gPSBGci5tdWwocmVzLnZbaS0xXSwgcmVzLnZbMV0pO1xuXG4gICAgLy8gQ2hhbGxlbmdlOiB1XG4gICAgdHJhbnNjcmlwdC5yZXNldCgpO1xuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5XeGkpO1xuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5XeGl3KTtcbiAgICByZXMudSA9IHRyYW5zY3JpcHQuZ2V0Q2hhbGxlbmdlKCk7XG5cbiAgICByZXR1cm4gcmVzO1xufVxuXG5mdW5jdGlvbiBjYWxjdWxhdGVMYWdyYW5nZUV2YWx1YXRpb25zKGN1cnZlLCBjaGFsbGVuZ2VzLCB2aykge1xuICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG5cbiAgICBsZXQgeGluID0gY2hhbGxlbmdlcy54aTtcbiAgICBsZXQgZG9tYWluU2l6ZSA9IDE7XG4gICAgZm9yIChsZXQgaT0wOyBpPHZrLnBvd2VyOyBpKyspIHtcbiAgICAgICAgeGluID0gRnIuc3F1YXJlKHhpbik7XG4gICAgICAgIGRvbWFpblNpemUgKj0gMjtcbiAgICB9XG4gICAgY2hhbGxlbmdlcy54aW4gPSB4aW47XG5cbiAgICBjaGFsbGVuZ2VzLnpoID0gRnIuc3ViKHhpbiwgRnIub25lKTtcblxuICAgIGNvbnN0IEwgPSBbXTtcblxuICAgIGNvbnN0IG4gPSBGci5lKGRvbWFpblNpemUpO1xuICAgIGxldCB3ID0gRnIub25lO1xuICAgIGZvciAobGV0IGk9MTsgaTw9TWF0aC5tYXgoMSwgdmsublB1YmxpYyk7IGkrKykge1xuICAgICAgICBMW2ldID0gRnIuZGl2KEZyLm11bCh3LCBjaGFsbGVuZ2VzLnpoKSwgRnIubXVsKG4sIEZyLnN1YihjaGFsbGVuZ2VzLnhpLCB3KSkpO1xuICAgICAgICB3ID0gRnIubXVsKHcsIEZyLndbdmsucG93ZXJdKTtcbiAgICB9XG5cbiAgICByZXR1cm4gTDtcbn1cblxuZnVuY3Rpb24gY2FsY3VsYXRlUEkoY3VydmUsIHB1YmxpY1NpZ25hbHMsIEwpIHtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuXG4gICAgbGV0IHBpID0gRnIuemVybztcbiAgICBmb3IgKGxldCBpPTA7IGk8cHVibGljU2lnbmFscy5sZW5ndGg7IGkrKykgeyAgICAgICAgXG4gICAgICAgIGNvbnN0IHcgPSBGci5lKHB1YmxpY1NpZ25hbHNbaV0pO1xuICAgICAgICBwaSA9IEZyLnN1YihwaSwgRnIubXVsKHcsIExbaSsxXSkpO1xuICAgIH1cbiAgICByZXR1cm4gcGk7XG59XG5cbmZ1bmN0aW9uIGNhbGN1bGF0ZVIwKGN1cnZlLCBwcm9vZiwgY2hhbGxlbmdlcywgcGksIGwxKSB7XG4gICAgY29uc3QgRnIgPSBjdXJ2ZS5GcjtcblxuICAgIGNvbnN0IGUxID0gcGk7XG5cbiAgICBjb25zdCBlMiA9IEZyLm11bChsMSwgRnIuc3F1YXJlKGNoYWxsZW5nZXMuYWxwaGEpKTtcblxuICAgIGxldCBlM2EgPSBGci5hZGQocHJvb2YuZXZhbF9hLCBGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCBwcm9vZi5ldmFsX3MxKSk7XG4gICAgZTNhID0gRnIuYWRkKGUzYSwgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICBsZXQgZTNiID0gRnIuYWRkKHByb29mLmV2YWxfYiwgRnIubXVsKGNoYWxsZW5nZXMuYmV0YSwgcHJvb2YuZXZhbF9zMikpO1xuICAgIGUzYiA9IEZyLmFkZChlM2IsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgbGV0IGUzYyA9IEZyLmFkZChwcm9vZi5ldmFsX2MsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgbGV0IGUzID0gRnIubXVsKEZyLm11bChlM2EsIGUzYiksIGUzYyk7XG4gICAgZTMgPSBGci5tdWwoZTMsIHByb29mLmV2YWxfencpO1xuICAgIGUzID0gRnIubXVsKGUzLCBjaGFsbGVuZ2VzLmFscGhhKTtcblxuICAgIGNvbnN0IHIwID0gRnIuc3ViKEZyLnN1YihlMSwgZTIpLCBlMyk7XG5cbiAgICByZXR1cm4gcjA7XG59XG5cbmZ1bmN0aW9uIGNhbGN1bGF0ZUQoY3VydmUsIHByb29mLCBjaGFsbGVuZ2VzLCB2aywgbDEpIHtcbiAgICBjb25zdCBHMSA9IGN1cnZlLkcxO1xuICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG4gICAgXG4gICAgbGV0IGQxID0gRzEudGltZXNGcih2ay5RbSwgRnIubXVsKHByb29mLmV2YWxfYSwgcHJvb2YuZXZhbF9iKSk7XG4gICAgZDEgPSBHMS5hZGQoZDEsIEcxLnRpbWVzRnIodmsuUWwsIHByb29mLmV2YWxfYSkpO1xuICAgIGQxID0gRzEuYWRkKGQxLCBHMS50aW1lc0ZyKHZrLlFyLCBwcm9vZi5ldmFsX2IpKTtcbiAgICBkMSA9IEcxLmFkZChkMSwgRzEudGltZXNGcih2ay5RbywgcHJvb2YuZXZhbF9jKSk7XG4gICAgZDEgPSBHMS5hZGQoZDEsIHZrLlFjKTtcblxuICAgIGNvbnN0IGJldGF4aSA9IEZyLm11bChjaGFsbGVuZ2VzLmJldGEsIGNoYWxsZW5nZXMueGkpO1xuXG4gICAgY29uc3QgZDJhMSA9IEZyLmFkZChGci5hZGQocHJvb2YuZXZhbF9hLCBiZXRheGkpLCBjaGFsbGVuZ2VzLmdhbW1hKTtcbiAgICBjb25zdCBkMmEyID0gRnIuYWRkKEZyLmFkZChwcm9vZi5ldmFsX2IsIEZyLm11bChiZXRheGksIHZrLmsxKSksIGNoYWxsZW5nZXMuZ2FtbWEpO1xuICAgIGNvbnN0IGQyYTMgPSBGci5hZGQoRnIuYWRkKHByb29mLmV2YWxfYywgRnIubXVsKGJldGF4aSwgdmsuazIpKSwgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICBjb25zdCBkMmEgPSBGci5tdWwoRnIubXVsKEZyLm11bChkMmExLCBkMmEyKSwgZDJhMyksIGNoYWxsZW5nZXMuYWxwaGEpO1xuXG4gICAgY29uc3QgZDJiID0gRnIubXVsKGwxLCBGci5zcXVhcmUoY2hhbGxlbmdlcy5hbHBoYSkpO1xuXG4gICAgY29uc3QgZDIgPSBHMS50aW1lc0ZyKHByb29mLlosIEZyLmFkZChGci5hZGQoZDJhLCBkMmIpLCBjaGFsbGVuZ2VzLnUpKTtcblxuICAgIGNvbnN0IGQzYSA9IEZyLmFkZChGci5hZGQocHJvb2YuZXZhbF9hLCBGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCBwcm9vZi5ldmFsX3MxKSksIGNoYWxsZW5nZXMuZ2FtbWEpO1xuICAgIGNvbnN0IGQzYiA9IEZyLmFkZChGci5hZGQocHJvb2YuZXZhbF9iLCBGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCBwcm9vZi5ldmFsX3MyKSksIGNoYWxsZW5nZXMuZ2FtbWEpO1xuICAgIGNvbnN0IGQzYyA9IEZyLm11bChGci5tdWwoY2hhbGxlbmdlcy5hbHBoYSwgY2hhbGxlbmdlcy5iZXRhKSwgcHJvb2YuZXZhbF96dyk7XG5cbiAgICBjb25zdCBkMyA9IEcxLnRpbWVzRnIodmsuUzMsIEZyLm11bChGci5tdWwoZDNhLCBkM2IpLCBkM2MpKTtcbiAgICBcbiAgICBjb25zdCBkNGxvdyA9IHByb29mLlQxO1xuICAgIGNvbnN0IGQ0bWlkID0gRzEudGltZXNGcihwcm9vZi5UMiwgY2hhbGxlbmdlcy54aW4pO1xuICAgIGNvbnN0IGQ0aGlnaCA9IEcxLnRpbWVzRnIocHJvb2YuVDMsIEZyLnNxdWFyZShjaGFsbGVuZ2VzLnhpbikpO1xuICAgIGxldCBkNCA9IEcxLmFkZChkNGxvdywgRzEuYWRkKGQ0bWlkLCBkNGhpZ2gpKTtcbiAgICBkNCA9IEcxLnRpbWVzRnIoZDQsIGNoYWxsZW5nZXMuemgpO1xuXG4gICAgY29uc3QgZCA9IEcxLnN1YihHMS5zdWIoRzEuYWRkKGQxLCBkMiksIGQzKSwgZDQpO1xuXG4gICAgcmV0dXJuIGQ7XG59XG5cbmZ1bmN0aW9uIGNhbGN1bGF0ZUYoY3VydmUsIHByb29mLCBjaGFsbGVuZ2VzLCB2aywgRCkge1xuICAgIGNvbnN0IEcxID0gY3VydmUuRzE7XG5cbiAgICBsZXQgcmVzID0gRzEuYWRkKEQsIEcxLnRpbWVzRnIocHJvb2YuQSwgY2hhbGxlbmdlcy52WzFdKSk7XG4gICAgcmVzID0gRzEuYWRkKHJlcywgRzEudGltZXNGcihwcm9vZi5CLCBjaGFsbGVuZ2VzLnZbMl0pKTtcbiAgICByZXMgPSBHMS5hZGQocmVzLCBHMS50aW1lc0ZyKHByb29mLkMsIGNoYWxsZW5nZXMudlszXSkpO1xuICAgIHJlcyA9IEcxLmFkZChyZXMsIEcxLnRpbWVzRnIodmsuUzEsIGNoYWxsZW5nZXMudls0XSkpO1xuICAgIHJlcyA9IEcxLmFkZChyZXMsIEcxLnRpbWVzRnIodmsuUzIsIGNoYWxsZW5nZXMudls1XSkpO1xuXG4gICAgcmV0dXJuIHJlcztcbn1cblxuZnVuY3Rpb24gY2FsY3VsYXRlRShjdXJ2ZSwgcHJvb2YsIGNoYWxsZW5nZXMsIHIwKSB7XG4gICAgY29uc3QgRzEgPSBjdXJ2ZS5HMTtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuXG4gICAgbGV0IGUgPSBGci5hZGQoRnIubmVnKHIwKSwgRnIubXVsKGNoYWxsZW5nZXMudlsxXSwgcHJvb2YuZXZhbF9hKSk7XG4gICAgZSA9IEZyLmFkZChlLCBGci5tdWwoY2hhbGxlbmdlcy52WzJdLCBwcm9vZi5ldmFsX2IpKTtcbiAgICBlID0gRnIuYWRkKGUsIEZyLm11bChjaGFsbGVuZ2VzLnZbM10sIHByb29mLmV2YWxfYykpO1xuICAgIGUgPSBGci5hZGQoZSwgRnIubXVsKGNoYWxsZW5nZXMudls0XSwgcHJvb2YuZXZhbF9zMSkpO1xuICAgIGUgPSBGci5hZGQoZSwgRnIubXVsKGNoYWxsZW5nZXMudls1XSwgcHJvb2YuZXZhbF9zMikpO1xuICAgIGUgPSBGci5hZGQoZSwgRnIubXVsKGNoYWxsZW5nZXMudSwgcHJvb2YuZXZhbF96dykpO1xuXG4gICAgY29uc3QgcmVzID0gRzEudGltZXNGcihHMS5vbmUsIGUpO1xuXG4gICAgcmV0dXJuIHJlcztcbn1cblxuYXN5bmMgZnVuY3Rpb24gaXNWYWxpZFBhaXJpbmcoY3VydmUsIHByb29mLCBjaGFsbGVuZ2VzLCB2aywgRSwgRikge1xuICAgIGNvbnN0IEcxID0gY3VydmUuRzE7XG4gICAgY29uc3QgRnIgPSBjdXJ2ZS5GcjtcblxuICAgIGxldCBBMSA9IHByb29mLld4aTtcbiAgICBBMSA9IEcxLmFkZChBMSwgRzEudGltZXNGcihwcm9vZi5XeGl3LCBjaGFsbGVuZ2VzLnUpKTtcblxuICAgIGxldCBCMSA9IEcxLnRpbWVzRnIocHJvb2YuV3hpLCBjaGFsbGVuZ2VzLnhpKTtcbiAgICBjb25zdCBzID0gRnIubXVsKEZyLm11bChjaGFsbGVuZ2VzLnUsIGNoYWxsZW5nZXMueGkpLCBGci53W3ZrLnBvd2VyXSk7XG4gICAgQjEgPSBHMS5hZGQoQjEsIEcxLnRpbWVzRnIocHJvb2YuV3hpdywgcykpO1xuICAgIEIxID0gRzEuYWRkKEIxLCBGKTtcbiAgICBCMSA9IEcxLnN1YihCMSwgRSk7XG5cbiAgICBjb25zdCByZXMgPSBhd2FpdCBjdXJ2ZS5wYWlyaW5nRXEoXG4gICAgICAgIEcxLm5lZyhBMSkgLCB2ay5YXzIsXG4gICAgICAgIEIxICwgY3VydmUuRzIub25lXG4gICAgKTtcblxuICAgIHJldHVybiByZXM7XG59XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDIxIDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgeyBnZXRDdXJ2ZUZyb21OYW1lIH0gZnJvbSBcIi4vY3VydmVzLmpzXCI7XG5pbXBvcnQgeyAgdXRpbHMgfSAgIGZyb20gXCJmZmphdmFzY3JpcHRcIjtcbmNvbnN0IHsgdW5zdHJpbmdpZnlCaWdJbnRzfSA9IHV0aWxzO1xuXG5mdW5jdGlvbiBwMjU2KG4pIHtcbiAgICBsZXQgbnN0ciA9IG4udG9TdHJpbmcoMTYpO1xuICAgIHdoaWxlIChuc3RyLmxlbmd0aCA8IDY0KSBuc3RyID0gXCIwXCIrbnN0cjtcbiAgICBuc3RyID0gYFwiMHgke25zdHJ9XCJgO1xuICAgIHJldHVybiBuc3RyO1xufVxuXG5leHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBwbG9ua0V4cG9ydFNvbGlkaXR5Q2FsbERhdGEoX3Byb29mLCBfcHViKSB7XG4gICAgY29uc3QgcHJvb2YgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX3Byb29mKTtcbiAgICBjb25zdCBwdWIgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX3B1Yik7XG5cbiAgICBhd2FpdCBnZXRDdXJ2ZUZyb21OYW1lKHByb29mLmN1cnZlKTtcblxuICAgIGxldCBpbnB1dHMgPSBcIlwiO1xuICAgIGZvciAobGV0IGk9MDsgaTxwdWIubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKGlucHV0cyAhPSBcIlwiKSBpbnB1dHMgPSBpbnB1dHMgKyBcIixcIjtcbiAgICAgICAgaW5wdXRzID0gaW5wdXRzICsgcDI1NihwdWJbaV0pO1xuICAgIH1cblxuICAgIHJldHVybiBgWyR7cDI1Nihwcm9vZi5BWzBdKX0sICR7cDI1Nihwcm9vZi5BWzFdKX0sYCArXG4gICAgYCR7cDI1Nihwcm9vZi5CWzBdKX0sJHtwMjU2KHByb29mLkJbMV0pfSxgICtcbiAgICBgJHtwMjU2KHByb29mLkNbMF0pfSwke3AyNTYocHJvb2YuQ1sxXSl9LGAgK1xuICAgIGAke3AyNTYocHJvb2YuWlswXSl9LCR7cDI1Nihwcm9vZi5aWzFdKX0sYCArXG4gICAgYCR7cDI1Nihwcm9vZi5UMVswXSl9LCR7cDI1Nihwcm9vZi5UMVsxXSl9LGAgK1xuICAgIGAke3AyNTYocHJvb2YuVDJbMF0pfSwke3AyNTYocHJvb2YuVDJbMV0pfSxgICtcbiAgICBgJHtwMjU2KHByb29mLlQzWzBdKX0sJHtwMjU2KHByb29mLlQzWzFdKX0sYCArXG4gICAgYCR7cDI1Nihwcm9vZi5XeGlbMF0pfSwke3AyNTYocHJvb2YuV3hpWzFdKX0sYCArXG4gICAgYCR7cDI1Nihwcm9vZi5XeGl3WzBdKX0sJHtwMjU2KHByb29mLld4aXdbMV0pfSxgICtcbiAgICBgJHtwMjU2KHByb29mLmV2YWxfYSl9LGAgKyBcbiAgICBgJHtwMjU2KHByb29mLmV2YWxfYil9LGAgKyBcbiAgICBgJHtwMjU2KHByb29mLmV2YWxfYyl9LGAgKyBcbiAgICBgJHtwMjU2KHByb29mLmV2YWxfczEpfSxgICsgXG4gICAgYCR7cDI1Nihwcm9vZi5ldmFsX3MyKX0sYCArIFxuICAgIGAke3AyNTYocHJvb2YuZXZhbF96dyl9XWAgKyBcbiAgICBgWyR7aW5wdXRzfV1gO1xufVxuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAxOCAwS0lNUyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJrSlMuXG5cbiAgICBzbmFya0pTIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdFxuICAgIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtKUyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVFxuICAgIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpY1xuICAgIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBzbmFya0pTLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuLy8gWktFWSBjb25zdGFudHNcbmV4cG9ydCB7ZGVmYXVsdCBhcyBzZXR1cH0gZnJvbSBcIi4vcGxvbmtfc2V0dXAuanNcIjtcbmV4cG9ydCB7ZGVmYXVsdCBhcyBmdWxsUHJvdmV9IGZyb20gXCIuL3Bsb25rX2Z1bGxwcm92ZS5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIHByb3ZlfSBmcm9tIFwiLi9wbG9ua19wcm92ZS5qc1wiO1xuZXhwb3J0IHtkZWZhdWx0IGFzIHZlcmlmeX0gZnJvbSBcIi4vcGxvbmtfdmVyaWZ5LmpzXCI7XG5leHBvcnQge2RlZmF1bHQgYXMgZXhwb3J0U29saWRpdHlDYWxsRGF0YX0gZnJvbSBcIi4vcGxvbmtfZXhwb3J0c29saWRpdHljYWxsZGF0YS5qc1wiO1xuIiwiLypcbiAgICBDb3B5cmlnaHQgMjAyMiBpZGVuMyBhc3NvY2lhdGlvbi5cblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHNuYXJranMuXG5cbiAgICBzbmFya2pzIGlzIGEgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4gICAgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZVxuICAgIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKVxuICAgIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgc25hcmtqcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWVxuICAgIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvclxuICAgIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGhcbiAgICBzbmFya2pzLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cblxuLy8gV2UgZXhwb3J0IHRvIHprZXkgdGhlIHNpZ25hbHMgYW5kIHZhbHVlcyBvZiB0aGUgYSwgYiwgYywgcWwsIHFyLCBxbSwgcW8gYW5kIHFjXG5cbi8vIGEsIGIgYW5kIGMgYXJlIHNpZ25hbHMgaWQgKDMyLWJpdCBpbnRlZ2Vycylcbi8vIHFsLCBxciwgcW0sIHFvIGFuZCBxYyBhcmUgZmllbGQgdmFsdWVzXG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRGRmxvbmtDb25zdGFudENvbnN0cmFpbnQoc2lnbmFsMSwgRnIpIHtcbiAgICByZXR1cm4gW3NpZ25hbDEsIDAsIDAsIEZyLm9uZSwgRnIuemVybywgRnIuemVybywgRnIuemVybywgRnIuemVyb107XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRGRmxvbmtBZGRpdGlvbkNvbnN0cmFpbnQoc2lnbmFsMSwgc2lnbmFsMiwgc2lnbmFsT3V0LCBxbCwgcXIsIHFtLCBxbywgcWMpIHtcbiAgICByZXR1cm4gW3NpZ25hbDEsIHNpZ25hbDIsIHNpZ25hbE91dCwgcWwsIHFyLCBxbSwgcW8sIHFjXTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEZGbG9ua011bHRpcGxpY2F0aW9uQ29uc3RyYWludChzaWduYWwxLCBzaWduYWwyLCBzaWduYWxPdXQsIHFsLCBxciwgcW0sIHFvLCBxYywgRnIpIHtcbiAgICByZXR1cm4gW3NpZ25hbDEsIHNpZ25hbDIsIHNpZ25hbE91dCwgcWwsIHFyLCBxbSwgcW8sIHFjXTtcbn1cbiIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMjIgaWRlbjMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya2pzLlxuXG4gICAgc25hcmtqcyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuICAgIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGVcbiAgICBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbilcbiAgICBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJranMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3JcbiAgICBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoXG4gICAgc25hcmtqcy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmNvbnN0IExJTkVBUl9DT01CSU5BVElPTl9OVUxMQUJMRSA9IDA7XG5jb25zdCBMSU5FQVJfQ09NQklOQVRJT05fQ09OU1RBTlQgPSAxO1xuY29uc3QgTElORUFSX0NPTUJJTkFUSU9OX1ZBUklBQkxFID0gMjtcblxuZXhwb3J0IGNsYXNzIHIxY3NDb25zdHJhaW50UHJvY2Vzc29yIHtcbiAgICBjb25zdHJ1Y3RvcihGciwgZm5HZXRDb25zdGFudENvbnN0cmFpbnQsIGZuR2V0QWRkaXRpb25Db25zdHJhaW50LCBmbkdldE11bHRpcGxpY2F0aW9uQ29uc3RyYWludCwgbG9nZ2VyKSB7XG4gICAgICAgIHRoaXMuRnIgPSBGcjtcbiAgICAgICAgdGhpcy5sb2dnZXIgPSBsb2dnZXI7XG4gICAgICAgIHRoaXMuZm5HZXRBZGRpdGlvbkNvbnN0cmFpbnQgPSBmbkdldEFkZGl0aW9uQ29uc3RyYWludDtcbiAgICAgICAgdGhpcy5mbkdldE11bHRpcGxpY2F0aW9uQ29uc3RyYWludCA9IGZuR2V0TXVsdGlwbGljYXRpb25Db25zdHJhaW50O1xuICAgIH1cblxuICAgIHByb2Nlc3NSMWNzQ29uc3RyYWludChzZXR0aW5ncywgbGNBLCBsY0IsIGxjQykge1xuICAgICAgICB0aGlzLm5vcm1hbGl6ZUxpbmVhckNvbWJpbmF0aW9uKGxjQSk7XG4gICAgICAgIHRoaXMubm9ybWFsaXplTGluZWFyQ29tYmluYXRpb24obGNCKTtcbiAgICAgICAgdGhpcy5ub3JtYWxpemVMaW5lYXJDb21iaW5hdGlvbihsY0MpO1xuXG4gICAgICAgIGNvbnN0IGxjdEEgPSB0aGlzLmdldExpbmVhckNvbWJpbmF0aW9uVHlwZShsY0EpO1xuICAgICAgICBjb25zdCBsY3RCID0gdGhpcy5nZXRMaW5lYXJDb21iaW5hdGlvblR5cGUobGNCKTtcblxuICAgICAgICBpZiAoKGxjdEEgPT09IExJTkVBUl9DT01CSU5BVElPTl9OVUxMQUJMRSkgfHwgKGxjdEIgPT09IExJTkVBUl9DT01CSU5BVElPTl9OVUxMQUJMRSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnByb2Nlc3NSMWNzQWRkaXRpb25Db25zdHJhaW50KHNldHRpbmdzLCBsY0MpO1xuICAgICAgICB9IGVsc2UgaWYgKGxjdEEgPT09IExJTkVBUl9DT01CSU5BVElPTl9DT05TVEFOVCkge1xuICAgICAgICAgICAgY29uc3QgbGNDQyA9IHRoaXMuam9pbkxpbmVhckNvbWJpbmF0aW9ucyhsY0IsIGxjQywgbGNBWzBdKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnByb2Nlc3NSMWNzQWRkaXRpb25Db25zdHJhaW50KHNldHRpbmdzLCBsY0NDKTtcbiAgICAgICAgfSBlbHNlIGlmIChsY3RCID09PSBMSU5FQVJfQ09NQklOQVRJT05fQ09OU1RBTlQpIHtcbiAgICAgICAgICAgIGNvbnN0IGxjQ0MgPSB0aGlzLmpvaW5MaW5lYXJDb21iaW5hdGlvbnMobGNBLCBsY0MsIGxjQlswXSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wcm9jZXNzUjFjc0FkZGl0aW9uQ29uc3RyYWludChzZXR0aW5ncywgbGNDQyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wcm9jZXNzUjFjc011bHRpcGxpY2F0aW9uQ29uc3RyYWludChzZXR0aW5ncywgbGNBLCBsY0IsIGxjQyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBnZXRMaW5lYXJDb21iaW5hdGlvblR5cGUobGluQ29tKSB7XG4gICAgICAgIC8vIGxldCBrID0gdGhpcy5Gci56ZXJvO1xuICAgICAgICAvL1xuICAgICAgICAvLyBjb25zdCBzaWduYWxJZHMgPSBPYmplY3Qua2V5cyhsaW5Db20pO1xuICAgICAgICAvLyBmb3IgKGxldCBpID0gMDsgaSA8IHNpZ25hbElkcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAvLyAgICAgaWYgKHNpZ25hbElkc1tpXSA9PT0gXCIwXCIpIHtcbiAgICAgICAgLy8gICAgICAgICBrID0gdGhpcy5Gci5hZGQoaywgbGluQ29tW3NpZ25hbElkc1tpXV0pO1xuICAgICAgICAvLyAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gICAgICAgICByZXR1cm4gTElORUFSX0NPTUJJTkFUSU9OX1ZBUklBQkxFO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyB9XG4gICAgICAgIC8vXG4gICAgICAgIC8vIGlmICghdGhpcy5Gci5lcShrLCB0aGlzLkZyLnplcm8pKSByZXR1cm4gTElORUFSX0NPTUJJTkFUSU9OX0NPTlNUQU5UO1xuICAgICAgICAvL1xuICAgICAgICAvLyByZXR1cm4gTElORUFSX0NPTUJJTkFUSU9OX05VTExBQkxFO1xuXG4gICAgICAgIGxldCBrID0gdGhpcy5Gci56ZXJvO1xuICAgICAgICBsZXQgbiA9IDA7XG4gICAgICAgIGNvbnN0IHNzID0gT2JqZWN0LmtleXMobGluQ29tKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKGxpbkNvbVtzc1tpXV0gPT0gMG4pIHtcbiAgICAgICAgICAgICAgICBkZWxldGUgbGluQ29tW3NzW2ldXTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoc3NbaV0gPT0gMCkge1xuICAgICAgICAgICAgICAgIGsgPSB0aGlzLkZyLmFkZChrLCBsaW5Db21bc3NbaV1dKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbisrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChuID4gMCkgcmV0dXJuIExJTkVBUl9DT01CSU5BVElPTl9WQVJJQUJMRTtcbiAgICAgICAgaWYgKCF0aGlzLkZyLmlzWmVybyhrKSkgcmV0dXJuIExJTkVBUl9DT01CSU5BVElPTl9DT05TVEFOVDtcbiAgICAgICAgcmV0dXJuIExJTkVBUl9DT01CSU5BVElPTl9OVUxMQUJMRTtcbiAgICB9XG5cbiAgICBub3JtYWxpemVMaW5lYXJDb21iaW5hdGlvbihsaW5Db20pIHtcbiAgICAgICAgY29uc3Qgc2lnbmFsSWRzID0gT2JqZWN0LmtleXMobGluQ29tKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzaWduYWxJZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmICh0aGlzLkZyLmlzWmVybyhsaW5Db21bc2lnbmFsSWRzW2ldXSkpIGRlbGV0ZSBsaW5Db21bc2lnbmFsSWRzW2ldXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBsaW5Db207XG4gICAgfVxuXG4gICAgam9pbkxpbmVhckNvbWJpbmF0aW9ucyhsaW5Db20xLCBsaW5Db20yLCBrKSB7XG4gICAgICAgIGNvbnN0IHJlcyA9IHt9O1xuXG4gICAgICAgIC8vIGZvciAobGV0IHMgaW4gbGluQ29tMSkge1xuICAgICAgICAvLyAgICAgY29uc3QgdmFsID0gdGhpcy5Gci5tdWwoaywgbGluQ29tMVtzXSk7XG4gICAgICAgIC8vICAgICByZXNbc10gPSAhKHMgaW4gcmVzKSA/IHZhbCA6IHRoaXMuRnIuYWRkKHZhbCwgcmVzW3NdKTtcbiAgICAgICAgLy8gfVxuICAgICAgICAvL1xuICAgICAgICAvLyBmb3IgKGxldCBzIGluIGxpbkNvbTIpIHtcbiAgICAgICAgLy8gICAgIGNvbnN0IHZhbCA9IHRoaXMuRnIubXVsKGssIGxpbkNvbTJbc10pO1xuICAgICAgICAvLyAgICAgcmVzW3NdID0gIShzIGluIHJlcykgPyB2YWwgOiB0aGlzLkZyLmFkZCh2YWwsIHJlc1tzXSk7XG4gICAgICAgIC8vIH1cblxuICAgICAgICBmb3IgKGxldCBzIGluIGxpbkNvbTEpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcmVzW3NdID09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICByZXNbc10gPSB0aGlzLkZyLm11bChrLCBsaW5Db20xW3NdKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVzW3NdID0gdGhpcy5Gci5hZGQocmVzW3NdLCB0aGlzLkZyLm11bChrLCBsaW5Db20xW3NdKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGxldCBzIGluIGxpbkNvbTIpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcmVzW3NdID09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICByZXNbc10gPSBsaW5Db20yW3NdO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXNbc10gPSB0aGlzLkZyLmFkZChyZXNbc10sIGxpbkNvbTJbc10pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMubm9ybWFsaXplTGluZWFyQ29tYmluYXRpb24ocmVzKTtcbiAgICB9XG5cbiAgICByZWR1Y2VDb2VmcyhzZXR0aW5ncywgY29uc3RyYWludHNBcnIsIGFkZGl0aW9uc0FyciwgbGluQ29tLCBtYXhDKSB7XG4gICAgICAgIGNvbnN0IHJlcyA9IHtcbiAgICAgICAgICAgIGs6IHRoaXMuRnIuemVybyxcbiAgICAgICAgICAgIHNpZ25hbHM6IFtdLFxuICAgICAgICAgICAgY29lZnM6IFtdXG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IGNzID0gW107XG5cbiAgICAgICAgZm9yIChsZXQgc2lnbmFsSWQgaW4gbGluQ29tKSB7XG4gICAgICAgICAgICBpZiAoc2lnbmFsSWQgPT0gMCkge1xuICAgICAgICAgICAgICAgIHJlcy5rID0gdGhpcy5Gci5hZGQocmVzLmssIGxpbkNvbVtzaWduYWxJZF0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChsaW5Db21bc2lnbmFsSWRdICE9IDBuKSB7XG4gICAgICAgICAgICAgICAgY3MucHVzaChbTnVtYmVyKHNpZ25hbElkKSwgbGluQ29tW3NpZ25hbElkXV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgd2hpbGUgKGNzLmxlbmd0aCA+IG1heEMpIHtcbiAgICAgICAgICAgIGNvbnN0IGMxID0gY3Muc2hpZnQoKTtcbiAgICAgICAgICAgIGNvbnN0IGMyID0gY3Muc2hpZnQoKTtcbiAgICAgICAgICAgIGNvbnN0IHNvID0gc2V0dGluZ3MublZhcnMrKztcblxuICAgICAgICAgICAgY29uc3QgY29uc3RyYWludHMgPSB0aGlzLmZuR2V0QWRkaXRpb25Db25zdHJhaW50KFxuICAgICAgICAgICAgICAgIGMxWzBdLCBjMlswXSwgc28sXG4gICAgICAgICAgICAgICAgdGhpcy5Gci5uZWcoYzFbMV0pLCB0aGlzLkZyLm5lZyhjMlsxXSksIHRoaXMuRnIuemVybywgdGhpcy5Gci5vbmUsIHRoaXMuRnIuemVybyk7XG5cbiAgICAgICAgICAgIGNvbnN0cmFpbnRzQXJyLnB1c2goY29uc3RyYWludHMpO1xuICAgICAgICAgICAgYWRkaXRpb25zQXJyLnB1c2goW2MxWzBdLCBjMlswXSwgYzFbMV0sIGMyWzFdXSk7XG5cbiAgICAgICAgICAgIGNzLnB1c2goW3NvLCB0aGlzLkZyLm9uZV0pO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgcmVzLnNpZ25hbHNbaV0gPSBjc1tpXVswXTtcbiAgICAgICAgICAgIHJlcy5jb2Vmc1tpXSA9IGNzW2ldWzFdO1xuICAgICAgICB9XG5cbiAgICAgICAgd2hpbGUgKHJlcy5jb2Vmcy5sZW5ndGggPCBtYXhDKSB7XG4gICAgICAgICAgICByZXMuc2lnbmFscy5wdXNoKDApO1xuICAgICAgICAgICAgcmVzLmNvZWZzLnB1c2godGhpcy5Gci56ZXJvKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgcHJvY2Vzc1IxY3NBZGRpdGlvbkNvbnN0cmFpbnQoc2V0dGluZ3MsIGxpbkNvbSkge1xuICAgICAgICBjb25zdCBjb25zdHJhaW50c0FyciA9IFtdO1xuICAgICAgICBjb25zdCBhZGRpdGlvbnNBcnIgPSBbXTtcblxuICAgICAgICBjb25zdCBDID0gdGhpcy5yZWR1Y2VDb2VmcyhzZXR0aW5ncywgY29uc3RyYWludHNBcnIsIGFkZGl0aW9uc0FyciwgbGluQ29tLCAzKTtcblxuICAgICAgICBjb25zdCBjb25zdHJhaW50cyA9IHRoaXMuZm5HZXRBZGRpdGlvbkNvbnN0cmFpbnQoXG4gICAgICAgICAgICBDLnNpZ25hbHNbMF0sIEMuc2lnbmFsc1sxXSwgQy5zaWduYWxzWzJdLFxuICAgICAgICAgICAgQy5jb2Vmc1swXSwgQy5jb2Vmc1sxXSwgdGhpcy5Gci56ZXJvLCBDLmNvZWZzWzJdLCBDLmspO1xuXG4gICAgICAgIGNvbnN0cmFpbnRzQXJyLnB1c2goY29uc3RyYWludHMpO1xuXG4gICAgICAgIHJldHVybiBbY29uc3RyYWludHNBcnIsIGFkZGl0aW9uc0Fycl07XG4gICAgfVxuXG4gICAgcHJvY2Vzc1IxY3NNdWx0aXBsaWNhdGlvbkNvbnN0cmFpbnQoc2V0dGluZ3MsIGxjQSwgbGNCLCBsY0MpIHtcbiAgICAgICAgY29uc3QgY29uc3RyYWludHNBcnIgPSBbXTtcbiAgICAgICAgY29uc3QgYWRkaXRpb25zQXJyID0gW107XG5cbiAgICAgICAgY29uc3QgQSA9IHRoaXMucmVkdWNlQ29lZnMoc2V0dGluZ3MsIGNvbnN0cmFpbnRzQXJyLCBhZGRpdGlvbnNBcnIsIGxjQSwgMSk7XG4gICAgICAgIGNvbnN0IEIgPSB0aGlzLnJlZHVjZUNvZWZzKHNldHRpbmdzLCBjb25zdHJhaW50c0FyciwgYWRkaXRpb25zQXJyLCBsY0IsIDEpO1xuICAgICAgICBjb25zdCBDID0gdGhpcy5yZWR1Y2VDb2VmcyhzZXR0aW5ncywgY29uc3RyYWludHNBcnIsIGFkZGl0aW9uc0FyciwgbGNDLCAxKTtcblxuICAgICAgICBjb25zdCBjb25zdHJhaW50cyA9IHRoaXMuZm5HZXRNdWx0aXBsaWNhdGlvbkNvbnN0cmFpbnQoXG4gICAgICAgICAgICBBLnNpZ25hbHNbMF0sIEIuc2lnbmFsc1swXSwgQy5zaWduYWxzWzBdLFxuICAgICAgICAgICAgdGhpcy5Gci5tdWwoQS5jb2Vmc1swXSwgQi5rKSxcbiAgICAgICAgICAgIHRoaXMuRnIubXVsKEEuaywgQi5jb2Vmc1swXSksXG4gICAgICAgICAgICB0aGlzLkZyLm11bChBLmNvZWZzWzBdLCBCLmNvZWZzWzBdKSxcbiAgICAgICAgICAgIHRoaXMuRnIubmVnKEMuY29lZnNbMF0pLFxuICAgICAgICAgICAgdGhpcy5Gci5zdWIodGhpcy5Gci5tdWwoQS5rLCBCLmspLCBDLmspKTtcblxuICAgICAgICBjb25zdHJhaW50c0Fyci5wdXNoKGNvbnN0cmFpbnRzKTtcblxuICAgICAgICByZXR1cm4gW2NvbnN0cmFpbnRzQXJyLCBhZGRpdGlvbnNBcnJdO1xuICAgIH1cbn0iLCIvKlxuICAgIENvcHlyaWdodCAyMDIyIGlkZW4zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG4vLyBDUG9seW5vbWlhbCBpcyBhIENvbWJpbmVkIFBvbHlub21pYWwgb2YgdGhlIHR5cGUgOlxuLy8gQ1BvbHlub21pYWwoWCkgOj0gUF8wKFhebikgKyBYwrdQXzEoWF5uKSArIC4uLiArIFhee24tMX3Ct1Bfe24tMX0oWF5uKVxuLy8gV2UgY2FuIHVzZSB0aGlzIGNsYXNzIHRvIGF2b2lkIHRoZSBhbGxvY2F0aW9uIG9mIGEgYmlnIG1lbW9yeSBidWZmZXJcbi8vIGZvciB0aGUgY29lZmZpY2llbnRzIGJlY2F1c2UgaW4gc29tZSBjYXNlcyBhIGJpZyBudW1iZXIgb2YgdGhlIGNvZWZmaWNpZW50cyBhcmUgemVyb1xuXG5pbXBvcnQge0JpZ0J1ZmZlcn0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuaW1wb3J0IHtsb2cyfSBmcm9tIFwiLi4vbWlzYy5qc1wiO1xuaW1wb3J0IHtQb2x5bm9taWFsfSBmcm9tIFwiLi9wb2x5bm9taWFsLmpzXCI7XG5cbmV4cG9ydCBjbGFzcyBDUG9seW5vbWlhbCB7XG4gICAgY29uc3RydWN0b3IobiwgY3VydmUsIGxvZ2dlcikge1xuICAgICAgICB0aGlzLm4gPSBuO1xuICAgICAgICB0aGlzLnBvbHlub21pYWxzID0gQXJyYXkobikuZmlsbCh1bmRlZmluZWQpO1xuICAgICAgICB0aGlzLmN1cnZlID0gY3VydmU7XG4gICAgICAgIHRoaXMuRnIgPSBjdXJ2ZS5GcjtcbiAgICAgICAgdGhpcy5HMSA9IGN1cnZlLkcxO1xuICAgICAgICB0aGlzLmxvZ2dlciA9IGxvZ2dlcjtcbiAgICB9XG5cbiAgICBhZGRQb2x5bm9taWFsKHBvc2l0aW9uLCBwb2x5bm9taWFsKSB7XG4gICAgICAgIGlmIChwb3NpdGlvbiA+IHRoaXMubiAtIDEpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNQb2x5bm9taWFsOmFkZFBvbHlub21pYWwsIGNhbm5vdCBhZGQgYSBwb2x5bm9taWFsIHRvIGEgcG9zaXRpb24gZ3JlYXRlciB0aGFuIG4tMVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucG9seW5vbWlhbHNbcG9zaXRpb25dID0gcG9seW5vbWlhbDtcbiAgICB9XG5cbiAgICBkZWdyZWUoKSB7XG4gICAgICAgIGxldCBkZWdyZWVzID0gdGhpcy5wb2x5bm9taWFscy5tYXAoXG4gICAgICAgICAgICAocG9seW5vbWlhbCwgaW5kZXgpID0+IHBvbHlub21pYWwgPT09IHVuZGVmaW5lZCA/IDAgOiBwb2x5bm9taWFsLmRlZ3JlZSgpICogdGhpcy5uICsgaW5kZXgpO1xuICAgICAgICByZXR1cm4gTWF0aC5tYXgoLi4uZGVncmVlcyk7XG4gICAgfVxuXG4gICAgZ2V0UG9seW5vbWlhbCgpIHtcbiAgICAgICAgbGV0IGRlZ3JlZXMgPSB0aGlzLnBvbHlub21pYWxzLm1hcChwb2x5bm9taWFsID0+IHBvbHlub21pYWwgPT09IHVuZGVmaW5lZCA/IDAgOiBwb2x5bm9taWFsLmRlZ3JlZSgpKTtcbiAgICAgICAgY29uc3QgbWF4RGVncmVlID0gdGhpcy5kZWdyZWUoKTtcbiAgICAgICAgY29uc3QgbGVuZ3RoQnVmZmVyID0gMiAqKiAobG9nMihtYXhEZWdyZWUgLSAxKSArIDEpO1xuICAgICAgICBjb25zdCBzRnIgPSB0aGlzLkZyLm44O1xuXG4gICAgICAgIGxldCBwb2x5bm9taWFsID0gbmV3IFBvbHlub21pYWwobmV3IEJpZ0J1ZmZlcihsZW5ndGhCdWZmZXIgKiBzRnIpLCB0aGlzLmN1cnZlLCB0aGlzLmxvZ2dlcik7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtYXhEZWdyZWU7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgaV9uOCA9IGkgKiBzRnI7XG4gICAgICAgICAgICBjb25zdCBpX3NGciA9IGlfbjggKiB0aGlzLm47XG5cbiAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5uOyBqKyspIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5wb2x5bm9taWFsc1tqXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpIDw9IGRlZ3JlZXNbal0pIHBvbHlub21pYWwuY29lZi5zZXQodGhpcy5wb2x5bm9taWFsc1tqXS5jb2VmLnNsaWNlKGlfbjgsIGlfbjggKyBzRnIpLCBpX3NGciArIGogKiBzRnIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBwb2x5bm9taWFsO1xuICAgIH1cblxuICAgIGFzeW5jIG11bHRpRXhwb25lbnRpYXRpb24oUFRhdSwgbmFtZSkge1xuICAgICAgICBsZXQgcG9seW5vbWlhbCA9IHRoaXMuZ2V0UG9seW5vbWlhbCgpO1xuICAgICAgICBjb25zdCBuID0gcG9seW5vbWlhbC5jb2VmLmJ5dGVMZW5ndGggLyB0aGlzLkZyLm44O1xuICAgICAgICBjb25zdCBQVGF1TiA9IFBUYXUuc2xpY2UoMCwgbiAqIHRoaXMuRzEuRi5uOCAqIDIpO1xuICAgICAgICBjb25zdCBibSA9IGF3YWl0IHRoaXMuRnIuYmF0Y2hGcm9tTW9udGdvbWVyeShwb2x5bm9taWFsLmNvZWYpO1xuICAgICAgICBsZXQgcmVzID0gYXdhaXQgdGhpcy5HMS5tdWx0aUV4cEFmZmluZShQVGF1TiwgYm0sIHRoaXMubG9nZ2VyLCBuYW1lKTtcbiAgICAgICAgcmVzID0gdGhpcy5HMS50b0FmZmluZShyZXMpO1xuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cbn0iLCIvKlxuICAgIENvcHlyaWdodCAyMDIyIGlkZW4zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQge3JlYWRSMWNzRmR9IGZyb20gXCJyMWNzZmlsZVwiO1xuaW1wb3J0ICogYXMgdXRpbHMgZnJvbSBcIi4vcG93ZXJzb2Z0YXVfdXRpbHMuanNcIjtcbmltcG9ydCB7Y3JlYXRlQmluRmlsZSwgZW5kV3JpdGVTZWN0aW9uLCByZWFkQmluRmlsZSwgc3RhcnRXcml0ZVNlY3Rpb24sIHdyaXRlQmlnSW50LH0gZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCB7bG9nMn0gZnJvbSBcIi4vbWlzYy5qc1wiO1xuaW1wb3J0IHtCaWdCdWZmZXIsIFNjYWxhcn0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuaW1wb3J0IEJpZ0FycmF5IGZyb20gXCIuL2JpZ2FycmF5LmpzXCI7XG5pbXBvcnQge1xuICAgIFpLRVlfRkZfSEVBREVSX1NFQ1RJT04sXG4gICAgWktFWV9GRl9BRERJVElPTlNfU0VDVElPTixcbiAgICBaS0VZX0ZGX0FfTUFQX1NFQ1RJT04sXG4gICAgWktFWV9GRl9CX01BUF9TRUNUSU9OLFxuICAgIFpLRVlfRkZfQ19NQVBfU0VDVElPTixcbiAgICBaS0VZX0ZGX1FMX1NFQ1RJT04sXG4gICAgWktFWV9GRl9RUl9TRUNUSU9OLFxuICAgIFpLRVlfRkZfUU1fU0VDVElPTixcbiAgICBaS0VZX0ZGX1FPX1NFQ1RJT04sXG4gICAgWktFWV9GRl9RQ19TRUNUSU9OLFxuICAgIFpLRVlfRkZfU0lHTUExX1NFQ1RJT04sXG4gICAgWktFWV9GRl9TSUdNQTJfU0VDVElPTixcbiAgICBaS0VZX0ZGX1NJR01BM19TRUNUSU9OLFxuICAgIFpLRVlfRkZfTEFHUkFOR0VfU0VDVElPTixcbiAgICBaS0VZX0ZGX1BUQVVfU0VDVElPTixcbiAgICBGRl9UX1BPTF9ERUdfTUlOLFxuICAgIFpLRVlfRkZfTlNFQ1RJT05TLFxuICAgIFpLRVlfRkZfQzBfU0VDVElPTixcbn0gZnJvbSBcIi4vZmZsb25rX2NvbnN0YW50cy5qc1wiO1xuaW1wb3J0IHtGRkxPTktfUFJPVE9DT0xfSUQsIEhFQURFUl9aS0VZX1NFQ1RJT059IGZyb20gXCIuL3prZXlfY29uc3RhbnRzLmpzXCI7XG5pbXBvcnQge1xuICAgIGdldEZGbG9ua0FkZGl0aW9uQ29uc3RyYWludCxcbiAgICBnZXRGRmxvbmtDb25zdGFudENvbnN0cmFpbnQsXG4gICAgZ2V0RkZsb25rTXVsdGlwbGljYXRpb25Db25zdHJhaW50XG59IGZyb20gXCIuL3Bsb25rX2VxdWF0aW9uLmpzXCI7XG5pbXBvcnQge3IxY3NDb25zdHJhaW50UHJvY2Vzc29yfSBmcm9tIFwiLi9yMWNzX2NvbnN0cmFpbnRfcHJvY2Vzc29yLmpzXCI7XG5pbXBvcnQge1BvbHlub21pYWx9IGZyb20gXCIuL3BvbHlub21pYWwvcG9seW5vbWlhbC5qc1wiO1xuaW1wb3J0ICogYXMgYmluRmlsZVV0aWxzIGZyb20gXCJAaWRlbjMvYmluZmlsZXV0aWxzXCI7XG5pbXBvcnQge0V2YWx1YXRpb25zfSBmcm9tIFwiLi9wb2x5bm9taWFsL2V2YWx1YXRpb25zLmpzXCI7XG5pbXBvcnQge0NQb2x5bm9taWFsfSBmcm9tIFwiLi9wb2x5bm9taWFsL2Nwb2x5bm9taWFsLmpzXCI7XG5cblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gZmZsb25rU2V0dXAocjFjc0ZpbGVuYW1lLCBwdGF1RmlsZW5hbWUsIHprZXlGaWxlbmFtZSwgbG9nZ2VyKSB7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJGRkxPTksgU0VUVVAgU1RBUlRFRFwiKTtcblxuICAgIGlmIChnbG9iYWxUaGlzLmdjKSBnbG9iYWxUaGlzLmdjKCk7XG5cbiAgICAvLyBSZWFkIFBUYXUgZmlsZVxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBSZWFkaW5nIFBUYXUgZmlsZVwiKTtcbiAgICBjb25zdCB7ZmQ6IGZkUFRhdSwgc2VjdGlvbnM6IHBUYXVTZWN0aW9uc30gPSBhd2FpdCByZWFkQmluRmlsZShwdGF1RmlsZW5hbWUsIFwicHRhdVwiLCAxLCAxIDw8IDIyLCAxIDw8IDI0KTtcbiAgICBpZiAoIXBUYXVTZWN0aW9uc1sxMl0pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUG93ZXJzIG9mIFRhdSBpcyBub3Qgd2VsbCBwcmVwYXJlZC4gU2VjdGlvbiAxMiBtaXNzaW5nLlwiKTtcbiAgICB9XG5cbiAgICAvLyBHZXQgY3VydmUgZGVmaW5lZCBpbiBQVGF1XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IEdldHRpbmcgY3VydmUgZnJvbSBQVGF1IHNldHRpbmdzXCIpO1xuICAgIGNvbnN0IHtjdXJ2ZX0gPSBhd2FpdCB1dGlscy5yZWFkUFRhdUhlYWRlcihmZFBUYXUsIHBUYXVTZWN0aW9ucyk7XG5cbiAgICAvLyBSZWFkIHIxY3MgZmlsZVxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBSZWFkaW5nIHIxY3MgZmlsZVwiKTtcbiAgICBjb25zdCB7ZmQ6IGZkUjFjcywgc2VjdGlvbnM6IHNlY3Rpb25zUjFjc30gPSBhd2FpdCByZWFkQmluRmlsZShyMWNzRmlsZW5hbWUsIFwicjFjc1wiLCAxLCAxIDw8IDIyLCAxIDw8IDI0KTtcbiAgICBjb25zdCByMWNzID0gYXdhaXQgcmVhZFIxY3NGZChmZFIxY3MsIHNlY3Rpb25zUjFjcywge2xvYWRDb25zdHJhaW50czogZmFsc2UsIGxvYWRDdXN0b21HYXRlczogdHJ1ZX0pO1xuXG4gICAgLy8gUG90ZW50aWFsIGVycm9yIGNoZWNrc1xuICAgIGlmIChyMWNzLnByaW1lICE9PSBjdXJ2ZS5yKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcInIxY3MgY3VydmUgZG9lcyBub3QgbWF0Y2ggcG93ZXJzIG9mIHRhdSBjZXJlbW9ueSBjdXJ2ZVwiKTtcbiAgICB9XG5cbiAgICAvLyBJbml0aWFsaXphdGlvbnNcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuXG4gICAgY29uc3Qgc0ZyID0gY3VydmUuRnIubjg7XG4gICAgY29uc3Qgc0cxID0gY3VydmUuRzEuRi5uOCAqIDI7XG4gICAgY29uc3Qgc0cyID0gY3VydmUuRzIuRi5uOCAqIDI7XG5cbiAgICBsZXQgcG9seW5vbWlhbHMgPSB7fTtcbiAgICBsZXQgZXZhbHVhdGlvbnMgPSB7fTtcbiAgICBsZXQgUFRhdTtcblxuICAgIGxldCBzZXR0aW5ncyA9IHtcbiAgICAgICAgblZhcnM6IHIxY3MublZhcnMsXG4gICAgICAgIG5QdWJsaWM6IHIxY3Mubk91dHB1dHMgKyByMWNzLm5QdWJJbnB1dHNcbiAgICB9O1xuXG4gICAgY29uc3QgcGxvbmtDb25zdHJhaW50cyA9IG5ldyBCaWdBcnJheSgpO1xuICAgIGxldCBwbG9ua0FkZGl0aW9ucyA9IG5ldyBCaWdBcnJheSgpO1xuXG4gICAgLy8gUHJvY2VzcyBjb25zdHJhaW50cyBpbnNpZGUgcjFjc1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBQcm9jZXNzaW5nIEZGbG9uayBjb25zdHJhaW50c1wiKTtcbiAgICBhd2FpdCBjb21wdXRlRkZDb25zdHJhaW50cyhjdXJ2ZS5GciwgcjFjcywgbG9nZ2VyKTtcbiAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgLy8gQXMgdGhlIHQgcG9seW5vbWlhbCBpcyBuKzUgd2UgbmVlZCBhdCBsZWFzdCBhIHBvd2VyIG9mIDRcbiAgICAvL1RPRE8gY2hlY2shISEhXG4gICAgLy8gTk9URSA6IHBsb25rQ29uc3RyYWludHMgKyAyID0gI2NvbnN0cmFpbnRzICsgYmxpbmRpbmcgY29lZmZpY2llbnRzIGZvciBlYWNoIHdpcmUgcG9seW5vbWlhbFxuICAgIHNldHRpbmdzLmNpclBvd2VyID0gTWF0aC5tYXgoRkZfVF9QT0xfREVHX01JTiwgbG9nMigocGxvbmtDb25zdHJhaW50cy5sZW5ndGggKyAyKSAtIDEpICsgMSk7XG4gICAgc2V0dGluZ3MuZG9tYWluU2l6ZSA9IDIgKiogc2V0dGluZ3MuY2lyUG93ZXI7XG5cbiAgICBpZiAocFRhdVNlY3Rpb25zWzJdWzBdLnNpemUgPCAoc2V0dGluZ3MuZG9tYWluU2l6ZSAqIDkgKyAxOCkgKiBzRzEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUG93ZXJzIG9mIFRhdSBpcyBub3QgYmlnIGVub3VnaCBmb3IgdGhpcyBjaXJjdWl0IHNpemUuIFNlY3Rpb24gMiB0b28gc21hbGwuXCIpO1xuICAgIH1cbiAgICBpZiAocFRhdVNlY3Rpb25zWzNdWzBdLnNpemUgPCBzRzIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUG93ZXJzIG9mIFRhdSBpcyBub3Qgd2VsbCBwcmVwYXJlZC4gU2VjdGlvbiAzIHRvbyBzbWFsbC5cIik7XG4gICAgfVxuXG4gICAgaWYgKGxvZ2dlcikge1xuICAgICAgICBsb2dnZXIuaW5mbyhcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIik7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiICBGRkxPTksgU0VUVVAgU0VUVElOR1NcIik7XG4gICAgICAgIGxvZ2dlci5pbmZvKGAgIEN1cnZlOiAgICAgICAgICR7Y3VydmUubmFtZX1gKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYCAgQ2lyY3VpdCBwb3dlcjogJHtzZXR0aW5ncy5jaXJQb3dlcn1gKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYCAgRG9tYWluIHNpemU6ICAgJHtzZXR0aW5ncy5kb21haW5TaXplfWApO1xuICAgICAgICBsb2dnZXIuaW5mbyhgICBWYXJzOiAgICAgICAgICAke3NldHRpbmdzLm5WYXJzfWApO1xuICAgICAgICBsb2dnZXIuaW5mbyhgICBQdWJsaWMgdmFyczogICAke3NldHRpbmdzLm5QdWJsaWN9YCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKGAgIENvbnN0cmFpbnRzOiAgICR7cGxvbmtDb25zdHJhaW50cy5sZW5ndGh9YCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKGAgIEFkZGl0aW9uczogICAgICR7cGxvbmtBZGRpdGlvbnMubGVuZ3RofWApO1xuICAgICAgICBsb2dnZXIuaW5mbyhcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIik7XG4gICAgfVxuXG4gICAgLy8gQ29tcHV0ZSBrMSBhbmQgazIgdG8gYmUgdXNlZCBpbiB0aGUgcGVybXV0YXRpb24gY2hlY2tzXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IGNvbXB1dGluZyBrMSBhbmQgazJcIik7XG4gICAgY29uc3QgW2sxLCBrMl0gPSBjb21wdXRlSzFLMigpO1xuXG4gICAgLy8gQ29tcHV0ZSBvbWVnYSAzICh3MykgYW5kIG9tZWdhIDQgKHc0KSB0byBiZSB1c2VkIGluIHRoZSBwcm92ZXIgYW5kIHRoZSB2ZXJpZmllclxuICAgIC8vIHczXjMgPSAxIGFuZCAgdzReNCA9IDFcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gY29tcHV0aW5nIHczXCIpO1xuICAgIGNvbnN0IHczID0gY29tcHV0ZVczKCk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IGNvbXB1dGluZyB3NFwiKTtcbiAgICBjb25zdCB3NCA9IGNvbXB1dGVXNCgpO1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBjb21wdXRpbmcgdzhcIik7XG4gICAgY29uc3QgdzggPSBjb21wdXRlVzgoKTtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gY29tcHV0aW5nIHdyXCIpO1xuICAgIGNvbnN0IHdyID0gZ2V0T21lZ2FDdWJpY1Jvb3Qoc2V0dGluZ3MuY2lyUG93ZXIsIGN1cnZlLkZyKTtcblxuICAgIC8vIFdyaXRlIG91dHB1dCB6a2V5IGZpbGVcbiAgICBhd2FpdCB3cml0ZVprZXlGaWxlKCk7XG5cbiAgICBhd2FpdCBmZFIxY3MuY2xvc2UoKTtcbiAgICBhd2FpdCBmZFBUYXUuY2xvc2UoKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiRkZMT05LIFNFVFVQIEZJTklTSEVEXCIpO1xuXG4gICAgcmV0dXJuIDA7XG5cbiAgICBhc3luYyBmdW5jdGlvbiBjb21wdXRlRkZDb25zdHJhaW50cyhGciwgcjFjcywgbG9nZ2VyKSB7XG4gICAgICAgIC8vIEFkZCBwdWJsaWMgaW5wdXRzIGFuZCBvdXRwdXRzXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2V0dGluZ3MublB1YmxpYzsgaSsrKSB7XG4gICAgICAgICAgICBwbG9ua0NvbnN0cmFpbnRzLnB1c2goZ2V0RkZsb25rQ29uc3RhbnRDb25zdHJhaW50KGkgKyAxLCBGcikpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQWRkIGFsbCBjb25zdHJhaW50cyBmcm9tIHIxY3MgZmlsZVxuICAgICAgICBjb25zdCByMWNzUHJvY2Vzc29yID0gbmV3IHIxY3NDb25zdHJhaW50UHJvY2Vzc29yKEZyLCBnZXRGRmxvbmtDb25zdGFudENvbnN0cmFpbnQsIGdldEZGbG9ua0FkZGl0aW9uQ29uc3RyYWludCwgZ2V0RkZsb25rTXVsdGlwbGljYXRpb25Db25zdHJhaW50LCBsb2dnZXIpO1xuXG4gICAgICAgIGNvbnN0IGJSMWNzID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRTZWN0aW9uKGZkUjFjcywgc2VjdGlvbnNSMWNzLCAyKTtcbiAgICAgICAgbGV0IGJSMWNzUG9zID0gMDtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCByMWNzLm5Db25zdHJhaW50czsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoKGxvZ2dlcikgJiYgKGkgIT09IDApICYmIChpICUgNTAwMDAwID09PSAwKSkge1xuICAgICAgICAgICAgICAgIGxvZ2dlci5pbmZvKGAgICAgcHJvY2Vzc2luZyByMWNzIGNvbnN0cmFpbnRzICR7aX0vJHtyMWNzLm5Db25zdHJhaW50c31gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IFtjb25zdHJhaW50cywgYWRkaXRpb25zXSA9IHIxY3NQcm9jZXNzb3IucHJvY2Vzc1IxY3NDb25zdHJhaW50KHNldHRpbmdzLCAuLi5yZWFkQ29uc3RyYWludCgpKTtcblxuICAgICAgICAgICAgcGxvbmtDb25zdHJhaW50cy5wdXNoKC4uLmNvbnN0cmFpbnRzKTtcbiAgICAgICAgICAgIHBsb25rQWRkaXRpb25zLnB1c2goLi4uYWRkaXRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIHJlYWRDb25zdHJhaW50KCkge1xuICAgICAgICAgICAgY29uc3QgYyA9IFtdO1xuICAgICAgICAgICAgY1swXSA9IHJlYWRMQygpO1xuICAgICAgICAgICAgY1sxXSA9IHJlYWRMQygpO1xuICAgICAgICAgICAgY1syXSA9IHJlYWRMQygpO1xuICAgICAgICAgICAgcmV0dXJuIGM7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiByZWFkTEMoKSB7XG4gICAgICAgICAgICBjb25zdCBsYyA9IHt9O1xuXG4gICAgICAgICAgICBjb25zdCBidWZmVUwzMiA9IGJSMWNzLnNsaWNlKGJSMWNzUG9zLCBiUjFjc1BvcyArIDQpO1xuICAgICAgICAgICAgYlIxY3NQb3MgKz0gNDtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZVTDMyViA9IG5ldyBEYXRhVmlldyhidWZmVUwzMi5idWZmZXIpO1xuICAgICAgICAgICAgY29uc3QgbklkeCA9IGJ1ZmZVTDMyVi5nZXRVaW50MzIoMCwgdHJ1ZSk7XG5cbiAgICAgICAgICAgIGNvbnN0IGJ1ZmYgPSBiUjFjcy5zbGljZShiUjFjc1BvcywgYlIxY3NQb3MgKyAoNCArIHIxY3MubjgpICogbklkeCk7XG4gICAgICAgICAgICBiUjFjc1BvcyArPSAoNCArIHIxY3MubjgpICogbklkeDtcbiAgICAgICAgICAgIGNvbnN0IGJ1ZmZWID0gbmV3IERhdGFWaWV3KGJ1ZmYuYnVmZmVyKTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbklkeDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaWR4ID0gYnVmZlYuZ2V0VWludDMyKGkgKiAoNCArIHIxY3MubjgpLCB0cnVlKTtcbiAgICAgICAgICAgICAgICBjb25zdCB2YWwgPSByMWNzLkYuZnJvbVJwckxFKGJ1ZmYsIGkgKiAoNCArIHIxY3MubjgpICsgNCk7XG4gICAgICAgICAgICAgICAgbGNbaWR4XSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBsYztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlWmtleUZpbGUoKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBXcml0aW5nIHRoZSB6a2V5IGZpbGVcIik7XG4gICAgICAgIGNvbnN0IGZkWktleSA9IGF3YWl0IGNyZWF0ZUJpbkZpbGUoemtleUZpbGVuYW1lLCBcInprZXlcIiwgMSwgWktFWV9GRl9OU0VDVElPTlMsIDEgPDwgMjIsIDEgPDwgMjQpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7SEVBREVSX1pLRVlfU0VDVElPTn0uIFprZXkgSGVhZGVyYCk7XG4gICAgICAgIGF3YWl0IHdyaXRlWmtleUhlYWRlcihmZFpLZXkpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9BRERJVElPTlNfU0VDVElPTn0uIEFkZGl0aW9uc2ApO1xuICAgICAgICBhd2FpdCB3cml0ZUFkZGl0aW9ucyhmZFpLZXkpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9BX01BUF9TRUNUSU9OfS4gQSBNYXBgKTtcbiAgICAgICAgYXdhaXQgd3JpdGVXaXRuZXNzTWFwKGZkWktleSwgWktFWV9GRl9BX01BUF9TRUNUSU9OLCAwLCBcIkEgbWFwXCIpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9CX01BUF9TRUNUSU9OfS4gQiBNYXBgKTtcbiAgICAgICAgYXdhaXQgd3JpdGVXaXRuZXNzTWFwKGZkWktleSwgWktFWV9GRl9CX01BUF9TRUNUSU9OLCAxLCBcIkIgbWFwXCIpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9DX01BUF9TRUNUSU9OfS4gQyBNYXBgKTtcbiAgICAgICAgYXdhaXQgd3JpdGVXaXRuZXNzTWFwKGZkWktleSwgWktFWV9GRl9DX01BUF9TRUNUSU9OLCAyLCBcIkMgbWFwXCIpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9RTF9TRUNUSU9OfS4gUUxgKTtcbiAgICAgICAgYXdhaXQgd3JpdGVRTWFwKGZkWktleSwgWktFWV9GRl9RTF9TRUNUSU9OLCAzLCBcIlFMXCIpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9RUl9TRUNUSU9OfS4gUVJgKTtcbiAgICAgICAgYXdhaXQgd3JpdGVRTWFwKGZkWktleSwgWktFWV9GRl9RUl9TRUNUSU9OLCA0LCBcIlFSXCIpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9RTV9TRUNUSU9OfS4gUU1gKTtcbiAgICAgICAgYXdhaXQgd3JpdGVRTWFwKGZkWktleSwgWktFWV9GRl9RTV9TRUNUSU9OLCA1LCBcIlFNXCIpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9RT19TRUNUSU9OfS4gUU9gKTtcbiAgICAgICAgYXdhaXQgd3JpdGVRTWFwKGZkWktleSwgWktFWV9GRl9RT19TRUNUSU9OLCA2LCBcIlFPXCIpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9RQ19TRUNUSU9OfS4gUUNgKTtcbiAgICAgICAgYXdhaXQgd3JpdGVRTWFwKGZkWktleSwgWktFWV9GRl9RQ19TRUNUSU9OLCA3LCBcIlFDXCIpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9ucyAke1pLRVlfRkZfU0lHTUExX1NFQ1RJT059LCR7WktFWV9GRl9TSUdNQTJfU0VDVElPTn0sJHtaS0VZX0ZGX1NJR01BM19TRUNUSU9OfS4gU2lnbWExLCBTaWdtYTIgJiBTaWdtYSAzYCk7XG4gICAgICAgIGF3YWl0IHdyaXRlU2lnbWEoZmRaS2V5KTtcbiAgICAgICAgaWYgKGdsb2JhbFRoaXMuZ2MpIGdsb2JhbFRoaXMuZ2MoKTtcblxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhgwrfCt8K3IFdyaXRpbmcgU2VjdGlvbiAke1pLRVlfRkZfTEFHUkFOR0VfU0VDVElPTn0uIExhZ3JhbmdlIFBvbHlub21pYWxzYCk7XG4gICAgICAgIGF3YWl0IHdyaXRlTGFncmFuZ2VQb2x5bm9taWFscyhmZFpLZXkpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9QVEFVX1NFQ1RJT059LiBQb3dlcnMgb2YgVGF1YCk7XG4gICAgICAgIGF3YWl0IHdyaXRlUHRhdShmZFpLZXkpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9DMF9TRUNUSU9OfS4gQzBgKTtcbiAgICAgICAgYXdhaXQgd3JpdGVDMChmZFpLZXkpO1xuICAgICAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGDCt8K3wrcgV3JpdGluZyBTZWN0aW9uICR7WktFWV9GRl9IRUFERVJfU0VDVElPTn0uIEZGbG9uayBIZWFkZXJgKTtcbiAgICAgICAgYXdhaXQgd3JpdGVGRmxvbmtIZWFkZXIoZmRaS2V5KTtcbiAgICAgICAgaWYgKGdsb2JhbFRoaXMuZ2MpIGdsb2JhbFRoaXMuZ2MoKTtcblxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gV3JpdGluZyB0aGUgemtleSBmaWxlIGZpbmlzaGVkXCIpO1xuXG4gICAgICAgIGF3YWl0IGZkWktleS5jbG9zZSgpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlWmtleUhlYWRlcihmZFpLZXkpIHtcbiAgICAgICAgYXdhaXQgc3RhcnRXcml0ZVNlY3Rpb24oZmRaS2V5LCBIRUFERVJfWktFWV9TRUNUSU9OKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIoRkZMT05LX1BST1RPQ09MX0lEKTtcbiAgICAgICAgYXdhaXQgZW5kV3JpdGVTZWN0aW9uKGZkWktleSk7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gd3JpdGVBZGRpdGlvbnMoZmRaS2V5KSB7XG4gICAgICAgIGF3YWl0IHN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleSwgWktFWV9GRl9BRERJVElPTlNfU0VDVElPTik7XG5cbiAgICAgICAgLy8gV3JpdHRlbiB2YWx1ZXMgYXJlIDIgKiAzMiBiaXQgaW50ZWdlcnMgKDIgKiA0IGJ5dGVzKSArIDIgZmllbGQgc2l6ZSB2YWx1ZXMgKCAyICogc0ZyIGJ5dGVzKVxuICAgICAgICBjb25zdCBidWZmT3V0ID0gbmV3IFVpbnQ4QXJyYXkoOCArIDIgKiBzRnIpO1xuICAgICAgICBjb25zdCBidWZmT3V0ViA9IG5ldyBEYXRhVmlldyhidWZmT3V0LmJ1ZmZlcik7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwbG9ua0FkZGl0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKChsb2dnZXIpICYmIChpICE9PSAwKSAmJiAoaSAlIDUwMDAwMCA9PT0gMCkpIGxvZ2dlci5pbmZvKGAgICAgICB3cml0aW5nIEFkZGl0aW9uczogJHtpfS8ke3Bsb25rQWRkaXRpb25zLmxlbmd0aH1gKTtcblxuICAgICAgICAgICAgY29uc3QgYWRkaXRpb24gPSBwbG9ua0FkZGl0aW9uc1tpXTtcblxuICAgICAgICAgICAgYnVmZk91dFYuc2V0VWludDMyKDAsIGFkZGl0aW9uWzBdLCB0cnVlKTtcbiAgICAgICAgICAgIGJ1ZmZPdXRWLnNldFVpbnQzMig0LCBhZGRpdGlvblsxXSwgdHJ1ZSk7XG4gICAgICAgICAgICBidWZmT3V0LnNldChhZGRpdGlvblsyXSwgOCk7XG4gICAgICAgICAgICBidWZmT3V0LnNldChhZGRpdGlvblszXSwgOCArIHNGcik7XG5cbiAgICAgICAgICAgIGF3YWl0IGZkWktleS53cml0ZShidWZmT3V0KTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBlbmRXcml0ZVNlY3Rpb24oZmRaS2V5KTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiB3cml0ZVdpdG5lc3NNYXAoZmRaS2V5LCBzZWN0aW9uTnVtLCBwb3NDb25zdHJhaW50LCBuYW1lKSB7XG4gICAgICAgIGF3YWl0IHN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleSwgc2VjdGlvbk51bSk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGxvbmtDb25zdHJhaW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKGxvZ2dlciAmJiAoaSAhPT0gMCkgJiYgKGkgJSA1MDAwMDAgPT09IDApKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmluZm8oYCAgICAgIHdyaXRpbmcgd2l0bmVzcyAke25hbWV9OiAke2l9LyR7cGxvbmtDb25zdHJhaW50cy5sZW5ndGh9YCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGF3YWl0IGZkWktleS53cml0ZVVMRTMyKHBsb25rQ29uc3RyYWludHNbaV1bcG9zQ29uc3RyYWludF0pO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlUU1hcChmZFpLZXksIHNlY3Rpb25OdW0sIHBvc0NvbnN0cmFpbnQsIG5hbWUpIHtcbiAgICAgICAgLy8gQ29tcHV0ZSBRIGZyb20gcSBldmFsdWF0aW9uc1xuICAgICAgICBsZXQgUSA9IG5ldyBCaWdCdWZmZXIoc2V0dGluZ3MuZG9tYWluU2l6ZSAqIHNGcik7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwbG9ua0NvbnN0cmFpbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBRLnNldChwbG9ua0NvbnN0cmFpbnRzW2ldW3Bvc0NvbnN0cmFpbnRdLCBpICogc0ZyKTtcbiAgICAgICAgICAgIGlmICgobG9nZ2VyKSAmJiAoaSAhPT0gMCkgJiYgKGkgJSA1MDAwMDAgPT09IDApKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmluZm8oYCAgICAgIHdyaXRpbmcgJHtuYW1lfTogJHtpfS8ke3Bsb25rQ29uc3RyYWludHMubGVuZ3RofWApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcG9seW5vbWlhbHNbbmFtZV0gPSBhd2FpdCBQb2x5bm9taWFsLmZyb21FdmFsdWF0aW9ucyhRLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgZXZhbHVhdGlvbnNbbmFtZV0gPSBhd2FpdCBFdmFsdWF0aW9ucy5mcm9tUG9seW5vbWlhbChwb2x5bm9taWFsc1tuYW1lXSwgNCwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICAgICAgLy8gV3JpdGUgUSBjb2VmZmljaWVudHMgYW5kIGV2YWx1YXRpb25zXG4gICAgICAgIGF3YWl0IHN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleSwgc2VjdGlvbk51bSk7XG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZShwb2x5bm9taWFsc1tuYW1lXS5jb2VmKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKGV2YWx1YXRpb25zW25hbWVdLmV2YWwpO1xuICAgICAgICBhd2FpdCBlbmRXcml0ZVNlY3Rpb24oZmRaS2V5KTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiB3cml0ZVNpZ21hKGZkWktleSkge1xuICAgICAgICAvLyBDb21wdXRlIHNpZ21hXG4gICAgICAgIGNvbnN0IHNpZ21hID0gbmV3IEJpZ0J1ZmZlcihzRnIgKiBzZXR0aW5ncy5kb21haW5TaXplICogMyk7XG4gICAgICAgIGNvbnN0IGxhc3RTZWVuID0gbmV3IEJpZ0FycmF5KHNldHRpbmdzLm5WYXJzKTtcbiAgICAgICAgY29uc3QgZmlyc3RQb3MgPSBuZXcgQmlnQXJyYXkoc2V0dGluZ3MublZhcnMpO1xuXG4gICAgICAgIGxldCB3ID0gRnIub25lO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNldHRpbmdzLmRvbWFpblNpemU7IGkrKykge1xuICAgICAgICAgICAgaWYgKGkgPCBwbG9ua0NvbnN0cmFpbnRzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGJ1aWxkU2lnbWEocGxvbmtDb25zdHJhaW50c1tpXVswXSwgaSk7XG4gICAgICAgICAgICAgICAgYnVpbGRTaWdtYShwbG9ua0NvbnN0cmFpbnRzW2ldWzFdLCBzZXR0aW5ncy5kb21haW5TaXplICsgaSk7XG4gICAgICAgICAgICAgICAgYnVpbGRTaWdtYShwbG9ua0NvbnN0cmFpbnRzW2ldWzJdLCBzZXR0aW5ncy5kb21haW5TaXplICogMiArIGkpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChpIDwgc2V0dGluZ3MuZG9tYWluU2l6ZSAtIDIpIHtcbiAgICAgICAgICAgICAgICBidWlsZFNpZ21hKDAsIGkpO1xuICAgICAgICAgICAgICAgIGJ1aWxkU2lnbWEoMCwgc2V0dGluZ3MuZG9tYWluU2l6ZSArIGkpO1xuICAgICAgICAgICAgICAgIGJ1aWxkU2lnbWEoMCwgc2V0dGluZ3MuZG9tYWluU2l6ZSAqIDIgKyBpKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2lnbWEuc2V0KHcsIGkgKiBzRnIpO1xuICAgICAgICAgICAgICAgIHNpZ21hLnNldChGci5tdWwodywgazEpLCAoc2V0dGluZ3MuZG9tYWluU2l6ZSArIGkpICogc0ZyKTtcbiAgICAgICAgICAgICAgICBzaWdtYS5zZXQoRnIubXVsKHcsIGsyKSwgKHNldHRpbmdzLmRvbWFpblNpemUgKiAyICsgaSkgKiBzRnIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB3ID0gRnIubXVsKHcsIEZyLndbc2V0dGluZ3MuY2lyUG93ZXJdKTtcblxuICAgICAgICAgICAgaWYgKChsb2dnZXIpICYmIChpICE9PSAwKSAmJiAoaSAlIDUwMDAwMCA9PT0gMCkpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIuaW5mbyhgICAgICAgd3JpdGluZyBzaWdtYSBwaGFzZTE6ICR7aX0vJHtwbG9ua0NvbnN0cmFpbnRzLmxlbmd0aH1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2V0dGluZ3MublZhcnM7IGkrKykge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBmaXJzdFBvc1tpXSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgICAgIHNpZ21hLnNldChsYXN0U2VlbltpXSwgZmlyc3RQb3NbaV0gKiBzRnIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyB0aHJvdyBuZXcgRXJyb3IoXCJWYXJpYWJsZSBub3QgdXNlZFwiKTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIlZhcmlhYmxlIG5vdCB1c2VkXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKChsb2dnZXIpICYmIChpICE9PSAwKSAmJiAoaSAlIDUwMDAwMCA9PT0gMCkpIGxvZ2dlci5pbmZvKGAgICAgICB3cml0aW5nIHNpZ21hIHBoYXNlMjogJHtpfS8ke3NldHRpbmdzLm5WYXJzfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGdsb2JhbFRoaXMuZ2MpIGdsb2JhbFRoaXMuZ2MoKTtcblxuICAgICAgICAvLyBXcml0ZSBzaWdtYSBjb2VmZmljaWVudHMgYW5kIGV2YWx1YXRpb25zXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMzsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBzZWN0aW9uSWQgPSAwID09PSBpID8gWktFWV9GRl9TSUdNQTFfU0VDVElPTiA6IDEgPT09IGkgPyBaS0VZX0ZGX1NJR01BMl9TRUNUSU9OIDogWktFWV9GRl9TSUdNQTNfU0VDVElPTjtcblxuICAgICAgICAgICAgbGV0IG5hbWUgPSBcIlNcIiArIChpICsgMSk7XG4gICAgICAgICAgICBwb2x5bm9taWFsc1tuYW1lXSA9IGF3YWl0IFBvbHlub21pYWwuZnJvbUV2YWx1YXRpb25zKHNpZ21hLnNsaWNlKHNldHRpbmdzLmRvbWFpblNpemUgKiBzRnIgKiBpLCBzZXR0aW5ncy5kb21haW5TaXplICogc0ZyICogKGkgKyAxKSksIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICAgICAgZXZhbHVhdGlvbnNbbmFtZV0gPSBhd2FpdCBFdmFsdWF0aW9ucy5mcm9tUG9seW5vbWlhbChwb2x5bm9taWFsc1tuYW1lXSwgNCwgY3VydmUsIGxvZ2dlcik7XG4gICAgICAgICAgICBhd2FpdCBzdGFydFdyaXRlU2VjdGlvbihmZFpLZXksIHNlY3Rpb25JZCk7XG4gICAgICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUocG9seW5vbWlhbHNbbmFtZV0uY29lZik7XG4gICAgICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUoZXZhbHVhdGlvbnNbbmFtZV0uZXZhbCk7XG4gICAgICAgICAgICBhd2FpdCBlbmRXcml0ZVNlY3Rpb24oZmRaS2V5KTtcblxuICAgICAgICAgICAgaWYgKGdsb2JhbFRoaXMuZ2MpIGdsb2JhbFRoaXMuZ2MoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAwO1xuXG4gICAgICAgIGZ1bmN0aW9uIGJ1aWxkU2lnbWEoc2lnbmFsSWQsIGlkeCkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBsYXN0U2VlbltzaWduYWxJZF0gPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICBmaXJzdFBvc1tzaWduYWxJZF0gPSBpZHg7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNpZ21hLnNldChsYXN0U2VlbltzaWduYWxJZF0sIGlkeCAqIHNGcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsZXQgdjtcbiAgICAgICAgICAgIGlmIChpZHggPCBzZXR0aW5ncy5kb21haW5TaXplKSB7XG4gICAgICAgICAgICAgICAgdiA9IHc7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGlkeCA8IDIgKiBzZXR0aW5ncy5kb21haW5TaXplKSB7XG4gICAgICAgICAgICAgICAgdiA9IEZyLm11bCh3LCBrMSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHYgPSBGci5tdWwodywgazIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsYXN0U2VlbltzaWduYWxJZF0gPSB2O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gd3JpdGVMYWdyYW5nZVBvbHlub21pYWxzKGZkWktleSkge1xuICAgICAgICBhd2FpdCBzdGFydFdyaXRlU2VjdGlvbihmZFpLZXksIFpLRVlfRkZfTEFHUkFOR0VfU0VDVElPTik7XG5cbiAgICAgICAgY29uc3QgbCA9IE1hdGgubWF4KHNldHRpbmdzLm5QdWJsaWMsIDEpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgbGV0IGJ1ZmYgPSBuZXcgQmlnQnVmZmVyKHNldHRpbmdzLmRvbWFpblNpemUgKiBzRnIpO1xuICAgICAgICAgICAgYnVmZi5zZXQoRnIub25lLCBpICogc0ZyKTtcblxuICAgICAgICAgICAgYXdhaXQgd3JpdGVQNChmZFpLZXksIGJ1ZmYpO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlUHRhdShmZFpLZXkpIHtcbiAgICAgICAgYXdhaXQgc3RhcnRXcml0ZVNlY3Rpb24oZmRaS2V5LCBaS0VZX0ZGX1BUQVVfU0VDVElPTik7XG5cbiAgICAgICAgLy8gZG9tYWluU2l6ZSAqIDkgKyAxOCA9IG1heGltdW0gU1JTIGxlbmd0aCBuZWVkZWQsIHNwZWNpZmljYWxseSB0byBjb21taXQgQzJcbiAgICAgICAgUFRhdSA9IG5ldyBCaWdCdWZmZXIoKHNldHRpbmdzLmRvbWFpblNpemUgKiA5ICsgMTgpICogc0cxKTtcbiAgICAgICAgYXdhaXQgZmRQVGF1LnJlYWRUb0J1ZmZlcihQVGF1LCAwLCAoc2V0dGluZ3MuZG9tYWluU2l6ZSAqIDkgKyAxOCkgKiBzRzEsIHBUYXVTZWN0aW9uc1syXVswXS5wKTtcblxuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUoUFRhdSk7XG4gICAgICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlQzAoZmRaS2V5KSB7XG4gICAgICAgIC8vIEMwKFgpIDo9IFFMKFheOCkgKyBYIMK3IFFSKFheOCkgKyBYXjIgwrcgUU8oWF44KSArIFheMyDCtyBRTShYXjgpICsgWF40IMK3IFFDKFheOClcbiAgICAgICAgLy8gICAgICAgICAgICArIFheNSDCtyBTSUdNQTEoWF44KSArIFheNiDCtyBTSUdNQTIoWF44KSArIFheNyDCtyBTSUdNQTMoWF44KVxuICAgICAgICBsZXQgQzAgPSBuZXcgQ1BvbHlub21pYWwoOCwgY3VydmUsIGxvZ2dlcik7XG4gICAgICAgIEMwLmFkZFBvbHlub21pYWwoMCwgcG9seW5vbWlhbHMuUUwpO1xuICAgICAgICBDMC5hZGRQb2x5bm9taWFsKDEsIHBvbHlub21pYWxzLlFSKTtcbiAgICAgICAgQzAuYWRkUG9seW5vbWlhbCgyLCBwb2x5bm9taWFscy5RTyk7XG4gICAgICAgIEMwLmFkZFBvbHlub21pYWwoMywgcG9seW5vbWlhbHMuUU0pO1xuICAgICAgICBDMC5hZGRQb2x5bm9taWFsKDQsIHBvbHlub21pYWxzLlFDKTtcbiAgICAgICAgQzAuYWRkUG9seW5vbWlhbCg1LCBwb2x5bm9taWFscy5TMSk7XG4gICAgICAgIEMwLmFkZFBvbHlub21pYWwoNiwgcG9seW5vbWlhbHMuUzIpO1xuICAgICAgICBDMC5hZGRQb2x5bm9taWFsKDcsIHBvbHlub21pYWxzLlMzKTtcblxuICAgICAgICBwb2x5bm9taWFscy5DMCA9IEMwLmdldFBvbHlub21pYWwoKTtcblxuICAgICAgICAvLyBDaGVjayBkZWdyZWVcbiAgICAgICAgaWYgKHBvbHlub21pYWxzLkMwLmRlZ3JlZSgpID49IDggKiBzZXR0aW5ncy5kb21haW5TaXplKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDMCBQb2x5bm9taWFsIGlzIG5vdCB3ZWxsIGNhbGN1bGF0ZWRcIik7XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBzdGFydFdyaXRlU2VjdGlvbihmZFpLZXksIFpLRVlfRkZfQzBfU0VDVElPTik7XG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZShwb2x5bm9taWFscy5DMC5jb2VmKTtcbiAgICAgICAgYXdhaXQgZW5kV3JpdGVTZWN0aW9uKGZkWktleSk7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gd3JpdGVGRmxvbmtIZWFkZXIoZmRaS2V5KSB7XG4gICAgICAgIGF3YWl0IHN0YXJ0V3JpdGVTZWN0aW9uKGZkWktleSwgWktFWV9GRl9IRUFERVJfU0VDVElPTik7XG5cbiAgICAgICAgY29uc3QgcHJpbWVRID0gY3VydmUucTtcbiAgICAgICAgY29uc3QgbjhxID0gKE1hdGguZmxvb3IoKFNjYWxhci5iaXRMZW5ndGgocHJpbWVRKSAtIDEpIC8gNjQpICsgMSkgKiA4O1xuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGVVTEUzMihuOHEpO1xuICAgICAgICBhd2FpdCB3cml0ZUJpZ0ludChmZFpLZXksIHByaW1lUSwgbjhxKTtcblxuICAgICAgICBjb25zdCBwcmltZVIgPSBjdXJ2ZS5yO1xuICAgICAgICBjb25zdCBuOHIgPSAoTWF0aC5mbG9vcigoU2NhbGFyLmJpdExlbmd0aChwcmltZVIpIC0gMSkgLyA2NCkgKyAxKSAqIDg7XG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZVVMRTMyKG44cik7XG4gICAgICAgIGF3YWl0IHdyaXRlQmlnSW50KGZkWktleSwgcHJpbWVSLCBuOHIpO1xuXG4gICAgICAgIC8vIFRvdGFsIG51bWJlciBvZiByMWNzIHZhcnNcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIoc2V0dGluZ3MublZhcnMpO1xuICAgICAgICAvLyBUb3RhbCBudW1iZXIgb2YgcjFjcyBwdWJsaWMgdmFycyA9IG91dHB1dHMgKyBwdWJsaWMgaW5wdXRzXG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZVVMRTMyKHNldHRpbmdzLm5QdWJsaWMpO1xuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGVVTEUzMihzZXR0aW5ncy5kb21haW5TaXplKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIocGxvbmtBZGRpdGlvbnMubGVuZ3RoKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlVUxFMzIocGxvbmtDb25zdHJhaW50cy5sZW5ndGgpO1xuXG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZShrMSk7XG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZShrMik7XG5cbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKHczKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKHc0KTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKHc4KTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKHdyKTtcblxuICAgICAgICBsZXQgYlhfMjtcbiAgICAgICAgYlhfMiA9IGF3YWl0IGZkUFRhdS5yZWFkKHNHMiwgcFRhdVNlY3Rpb25zWzNdWzBdLnAgKyBzRzIpO1xuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUoYlhfMik7XG5cbiAgICAgICAgbGV0IGNvbW1pdEMwID0gYXdhaXQgcG9seW5vbWlhbHMuQzAubXVsdGlFeHBvbmVudGlhdGlvbihQVGF1LCBcIkMwXCIpO1xuICAgICAgICBhd2FpdCBmZFpLZXkud3JpdGUoY29tbWl0QzApO1xuXG4gICAgICAgIGF3YWl0IGVuZFdyaXRlU2VjdGlvbihmZFpLZXkpO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHdyaXRlUDQoZmRaS2V5LCBidWZmKSB7XG4gICAgICAgIGNvbnN0IFtjb2VmZmljaWVudHMsIGV2YWx1YXRpb25zNF0gPSBhd2FpdCBQb2x5bm9taWFsLnRvNFQoYnVmZiwgc2V0dGluZ3MuZG9tYWluU2l6ZSwgW10sIEZyKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LndyaXRlKGNvZWZmaWNpZW50cyk7XG4gICAgICAgIGF3YWl0IGZkWktleS53cml0ZShldmFsdWF0aW9uczQpO1xuXG4gICAgICAgIHJldHVybiBbY29lZmZpY2llbnRzLCBldmFsdWF0aW9uczRdO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNvbXB1dGVLMUsyKCkge1xuICAgICAgICBsZXQgazEgPSBGci50d287XG4gICAgICAgIHdoaWxlIChpc0luY2x1ZGVkKGsxLCBbXSwgc2V0dGluZ3MuY2lyUG93ZXIpKSBGci5hZGQoazEsIEZyLm9uZSk7XG4gICAgICAgIGxldCBrMiA9IEZyLmFkZChrMSwgRnIub25lKTtcbiAgICAgICAgd2hpbGUgKGlzSW5jbHVkZWQoazIsIFtrMV0sIHNldHRpbmdzLmNpclBvd2VyKSkgRnIuYWRkKGsyLCBGci5vbmUpO1xuICAgICAgICByZXR1cm4gW2sxLCBrMl07XG5cbiAgICAgICAgZnVuY3Rpb24gaXNJbmNsdWRlZChrLCBrQXJyLCBwb3cpIHtcbiAgICAgICAgICAgIGNvbnN0IGRvbWFpblNpemUgPSAyICoqIHBvdztcbiAgICAgICAgICAgIGxldCB3ID0gRnIub25lO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBkb21haW5TaXplOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAoRnIuZXEoaywgdykpIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwga0Fyci5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoRnIuZXEoaywgRnIubXVsKGtBcnJbal0sIHcpKSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHcgPSBGci5tdWwodywgRnIud1twb3ddKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNvbXB1dGVXMygpIHtcbiAgICAgICAgbGV0IGdlbmVyYXRvciA9IEZyLmUoMzE2MjQpO1xuXG4gICAgICAgIC8vIEV4cG9uZW50IGlzIG9yZGVyKHIgLSAxKSAvIDNcbiAgICAgICAgbGV0IG9yZGVyUnN1YjEgPSAzNjQ4MDQwNDc4NjM5ODc5MjAzNzA3NzM0MjkwODc2MjEyNTE0NzU4MDYwNzMzNDAyNjcyMzkwNjE2MzY3MzY0NDI5MzAxNDE1OTM2bjtcbiAgICAgICAgbGV0IGV4cG9uZW50ID0gU2NhbGFyLmRpdihvcmRlclJzdWIxLCBTY2FsYXIuZSgzKSk7XG5cbiAgICAgICAgcmV0dXJuIEZyLmV4cChnZW5lcmF0b3IsIGV4cG9uZW50KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjb21wdXRlVzQoKSB7XG4gICAgICAgIHJldHVybiBGci53WzJdO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNvbXB1dGVXOCgpIHtcbiAgICAgICAgcmV0dXJuIEZyLndbM107XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0T21lZ2FDdWJpY1Jvb3QocG93ZXIsIEZyKSB7XG4gICAgICAgIC8vIEhhcmRjb3JkZWQgM3RoLXJvb3Qgb2YgRnIud1syOF1cbiAgICAgICAgY29uc3QgZmlyc3RSb290ID0gRnIuZSg0Njc3OTkxNjU4ODYwNjk2MTAwMzYwNDY4NjY3OTkyNjQwMjY0ODEzNDQyOTkwNzkwMTE3NjIwMjY3NzQ1MzM3NzQzNDU5ODgwODBuKTtcblxuICAgICAgICByZXR1cm4gRnIuZXhwKGZpcnN0Um9vdCwgMiAqKiAoMjggLSBwb3dlcikpO1xuICAgIH1cbn1cblxuXG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDIyIGlkZW4zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgKiBhcyBiaW5GaWxlVXRpbHMgZnJvbSBcIkBpZGVuMy9iaW5maWxldXRpbHNcIjtcbmltcG9ydCAqIGFzIHprZXlVdGlscyBmcm9tIFwiLi96a2V5X3V0aWxzLmpzXCI7XG5pbXBvcnQgKiBhcyB3dG5zVXRpbHMgZnJvbSBcIi4vd3Ruc191dGlscy5qc1wiO1xuaW1wb3J0IHsgQmlnQnVmZmVyLCBTY2FsYXIsIHV0aWxzIH0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuaW1wb3J0IHsgRkZMT05LX1BST1RPQ09MX0lEIH0gZnJvbSBcIi4vemtleV9jb25zdGFudHMuanNcIjtcbmltcG9ydCB7XG4gICAgWktFWV9GRl9BX01BUF9TRUNUSU9OLFxuICAgIFpLRVlfRkZfQURESVRJT05TX1NFQ1RJT04sXG4gICAgWktFWV9GRl9CX01BUF9TRUNUSU9OLFxuICAgIFpLRVlfRkZfQzBfU0VDVElPTixcbiAgICBaS0VZX0ZGX0NfTUFQX1NFQ1RJT04sXG4gICAgWktFWV9GRl9MQUdSQU5HRV9TRUNUSU9OLFxuICAgIFpLRVlfRkZfUFRBVV9TRUNUSU9OLFxuICAgIFpLRVlfRkZfUUNfU0VDVElPTixcbiAgICBaS0VZX0ZGX1FMX1NFQ1RJT04sXG4gICAgWktFWV9GRl9RTV9TRUNUSU9OLFxuICAgIFpLRVlfRkZfUU9fU0VDVElPTixcbiAgICBaS0VZX0ZGX1FSX1NFQ1RJT04sXG4gICAgWktFWV9GRl9TSUdNQTFfU0VDVElPTixcbiAgICBaS0VZX0ZGX1NJR01BMl9TRUNUSU9OLFxuICAgIFpLRVlfRkZfU0lHTUEzX1NFQ1RJT04sXG59IGZyb20gXCIuL2ZmbG9ua19jb25zdGFudHMuanNcIjtcbmltcG9ydCB7IEtlY2NhazI1NlRyYW5zY3JpcHQgfSBmcm9tIFwiLi9LZWNjYWsyNTZUcmFuc2NyaXB0LmpzXCI7XG5pbXBvcnQgeyBQcm9vZiB9IGZyb20gXCIuL3Byb29mLmpzXCI7XG5pbXBvcnQgeyBQb2x5bm9taWFsIH0gZnJvbSBcIi4vcG9seW5vbWlhbC9wb2x5bm9taWFsLmpzXCI7XG5pbXBvcnQgeyBFdmFsdWF0aW9ucyB9IGZyb20gXCIuL3BvbHlub21pYWwvZXZhbHVhdGlvbnMuanNcIjtcbmltcG9ydCB7IENQb2x5bm9taWFsIH0gZnJvbSBcIi4vcG9seW5vbWlhbC9jcG9seW5vbWlhbC5qc1wiO1xuXG5jb25zdCB7IHN0cmluZ2lmeUJpZ0ludHMgfSA9IHV0aWxzO1xuXG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIGZmbG9ua1Byb3ZlKHprZXlGaWxlTmFtZSwgd2l0bmVzc0ZpbGVOYW1lLCBsb2dnZXIsIG9wdGlvbnMpIHtcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIkZGTE9OSyBQUk9WRVIgU1RBUlRFRFwiKTtcblxuICAgIC8vIFJlYWQgd2l0bmVzcyBmaWxlXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IFJlYWRpbmcgd2l0bmVzcyBmaWxlXCIpO1xuICAgIGNvbnN0IHtcbiAgICAgICAgZmQ6IGZkV3RucyxcbiAgICAgICAgc2VjdGlvbnM6IHd0bnNTZWN0aW9uc1xuICAgIH0gPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZEJpbkZpbGUod2l0bmVzc0ZpbGVOYW1lLCBcInd0bnNcIiwgMiwgMSA8PCAyNSwgMSA8PCAyMyk7XG4gICAgY29uc3Qgd3RucyA9IGF3YWl0IHd0bnNVdGlscy5yZWFkSGVhZGVyKGZkV3Rucywgd3Ruc1NlY3Rpb25zKTtcblxuICAgIC8vUmVhZCB6a2V5IGZpbGVcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gUmVhZGluZyB6a2V5IGZpbGVcIik7XG4gICAgY29uc3Qge1xuICAgICAgICBmZDogZmRaS2V5LFxuICAgICAgICBzZWN0aW9uczogemtleVNlY3Rpb25zXG4gICAgfSA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkQmluRmlsZSh6a2V5RmlsZU5hbWUsIFwiemtleVwiLCAyLCAxIDw8IDI1LCAxIDw8IDIzKTtcblxuICAgIGNvbnN0IHprZXkgPSBhd2FpdCB6a2V5VXRpbHMucmVhZEhlYWRlcihmZFpLZXksIHprZXlTZWN0aW9ucywgdW5kZWZpbmVkLCBvcHRpb25zKTtcblxuICAgIGlmICh6a2V5LnByb3RvY29sSWQgIT09IEZGTE9OS19QUk9UT0NPTF9JRCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJ6a2V5IGZpbGUgaXMgbm90IGZmbG9ua1wiKTtcbiAgICB9XG5cbiAgICBpZiAoIVNjYWxhci5lcSh6a2V5LnIsIHd0bnMucSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ3VydmUgb2YgdGhlIHdpdG5lc3MgZG9lcyBub3QgbWF0Y2ggdGhlIGN1cnZlIG9mIHRoZSBwcm92aW5nIGtleVwiKTtcbiAgICB9XG5cbiAgICBpZiAod3Rucy5uV2l0bmVzcyAhPT0gemtleS5uVmFycyAtIHprZXkubkFkZGl0aW9ucykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgd2l0bmVzcyBsZW5ndGguIENpcmN1aXQ6ICR7emtleS5uVmFyc30sIHdpdG5lc3M6ICR7d3Rucy5uV2l0bmVzc30sICR7emtleS5uQWRkaXRpb25zfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnZlID0gemtleS5jdXJ2ZTtcblxuICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG5cbiAgICBjb25zdCBzRnIgPSBjdXJ2ZS5Gci5uODtcbiAgICBjb25zdCBzRzEgPSBjdXJ2ZS5HMS5GLm44ICogMjtcbiAgICBjb25zdCBzRG9tYWluID0gemtleS5kb21haW5TaXplICogc0ZyO1xuXG4gICAgaWYgKGxvZ2dlcikge1xuICAgICAgICBsb2dnZXIuaW5mbyhcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIik7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiICBGRkxPTksgUFJPVkUgU0VUVElOR1NcIik7XG4gICAgICAgIGxvZ2dlci5pbmZvKGAgIEN1cnZlOiAgICAgICAgICR7Y3VydmUubmFtZX1gKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYCAgQ2lyY3VpdCBwb3dlcjogJHt6a2V5LnBvd2VyfWApO1xuICAgICAgICBsb2dnZXIuaW5mbyhgICBEb21haW4gc2l6ZTogICAke3prZXkuZG9tYWluU2l6ZX1gKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYCAgVmFyczogICAgICAgICAgJHt6a2V5Lm5WYXJzfWApO1xuICAgICAgICBsb2dnZXIuaW5mbyhgICBQdWJsaWMgdmFyczogICAke3prZXkublB1YmxpY31gKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYCAgQ29uc3RyYWludHM6ICAgJHt6a2V5Lm5Db25zdHJhaW50c31gKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYCAgQWRkaXRpb25zOiAgICAgJHt6a2V5Lm5BZGRpdGlvbnN9YCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiKTtcbiAgICB9XG5cbiAgICAvL1JlYWQgd2l0bmVzcyBkYXRhXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IFJlYWRpbmcgd2l0bmVzcyBmaWxlIGRhdGFcIik7XG4gICAgY29uc3QgYnVmZldpdG5lc3MgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRXdG5zLCB3dG5zU2VjdGlvbnMsIDIpO1xuICAgIGF3YWl0IGZkV3Rucy5jbG9zZSgpO1xuXG4gICAgLy8gRmlyc3QgZWxlbWVudCBpbiBwbG9uayBpcyBub3QgdXNlZCBhbmQgY2FuIGJlIGFueSB2YWx1ZS4gKEJ1dCBhbHdheXMgdGhlIHNhbWUpLlxuICAgIC8vIFdlIHNldCBpdCB0byB6ZXJvIHRvIGdvIGZhc3RlciBpbiB0aGUgZXhwb25lbnRpYXRpb25zLlxuICAgIGJ1ZmZXaXRuZXNzLnNldChGci56ZXJvLCAwKTtcbiAgICBjb25zdCBidWZmSW50ZXJuYWxXaXRuZXNzID0gbmV3IEJpZ0J1ZmZlcih6a2V5Lm5BZGRpdGlvbnMgKiBzRnIpO1xuXG4gICAgbGV0IGJ1ZmZlcnMgPSB7fTtcbiAgICBsZXQgcG9seW5vbWlhbHMgPSB7fTtcbiAgICBsZXQgZXZhbHVhdGlvbnMgPSB7fTtcblxuICAgIC8vIFRvIGRpdmlkZSBwcmltZSBmaWVsZHMgdGhlIEV4dGVuZGVkIEV1Y2xpZGVhbiBBbGdvcml0aG0gZm9yIGNvbXB1dGluZyBtb2R1bGFyIGludmVyc2VzIGlzIG5lZWRlZC5cbiAgICAvLyBOT1RFOiBUaGlzIGlzIHRoZSBlcXVpdmFsZW50IG9mIGNvbXB1dGUgMS9kZW5vbWluYXRvciBhbmQgdGhlbiBtdWx0aXBseSBpdCBieSB0aGUgbnVtZXJhdG9yLlxuICAgIC8vIFRoZSBFeHRlbmRlZCBFdWNsaWRlYW4gQWxnb3JpdGhtIGlzIGV4cGVuc2l2ZSBpbiB0ZXJtcyBvZiBjb21wdXRhdGlvbi5cbiAgICAvLyBGb3IgdGhlIHNwZWNpYWwgY2FzZSB3aGVyZSB3ZSBuZWVkIHRvIGRvIG1hbnkgbW9kdWxhciBpbnZlcnNlcywgdGhlcmUncyBhIHNpbXBsZSBtYXRoZW1hdGljYWwgdHJpY2tcbiAgICAvLyB0aGF0IGFsbG93cyB1cyB0byBjb21wdXRlIG1hbnkgaW52ZXJzZXMsIGNhbGxlZCBNb250Z29tZXJ5IGJhdGNoIGludmVyc2lvbi5cbiAgICAvLyBNb3JlIGluZm86IGh0dHBzOi8vdml0YWxpay5jYS9nZW5lcmFsLzIwMTgvMDcvMjEvc3RhcmtzX3BhcnRfMy5odG1sXG4gICAgLy8gTW9udGdvbWVyeSBiYXRjaCBpbnZlcnNpb24gcmVkdWNlcyB0aGUgbiBpbnZlcnNlIGNvbXB1dGF0aW9ucyB0byBhIHNpbmdsZSBvbmVcbiAgICAvLyBUbyBzYXZlIHRoaXMgKHNpbmdsZSkgaW52ZXJzZSBjb21wdXRhdGlvbiBvbi1jaGFpbiwgd2lsbCBjb21wdXRlIGl0IGluIHByb3ZpbmcgdGltZSBhbmQgc2VuZCBpdCB0byB0aGUgdmVyaWZpZXIuXG4gICAgLy8gVGhlIHZlcmlmaWVyIHdpbGwgaGF2ZSB0byBjaGVjazpcbiAgICAvLyAxKSB0aGUgZGVub21pbmF0b3IgaXMgY29ycmVjdCBtdWx0aXBseWluZyBieSBoaW1zZWxmIG5vbi1pbnZlcnRlZCAtPiBhICogMS9hID09IDFcbiAgICAvLyAyKSBjb21wdXRlIHRoZSByZXN0IG9mIHRoZSBkZW5vbWluYXRvcnMgdXNpbmcgdGhlIE1vbnRnb21lcnkgYmF0Y2ggaW52ZXJzaW9uXG4gICAgLy8gVGhlIGludmVyc2lvbnMgYXJlOlxuICAgIC8vICAgwrcgZGVub21pbmF0b3IgbmVlZGVkIGluIHN0ZXAgOCBhbmQgOSBvZiB0aGUgdmVyaWZpZXIgdG8gbXVsdGlwbHkgYnkgMS9aX0goeGkpXG4gICAgLy8gICDCtyBkZW5vbWluYXRvciBuZWVkZWQgaW4gc3RlcCAxMCBhbmQgMTEgb2YgdGhlIHZlcmlmaWVyXG4gICAgLy8gICDCtyBkZW5vbWluYXRvciBuZWVkZWQgaW4gdGhlIHZlcmlmaWVyIHdoZW4gY29tcHV0aW5nIExfaV57UzF9KFgpIGFuZCBMX2lee1MyfShYKVxuICAgIC8vICAgwrcgTF9pIGk9MSB0byBudW0gcHVibGljIGlucHV0cywgbmVlZGVkIGluIHN0ZXAgNiBhbmQgNyBvZiB0aGUgdmVyaWZpZXIgdG8gY29tcHV0ZSBMXzEoeGkpIGFuZCBQSSh4aSlcbiAgICBsZXQgdG9JbnZlcnNlID0ge307XG5cbiAgICBsZXQgY2hhbGxlbmdlcyA9IHt9O1xuICAgIGxldCByb290cyA9IHt9O1xuXG4gICAgbGV0IHByb29mID0gbmV3IFByb29mKGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oYD4gUmVhZGluZyBTZWN0aW9uICR7WktFWV9GRl9BRERJVElPTlNfU0VDVElPTn0uIEFkZGl0aW9uc2ApO1xuICAgIGF3YWl0IGNhbGN1bGF0ZUFkZGl0aW9ucygpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oYD4gUmVhZGluZyBTZWN0aW9ucyAke1pLRVlfRkZfU0lHTUExX1NFQ1RJT059LCR7WktFWV9GRl9TSUdNQTJfU0VDVElPTn0sJHtaS0VZX0ZGX1NJR01BM19TRUNUSU9OfS4gU2lnbWExLCBTaWdtYTIgJiBTaWdtYSAzYCk7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCLCt8K3wrcgUmVhZGluZyBTaWdtYSBwb2x5bm9taWFscyBcIik7XG4gICAgcG9seW5vbWlhbHMuU2lnbWExID0gbmV3IFBvbHlub21pYWwobmV3IEJpZ0J1ZmZlcihzRG9tYWluKSwgY3VydmUsIGxvZ2dlcik7XG4gICAgcG9seW5vbWlhbHMuU2lnbWEyID0gbmV3IFBvbHlub21pYWwobmV3IEJpZ0J1ZmZlcihzRG9tYWluKSwgY3VydmUsIGxvZ2dlcik7XG4gICAgcG9seW5vbWlhbHMuU2lnbWEzID0gbmV3IFBvbHlub21pYWwobmV3IEJpZ0J1ZmZlcihzRG9tYWluKSwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKHBvbHlub21pYWxzLlNpZ21hMS5jb2VmLCAwLCBzRG9tYWluLCB6a2V5U2VjdGlvbnNbWktFWV9GRl9TSUdNQTFfU0VDVElPTl1bMF0ucCk7XG4gICAgYXdhaXQgZmRaS2V5LnJlYWRUb0J1ZmZlcihwb2x5bm9taWFscy5TaWdtYTIuY29lZiwgMCwgc0RvbWFpbiwgemtleVNlY3Rpb25zW1pLRVlfRkZfU0lHTUEyX1NFQ1RJT05dWzBdLnApO1xuICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIocG9seW5vbWlhbHMuU2lnbWEzLmNvZWYsIDAsIHNEb21haW4sIHprZXlTZWN0aW9uc1taS0VZX0ZGX1NJR01BM19TRUNUSU9OXVswXS5wKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IFJlYWRpbmcgU2lnbWEgZXZhbHVhdGlvbnNcIik7XG4gICAgZXZhbHVhdGlvbnMuU2lnbWExID0gbmV3IEV2YWx1YXRpb25zKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICBldmFsdWF0aW9ucy5TaWdtYTIgPSBuZXcgRXZhbHVhdGlvbnMobmV3IEJpZ0J1ZmZlcihzRG9tYWluICogNCksIGN1cnZlLCBsb2dnZXIpO1xuICAgIGV2YWx1YXRpb25zLlNpZ21hMyA9IG5ldyBFdmFsdWF0aW9ucyhuZXcgQmlnQnVmZmVyKHNEb21haW4gKiA0KSwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKGV2YWx1YXRpb25zLlNpZ21hMS5ldmFsLCAwLCBzRG9tYWluICogNCwgemtleVNlY3Rpb25zW1pLRVlfRkZfU0lHTUExX1NFQ1RJT05dWzBdLnAgKyBzRG9tYWluKTtcbiAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKGV2YWx1YXRpb25zLlNpZ21hMi5ldmFsLCAwLCBzRG9tYWluICogNCwgemtleVNlY3Rpb25zW1pLRVlfRkZfU0lHTUEyX1NFQ1RJT05dWzBdLnAgKyBzRG9tYWluKTtcbiAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKGV2YWx1YXRpb25zLlNpZ21hMy5ldmFsLCAwLCBzRG9tYWluICogNCwgemtleVNlY3Rpb25zW1pLRVlfRkZfU0lHTUEzX1NFQ1RJT05dWzBdLnAgKyBzRG9tYWluKTtcblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKGA+IFJlYWRpbmcgU2VjdGlvbiAke1pLRVlfRkZfUFRBVV9TRUNUSU9OfS4gUG93ZXJzIG9mIFRhdWApO1xuICAgIGNvbnN0IFBUYXUgPSBuZXcgQmlnQnVmZmVyKHprZXkuZG9tYWluU2l6ZSAqIDE2ICogc0cxKTtcbiAgICAvLyBkb21haW5TaXplICogOSArIDE4ID0gU1JTIGxlbmd0aCBpbiB0aGUgemtleSBzYXZlZCBpbiBzZXR1cCBwcm9jZXNzLlxuICAgIC8vIGl0IGNvcnJlc3BvbmRzIHRvIHRoZSBtYXhpbXVtIFNSUyBsZW5ndGggbmVlZGVkLCBzcGVjaWZpY2FsbHkgdG8gY29tbWl0IEMyXG4gICAgLy8gbm90aWNlIHRoYXQgdGhlIHJlc2VydmVkIGJ1ZmZlcnMgc2l6ZSBpcyB6a2V5LmRvbWFpblNpemUgKiAxNiAqIHNHMSBiZWNhdXNlIGEgcG93ZXIgb2YgdHdvIGJ1ZmZlciBzaXplIGlzIG5lZWRlZFxuICAgIC8vIHRoZSByZW1haW5pbmcgYnVmZmVyIG5vdCBmaWxsZWQgZnJvbSBTUlMgYXJlIHNldCB0byAwXG4gICAgYXdhaXQgZmRaS2V5LnJlYWRUb0J1ZmZlcihQVGF1LCAwLCAoemtleS5kb21haW5TaXplICogOSArIDE4KSAqIHNHMSwgemtleVNlY3Rpb25zW1pLRVlfRkZfUFRBVV9TRUNUSU9OXVswXS5wKTtcblxuICAgIC8vIFNUQVJUIEZGTE9OSyBQUk9WRVIgUFJPVE9DT0xcbiAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgLy8gUk9VTkQgMS4gQ29tcHV0ZSBDMShYKSBwb2x5bm9taWFsXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJcIik7XG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IFJPVU5EIDFcIik7XG4gICAgYXdhaXQgcm91bmQxKCk7XG5cbiAgICBkZWxldGUgcG9seW5vbWlhbHMuVDA7XG4gICAgZGVsZXRlIGV2YWx1YXRpb25zLlFMO1xuICAgIGRlbGV0ZSBldmFsdWF0aW9ucy5RUjtcbiAgICBkZWxldGUgZXZhbHVhdGlvbnMuUU07XG4gICAgZGVsZXRlIGV2YWx1YXRpb25zLlFPO1xuICAgIGRlbGV0ZSBldmFsdWF0aW9ucy5RQztcbiAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgLy8gUk9VTkQgMi4gQ29tcHV0ZSBDMihYKSBwb2x5bm9taWFsXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IFJPVU5EIDJcIik7XG4gICAgYXdhaXQgcm91bmQyKCk7XG5cbiAgICBkZWxldGUgYnVmZmVycy5BO1xuICAgIGRlbGV0ZSBidWZmZXJzLkI7XG4gICAgZGVsZXRlIGJ1ZmZlcnMuQztcbiAgICBkZWxldGUgZXZhbHVhdGlvbnMuQTtcbiAgICBkZWxldGUgZXZhbHVhdGlvbnMuQjtcbiAgICBkZWxldGUgZXZhbHVhdGlvbnMuQztcbiAgICBkZWxldGUgZXZhbHVhdGlvbnMuU2lnbWExO1xuICAgIGRlbGV0ZSBldmFsdWF0aW9ucy5TaWdtYTI7XG4gICAgZGVsZXRlIGV2YWx1YXRpb25zLlNpZ21hMztcbiAgICBkZWxldGUgZXZhbHVhdGlvbnMubGFncmFuZ2UxO1xuICAgIGRlbGV0ZSBldmFsdWF0aW9ucy5aO1xuICAgIGlmIChnbG9iYWxUaGlzLmdjKSBnbG9iYWxUaGlzLmdjKCk7XG5cbiAgICAvLyBST1VORCAzLiBDb21wdXRlIG9wZW5pbmcgZXZhbHVhdGlvbnNcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gUk9VTkQgM1wiKTtcbiAgICBhd2FpdCByb3VuZDMoKTtcblxuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5BO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5CO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5DO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5aO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5UMTtcbiAgICBkZWxldGUgcG9seW5vbWlhbHMuVDI7XG4gICAgZGVsZXRlIHBvbHlub21pYWxzLlNpZ21hMTtcbiAgICBkZWxldGUgcG9seW5vbWlhbHMuU2lnbWEyO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5TaWdtYTM7XG4gICAgZGVsZXRlIHBvbHlub21pYWxzLlFMO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5RUjtcbiAgICBkZWxldGUgcG9seW5vbWlhbHMuUU07XG4gICAgZGVsZXRlIHBvbHlub21pYWxzLlFDO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5RTztcbiAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgLy8gUk9VTkQgNC4gQ29tcHV0ZSBXKFgpIHBvbHlub21pYWxcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gUk9VTkQgNFwiKTtcbiAgICBhd2FpdCByb3VuZDQoKTtcbiAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgLy8gUk9VTkQgNS4gQ29tcHV0ZSBXJyhYKSBwb2x5bm9taWFsXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IFJPVU5EIDVcIik7XG4gICAgYXdhaXQgcm91bmQ1KCk7XG5cbiAgICBkZWxldGUgcG9seW5vbWlhbHMuQzA7XG4gICAgZGVsZXRlIHBvbHlub21pYWxzLkMxO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5DMjtcbiAgICBkZWxldGUgcG9seW5vbWlhbHMuUjE7XG4gICAgZGVsZXRlIHBvbHlub21pYWxzLlIyO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5GO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5MO1xuICAgIGRlbGV0ZSBwb2x5bm9taWFscy5aVDtcbiAgICBkZWxldGUgcG9seW5vbWlhbHMuWlRTMjtcbiAgICBhd2FpdCBmZFpLZXkuY2xvc2UoKTtcbiAgICBpZiAoZ2xvYmFsVGhpcy5nYykgZ2xvYmFsVGhpcy5nYygpO1xuXG4gICAgcHJvb2YuYWRkRXZhbHVhdGlvbihcImludlwiLCBnZXRNb250Z29tZXJ5QmF0Y2hlZEludmVyc2UoKSk7XG5cbiAgICAvLyBQcmVwYXJlIHByb29mXG4gICAgbGV0IF9wcm9vZiA9IHByb29mLnRvT2JqZWN0UHJvb2YoKTtcbiAgICBfcHJvb2YucHJvdG9jb2wgPSBcImZmbG9ua1wiO1xuICAgIF9wcm9vZi5jdXJ2ZSA9IGN1cnZlLm5hbWU7XG5cbiAgICAvLyBQcmVwYXJlIHB1YmxpYyBpbnB1dHNcbiAgICBsZXQgcHVibGljU2lnbmFscyA9IFtdO1xuXG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPD0gemtleS5uUHVibGljOyBpKyspIHtcbiAgICAgICAgY29uc3QgaV9zRnIgPSBpICogc0ZyO1xuXG4gICAgICAgIGNvbnN0IHB1YiA9IGJ1ZmZXaXRuZXNzLnNsaWNlKGlfc0ZyLCBpX3NGciArIHNGcik7XG4gICAgICAgIHB1YmxpY1NpZ25hbHMucHVzaChTY2FsYXIuZnJvbVJwckxFKHB1YikpO1xuICAgIH1cblxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiRkZMT05LIFBST1ZFUiBGSU5JU0hFRFwiKTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIHByb29mOiBzdHJpbmdpZnlCaWdJbnRzKF9wcm9vZiksXG4gICAgICAgIHB1YmxpY1NpZ25hbHM6IHN0cmluZ2lmeUJpZ0ludHMocHVibGljU2lnbmFscylcbiAgICB9O1xuXG4gICAgYXN5bmMgZnVuY3Rpb24gY2FsY3VsYXRlQWRkaXRpb25zKCkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgYWRkaXRpb25zXCIpO1xuICAgICAgICBjb25zdCBhZGRpdGlvbnNCdWZmID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRTZWN0aW9uKGZkWktleSwgemtleVNlY3Rpb25zLCBaS0VZX0ZGX0FERElUSU9OU19TRUNUSU9OKTtcblxuICAgICAgICAvLyBzaXplczogd2lyZUlkX3ggPSA0IGJ5dGVzICgzMiBiaXRzKSwgZmFjdG9yX3ggPSBmaWVsZCBzaXplIGJpdHNcbiAgICAgICAgLy8gQWRkaXRpb24gZm9ybTogd2lyZUlkX2Egd2lyZUlkX2IgZmFjdG9yX2EgZmFjdG9yX2IgKHNpemUgaXMgNCArIDQgKyBzRnIgKyBzRnIpXG4gICAgICAgIGNvbnN0IHNTdW0gPSA4ICsgc0ZyICogMjtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHprZXkubkFkZGl0aW9uczsgaSsrKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyICYmICgwICE9PSBpKSAmJiAoaSAlIDEwMDAwMCA9PT0gMCkpIGxvZ2dlci5pbmZvKGAgICAgYWRkaXRpb24gJHtpfS8ke3prZXkubkFkZGl0aW9uc31gKTtcblxuICAgICAgICAgICAgLy8gUmVhZCBhZGRpdGlvbiB2YWx1ZXNcbiAgICAgICAgICAgIGxldCBvZmZzZXQgPSBpICogc1N1bTtcbiAgICAgICAgICAgIGNvbnN0IHNpZ25hbElkMSA9IHJlYWRVSW50MzIoYWRkaXRpb25zQnVmZiwgb2Zmc2V0KTtcbiAgICAgICAgICAgIG9mZnNldCArPSA0O1xuICAgICAgICAgICAgY29uc3Qgc2lnbmFsSWQyID0gcmVhZFVJbnQzMihhZGRpdGlvbnNCdWZmLCBvZmZzZXQpO1xuICAgICAgICAgICAgb2Zmc2V0ICs9IDQ7XG4gICAgICAgICAgICBjb25zdCBmYWN0b3IxID0gYWRkaXRpb25zQnVmZi5zbGljZShvZmZzZXQsIG9mZnNldCArIHNGcik7XG4gICAgICAgICAgICBvZmZzZXQgKz0gc0ZyO1xuICAgICAgICAgICAgY29uc3QgZmFjdG9yMiA9IGFkZGl0aW9uc0J1ZmYuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyBzRnIpO1xuXG4gICAgICAgICAgICAvLyBHZXQgd2l0bmVzcyB2YWx1ZVxuICAgICAgICAgICAgY29uc3Qgd2l0bmVzczEgPSBnZXRXaXRuZXNzKHNpZ25hbElkMSk7XG4gICAgICAgICAgICBjb25zdCB3aXRuZXNzMiA9IGdldFdpdG5lc3Moc2lnbmFsSWQyKTtcblxuICAgICAgICAgICAgLy9DYWxjdWxhdGUgZmluYWwgcmVzdWx0XG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSBGci5hZGQoRnIubXVsKGZhY3RvcjEsIHdpdG5lc3MxKSwgRnIubXVsKGZhY3RvcjIsIHdpdG5lc3MyKSk7XG5cbiAgICAgICAgICAgIGJ1ZmZJbnRlcm5hbFdpdG5lc3Muc2V0KHJlc3VsdCwgc0ZyICogaSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZWFkVUludDMyKGIsIG8pIHtcbiAgICAgICAgY29uc3QgYnVmZiA9IGIuc2xpY2UobywgbyArIDQpO1xuICAgICAgICBjb25zdCBidWZmViA9IG5ldyBEYXRhVmlldyhidWZmLmJ1ZmZlciwgYnVmZi5ieXRlT2Zmc2V0LCBidWZmLmJ5dGVMZW5ndGgpO1xuICAgICAgICByZXR1cm4gYnVmZlYuZ2V0VWludDMyKDAsIHRydWUpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldFdpdG5lc3MoaWR4KSB7XG4gICAgICAgIGxldCBkaWZmID0gemtleS5uVmFycyAtIHprZXkubkFkZGl0aW9ucztcbiAgICAgICAgaWYgKGlkeCA8IGRpZmYpIHtcbiAgICAgICAgICAgIHJldHVybiBidWZmV2l0bmVzcy5zbGljZShpZHggKiBzRnIsIGlkeCAqIHNGciArIHNGcik7XG4gICAgICAgIH0gZWxzZSBpZiAoaWR4IDwgemtleS5uVmFycykge1xuICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gKGlkeCAtIGRpZmYpICogc0ZyO1xuICAgICAgICAgICAgcmV0dXJuIGJ1ZmZJbnRlcm5hbFdpdG5lc3Muc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyBzRnIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIEZyLnplcm87XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gcm91bmQxKCkge1xuICAgICAgICAvLyBTVEVQIDEuMSAtIEdlbmVyYXRlIHJhbmRvbSBibGluZGluZyBzY2FsYXJzIChiXzEsIC4uLiwgYjkpIOKIiCBGXG4gICAgICAgIGNoYWxsZW5nZXMuYiA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMTsgaSA8PSA5OyBpKyspIHtcbiAgICAgICAgICAgIGNoYWxsZW5nZXMuYltpXSA9IEZyLnJhbmRvbSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU1RFUCAxLjIgLSBDb21wdXRlIHdpcmUgcG9seW5vbWlhbHMgYShYKSwgYihYKSBhbmQgYyhYKVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIEEsIEIsIEMgd2lyZSBwb2x5bm9taWFsc1wiKTtcbiAgICAgICAgYXdhaXQgY29tcHV0ZVdpcmVQb2x5bm9taWFscygpO1xuXG4gICAgICAgIC8vIFNURVAgMS4zIC0gQ29tcHV0ZSB0aGUgcXVvdGllbnQgcG9seW5vbWlhbCBUMChYKVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIFQwIHBvbHlub21pYWxcIik7XG4gICAgICAgIGF3YWl0IGNvbXB1dGVUMCgpO1xuXG4gICAgICAgIC8vIFNURVAgMS40IC0gQ29tcHV0ZSB0aGUgRkZULXN0eWxlIGNvbWJpbmF0aW9uIHBvbHlub21pYWwgQzEoWClcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBDMSBwb2x5bm9taWFsXCIpO1xuICAgICAgICBhd2FpdCBjb21wdXRlQzEoKTtcblxuICAgICAgICAvLyBUaGUgZmlyc3Qgb3V0cHV0IG9mIHRoZSBwcm92ZXIgaXMgKFtDMV1fMSlcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBDMSBtdWx0aSBleHBvbmVudGlhdGlvblwiKTtcbiAgICAgICAgbGV0IGNvbW1pdEMxID0gYXdhaXQgcG9seW5vbWlhbHMuQzEubXVsdGlFeHBvbmVudGlhdGlvbihQVGF1LCBcIkMxXCIpO1xuICAgICAgICBwcm9vZi5hZGRQb2x5bm9taWFsKFwiQzFcIiwgY29tbWl0QzEpO1xuXG4gICAgICAgIHJldHVybiAwO1xuXG4gICAgICAgIGFzeW5jIGZ1bmN0aW9uIGNvbXB1dGVXaXJlUG9seW5vbWlhbHMoKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBSZWFkaW5nIGRhdGEgZnJvbSB6a2V5IGZpbGVcIik7XG4gICAgICAgICAgICAvLyBCdWlsZCBBLCBCIGFuZCBDIGV2YWx1YXRpb25zIGJ1ZmZlciBmcm9tIHprZXkgYW5kIHdpdG5lc3MgZmlsZXNcbiAgICAgICAgICAgIGJ1ZmZlcnMuQSA9IG5ldyBCaWdCdWZmZXIoc0RvbWFpbik7XG4gICAgICAgICAgICBidWZmZXJzLkIgPSBuZXcgQmlnQnVmZmVyKHNEb21haW4pO1xuICAgICAgICAgICAgYnVmZmVycy5DID0gbmV3IEJpZ0J1ZmZlcihzRG9tYWluKTtcblxuICAgICAgICAgICAgLy8gUmVhZCB6a2V5IHNlY3Rpb25zIGFuZCBmaWxsIHRoZSBidWZmZXJzXG4gICAgICAgICAgICBjb25zdCBhTWFwQnVmZiA9IGF3YWl0IGJpbkZpbGVVdGlscy5yZWFkU2VjdGlvbihmZFpLZXksIHprZXlTZWN0aW9ucywgWktFWV9GRl9BX01BUF9TRUNUSU9OKTtcbiAgICAgICAgICAgIGNvbnN0IGJNYXBCdWZmID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRTZWN0aW9uKGZkWktleSwgemtleVNlY3Rpb25zLCBaS0VZX0ZGX0JfTUFQX1NFQ1RJT04pO1xuICAgICAgICAgICAgY29uc3QgY01hcEJ1ZmYgPSBhd2FpdCBiaW5GaWxlVXRpbHMucmVhZFNlY3Rpb24oZmRaS2V5LCB6a2V5U2VjdGlvbnMsIFpLRVlfRkZfQ19NQVBfU0VDVElPTik7XG5cbiAgICAgICAgICAgIC8vIENvbXB1dGUgYWxsIHdpdG5lc3MgZnJvbSBzaWduYWwgaWRzIGFuZCBzZXQgdGhlbSB0byBBLEIgJiBDIGJ1ZmZlcnNcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgemtleS5uQ29uc3RyYWludHM7IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGlfc0ZyID0gaSAqIHNGcjtcbiAgICAgICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBpICogNDtcblxuICAgICAgICAgICAgICAgIC8vIENvbXB1dGUgQSB2YWx1ZSBmcm9tIGEgc2lnbmFsIGlkXG4gICAgICAgICAgICAgICAgY29uc3Qgc2lnbmFsSWRBID0gcmVhZFVJbnQzMihhTWFwQnVmZiwgb2Zmc2V0KTtcbiAgICAgICAgICAgICAgICBidWZmZXJzLkEuc2V0KGdldFdpdG5lc3Moc2lnbmFsSWRBKSwgaV9zRnIpO1xuXG4gICAgICAgICAgICAgICAgLy8gQ29tcHV0ZSBCIHZhbHVlIGZyb20gYSBzaWduYWwgaWRcbiAgICAgICAgICAgICAgICBjb25zdCBzaWduYWxJZEIgPSByZWFkVUludDMyKGJNYXBCdWZmLCBvZmZzZXQpO1xuICAgICAgICAgICAgICAgIGJ1ZmZlcnMuQi5zZXQoZ2V0V2l0bmVzcyhzaWduYWxJZEIpLCBpX3NGcik7XG5cbiAgICAgICAgICAgICAgICAvLyBDb21wdXRlIEMgdmFsdWUgZnJvbSBhIHNpZ25hbCBpZFxuICAgICAgICAgICAgICAgIGNvbnN0IHNpZ25hbElkQyA9IHJlYWRVSW50MzIoY01hcEJ1ZmYsIG9mZnNldCk7XG4gICAgICAgICAgICAgICAgYnVmZmVycy5DLnNldChnZXRXaXRuZXNzKHNpZ25hbElkQyksIGlfc0ZyKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQmxpbmQgYShYKSwgYihYKSBhbmQgYyhYKSBwb2x5bm9taWFscyBjb2VmZmljaWVudHMgd2l0aCBibGluZGluZyBzY2FsYXJzIGJcbiAgICAgICAgICAgIGJ1ZmZlcnMuQS5zZXQoY2hhbGxlbmdlcy5iWzFdLCBzRG9tYWluIC0gNjQpO1xuICAgICAgICAgICAgYnVmZmVycy5BLnNldChjaGFsbGVuZ2VzLmJbMl0sIHNEb21haW4gLSAzMik7XG4gICAgICAgICAgICBidWZmZXJzLkIuc2V0KGNoYWxsZW5nZXMuYlszXSwgc0RvbWFpbiAtIDY0KTtcbiAgICAgICAgICAgIGJ1ZmZlcnMuQi5zZXQoY2hhbGxlbmdlcy5iWzRdLCBzRG9tYWluIC0gMzIpO1xuICAgICAgICAgICAgYnVmZmVycy5DLnNldChjaGFsbGVuZ2VzLmJbNV0sIHNEb21haW4gLSA2NCk7XG4gICAgICAgICAgICBidWZmZXJzLkMuc2V0KGNoYWxsZW5nZXMuYls2XSwgc0RvbWFpbiAtIDMyKTtcblxuICAgICAgICAgICAgYnVmZmVycy5BID0gYXdhaXQgRnIuYmF0Y2hUb01vbnRnb21lcnkoYnVmZmVycy5BKTtcbiAgICAgICAgICAgIGJ1ZmZlcnMuQiA9IGF3YWl0IEZyLmJhdGNoVG9Nb250Z29tZXJ5KGJ1ZmZlcnMuQik7XG4gICAgICAgICAgICBidWZmZXJzLkMgPSBhd2FpdCBGci5iYXRjaFRvTW9udGdvbWVyeShidWZmZXJzLkMpO1xuXG4gICAgICAgICAgICAvLyBDb21wdXRlIHRoZSBjb2VmZmljaWVudHMgb2YgdGhlIHdpcmUgcG9seW5vbWlhbHMgYShYKSwgYihYKSBhbmQgYyhYKSBmcm9tIEEsQiAmIEMgYnVmZmVyc1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCLCt8K3wrcgQ29tcHV0aW5nIEEgaWZmdFwiKTtcbiAgICAgICAgICAgIHBvbHlub21pYWxzLkEgPSBhd2FpdCBQb2x5bm9taWFsLmZyb21FdmFsdWF0aW9ucyhidWZmZXJzLkEsIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCLCt8K3wrcgQ29tcHV0aW5nIEIgaWZmdFwiKTtcbiAgICAgICAgICAgIHBvbHlub21pYWxzLkIgPSBhd2FpdCBQb2x5bm9taWFsLmZyb21FdmFsdWF0aW9ucyhidWZmZXJzLkIsIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCLCt8K3wrcgQ29tcHV0aW5nIEMgaWZmdFwiKTtcbiAgICAgICAgICAgIHBvbHlub21pYWxzLkMgPSBhd2FpdCBQb2x5bm9taWFsLmZyb21FdmFsdWF0aW9ucyhidWZmZXJzLkMsIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgICAgICAgICAvLyBDb21wdXRlIGV4dGVuZGVkIGV2YWx1YXRpb25zIG9mIGEoWCksIGIoWCkgYW5kIGMoWCkgcG9seW5vbWlhbHNcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBBIGZmdFwiKTtcbiAgICAgICAgICAgIGV2YWx1YXRpb25zLkEgPSBhd2FpdCBFdmFsdWF0aW9ucy5mcm9tUG9seW5vbWlhbChwb2x5bm9taWFscy5BLCA0LCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBCIGZmdFwiKTtcbiAgICAgICAgICAgIGV2YWx1YXRpb25zLkIgPSBhd2FpdCBFdmFsdWF0aW9ucy5mcm9tUG9seW5vbWlhbChwb2x5bm9taWFscy5CLCA0LCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBDIGZmdFwiKTtcbiAgICAgICAgICAgIGV2YWx1YXRpb25zLkMgPSBhd2FpdCBFdmFsdWF0aW9ucy5mcm9tUG9seW5vbWlhbChwb2x5bm9taWFscy5DLCA0LCBjdXJ2ZSwgbG9nZ2VyKTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgZGVncmVlc1xuICAgICAgICAgICAgaWYgKHBvbHlub21pYWxzLkEuZGVncmVlKCkgPj0gemtleS5kb21haW5TaXplKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQSBQb2x5bm9taWFsIGlzIG5vdCB3ZWxsIGNhbGN1bGF0ZWRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocG9seW5vbWlhbHMuQi5kZWdyZWUoKSA+PSB6a2V5LmRvbWFpblNpemUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJCIFBvbHlub21pYWwgaXMgbm90IHdlbGwgY2FsY3VsYXRlZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChwb2x5bm9taWFscy5DLmRlZ3JlZSgpID49IHprZXkuZG9tYWluU2l6ZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkMgUG9seW5vbWlhbCBpcyBub3Qgd2VsbCBjYWxjdWxhdGVkXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgYXN5bmMgZnVuY3Rpb24gY29tcHV0ZVQwKCkge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oYMK3wrfCtyBSZWFkaW5nIHNlY3Rpb25zICR7WktFWV9GRl9RTF9TRUNUSU9OfSwgJHtaS0VZX0ZGX1FSX1NFQ1RJT059YCArXG4gICAgICAgICAgICAgICAgYCwgJHtaS0VZX0ZGX1FNX1NFQ1RJT059LCAke1pLRVlfRkZfUU9fU0VDVElPTn0sICR7WktFWV9GRl9RQ19TRUNUSU9OfS4gUSBzZWxlY3RvcnNgKTtcbiAgICAgICAgICAgIC8vIFJlc2VydmUgbWVtb3J5IGZvciBRJ3MgZXZhbHVhdGlvbnNcbiAgICAgICAgICAgIGV2YWx1YXRpb25zLlFMID0gbmV3IEV2YWx1YXRpb25zKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgICAgIGV2YWx1YXRpb25zLlFSID0gbmV3IEV2YWx1YXRpb25zKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgICAgIGV2YWx1YXRpb25zLlFNID0gbmV3IEV2YWx1YXRpb25zKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgICAgIGV2YWx1YXRpb25zLlFPID0gbmV3IEV2YWx1YXRpb25zKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgICAgIGV2YWx1YXRpb25zLlFDID0gbmV3IEV2YWx1YXRpb25zKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpLCBjdXJ2ZSwgbG9nZ2VyKTtcblxuICAgICAgICAgICAgLy8gUmVhZCBRJ3MgZXZhbHVhdGlvbnMgZnJvbSB6a2V5IGZpbGVcbiAgICAgICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIoZXZhbHVhdGlvbnMuUUwuZXZhbCwgMCwgc0RvbWFpbiAqIDQsIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FMX1NFQ1RJT05dWzBdLnAgKyBzRG9tYWluKTtcbiAgICAgICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIoZXZhbHVhdGlvbnMuUVIuZXZhbCwgMCwgc0RvbWFpbiAqIDQsIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FSX1NFQ1RJT05dWzBdLnAgKyBzRG9tYWluKTtcbiAgICAgICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIoZXZhbHVhdGlvbnMuUU0uZXZhbCwgMCwgc0RvbWFpbiAqIDQsIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FNX1NFQ1RJT05dWzBdLnAgKyBzRG9tYWluKTtcbiAgICAgICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIoZXZhbHVhdGlvbnMuUU8uZXZhbCwgMCwgc0RvbWFpbiAqIDQsIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FPX1NFQ1RJT05dWzBdLnAgKyBzRG9tYWluKTtcbiAgICAgICAgICAgIGF3YWl0IGZkWktleS5yZWFkVG9CdWZmZXIoZXZhbHVhdGlvbnMuUUMuZXZhbCwgMCwgc0RvbWFpbiAqIDQsIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FDX1NFQ1RJT05dWzBdLnAgKyBzRG9tYWluKTtcblxuICAgICAgICAgICAgLy8gUmVhZCBMYWdyYW5nZSBwb2x5bm9taWFscyAmIGV2YWx1YXRpb25zIGZyb20gemtleSBmaWxlXG4gICAgICAgICAgICBjb25zdCBsYWdyYW5nZVBvbHlub21pYWxzID0gYXdhaXQgYmluRmlsZVV0aWxzLnJlYWRTZWN0aW9uKGZkWktleSwgemtleVNlY3Rpb25zLCBaS0VZX0ZGX0xBR1JBTkdFX1NFQ1RJT04pO1xuICAgICAgICAgICAgZXZhbHVhdGlvbnMubGFncmFuZ2UxID0gbmV3IEV2YWx1YXRpb25zKGxhZ3JhbmdlUG9seW5vbWlhbHMsIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgICAgICAgICAvLyBSZXNlcnZlIG1lbW9yeSBmb3IgYnVmZmVycyBUMFxuICAgICAgICAgICAgYnVmZmVycy5UMCA9IG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpO1xuXG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgVDAgZXZhbHVhdGlvbnNcIik7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHprZXkuZG9tYWluU2l6ZSAqIDQ7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmIChsb2dnZXIgJiYgKDAgIT09IGkpICYmIChpICUgMTAwMDAwID09PSAwKSkgbG9nZ2VyLmluZm8oYCAgICAgIFQwIGV2YWx1YXRpb24gJHtpfS8ke3prZXkuZG9tYWluU2l6ZSAqIDR9YCk7XG5cbiAgICAgICAgICAgICAgICAvLyBHZXQgcmVsYXRlZCBldmFsdWF0aW9ucyB0byBjb21wdXRlIGN1cnJlbnQgVDAgZXZhbHVhdGlvblxuICAgICAgICAgICAgICAgIGNvbnN0IGEgPSBldmFsdWF0aW9ucy5BLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICAgICAgY29uc3QgYiA9IGV2YWx1YXRpb25zLkIuZ2V0RXZhbHVhdGlvbihpKTtcbiAgICAgICAgICAgICAgICBjb25zdCBjID0gZXZhbHVhdGlvbnMuQy5nZXRFdmFsdWF0aW9uKGkpO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgcWwgPSBldmFsdWF0aW9ucy5RTC5nZXRFdmFsdWF0aW9uKGkpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHFyID0gZXZhbHVhdGlvbnMuUVIuZ2V0RXZhbHVhdGlvbihpKTtcbiAgICAgICAgICAgICAgICBjb25zdCBxbSA9IGV2YWx1YXRpb25zLlFNLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICAgICAgY29uc3QgcW8gPSBldmFsdWF0aW9ucy5RTy5nZXRFdmFsdWF0aW9uKGkpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHFjID0gZXZhbHVhdGlvbnMuUUMuZ2V0RXZhbHVhdGlvbihpKTtcblxuICAgICAgICAgICAgICAgIC8vIENvbXB1dGUgY3VycmVudCBwdWJsaWMgaW5wdXRcbiAgICAgICAgICAgICAgICBsZXQgcGkgPSBGci56ZXJvO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgemtleS5uUHVibGljOyBqKyspIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gKGogKiA1ICogemtleS5kb21haW5TaXplKSArIHprZXkuZG9tYWluU2l6ZSArIGk7XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbFBvbCA9IGV2YWx1YXRpb25zLmxhZ3JhbmdlMS5nZXRFdmFsdWF0aW9uKG9mZnNldCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGFWYWwgPSBidWZmZXJzLkEuc2xpY2UoaiAqIHNGciwgKGogKyAxKSAqIHNGcik7XG5cbiAgICAgICAgICAgICAgICAgICAgcGkgPSBGci5zdWIocGksIEZyLm11bChsUG9sLCBhVmFsKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy9UMChYKSA9IFtxX0woWCnCt2EoWCkgKyBxX1IoWCnCt2IoWCkgKyBxX00oWCnCt2EoWCnCt2IoWCkgKyBxX08oWCnCt2MoWCkgKyBxX0MoWCkgKyBQSShYKV0gwrcgMS9aX0goWClcbiAgICAgICAgICAgICAgICAvLyBDb21wdXRlIGZpcnN0IFQwKFgpwrdaX0goWCksIHNvIGRpdmlkZSBsYXRlciB0aGUgcmVzdWx0aW5nIHBvbHlub21pYWwgYnkgWl9IKFgpXG4gICAgICAgICAgICAgICAgLy8gZXhwcmVzc2lvbiAxIC0+IHFfTChYKcK3YShYKVxuICAgICAgICAgICAgICAgIGNvbnN0IGUxID0gRnIubXVsKGEsIHFsKTtcblxuICAgICAgICAgICAgICAgIC8vIGV4cHJlc3Npb24gMiAtPiBxX1IoWCnCt2IoWClcbiAgICAgICAgICAgICAgICBjb25zdCBlMiA9IEZyLm11bChiLCBxcik7XG5cbiAgICAgICAgICAgICAgICAvLyBleHByZXNzaW9uIDMgLT4gcV9NKFgpwrdhKFgpwrdiKFgpXG4gICAgICAgICAgICAgICAgY29uc3QgZTMgPSBGci5tdWwoRnIubXVsKGEsIGIpLCBxbSk7XG5cbiAgICAgICAgICAgICAgICAvLyBleHByZXNzaW9uIDQgLT4gcV9PKFgpwrdjKFgpXG4gICAgICAgICAgICAgICAgY29uc3QgZTQgPSBGci5tdWwoYywgcW8pO1xuXG4gICAgICAgICAgICAgICAgLy8gdDAgPSBleHByZXNzaW9ucyAxICsgZXhwcmVzc2lvbiAyICsgZXhwcmVzc2lvbiAzICsgZXhwcmVzc2lvbiA0ICsgcWMgKyBwaVxuICAgICAgICAgICAgICAgIGNvbnN0IHQwID0gRnIuYWRkKGUxLCBGci5hZGQoZTIsIEZyLmFkZChlMywgRnIuYWRkKGU0LCBGci5hZGQocWMsIHBpKSkpKSk7XG5cbiAgICAgICAgICAgICAgICBidWZmZXJzLlQwLnNldCh0MCwgaSAqIHNGcik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiYnVmZmVyIFQwOiBcIiArIGJ1ZmZlcnMuVDAuYnl0ZUxlbmd0aCAvIHNGcik7XG5cbiAgICAgICAgICAgIC8vIENvbXB1dGUgdGhlIGNvZWZmaWNpZW50cyBvZiB0aGUgcG9seW5vbWlhbCBUMChYKSBmcm9tIGJ1ZmZlcnMuVDBcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBUMCBpZmZ0XCIpO1xuICAgICAgICAgICAgcG9seW5vbWlhbHMuVDAgPSBhd2FpdCBQb2x5bm9taWFsLmZyb21FdmFsdWF0aW9ucyhidWZmZXJzLlQwLCBjdXJ2ZSwgbG9nZ2VyKTtcblxuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJUMCBsZW5ndGg6IFwiICsgcG9seW5vbWlhbHMuVDAubGVuZ3RoKCkpO1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCJUMCBkZWdyZWU6IFwiICsgcG9seW5vbWlhbHMuVDAuZGVncmVlKCkpO1xuXG4gICAgICAgICAgICAvLyBEaXZpZGUgdGhlIHBvbHlub21pYWwgVDAgYnkgWl9IKFgpXG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgVDAgLyBaSFwiKTtcbiAgICAgICAgICAgIHBvbHlub21pYWxzLlQwLmRpdkJ5WmVyb2ZpZXIoemtleS5kb21haW5TaXplLCBGci5vbmUpO1xuXG4gICAgICAgICAgICAvLyBDaGVjayBkZWdyZWVcbiAgICAgICAgICAgIGlmIChwb2x5bm9taWFscy5UMC5kZWdyZWUoKSA+PSAyICogemtleS5kb21haW5TaXplIC0gMikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVDAgUG9seW5vbWlhbCBpcyBub3Qgd2VsbCBjYWxjdWxhdGVkIChkZWdyZWUgaXMgJHtwb2x5bm9taWFscy5UMC5kZWdyZWUoKX0gYW5kIG11c3QgYmUgbGVzcyB0aGFuICR7MiAqIHprZXkuZG9tYWluU2l6ZSArIDJ9YCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGRlbGV0ZSBidWZmZXJzLlQwO1xuICAgICAgICB9XG5cbiAgICAgICAgYXN5bmMgZnVuY3Rpb24gY29tcHV0ZUMxKCkge1xuICAgICAgICAgICAgbGV0IEMxID0gbmV3IENQb2x5bm9taWFsKDQsIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICAgICAgQzEuYWRkUG9seW5vbWlhbCgwLCBwb2x5bm9taWFscy5BKTtcbiAgICAgICAgICAgIEMxLmFkZFBvbHlub21pYWwoMSwgcG9seW5vbWlhbHMuQik7XG4gICAgICAgICAgICBDMS5hZGRQb2x5bm9taWFsKDIsIHBvbHlub21pYWxzLkMpO1xuICAgICAgICAgICAgQzEuYWRkUG9seW5vbWlhbCgzLCBwb2x5bm9taWFscy5UMCk7XG5cbiAgICAgICAgICAgIHBvbHlub21pYWxzLkMxID0gQzEuZ2V0UG9seW5vbWlhbCgpO1xuXG4gICAgICAgICAgICAvLyBDaGVjayBkZWdyZWVcbiAgICAgICAgICAgIGlmIChwb2x5bm9taWFscy5DMS5kZWdyZWUoKSA+PSA4ICogemtleS5kb21haW5TaXplIC0gOCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkMxIFBvbHlub21pYWwgaXMgbm90IHdlbGwgY2FsY3VsYXRlZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIHJvdW5kMigpIHtcbiAgICAgICAgLy8gU1RFUCAyLjEgLSBDb21wdXRlIHBlcm11dGF0aW9uIGNoYWxsZW5nZSBiZXRhIGFuZCBnYW1tYSDiiIggRlxuICAgICAgICAvLyBDb21wdXRlIHBlcm11dGF0aW9uIGNoYWxsZW5nZSBiZXRhXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBDb21wdXRpbmcgY2hhbGxlbmdlcyBiZXRhIGFuZCBnYW1tYVwiKTtcbiAgICAgICAgY29uc3QgdHJhbnNjcmlwdCA9IG5ldyBLZWNjYWsyNTZUcmFuc2NyaXB0KGN1cnZlKTtcblxuICAgICAgICAvLyBBZGQgQzAgdG8gdGhlIHRyYW5zY3JpcHRcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHprZXkuQzApO1xuXG4gICAgICAgIC8vIEFkZCBBIHRvIHRoZSB0cmFuc2NyaXB0XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgemtleS5uUHVibGljOyBpKyspIHtcbiAgICAgICAgICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKGJ1ZmZlcnMuQS5zbGljZShpICogc0ZyLCBpICogc0ZyICsgc0ZyKSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBZGQgQzEgdG8gdGhlIHRyYW5zY3JpcHRcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRQb2xDb21taXRtZW50KHByb29mLmdldFBvbHlub21pYWwoXCJDMVwiKSk7XG5cbiAgICAgICAgY2hhbGxlbmdlcy5iZXRhID0gdHJhbnNjcmlwdC5nZXRDaGFsbGVuZ2UoKTtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCLCt8K3wrcgY2hhbGxlbmdlcy5iZXRhOiBcIiArIEZyLnRvU3RyaW5nKGNoYWxsZW5nZXMuYmV0YSkpO1xuXG4gICAgICAgIC8vIENvbXB1dGUgcGVybXV0YXRpb24gY2hhbGxlbmdlIGdhbW1hXG4gICAgICAgIHRyYW5zY3JpcHQucmVzZXQoKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIoY2hhbGxlbmdlcy5iZXRhKTtcbiAgICAgICAgY2hhbGxlbmdlcy5nYW1tYSA9IHRyYW5zY3JpcHQuZ2V0Q2hhbGxlbmdlKCk7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IGNoYWxsZW5nZXMuZ2FtbWE6IFwiICsgRnIudG9TdHJpbmcoY2hhbGxlbmdlcy5nYW1tYSkpO1xuXG4gICAgICAgIC8vIFNURVAgMi4yIC0gQ29tcHV0ZSBwZXJtdXRhdGlvbiBwb2x5bm9taWFsIHooWClcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBaIHBvbHlub21pYWxcIik7XG4gICAgICAgIGF3YWl0IGNvbXB1dGVaKCk7XG5cbiAgICAgICAgLy8gU1RFUCAyLjMgLSBDb21wdXRlIHF1b3RpZW50IHBvbHlub21pYWwgVDEoWCkgYW5kIFQyKFgpXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBDb21wdXRpbmcgVDEgcG9seW5vbWlhbFwiKTtcbiAgICAgICAgYXdhaXQgY29tcHV0ZVQxKCk7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBDb21wdXRpbmcgVDIgcG9seW5vbWlhbFwiKTtcbiAgICAgICAgYXdhaXQgY29tcHV0ZVQyKCk7XG5cbiAgICAgICAgLy8gU1RFUCAyLjQgLSBDb21wdXRlIHRoZSBGRlQtc3R5bGUgY29tYmluYXRpb24gcG9seW5vbWlhbCBDMihYKVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIEMyIHBvbHlub21pYWxcIik7XG4gICAgICAgIGF3YWl0IGNvbXB1dGVDMigpO1xuXG4gICAgICAgIC8vIFRoZSBzZWNvbmQgb3V0cHV0IG9mIHRoZSBwcm92ZXIgaXMgKFtDMl1fMSlcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBDMiBtdWx0aSBleHBvbmVudGlhdGlvblwiKTtcbiAgICAgICAgbGV0IGNvbW1pdEMyID0gYXdhaXQgcG9seW5vbWlhbHMuQzIubXVsdGlFeHBvbmVudGlhdGlvbihQVGF1LCBcIkMyXCIpO1xuICAgICAgICBwcm9vZi5hZGRQb2x5bm9taWFsKFwiQzJcIiwgY29tbWl0QzIpO1xuXG4gICAgICAgIHJldHVybiAwO1xuXG4gICAgICAgIGFzeW5jIGZ1bmN0aW9uIGNvbXB1dGVaKCkge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCLCt8K3wrcgQ29tcHV0aW5nIFogZXZhbHVhdGlvbnNcIik7XG5cbiAgICAgICAgICAgIGxldCBudW1BcnIgPSBuZXcgQmlnQnVmZmVyKHNEb21haW4pO1xuICAgICAgICAgICAgbGV0IGRlbkFyciA9IG5ldyBCaWdCdWZmZXIoc0RvbWFpbik7XG5cbiAgICAgICAgICAgIC8vIFNldCB0aGUgZmlyc3QgdmFsdWVzIHRvIDFcbiAgICAgICAgICAgIG51bUFyci5zZXQoRnIub25lLCAwKTtcbiAgICAgICAgICAgIGRlbkFyci5zZXQoRnIub25lLCAwKTtcblxuICAgICAgICAgICAgLy8gU2V0IGluaXRpYWwgb21lZ2FcbiAgICAgICAgICAgIGxldCB3ID0gRnIub25lO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB6a2V5LmRvbWFpblNpemU7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmIChsb2dnZXIgJiYgKDAgIT09IGkpICYmIChpICUgMTAwMDAwID09PSAwKSkgbG9nZ2VyLmluZm8oYCAgICBaIGV2YWx1YXRpb24gJHtpfS8ke3prZXkuZG9tYWluU2l6ZX1gKTtcbiAgICAgICAgICAgICAgICBjb25zdCBpX3NGciA9IGkgKiBzRnI7XG5cbiAgICAgICAgICAgICAgICAvLyBaKFgpIDo9IG51bUFyciAvIGRlbkFyclxuICAgICAgICAgICAgICAgIC8vIG51bUFyciA6PSAoYSArIGJldGHCt8+JICsgZ2FtbWEpKGIgKyBiZXRhwrfPicK3azEgKyBnYW1tYSkoYyArIGJldGHCt8+JwrdrMiArIGdhbW1hKVxuICAgICAgICAgICAgICAgIGNvbnN0IGJldGF3ID0gRnIubXVsKGNoYWxsZW5nZXMuYmV0YSwgdyk7XG5cbiAgICAgICAgICAgICAgICBsZXQgbnVtMSA9IGJ1ZmZlcnMuQS5zbGljZShpX3NGciwgaV9zRnIgKyBzRnIpO1xuICAgICAgICAgICAgICAgIG51bTEgPSBGci5hZGQobnVtMSwgYmV0YXcpO1xuICAgICAgICAgICAgICAgIG51bTEgPSBGci5hZGQobnVtMSwgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgICAgICAgICBsZXQgbnVtMiA9IGJ1ZmZlcnMuQi5zbGljZShpX3NGciwgaV9zRnIgKyBzRnIpO1xuICAgICAgICAgICAgICAgIG51bTIgPSBGci5hZGQobnVtMiwgRnIubXVsKHprZXkuazEsIGJldGF3KSk7XG4gICAgICAgICAgICAgICAgbnVtMiA9IEZyLmFkZChudW0yLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICAgICAgICAgIGxldCBudW0zID0gYnVmZmVycy5DLnNsaWNlKGlfc0ZyLCBpX3NGciArIHNGcik7XG4gICAgICAgICAgICAgICAgbnVtMyA9IEZyLmFkZChudW0zLCBGci5tdWwoemtleS5rMiwgYmV0YXcpKTtcbiAgICAgICAgICAgICAgICBudW0zID0gRnIuYWRkKG51bTMsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgICAgICAgICAgICAgbGV0IG51bSA9IEZyLm11bChudW0xLCBGci5tdWwobnVtMiwgbnVtMykpO1xuXG4gICAgICAgICAgICAgICAgLy8gZGVuQXJyIDo9IChhICsgYmV0YcK3c2lnbWExICsgZ2FtbWEpKGIgKyBiZXRhwrdzaWdtYTIgKyBnYW1tYSkoYyArIGJldGHCt3NpZ21hMyArIGdhbW1hKVxuICAgICAgICAgICAgICAgIGxldCBkZW4xID0gYnVmZmVycy5BLnNsaWNlKGlfc0ZyLCBpX3NGciArIHNGcik7XG4gICAgICAgICAgICAgICAgZGVuMSA9IEZyLmFkZChkZW4xLCBGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCBldmFsdWF0aW9ucy5TaWdtYTEuZ2V0RXZhbHVhdGlvbihpICogNCkpKTtcbiAgICAgICAgICAgICAgICBkZW4xID0gRnIuYWRkKGRlbjEsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgICAgICAgICAgICAgbGV0IGRlbjIgPSBidWZmZXJzLkIuc2xpY2UoaV9zRnIsIGlfc0ZyICsgc0ZyKTtcbiAgICAgICAgICAgICAgICBkZW4yID0gRnIuYWRkKGRlbjIsIEZyLm11bChjaGFsbGVuZ2VzLmJldGEsIGV2YWx1YXRpb25zLlNpZ21hMi5nZXRFdmFsdWF0aW9uKGkgKiA0KSkpO1xuICAgICAgICAgICAgICAgIGRlbjIgPSBGci5hZGQoZGVuMiwgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgICAgICAgICBsZXQgZGVuMyA9IGJ1ZmZlcnMuQy5zbGljZShpX3NGciwgaV9zRnIgKyBzRnIpO1xuICAgICAgICAgICAgICAgIGRlbjMgPSBGci5hZGQoZGVuMywgRnIubXVsKGNoYWxsZW5nZXMuYmV0YSwgZXZhbHVhdGlvbnMuU2lnbWEzLmdldEV2YWx1YXRpb24oaSAqIDQpKSk7XG4gICAgICAgICAgICAgICAgZGVuMyA9IEZyLmFkZChkZW4zLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICAgICAgICAgIGxldCBkZW4gPSBGci5tdWwoZGVuMSwgRnIubXVsKGRlbjIsIGRlbjMpKTtcblxuICAgICAgICAgICAgICAgIC8vIE11bHRpcGx5IGN1cnJlbnQgbnVtIHZhbHVlIHdpdGggdGhlIHByZXZpb3VzIG9uZSBzYXZlZCBpbiBudW1BcnJcbiAgICAgICAgICAgICAgICBudW0gPSBGci5tdWwobnVtQXJyLnNsaWNlKGlfc0ZyLCBpX3NGciArIHNGciksIG51bSk7XG4gICAgICAgICAgICAgICAgbnVtQXJyLnNldChudW0sICgoaSArIDEpICUgemtleS5kb21haW5TaXplKSAqIHNGcik7XG5cbiAgICAgICAgICAgICAgICAvLyBNdWx0aXBseSBjdXJyZW50IGRlbiB2YWx1ZSB3aXRoIHRoZSBwcmV2aW91cyBvbmUgc2F2ZWQgaW4gZGVuQXJyXG4gICAgICAgICAgICAgICAgZGVuID0gRnIubXVsKGRlbkFyci5zbGljZShpX3NGciwgaV9zRnIgKyBzRnIpLCBkZW4pO1xuICAgICAgICAgICAgICAgIGRlbkFyci5zZXQoZGVuLCAoKGkgKyAxKSAlIHprZXkuZG9tYWluU2l6ZSkgKiBzRnIpO1xuXG4gICAgICAgICAgICAgICAgLy8gTmV4dCBvbWVnYVxuICAgICAgICAgICAgICAgIHcgPSBGci5tdWwodywgRnIud1t6a2V5LnBvd2VyXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBDb21wdXRlIHRoZSBpbnZlcnNlIG9mIGRlbkFyciB0byBjb21wdXRlIGluIHRoZSBuZXh0IGNvbW1hbmQgdGhlXG4gICAgICAgICAgICAvLyBkaXZpc2lvbiBudW1BcnIvZGVuQXJyIGJ5IG11bHRpcGx5aW5nIG51bSDCtyAxL2RlbkFyclxuICAgICAgICAgICAgZGVuQXJyID0gYXdhaXQgRnIuYmF0Y2hJbnZlcnNlKGRlbkFycik7XG5cbiAgICAgICAgICAgIC8vIFRPRE86IERvIGl0IGluIGFzc2VtYmx5IGFuZCBpbiBwYXJhbGxlbFxuICAgICAgICAgICAgLy8gTXVsdGlwbHkgbnVtQXJyIMK3IGRlbkFyciB3aGVyZSBkZW5BcnIgd2FzIGludmVydGVkIGluIHRoZSBwcmV2aW91cyBjb21tYW5kXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHprZXkuZG9tYWluU2l6ZTsgaSsrKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaV9zRnIgPSBpICogc0ZyO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgeiA9IEZyLm11bChudW1BcnIuc2xpY2UoaV9zRnIsIGlfc0ZyICsgc0ZyKSwgZGVuQXJyLnNsaWNlKGlfc0ZyLCBpX3NGciArIHNGcikpO1xuICAgICAgICAgICAgICAgIG51bUFyci5zZXQoeiwgaV9zRnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRnJvbSBub3cgb24gdGhlIHZhbHVlcyBzYXZlZCBvbiBudW1BcnIgd2lsbCBiZSBaKFgpIGJ1ZmZlclxuICAgICAgICAgICAgYnVmZmVycy5aID0gbnVtQXJyO1xuXG4gICAgICAgICAgICBpZiAoIUZyLmVxKG51bUFyci5zbGljZSgwLCBzRnIpLCBGci5vbmUpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29weSBjb25zdHJhaW50cyBkb2VzIG5vdCBtYXRjaFwiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ29tcHV0ZSBwb2x5bm9taWFsIGNvZWZmaWNpZW50cyB6KFgpIGZyb20gYnVmZmVycy5aXG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgWiBpZmZ0XCIpO1xuICAgICAgICAgICAgcG9seW5vbWlhbHMuWiA9IGF3YWl0IFBvbHlub21pYWwuZnJvbUV2YWx1YXRpb25zKGJ1ZmZlcnMuWiwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICAgICAgICAgIC8vIENvbXB1dGUgZXh0ZW5kZWQgZXZhbHVhdGlvbnMgb2YgeihYKSBwb2x5bm9taWFsXG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgWiBmZnRcIik7XG4gICAgICAgICAgICBldmFsdWF0aW9ucy5aID0gYXdhaXQgRXZhbHVhdGlvbnMuZnJvbVBvbHlub21pYWwocG9seW5vbWlhbHMuWiwgNCwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICAgICAgICAgIC8vIEJsaW5kIHooWCkgcG9seW5vbWlhbCBjb2VmZmljaWVudHMgd2l0aCBibGluZGluZyBzY2FsYXJzIGJcbiAgICAgICAgICAgIHBvbHlub21pYWxzLlouYmxpbmRDb2VmZmljaWVudHMoW2NoYWxsZW5nZXMuYls5XSwgY2hhbGxlbmdlcy5iWzhdLCBjaGFsbGVuZ2VzLmJbN11dKTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgZGVncmVlXG4gICAgICAgICAgICBpZiAocG9seW5vbWlhbHMuWi5kZWdyZWUoKSA+PSB6a2V5LmRvbWFpblNpemUgKyAzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiWiBQb2x5bm9taWFsIGlzIG5vdCB3ZWxsIGNhbGN1bGF0ZWRcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGRlbGV0ZSBidWZmZXJzLlo7XG4gICAgICAgIH1cblxuICAgICAgICBhc3luYyBmdW5jdGlvbiBjb21wdXRlVDEoKSB7XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgVDEgZXZhbHVhdGlvbnNcIik7XG5cbiAgICAgICAgICAgIGJ1ZmZlcnMuVDEgPSBuZXcgQmlnQnVmZmVyKHNEb21haW4gKiAyKTtcbiAgICAgICAgICAgIGJ1ZmZlcnMuVDF6ID0gbmV3IEJpZ0J1ZmZlcihzRG9tYWluICogMik7XG5cbiAgICAgICAgICAgIC8vIFNldCBpbml0aWFsIG9tZWdhXG4gICAgICAgICAgICBsZXQgb21lZ2EgPSBGci5vbmU7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHprZXkuZG9tYWluU2l6ZSAqIDI7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmIChsb2dnZXIgJiYgKDAgIT09IGkpICYmIChpICUgMTAwMDAwID09PSAwKSkgbG9nZ2VyLmluZm8oYCAgICBUMSBldmFsdWF0aW9uICR7aX0vJHt6a2V5LmRvbWFpblNpemUgKiA0fWApO1xuXG4gICAgICAgICAgICAgICAgY29uc3Qgb21lZ2EyID0gRnIuc3F1YXJlKG9tZWdhKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHogPSBldmFsdWF0aW9ucy5aLmdldEV2YWx1YXRpb24oaSAqIDIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHpwID0gRnIuYWRkKEZyLmFkZChGci5tdWwoY2hhbGxlbmdlcy5iWzddLCBvbWVnYTIpLCBGci5tdWwoY2hhbGxlbmdlcy5iWzhdLCBvbWVnYSkpLCBjaGFsbGVuZ2VzLmJbOV0pO1xuXG4gICAgICAgICAgICAgICAgLy8gVDEoWCkgOj0gKHooWCkgLSAxKSDCtyBMXzEoWClcbiAgICAgICAgICAgICAgICAvLyBDb21wdXRlIGZpcnN0IFQxKFgpwrdaX0goWCksIHNvIGRpdmlkZSBsYXRlciB0aGUgcmVzdWx0aW5nIHBvbHlub21pYWwgYnkgWl9IKFgpXG4gICAgICAgICAgICAgICAgY29uc3QgbGFncmFuZ2UxID0gZXZhbHVhdGlvbnMubGFncmFuZ2UxLmdldEV2YWx1YXRpb24oemtleS5kb21haW5TaXplICsgaSAqIDIpO1xuICAgICAgICAgICAgICAgIGxldCB0MSA9IEZyLm11bChGci5zdWIoeiwgRnIub25lKSwgbGFncmFuZ2UxKTtcbiAgICAgICAgICAgICAgICBsZXQgdDF6ID0gRnIubXVsKHpwLCBsYWdyYW5nZTEpO1xuXG4gICAgICAgICAgICAgICAgYnVmZmVycy5UMS5zZXQodDEsIGkgKiBzRnIpO1xuICAgICAgICAgICAgICAgIGJ1ZmZlcnMuVDF6LnNldCh0MXosIGkgKiBzRnIpO1xuXG4gICAgICAgICAgICAgICAgLy8gQ29tcHV0ZSBuZXh0IG9tZWdhXG4gICAgICAgICAgICAgICAgb21lZ2EgPSBGci5tdWwob21lZ2EsIEZyLndbemtleS5wb3dlciArIDFdKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ29tcHV0ZSB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBwb2x5bm9taWFsIFQxKFgpIGZyb20gYnVmZmVycy5UMVxuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCLCt8K3wrcgQ29tcHV0aW5nIFQxIGlmZnRcIik7XG4gICAgICAgICAgICBwb2x5bm9taWFscy5UMSA9IGF3YWl0IFBvbHlub21pYWwuZnJvbUV2YWx1YXRpb25zKGJ1ZmZlcnMuVDEsIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgICAgICAgICAvLyBEaXZpZGUgdGhlIHBvbHlub21pYWwgVDEgYnkgWl9IKFgpXG4gICAgICAgICAgICBwb2x5bm9taWFscy5UMS5kaXZCeVplcm9maWVyKHprZXkuZG9tYWluU2l6ZSwgRnIub25lKTtcblxuICAgICAgICAgICAgLy8gQ29tcHV0ZSB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBwb2x5bm9taWFsIFQxeihYKSBmcm9tIGJ1ZmZlcnMuVDF6XG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgVDF6IGlmZnRcIik7XG4gICAgICAgICAgICBwb2x5bm9taWFscy5UMXogPSBhd2FpdCBQb2x5bm9taWFsLmZyb21FdmFsdWF0aW9ucyhidWZmZXJzLlQxeiwgY3VydmUsIGxvZ2dlcik7XG5cbiAgICAgICAgICAgIC8vIEFkZCB0aGUgcG9seW5vbWlhbCBUMXogdG8gVDEgdG8gZ2V0IHRoZSBmaW5hbCBwb2x5bm9taWFsIFQxXG4gICAgICAgICAgICBwb2x5bm9taWFscy5UMS5hZGQocG9seW5vbWlhbHMuVDF6KTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgZGVncmVlXG4gICAgICAgICAgICBpZiAocG9seW5vbWlhbHMuVDEuZGVncmVlKCkgPj0gemtleS5kb21haW5TaXplICsgMikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlQxIFBvbHlub21pYWwgaXMgbm90IHdlbGwgY2FsY3VsYXRlZFwiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZGVsZXRlIGJ1ZmZlcnMuVDE7XG4gICAgICAgICAgICBkZWxldGUgYnVmZmVycy5UMXo7XG4gICAgICAgICAgICBkZWxldGUgcG9seW5vbWlhbHMuVDF6O1xuICAgICAgICB9XG5cbiAgICAgICAgYXN5bmMgZnVuY3Rpb24gY29tcHV0ZVQyKCkge1xuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCLCt8K3wrcgQ29tcHV0aW5nIFQyIGV2YWx1YXRpb25zXCIpO1xuXG4gICAgICAgICAgICBidWZmZXJzLlQyID0gbmV3IEJpZ0J1ZmZlcihzRG9tYWluICogNCk7XG4gICAgICAgICAgICBidWZmZXJzLlQyeiA9IG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDQpO1xuXG4gICAgICAgICAgICAvLyBTZXQgaW5pdGlhbCBvbWVnYVxuICAgICAgICAgICAgbGV0IG9tZWdhID0gRnIub25lO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB6a2V5LmRvbWFpblNpemUgKiA0OyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAobG9nZ2VyICYmICgwICE9PSBpKSAmJiAoaSAlIDEwMDAwMCA9PT0gMCkpIGxvZ2dlci5pbmZvKGAgICAgVDIgZXZhbHVhdGlvbiAke2l9LyR7emtleS5kb21haW5TaXplICogNH1gKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IG9tZWdhMiA9IEZyLnNxdWFyZShvbWVnYSk7XG4gICAgICAgICAgICAgICAgY29uc3Qgb21lZ2FXID0gRnIubXVsKG9tZWdhLCBGci53W3prZXkucG93ZXJdKTtcbiAgICAgICAgICAgICAgICBjb25zdCBvbWVnYVcyID0gRnIuc3F1YXJlKG9tZWdhVyk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBhID0gZXZhbHVhdGlvbnMuQS5nZXRFdmFsdWF0aW9uKGkpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGIgPSBldmFsdWF0aW9ucy5CLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICAgICAgY29uc3QgYyA9IGV2YWx1YXRpb25zLkMuZ2V0RXZhbHVhdGlvbihpKTtcbiAgICAgICAgICAgICAgICBjb25zdCB6ID0gZXZhbHVhdGlvbnMuWi5nZXRFdmFsdWF0aW9uKGkpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHpXID0gZXZhbHVhdGlvbnMuWi5nZXRFdmFsdWF0aW9uKCh6a2V5LmRvbWFpblNpemUgKiA0ICsgNCArIGkpICUgKHprZXkuZG9tYWluU2l6ZSAqIDQpKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHpwID0gRnIuYWRkKEZyLmFkZChGci5tdWwoY2hhbGxlbmdlcy5iWzddLCBvbWVnYTIpLCBGci5tdWwoY2hhbGxlbmdlcy5iWzhdLCBvbWVnYSkpLCBjaGFsbGVuZ2VzLmJbOV0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IHpXcCA9IEZyLmFkZChGci5hZGQoRnIubXVsKGNoYWxsZW5nZXMuYls3XSwgb21lZ2FXMiksIEZyLm11bChjaGFsbGVuZ2VzLmJbOF0sIG9tZWdhVykpLCBjaGFsbGVuZ2VzLmJbOV0pO1xuXG4gICAgICAgICAgICAgICAgY29uc3Qgc2lnbWExID0gZXZhbHVhdGlvbnMuU2lnbWExLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICAgICAgY29uc3Qgc2lnbWEyID0gZXZhbHVhdGlvbnMuU2lnbWEyLmdldEV2YWx1YXRpb24oaSk7XG4gICAgICAgICAgICAgICAgY29uc3Qgc2lnbWEzID0gZXZhbHVhdGlvbnMuU2lnbWEzLmdldEV2YWx1YXRpb24oaSk7XG5cbiAgICAgICAgICAgICAgICAvLyBUMihYKSA6PSBbIChhKFgpICsgYmV0YcK3WCArIGdhbW1hKShiKFgpICsgYmV0YcK3azHCt1ggKyBnYW1tYSkoYyhYKSArIGJldGHCt2sywrdYICsgZ2FtbWEpeihYKVxuICAgICAgICAgICAgICAgIC8vICAgICAgICAgICAtKGEoWCkgKyBiZXRhwrdzaWdtYTEoWCkgKyBnYW1tYSkoYihYKSArIGJldGHCt3NpZ21hMihYKSArIGdhbW1hKShjKFgpICsgYmV0YcK3c2lnbWEzKFgpICsgZ2FtbWEpeihYz4kpXSDCtyAxL1pfSChYKVxuICAgICAgICAgICAgICAgIC8vIENvbXB1dGUgZmlyc3QgVDIoWCnCt1pfSChYKSwgc28gZGl2aWRlIGxhdGVyIHRoZSByZXN1bHRpbmcgcG9seW5vbWlhbCBieSBaX0goWClcblxuICAgICAgICAgICAgICAgIC8vIGV4cHJlc3Npb24gMSAtPiAoYShYKSArIGJldGHCt1ggKyBnYW1tYSkoYihYKSArIGJldGHCt2sxwrdYICsgZ2FtbWEpKGMoWCkgKyBiZXRhwrdrMsK3WCArIGdhbW1hKXooWClcbiAgICAgICAgICAgICAgICBjb25zdCBiZXRhWCA9IEZyLm11bChjaGFsbGVuZ2VzLmJldGEsIG9tZWdhKTtcblxuICAgICAgICAgICAgICAgIGxldCBlMTEgPSBGci5hZGQoYSwgYmV0YVgpO1xuICAgICAgICAgICAgICAgIGUxMSA9IEZyLmFkZChlMTEsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgICAgICAgICAgICAgbGV0IGUxMiA9IEZyLmFkZChiLCBGci5tdWwoYmV0YVgsIHprZXkuazEpKTtcbiAgICAgICAgICAgICAgICBlMTIgPSBGci5hZGQoZTEyLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICAgICAgICAgIGxldCBlMTMgPSBGci5hZGQoYywgRnIubXVsKGJldGFYLCB6a2V5LmsyKSk7XG4gICAgICAgICAgICAgICAgZTEzID0gRnIuYWRkKGUxMywgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgICAgICAgICBsZXQgZTEgPSBGci5tdWwoRnIubXVsKEZyLm11bChlMTEsIGUxMiksIGUxMyksIHopO1xuICAgICAgICAgICAgICAgIGxldCBlMXogPSBGci5tdWwoRnIubXVsKEZyLm11bChlMTEsIGUxMiksIGUxMyksIHpwKTtcbiAgICAgICAgICAgICAgICAvLyBjb25zdCBbZTEsIGUxel0gPSBNdWxaLm11bDQoZTExLCBlMTIsIGUxMywgeiwgYXAsIGJwLCBjcCwgenAsIGkgJSA0LCBGcik7XG5cbiAgICAgICAgICAgICAgICAvLyBleHByZXNzaW9uIDIgLT4gKGEoWCkgKyBiZXRhwrdzaWdtYTEoWCkgKyBnYW1tYSkoYihYKSArIGJldGHCt3NpZ21hMihYKSArIGdhbW1hKShjKFgpICsgYmV0YcK3c2lnbWEzKFgpICsgZ2FtbWEpeihYz4kpXG4gICAgICAgICAgICAgICAgbGV0IGUyMSA9IEZyLmFkZChhLCBGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCBzaWdtYTEpKTtcbiAgICAgICAgICAgICAgICBlMjEgPSBGci5hZGQoZTIxLCBjaGFsbGVuZ2VzLmdhbW1hKTtcblxuICAgICAgICAgICAgICAgIGxldCBlMjIgPSBGci5hZGQoYiwgRnIubXVsKGNoYWxsZW5nZXMuYmV0YSwgc2lnbWEyKSk7XG4gICAgICAgICAgICAgICAgZTIyID0gRnIuYWRkKGUyMiwgY2hhbGxlbmdlcy5nYW1tYSk7XG5cbiAgICAgICAgICAgICAgICBsZXQgZTIzID0gRnIuYWRkKGMsIEZyLm11bChjaGFsbGVuZ2VzLmJldGEsIHNpZ21hMykpO1xuICAgICAgICAgICAgICAgIGUyMyA9IEZyLmFkZChlMjMsIGNoYWxsZW5nZXMuZ2FtbWEpO1xuXG4gICAgICAgICAgICAgICAgbGV0IGUyID0gRnIubXVsKEZyLm11bChGci5tdWwoZTIxLCBlMjIpLCBlMjMpLCB6Vyk7XG4gICAgICAgICAgICAgICAgbGV0IGUyeiA9IEZyLm11bChGci5tdWwoRnIubXVsKGUyMSwgZTIyKSwgZTIzKSwgeldwKTtcbiAgICAgICAgICAgICAgICAvLyBjb25zdCBbZTIsIGUyel0gPSBNdWxaLm11bDQoZTIxLCBlMjIsIGUyMywgelcsIGFwLCBicCwgY3AsIHpXcCwgaSAlIDQsIEZyKTtcblxuICAgICAgICAgICAgICAgIGxldCB0MiA9IEZyLnN1YihlMSwgZTIpO1xuICAgICAgICAgICAgICAgIGxldCB0MnogPSBGci5zdWIoZTF6LCBlMnopO1xuXG4gICAgICAgICAgICAgICAgYnVmZmVycy5UMi5zZXQodDIsIGkgKiBzRnIpO1xuICAgICAgICAgICAgICAgIGJ1ZmZlcnMuVDJ6LnNldCh0MnosIGkgKiBzRnIpO1xuXG4gICAgICAgICAgICAgICAgLy8gQ29tcHV0ZSBuZXh0IG9tZWdhXG4gICAgICAgICAgICAgICAgb21lZ2EgPSBGci5tdWwob21lZ2EsIEZyLndbemtleS5wb3dlciArIDJdKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ29tcHV0ZSB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBwb2x5bm9taWFsIFQyKFgpIGZyb20gYnVmZmVycy5UMlxuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCLCt8K3wrcgQ29tcHV0aW5nIFQyIGlmZnRcIik7XG4gICAgICAgICAgICBwb2x5bm9taWFscy5UMiA9IGF3YWl0IFBvbHlub21pYWwuZnJvbUV2YWx1YXRpb25zKGJ1ZmZlcnMuVDIsIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgICAgICAgICAvLyBEaXZpZGUgdGhlIHBvbHlub21pYWwgVDIgYnkgWl9IKFgpXG4gICAgICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgVDIgLyBaSFwiKTtcbiAgICAgICAgICAgIHBvbHlub21pYWxzLlQyLmRpdkJ5WmVyb2ZpZXIoemtleS5kb21haW5TaXplLCBGci5vbmUpO1xuXG4gICAgICAgICAgICAvLyBDb21wdXRlIHRoZSBjb2VmZmljaWVudHMgb2YgdGhlIHBvbHlub21pYWwgVDJ6KFgpIGZyb20gYnVmZmVycy5UMnpcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBUMnogaWZmdFwiKTtcbiAgICAgICAgICAgIHBvbHlub21pYWxzLlQyeiA9IGF3YWl0IFBvbHlub21pYWwuZnJvbUV2YWx1YXRpb25zKGJ1ZmZlcnMuVDJ6LCBjdXJ2ZSwgbG9nZ2VyKTtcblxuICAgICAgICAgICAgLy8gQWRkIHRoZSBwb2x5bm9taWFsIFQyeiB0byBUMiB0byBnZXQgdGhlIGZpbmFsIHBvbHlub21pYWwgVDJcbiAgICAgICAgICAgIHBvbHlub21pYWxzLlQyLmFkZChwb2x5bm9taWFscy5UMnopO1xuXG4gICAgICAgICAgICAvLyBDaGVjayBkZWdyZWVcbiAgICAgICAgICAgIGlmIChwb2x5bm9taWFscy5UMi5kZWdyZWUoKSA+PSAzICogemtleS5kb21haW5TaXplKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVDIgUG9seW5vbWlhbCBpcyBub3Qgd2VsbCBjYWxjdWxhdGVkXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBkZWxldGUgYnVmZmVycy5UMjtcbiAgICAgICAgICAgIGRlbGV0ZSBidWZmZXJzLlQyejtcbiAgICAgICAgICAgIGRlbGV0ZSBwb2x5bm9taWFscy5UMno7XG4gICAgICAgIH1cblxuICAgICAgICBhc3luYyBmdW5jdGlvbiBjb21wdXRlQzIoKSB7XG4gICAgICAgICAgICBsZXQgQzIgPSBuZXcgQ1BvbHlub21pYWwoMywgY3VydmUsIGxvZ2dlcik7XG4gICAgICAgICAgICBDMi5hZGRQb2x5bm9taWFsKDAsIHBvbHlub21pYWxzLlopO1xuICAgICAgICAgICAgQzIuYWRkUG9seW5vbWlhbCgxLCBwb2x5bm9taWFscy5UMSk7XG4gICAgICAgICAgICBDMi5hZGRQb2x5bm9taWFsKDIsIHBvbHlub21pYWxzLlQyKTtcblxuICAgICAgICAgICAgcG9seW5vbWlhbHMuQzIgPSBDMi5nZXRQb2x5bm9taWFsKCk7XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGRlZ3JlZVxuICAgICAgICAgICAgaWYgKHBvbHlub21pYWxzLkMyLmRlZ3JlZSgpID49IDkgKiB6a2V5LmRvbWFpblNpemUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDMiBQb2x5bm9taWFsIGlzIG5vdCB3ZWxsIGNhbGN1bGF0ZWRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiByb3VuZDMoKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBDb21wdXRpbmcgY2hhbGxlbmdlIHhpXCIpO1xuICAgICAgICAvLyBTVEVQIDMuMSAtIENvbXB1dGUgZXZhbHVhdGlvbiBjaGFsbGVuZ2UgeGkg4oiIIFNcbiAgICAgICAgY29uc3QgdHJhbnNjcmlwdCA9IG5ldyBLZWNjYWsyNTZUcmFuc2NyaXB0KGN1cnZlKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIoY2hhbGxlbmdlcy5nYW1tYSk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5nZXRQb2x5bm9taWFsKFwiQzJcIikpO1xuXG4gICAgICAgIC8vIE9idGFpbiBhIHhpX3NlZWRlciBmcm9tIHRoZSB0cmFuc2NyaXB0XG4gICAgICAgIC8vIFRvIGZvcmNlIGgxXjQgPSB4aSwgaDJeMyA9IHhpIGFuZCBoXzNeMiA9IHhpz4lcbiAgICAgICAgLy8gd2UgY29tcHV0ZSB4aSA9IHhpX3NlZWRlcl4xMiwgaDEgPSB4aV9zZWVkZXJeMywgaDIgPSB4aV9zZWVkZXJeNCBhbmQgaDMgPSB4aV9zZWVkZXJeNlxuICAgICAgICBjaGFsbGVuZ2VzLnhpU2VlZCA9IHRyYW5zY3JpcHQuZ2V0Q2hhbGxlbmdlKCk7XG4gICAgICAgIGNvbnN0IHhpU2VlZDIgPSBGci5zcXVhcmUoY2hhbGxlbmdlcy54aVNlZWQpO1xuXG4gICAgICAgIC8vIENvbXB1dGUgb21lZ2E4LCBvbWVnYTQgYW5kIG9tZWdhM1xuICAgICAgICByb290cy53OCA9IFtdO1xuICAgICAgICByb290cy53OFswXSA9IEZyLm9uZTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPCA4OyBpKyspIHtcbiAgICAgICAgICAgIHJvb3RzLnc4W2ldID0gRnIubXVsKHJvb3RzLnc4W2kgLSAxXSwgemtleS53OCk7XG4gICAgICAgIH1cblxuICAgICAgICByb290cy53NCA9IFtdO1xuICAgICAgICByb290cy53NFswXSA9IEZyLm9uZTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPCA0OyBpKyspIHtcbiAgICAgICAgICAgIHJvb3RzLnc0W2ldID0gRnIubXVsKHJvb3RzLnc0W2kgLSAxXSwgemtleS53NCk7XG4gICAgICAgIH1cblxuICAgICAgICByb290cy53MyA9IFtdO1xuICAgICAgICByb290cy53M1swXSA9IEZyLm9uZTtcbiAgICAgICAgcm9vdHMudzNbMV0gPSB6a2V5LnczO1xuICAgICAgICByb290cy53M1syXSA9IEZyLnNxdWFyZSh6a2V5LnczKTtcblxuICAgICAgICAvLyBDb21wdXRlIGgwID0geGlTZWVkZXJeM1xuICAgICAgICByb290cy5TMCA9IHt9O1xuICAgICAgICByb290cy5TMC5oMHc4ID0gW107XG4gICAgICAgIHJvb3RzLlMwLmgwdzhbMF0gPSBGci5tdWwoeGlTZWVkMiwgY2hhbGxlbmdlcy54aVNlZWQpO1xuICAgICAgICBmb3IgKGxldCBpID0gMTsgaSA8IDg7IGkrKykge1xuICAgICAgICAgICAgcm9vdHMuUzAuaDB3OFtpXSA9IEZyLm11bChyb290cy5TMC5oMHc4WzBdLCByb290cy53OFtpXSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDb21wdXRlIGgxID0geGlfc2VlZGVyXjZcbiAgICAgICAgcm9vdHMuUzEgPSB7fTtcbiAgICAgICAgcm9vdHMuUzEuaDF3NCA9IFtdO1xuICAgICAgICByb290cy5TMS5oMXc0WzBdID0gRnIuc3F1YXJlKHJvb3RzLlMwLmgwdzhbMF0pO1xuICAgICAgICBmb3IgKGxldCBpID0gMTsgaSA8IDQ7IGkrKykge1xuICAgICAgICAgICAgcm9vdHMuUzEuaDF3NFtpXSA9IEZyLm11bChyb290cy5TMS5oMXc0WzBdLCByb290cy53NFtpXSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDb21wdXRlIGgyID0geGlfc2VlZGVyXjhcbiAgICAgICAgcm9vdHMuUzIgPSB7fTtcbiAgICAgICAgcm9vdHMuUzIuaDJ3MyA9IFtdO1xuICAgICAgICByb290cy5TMi5oMnczWzBdID0gRnIubXVsKHJvb3RzLlMxLmgxdzRbMF0sIHhpU2VlZDIpO1xuICAgICAgICByb290cy5TMi5oMnczWzFdID0gRnIubXVsKHJvb3RzLlMyLmgydzNbMF0sIHJvb3RzLnczWzFdKTtcbiAgICAgICAgcm9vdHMuUzIuaDJ3M1syXSA9IEZyLm11bChyb290cy5TMi5oMnczWzBdLCByb290cy53M1syXSk7XG5cbiAgICAgICAgcm9vdHMuUzIuaDN3MyA9IFtdO1xuICAgICAgICAvLyBNdWx0aXBseSBoMyBieSB0aGlyZC1yb290LW9tZWdhIHRvIG9idGFpbiBoXzNeMyA9IHhpz4lcbiAgICAgICAgLy8gU28sIGgzID0geGlfc2VlZGVyXjggz4leezEvM31cbiAgICAgICAgcm9vdHMuUzIuaDN3M1swXSA9IEZyLm11bChyb290cy5TMi5oMnczWzBdLCB6a2V5LndyKTtcbiAgICAgICAgcm9vdHMuUzIuaDN3M1sxXSA9IEZyLm11bChyb290cy5TMi5oM3czWzBdLCByb290cy53M1sxXSk7XG4gICAgICAgIHJvb3RzLlMyLmgzdzNbMl0gPSBGci5tdWwocm9vdHMuUzIuaDN3M1swXSwgcm9vdHMudzNbMl0pO1xuXG4gICAgICAgIC8vIENvbXB1dGUgeGkgPSB4aV9zZWVkZXJeMjRcbiAgICAgICAgY2hhbGxlbmdlcy54aSA9IEZyLm11bChGci5zcXVhcmUocm9vdHMuUzIuaDJ3M1swXSksIHJvb3RzLlMyLmgydzNbMF0pO1xuXG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IGNoYWxsZW5nZXMueGk6IFwiICsgRnIudG9TdHJpbmcoY2hhbGxlbmdlcy54aSkpO1xuXG4gICAgICAgIC8vIFJlc2VydmUgbWVtb3J5IGZvciBRJ3MgcG9seW5vbWlhbHNcbiAgICAgICAgcG9seW5vbWlhbHMuUUwgPSBuZXcgUG9seW5vbWlhbChuZXcgQmlnQnVmZmVyKHNEb21haW4pLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgcG9seW5vbWlhbHMuUVIgPSBuZXcgUG9seW5vbWlhbChuZXcgQmlnQnVmZmVyKHNEb21haW4pLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgcG9seW5vbWlhbHMuUU0gPSBuZXcgUG9seW5vbWlhbChuZXcgQmlnQnVmZmVyKHNEb21haW4pLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgcG9seW5vbWlhbHMuUU8gPSBuZXcgUG9seW5vbWlhbChuZXcgQmlnQnVmZmVyKHNEb21haW4pLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgcG9seW5vbWlhbHMuUUMgPSBuZXcgUG9seW5vbWlhbChuZXcgQmlnQnVmZmVyKHNEb21haW4pLCBjdXJ2ZSwgbG9nZ2VyKTtcblxuICAgICAgICAvLyBSZWFkIFEncyBldmFsdWF0aW9ucyBmcm9tIHprZXkgZmlsZVxuICAgICAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKHBvbHlub21pYWxzLlFMLmNvZWYsIDAsIHNEb21haW4sIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FMX1NFQ1RJT05dWzBdLnApO1xuICAgICAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKHBvbHlub21pYWxzLlFSLmNvZWYsIDAsIHNEb21haW4sIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FSX1NFQ1RJT05dWzBdLnApO1xuICAgICAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKHBvbHlub21pYWxzLlFNLmNvZWYsIDAsIHNEb21haW4sIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FNX1NFQ1RJT05dWzBdLnApO1xuICAgICAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKHBvbHlub21pYWxzLlFPLmNvZWYsIDAsIHNEb21haW4sIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FPX1NFQ1RJT05dWzBdLnApO1xuICAgICAgICBhd2FpdCBmZFpLZXkucmVhZFRvQnVmZmVyKHBvbHlub21pYWxzLlFDLmNvZWYsIDAsIHNEb21haW4sIHprZXlTZWN0aW9uc1taS0VZX0ZGX1FDX1NFQ1RJT05dWzBdLnApO1xuXG4gICAgICAgIC8vIFNURVAgMy4yIC0gQ29tcHV0ZSBvcGVuaW5nIGV2YWx1YXRpb25zIGFuZCBhZGQgdGhlbSB0byB0aGUgcHJvb2YgKHRoaXJkIG91dHB1dCBvZiB0aGUgcHJvdmVyKVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgZXZhbHVhdGlvbnNcIik7XG4gICAgICAgIHByb29mLmFkZEV2YWx1YXRpb24oXCJxbFwiLCBwb2x5bm9taWFscy5RTC5ldmFsdWF0ZShjaGFsbGVuZ2VzLnhpKSk7XG4gICAgICAgIHByb29mLmFkZEV2YWx1YXRpb24oXCJxclwiLCBwb2x5bm9taWFscy5RUi5ldmFsdWF0ZShjaGFsbGVuZ2VzLnhpKSk7XG4gICAgICAgIHByb29mLmFkZEV2YWx1YXRpb24oXCJxbVwiLCBwb2x5bm9taWFscy5RTS5ldmFsdWF0ZShjaGFsbGVuZ2VzLnhpKSk7XG4gICAgICAgIHByb29mLmFkZEV2YWx1YXRpb24oXCJxb1wiLCBwb2x5bm9taWFscy5RTy5ldmFsdWF0ZShjaGFsbGVuZ2VzLnhpKSk7XG4gICAgICAgIHByb29mLmFkZEV2YWx1YXRpb24oXCJxY1wiLCBwb2x5bm9taWFscy5RQy5ldmFsdWF0ZShjaGFsbGVuZ2VzLnhpKSk7XG4gICAgICAgIHByb29mLmFkZEV2YWx1YXRpb24oXCJzMVwiLCBwb2x5bm9taWFscy5TaWdtYTEuZXZhbHVhdGUoY2hhbGxlbmdlcy54aSkpO1xuICAgICAgICBwcm9vZi5hZGRFdmFsdWF0aW9uKFwiczJcIiwgcG9seW5vbWlhbHMuU2lnbWEyLmV2YWx1YXRlKGNoYWxsZW5nZXMueGkpKTtcbiAgICAgICAgcHJvb2YuYWRkRXZhbHVhdGlvbihcInMzXCIsIHBvbHlub21pYWxzLlNpZ21hMy5ldmFsdWF0ZShjaGFsbGVuZ2VzLnhpKSk7XG4gICAgICAgIHByb29mLmFkZEV2YWx1YXRpb24oXCJhXCIsIHBvbHlub21pYWxzLkEuZXZhbHVhdGUoY2hhbGxlbmdlcy54aSkpO1xuICAgICAgICBwcm9vZi5hZGRFdmFsdWF0aW9uKFwiYlwiLCBwb2x5bm9taWFscy5CLmV2YWx1YXRlKGNoYWxsZW5nZXMueGkpKTtcbiAgICAgICAgcHJvb2YuYWRkRXZhbHVhdGlvbihcImNcIiwgcG9seW5vbWlhbHMuQy5ldmFsdWF0ZShjaGFsbGVuZ2VzLnhpKSk7XG4gICAgICAgIHByb29mLmFkZEV2YWx1YXRpb24oXCJ6XCIsIHBvbHlub21pYWxzLlouZXZhbHVhdGUoY2hhbGxlbmdlcy54aSkpO1xuXG4gICAgICAgIGNoYWxsZW5nZXMueGl3ID0gRnIubXVsKGNoYWxsZW5nZXMueGksIEZyLndbemtleS5wb3dlcl0pO1xuICAgICAgICBwcm9vZi5hZGRFdmFsdWF0aW9uKFwiendcIiwgcG9seW5vbWlhbHMuWi5ldmFsdWF0ZShjaGFsbGVuZ2VzLnhpdykpO1xuICAgICAgICBwcm9vZi5hZGRFdmFsdWF0aW9uKFwidDF3XCIsIHBvbHlub21pYWxzLlQxLmV2YWx1YXRlKGNoYWxsZW5nZXMueGl3KSk7XG4gICAgICAgIHByb29mLmFkZEV2YWx1YXRpb24oXCJ0MndcIiwgcG9seW5vbWlhbHMuVDIuZXZhbHVhdGUoY2hhbGxlbmdlcy54aXcpKTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiByb3VuZDQoKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBDb21wdXRpbmcgY2hhbGxlbmdlIGFscGhhXCIpO1xuICAgICAgICAvLyBTVEVQIDQuMSAtIENvbXB1dGUgY2hhbGxlbmdlIGFscGhhIOKIiCBGXG4gICAgICAgIGNvbnN0IHRyYW5zY3JpcHQgPSBuZXcgS2VjY2FrMjU2VHJhbnNjcmlwdChjdXJ2ZSk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKGNoYWxsZW5nZXMueGlTZWVkKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInFsXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInFyXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInFtXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInFvXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInFjXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInMxXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInMyXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInMzXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcImFcIikpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5nZXRFdmFsdWF0aW9uKFwiYlwiKSk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHByb29mLmdldEV2YWx1YXRpb24oXCJjXCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInpcIikpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5nZXRFdmFsdWF0aW9uKFwiendcIikpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5nZXRFdmFsdWF0aW9uKFwidDF3XCIpKTtcbiAgICAgICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZ2V0RXZhbHVhdGlvbihcInQyd1wiKSk7XG4gICAgICAgIGNoYWxsZW5nZXMuYWxwaGEgPSB0cmFuc2NyaXB0LmdldENoYWxsZW5nZSgpO1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBjaGFsbGVuZ2VzLmFscGhhOiBcIiArIEZyLnRvU3RyaW5nKGNoYWxsZW5nZXMuYWxwaGEpKTtcblxuICAgICAgICAvLyBTVEVQIDQuMiAtIENvbXB1dGUgRihYKVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gUmVhZGluZyBDMCBwb2x5bm9taWFsXCIpO1xuICAgICAgICBwb2x5bm9taWFscy5DMCA9IG5ldyBQb2x5bm9taWFsKG5ldyBCaWdCdWZmZXIoc0RvbWFpbiAqIDgpLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgYXdhaXQgZmRaS2V5LnJlYWRUb0J1ZmZlcihwb2x5bm9taWFscy5DMC5jb2VmLCAwLCBzRG9tYWluICogOCwgemtleVNlY3Rpb25zW1pLRVlfRkZfQzBfU0VDVElPTl1bMF0ucCk7XG5cbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBSMCBwb2x5bm9taWFsXCIpO1xuICAgICAgICBjb21wdXRlUjAoKTtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBSMSBwb2x5bm9taWFsXCIpO1xuICAgICAgICBjb21wdXRlUjEoKTtcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBSMiBwb2x5bm9taWFsXCIpO1xuICAgICAgICBjb21wdXRlUjIoKTtcblxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIEYgcG9seW5vbWlhbFwiKTtcbiAgICAgICAgYXdhaXQgY29tcHV0ZUYoKTtcblxuICAgICAgICAvLyBUaGUgZm91cnRoIG91dHB1dCBvZiB0aGUgcHJvdmVyIGlzIChbVzFdXzEpLCB3aGVyZSBXMTo9KGYvWl90KSh4KVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIFcxIG11bHRpIGV4cG9uZW50aWF0aW9uXCIpO1xuICAgICAgICBsZXQgY29tbWl0VzEgPSBhd2FpdCBwb2x5bm9taWFscy5GLm11bHRpRXhwb25lbnRpYXRpb24oUFRhdSwgXCJXMVwiKTtcbiAgICAgICAgcHJvb2YuYWRkUG9seW5vbWlhbChcIlcxXCIsIGNvbW1pdFcxKTtcblxuICAgICAgICByZXR1cm4gMDtcblxuICAgICAgICBmdW5jdGlvbiBjb21wdXRlUjAoKSB7XG4gICAgICAgICAgICAvLyBDT01QVVRFIFIwXG4gICAgICAgICAgICAvLyBDb21wdXRlIHRoZSBjb2VmZmljaWVudHMgb2YgUjAoWCkgZnJvbSA4IGV2YWx1YXRpb25zIHVzaW5nIGxhZ3JhbmdlIGludGVycG9sYXRpb24uIFIwKFgpIOKIiCBGX3s8OH1bWF1cbiAgICAgICAgICAgIC8vIFdlIGRlY2lkZSB0byB1c2UgTGFncmFuZ2UgaW50ZXJwb2xhdGlvbnMgYmVjYXVzZSB0aGUgUjAgZGVncmVlIGlzIHZlcnkgc21hbGwgKGRlZyhSMCk9PT03KSxcbiAgICAgICAgICAgIC8vIGFuZCB3ZSB3ZXJlIG5vdCBhYmxlIHRvIGNvbXB1dGUgaXQgdXNpbmcgY3VycmVudCBpZmZ0IGltcGxlbWVudGF0aW9uIGJlY2F1c2UgdGhlIG9tZWdhIGFyZSBkaWZmZXJlbnRcbiAgICAgICAgICAgIHBvbHlub21pYWxzLlIwID0gUG9seW5vbWlhbC5sYWdyYW5nZVBvbHlub21pYWxJbnRlcnBvbGF0aW9uKFxuICAgICAgICAgICAgICAgIFtyb290cy5TMC5oMHc4WzBdLCByb290cy5TMC5oMHc4WzFdLCByb290cy5TMC5oMHc4WzJdLCByb290cy5TMC5oMHc4WzNdLFxuICAgICAgICAgICAgICAgICAgICByb290cy5TMC5oMHc4WzRdLCByb290cy5TMC5oMHc4WzVdLCByb290cy5TMC5oMHc4WzZdLCByb290cy5TMC5oMHc4WzddXSxcbiAgICAgICAgICAgICAgICBbcG9seW5vbWlhbHMuQzAuZXZhbHVhdGUocm9vdHMuUzAuaDB3OFswXSksIHBvbHlub21pYWxzLkMwLmV2YWx1YXRlKHJvb3RzLlMwLmgwdzhbMV0pLFxuICAgICAgICAgICAgICAgICAgICBwb2x5bm9taWFscy5DMC5ldmFsdWF0ZShyb290cy5TMC5oMHc4WzJdKSwgcG9seW5vbWlhbHMuQzAuZXZhbHVhdGUocm9vdHMuUzAuaDB3OFszXSksXG4gICAgICAgICAgICAgICAgICAgIHBvbHlub21pYWxzLkMwLmV2YWx1YXRlKHJvb3RzLlMwLmgwdzhbNF0pLCBwb2x5bm9taWFscy5DMC5ldmFsdWF0ZShyb290cy5TMC5oMHc4WzVdKSxcbiAgICAgICAgICAgICAgICAgICAgcG9seW5vbWlhbHMuQzAuZXZhbHVhdGUocm9vdHMuUzAuaDB3OFs2XSksIHBvbHlub21pYWxzLkMwLmV2YWx1YXRlKHJvb3RzLlMwLmgwdzhbN10pXSwgY3VydmUpO1xuXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZGVncmVlIG9mIHIwKFgpIDwgOFxuICAgICAgICAgICAgaWYgKHBvbHlub21pYWxzLlIwLmRlZ3JlZSgpID4gNykge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlIwIFBvbHlub21pYWwgaXMgbm90IHdlbGwgY2FsY3VsYXRlZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGNvbXB1dGVSMSgpIHtcbiAgICAgICAgICAgIC8vIENPTVBVVEUgUjFcbiAgICAgICAgICAgIC8vIENvbXB1dGUgdGhlIGNvZWZmaWNpZW50cyBvZiBSMShYKSBmcm9tIDQgZXZhbHVhdGlvbnMgdXNpbmcgbGFncmFuZ2UgaW50ZXJwb2xhdGlvbi4gUjEoWCkg4oiIIEZfezw0fVtYXVxuICAgICAgICAgICAgLy8gV2UgZGVjaWRlIHRvIHVzZSBMYWdyYW5nZSBpbnRlcnBvbGF0aW9ucyBiZWNhdXNlIHRoZSBSMSBkZWdyZWUgaXMgdmVyeSBzbWFsbCAoZGVnKFIxKT09PTMpLFxuICAgICAgICAgICAgLy8gYW5kIHdlIHdlcmUgbm90IGFibGUgdG8gY29tcHV0ZSBpdCB1c2luZyBjdXJyZW50IGlmZnQgaW1wbGVtZW50YXRpb24gYmVjYXVzZSB0aGUgb21lZ2EgYXJlIGRpZmZlcmVudFxuICAgICAgICAgICAgcG9seW5vbWlhbHMuUjEgPSBQb2x5bm9taWFsLmxhZ3JhbmdlUG9seW5vbWlhbEludGVycG9sYXRpb24oXG4gICAgICAgICAgICAgICAgW3Jvb3RzLlMxLmgxdzRbMF0sIHJvb3RzLlMxLmgxdzRbMV0sIHJvb3RzLlMxLmgxdzRbMl0sIHJvb3RzLlMxLmgxdzRbM11dLFxuICAgICAgICAgICAgICAgIFtwb2x5bm9taWFscy5DMS5ldmFsdWF0ZShyb290cy5TMS5oMXc0WzBdKSwgcG9seW5vbWlhbHMuQzEuZXZhbHVhdGUocm9vdHMuUzEuaDF3NFsxXSksXG4gICAgICAgICAgICAgICAgICAgIHBvbHlub21pYWxzLkMxLmV2YWx1YXRlKHJvb3RzLlMxLmgxdzRbMl0pLCBwb2x5bm9taWFscy5DMS5ldmFsdWF0ZShyb290cy5TMS5oMXc0WzNdKV0sIGN1cnZlKTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGRlZ3JlZSBvZiByMShYKSA8IDRcbiAgICAgICAgICAgIGlmIChwb2x5bm9taWFscy5SMS5kZWdyZWUoKSA+IDMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJSMSBQb2x5bm9taWFsIGlzIG5vdCB3ZWxsIGNhbGN1bGF0ZWRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBjb21wdXRlUjIoKSB7XG4gICAgICAgICAgICAvLyBDT01QVVRFIFIyXG4gICAgICAgICAgICAvLyBDb21wdXRlIHRoZSBjb2VmZmljaWVudHMgb2YgcjIoWCkgZnJvbSA2IGV2YWx1YXRpb25zIHVzaW5nIGxhZ3JhbmdlIGludGVycG9sYXRpb24uIHIyKFgpIOKIiCBGX3s8Nn1bWF1cbiAgICAgICAgICAgIC8vIFdlIGRlY2lkZSB0byB1c2UgTGFncmFuZ2UgaW50ZXJwb2xhdGlvbnMgYmVjYXVzZSB0aGUgUjIuZGVncmVlIGlzIHZlcnkgc21hbGwgKGRlZyhSMik9PT01KSxcbiAgICAgICAgICAgIC8vIGFuZCB3ZSB3ZXJlIG5vdCBhYmxlIHRvIGNvbXB1dGUgaXQgdXNpbmcgY3VycmVudCBpZmZ0IGltcGxlbWVudGF0aW9uIGJlY2F1c2UgdGhlIG9tZWdhIGFyZSBkaWZmZXJlbnRcbiAgICAgICAgICAgIHBvbHlub21pYWxzLlIyID0gUG9seW5vbWlhbC5sYWdyYW5nZVBvbHlub21pYWxJbnRlcnBvbGF0aW9uKFxuICAgICAgICAgICAgICAgIFtyb290cy5TMi5oMnczWzBdLCByb290cy5TMi5oMnczWzFdLCByb290cy5TMi5oMnczWzJdLFxuICAgICAgICAgICAgICAgICAgICByb290cy5TMi5oM3czWzBdLCByb290cy5TMi5oM3czWzFdLCByb290cy5TMi5oM3czWzJdXSxcbiAgICAgICAgICAgICAgICBbcG9seW5vbWlhbHMuQzIuZXZhbHVhdGUocm9vdHMuUzIuaDJ3M1swXSksIHBvbHlub21pYWxzLkMyLmV2YWx1YXRlKHJvb3RzLlMyLmgydzNbMV0pLFxuICAgICAgICAgICAgICAgICAgICBwb2x5bm9taWFscy5DMi5ldmFsdWF0ZShyb290cy5TMi5oMnczWzJdKSwgcG9seW5vbWlhbHMuQzIuZXZhbHVhdGUocm9vdHMuUzIuaDN3M1swXSksXG4gICAgICAgICAgICAgICAgICAgIHBvbHlub21pYWxzLkMyLmV2YWx1YXRlKHJvb3RzLlMyLmgzdzNbMV0pLCBwb2x5bm9taWFscy5DMi5ldmFsdWF0ZShyb290cy5TMi5oM3czWzJdKV0sIGN1cnZlKTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGRlZ3JlZSBvZiByMihYKSA8IDZcbiAgICAgICAgICAgIGlmIChwb2x5bm9taWFscy5SMi5kZWdyZWUoKSA+IDUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJSMiBQb2x5bm9taWFsIGlzIG5vdCB3ZWxsIGNhbGN1bGF0ZWRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBhc3luYyBmdW5jdGlvbiBjb21wdXRlRigpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBGIHBvbHlub21pYWxcIik7XG5cbiAgICAgICAgICAgIC8vIENPTVBVVEUgRihYKVxuICAgICAgICAgICAgcG9seW5vbWlhbHMuRiA9IFBvbHlub21pYWwuZnJvbVBvbHlub21pYWwocG9seW5vbWlhbHMuQzAsIGN1cnZlLCBsb2dnZXIpO1xuICAgICAgICAgICAgcG9seW5vbWlhbHMuRi5zdWIocG9seW5vbWlhbHMuUjApO1xuICAgICAgICAgICAgcG9seW5vbWlhbHMuRi5kaXZCeVplcm9maWVyKDgsIGNoYWxsZW5nZXMueGkpO1xuXG4gICAgICAgICAgICBsZXQgZjIgPSBQb2x5bm9taWFsLmZyb21Qb2x5bm9taWFsKHBvbHlub21pYWxzLkMxLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgICAgIGYyLnN1Yihwb2x5bm9taWFscy5SMSk7XG4gICAgICAgICAgICBmMi5tdWxTY2FsYXIoY2hhbGxlbmdlcy5hbHBoYSk7XG4gICAgICAgICAgICBmMi5kaXZCeVplcm9maWVyKDQsIGNoYWxsZW5nZXMueGkpO1xuXG4gICAgICAgICAgICBsZXQgZjMgPSBQb2x5bm9taWFsLmZyb21Qb2x5bm9taWFsKHBvbHlub21pYWxzLkMyLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgICAgIGYzLnN1Yihwb2x5bm9taWFscy5SMik7XG4gICAgICAgICAgICBmMy5tdWxTY2FsYXIoRnIuc3F1YXJlKGNoYWxsZW5nZXMuYWxwaGEpKTtcbiAgICAgICAgICAgIGYzLmRpdkJ5WmVyb2ZpZXIoMywgY2hhbGxlbmdlcy54aSk7XG4gICAgICAgICAgICBmMy5kaXZCeVplcm9maWVyKDMsIGNoYWxsZW5nZXMueGl3KTtcblxuICAgICAgICAgICAgcG9seW5vbWlhbHMuRi5hZGQoZjIpO1xuICAgICAgICAgICAgcG9seW5vbWlhbHMuRi5hZGQoZjMpO1xuXG4gICAgICAgICAgICBpZiAocG9seW5vbWlhbHMuRi5kZWdyZWUoKSA+PSA5ICogemtleS5kb21haW5TaXplIC0gNikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkYgUG9seW5vbWlhbCBpcyBub3Qgd2VsbCBjYWxjdWxhdGVkXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gcm91bmQ1KCkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIGNoYWxsZW5nZSB5XCIpO1xuXG4gICAgICAgIC8vIFNURVAgNS4xIC0gQ29tcHV0ZSByYW5kb20gZXZhbHVhdGlvbiBwb2ludCB5IOKIiCBGXG4gICAgICAgIGNvbnN0IHRyYW5zY3JpcHQgPSBuZXcgS2VjY2FrMjU2VHJhbnNjcmlwdChjdXJ2ZSk7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKGNoYWxsZW5nZXMuYWxwaGEpO1xuICAgICAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQocHJvb2YuZ2V0UG9seW5vbWlhbChcIlcxXCIpKTtcblxuICAgICAgICBjaGFsbGVuZ2VzLnkgPSB0cmFuc2NyaXB0LmdldENoYWxsZW5nZSgpO1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBjaGFsbGVuZ2VzLnk6IFwiICsgRnIudG9TdHJpbmcoY2hhbGxlbmdlcy55KSk7XG5cbiAgICAgICAgLy8gU1RFUCA1LjIgLSBDb21wdXRlIEwoWClcbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBMIHBvbHlub21pYWxcIik7XG4gICAgICAgIGF3YWl0IGNvbXB1dGVMKCk7XG5cbiAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBaVFMyIHBvbHlub21pYWxcIik7XG4gICAgICAgIGF3YWl0IGNvbXB1dGVaVFMyKCk7XG5cbiAgICAgICAgbGV0IFpUUzJZID0gcG9seW5vbWlhbHMuWlRTMi5ldmFsdWF0ZShjaGFsbGVuZ2VzLnkpO1xuICAgICAgICBaVFMyWSA9IEZyLmludihaVFMyWSk7XG4gICAgICAgIHBvbHlub21pYWxzLkwubXVsU2NhbGFyKFpUUzJZKTtcblxuICAgICAgICBjb25zdCBwb2xEaXZpZGVuZCA9IFBvbHlub21pYWwuZnJvbUNvZWZmaWNpZW50c0FycmF5KFtGci5uZWcoY2hhbGxlbmdlcy55KSwgRnIub25lXSwgY3VydmUpO1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIFcnID0gTCAvIFpUUzIgcG9seW5vbWlhbFwiKTtcbiAgICAgICAgY29uc3QgcG9sUmVtYWluZGVyID0gcG9seW5vbWlhbHMuTC5kaXZCeShwb2xEaXZpZGVuZCk7XG5cbiAgICAgICAgLy9DaGVjayBwb2xSZW1pbmRlciBkZWdyZWUgaXMgZXF1YWwgdG8gemVyb1xuICAgICAgICBpZiAocG9sUmVtYWluZGVyLmRlZ3JlZSgpID4gMCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBEZWdyZWUgb2YgTChYKS8oWlRTMih5KShYLXkpKSByZW1haW5kZXIgaXMgJHtwb2xSZW1haW5kZXIuZGVncmVlKCl9IGFuZCBzaG91bGQgYmUgMGApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBvbHlub21pYWxzLkwuZGVncmVlKCkgPj0gOSAqIHprZXkuZG9tYWluU2l6ZSAtIDEpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkRlZ3JlZSBvZiBMKFgpLyhaVFMyKHkpKFgteSkpIGlzIG5vdCBjb3JyZWN0XCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVGhlIGZpZnRoIG91dHB1dCBvZiB0aGUgcHJvdmVyIGlzIChbVzJdXzEpLCB3aGVyZSBXMjo9KGYvWl90KSh4KVxuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIFcnIG11bHRpIGV4cG9uZW50aWF0aW9uXCIpO1xuICAgICAgICBsZXQgY29tbWl0VzIgPSBhd2FpdCBwb2x5bm9taWFscy5MLm11bHRpRXhwb25lbnRpYXRpb24oUFRhdSwgXCJXMlwiKTtcbiAgICAgICAgcHJvb2YuYWRkUG9seW5vbWlhbChcIlcyXCIsIGNvbW1pdFcyKTtcblxuICAgICAgICByZXR1cm4gMDtcblxuICAgICAgICBhc3luYyBmdW5jdGlvbiBjb21wdXRlTCgpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBMIHBvbHlub21pYWxcIik7XG5cbiAgICAgICAgICAgIGNvbnN0IGV2YWxSMFkgPSBwb2x5bm9taWFscy5SMC5ldmFsdWF0ZShjaGFsbGVuZ2VzLnkpO1xuICAgICAgICAgICAgY29uc3QgZXZhbFIxWSA9IHBvbHlub21pYWxzLlIxLmV2YWx1YXRlKGNoYWxsZW5nZXMueSk7XG4gICAgICAgICAgICBjb25zdCBldmFsUjJZID0gcG9seW5vbWlhbHMuUjIuZXZhbHVhdGUoY2hhbGxlbmdlcy55KTtcblxuICAgICAgICAgICAgbGV0IG11bEwwID0gRnIuc3ViKGNoYWxsZW5nZXMueSwgcm9vdHMuUzAuaDB3OFswXSk7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMTsgaSA8IDg7IGkrKykge1xuICAgICAgICAgICAgICAgIG11bEwwID0gRnIubXVsKG11bEwwLCBGci5zdWIoY2hhbGxlbmdlcy55LCByb290cy5TMC5oMHc4W2ldKSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCBtdWxMMSA9IEZyLnN1YihjaGFsbGVuZ2VzLnksIHJvb3RzLlMxLmgxdzRbMF0pO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPCA0OyBpKyspIHtcbiAgICAgICAgICAgICAgICBtdWxMMSA9IEZyLm11bChtdWxMMSwgRnIuc3ViKGNoYWxsZW5nZXMueSwgcm9vdHMuUzEuaDF3NFtpXSkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgbXVsTDIgPSBGci5zdWIoY2hhbGxlbmdlcy55LCByb290cy5TMi5oMnczWzBdKTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAxOyBpIDwgMzsgaSsrKSB7XG4gICAgICAgICAgICAgICAgbXVsTDIgPSBGci5tdWwobXVsTDIsIEZyLnN1YihjaGFsbGVuZ2VzLnksIHJvb3RzLlMyLmgydzNbaV0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMzsgaSsrKSB7XG4gICAgICAgICAgICAgICAgbXVsTDIgPSBGci5tdWwobXVsTDIsIEZyLnN1YihjaGFsbGVuZ2VzLnksIHJvb3RzLlMyLmgzdzNbaV0pKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IHByZUwwID0gRnIubXVsKG11bEwxLCBtdWxMMik7XG4gICAgICAgICAgICBsZXQgcHJlTDEgPSBGci5tdWwoY2hhbGxlbmdlcy5hbHBoYSwgRnIubXVsKG11bEwwLCBtdWxMMikpO1xuICAgICAgICAgICAgbGV0IHByZUwyID0gRnIubXVsKEZyLnNxdWFyZShjaGFsbGVuZ2VzLmFscGhhKSwgRnIubXVsKG11bEwwLCBtdWxMMSkpO1xuXG4gICAgICAgICAgICB0b0ludmVyc2VbXCJkZW5IMVwiXSA9IG11bEwxO1xuICAgICAgICAgICAgdG9JbnZlcnNlW1wiZGVuSDJcIl0gPSBtdWxMMjtcblxuICAgICAgICAgICAgLy8gQ09NUFVURSBMKFgpXG4gICAgICAgICAgICBwb2x5bm9taWFscy5MID0gUG9seW5vbWlhbC5mcm9tUG9seW5vbWlhbChwb2x5bm9taWFscy5DMCwgY3VydmUsIGxvZ2dlcik7XG4gICAgICAgICAgICBwb2x5bm9taWFscy5MLnN1YlNjYWxhcihldmFsUjBZKTtcbiAgICAgICAgICAgIHBvbHlub21pYWxzLkwubXVsU2NhbGFyKHByZUwwKTtcblxuICAgICAgICAgICAgbGV0IGwyID0gUG9seW5vbWlhbC5mcm9tUG9seW5vbWlhbChwb2x5bm9taWFscy5DMSwgY3VydmUsIGxvZ2dlcik7XG4gICAgICAgICAgICBsMi5zdWJTY2FsYXIoZXZhbFIxWSk7XG4gICAgICAgICAgICBsMi5tdWxTY2FsYXIocHJlTDEpO1xuXG4gICAgICAgICAgICBsZXQgbDMgPSBQb2x5bm9taWFsLmZyb21Qb2x5bm9taWFsKHBvbHlub21pYWxzLkMyLCBjdXJ2ZSwgbG9nZ2VyKTtcbiAgICAgICAgICAgIGwzLnN1YlNjYWxhcihldmFsUjJZKTtcbiAgICAgICAgICAgIGwzLm11bFNjYWxhcihwcmVMMik7XG5cbiAgICAgICAgICAgIHBvbHlub21pYWxzLkwuYWRkKGwyKTtcbiAgICAgICAgICAgIHBvbHlub21pYWxzLkwuYWRkKGwzKTtcblxuICAgICAgICAgICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBaVCBwb2x5bm9taWFsXCIpO1xuICAgICAgICAgICAgYXdhaXQgY29tcHV0ZVpUKCk7XG5cbiAgICAgICAgICAgIGNvbnN0IGV2YWxaVFkgPSBwb2x5bm9taWFscy5aVC5ldmFsdWF0ZShjaGFsbGVuZ2VzLnkpO1xuICAgICAgICAgICAgcG9seW5vbWlhbHMuRi5tdWxTY2FsYXIoZXZhbFpUWSk7XG4gICAgICAgICAgICBwb2x5bm9taWFscy5MLnN1Yihwb2x5bm9taWFscy5GKTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgZGVncmVlXG4gICAgICAgICAgICBpZiAocG9seW5vbWlhbHMuTC5kZWdyZWUoKSA+PSA5ICogemtleS5kb21haW5TaXplKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTCBQb2x5bm9taWFsIGlzIG5vdCB3ZWxsIGNhbGN1bGF0ZWRcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGRlbGV0ZSBidWZmZXJzLkw7XG4gICAgICAgIH1cblxuICAgICAgICBhc3luYyBmdW5jdGlvbiBjb21wdXRlWlQoKSB7XG4gICAgICAgICAgICBwb2x5bm9taWFscy5aVCA9IFBvbHlub21pYWwuemVyb2ZpZXJQb2x5bm9taWFsKFxuICAgICAgICAgICAgICAgIFtcbiAgICAgICAgICAgICAgICAgICAgcm9vdHMuUzAuaDB3OFswXSwgcm9vdHMuUzAuaDB3OFsxXSwgcm9vdHMuUzAuaDB3OFsyXSwgcm9vdHMuUzAuaDB3OFszXSxcbiAgICAgICAgICAgICAgICAgICAgcm9vdHMuUzAuaDB3OFs0XSwgcm9vdHMuUzAuaDB3OFs1XSwgcm9vdHMuUzAuaDB3OFs2XSwgcm9vdHMuUzAuaDB3OFs3XSxcbiAgICAgICAgICAgICAgICAgICAgcm9vdHMuUzEuaDF3NFswXSwgcm9vdHMuUzEuaDF3NFsxXSwgcm9vdHMuUzEuaDF3NFsyXSwgcm9vdHMuUzEuaDF3NFszXSxcbiAgICAgICAgICAgICAgICAgICAgcm9vdHMuUzIuaDJ3M1swXSwgcm9vdHMuUzIuaDJ3M1sxXSwgcm9vdHMuUzIuaDJ3M1syXSxcbiAgICAgICAgICAgICAgICAgICAgcm9vdHMuUzIuaDN3M1swXSwgcm9vdHMuUzIuaDN3M1sxXSwgcm9vdHMuUzIuaDN3M1syXV0sIGN1cnZlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGFzeW5jIGZ1bmN0aW9uIGNvbXB1dGVaVFMyKCkge1xuICAgICAgICAgICAgcG9seW5vbWlhbHMuWlRTMiA9IFBvbHlub21pYWwuemVyb2ZpZXJQb2x5bm9taWFsKFxuICAgICAgICAgICAgICAgIFtyb290cy5TMS5oMXc0WzBdLCByb290cy5TMS5oMXc0WzFdLCByb290cy5TMS5oMXc0WzJdLCByb290cy5TMS5oMXc0WzNdLFxuICAgICAgICAgICAgICAgICAgICByb290cy5TMi5oMnczWzBdLCByb290cy5TMi5oMnczWzFdLCByb290cy5TMi5oMnczWzJdLFxuICAgICAgICAgICAgICAgICAgICByb290cy5TMi5oM3czWzBdLCByb290cy5TMi5oM3czWzFdLCByb290cy5TMi5oM3czWzJdXSwgY3VydmUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0TW9udGdvbWVyeUJhdGNoZWRJbnZlcnNlKCkge1xuICAgICAgICAvLyAgIMK3IGRlbm9taW5hdG9yIG5lZWRlZCBpbiBzdGVwIDggYW5kIDkgb2YgdGhlIHZlcmlmaWVyIHRvIG11bHRpcGx5IGJ5IDEvWl9IKHhpKVxuICAgICAgICBsZXQgeGlOID0gY2hhbGxlbmdlcy54aTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB6a2V5LnBvd2VyOyBpKyspIHtcbiAgICAgICAgICAgIHhpTiA9IEZyLnNxdWFyZSh4aU4pO1xuICAgICAgICB9XG4gICAgICAgIHRvSW52ZXJzZVtcInpoXCJdID0gRnIuc3ViKHhpTiwgRnIub25lKTtcblxuICAgICAgICAvLyAgIMK3IGRlbm9taW5hdG9yIG5lZWRlZCBpbiBzdGVwIDEwIGFuZCAxMSBvZiB0aGUgdmVyaWZpZXJcbiAgICAgICAgLy8gICAgIHRvSW52ZXJzZS5kZW5IMSAmIHRvSW52ZXJzZS5kZW5IMiAgLT4gQ29tcHV0ZWQgaW4gcm91bmQ1LCBjb21wdXRlTCgpXG5cbiAgICAgICAgLy8gICDCtyBkZW5vbWluYXRvciBuZWVkZWQgaW4gdGhlIHZlcmlmaWVyIHdoZW4gY29tcHV0aW5nIExfaV57UzB9KFgpLCBMX2lee1MxfShYKSBhbmQgTF9pXntTMn0oWClcbiAgICAgICAgY29tcHV0ZUxpUzAodG9JbnZlcnNlLCByb290cy5TMC5oMHc4LCBjaGFsbGVuZ2VzLnksIGN1cnZlKTtcblxuICAgICAgICBjb21wdXRlTGlTMSh0b0ludmVyc2UsIHJvb3RzLlMxLmgxdzQsIGNoYWxsZW5nZXMueSwgY3VydmUpO1xuXG4gICAgICAgIGNvbXB1dGVMaVMyKHRvSW52ZXJzZSwgcm9vdHMuUzIuaDJ3Mywgcm9vdHMuUzIuaDN3MywgY2hhbGxlbmdlcy55LCBjaGFsbGVuZ2VzLnhpLCBjaGFsbGVuZ2VzLnhpdywgY3VydmUpO1xuXG4gICAgICAgIC8vICAgwrcgTF9pIGk9MSB0byBudW0gcHVibGljIGlucHV0cywgbmVlZGVkIGluIHN0ZXAgNiBhbmQgNyBvZiB0aGUgdmVyaWZpZXIgdG8gY29tcHV0ZSBMXzEoeGkpIGFuZCBQSSh4aSlcbiAgICAgICAgY29uc3Qgc2l6ZSA9IE1hdGgubWF4KDEsIHprZXkublB1YmxpYyk7XG5cbiAgICAgICAgbGV0IHcgPSBGci5vbmU7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2l6ZTsgaSsrKSB7XG4gICAgICAgICAgICB0b0ludmVyc2VbXCJMaV9cIiArIChpICsgMSldID0gRnIubXVsKEZyLmUoemtleS5kb21haW5TaXplKSwgRnIuc3ViKGNoYWxsZW5nZXMueGksIHcpKTtcbiAgICAgICAgICAgIHcgPSBGci5tdWwodywgRnIud1t6a2V5LnBvd2VyXSk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbXVsQWNjdW11bGF0b3IgPSBGci5vbmU7XG4gICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBPYmplY3QudmFsdWVzKHRvSW52ZXJzZSkpIHtcbiAgICAgICAgICAgIGlmKEFycmF5LmlzQXJyYXkoZWxlbWVudCkpIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IHN1YkVsZW1lbnQgb2YgZWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICBtdWxBY2N1bXVsYXRvciA9IEZyLm11bChtdWxBY2N1bXVsYXRvciwgc3ViRWxlbWVudCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBtdWxBY2N1bXVsYXRvciA9IEZyLm11bChtdWxBY2N1bXVsYXRvciwgZWxlbWVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIEZyLmludihtdWxBY2N1bXVsYXRvcik7XG5cbiAgICAgICAgXG4gICAgICAgIGZ1bmN0aW9uIGNvbXB1dGVMaVMwKHRvSW52ZXJzZSwgcm9vdHMsIHgsIGN1cnZlKSB7XG4gICAgICAgICAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgICAgICAgICAgY29uc3QgbGVuID0gcm9vdHMubGVuZ3RoO1xuICAgICAgICBcbiAgICAgICAgICAgIGNvbnN0IGRlbjEgPSBGci5tdWwoRnIuZShsZW4pLCBGci5leHAocm9vdHNbMF0sIGxlbiAtIDIpKTtcbiAgICAgICAgXG4gICAgICAgICAgICBjb25zdCBMaSA9IFtdO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGRlbjIgPSByb290c1soKGxlbiAtIDEpICogaSkgJSBsZW5dO1xuICAgICAgICAgICAgICAgIGNvbnN0IGRlbjMgPSBGci5zdWIoeCwgcm9vdHNbaV0pO1xuICAgICAgICBcbiAgICAgICAgICAgICAgICB0b0ludmVyc2VbW1wiTGlTMF9cIiArIChpICsgMSldXSA9IEZyLm11bChGci5tdWwoZGVuMSwgZGVuMiksIGRlbjMpO1xuICAgICAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgICAgIHJldHVybiBMaTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGNvbXB1dGVMaVMxKHRvSW52ZXJzZSwgcm9vdHMsIHgsIGN1cnZlKSB7XG4gICAgICAgICAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuICAgICAgICAgICAgY29uc3QgbGVuID0gcm9vdHMubGVuZ3RoO1xuICAgICAgICBcbiAgICAgICAgICAgIGNvbnN0IGRlbjEgPSBGci5tdWwoRnIuZShsZW4pLCBGci5leHAocm9vdHNbMF0sIGxlbiAtIDIpKTtcbiAgICAgICAgXG4gICAgICAgICAgICBjb25zdCBMaSA9IFtdO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGRlbjIgPSByb290c1soKGxlbiAtIDEpICogaSkgJSBsZW5dO1xuICAgICAgICAgICAgICAgIGNvbnN0IGRlbjMgPSBGci5zdWIoeCwgcm9vdHNbaV0pO1xuICAgICAgICBcbiAgICAgICAgICAgICAgICB0b0ludmVyc2VbW1wiTGlTMV9cIiArIChpICsgMSldXSA9IEZyLm11bChGci5tdWwoZGVuMSwgZGVuMiksIGRlbjMpO1xuXG4gICAgICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAgICAgcmV0dXJuIExpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gY29tcHV0ZUxpUzIodG9JbnZlcnNlLCBTMiwgUzJwLCB2YWx1ZSwgeGksIHhpdywgY3VydmUpIHtcbiAgICAgICAgICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG4gICAgICAgIFxuICAgICAgICAgICAgY29uc3QgTGkgPSBbXTtcbiAgICAgICAgXG4gICAgICAgICAgICBjb25zdCBfM2gyID0gRnIubXVsKEZyLmUoMyksIFMyWzBdKTtcbiAgICAgICAgICAgIGNvbnN0IHhpc3VieGl3ID0gRnIuc3ViKHhpLCB4aXcpO1xuICAgICAgICAgICAgbGV0IGRlbjEgPSBGci5tdWwoXzNoMiwgeGlzdWJ4aXcpO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCAzOyBpKyspIHtcbiAgICAgICAgICAgICAgICBjb25zdCBkZW4yID0gUzJbMiAqIGkgJSAzXTtcbiAgICAgICAgICAgICAgICBjb25zdCBkZW4zID0gRnIuc3ViKHZhbHVlLCBTMltpXSk7XG4gICAgICAgIFxuICAgICAgICAgICAgICAgIHRvSW52ZXJzZVtbXCJMaVMyX1wiICsgKGkgKyAxKV1dID0gRnIubXVsKGRlbjEsRnIubXVsKGRlbjIsIGRlbjMpKTtcbiAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgICAgICBjb25zdCBfM2gzID0gRnIubXVsKEZyLmUoMyksIFMycFswXSk7XG4gICAgICAgICAgICBjb25zdCB4aXdzdWJ4aSA9IEZyLnN1Yih4aXcsIHhpKTtcbiAgICAgICAgICAgIGRlbjEgPSBGci5tdWwoXzNoMywgeGl3c3VieGkpO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCAzOyBpKyspIHtcbiAgICAgICAgICAgICAgICBjb25zdCBkZW4yID0gUzJwWzIgKiBpICUgM107XG4gICAgICAgICAgICAgICAgY29uc3QgZGVuMyA9IEZyLnN1Yih2YWx1ZSwgUzJwW2ldKTtcbiAgICAgICAgXG4gICAgICAgICAgICAgICAgdG9JbnZlcnNlW1tcIkxpUzJfXCIgKyAoaSArIDEgKyAzKV1dID0gRnIubXVsKGRlbjEsRnIubXVsKGRlbjIsIGRlbjMpKTsgICAgXG4gICAgICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAgICAgcmV0dXJuIExpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya2pzLlxuXG4gICAgc25hcmtqcyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuICAgIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGVcbiAgICBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbilcbiAgICBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJranMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3JcbiAgICBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoXG4gICAgc25hcmtqcy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCBmZmxvbmtQcm92ZSBmcm9tIFwiLi9mZmxvbmtfcHJvdmUuanNcIjtcbmltcG9ydCB3dG5zX2NhbGN1bGF0ZSBmcm9tIFwiLi93dG5zX2NhbGN1bGF0ZS5qc1wiO1xuaW1wb3J0IHt1dGlsc30gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuY29uc3Qge3Vuc3RyaW5naWZ5QmlnSW50c30gPSB1dGlscztcblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gZmZsb25rRnVsbFByb3ZlKF9pbnB1dCwgd2FzbUZpbGVuYW1lLCB6a2V5RmlsZW5hbWUsIGxvZ2dlciwgd3Ruc0NhbGNPcHRpb25zLCBwcm92ZXJPcHRpb25zKSB7XG4gICAgY29uc3QgaW5wdXQgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX2lucHV0KTtcblxuICAgIGNvbnN0IHd0bnM9IHt0eXBlOiBcIm1lbVwifTtcblxuICAgIC8vIENvbXB1dGUgdGhlIHdpdG5lc3NcbiAgICBhd2FpdCB3dG5zX2NhbGN1bGF0ZShpbnB1dCwgd2FzbUZpbGVuYW1lLCB3dG5zLCB3dG5zQ2FsY09wdGlvbnMpO1xuXG4gICAgLy8gQ29tcHV0ZSB0aGUgcHJvb2ZcbiAgICByZXR1cm4gYXdhaXQgZmZsb25rUHJvdmUoemtleUZpbGVuYW1lLCB3dG5zLCBsb2dnZXIsIHByb3Zlck9wdGlvbnMpO1xufSIsIi8qXG4gICAgQ29weXJpZ2h0IDIwMjIgaWRlbjMgYXNzb2NpYXRpb24uXG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBzbmFya2pzLlxuXG4gICAgc25hcmtqcyBpcyBhIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuICAgIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGVcbiAgICBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbilcbiAgICBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIHNuYXJranMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFlcbiAgICBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3JcbiAgICBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoXG4gICAgc25hcmtqcy4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG5cbmltcG9ydCAqIGFzIGN1cnZlcyBmcm9tIFwiLi9jdXJ2ZXMuanNcIjtcbmltcG9ydCB7IEJpZ0J1ZmZlciwgdXRpbHMgfSBmcm9tIFwiZmZqYXZhc2NyaXB0XCI7XG5pbXBvcnQgeyBQcm9vZiB9IGZyb20gXCIuL3Byb29mLmpzXCI7XG5pbXBvcnQgeyBLZWNjYWsyNTZUcmFuc2NyaXB0IH0gZnJvbSBcIi4vS2VjY2FrMjU2VHJhbnNjcmlwdC5qc1wiO1xuaW1wb3J0IHsgU2NhbGFyIH0gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuXG5jb25zdCB7IHVuc3RyaW5naWZ5QmlnSW50cyB9ID0gdXRpbHM7XG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIGZmbG9ua1ZlcmlmeShfdmtfdmVyaWZpZXIsIF9wdWJsaWNTaWduYWxzLCBfcHJvb2YsIGxvZ2dlcikge1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiRkZMT05LIFZFUklGSUVSIFNUQVJURURcIik7XG5cbiAgICBfdmtfdmVyaWZpZXIgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX3ZrX3ZlcmlmaWVyKTtcbiAgICBfcHJvb2YgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX3Byb29mKTtcblxuICAgIGNvbnN0IGN1cnZlID0gYXdhaXQgY3VydmVzLmdldEN1cnZlRnJvbU5hbWUoX3ZrX3ZlcmlmaWVyLmN1cnZlKTtcblxuICAgIGNvbnN0IHZrID0gZnJvbU9iamVjdFZrKGN1cnZlLCBfdmtfdmVyaWZpZXIpO1xuXG4gICAgLy8gVE9ETyA/Pz8gQ29tcHV0ZSB3cl4zIGFuZCBjaGVjayBpZiBpdCBtYXRjaGVzIHdpdGggd1xuXG4gICAgY29uc3QgcHJvb2YgPSBuZXcgUHJvb2YoY3VydmUsIGxvZ2dlcik7XG4gICAgcHJvb2YuZnJvbU9iamVjdFByb29mKF9wcm9vZik7XG5cbiAgICBjb25zdCBwdWJsaWNTaWduYWxzID0gdW5zdHJpbmdpZnlCaWdJbnRzKF9wdWJsaWNTaWduYWxzKTtcblxuICAgIGlmIChwdWJsaWNTaWduYWxzLmxlbmd0aCAhPT0gdmsublB1YmxpYykge1xuICAgICAgICBsb2dnZXIuZXJyb3IoXCJOdW1iZXIgb2YgcHVibGljIHNpZ25hbHMgZG9lcyBub3QgbWF0Y2ggd2l0aCB2a1wiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG5cbiAgICBpZiAobG9nZ2VyKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oXCIgIEZGTE9OSyBWRVJJRlkgU0VUVElOR1NcIik7XG4gICAgICAgIGxvZ2dlci5pbmZvKGAgIEN1cnZlOiAgICAgICAgICR7Y3VydmUubmFtZX1gKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYCAgQ2lyY3VpdCBwb3dlcjogJHt2ay5wb3dlcn1gKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYCAgRG9tYWluIHNpemU6ICAgJHsyICoqIHZrLnBvd2VyfWApO1xuICAgICAgICBsb2dnZXIuaW5mbyhgICBQdWJsaWMgdmFyczogICAke3ZrLm5QdWJsaWN9YCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiKTtcbiAgICB9XG5cbiAgICAvLyBTVEVQIDEgLSBWYWxpZGF0ZSB0aGF0IGFsbCBwb2x5bm9taWFsIGNvbW1pdG1lbnRzIOKIiCBHXzFcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ2hlY2tpbmcgY29tbWl0bWVudHMgYmVsb25nIHRvIEcxXCIpO1xuICAgIGlmICghY29tbWl0bWVudHNCZWxvbmdUb0cxKGN1cnZlLCBwcm9vZiwgdmspKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIGxvZ2dlci5lcnJvcihcIlByb29mIGNvbW1pdG1lbnRzIGFyZSBub3QgdmFsaWRcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBTVEVQIDIgLSBWYWxpZGF0ZSB0aGF0IGFsbCBldmFsdWF0aW9ucyDiiIggRlxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiPiBDaGVja2luZyBldmFsdWF0aW9ucyBiZWxvbmcgdG8gRlwiKTtcbiAgICBpZiAoIWV2YWx1YXRpb25zQXJlVmFsaWQoY3VydmUsIHByb29mKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJQcm9vZiBldmFsdWF0aW9ucyBhcmUgbm90IHZhbGlkLlwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIFNURVAgMyAtIFZhbGlkYXRlIHRoYXQgd19pIOKIiCBGIGZvciBpIOKIiCBbbF1cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ2hlY2tpbmcgcHVibGljIGlucHV0cyBiZWxvbmcgdG8gRlwiKTtcbiAgICBpZiAoIXB1YmxpY0lucHV0c0FyZVZhbGlkKGN1cnZlLCBwdWJsaWNTaWduYWxzKSkge1xuICAgICAgICBpZiAobG9nZ2VyKSBsb2dnZXIuZXJyb3IoXCJQdWJsaWMgaW5wdXRzIGFyZSBub3QgdmFsaWQuXCIpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gU1RFUCA0IC0gQ29tcHV0ZSB0aGUgY2hhbGxlbmdlczogYmV0YSwgZ2FtbWEsIHhpLCBhbHBoYSBhbmQgeSDiiIggRlxuICAgIC8vIGFzIGluIHByb3ZlciBkZXNjcmlwdGlvbiwgZnJvbSB0aGUgY29tbW9uIHByZXByb2Nlc3NlZCBpbnB1dHMsIHB1YmxpYyBpbnB1dHMgYW5kIGVsZW1lbnRzIG9mIM+AX1NOQVJLXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBjaGFsbGVuZ2VzXCIpO1xuICAgIGNvbnN0IHsgY2hhbGxlbmdlcywgcm9vdHMgfSA9IGNvbXB1dGVDaGFsbGVuZ2VzKGN1cnZlLCBwcm9vZiwgdmssIHB1YmxpY1NpZ25hbHMsIGxvZ2dlcik7XG5cbiAgICAvLyBTVEVQIDUgLSBDb21wdXRlIHRoZSB6ZXJvIHBvbHlub21pYWwgZXZhbHVhdGlvbiBaX0goeGkpID0geGlebiAtIDFcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIFplcm8gcG9seW5vbWlhbCBldmFsdWF0aW9uIFpfSCh4aSlcIik7XG4gICAgY2hhbGxlbmdlcy56aCA9IEZyLnN1YihjaGFsbGVuZ2VzLnhpTiwgRnIub25lKTtcbiAgICBjaGFsbGVuZ2VzLmludnpoID0gRnIuaW52KGNoYWxsZW5nZXMuemgpO1xuXG4gICAgLy8gU1RFUCA2IC0gQ29tcHV0ZSB0aGUgbGFncmFuZ2UgcG9seW5vbWlhbCBldmFsdWF0aW9uIExfMSh4aSlcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIExhZ3JhbmdlIGV2YWx1YXRpb25zXCIpO1xuICAgIGNvbnN0IGxhZ3JhbmdlRXZhbHMgPSBhd2FpdCBjb21wdXRlTGFncmFuZ2VFdmFsdWF0aW9ucyhjdXJ2ZSwgY2hhbGxlbmdlcywgdmspO1xuXG4gICAgLy8gU1RFUCA3IC0gQ29tcHV0ZSBwdWJsaWMgaW5wdXQgZXZhbHVhdGlvbiBQSSh4aSlcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIHBvbHlub21pYWwgaWRlbnRpdGllcyBQSShYKVwiKTtcbiAgICBjb25zdCBwaSA9IGNhbGN1bGF0ZVBJKGN1cnZlLCBwdWJsaWNTaWduYWxzLCBsYWdyYW5nZUV2YWxzKTtcblxuICAgIC8vIFNURVAgOCAtIENvbXB1dGUgcG9seW5vbWlhbCByMCDiiIggRl97PDR9W1hdXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyByMCh5KVwiKTtcbiAgICBjb25zdCByMCA9IGNvbXB1dGVSMChwcm9vZiwgY2hhbGxlbmdlcywgcm9vdHMsIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgLy8gU1RFUCA5IC0gQ29tcHV0ZSBwb2x5bm9taWFsIHIxIOKIiCBGX3s8NH1bWF1cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIHIxKHkpXCIpO1xuICAgIGNvbnN0IHIxID0gY29tcHV0ZVIxKHByb29mLCBjaGFsbGVuZ2VzLCByb290cywgcGksIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgLy8gU1RFUCA5IC0gQ29tcHV0ZSBwb2x5bm9taWFsIHIyIOKIiCBGX3s8Nn1bWF1cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIHIyKHkpXCIpO1xuICAgIGNvbnN0IHIyID0gY29tcHV0ZVIyKHByb29mLCBjaGFsbGVuZ2VzLCByb290cywgbGFncmFuZ2VFdmFsc1sxXSwgdmssIGN1cnZlLCBsb2dnZXIpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBGXCIpO1xuICAgIGNvbnN0IEYgPSBjb21wdXRlRihjdXJ2ZSwgcHJvb2YsIHZrLCBjaGFsbGVuZ2VzLCByb290cyk7XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIj4gQ29tcHV0aW5nIEVcIik7XG4gICAgY29uc3QgRSA9IGNvbXB1dGVFKGN1cnZlLCBwcm9vZiwgY2hhbGxlbmdlcywgdmssIHIwLCByMSwgcjIpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IENvbXB1dGluZyBKXCIpO1xuICAgIGNvbnN0IEogPSBjb21wdXRlSihjdXJ2ZSwgcHJvb2YsIGNoYWxsZW5nZXMpO1xuXG4gICAgaWYgKGxvZ2dlcikgbG9nZ2VyLmluZm8oXCI+IFZhbGlkYXRlIGFsbCBldmFsdWF0aW9ucyB3aXRoIGEgcGFpcmluZ1wiKTtcbiAgICBjb25zdCByZXMgPSBhd2FpdCBpc1ZhbGlkUGFpcmluZyhjdXJ2ZSwgcHJvb2YsIGNoYWxsZW5nZXMsIHZrLCBGLCBFLCBKKTtcblxuICAgIGlmIChsb2dnZXIpIHtcbiAgICAgICAgaWYgKHJlcykge1xuICAgICAgICAgICAgbG9nZ2VyLmluZm8oXCJQUk9PRiBWRVJJRklFRCBTVUNDRVNTRlVMTFlcIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybihcIkludmFsaWQgUHJvb2ZcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIkZGTE9OSyBWRVJJRklFUiBGSU5JU0hFRFwiKTtcblxuICAgIHJldHVybiByZXM7XG5cbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdFZrKGN1cnZlLCB2aykge1xuICAgIGNvbnN0IHJlcyA9IHZrO1xuICAgIHJlcy5rMSA9IGN1cnZlLkZyLmZyb21PYmplY3QodmsuazEpO1xuICAgIHJlcy5rMiA9IGN1cnZlLkZyLmZyb21PYmplY3QodmsuazIpO1xuICAgIHJlcy53ID0gY3VydmUuRnIuZnJvbU9iamVjdCh2ay53KTtcbiAgICAvLyByZXMud1cgPSBjdXJ2ZS5Gci5mcm9tT2JqZWN0KHZrLndXKTtcbiAgICByZXMudzMgPSBjdXJ2ZS5Gci5mcm9tT2JqZWN0KHZrLnczKTtcbiAgICByZXMudzQgPSBjdXJ2ZS5Gci5mcm9tT2JqZWN0KHZrLnc0KTtcbiAgICByZXMudzggPSBjdXJ2ZS5Gci5mcm9tT2JqZWN0KHZrLnc4KTtcbiAgICByZXMud3IgPSBjdXJ2ZS5Gci5mcm9tT2JqZWN0KHZrLndyKTtcbiAgICByZXMuWF8yID0gY3VydmUuRzIuZnJvbU9iamVjdCh2ay5YXzIpO1xuICAgIHJlcy5DMCA9IGN1cnZlLkcxLmZyb21PYmplY3QodmsuQzApO1xuICAgIHJldHVybiByZXM7XG59XG5cbmZ1bmN0aW9uIGNvbW1pdG1lbnRzQmVsb25nVG9HMShjdXJ2ZSwgcHJvb2YsIHZrKSB7XG4gICAgY29uc3QgRzEgPSBjdXJ2ZS5HMTtcbiAgICByZXR1cm4gRzEuaXNWYWxpZChwcm9vZi5wb2x5bm9taWFscy5DMSlcbiAgICAgICAgJiYgRzEuaXNWYWxpZChwcm9vZi5wb2x5bm9taWFscy5DMilcbiAgICAgICAgJiYgRzEuaXNWYWxpZChwcm9vZi5wb2x5bm9taWFscy5XMSlcbiAgICAgICAgJiYgRzEuaXNWYWxpZChwcm9vZi5wb2x5bm9taWFscy5XMilcbiAgICAgICAgJiYgRzEuaXNWYWxpZCh2ay5DMCk7XG59XG5cbmZ1bmN0aW9uIGNoZWNrVmFsdWVCZWxvbmdUb0ZpZWxkKGN1cnZlLCB2YWx1ZSkge1xuICAgIHJldHVybiBTY2FsYXIuZ2VxKHZhbHVlLCAwKSAmJiBTY2FsYXIubHQodmFsdWUsIGN1cnZlLnIpO1xufVxuXG5mdW5jdGlvbiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBldmFsdWF0aW9uKSB7XG4gICAgcmV0dXJuIGNoZWNrVmFsdWVCZWxvbmdUb0ZpZWxkKGN1cnZlLCBTY2FsYXIuZnJvbVJwckxFKGV2YWx1YXRpb24pKTtcbn1cblxuZnVuY3Rpb24gZXZhbHVhdGlvbnNBcmVWYWxpZChjdXJ2ZSwgcHJvb2YpIHtcbiAgICByZXR1cm4gY2hlY2tFdmFsdWF0aW9uSXNWYWxpZChjdXJ2ZSwgcHJvb2YuZXZhbHVhdGlvbnMucWwpXG4gICAgICAgICYmIGNoZWNrRXZhbHVhdGlvbklzVmFsaWQoY3VydmUsIHByb29mLmV2YWx1YXRpb25zLnFyKVxuICAgICAgICAmJiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBwcm9vZi5ldmFsdWF0aW9ucy5xbSlcbiAgICAgICAgJiYgY2hlY2tFdmFsdWF0aW9uSXNWYWxpZChjdXJ2ZSwgcHJvb2YuZXZhbHVhdGlvbnMucW8pXG4gICAgICAgICYmIGNoZWNrRXZhbHVhdGlvbklzVmFsaWQoY3VydmUsIHByb29mLmV2YWx1YXRpb25zLnFjKVxuICAgICAgICAmJiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBwcm9vZi5ldmFsdWF0aW9ucy5zMSlcbiAgICAgICAgJiYgY2hlY2tFdmFsdWF0aW9uSXNWYWxpZChjdXJ2ZSwgcHJvb2YuZXZhbHVhdGlvbnMuczIpXG4gICAgICAgICYmIGNoZWNrRXZhbHVhdGlvbklzVmFsaWQoY3VydmUsIHByb29mLmV2YWx1YXRpb25zLnMzKVxuICAgICAgICAmJiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBwcm9vZi5ldmFsdWF0aW9ucy5hKVxuICAgICAgICAmJiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBwcm9vZi5ldmFsdWF0aW9ucy5iKVxuICAgICAgICAmJiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBwcm9vZi5ldmFsdWF0aW9ucy5jKVxuICAgICAgICAmJiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBwcm9vZi5ldmFsdWF0aW9ucy56KVxuICAgICAgICAmJiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBwcm9vZi5ldmFsdWF0aW9ucy56dylcbiAgICAgICAgJiYgY2hlY2tFdmFsdWF0aW9uSXNWYWxpZChjdXJ2ZSwgcHJvb2YuZXZhbHVhdGlvbnMudDF3KVxuICAgICAgICAmJiBjaGVja0V2YWx1YXRpb25Jc1ZhbGlkKGN1cnZlLCBwcm9vZi5ldmFsdWF0aW9ucy50MncpO1xufVxuXG5mdW5jdGlvbiBwdWJsaWNJbnB1dHNBcmVWYWxpZChjdXJ2ZSwgcHVibGljSW5wdXRzKSB7XG4gICAgZm9yKGxldCBpID0gMDsgaSA8IHB1YmxpY0lucHV0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZighY2hlY2tWYWx1ZUJlbG9uZ1RvRmllbGQoY3VydmUsIHB1YmxpY0lucHV0c1tpXSkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cblxuZnVuY3Rpb24gY29tcHV0ZUNoYWxsZW5nZXMoY3VydmUsIHByb29mLCB2aywgcHVibGljU2lnbmFscywgbG9nZ2VyKSB7XG4gICAgY29uc3QgRnIgPSBjdXJ2ZS5GcjtcblxuICAgIGNvbnN0IGNoYWxsZW5nZXMgPSB7fTtcbiAgICBjb25zdCByb290cyA9IHt9O1xuICAgIGNvbnN0IHRyYW5zY3JpcHQgPSBuZXcgS2VjY2FrMjU2VHJhbnNjcmlwdChjdXJ2ZSk7XG5cbiAgICAvLyBBZGQgQzAgdG8gdGhlIHRyYW5zY3JpcHRcbiAgICB0cmFuc2NyaXB0LmFkZFBvbENvbW1pdG1lbnQodmsuQzApO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwdWJsaWNTaWduYWxzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKEZyLmUocHVibGljU2lnbmFsc1tpXSkpO1xuICAgIH1cblxuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5wb2x5bm9taWFscy5DMSk7XG4gICAgY2hhbGxlbmdlcy5iZXRhID0gdHJhbnNjcmlwdC5nZXRDaGFsbGVuZ2UoKTtcbiAgICB0cmFuc2NyaXB0LnJlc2V0KCk7XG5cbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihjaGFsbGVuZ2VzLmJldGEpO1xuICAgIGNoYWxsZW5nZXMuZ2FtbWEgPSB0cmFuc2NyaXB0LmdldENoYWxsZW5nZSgpO1xuXG4gICAgdHJhbnNjcmlwdC5yZXNldCgpO1xuICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKGNoYWxsZW5nZXMuZ2FtbWEpO1xuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5wb2x5bm9taWFscy5DMik7XG4gICAgY29uc3QgeGlTZWVkID0gdHJhbnNjcmlwdC5nZXRDaGFsbGVuZ2UoKTtcbiAgICBjb25zdCB4aVNlZWQyID0gRnIuc3F1YXJlKHhpU2VlZCk7XG5cbiAgICBsZXQgdzggPSBbXTtcbiAgICB3OFsxXSA9IHZrLnc4O1xuICAgIHc4WzJdID0gRnIuc3F1YXJlKHZrLnc4KTtcbiAgICB3OFszXSA9IEZyLm11bCh3OFsyXSwgdmsudzgpO1xuICAgIHc4WzRdID0gRnIubXVsKHc4WzNdLCB2ay53OCk7XG4gICAgdzhbNV0gPSBGci5tdWwodzhbNF0sIHZrLnc4KTtcbiAgICB3OFs2XSA9IEZyLm11bCh3OFs1XSwgdmsudzgpO1xuICAgIHc4WzddID0gRnIubXVsKHc4WzZdLCB2ay53OCk7XG4gICAgbGV0IHc0ID0gW107XG4gICAgdzRbMV0gPSB2ay53NDtcbiAgICB3NFsyXSA9IEZyLnNxdWFyZSh2ay53NCk7XG4gICAgdzRbM10gPSBGci5tdWwodzRbMl0sIHZrLnc0KTtcbiAgICBsZXQgdzMgPSBbXTtcbiAgICB3M1sxXSA9IHZrLnczO1xuICAgIHczWzJdID0gRnIuc3F1YXJlKHZrLnczKTtcblxuICAgIC8vIGNvbnN0IHc0XzIgPSBGci5zcXVhcmUodmsudzQpO1xuICAgIC8vIGNvbnN0IHc0XzMgPSBGci5tdWwodzRfMiwgdmsudzQpO1xuICAgIC8vIGNvbnN0IHczXzIgPSBGci5zcXVhcmUodmsudzMpO1xuXG4gICAgLy8gQ29tcHV0ZSBoMCA9IHhpU2VlZGVyXjNcbiAgICByb290cy5TMCA9IHt9O1xuICAgIHJvb3RzLlMwLmgwdzggPSBbXTtcbiAgICByb290cy5TMC5oMHc4WzBdID0gRnIubXVsKHhpU2VlZDIsIHhpU2VlZCk7XG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPCA4OyBpKyspIHtcbiAgICAgICAgcm9vdHMuUzAuaDB3OFtpXSA9IEZyLm11bChyb290cy5TMC5oMHc4WzBdLCB3OFtpXSk7XG4gICAgfVxuXG4gICAgLy8gQ29tcHV0ZSBoMSA9IHhpX3NlZWRlcl42XG4gICAgcm9vdHMuUzEgPSB7fTtcbiAgICByb290cy5TMS5oMXc0ID0gW107XG4gICAgcm9vdHMuUzEuaDF3NFswXSA9IEZyLnNxdWFyZShyb290cy5TMC5oMHc4WzBdKTtcbiAgICBmb3IgKGxldCBpID0gMTsgaSA8IDQ7IGkrKykge1xuICAgICAgICByb290cy5TMS5oMXc0W2ldID0gRnIubXVsKHJvb3RzLlMxLmgxdzRbMF0sIHc0W2ldKTtcbiAgICB9XG5cbiAgICAvLyBDb21wdXRlIGgyID0geGlfc2VlZGVyXjhcbiAgICByb290cy5TMiA9IHt9O1xuICAgIHJvb3RzLlMyLmgydzMgPSBbXTtcbiAgICByb290cy5TMi5oMnczWzBdID0gRnIubXVsKHJvb3RzLlMxLmgxdzRbMF0sIHhpU2VlZDIpO1xuICAgIHJvb3RzLlMyLmgydzNbMV0gPSBGci5tdWwocm9vdHMuUzIuaDJ3M1swXSwgdzNbMV0pO1xuICAgIHJvb3RzLlMyLmgydzNbMl0gPSBGci5tdWwocm9vdHMuUzIuaDJ3M1swXSwgdzNbMl0pO1xuXG4gICAgcm9vdHMuUzIuaDN3MyA9IFtdO1xuICAgIC8vIE11bHRpcGx5IGgzIGJ5IHRoaXJkLXJvb3Qtb21lZ2EgdG8gb2J0YWluIGhfM14zID0geGnPiVxuICAgIC8vIFNvLCBoMyA9IHhpX3NlZWRlcl44IM+JXnsxLzN9XG4gICAgcm9vdHMuUzIuaDN3M1swXSA9IEZyLm11bChyb290cy5TMi5oMnczWzBdLCB2ay53cik7XG4gICAgcm9vdHMuUzIuaDN3M1sxXSA9IEZyLm11bChyb290cy5TMi5oM3czWzBdLCB3M1sxXSk7XG4gICAgcm9vdHMuUzIuaDN3M1syXSA9IEZyLm11bChyb290cy5TMi5oM3czWzBdLCB3M1syXSk7XG5cbiAgICAvLyBDb21wdXRlIHhpID0geGlfc2VlZGVyXjEyXG4gICAgY2hhbGxlbmdlcy54aSA9IEZyLm11bChGci5zcXVhcmUocm9vdHMuUzIuaDJ3M1swXSksIHJvb3RzLlMyLmgydzNbMF0pO1xuICAgIGNoYWxsZW5nZXMueGl3ID0gRnIubXVsKGNoYWxsZW5nZXMueGksIEZyLndbdmsucG93ZXJdKTtcblxuICAgIGNoYWxsZW5nZXMueGlOID0gY2hhbGxlbmdlcy54aTtcbiAgICB2ay5kb21haW5TaXplID0gMTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHZrLnBvd2VyOyBpKyspIHtcbiAgICAgICAgY2hhbGxlbmdlcy54aU4gPSBGci5zcXVhcmUoY2hhbGxlbmdlcy54aU4pO1xuICAgICAgICB2ay5kb21haW5TaXplICo9IDI7XG4gICAgfVxuXG4gICAgdHJhbnNjcmlwdC5yZXNldCgpO1xuICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHhpU2VlZCk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZXZhbHVhdGlvbnMucWwpO1xuICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHByb29mLmV2YWx1YXRpb25zLnFyKTtcbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5ldmFsdWF0aW9ucy5xbSk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZXZhbHVhdGlvbnMucW8pO1xuICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHByb29mLmV2YWx1YXRpb25zLnFjKTtcbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5ldmFsdWF0aW9ucy5zMSk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZXZhbHVhdGlvbnMuczIpO1xuICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKHByb29mLmV2YWx1YXRpb25zLnMzKTtcbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5ldmFsdWF0aW9ucy5hKTtcbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5ldmFsdWF0aW9ucy5iKTtcbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5ldmFsdWF0aW9ucy5jKTtcbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5ldmFsdWF0aW9ucy56KTtcbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5ldmFsdWF0aW9ucy56dyk7XG4gICAgdHJhbnNjcmlwdC5hZGRTY2FsYXIocHJvb2YuZXZhbHVhdGlvbnMudDF3KTtcbiAgICB0cmFuc2NyaXB0LmFkZFNjYWxhcihwcm9vZi5ldmFsdWF0aW9ucy50MncpO1xuICAgIGNoYWxsZW5nZXMuYWxwaGEgPSB0cmFuc2NyaXB0LmdldENoYWxsZW5nZSgpO1xuXG4gICAgdHJhbnNjcmlwdC5yZXNldCgpO1xuICAgIHRyYW5zY3JpcHQuYWRkU2NhbGFyKGNoYWxsZW5nZXMuYWxwaGEpO1xuICAgIHRyYW5zY3JpcHQuYWRkUG9sQ29tbWl0bWVudChwcm9vZi5wb2x5bm9taWFscy5XMSk7XG4gICAgY2hhbGxlbmdlcy55ID0gdHJhbnNjcmlwdC5nZXRDaGFsbGVuZ2UoKTtcblxuICAgIGlmIChsb2dnZXIpIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oXCLCt8K3wrcgY2hhbGxlbmdlcy5iZXRhOiAgXCIgKyBGci50b1N0cmluZyhjaGFsbGVuZ2VzLmJldGEpKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oXCLCt8K3wrcgY2hhbGxlbmdlcy5nYW1tYTogXCIgKyBGci50b1N0cmluZyhjaGFsbGVuZ2VzLmdhbW1hKSk7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiwrfCt8K3IGNoYWxsZW5nZXMueGk6ICAgIFwiICsgRnIudG9TdHJpbmcoY2hhbGxlbmdlcy54aSkpO1xuICAgICAgICBsb2dnZXIuaW5mbyhcIsK3wrfCtyBjaGFsbGVuZ2VzLmFscGhhOiBcIiArIEZyLnRvU3RyaW5nKGNoYWxsZW5nZXMuYWxwaGEpKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oXCLCt8K3wrcgY2hhbGxlbmdlcy55OiAgICAgXCIgKyBGci50b1N0cmluZyhjaGFsbGVuZ2VzLnkpKTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBjaGFsbGVuZ2VzOiBjaGFsbGVuZ2VzLCByb290czogcm9vdHMgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY29tcHV0ZUxhZ3JhbmdlRXZhbHVhdGlvbnMoY3VydmUsIGNoYWxsZW5nZXMsIHZrKSB7XG4gICAgY29uc3QgRnIgPSBjdXJ2ZS5GcjtcblxuICAgIGNvbnN0IHNpemUgPSBNYXRoLm1heCgxLCB2ay5uUHVibGljKTtcbiAgICBjb25zdCBudW1BcnIgPSBuZXcgQmlnQnVmZmVyKHNpemUgKiBGci5uOCk7XG4gICAgbGV0IGRlbkFyciA9IG5ldyBCaWdCdWZmZXIoc2l6ZSAqIEZyLm44KTtcblxuICAgIGxldCB3ID0gRnIub25lO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2l6ZTsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGlfc0ZyID0gaSAqIEZyLm44O1xuICAgICAgICBudW1BcnIuc2V0KEZyLm11bCh3LCBjaGFsbGVuZ2VzLnpoKSwgaV9zRnIpO1xuICAgICAgICBkZW5BcnIuc2V0KEZyLm11bChGci5lKHZrLmRvbWFpblNpemUpLCBGci5zdWIoY2hhbGxlbmdlcy54aSwgdykpLCBpX3NGcik7XG4gICAgICAgIHcgPSBGci5tdWwodywgdmsudyk7XG4gICAgfVxuXG4gICAgZGVuQXJyID0gYXdhaXQgRnIuYmF0Y2hJbnZlcnNlKGRlbkFycik7XG5cbiAgICBsZXQgTCA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2l6ZTsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGlfc0ZyID0gaSAqIEZyLm44O1xuICAgICAgICBMW2kgKyAxXSA9IEZyLm11bChudW1BcnIuc2xpY2UoaV9zRnIsIGlfc0ZyICsgRnIubjgpLCBkZW5BcnIuc2xpY2UoaV9zRnIsIGlfc0ZyICsgRnIubjgpKTtcbiAgICB9XG4gICAgcmV0dXJuIEw7XG59XG5cbmZ1bmN0aW9uIGNhbGN1bGF0ZVBJKGN1cnZlLCBwdWJsaWNTaWduYWxzLCBsYWdyYW5nZUV2YWxzKSB7XG4gICAgY29uc3QgRnIgPSBjdXJ2ZS5GcjtcblxuICAgIGxldCBwaSA9IEZyLnplcm87XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwdWJsaWNTaWduYWxzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IHcgPSBGci5lKHB1YmxpY1NpZ25hbHNbaV0pO1xuICAgICAgICBwaSA9IEZyLnN1YihwaSwgRnIubXVsKHcsIGxhZ3JhbmdlRXZhbHNbaSArIDFdKSk7XG4gICAgfVxuICAgIHJldHVybiBwaTtcbn1cblxuZnVuY3Rpb24gY29tcHV0ZVIwKHByb29mLCBjaGFsbGVuZ2VzLCByb290cywgY3VydmUsIGxvZ2dlcikge1xuICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG5cbiAgICBjb25zdCBMaSA9IGNvbXB1dGVMYWdyYW5nZUxpU2kocm9vdHMuUzAuaDB3OCwgY2hhbGxlbmdlcy55LCBjaGFsbGVuZ2VzLnhpLCBjdXJ2ZSk7XG5cbiAgICAvLyByMCh5KSA9IOKIkV8xXjggQ18wKGhfMCDPiV84XntpLTF9KSBMX2koeSkuIFRvIHRoaXMgZW5kIHdlIG5lZWQgdG8gY29tcHV0ZVxuXG4gICAgLy8gQ29tcHV0ZSB0aGUgOCBDMCB2YWx1ZXNcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgcjAoeSlcIik7XG5cbiAgICBsZXQgcmVzID0gRnIuemVybztcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IDg7IGkrKykge1xuICAgICAgICBsZXQgY29lZlZhbHVlcyA9IFtdO1xuICAgICAgICBjb2VmVmFsdWVzWzFdID0gcm9vdHMuUzAuaDB3OFtpXTtcbiAgICAgICAgZm9yIChsZXQgaiA9IDI7IGogPCA4OyBqKyspIHtcbiAgICAgICAgICAgIGNvZWZWYWx1ZXNbal0gPSBGci5tdWwoY29lZlZhbHVlc1tqIC0gMV0sIHJvb3RzLlMwLmgwdzhbaV0pO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGMwID0gRnIuYWRkKHByb29mLmV2YWx1YXRpb25zLnFsLCBGci5tdWwocHJvb2YuZXZhbHVhdGlvbnMucXIsIGNvZWZWYWx1ZXNbMV0pKTtcbiAgICAgICAgYzAgPSBGci5hZGQoYzAsIEZyLm11bChwcm9vZi5ldmFsdWF0aW9ucy5xbywgY29lZlZhbHVlc1syXSkpO1xuICAgICAgICBjMCA9IEZyLmFkZChjMCwgRnIubXVsKHByb29mLmV2YWx1YXRpb25zLnFtLCBjb2VmVmFsdWVzWzNdKSk7XG4gICAgICAgIGMwID0gRnIuYWRkKGMwLCBGci5tdWwocHJvb2YuZXZhbHVhdGlvbnMucWMsIGNvZWZWYWx1ZXNbNF0pKTtcbiAgICAgICAgYzAgPSBGci5hZGQoYzAsIEZyLm11bChwcm9vZi5ldmFsdWF0aW9ucy5zMSwgY29lZlZhbHVlc1s1XSkpO1xuICAgICAgICBjMCA9IEZyLmFkZChjMCwgRnIubXVsKHByb29mLmV2YWx1YXRpb25zLnMyLCBjb2VmVmFsdWVzWzZdKSk7XG4gICAgICAgIGMwID0gRnIuYWRkKGMwLCBGci5tdWwocHJvb2YuZXZhbHVhdGlvbnMuczMsIGNvZWZWYWx1ZXNbN10pKTtcblxuICAgICAgICByZXMgPSBGci5hZGQocmVzLCBGci5tdWwoYzAsIExpW2ldKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlcztcbn1cblxuZnVuY3Rpb24gY29tcHV0ZVIxKHByb29mLCBjaGFsbGVuZ2VzLCByb290cywgcGksIGN1cnZlLCBsb2dnZXIpIHtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuXG4gICAgY29uc3QgTGkgPSBjb21wdXRlTGFncmFuZ2VMaVNpKHJvb3RzLlMxLmgxdzQsIGNoYWxsZW5nZXMueSwgY2hhbGxlbmdlcy54aSwgY3VydmUpO1xuXG4gICAgLy8gcjEoeSkgPSDiiJFfMV40IENfMShoXzEgz4lfNF57aS0xfSkgTF9pKHkpLiBUbyB0aGlzIGVuZCB3ZSBuZWVkIHRvIGNvbXB1dGVcbiAgICAvLyBaMSA9IHtDMShoXzF9LCBDMShoXzEgz4lfNCksIEMxKGhfMSDPiV80XjIpLCBDMShoXzEgz4lfNF4zKX1cbiAgICAvLyB3aGVyZSBDXzEoaF8xIM+JXzRee2ktMX0pID0gZXZhbC5hICsgaF8xIM+JXzReaSBldmFsLmIgKyAoaF8xIM+JXzReaSleMiBldmFsLmMgKyAoaF8xIM+JXzReaSleMyBUMCh4aSksXG4gICAgLy8gd2hlcmUgVDAoeGkpID0gWyBxTMK3YSArIHFSwrdiICsgcU3Ct2HCt2IgKyBxT8K3YyArIHFDICsgUEkoeGkpIF0gLyBaX0goeGkpXG5cbiAgICAvLyBDb21wdXRlIFQwKHhpKVxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBUMCh4aSlcIik7XG4gICAgbGV0IHQwID0gRnIubXVsKHByb29mLmV2YWx1YXRpb25zLnFsLCBwcm9vZi5ldmFsdWF0aW9ucy5hKTtcbiAgICB0MCA9IEZyLmFkZCh0MCwgRnIubXVsKHByb29mLmV2YWx1YXRpb25zLnFyLCBwcm9vZi5ldmFsdWF0aW9ucy5iKSk7XG4gICAgdDAgPSBGci5hZGQodDAsIEZyLm11bChwcm9vZi5ldmFsdWF0aW9ucy5xbSwgRnIubXVsKHByb29mLmV2YWx1YXRpb25zLmEsIHByb29mLmV2YWx1YXRpb25zLmIpKSk7XG4gICAgdDAgPSBGci5hZGQodDAsIEZyLm11bChwcm9vZi5ldmFsdWF0aW9ucy5xbywgcHJvb2YuZXZhbHVhdGlvbnMuYykpO1xuICAgIHQwID0gRnIuYWRkKHQwLCBwcm9vZi5ldmFsdWF0aW9ucy5xYyk7XG4gICAgdDAgPSBGci5hZGQodDAsIHBpKTtcbiAgICB0MCA9IEZyLm11bCh0MCwgY2hhbGxlbmdlcy5pbnZ6aCk7XG5cbiAgICAvLyBDb21wdXRlIHRoZSA0IEMxIHZhbHVlc1xuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBDMShoXzHPiV80XmkpIHZhbHVlc1wiKTtcblxuICAgIGxldCByZXMgPSBGci56ZXJvO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgNDsgaSsrKSB7XG4gICAgICAgIGxldCBjMSA9IHByb29mLmV2YWx1YXRpb25zLmE7XG4gICAgICAgIGMxID0gRnIuYWRkKGMxLCBGci5tdWwocm9vdHMuUzEuaDF3NFtpXSwgcHJvb2YuZXZhbHVhdGlvbnMuYikpO1xuICAgICAgICBjb25zdCBoMXc0U3F1YXJlZCA9IEZyLnNxdWFyZShyb290cy5TMS5oMXc0W2ldKTtcbiAgICAgICAgYzEgPSBGci5hZGQoYzEsIEZyLm11bChoMXc0U3F1YXJlZCwgcHJvb2YuZXZhbHVhdGlvbnMuYykpO1xuICAgICAgICBjMSA9IEZyLmFkZChjMSwgRnIubXVsKEZyLm11bChoMXc0U3F1YXJlZCwgcm9vdHMuUzEuaDF3NFtpXSksIHQwKSk7XG5cbiAgICAgICAgcmVzID0gRnIuYWRkKHJlcywgRnIubXVsKGMxLCBMaVtpXSkpO1xuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVSMihwcm9vZiwgY2hhbGxlbmdlcywgcm9vdHMsIGxhZ3JhbmdlMSwgdmssIGN1cnZlLCBsb2dnZXIpIHtcbiAgICBjb25zdCBGciA9IGN1cnZlLkZyO1xuXG4gICAgY29uc3QgTGlTMiA9IGNvbXB1dGVMYWdyYW5nZUxpUzIoW3Jvb3RzLlMyLmgydzMsIHJvb3RzLlMyLmgzdzNdLCBjaGFsbGVuZ2VzLnksIGNoYWxsZW5nZXMueGksIGNoYWxsZW5nZXMueGl3LCBjdXJ2ZSk7XG5cbiAgICAvLyByMih5KSA9IOKIkV8xXjMgQ18yKGhfMiDPiV8zXntpLTF9KSBMX2koeSkgKyDiiJFfMV4zIENfMihoXzMgz4lfM157aS0xfSkgTF97aSszfSh5KS4gVG8gdGhpcyBlbmQgd2UgbmVlZCB0byBjb21wdXRlXG4gICAgLy8gWjIgPSB7W0MyKGhfMn0sIEMyKGhfMiDPiV8zKSwgQzIoaF8yIM+JXzNeMildLCBbQzIoaF8zfSwgQzIoaF8zIM+JXzMpLCBDMihoXzMgz4lfM14yKV19XG4gICAgLy8gd2hlcmUgQ18yKGhfMiDPiV8zXntpLTF9KSA9IGV2YWwueiArIGhfMiDPiV8yXmkgVDEoeGkpICsgKGhfMiDPiV8zXmkpXjIgVDIoeGkpLFxuICAgIC8vIHdoZXJlIENfMihoXzMgz4lfM157aS0xfSkgPSBldmFsLnogKyBoXzMgz4lfMl5pIFQxKHhpKSArIChoXzMgz4lfM15pKV4yIFQyKHhpKSxcbiAgICAvLyB3aGVyZSBUMSh4aSkgPSBbIExfMSh4aSkoei0xKV0gLyBaX0goeGkpXG4gICAgLy8gYW5kIFQyKHhpKSA9IFsgIChhICsgYmV0YcK3eGkgKyBnYW1tYSkoYiArIGJldGHCt3hpwrdrMSArIGdhbW1hKShjICsgYmV0YcK3eGnCt2syICsgZ2FtbWEpelxuICAgIC8vICAgICAgICAgICAgICAgLSAoYSArIGJldGHCt3NpZ21hMSArIGdhbW1hKShiICsgYmV0YcK3c2lnbWEyICsgZ2FtbWEpKGMgKyBiZXRhwrdzaWdtYTMgKyBnYW1tYSl6z4kgIF0gLyBaX0goeGkpXG5cbiAgICAvLyBDb21wdXRlIFQxKHhpKVxuICAgIGlmIChsb2dnZXIpIGxvZ2dlci5pbmZvKFwiwrfCt8K3IENvbXB1dGluZyBUMSh4aSlcIik7XG4gICAgbGV0IHQxID0gRnIuc3ViKHByb29mLmV2YWx1YXRpb25zLnosIEZyLm9uZSk7XG4gICAgdDEgPSBGci5tdWwodDEsIGxhZ3JhbmdlMSk7XG4gICAgdDEgPSBGci5tdWwodDEsIGNoYWxsZW5nZXMuaW52emgpO1xuXG4gICAgLy8gQ29tcHV0ZSBUMih4aSlcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgVDIoeGkpXCIpO1xuICAgIGNvbnN0IGJldGF4aSA9IEZyLm11bChjaGFsbGVuZ2VzLmJldGEsIGNoYWxsZW5nZXMueGkpO1xuICAgIGNvbnN0IHQyMTEgPSBGci5hZGQocHJvb2YuZXZhbHVhdGlvbnMuYSwgRnIuYWRkKGJldGF4aSwgY2hhbGxlbmdlcy5nYW1tYSkpO1xuICAgIGNvbnN0IHQyMTIgPSBGci5hZGQocHJvb2YuZXZhbHVhdGlvbnMuYiwgRnIuYWRkKEZyLm11bChiZXRheGksIHZrLmsxKSwgY2hhbGxlbmdlcy5nYW1tYSkpO1xuICAgIGNvbnN0IHQyMTMgPSBGci5hZGQocHJvb2YuZXZhbHVhdGlvbnMuYywgRnIuYWRkKEZyLm11bChiZXRheGksIHZrLmsyKSwgY2hhbGxlbmdlcy5nYW1tYSkpO1xuICAgIGNvbnN0IHQyMSA9IEZyLm11bCh0MjExLCBGci5tdWwodDIxMiwgRnIubXVsKHQyMTMsIHByb29mLmV2YWx1YXRpb25zLnopKSk7XG5cbiAgICBjb25zdCB0MjIxID0gRnIuYWRkKHByb29mLmV2YWx1YXRpb25zLmEsIEZyLmFkZChGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCBwcm9vZi5ldmFsdWF0aW9ucy5zMSksIGNoYWxsZW5nZXMuZ2FtbWEpKTtcbiAgICBjb25zdCB0MjIyID0gRnIuYWRkKHByb29mLmV2YWx1YXRpb25zLmIsIEZyLmFkZChGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCBwcm9vZi5ldmFsdWF0aW9ucy5zMiksIGNoYWxsZW5nZXMuZ2FtbWEpKTtcbiAgICBjb25zdCB0MjIzID0gRnIuYWRkKHByb29mLmV2YWx1YXRpb25zLmMsIEZyLmFkZChGci5tdWwoY2hhbGxlbmdlcy5iZXRhLCBwcm9vZi5ldmFsdWF0aW9ucy5zMyksIGNoYWxsZW5nZXMuZ2FtbWEpKTtcbiAgICBjb25zdCB0MjIgPSBGci5tdWwodDIyMSwgRnIubXVsKHQyMjIsIEZyLm11bCh0MjIzLCBwcm9vZi5ldmFsdWF0aW9ucy56dykpKTtcblxuICAgIGxldCB0MiA9IEZyLnN1Yih0MjEsIHQyMik7XG4gICAgdDIgPSBGci5tdWwodDIsIGNoYWxsZW5nZXMuaW52emgpO1xuXG4gICAgLy8gQ29tcHV0ZSB0aGUgNiBDMiB2YWx1ZXNcbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgQzIoaF8yz4lfM15pKSB2YWx1ZXNcIik7XG4gICAgbGV0IHJlcyA9IEZyLnplcm87XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCAzOyBpKyspIHtcbiAgICAgICAgbGV0IGMyID0gRnIuYWRkKHByb29mLmV2YWx1YXRpb25zLnosIEZyLm11bChyb290cy5TMi5oMnczW2ldLCB0MSkpO1xuICAgICAgICBjMiA9IEZyLmFkZChjMiwgRnIubXVsKEZyLnNxdWFyZShyb290cy5TMi5oMnczW2ldKSwgdDIpKTtcblxuICAgICAgICByZXMgPSBGci5hZGQocmVzLCBGci5tdWwoYzIsIExpUzJbaV0pKTtcbiAgICB9XG5cbiAgICBpZiAobG9nZ2VyKSBsb2dnZXIuaW5mbyhcIsK3wrfCtyBDb21wdXRpbmcgQzIoaF8zz4lfM15pKSB2YWx1ZXNcIik7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCAzOyBpKyspIHtcbiAgICAgICAgbGV0IGMyID0gRnIuYWRkKHByb29mLmV2YWx1YXRpb25zLnp3LCBGci5tdWwocm9vdHMuUzIuaDN3M1tpXSwgcHJvb2YuZXZhbHVhdGlvbnMudDF3KSk7XG4gICAgICAgIGMyID0gRnIuYWRkKGMyLCBGci5tdWwoRnIuc3F1YXJlKHJvb3RzLlMyLmgzdzNbaV0pLCBwcm9vZi5ldmFsdWF0aW9ucy50MncpKTtcblxuICAgICAgICByZXMgPSBGci5hZGQocmVzLCBGci5tdWwoYzIsIExpUzJbaSArIDNdKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlcztcbn1cblxuZnVuY3Rpb24gY29tcHV0ZUYoY3VydmUsIHByb29mLCB2aywgY2hhbGxlbmdlcywgcm9vdHMpIHtcbiAgICBjb25zdCBHMSA9IGN1cnZlLkcxO1xuICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG5cbiAgICBsZXQgbXVsSDAgPSBGci5zdWIoY2hhbGxlbmdlcy55LCByb290cy5TMC5oMHc4WzBdKTtcbiAgICBmb3IgKGxldCBpID0gMTsgaSA8IDg7IGkrKykge1xuICAgICAgICBtdWxIMCA9IEZyLm11bChtdWxIMCwgRnIuc3ViKGNoYWxsZW5nZXMueSwgcm9vdHMuUzAuaDB3OFtpXSkpO1xuICAgIH1cblxuICAgIGNoYWxsZW5nZXMudGVtcCA9IG11bEgwO1xuXG4gICAgbGV0IG11bEgxID0gRnIuc3ViKGNoYWxsZW5nZXMueSwgcm9vdHMuUzEuaDF3NFswXSk7XG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPCA0OyBpKyspIHtcbiAgICAgICAgbXVsSDEgPSBGci5tdWwobXVsSDEsIEZyLnN1YihjaGFsbGVuZ2VzLnksIHJvb3RzLlMxLmgxdzRbaV0pKTtcbiAgICB9XG5cbiAgICBsZXQgbXVsSDIgPSBGci5zdWIoY2hhbGxlbmdlcy55LCByb290cy5TMi5oMnczWzBdKTtcbiAgICBmb3IgKGxldCBpID0gMTsgaSA8IDM7IGkrKykge1xuICAgICAgICBtdWxIMiA9IEZyLm11bChtdWxIMiwgRnIuc3ViKGNoYWxsZW5nZXMueSwgcm9vdHMuUzIuaDJ3M1tpXSkpO1xuICAgIH1cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IDM7IGkrKykge1xuICAgICAgICBtdWxIMiA9IEZyLm11bChtdWxIMiwgRnIuc3ViKGNoYWxsZW5nZXMueSwgcm9vdHMuUzIuaDN3M1tpXSkpO1xuICAgIH1cblxuICAgIGNoYWxsZW5nZXMucXVvdGllbnQxID0gRnIubXVsKGNoYWxsZW5nZXMuYWxwaGEsIEZyLmRpdihtdWxIMCwgbXVsSDEpKTtcbiAgICBjaGFsbGVuZ2VzLnF1b3RpZW50MiA9IEZyLm11bChGci5zcXVhcmUoY2hhbGxlbmdlcy5hbHBoYSksIEZyLmRpdihtdWxIMCwgbXVsSDIpKTtcblxuICAgIGxldCBGMiA9IEcxLnRpbWVzRnIocHJvb2YucG9seW5vbWlhbHMuQzEsIGNoYWxsZW5nZXMucXVvdGllbnQxKTtcbiAgICBsZXQgRjMgPSBHMS50aW1lc0ZyKHByb29mLnBvbHlub21pYWxzLkMyLCBjaGFsbGVuZ2VzLnF1b3RpZW50Mik7XG5cbiAgICByZXR1cm4gRzEuYWRkKHZrLkMwLCBHMS5hZGQoRjIsIEYzKSk7XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVFKGN1cnZlLCBwcm9vZiwgY2hhbGxlbmdlcywgdmssIHIwLCByMSwgcjIpIHtcbiAgICBjb25zdCBHMSA9IGN1cnZlLkcxO1xuICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG5cbiAgICBsZXQgRTIgPSBGci5tdWwocjEsIGNoYWxsZW5nZXMucXVvdGllbnQxKTtcbiAgICBsZXQgRTMgPSBGci5tdWwocjIsIGNoYWxsZW5nZXMucXVvdGllbnQyKTtcblxuICAgIHJldHVybiBHMS50aW1lc0ZyKEcxLm9uZSwgRnIuYWRkKHIwLCBGci5hZGQoRTIsIEUzKSkpO1xufVxuXG5mdW5jdGlvbiBjb21wdXRlSihjdXJ2ZSwgcHJvb2YsIGNoYWxsZW5nZXMpIHtcbiAgICBjb25zdCBHMSA9IGN1cnZlLkcxO1xuXG4gICAgcmV0dXJuIEcxLnRpbWVzRnIocHJvb2YucG9seW5vbWlhbHMuVzEsIGNoYWxsZW5nZXMudGVtcCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGlzVmFsaWRQYWlyaW5nKGN1cnZlLCBwcm9vZiwgY2hhbGxlbmdlcywgdmssIEYsIEUsIEopIHtcbiAgICBjb25zdCBHMSA9IGN1cnZlLkcxO1xuXG4gICAgbGV0IEExID0gRzEudGltZXNGcihwcm9vZi5wb2x5bm9taWFscy5XMiwgY2hhbGxlbmdlcy55KTtcbiAgICBBMSA9IEcxLmFkZChHMS5zdWIoRzEuc3ViKEYsIEUpLCBKKSwgQTEpO1xuICAgIGNvbnN0IEEyID0gY3VydmUuRzIub25lO1xuXG4gICAgY29uc3QgQjEgPSBwcm9vZi5wb2x5bm9taWFscy5XMjtcbiAgICBjb25zdCBCMiA9IHZrLlhfMjtcblxuICAgIHJldHVybiBhd2FpdCBjdXJ2ZS5wYWlyaW5nRXEoRzEubmVnKEExKSwgQTIsIEIxLCBCMik7XG59XG5cblxuZXhwb3J0IGZ1bmN0aW9uIGNvbXB1dGVMYWdyYW5nZUxpU2kocm9vdHMsIHgsIHhpLCBjdXJ2ZSkge1xuICAgIGNvbnN0IEZyID0gY3VydmUuRnI7XG4gICAgY29uc3QgbGVuID0gcm9vdHMubGVuZ3RoO1xuXG4gICAgY29uc3QgbnVtID0gRnIuc3ViKEZyLmV4cCh4LCBsZW4pLCB4aSk7XG4gICAgY29uc3QgZGVuMSA9IEZyLm11bChGci5lKGxlbiksIEZyLmV4cChyb290c1swXSwgbGVuIC0gMikpO1xuXG4gICAgY29uc3QgTGkgPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGRlbjIgPSByb290c1soKGxlbiAtIDEpICogaSkgJSBsZW5dO1xuICAgICAgICBjb25zdCBkZW4zID0gRnIuc3ViKHgsIHJvb3RzW2ldKTtcblxuICAgICAgICBMaVtpXSA9IEZyLmRpdihudW0sIEZyLm11bChGci5tdWwoZGVuMSwgZGVuMiksIGRlbjMpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gTGk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjb21wdXRlTGFncmFuZ2VMaVMyKHJvb3RzLCB2YWx1ZSwgeGkwLCB4aTEsIGN1cnZlKSB7XG4gICAgY29uc3QgRnIgPSBjdXJ2ZS5GcjtcblxuICAgIGNvbnN0IExpID0gW107XG5cbiAgICBjb25zdCBsZW4gPSByb290c1swXS5sZW5ndGg7XG4gICAgY29uc3QgbiA9IGxlbiAqIHJvb3RzLmxlbmd0aDtcblxuICAgIGNvbnN0IG51bTEgPSBGci5leHAodmFsdWUsIG4pO1xuICAgIGNvbnN0IG51bTIgPSBGci5tdWwoRnIuYWRkKHhpMCwgeGkxKSwgRnIuZXhwKHZhbHVlLCBsZW4pKTtcbiAgICBjb25zdCBudW0zID0gRnIubXVsKHhpMCwgeGkxKTtcbiAgICBjb25zdCBudW0gPSBGci5hZGQoRnIuc3ViKG51bTEsIG51bTIpLCBudW0zKTtcblxuICAgIGxldCBkZW4xID0gRnIubXVsKEZyLm11bChGci5lKGxlbiksIHJvb3RzWzBdWzBdKSwgRnIuc3ViKHhpMCwgeGkxKSk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgICBjb25zdCBkZW4yID0gcm9vdHNbMF1bKGxlbiAtIDEpICogaSAlIGxlbl07XG4gICAgICAgIGNvbnN0IGRlbjMgPSBGci5zdWIodmFsdWUsIHJvb3RzWzBdW2ldKTtcblxuICAgICAgICBjb25zdCBkZW4gPSBGci5tdWwoZGVuMSxGci5tdWwoZGVuMiwgZGVuMykpO1xuXG4gICAgICAgIExpW2ldID0gRnIuZGl2KG51bSwgZGVuKTtcbiAgICB9XG5cbiAgICBkZW4xID0gRnIubXVsKEZyLm11bChGci5lKGxlbiksIHJvb3RzWzFdWzBdKSwgRnIuc3ViKHhpMSwgeGkwKSk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgICBjb25zdCBkZW4yID0gcm9vdHNbMV1bKGxlbiAtIDEpICogaSAlIGxlbl07XG4gICAgICAgIGNvbnN0IGRlbjMgPSBGci5zdWIodmFsdWUsIHJvb3RzWzFdW2ldKTtcblxuICAgICAgICBjb25zdCBkZW4gPSBGci5tdWwoZGVuMSxGci5tdWwoZGVuMiwgZGVuMykpO1xuXG4gICAgICAgIExpW2kgKyBsZW5dID0gRnIuZGl2KG51bSwgZGVuKTtcbiAgICB9XG5cbiAgICByZXR1cm4gTGk7XG59XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDIxIDBLSU1TIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtKUy5cblxuICAgIHNuYXJrSlMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0XG4gICAgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya0pTIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUXG4gICAgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljXG4gICAgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIHNuYXJrSlMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQge2dldEN1cnZlRnJvbU5hbWV9IGZyb20gXCIuL2N1cnZlcy5qc1wiO1xuaW1wb3J0IHt1dGlsc30gZnJvbSBcImZmamF2YXNjcmlwdFwiO1xuXG5jb25zdCB7dW5zdHJpbmdpZnlCaWdJbnRzfSA9IHV0aWxzO1xuXG5mdW5jdGlvbiBwMjU2KG4pIHtcbiAgICBsZXQgbnN0ciA9IG4udG9TdHJpbmcoMTYpO1xuICAgIHdoaWxlIChuc3RyLmxlbmd0aCA8IDY0KSBuc3RyID0gXCIwXCIgKyBuc3RyO1xuICAgIG5zdHIgPSBgMHgke25zdHJ9YDtcbiAgICByZXR1cm4gbnN0cjtcbn1cblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gZmZsb25rRXhwb3J0Q2FsbERhdGEoX3B1YiwgX3Byb29mKSB7XG4gICAgY29uc3QgcHJvb2YgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX3Byb29mKTtcbiAgICBjb25zdCBwdWIgPSB1bnN0cmluZ2lmeUJpZ0ludHMoX3B1Yik7XG5cbiAgICBhd2FpdCBnZXRDdXJ2ZUZyb21OYW1lKHByb29mLmN1cnZlKTtcblxuICAgIGxldCBpbnB1dHMgPSBcIlwiO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcHViLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChpbnB1dHMgIT09IFwiXCIpIGlucHV0cyA9IGlucHV0cyArIFwiLFwiO1xuICAgICAgICBpbnB1dHMgPSBpbnB1dHMgKyBwMjU2KHB1YltpXSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGBbJHtwMjU2KHByb29mLnBvbHlub21pYWxzLkMxWzBdKX0sICR7cDI1Nihwcm9vZi5wb2x5bm9taWFscy5DMVsxXSl9LGAgK1xuICAgIGAke3AyNTYocHJvb2YucG9seW5vbWlhbHMuQzJbMF0pfSwke3AyNTYocHJvb2YucG9seW5vbWlhbHMuQzJbMV0pfSxgICtcbiAgICBgJHtwMjU2KHByb29mLnBvbHlub21pYWxzLlcxWzBdKX0sJHtwMjU2KHByb29mLnBvbHlub21pYWxzLlcxWzFdKX0sYCArXG4gICAgYCR7cDI1Nihwcm9vZi5wb2x5bm9taWFscy5XMlswXSl9LCR7cDI1Nihwcm9vZi5wb2x5bm9taWFscy5XMlsxXSl9LGAgK1xuICAgIGAke3AyNTYocHJvb2YuZXZhbHVhdGlvbnMucWwpfSwke3AyNTYocHJvb2YuZXZhbHVhdGlvbnMucXIpfSwke3AyNTYocHJvb2YuZXZhbHVhdGlvbnMucW0pfSxgICtcbiAgICBgJHtwMjU2KHByb29mLmV2YWx1YXRpb25zLnFvKX0sJHtwMjU2KHByb29mLmV2YWx1YXRpb25zLnFjKX0sJHtwMjU2KHByb29mLmV2YWx1YXRpb25zLnMxKX0sYCArXG4gICAgYCR7cDI1Nihwcm9vZi5ldmFsdWF0aW9ucy5zMil9LCR7cDI1Nihwcm9vZi5ldmFsdWF0aW9ucy5zMyl9LCR7cDI1Nihwcm9vZi5ldmFsdWF0aW9ucy5hKX0sYCArXG4gICAgYCR7cDI1Nihwcm9vZi5ldmFsdWF0aW9ucy5iKX0sJHtwMjU2KHByb29mLmV2YWx1YXRpb25zLmMpfSwke3AyNTYocHJvb2YuZXZhbHVhdGlvbnMueil9LGAgK1xuICAgIGAke3AyNTYocHJvb2YuZXZhbHVhdGlvbnMuencpfSwke3AyNTYocHJvb2YuZXZhbHVhdGlvbnMudDF3KX0sJHtwMjU2KHByb29mLmV2YWx1YXRpb25zLnQydyl9LGAgK1xuICAgIGAke3AyNTYocHJvb2YuZXZhbHVhdGlvbnMuaW52KX1dLGAgK1xuICAgIGBbJHtpbnB1dHN9XWA7XG59XG4iLCIvKlxuICAgIENvcHlyaWdodCAyMDIyIGlkZW4zIGFzc29jaWF0aW9uLlxuXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2Ygc25hcmtqcy5cblxuICAgIHNuYXJranMgaXMgYSBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3JcbiAgICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlXG4gICAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pXG4gICAgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBzbmFya2pzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZXG4gICAgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yXG4gICAgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aFxuICAgIHNuYXJranMuIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5leHBvcnQgeyBkZWZhdWx0IGFzIHNldHVwIH0gZnJvbSBcIi4vZmZsb25rX3NldHVwLmpzXCI7XG5leHBvcnQgeyBkZWZhdWx0IGFzIHByb3ZlIH0gZnJvbSBcIi4vZmZsb25rX3Byb3ZlLmpzXCI7XG5leHBvcnQgeyBkZWZhdWx0IGFzIGZ1bGxQcm92ZSB9IGZyb20gXCIuL2ZmbG9ua19mdWxsX3Byb3ZlLmpzXCI7XG5leHBvcnQgeyBkZWZhdWx0IGFzIHZlcmlmeSB9IGZyb20gXCIuL2ZmbG9ua192ZXJpZnkuanNcIjtcbmV4cG9ydCB7IGRlZmF1bHQgYXMgZXhwb3J0U29saWRpdHlWZXJpZmllciB9IGZyb20gXCIuL2ZmbG9ua19leHBvcnRfc29saWRpdHlfdmVyaWZpZXIuanNcIjtcbmV4cG9ydCB7IGRlZmF1bHQgYXMgZXhwb3J0U29saWRpdHlDYWxsRGF0YSB9IGZyb20gXCIuL2ZmbG9ua19leHBvcnRfY2FsbGRhdGEuanNcIjtcbiJdLCJuYW1lcyI6WyJhZGQiLCJnZXRSYW5kb21CeXRlcyIsInN0cmluZ2lmeUJpZ0ludHMiLCJ1bnN0cmluZ2lmeUJpZ0ludHMiLCJsb2cyIiwiUEFHRV9TSVpFIiwiaXNOb2RlIiwiYmxzMTIzODFyIiwiYm4xMjhyIiwiZ2V0Q3VydmVGcm9tUiIsIm9wZW4iLCJGYXN0RmlsZSIsImNyZWF0ZU5ldyIsIk1lbUZpbGUiLCJyZWFkRXhpc3RpbmciLCJ0bXBCdWZmMzIiLCJ0bXBCdWZmMzJ2IiwidG1wQnVmZjY0IiwidG1wQnVmZjY0diIsIkJpZ01lbUZpbGUiLCJERUZBVUxUX0NBQ0hFX1NJWkUiLCJERUZBVUxUX1BBR0VfU0laRSIsImNyZWF0ZU92ZXJyaWRlIiwibWVtRmlsZS5jcmVhdGVOZXciLCJiaWdNZW1GaWxlLmNyZWF0ZU5ldyIsIm1lbUZpbGUucmVhZEV4aXN0aW5nIiwiYmlnTWVtRmlsZS5yZWFkRXhpc3RpbmciLCJyZWFkQmluRmlsZSIsImZhc3RGaWxlLnJlYWRFeGlzdGluZyIsImZhc3RGaWxlLmNyZWF0ZU92ZXJyaWRlIiwic3RhcnRSZWFkVW5pcXVlU2VjdGlvbiIsImVuZFJlYWRTZWN0aW9uIiwicmVhZEJpZ0ludCIsInJlYWRTZWN0aW9uIiwidTY0LmFkZDNMIiwidTY0LmFkZDNIIiwidTY0LnJvdHIzMkgiLCJ1NjQucm90cjMyTCIsInU2NC5hZGQiLCJ1NjQucm90clNIIiwidTY0LnJvdHJTTCIsInU2NC5yb3RyQkgiLCJ1NjQucm90ckJMIiwidTY0LmZyb21CaWciLCJzYW1lUmF0aW8iLCJiaW5GaWxlVXRpbHMuc3RhcnRXcml0ZVNlY3Rpb24iLCJiaW5GaWxlVXRpbHMuZW5kV3JpdGVTZWN0aW9uIiwiZ2V0Q3VydmUiLCJiaW5GaWxlVXRpbHMud3JpdGVCaWdJbnQiLCJyZWFkSGVhZGVyIiwiYmluRmlsZVV0aWxzLnN0YXJ0UmVhZFVuaXF1ZVNlY3Rpb24iLCJiaW5GaWxlVXRpbHMuZW5kUmVhZFNlY3Rpb24iLCJiaW5GaWxlVXRpbHMucmVhZEJpZ0ludCIsImJpbkZpbGVVdGlscy5yZWFkQmluRmlsZSIsIkYxRmllbGQiLCJyZWFkQ29udHJpYnV0aW9uIiwid3JpdGVDb250cmlidXRpb24iLCJ3dG5zVXRpbHMucmVhZEhlYWRlciIsInprZXlVdGlscy5yZWFkSGVhZGVyIiwiYmluRmlsZVV0aWxzLnJlYWRTZWN0aW9uIiwiV2l0bmVzc0NhbGN1bGF0b3JCdWlsZGVyIiwiYmluRmlsZVV0aWxzLmNyZWF0ZUJpbkZpbGUiLCJ3dG5zVXRpbHMud3JpdGVCaW4iLCJ3dG5zX2NhbGN1bGF0ZSIsImdyb3RoMTZfcHJvdmUiLCJjdXJ2ZXMuZ2V0Q3VydmVGcm9tTmFtZSIsInB1YmxpY0lucHV0c0FyZVZhbGlkIiwiaXNXZWxsQ29uc3RydWN0ZWQiLCJjaGVja1ZhbHVlQmVsb25nVG9GaWVsZCIsInAyNTYiLCJtaXNjLmZyb21QYXJ0aWFsSGFzaCIsIm1pc2Mucm5nRnJvbUJlYWNvblBhcmFtcyIsImtleVBhaXIuY3JlYXRlUFRhdUtleSIsInB0YXVVdGlscy53cml0ZVBUYXVIZWFkZXIiLCJwdGF1VXRpbHMuY2FsY3VsYXRlRmlyc3RDaGFsbGVuZ2VIYXNoIiwibWlzYy5mb3JtYXRIYXNoIiwidXRpbHMucmVhZFBUYXVIZWFkZXIiLCJ1dGlscy5yZWFkQ29udHJpYnV0aW9ucyIsInV0aWxzLmNhbGN1bGF0ZUZpcnN0Q2hhbGxlbmdlSGFzaCIsIm1pc2MuaGFzaElzRXF1YWwiLCJ1dGlscy53cml0ZVBUYXVIZWFkZXIiLCJtaXNjLnRvUGFydGlhbEhhc2giLCJ1dGlscy5mcm9tUHRhdVB1YktleVJwciIsInV0aWxzLndyaXRlQ29udHJpYnV0aW9ucyIsIm1pc2Muc2FtZVJhdGlvIiwidXRpbHMua2V5RnJvbUJlYWNvbiIsImtleVBhaXIuZ2V0RzJzcCIsInV0aWxzLnRvUHRhdVB1YktleVJwciIsIm1pc2MuYnl0ZUFycmF5MmhleCIsIm1pc2MuZ2V0UmFuZG9tQnl0ZXMiLCJtaXNjLnJlYWRVSW50MzJCRSIsIm1pc2MuZ2V0UmFuZG9tUm5nIiwiYmVhY29uIiwibWlzYy5oZXgyQnl0ZUFycmF5IiwiYmluRmlsZVV0aWxzLmNvcHlTZWN0aW9uIiwiU1VCQVJSQVlfU0laRSIsIkJpZ0FycmF5SGFuZGxlciIsIkJpZ0FycmF5IiwiX0JpZ0FycmF5IiwibG9hZFN5bXMiLCJ3dG5zVXRpbHMud3JpdGUiLCJjdXJ2ZXMuZ2V0Q3VydmVGcm9tUiIsInprZXlVdGlscy5yZWFkTVBDUGFyYW1zIiwiemtleVV0aWxzLndyaXRlSGVhZGVyIiwiemtleVV0aWxzLndyaXRlTVBDUGFyYW1zIiwibWlzYy5jbG9uZUhhc2hlciIsImJpbkZpbGVVdGlscy5zZWN0aW9uSXNFcXVhbCIsInV0aWxzLmhhc2hQdWJLZXkiLCJ1dGlscy5oYXNoRzEiLCJleHBvcnRWZXJpZmljYXRpb25LZXkiLCJmZmxvbmtFeHBvcnRTb2xpZGl0eVZlcmlmaWVyQ21kIiwicGxvbmtfcHJvdmUiLCJmcm9tT2JqZWN0VmsiLCJldmFsdWF0aW9uc0FyZVZhbGlkIiwiY2FsY3VsYXRlUEkiLCJpc1ZhbGlkUGFpcmluZyIsImNoZWNrRXZhbHVhdGlvbklzVmFsaWQiXSwibWFwcGluZ3MiOiI7OztJQUFBLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDOztJQUVoRSxTQUFTLFVBQVUsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFO0lBQzlCLElBQUksSUFBSSxDQUFDLENBQUMsS0FBSyxJQUFJLEtBQUssRUFBRSxFQUFFLENBQUMsRUFBRTtJQUMvQixRQUFRLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQztJQUN4QixJQUFJLENBQUMsTUFBTSxJQUFJLEtBQUssRUFBRSxFQUFFLEVBQUU7SUFDMUIsUUFBUSxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRTtJQUNsQyxZQUFZLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQztJQUM1QixRQUFRLENBQUMsTUFBTTtJQUNmLFlBQVksT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNqQyxRQUFRO0lBQ1IsSUFBSTtJQUNKOztJQUVBLE1BQU0sQ0FBQyxHQUFHLFVBQVU7O0lBRXBCLFNBQVMsU0FBUyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUU7SUFDN0IsSUFBSSxJQUFJLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ3RCLElBQUksS0FBSyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUM7SUFDekIsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtJ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QUVBLFNBQVMsTUFBTSxDQUFDLENBQUMsRUFBRTtJQUNuQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDaEM7O0lBRUEsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNuQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDakM7O0lBRUEsU0FBUyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNyQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDakM7O0lBRUEsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFO0lBQ2hCLElBQUksT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDbEQ7O0lBRUEsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNuQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDaEM7O0lBRUEsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNuQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDaEM7O0lBRUEsU0FBUyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNsQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDakM7O0lBRUEsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNuQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDakM7O0lBRUEsU0FBUyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNsQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDaEM7O0lBRUEsU0FBUyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNsQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDaEM7O0lBRUEsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNuQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDakM7O0lBRUEsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNuQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDakM7O0lBRUEsU0FBUyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNwQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDaEM7O0lBRUEsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNuQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDaEM7O0lBRUEsU0FBUyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNwQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDaEM7O0lBRUEsU0FBUyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNwQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDakM7O0lBRUEsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNuQixJQUFJLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDakM7O0lBRUEsU0FBUyxJQUFJLENBQUMsQ0FBQyxFQUFFO0lBQ2pCLElBQUksT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDckI7O0lBRUE7SUFDQSxTQUFTLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUU7SUFDakMsSUFBSSxNQUFNLENBQUMsR0FBRyxTQUFTLEdBQUcsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7SUFDeEMsSUFBSSxNQUFNLENBQUMsR0FBRyxJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDckUsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDNUMsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUMxRixJQUFJLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQzNDLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3hGOztJQUVBO0lBQ0EsU0FBUyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFO0lBQ2pDLElBQUksTUFBTSxDQUFDLEdBQUcsU0FBUyxHQUFHLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO0lBQ3hDLElBQUksTUFBTSxDQUFDLEdBQUcsSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUM7SUFDaEUsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDNUMsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDO0lBQ2xILElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3pDOztJQUVBO0lBQ0EsU0FBUyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUU7SUFDaEMsSUFBSSxFQUFFLEdBQUcsRUFBRSxJQUFJLElBQUksQ0FBQyxVQUFVO0lBQzlCLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO0lBQ2QsSUFBSSxNQUFNLENBQUMsR0FBRyxJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDckUsSUFBSSxNQUFNLENBQUMsR0FBRyxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzdCLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRTtJQUM1RSxJQUFJLE9BQU8sVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQ3JDOztJQUVBO0lBQ0EsU0FBUyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUU7SUFDaEMsSUFBSSxFQUFFLEdBQUcsRUFBRSxJQUFJLElBQUksQ0FBQyxVQUFVO0lBQzlCLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO0lBQ2QsSUFBSSxNQUFNLENBQUMsR0FBRyxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUNoRSxJQUFJLE1BQU0sQ0FBQyxHQUFHLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDN0IsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUMvQixRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDO0lBQ3BFLElBQUk7SUFDSixJQUFJLE9BQU8sVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQ3JDOztJQUVBLFNBQVMsUUFBUSxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUU7SUFDNUIsSUFBSSxPQUFPLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDO0lBQzVCOztJQUVBLFNBQVMsUUFBUSxDQUFDLENBQUMsRUFBRTtJQUNyQixJQUFJLE1BQU0sSUFBSSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN0RSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3hDLElBQUksT0FBTyxJQUFJO0lBQ2Y7O0lBRUEsTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqQixNQUFNLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDOztJQUVoQixJQUFJLE9BQU8sZ0JBQWdCLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDekMsSUFBSSxTQUFTLEVBQUUsSUFBSTtJQUNuQixJQUFJLEdBQUcsRUFBRSxHQUFHO0lBQ1osSUFBSSxHQUFHLEVBQUVBLEtBQUc7SUFDWixJQUFJLElBQUksRUFBRSxJQUFJO0lBQ2QsSUFBSSxTQUFTLEVBQUUsU0FBUztJQUN4QixJQUFJLElBQUksRUFBRSxJQUFJO0lBQ2QsSUFBSSxHQUFHLEVBQUUsR0FBRztJQUNaLElBQUksSUFBSSxFQUFFLElBQUk7SUFDZCxJQUFJLEdBQUcsRUFBRSxHQUFHO0lBQ1osSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUNSLElBQUksRUFBRSxFQUFFLEVBQUU7SUFDVixJQUFJLEdBQUcsRUFBRSxLQUFLO0lBQ2QsSUFBSSxTQUFTLEVBQUUsU0FBUztJQUN4QixJQUFJLFNBQVMsRUFBRSxTQUFTO0lBQ3hCLElBQUksU0FBUyxFQUFFLFNBQVM7SUFDeEIsSUFBSSxVQUFVLEVBQUUsVUFBVTtJQUMxQixJQUFJLEdBQUcsRUFBRSxHQUFHO0lBQ1osSUFBSSxFQUFFLEVBQUUsRUFBRTtJQUNWLElBQUksVUFBVSxFQUFFLFVBQVU7SUFDMUIsSUFBSSxLQUFLLEVBQUUsS0FBSztJQUNoQixJQUFJLE1BQU0sRUFBRSxNQUFNO0lBQ2xCLElBQUksSUFBSSxFQUFFLElBQUk7SUFDZCxJQUFJLEdBQUcsRUFBRSxHQUFHO0lBQ1osSUFBSSxJQUFJLEVBQUUsSUFBSTtJQUNkLElBQUksR0FBRyxFQUFFLEdBQUc7SUFDWixJQUFJLEVBQUUsRUFBRSxFQUFFO0lBQ1YsSUFBSSxHQUFHLEVBQUUsR0FBRztJQUNaLElBQUksR0FBRyxFQUFFLEdBQUc7SUFDWixJQUFJLEdBQUcsRUFBRSxHQUFHO0lBQ1osSUFBSSxHQUFHLEVBQUUsR0FBRztJQUNaLElBQUksR0FBRyxFQUFFLEdBQUc7SUFDWixJQUFJLEdBQUcsRUFBRSxHQUFHO0lBQ1osSUFBSSxHQUFHLEVBQUUsR0FBRztJQUNaLElBQUksU0FBUyxFQUFFLFNBQVM7SUFDeEIsSUFBSSxVQUFVLEVBQUUsVUFBVTtJQUMxQixJQUFJLEdBQUcsRUFBRSxHQUFHO0lBQ1osSUFBSSxHQUFHLEVBQUUsR0FBRztJQUNaLElBQUksTUFBTSxFQUFFLE1BQU07SUFDbEIsSUFBSSxHQUFHLEVBQUUsR0FBRztJQUNaLElBQUksT0FBTyxFQUFFLE9BQU87SUFDcEIsSUFBSSxRQUFRLEVBQUUsUUFBUTtJQUN0QixJQUFJLFFBQVEsRUFBRSxRQUFRO0lBQ3RCLElBQUksT0FBTyxFQUFFLE9BQU87SUFDcEIsSUFBSSxPQUFPLEVBQUUsT0FBTztJQUNwQixJQUFJLFFBQVEsRUFBRSxRQUFRO0lBQ3RCLElBQUksSUFBSSxFQUFFO0lBQ1YsQ0FBQyxDQUFDOzs7SUE4cEJGO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBOzs7SUFHQSxTQUFTLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRTs7SUFFekIsSUFBSSxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQyxHQUFHOztJQUUvQixJQUFJLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7O0lBRXJCLElBQUksSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQyxHQUFHOztJQUVqQyxJQUFJLElBQUksR0FBRyxHQUFHLElBQUk7O0lBRWxCLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFOztJQUV0QyxRQUFRLEdBQUcsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQzs7SUFFM0IsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNsQixZQUFZLEdBQUcsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUM7SUFDbEMsUUFBUTtJQUNSLElBQUk7O0lBRUosSUFBSSxPQUFPLEdBQUc7SUFDZDs7SUFFQTs7SUFFQSxTQUFTLFNBQVMsRUFBRSxDQUFDLEVBQUU7SUFDdkIsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFO0lBQ3hCLFFBQVEsSUFBSSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDakMsWUFBWSxJQUFJLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNyQyxnQkFBZ0IsSUFBSSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDMUM7SUFDQSxvQkFBb0Isa0JBQWtCLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLGdCQUFnQixDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDakQsb0JBQW9CLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDaEMsZ0JBQWdCLENBQUMsTUFBTTtJQUN2QixvQkFBb0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQztJQUN4RCxnQkFBZ0I7SUFDaEIsWUFBWSxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDNUMsZ0JBQWdCLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDN0IsWUFBWSxDQUFDLE1BQU07SUFDbkIsZ0JBQWdCLE1BQU0sSUFBSSxLQUFLLENBQUMsbUJBQW1CLENBQUM7SUFDcEQsWUFBWTtJQUNaLFFBQVEsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3hDLFlBQVksV0FBVyxDQUFDLENBQUMsQ0FBQztJQUMxQixRQUFRO0lBQ1IsSUFBSSxDQUFDLE1BQU07SUFDWCxRQUFRLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMvQyxRQUFRLElBQUksT0FBTyxJQUFJLENBQUMsRUFBRTtJQUMxQixZQUFZLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDeEIsUUFBUSxDQUFDLE1BQU0sSUFBSSxPQUFPLElBQUksQ0FBQyxFQUFFO0lBQ2pDLFlBQVksUUFBUSxDQUFDLENBQUMsQ0FBQztJQUN2QixRQUFRLENBQUMsTUFBTTtJQUNmLFlBQVksWUFBWSxDQUFDLENBQUMsQ0FBQztJQUMzQixRQUFROztJQUVSLElBQUk7SUFDSjs7O0lBR0EsU0FBUyxrQkFBa0IsQ0FBQyxDQUFDLEVBQUU7SUFDL0IsSUFBSSxDQUFDLENBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRTVCLElBQUksQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDO0lBQ2hCLElBQUksQ0FBQyxDQUFDLE1BQU0sR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7O0lBRS9CLElBQUksT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUU7SUFDN0IsUUFBUSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQztJQUMvQixRQUFRLENBQUMsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ25DLElBQUk7O0lBRUosSUFBSSxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRzs7SUFFbEIsSUFBSSxPQUFPLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRTtJQUM1QixRQUFRLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDNUIsUUFBUSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDckMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFO0lBQ2hELElBQUk7O0lBRUosSUFBSSxDQUFDLENBQUMsVUFBVSxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRTFDLElBQUksQ0FBQyxDQUFDLElBQUksR0FBRyxTQUFTLENBQUMsRUFBRTtJQUN6QixRQUFRLE1BQU0sQ0FBQyxDQUFDLElBQUk7SUFDcEIsUUFBUSxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsSUFBSTtJQUN0QyxRQUFRLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxVQUFVLENBQUM7SUFDdEMsUUFBUSxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNwRSxRQUFRLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLE9BQU8sSUFBSTs7SUFFM0MsUUFBUSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTTtJQUN4QixRQUFRLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMzQixRQUFRLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FB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QUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDOUMsSUFBSSxDQUFDO0lBQ0w7OztJQUdBLFNBQVMsWUFBWSxDQUFDLENBQUMsRUFBRTtJQUN6QixJQUFJLENBQUMsQ0FBQyxJQUFJLEdBQUcsV0FBVztJQUN4QixRQUFRLE1BQU0sSUFBSSxLQUFLLENBQUMsNEJBQTRCLENBQUM7SUFDckQsSUFBSSxDQUFDO0lBQ0w7O0lBRUEsU0FBUyxZQUFZLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTs7SUFFdEMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDakMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDakMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUM7O0lBRTNELElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ2pDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ2pDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDOztJQUUxRCxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNqQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNqQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQzs7SUFFeEQsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDakMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDakMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDeEQ7O0lBRUEsU0FBUyxXQUFXLENBQUMsRUFBRSxFQUFFO0lBQ3pCLElBQUksWUFBWSxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDaEMsSUFBSSxZQUFZLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUNoQyxJQUFJLFlBQVksQ0FBQyxFQUFFLEVB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QyxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDOztJQUVwRixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsQ0FBQzs7SUFFcEIsUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUNuRCxRQUFRLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUU7SUFDakMsUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUNuRCxRQUFRLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUU7SUFDakMsUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUNuRCxRQUFRLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUU7SUFDakMsUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUNuRCxJQUFJO0lBQ0o7O0lBRUEsSUFBSSxFQUFFLEdBQUcsRUFBRTs7SUFFWCxTQUFTQyxnQkFBYyxDQUFDLENBQUMsRUFBRTtJQUMzQixJQUFJLElBQUksS0FBSyxHQUFHLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQztJQUNqQztJ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QUMsQ0FBQyxDQUFDO0lBQ3hELElBQUk7O0lBRUosSUFBSSxNQUFNLEtBQUssR0FBRyxDQUFDLElBQUksQ0FBQztJQUN4QixJQUFJLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDdEQsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQzs7SUFFM0QsSUFBSSxNQUFNLEdBQUcsR0FBRyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUM7O0lBRTVCLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNoQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RFLFFBQVEsR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzVFLElBQUk7O0lBRUosSUFBSSxPQUFPLEdBQUc7SUFDZDs7SUFFQSxNQUFNLE9BQU8sQ0FBQztJQUNkLElBQUksV0FBVyxDQUFDLENBQUMsRUFBRTtJQUNuQixRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSTtJQUN0QixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUM1QixRQUFRLElBQUksQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUM3QixRQUFRLElBQUksQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUMxQixRQUFRLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQztJQUNsQixRQUFRLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRztJQUNyQyxRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUM1QixRQUFRLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRztJQUN0QyxRQUFRLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDMUMsUUFBUSxJQUFJLENBQUMsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLElBQUksQ0FBQyxHQUFHOztJQUVuRSxRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDMUQsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM3QixRQUFRLElBQUksQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzVCLFFBQVEsSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDeEQsUUFBUSxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQzs7SUFFbEMsUUFBUSxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxHQUFHO0lBQ3pDLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRztJQUMzQixRQUFRLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDckMsUUFBUSxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFO0lBQ3pDLFlBQVksSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHO0lBQzFDLFlBQVksQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDckMsUUFBUTs7O0lBR1IsUUFBUSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUM7SUFDbEIsUUFBUSxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNOztJQUU1QixRQUFRLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLEtBQUssSUFBSSxDQUFDLElBQUksRUFBRTtJQUNqRCxZQUFZLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQy9CLFlBQVksSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxHQUFHO0lBQ3ZDLFFBQVE7O0lBRVIsUUFBUSxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDOztJQUVsRCxRQUFRLFNBQVMsQ0FBQyxJQUFJLENBQUM7O0lBRXZCLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDOztJQUUzRCxRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDOUMsUUFBUSxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ2hELFFBQVEsSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDM0IsUUFBUSxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO0lBQzlCO0lBQ0EsUUFBUSxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUMxQyxRQUFRLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzlDLElBQUk7O0lBRUosSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNYLFFBQVEsSUFBSSxHQUFHO0lBQ2YsUUFBUSxJQUFJLENBQUMsQ0FBQyxFQUFFO0lBQ2hCLFlBQVksR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDM0IsUUFBUSxDQUFDLE1BQU0sSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFO0lBQzFCLFlBQVksR0FBRyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2hDLFFBQVE7SUFDUixRQUFRLElBQUksR0FBRyxHQUFHLENBQUMsRUFBRTtJQUNyQixZQUFZLElBQUksSUFB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QUksRUFBRSxDQUFDO0lBQzdDLFNBQVMsU0FBUyxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDckMsU0FBUyxFQUFFLEdBQUcsSUFBSTtJQUNsQjtJQUNBOztJQUVBLFNBQVNDLE1BQUksQ0FBQyxDQUFDLEVBQUU7SUFDakIsSUFBSTtJQUNKLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxVQUFVLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLFVBQVUsR0FBRyxFQUFFLElBQUksQ0FBQztJQUM3RCxTQUFTLENBQUMsQ0FBQyxHQUFHLFVBQVUsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksVUFBVSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDN0QsU0FBUyxDQUFDLENBQUMsR0FBRyxVQUFVLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLFVBQVUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzdELFNBQVMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxVQUFVLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM3RCxTQUFTLENBQUMsQ0FBQyxHQUFHLFVBQVUsTUFBTSxDQUFDO0lBQy9CO0lBQ0E7O0lBRUEsU0FBUyxlQUFlLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRTtJQUN0QyxJQUFJLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSztJQUNyQyxJQUFJLE1BQU0sSUFBSSxHQUFHQSxNQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksRUFBRTtJQUN4QixRQUFRLE1BQU0sSUFBSSxLQUFLLENBQUMsNEJBQTRCLENBQUM7SUFDckQsSUFBSTtJQUNKLElBQUksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNoQyxRQUFRLE1BQU0sQ0FBQyxHQUFHLFVBQVUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3JDLFFBQVEsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFO0lBQ25CLFlBQVksTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsS0FBSyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxLQUFLLENBQUM7SUFDOUQsWUFBWSxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEtBQUssRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQztJQUN2RSxZQUFZLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUM7SUFDcEMsUUFBUTtJQUNSLElBQUk7SUFDSjs7SUFFQSxTQUFTLFlBQVksQ0FBQyxHQUFHLEVBQUUsRUFBRSxFQUFFO0lBQy9CLElBQUksTUFBTSxJQUFJLEdBQUcsSUFBSSxVQUFVLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUM7O0lBRWhELElBQUksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDekMsUUFBUSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ2hDLElBQUk7O0lBRUosSUFBSSxPQUFPLElBQUk7SUFDZjs7SUFFQSxTQUFTLFlBQVksQ0FBQyxJQUFJLEVBQUUsRUFBRSxFQUFFO0lBQ2hDLElBQUksTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsR0FBRyxFQUFFO0lBQ2xDLElBQUksTUFBTSxHQUFHLEdBQUcsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQzVCLElBQUksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMs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LENBQUMsRUFBRTtJQUN0QixRQUFRLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3JDLFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDckMsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQztJQUN2RixRQUFRLE9BQU8sSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ2xELElBQUk7O0lBRUosSUFBSSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDMUIsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNyQyxRQUFRLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3JDLFFBQVEsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQ3JGLElBQUk7O0lBRUosSUFBSSxHQUFHLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRTtJQUNuQixRQUFRLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3JDLFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsT0FBTyxD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Q0FBQyxDQUFDLEdBQUcsQ0FBQztJQUN4QixRQUFRLElBQUksQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM3QixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMvQixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQzs7SUFFL0IsUUFBUSxJQUFJLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDcEMsUUFBUSxJQUFJLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDcEMsUUFBUSxJQUFJLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDcEMsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDN0QsUUFBUSxJQUFJLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ2xELFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQzVELFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQzs7SUFFakQsUUFBUSxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUN4QyxRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUM7O0lBRS9DLElBQUk7O0lBRUosSUFBSSxHQUFHLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDdEIsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNyQyxRQUFRLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3JDLFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDdkYsUUFBUSxPQUFPLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUNsRCxJQUFJOztJQUVKLElBQUksT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQzFCLFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDckMsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNyQyxRQUFRLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQztJQUNyRixJQUFJOztJQUVKLElB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QUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xFLFFBQVEsSUFBSSxDQUFDO0lBQ2IsUUFBUSxJQUFJLENBQUMsQ0FBQyxVQUFVLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFO0lBQ3pDLFlBQVksQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xFLFFBQVEsQ0FBQyxNQUFNO0lBQ2YsWUFBWSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7SUFDM0MsUUFBUTtJQUNSLFFBQVEsT0FBTyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3hCLElBQUk7O0lBRUosSUFBSSxVQUFVLENBQUMsQ0FBQyxFQUFFO0lBQ2xCLFFBQVEsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFFBQVEsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFFBQVEsSUFBSSxDQUFDO0lBQ2IsUUFBUSxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFO0lBQ3pCLFlBQVksQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2QyxRQUFRLENBQUMsTUFBTTtJQUNmLFlBQVksQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRztJQUMxQixRQUFRO0lBQ1IsUUFBUSxJQUFJLElBQUksQ0FBQyxDQUFD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QyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksVUFBVSxDQUFDO0lBQzlELFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksVUFBVSxDQUFDO0lBQzlELFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksVUFBVSxDQUFDO0lBQzlELFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksVUFBVSxDQUFDO0lBQzlELFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ2xDLFFBQVEsT0FBTyxDQUFDLEtBQUssQ0FBQztJQUN0QixJQUFJOztJQUVKO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQSxJQUFJLFNBQVMsY0FBYyxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFO0lBQzNDLFFBQVEsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLFVBQVUsR0FBRyxHQUFHO0lBQ3JDLFFBQVEsTUFBTSxLQUFLLEdBQUcsRUFBRSxHQUFHLElBQUk7SUFDL0IsUUFBUSxJQUFJLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxVQUFVLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFO0lBQzlELFlBQVksTUFBTSxLQUFLLEdBQUcsR0FBRyxLQUFLLENBQUM7SUFDbkMsWUFBWSxNQUFNLEdBQUcsR0FBRyxJQUFJLFdBQVcsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLFVBQVUsS0FBSyxD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RUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ3ZGLFlBQVksTUFBTSxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxFQUFFLFNBQVMsQ0FBQzs7SUFFckQsWUFBWSxNQUFNLFVBQVUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUM3RCxZQUFZLE1BQU0sSUFBSSxHQUFHLEVBQUU7O0lBRTNCLFlBQVksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7SUFDcEQsWUFBWSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQzs7SUFFcEQsWUFBWSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUQsWUFBWSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNyRCxZQUFZLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRCxZQUFZLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3JELFlBQVksSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdB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QUFDO0lBQ3pDLElBQUksS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDekMsSUFBSSxLQUFLLENBQUMsSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJO0lBQzVCLElBQUksS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBQ2pCLElBQUksS0FBSyxDQUFDLFFBQVEsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVE7SUFDekMsSUFBSSxLQUFLLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUTtJQUN6QyxJQUFJLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxVQUFVLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDOUQsSUFBSSxLQUFLLENBQUMsRUFBRSxHQUFHLElBQUksVUFBVSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQzlELElBQUksS0FBSyxDQUFDLEVBQUUsR0FBRyxJQUFJLFVBQVUsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUM7SUFDbEQsSUFBSSxLQUFLLENBQUMsRUFBRSxHQUFHLElBQUksU0FBUyxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsVUFBVSxDQUFDO0lBQzFHLElBQUksS0FBSyxDQUFDLEVBQUUsR0FBRyxJQUFJLFNBQVMsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxD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QVUsR0FBRyxJQUFJLFFBQVEsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDOztJQUV6RCxRQUFRLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUM7O0lBRXhDLFFBQVEsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUM7SUFDeEMsSUFBSTs7SUFFSixJQUFJLE1BQU0sVUFBVSxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDN0IsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJOztJQUV6QixRQUFRLE1BQU0sU0FBUyxHQUFHLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQztJQUMzQyxRQUFRLE1BQU0sVUFBVSxHQUFHLElBQUksUUFBUSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7O0lBRXpELFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQzs7SUFFekMsUUFBUSxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQztJQUN4QyxJQUFJOzs7SUFHSixJQUFJLE1BQU0sVUFBVSxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDN0IsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJOztJQUV6QixRQUFRLE1BQU0sU0FBUyxHQUFHLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQztJQUMzQyxRQUFRLE1BQU0sVUFBVSxHQUFHLElBQUksUUFBUSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7O0lBRXpELFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFVBQVUsRUFBRSxJQUFJLENBQUM7SUFDckQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxXQUFXLENBQUMsR0FBRyxJQUFJLENBQUM7O0lBRW5FLFFBQVEsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxH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eEQsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ3hELElBQUksRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN4RCxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDeEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3hELElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN4RCxJQUFJLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDeEQsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3hELElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUN4RCxJQUFJLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDeEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFO0lBQ3hELElBQUksRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN4RDtJQUNBLElBQUksRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN4RCxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDeEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3hELElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN4RCxDQUFDLENBQUM7O0lDOUJGLE1BQU0sVUFBVSxtQkFBbUIsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ3RELE1BQU0sSUFBSSxtQkFBbUIsTUFBTSxDQUFDLEVBQUUsQ0FBQztJQUN2QztJQUNBO0lBQ0EsU0FBUyxPQUFPLENBQUMsQ0FBQyxFQUFFLEVBQUUsR0FBRyxLQUFLLEVBQUU7SUFDaEMsSUFBSSxJQUFJLEVBQUU7SUFDVixRQUFRLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsR0FBRyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksSUFBSSxVQUFVLENBQUMsRUFBRTtJQUNqRixJQUFJLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLEdBQUcsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFO0lBQ3JGO0lBQ0E7SUFDQTtJQUNBLFNBQVMsS0FBSyxDQUFDLEdBQUcsRUFBRSxFQUFFLEdBQUcsS0FBSyxFQUFFO0lBQ2hDLElBQUksTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLE1BQU07SUFDMUIsSUFBSSxJQUFJLEVBQUUsR0FBRyxJQUFJLFdBQVcsQ0FBQyxHQUFHLENBQUM7SUFDakMsSUFBSSxJQUFJLEVBQUUsR0FBRyxJQUFJLFdBQVcsQ0FBQyxHQUFHLENBQUM7SUFDakMsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2xDLFFBQVEsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUM1QyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMvQixJQUFJO0lBQ0osSUFBSSxPQUFPLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUNuQjtJQVFBO0lBQ0EsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN2RDtJQUNBLE1BQU0sTUFBTSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdkQ7SUFDQSxNQUFNLE1BQU0sR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQzlEO0lBQ0EsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUM5RDtJQUNBLE1BQU0sT0FBTyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDO0lBQzVCO0lBQ0EsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUM7SUFDNUI7SUFDQSxNQUFNLE1BQU0sR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3ZEO0lBQ0EsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN2RDtJQUNBLE1BQU0sTUFBTSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDOUQ7SUFDQSxNQUFNLE1BQU0sR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzlEO0lBQ0E7SUFDQTtJQUNBLFNBQVMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRTtJQUM3QixJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ3JDLElBQUksT0FBTyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUU7SUFDL0Q7SUFDQTtJQUNBO0lBQ0EsTUFBTSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsS0FBSyxDQUFDLEVBQUUsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDbEU7SUFDQSxNQUFNLEtBQUssR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQzs7SUMzRDdFO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFNQTtJQUNBO0lBQ0EsTUFBTSxNQUFNLG1CQUFtQixXQUFXLENBQUMsSUFBSSxDQUFDO0lBQ2hELElBQUksVUFBVSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLFVBQVU7SUFDbEcsSUFBSSxVQUFVLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsVUFBVTtJQUNsRyxDQUFDLENBQUM7SUFDRjtJQUNBLE1BQU0sSUFBSSxtQkFBbUIsSUFBSSxXQUFXLENBQUMsRUFBRSxDQUFDO0lBQ2hEO0lBQ0EsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUU7SUFDakM7SUFDQSxJQUFJLE1BQU0sRUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN2QyxJQUFJLElBQUksRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQy9DLElBQUksSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDL0MsSUFBSSxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUMvQyxJQUFJLElBQUksRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQy9DO0lBQ0EsSUFBSSxJQUFJLEVBQUUsR0FBRzJCLEtBQVMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUNsQyxJQUFJLEVBQUUsR0FBR0MsS0FBUyxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUNsQyxJQUFJLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQztJQUNmO0lBQ0EsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUU7SUFDOUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFQyxPQUFXLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRUMsT0FBVyxDQUFDLEVBQU0sQ0FBQyxFQUFFO0lBQ3RFO0lBQ0EsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUdDLEdBQU8sQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDL0M7SUFDQSxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRTtJQUM5QyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUVDLE1BQVUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRUMsTUFBVSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUU7SUFDNUUsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQy9DLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUMvQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDL0MsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQy9DO0lBQ0E7SUFDQSxTQUFTLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRTtJQUNqQztJQUNBLElBQUksTUFBTSxFQUFFLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3ZDLElBQUksSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDL0MsSUFBSSxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUMvQyxJQUFJLElBQUksRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQy9DLElBQUksSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDL0M7SUFDQSxJQUFJLElBQUksRUFBRSxHQUFHTixLQUFTLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDbEMsSUFBSSxFQUFFLEdBQUdDLEtBQVMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDbEMsSUFBSSxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUM7SUFDZjtJQUNBLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFO0lBQzlDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRUksTUFBVSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFQyxNQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRTtJQUM1RTtJQUNBLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxHQUFHRixHQUFPLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBQy9DO0lBQ0EsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUU7SUFDOUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFRyxNQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUVDLE1BQVUsQ0FBQyxFQUFF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QU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3ZCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3ZCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3ZCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3ZCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3ZCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3ZCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO0lBQ3hCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO0lBQ3hCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO0lBQ3hCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO0lBQ3hCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO0lBQ3hCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO0lBQ3hCLElBQUksV0FBVyxDQUFDLElBQUksR0FBRyxFQUFFLEVBQUU7SUFDM0IsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxLQUFLLFNBQVMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUs7SUFDL0QsUUFBUSxLQUFLLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQztJQUN4QixRQUFRLGVBQWUsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBQy9DLFFBQVEsSUFBSSxFQUFFLEdBQUcsRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLEdBQUcsSUFBSTtJQUNqRCxRQUFRLElBQUksU0FBUyxHQUFHLENBQUM7SUFDekIsUUFBUSxJQUFJLEdBQUcsS0FBSyxTQUFTLEVBQUU7SUFDL0IsWUFBWSxNQUFNLENBQUMsR0FBRyxFQUFFLFNBQVMsRUFBRSxLQUFLLENBQUM7SUFDekMsWUFBWSxTQUFTLEdBQUcsR0FBRyxDQUFDLE1BQU07SUFDbEMsUUFBUTtJQUNSO0lBQ0E7SUFDQSxRQUFRLElBQUksQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLFNBQVMsSUFBSSxTQUFTLElBQUksQ0FBQyxDQUFDLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQyxJQUFJLElBQUksSUFBSSxFQUFFLENBQUM7SUFDbkYsUUFBUSxJQUFJLElBQUksS0FBSyxTQUFTLEVBQUU7SUFDaEMsWUFBWSxNQUFNLENBQUMsSUFBSSxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDM0MsWUFBWSxNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDO0lBQ2pDLFlBQVksSUFBSSxDQUFDLEdBQUcsSUFBSSxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFlBQVksSUFBSSxDQUFDLEdBQUcsSUFBSSxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFlBQVksSUFBSSxDQUFDLEdBQUcsSUFBSSxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFlBQVksSUFBSSxDQUFDLEdBQUcsSUFBSSxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFFBQVE7SUFDUixRQUFRLElBQUksZUFBZSxLQUFLLFNBQVMsRUFBRTtJQUMzQyxZQUFZLE1BQU0sQ0FBQyxlQUFlLEVBQUUsU0FBUyxFQUFFLGlCQUFpQixDQUFDO0lBQ2pFLFlBQVksTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLGVBQWUsQ0FBQztJQUM3QyxZQUFZLElBQUksQ0FBQyxHQUFHLElBQUksU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQyxZQUFZLElBQUksQ0FBQyxHQUFHLElBQUksU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQyxZQUFZLElBQUksQ0FBQyxHQUFHLElBQUksU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQyxZQUFZLElBQUksQ0FBQyxHQUFHLElBQUksU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQyxRQUFRO0lBQ1IsUUFBUSxJQUFJLEdBQUcsS0FBSyxTQUFTLEVBQUU7SUFDL0I7SUFDQSxZQUFZLE1BQU0sR0FBRyxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUM7SUFDckQsWUFBWSxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztJQUN4QixZQUFZLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDO0lBQzVCLFFBQVE7SUFDUixJQUFJO0lBQ0o7SUFDQSxJQUFJLEdBQUcsR0FBRztJQUNWLFFBQVEsSUFBSSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUk7SUFDckcsUUFBUSxPQUFPLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDO0lBQy9GLElBQUk7SUFDSjtJQUNBLElBQUksR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRTtJQUN4RixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDMUIsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQzFCLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUMxQixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDMUIsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQzFCLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUMxQixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDMUIsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQzFCLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUMxQixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDMUIsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQzFCLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUMxQixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDMUIsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQzFCLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUMxQixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDMUIsSUFBSTtJQUNKLElBQUksUUFBUSxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFO0lBQ2xDLFFBQVEsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEQsUUFBUSxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM3QixRQUFRLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEdBQUdDLE9BQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZELFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDakMsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNqQztJQUNBLFFBQVEsSUFBSSxNQUFNLEVBQUU7SUFDcEIsWUFBWSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ2hDLFlBQVksSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUNoQyxRQUFRO0lBQ1IsUUFBUSxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ2pCLFFBQVEsTUFBTSxDQUFDLEdBQUcsTUFBTTtJQUN4QjtJQUNBO0lBQ0EsUUFBUSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3JDLFlBQVksR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN0RCxZQUFZLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdEQsWUFBWSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3RELFlBQVksR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN0RCxZQUFZLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdkQsWUFBWSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZELFlBQVksR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN2RCxZQUFZLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdkQsWUFBWSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZELFlBQVksR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN2RCxZQUFZLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdkQsWUFBWSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZELFlBQVksR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN0RCxZQUFZLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdEQsWUFBWSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3RELFlBQVksR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN0RCxRQUFRO0lBQ1IsUUFBUSxJQUFJLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3RDLFFBQVEsSUFBSSxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN0QyxRQUFRLElBQUksQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDdEMsUUFBUSxJQUFJLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3RDLFFBQVEsSUFBSSxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN0QyxRQUFRLElBQUksQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDdEMsUUFBUSxJQUFJLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3RDLFFBQVEsSUFBSSxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN0QyxRQUFRLElBQUksQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDdEMsUUFBUSxJQUFJLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3RDLFFBQVEsSUFBSSxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN2QyxRQUFRLElBQUksQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDdkMsUUFBUSxJQUFJLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3ZDLFFBQVEsSUFBSSxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN2QyxRQUFRLElBQUksQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDdkMsUUFBUSxJQUFJLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3ZDLFFBQVEsS0FBSyxDQUFDLElBQUksQ0FBQztJQUNuQixJQUFJO0lBQ0osSUFBSSxPQUFPLEdBQUc7SUFDZCxRQUFRLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSTtJQUM3QixRQUFRLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQzVCLFFBQVEsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDaEUsSUFBSTtJQUNKO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDTyxNQUFNLE9BQU8sbUJBQW1CLFlBQVksQ0FBQyxDQUFDLElBQUksS0FBSyxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQzs7Ozs7O0lDclZqRjtJQUNBOztJQUVBOztJQUVBO0lBQ0E7SUFDQTtJQUNBOztJQUVBO0lBQ0E7SUFDQTtJQUNBOztJQUVBO0lBQ0E7SUFDQTs7OztJQW1DTyxTQUFTLElBQUksRUFBRSxDQUFDO0lBQ3ZCO0lBQ0EsSUFBSSxRQUFRLEVBQUUsRUFBRSxDQUFDLEdBQUcsVUFBVSxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksVUFBVSxFQUFFLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsVUFBVSxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksVUFBVSxFQUFFLENBQUMsS0FBSyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsR0FBRyxVQUFVLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxVQUFVLEVBQUUsQ0FBQyxLQUFLLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxHQUFHLFVBQVUsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLFVBQVUsRUFBRSxDQUFDLEtBQUssQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLEdBQUcsVUFBVSxPQUFPLENBQUMsRUFBRTtJQUN6Ujs7O0lBR08sU0FBUyxVQUFVLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRTtJQUNyQyxJQUFJLE1BQU0sQ0FBQyxHQUFHLElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDO0lBQ2hFLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRTtJQUNkLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUM1QixRQUFRLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSTtJQUMxQixRQUFRLENBQUMsSUFBSSxNQUFNO0lBQ25CLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNoQyxZQUFZLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksR0FBRztJQUM3QixZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQztJQUNwRSxRQUFRO0lBQ1IsSUFBSTtJQUNKLElBQUksSUFBSSxLQUFLLEVBQUUsQ0FBQyxHQUFHLEtBQUssR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUNuQyxJQUFJLE9BQU8sQ0FBQztJQUNaOztJQUVPLFNBQVMsV0FBVyxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUU7SUFDcEMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxVQUFVLElBQUksRUFBRSxDQUFDLFVBQVUsRUFBRSxPQUFPLEtBQUs7SUFDcEQsSUFBSSxJQUFJLEdBQUcsR0FBRyxJQUFJLFNBQVMsQ0FBQyxFQUFFLENBQUM7SUFDL0IsSUFBSSxJQUFJLEdBQUcsR0FBRyxJQUFJLFNBQVMsQ0FBQyxFQUFFLENBQUM7SUFDL0IsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLFVBQVUsR0FBRyxDQUFDLEVBQUU7SUFDN0MsSUFBSTtJQUNKLFFBQVEsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sS0FBSztJQUMxQyxJQUFJO0lBQ0osSUFBSSxPQUFPLElBQUk7SUFDZjs7SUFFTyxTQUFTLFdBQVcsQ0FBQyxDQUFDLEVBQUU7SUFDL0IsSUFBSSxPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUU7SUFDcEI7O0lBRU8sU0FBUyxlQUFlLENBQUMsT0FBTyxFQUFFO0lBQ3pDO0lBQ0EsSUFBSSxNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7SUFDeEMsSUFBSSxNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMzQyxJQUFJLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDN0MsSUFBSSxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7SUFDdkIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEQsSUFBSSxNQUFNLEtBQUssR0FBRyxDQUFDLElBQUksRUFBRTtJQUN6QixJQUFJLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSztJQUMzQyxJQUFJLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSztJQUMzQyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsR0FBRyxHQUFHLEdBQUc7SUFDMUIsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUc7SUFDakIsSUFBSSxPQUFPLEdBQUc7SUFDZDs7SUFFTyxTQUFTLGFBQWEsQ0FBQyxJQUFJLENBQUM7SUFDbkM7SUFDQSxJQUFJLE1BQU0sR0FBRyxHQUFHLElBQUksVUFBVSxDQUFDLEdBQUcsQ0FBQztJQUNuQyxJQUFJLE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3hDLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3hCLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUNoRCxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDaEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ2hELElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUNoRCxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDaEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ2xELElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUNsRCxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDbEQsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUc7SUFDeEIsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRztJQUNwQyxJQUFJLE9BQU8sR0FBRztJQUNkOztJQUVPLGVBQWVDLFdBQVMsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFO0lBQzdELElBQUksSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxPQUFPLEtBQUs7SUFDMUMsSUFBSSxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sS0FBSztJQUMzQyxJQUFJLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsT0FBTyxLQUFLO0lBQzFDLElBQUksSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEtBQUs7SUFDM0M7SUFDQSxJQUFJLE1BQU0sR0FBRyxHQUFHLE1BQU0sS0FBSyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQztJQUN6RSxJQUFJLE9BQU8sR0FBRztJQUNkOzs7SUFHTyxTQUFTLFVBQVUsR0FBRztJQUM3QjtJQUNBO0lBQ0E7SUFDQSxJQUFJLElBQUksT0FBTyxNQUFNLEtBQUssV0FBVyxJQUFJLE9BQU8sTUFBTSxDQUFDLE1BQU0sS0FBSyxVQUFVLEVBQUU7SUFDOUUsUUFBUSxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsa0NBQWtDLEVBQUUsRUFBRSxDQUFDO0lBQ3BFLElBQUksQ0FBQyxNQUFNO0lBQ1gsUUFBUSxNQUFNLEVBQUUsR0FBRyxRQUFRLENBQUMsZUFBZSxDQUFDO0lBQzVDLFlBQVksS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO0lBQ2hDLFlBQVksTUFBTSxFQUFFLE9BQU8sQ0FBQztJQUM1QixTQUFTLENBQUM7O0lBRVYsUUFBUSxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxLQUFLO0lBQ3hDLFlBQVksRUFBRSxDQUFDLFFBQVEsQ0FBQyxrQ0FBa0MsRUFBRSxDQUFDLEtBQUssS0FBSyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUU7SUFDdkYsUUFBUSxDQUFDLENBQUM7SUFDVixJQUFJO0lBQ0o7O0lBRU8sU0FBUyxjQUFjLENBQUMsQ0FBQyxFQUFFO0lBQ2xDLElBQUksSUFBSSxLQUFLLEdBQUcsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ2pDLElBQUksSUFBSSxNQUFNLElBQUksTUFBTSxDQUFDLGNBQWMsRUFBRTtJQUN6QyxRQUFRLE1BQU0sQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDO0lBQ3BDLElBQUksQ0FBQyxNQUFNLElBQUksT0FBTyxVQUFVLENBQUMsTUFBTSxLQUFLLFdBQVcsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLGVBQWUsRUFBRTtJQUM5RjtJQUNBLFFBQVEsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksS0FBSyxFQUFFO0lBQzNDLFlBQVksVUFBVSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEYsUUFBUTtJQUNSLElBQUksQ0FBQyxNQUFNO0lBQ1gsUUFBUSxNQUFNLElBQUksS0FBSyxDQUFDLG1DQUFtQyxDQUFDO0lBQzVELElBQUk7SUFDSixJQUFJLE9BQU8sS0FBSztJQUNoQjs7SUFFTyxlQUFlLFlBQVksQ0FBQyxJQUFJLEVBQUU7SUFDekMsSUFBSSxJQUFJLE1BQU0sSUFBSSxNQUFNLENBQUMsVUFBVSxFQUFFO0lBQ3JDLFFBQVEsT0FBTyxNQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDaEUsSUFBSSxDQUFDLE1BQU07SUFDWDtJQUNBO0lBQ0EsUUFBUSxNQUFNLE1BQU0sR0FBRyxNQUFNLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDO0lBQzdFLFFBQVEsT0FBTyxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUM7SUFDckMsSUFBSTtJQUNKOztJQUVBO0lBQ0E7SUFDQTtJQUNBO0lBQ08sU0FBUyxZQUFZLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRTtJQUMzQyxJQUFJLE9BQU8sSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDO0lBQzdEOztJQUVPLGVBQWUsWUFBWSxDQUFDLE9BQU8sRUFBRTtJQUM1QztJQUNBLElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRTtJQUNyQixRQUFRLE9BQU8sR0FBRyxNQUFNLFVBQVUsRUFBRTtJQUNwQyxJQUFJO0lBQ0osSUFBSSxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztJQUNyQyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3JDLElBQUksTUFBTSxHQUFHLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztJQUNsQyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0QyxJQUFJLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUU7O0lBRWhDLElBQUksTUFBTSxJQUFJLEdBQUcsRUFBRTtJQUNuQixJQUFJLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7SUFDMUIsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLElBQUk7SUFDSixJQUFJLE1BQU0sR0FBRyxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQztJQUNoQyxJQUFJLE9BQU8sR0FBRztJQUNkOztJQUVPLGVBQWUsbUJBQW1CLENBQUMsVUFBVSxFQUFFLGdCQUFnQixFQUFFO0lBQ3hFLElBQUksSUFBSSxnQkFBZ0I7SUFDeEIsSUFBSSxJQUFJLGdCQUFnQjtJQUN4QixJQUFJLElBQUksZ0JBQWdCLENBQUMsRUFBRSxFQUFFO0lBQzdCLFFBQVEsZ0JBQWdCLEdBQUcsQ0FBQyxDQUFDLElBQUksZ0JBQWdCLE1BQU0sQ0FBQztJQUN4RCxRQUFRLGdCQUFnQixHQUFHLENBQUM7SUFDNUIsSUFBSSxDQUFDLE1BQU07SUFDWCxRQUFRLGdCQUFnQixHQUFHLFdBQVc7SUFDdEMsUUFBUSxnQkFBZ0IsR0FBRyxDQUFDLENBQUMsS0FBSyxnQkFBZ0IsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDO0lBQzdELElBQUk7O0lBRUosSUFBSSxJQUFJLE9BQU8sR0FBRyxVQUFVO0lBQzVCLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLGdCQUFnQixFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzNDLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLGdCQUFnQixFQUFFLENBQUMsRUFBRSxFQUFFO0lBQy9DLFlBQVksT0FBTyxHQUFHLE1BQU0sWUFBWSxDQUFDLE9BQU8sQ0FBQztJQUNqRCxRQUFRO0lBQ1IsSUFBSTs7SUFFSixJQUFJLE1BQU0sUUFBUSxHQUFHLElBQUksUUFBUSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDO0lBQ3pGLElBQUksTUFBTSxJQUFJLEdBQUcsRUFBRTtJQUNuQixJQUFJLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDNUIsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQztJQUNoRCxJQUFJOztJQUVKLElBQUksTUFBTSxHQUFHLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDOztJQUVoQyxJQUFJLE9BQU8sR0FBRztJQUNkOztJQUVPLFNBQVMsYUFBYSxDQUFDLENBQUMsRUFBRTtJQUNqQyxJQUFJLElBQUksQ0FBQyxZQUFZLFVBQVUsRUFBRSxPQUFPLENBQUM7SUFDekMsSUFBSSxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDM0MsSUFBSSxPQUFPLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFO0lBQ25FLFFBQVEsT0FBTyxRQUFRLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUM5QixJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ1A7O0lBRU8sU0FBUyxhQUFhLENBQUMsU0FBUyxFQUFFO0lBQ3pDLElBQUksT0FBTyxLQUFLLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFNBQVMsSUFBSSxFQUFFO0lBQzlELFFBQVEsT0FBTyxDQUFDLEdBQUcsR0FBRyxDQUFDLElBQUksR0FBRyxJQUFJLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUM7SUFDM0QsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ2Y7O0lBRU8sU0FBUyx5QkFBeUIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFO0lBQ2pELElBQUksSUFBSSxDQUFDLFlBQVksVUFBVSxHQUFHO0lBQ2xDLFFBQVEsT0FBTyxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUM3QixJQUFJLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUU7SUFDakMsUUFBUSxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM5RCxJQUFJLENBQUMsTUFBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLFFBQVEsRUFBRTtJQUNyQyxRQUFRLE1BQU0sR0FBRyxHQUFHLEVBQUU7SUFDdEIsUUFBUSxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNuQyxRQUFRLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEtBQUs7SUFDN0IsWUFBWSxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcseUJBQXlCLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4RCxRQUFRLENBQUMsQ0FBQztJQUNWLFFBQVEsT0FBTyxHQUFHO0lBQ2xCLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLFFBQVEsS0FBSyxDQUFDLENBQUMsRUFBRSxLQUFLLFNBQVMsR0FBRztJQUMvRCxRQUFRLE9BQU8sQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7SUFDN0IsSUFBSSxDQUFDLE1BQU07SUFDWCxRQUFRLE9BQU8sQ0FBQztJQUNoQixJQUFJO0lBQ0o7O0lDOVFPLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQzs7SUFFN0IsTUFBTSxtQkFBbUIsR0FBRyxDQUFDO0lBQzdCLE1BQU0saUJBQWlCLEdBQUcsQ0FBQztJQUMzQixNQUFNLGtCQUFrQixHQUFHLEVBQUU7O0lDSnBDO0lBQ0E7O0lBRUE7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBOztJQUVBO0lBQ08sTUFBTSxnQkFBZ0IsR0FBRyxDQUFDOztJQUtqQztJQUNPLE1BQU0saUJBQWlCLEdBQUcsRUFBRTs7SUFFNUIsTUFBTSxzQkFBc0IsR0FBRyxDQUFDO0lBQ2hDLE1BQU0seUJBQXlCLEdBQUcsQ0FBQztJQUNuQyxNQUFNLHFCQUFxQixHQUFHLENBQUM7SUFDL0IsTUFBTSxxQkFBcUIsR0FBRyxDQUFDO0lBQy9CLE1BQU0scUJBQXFCLEdBQUcsQ0FBQztJQUMvQixNQUFNLGtCQUFrQixHQUFHLENBQUM7SUFDNUIsTUFBTSxrQkFBa0IsR0FBRyxDQUFDO0lBQzVCLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQztJQUM1QixNQUFNLGtCQUFrQixHQUFHLEVBQUU7SUFDN0IsTUFBTSxrQkFBa0IsR0FBRyxFQUFFO0lBQzdCLE1BQU0sc0JBQXNCLEdBQUcsRUFBRTtJQUNqQyxNQUFNLHNCQUFzQixHQUFHLEVBQUU7SUFDakMsTUFBTSxzQkFBc0IsR0FBRyxFQUFFO0lBQ2pDLE1BQU0sd0JBQXdCLEdBQUcsRUFBRTtJQUNuQyxNQUFNLG9CQUFvQixHQUFHLEVBQUU7SUFDL0IsTUFBTSxrQkFBa0IsR0FBRyxFQUFFOztJQzNDcEM7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7OztJQXFDTyxlQUFlLFdBQVcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFOztJQUU1QztJQUNBO0lBQ0EsSUFBSSxNQUFNQyxpQkFBOEIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLElBQUksTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNCLElBQUksTUFBTUMsZUFBNEIsQ0FBQyxFQUFFLENBQUM7O0lBRTFDO0lBQ0E7O0lBRUEsSUFBSSxNQUFNLEtBQUssR0FBRyxNQUFNQyxhQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQzs7SUFFeEMsSUFBSSxNQUFNRixpQkFBOEIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLElBQUksTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDMUIsSUFBSSxNQUFNLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQzs7SUFFdkUsSUFBSSxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQztJQUMxQixJQUFJLE1BQU0sR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDOztJQUV2RSxJQUFJLE1BQU0sRUFBRSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7SUFDNUIsSUFBSSxNQUFNRyxXQUF3QixDQUFDLEVBQUUsRUFBRSxNQUFNLEVBQUUsR0FBRyxDQUFDO0lBQ25ELElBQUksTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztJQUM1QixJQUFJLE1BQU1BLFdBQXdCLENBQUMsRUFBRSxFQUFFLE1BQU0sRUFBRSxHQUFHLENBQUM7SUFDbkQsSUFBSSxNQUFNLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3BDLElBQUksTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0QyxJQUFJLE1BQU0sRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDekMsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDN0MsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDNUMsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDNUMsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDN0MsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDN0MsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUM7O0lBRTdDLElBQUksTUFBTUYsZUFBNEIsQ0FBQyxFQUFFLENBQUM7OztJQUcxQzs7SUEyRkEsZUFBZSxPQUFPLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUU7SUFDckMsSUFBSSxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2hELElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDakMsSUFBSSxNQUFNLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ3hCOztJQUVBLGVBQWUsT0FBTyxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFO0lBQ3JDLElBQUksTUFBTSxJQUFJLEdBQUcsSUFBSSxVQUFVLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNoRCxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2pDLElBQUksTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztJQUN4Qjs7SUFFQSxlQUFlLE1BQU0sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRTtJQUMzQyxJQUFJLE1BQU0sSUFBSSxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQy9DLElBQUksTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUM1QyxJQUFJLE9BQU8sUUFBUSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUc7SUFDbEQ7O0lBRUEsZUFBZSxNQUFNLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7SUFDM0MsSUFBSSxNQUFNLElBQUksR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUMvQyxJQUFJLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDNUMsSUFBSSxPQUFPLFFBQVEsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsR0FBRyxHQUFHO0lBQ2xEOzs7SUFHTyxlQUFlRyxZQUFVLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFO0lBQ2xFO0lBQ0E7SUFDQSxJQUFJLE1BQU1DLHdCQUFtQyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQzlELElBQUksTUFBTSxVQUFVLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFO0lBQzNDLElBQUksTUFBTUMsZ0JBQTJCLENBQUMsRUFBRSxDQUFDOztJQUV6QyxJQUFJLElBQUksVUFBVSxLQUFLLG1CQUFtQixFQUFFO0lBQzVDLFFBQVEsT0FBTyxNQUFNLGlCQUFpQixDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQztJQUN2RSxJQUFJLENBQUMsTUFBTSxJQUFJLFVBQVUsS0FBSyxpQkFBaUIsRUFBRTtJQUNqRCxRQUFRLE9BQU8sTUFBTSxlQUFlLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsT0FBTyxDQUFDO0lBQ3JFLElBQUksQ0FBQyxNQUFNLElBQUksVUFBVSxLQUFLLGtCQUFrQixFQUFFO0lBQ2xELFFBQVEsT0FBTyxNQUFNLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQztJQUN0RSxJQUFJLENBQUMsTUFBTTtJQUNYLFFBQVEsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQztJQUNuRCxJQUFJO0lBQ0o7Ozs7O0lBS0EsZUFBZSxpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUU7SUFDbEUsSUFBSSxNQUFNLElBQUksR0FBRyxFQUFFOztJQUVuQixJQUFJLElBQUksQ0FBQyxRQUFRLEdBQUcsU0FBUzs7SUFFN0I7SUFDQTtJQUNBLElBQUksTUFBTUQsd0JBQW1DLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDOUQsSUFBSSxNQUFNLEdBQUcsR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7SUFDcEMsSUFBSSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUc7SUFDbEIsSUFBSSxJQUFJLENBQUMsQ0FBQyxHQUFHLE1BQU1FLFlBQXVCLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQzs7SUFFbkQsSUFBSSxNQUFNLEdBQUcsR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7SUFDcEMsSUFBSSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUc7SUFDbEIsSUFBSSxJQUFJLENBQUMsQ0FBQyxHQUFHLE1BQU1BLFlBQXVCLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQztJQUNuRCxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBTUwsYUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDO0lBQ2hELElBQUksSUFBSSxDQUFDLEtBQUssR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7SUFDckMsSUFBSSxJQUFJLENBQUMsT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLFNBQVMsRUFBRTtJQUN2QyxJQUFJLElBQUksQ0FBQyxVQUFVLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFO0lBQzFDLElBQUksSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUN0QyxJQUFJLElBQUksQ0FBQyxVQUFVLEdBQUcsTUFBTSxNQUFNLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQzVELElBQUksSUFBSSxDQUFDLFNBQVMsR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUM7SUFDM0QsSUFBSSxJQUFJLENBQUMsU0FBUyxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQztJQUMzRCxJQUFJLElBQUksQ0FBQyxVQUFVLEdBQUcsTUFBTSxNQUFNLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQzVELElBQUksSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUM7SUFDNUQsSUFBSSxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQztJQUM1RCxJQUFJLE1BQU1JLGdCQUEyQixDQUFDLEVBQUUsQ0FBQzs7SUFFekMsSUFBSSxPQUFPLElBQUk7O0lBRWY7O0lBRUEsZUFBZSxlQUFlLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFO0lBQ2hFLElBQUksTUFBTSxJQUFJLEdBQUcsRUFBRTs7SUFFbkIsSUFBSSxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU87O0lBRTNCO0lBQ0E7SUFDQSxJQUFJLE1BQU1ELHdCQUFtQyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQzlELElBQUksTUFBTSxHQUFHLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFO0lBQ3BDLElBQUksSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHO0lBQ2xCLElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxNQUFNRSxZQUF1QixDQUFDLEVBQUUsRUFBRSxHQUFHLENBQUM7O0lBRW5ELElBQUksTUFBTSxHQUFHLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFO0lBQ3BDLElBQUksSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHO0lBQ2xCLElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxNQUFNQSxZQUF1QixDQUFDLEVBQUUsRUFBRSxHQUFHLENBQUM7SUFDbkQsSUFBSSxJQUFJLENBQUMsS0FBSyxHQUFHLE1BQU1MLGFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQztJQUNoRCxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFO0lBQ3JDLElBQUksSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7SUFDdkMsSUFBSSxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sRUFBRSxDQUFDLFNBQVMsRUFBRTtJQUMxQyxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDdEMsSUFBSSxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sRUFBRSxDQUFDLFNBQVMsRUFBRTtJQUMxQyxJQUFJLElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFO0lBQzVDLElBQUksSUFBSSxDQUFDLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ2hDLElBQUksSUFBSSxDQUFDLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDOztJQUVoQyxJQUFJLElBQUksQ0FBQyxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ3BELElBQUksSUFBSSxDQUFDLEVBQUUsR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUM7SUFDcEQsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQztJQUNwRCxJQUFJLElBQUksQ0FBQyxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ3BELElBQUksSUFBSSxDQUFDLEVBQUUsR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUM7SUFDcEQsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQztJQUNwRCxJQUFJLElBQUksQ0FBQyxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ3BELElBQUksSUFBSSxDQUFDLEVBQUUsR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUM7SUFDcEQsSUFBSSxJQUFJLENBQUMsR0FBRyxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQzs7SUFFckQsSUFBSSxNQUFNSSxnQkFBMkIsQ0FBQyxFQUFFLENBQUM7O0lBRXpDLElBQUksT0FBTyxJQUFJO0lBQ2Y7O0lBRUEsZUFBZSxnQkFBZ0IsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUU7SUFDakUsSUFBSSxNQUFNLElBQUksR0FBRyxFQUFFOztJQUVuQixJQUFJLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUTtJQUM1QixJQUFJLElBQUksQ0FBQyxVQUFVLEdBQUcsa0JBQWtCOztJQUV4QyxJQUFJLE1BQU1ELHdCQUFtQyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsc0JBQXNCLENBQUM7SUFDbkYsSUFBSSxNQUFNLEdBQUcsR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7SUFDcEMsSUFBSSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUc7SUFDbEIsSUFBSSxJQUFJLENBQUMsQ0FBQyxHQUFHLE1BQU1FLFlBQXVCLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQztJQUNuRCxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBTUwsYUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDOztJQUVoRCxJQUFJLE1BQU0sR0FBRyxHQUFHLE1BQU0sRUFBRSxDQUFDLFNBQVMsRUFBRTtJQUNwQyxJQUFJLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRztJQUNsQixJQUFJLElBQUksQ0FBQyxDQUFDLEdBQUcsTUFBTUssWUFBdUIsQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDOztJQUVuRCxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFO0lBQ3JDLElBQUksSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7SUFDdkMsSUFBSSxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sRUFBRSxDQUFDLFNBQVMsRUFBRTtJQUMxQyxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDdEMsSUFBSSxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sRUFBRSxDQUFDLFNBQVMsRUFBRTtJQUMxQyxJQUFJLElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFOztJQUU1QyxJQUFJLElBQUksQ0FBQyxFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUNoQyxJQUFJLElBQUksQ0FBQyxFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQzs7SUFFaEMsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDaEMsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDaEMsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDaEMsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7O0lBRWhDLElBQUksSUFBSSxDQUFDLEdBQUcsR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUM7O0lBRXJELElBQUksSUFBSSxDQUFDLEVBQUUsR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUM7O0lBRXBELElBQUksTUFBTUQsZ0JBQTJCLENBQUMsRUFBRSxDQUFDOztJQUV6QyxJQUFJLE9BQU8sSUFBSTtJQUNmOztJQUVPLGVBQWUsUUFBUSxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUU7SUFDbkQsSUFBSSxNQUFNLENBQUMsRUFBRSxFQUFFLFFBQVEsQ0FBQyxHQUFHLE1BQU1FLGFBQXdCLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7O0lBRTlFLElBQUksTUFBTSxJQUFJLEdBQUcsTUFBTUosWUFBVSxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDOztJQUV6RCxJQUFJLE1BQU0sRUFBRSxHQUFHLElBQUlLLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2xDLElBQUksTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDNUQsSUFBSSxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztJQUMxQixJQUFJLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQzs7SUFFakMsSUFBSSxJQUFJLEtBQUssR0FBRyxNQUFNUCxhQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQzs7SUFFdEM7SUFDQTtJQUNBLElBQUksTUFBTUcsd0JBQW1DLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDOUQsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDaEIsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUN6QyxRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ25ELFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3ZCLElBQUk7SUFDSixJQUFJLE1BQU1DLGdCQUEyQixDQUFDLEVBQUUsQ0FBQzs7O0lBR3pDO0lBQ0E7SUFDQSxJQUFJLE1BQU1ELHdCQUFtQyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQzlELElBQUksTUFBTSxPQUFPLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFO0lBQ3hDLElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxFQUFFO0lBQ3BCLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNsQyxRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sRUFBRSxDQUFDLFNBQVMsRUFBRTtJQUN0QyxRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sRUFBRSxDQUFDLFNBQVMsRUFBRTtJQUN0QyxRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sRUFBRSxDQUFDLFNBQVMsRUFBRTtJQUN0QyxRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFTLENBQUM7SUFDekMsUUFBUSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztJQUN6QixZQUFZLE1BQU0sRUFBRSxDQUFDO0lBQ3JCLFlBQVksVUFBVSxFQUFFLENBQUM7SUFDekIsWUFBWSxNQUFNLEVBQUUsQ0FBQztJQUNyQixZQUFZLEtBQUssRUFBRTtJQUNuQixTQUFTLENBQUM7SUFDVixJQUFJO0lBQ0osSUFBSSxNQUFNQyxnQkFBMkIsQ0FBQyxFQUFFLENBQUM7O0lBRXpDO0lBQ0E7SUFDQSxJQUFJLE1BQU1ELHdCQUFtQyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQzlELElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFO0lBQ2YsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNyQyxRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ25ELFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3JCLElBQUk7SUFDSixJQUFJLE1BQU1DLGdCQUEyQixDQUFDLEVBQUUsQ0FBQzs7O0lBR3pDO0lBQ0E7SUFDQSxJQUFJLE1BQU1ELHdCQUFtQyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQzlELElBQUksSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBQ2hCLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDckMsUUFBUSxNQUFNLEVBQUUsR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLFFBQVEsQ0FBQzs7SUFFcEQsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUU7SUFDdkIsSUFBSTtJQUNKLElBQUksTUFBTUMsZ0JBQTJCLENBQUMsRUFBRSxDQUFDOzs7SUFHekM7SUFDQTtJQUNBLElBQUksTUFBTUQsd0JBQW1DLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDOUQsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDaEIsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNyQyxRQUFRLE1BQU0sRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ3BELFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFO0lBQ3ZCLElBQUk7SUFDSixJQUFJLE1BQU1DLGdCQUEyQixDQUFDLEVBQUUsQ0FBQzs7O0lBR3pDO0lBQ0E7SUFDQSxJQUFJLE1BQU1ELHdCQUFtQyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQzlELElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFO0lBQ2YsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2xELFFBQVEsTUFBTSxDQUFDLEdBQUcsTUFBTSxNQUFNLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLENBQUM7O0lBRW5ELFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ3JCLElBQUk7SUFDSixJQUFJLE1BQU1DLGdCQUEyQixDQUFDLEVBQUUsQ0FBQzs7O0lBR3pDO0lBQ0E7SUFDQSxJQUFJLE1BQU1ELHdCQUFtQyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQzlELElBQUksSUFBSSxDQUFDLEtBQUssR0FBRyxFQUFFO0lBQ25CLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDMUMsUUFBUSxNQUFNLENBQUMsR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLFFBQVEsQ0FBQztJQUNuRCxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUMxQixJQUFJO0lBQ0osSUFBSSxNQUFNQyxnQkFBMkIsQ0FBQyxFQUFFLENBQUM7O0lBRXpDLElBQUksTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFOztJQUVwQixJQUFJLE9BQU8sSUFBSTs7SUFFZixJQUFJLGVBQWUsT0FBTyxpQkFBaUI7SUFDM0MsUUFBUSxNQUFNLENBQUMsR0FBRyxNQUFNQyxZQUF1QixDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQzdELFFBQVEsT0FBTyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7SUFDOUIsSUFBSTs7SUFFSjs7O0lBR0EsZUFBZUcsa0JBQWdCLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7SUFDckQsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7SUFDeEIsSUFBSSxDQUFDLENBQUMsVUFBVSxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ3BELElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLEdBQUcsTUFBTSxNQUFNLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLENBQUM7SUFDcEQsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxNQUFNLE1BQU0sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLFFBQVEsQ0FBQztJQUNyRCxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLE1BQU0sTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ3RELElBQUksQ0FBQyxDQUFDLFVBQVUsR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3BDLElBQUksQ0FBQyxDQUFDLElBQUksR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7O0lBRWpDLElBQUksTUFBTSxXQUFXLEdBQUcsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFO0lBQzVDLElBQUksTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLEdBQUc7SUFDekIsSUFBSSxJQUFJLFFBQVEsRUFBRSxDQUFDO0lBQ25CLElBQUksT0FBTyxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxXQUFXLEVBQUU7SUFDeEMsUUFBUSxNQUFNLFFBQVEsR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFFBQVEsSUFBSSxRQUFRLENBQUMsQ0FBQyxDQUFDLEdBQUcsUUFBUSxFQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLENBQUM7SUFDcEcsUUFBUSxRQUFRLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUM5QixRQUFRLElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUM1QixZQUFZLE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDNUMsWUFBWSxNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JELFlBQVksQ0FBQyxDQUFDLElBQUksR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUM7SUFDdEQsUUFBUSxDQUFDLE1BQU0sSUFBSSxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQ25DLFlBQVksTUFBTSxPQUFPLEdBQUcsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUM1QyxZQUFZLENBQUMsQ0FBQyxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQzNDLFFBQVEsQ0FBQyxNQUFNLElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNuQyxZQUFZLE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDNUMsWUFBWSxDQUFDLENBQUMsVUFBVSxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEQsUUFBUSxDQUFDLE1BQU07SUFDZixZQUFZLE1BQU0sSUFBSSxLQUFLLENBQUMsMEJBQTBCLENBQUM7SUFDdkQsUUFBUTtJQUNSLElBQUk7SUFDSixJQUFJLElBQUksRUFBRSxDQUFDLEdBQUcsSUFBSSxNQUFNLEdBQUcsV0FBVyxFQUFFO0lBQ3hDLFFBQVEsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQztJQUNsRCxJQUFJOztJQUVKLElBQUksT0FBTyxDQUFDO0lBQ1o7OztJQUdPLGVBQWUsYUFBYSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFO0lBQ3pELElBQUksTUFBTUwsd0JBQW1DLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxFQUFFLENBQUM7SUFDL0QsSUFBSSxNQUFNLEdBQUcsR0FBRyxFQUFFLGFBQWEsRUFBRSxFQUFFLENBQUM7SUFDcEMsSUFBSSxHQUFHLENBQUMsTUFBTSxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDbEMsSUFBSSxNQUFNLENBQUMsR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7SUFDbEMsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzVCLFFBQVEsTUFBTSxDQUFDLEdBQUcsTUFBTUssa0JBQWdCLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQztJQUNuRCxRQUFRLEdBQUcsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNqQyxJQUFJO0lBQ0osSUFBSSxNQUFNSixnQkFBMkIsQ0FBQyxFQUFFLENBQUM7O0lBRXpDLElBQUksT0FBTyxHQUFHO0lBQ2Q7O0lBRUEsZUFBZUssbUJBQWlCLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUU7SUFDL0MsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxVQUFVLENBQUM7SUFDMUMsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQzFDLElBQUksTUFBTSxPQUFPLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztJQUMzQyxJQUFJLE1BQU0sT0FBTyxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDNUMsSUFBSSxNQUFNLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQztJQUNoQyxJQUFJLE1BQU0sRUFBRSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQzs7SUFFcEMsSUFBSSxNQUFNLE1BQU0sR0FBRyxFQUFFO0lBQ3JCLElBQUksSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFO0lBQ2hCLFFBQVEsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2QixRQUFRLE1BQU0sUUFBUSxHQUFHLElBQUksV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDaEYsUUFBUSxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUM7SUFDeEMsUUFBUSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRSxJQUFJO0lBQ0osSUFBSSxJQUFJLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxFQUFFO0lBQ3JCLFFBQVEsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2QixRQUFRLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDOztJQUV2QyxRQUFRLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkIsUUFBUSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDO0lBQzVDLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsVUFBVSxFQUFFLENBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsRixJQUFJO0lBQ0osSUFBSSxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFO0lBQ3pCLFFBQVEsTUFBTSxVQUFVLEdBQUcsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDO0lBQ2pELFFBQVEsTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUM7SUFDbEQsUUFBUSxNQUFNLEVBQUUsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDO0lBQ2xDLElBQUksQ0FBQyxNQUFNO0lBQ1gsUUFBUSxNQUFNLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQzlCLElBQUk7O0lBRUo7O0lBRU8sZUFBZSxjQUFjLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUU7SUFDM0QsSUFBSSxNQUFNWCxpQkFBOEIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBQ2hELElBQUksTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDcEMsSUFBSSxNQUFNLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUM7SUFDdkQsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDekQsUUFBUSxNQUFNVyxtQkFBaUIsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckUsSUFBSTtJQUNKLElBQUksTUFBTVYsZUFBNEIsQ0FBQyxFQUFFLENBQUM7SUFDMUM7O0lBRU8sU0FBUyxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUU7SUFDekMsSUFBSSxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2hELElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMxQyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO0lBQ3ZCOztJQUVPLFNBQVMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFO0lBQ3hDLElBQUksTUFBTSxJQUFJLEdBQUcsSUFBSSxVQUFVLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNoRCxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMsaUJBQWlCLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDMUMsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztJQUN2Qjs7SUFFTyxTQUFTLFVBQVUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRTtJQUM3QyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxVQUFVLENBQUM7SUFDdkMsSUFBSSxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztJQUN2QyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQ3hDLElBQUksTUFBTSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDekMsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUM7SUFDL0I7O0lDbmpCQTtJQUNBOztJQUVBOztJQUVBO0lBQ0E7SUFDQTtJQUNBOztJQUVBO0lBQ0E7SUFDQTtJQUNBOztJQUVBO0lBQ0E7SUFDQTs7OztJQU9PLGVBQWUsS0FBSyxDQUFDLEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFOztJQUVoRCxJQUFJLE1BQU1ELGlCQUE4QixDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDL0MsSUFBSSxNQUFNLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUNyRSxJQUFJLE1BQU0sRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7SUFDM0IsSUFBSSxNQUFNRyxXQUF3QixDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDO0lBQ2pELElBQUksTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7SUFDdkMsSUFBSSxNQUFNRixlQUE0QixDQUFDLEVBQUUsQ0FBQzs7SUFFMUMsSUFBSSxNQUFNRCxpQkFBOEIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDekMsUUFBUSxNQUFNRyxXQUF3QixDQUFDLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQzFELElBQUk7SUFDSixJQUFJLE1BQU1GLGVBQTRCLENBQUMsRUFBSyxDQUFDOzs7SUFHN0M7O0lBRU8sZUFBZSxRQUFRLENBQUMsRUFBRSxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUU7O0lBRXRELElBQUksTUFBTUQsaUJBQThCLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUMvQyxJQUFJLE1BQU0sRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ3JFLElBQUksTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztJQUMzQixJQUFJLE1BQU1HLFdBQXdCLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUM7SUFDakQsSUFBSSxJQUFJLFVBQVUsQ0FBQyxVQUFVLEdBQUcsRUFBRSxJQUFJLENBQUMsRUFBRTtJQUN6QyxRQUFRLE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLENBQUM7SUFDakQsSUFBSTtJQUNKLElBQUksTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxVQUFVLEdBQUcsRUFBRSxDQUFDO0lBQ25ELElBQUksTUFBTUYsZUFBNEIsQ0FBQyxFQUFFLENBQUM7OztJQUcxQyxJQUFJLE1BQU1ELGlCQUE4QixDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDL0MsSUFBSSxNQUFNLEVBQUUsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDO0lBQzlCLElBQUksTUFBTUMsZUFBNEIsQ0FBQyxFQUFFLENBQUM7O0lBRTFDOztJQUVPLGVBQWUsVUFBVSxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUU7O0lBRS9DLElBQUksTUFBTUksd0JBQW1DLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDOUQsSUFBSSxNQUFNLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7SUFDbkMsSUFBSSxNQUFNLENBQUMsR0FBRyxNQUFNRSxZQUF1QixDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDbkQsSUFBSSxNQUFNLFFBQVEsR0FBRyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUU7SUFDekMsSUFBSSxNQUFNRCxnQkFBMkIsQ0FBQyxFQUFFLENBQUM7O0lBRXpDLElBQUksT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsUUFBUSxDQUFDOztJQUU1Qjs7SUFFTyxlQUFlLElBQUksQ0FBQyxRQUFRLEVBQUU7O0lBRXJDLElBQUksTUFBTSxDQUFDLEVBQUUsRUFBRSxRQUFRLENBQUMsR0FBRyxNQUFNRSxhQUF3QixDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDOztJQUU5RSxJQUFJLE1BQU0sQ0FBQyxFQUFFLEVBQUUsUUFBUSxDQUFDLEdBQUcsTUFBTSxVQUFVLENBQUMsRUFBRSxFQUFFLFFBQVEsQ0FBQzs7SUFFekQsSUFBSSxNQUFNSCx3QkFBbUMsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUM5RCxJQUFJLE1BQU0sR0FBRyxHQUFHLEVBQUU7SUFDbEIsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ25DLFFBQVEsTUFBTSxDQUFDLEdBQUcsTUFBTUUsWUFBdUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBQ3ZELFFBQVEsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDbkIsSUFBSTtJQUNKLElBQUksTUFBTUQsZ0JBQTJCLENBQUMsRUFBRSxDQUFDOztJQUV6QyxJQUFJLE1BQU0sRUFBRSxDQUFDLEtBQUssRUFBRTs7SUFFcEIsSUFBSSxPQUFPLEdBQUc7SUFDZDs7SUMxRkE7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7O0lBT0EsTUFBTSxtQkFBQ2pELGtCQUFnQixDQUFDLEdBQUcsS0FBSzs7SUFFakIsZUFBZSxZQUFZLENBQUMsWUFBWSxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFO0lBQzNGO0lBQ0E7SUFDQTtJQUNBLElBQUksSUFBSSxRQUFRLEdBQUcsSUFBSTtJQUN2QixJQUFJLElBQUksTUFBTSxJQUFJLE9BQU8sSUFBSSxPQUFPLENBQUM7SUFDckMsV0FBVyxPQUFPLE9BQU8sS0FBSyxXQUFXLElBQUksT0FBTyxPQUFPLENBQUMsV0FBVyxLQUFLLFVBQVUsRUFBRTtJQUN4RixRQUFRLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEdBQUcsSUFBSTtJQUNqRyxRQUFRLFFBQVEsR0FBRyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDO0lBQ3ZELElBQUk7SUFDSixJQUFJLElBQUk7SUFDUixRQUFRLE9BQU8sTUFBTSxhQUFhLENBQUMsWUFBWSxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDO0lBQ2xGLElBQUksQ0FBQyxTQUFTO0lBQ2QsUUFBUSxJQUFJLFFBQVEsRUFBRTtJQUN0QixZQUFZLGFBQWEsQ0FBQyxRQUFRLENBQUM7SUFDbkMsWUFBWSxRQUFRLENBQUMsTUFBTSxDQUFDO0lBQzVCLFFBQVE7SUFDUixJQUFJO0lBQ0o7O0lBRUEsZUFBZSxhQUFhLENBQUMsWUFBWSxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFOztJQUU3RSxJQUFJLE1BQU0sQ0FBQyxFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxZQUFZLENBQUMsR0FBRyxNQUFNbUQsYUFBd0IsQ0FBQyxlQUFlLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7O0lBRXpILElBQUksTUFBTSxJQUFJLEdBQUcsTUFBTUksVUFBb0IsQ0FBQyxNQUFNLEVBQUUsWUFBWSxDQUFDOztJQUVqRSxJQUFJLE1BQU0sQ0FBQyxFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxZQUFZLENBQUMsR0FBRyxNQUFNSixhQUF3QixDQUFDLFlBQVksRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQzs7SUFFdEgsSUFBSSxNQUFNLElBQUksR0FBRyxNQUFNSyxZQUFvQixDQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQzs7SUFFckYsSUFBSSxJQUFJLElBQUksQ0FBQyxRQUFRLElBQUksU0FBUyxFQUFFO0lBQ3BDLFFBQVEsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQztJQUNuRCxJQUFJOztJQUVKLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUU7SUFDckMsUUFBUSxNQUFNLElBQUksS0FBSyxDQUFDLGtFQUFrRSxDQUFDO0lBQzNGLElBQUk7O0lBRUosSUFBSSxJQUFJLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRTtJQUNyQyxRQUFRLE1BQU0sSUFBSSxLQUFLLENBQUMsQ0FBQyxpQ0FBaUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUNwRyxJQUFJOztJQUVKLElBQUksTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUs7SUFDNUIsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTtJQUN2QixJQUFJLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFO0lBQ3ZCLElBQUksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUU7O0lBRXZCLElBQUksT0FBTyxHQUFHLE9BQU8sSUFBSSxFQUFFOztJQUUzQjtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0EsSUFBSSxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsV0FBVyxJQUFJLE1BQU07SUFDckQsSUFBSSxJQUFJLFdBQVcsS0FBSyxNQUFNLElBQUksV0FBVyxLQUFLLFNBQVMsSUFBSSxXQUFXLEtBQUssVUFBVSxFQUFFO0lBQzNGLFFBQVEsTUFBTSxJQUFJLEtBQUssQ0FBQyxDQUFDLG1DQUFtQyxFQUFFLFdBQVcsQ0FBQyw0Q0FBNEMsQ0FBQyxDQUFDO0lBQ3hILElBQUk7SUFDSjtJQUNBO0lBQ0E7SUFDQTtJQUNBLElBQUksTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sSUFBSSxNQUFNO0lBQzNDLElBQUksTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sSUFBSSxNQUFNO0lBQzNDLElBQUksS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUMsRUFBRTtJQUN0RSxRQUFRLElBQUksQ0FBQyxLQUFLLE1BQU0sSUFBSSxDQUFDLEtBQUssVUFBVSxFQUFFO0lBQzlDLFlBQVksTUFBTSxJQUFJLEtBQUssQ0FBQyxDQUFDLHNCQUFzQixFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7SUFDbkcsUUFBUTtJQUNSLElBQUk7SUFDSixJQUFJLE1BQU0sT0FBTyxHQUFHLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUU7O0lBRXBFLElBQUksTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7O0lBRXZDLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUM7SUFDNUMsSUFBSSxNQUFNLFdBQVcsR0FBRyxNQUFNQyxhQUF3QixDQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDOztJQUUvRTtJQUNBO0lBQ0E7SUFDQTtJQUNBLElBQUksTUFBTSxlQUFlLEdBQUcsQ0FBQyxTQUFTLEtBQUs7SUFDM0MsUUFBUSxNQUFNLEtBQUssR0FBRyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsRCxRQUFRLE1BQU0sSUFBSSxHQUFHLFlBQVksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJO0lBQ3BELFFBQVEsT0FBTyxPQUFPLEdBQUcsRUFBRSxHQUFHLEtBQUs7SUFDbkMsWUFBWSxJQUFJLEdBQUcsR0FBRyxHQUFHLEdBQUcsSUFBSSxFQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsQ0FBQywyQ0FBMkMsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQzVHLFlBQVksTUFBTSxJQUFJLEdBQUcsSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDO0lBQzVDLFlBQVksTUFBTSxNQUFNLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLEtBQUssR0FBRyxHQUFHLENBQUM7SUFDaEUsWUFBWSxPQUFPLElBQUk7SUFDdkIsUUFBUSxDQUFDO0lBQ1QsSUFBSSxDQUFDOztJQUVMLElBQUksSUFBSSxJQUFJO0lBQ1osSUFBSSxJQUFJLFdBQVc7SUFDbkIsSUFBSSxJQUFJLFVBQVU7O0lBRWxCLElBQUksSUFBSSxVQUFVLEdBQUcsQ0FBQyxpQkFBaUI7SUFDdkMsUUFBUSxJQUFJLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTzs7SUFFckMsUUFBUSxNQUFNLENBQUMsaUJBQWlCO0lBQ2hDLFlBQVksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQztJQUN0RCxZQUFZLE1BQU0sVUFBVSxHQUFHLE1BQU1BLGFBQXdCLENBQUMsTUFBTSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUM7O0lBRXRGLFlBQVksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUM7O0lBRXBELFlBQVksSUFBSSxPQUFPLENBQUMsUUFBUSxLQUFLLElBQUksRUFBRTtJQUMzQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLE1BQU0sU0FBUyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxNQUFNLENBQUM7SUFDM0csWUFBWSxDQUFDLE1BQU0sSUFBSSxPQUFPLENBQUMsUUFBUSxLQUFLLFFBQVEsRUFBRTtJQUN0RCxnQkFBZ0IsTUFBTSxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsT0FBTyxDQUFDO0lBQzVFLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLEdBQUcsTUFBTSxjQUFjLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxXQUFXLENBQUM7SUFDMUksWUFBWSxDQUFDLE1BQU07SUFDbkI7SUFDQTtJQUNBO0lBQ0EsZ0JBQWdCLE1BQU0sQ0FBQyxHQUFHLGdCQUFnQixDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQztJQUM1RSxnQkFBZ0IsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLHlCQUF5QixFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBQzlHLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLEdBQUcsTUFBTSxjQUFjLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxXQUFXLENBQUM7SUFDMUksWUFBWTtJQUNaLFFBQVEsQ0FBQyxHQUFHOzs7SUFHWjtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7O0lBRUEsUUFBUSxNQUFNLEdBQUcsR0FBRyxLQUFLLEtBQUssRUFBRSxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDOztJQUV6RSxRQUFRLElBQUksVUFBVSxFQUFFLFVBQVUsRUFBRSxVQUFVO0lBQzlDO0lBQ0E7SUFDQTtJQUNBLFFBQVEsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDO0lBQzFCLFlBQVksQ0FBQyxrQkFBa0I7SUFDL0IsZ0JBQWdCLElBQUksS0FBSyxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQztJQUNsRixnQkFBZ0IsT0FBTyxHQUFHLElBQUk7SUFDOUIsZ0JBQWdCLE1BQU0sUUFBUSxHQUFHLE1BQU0sRUFBRSxDQUFDLGFBQWEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7SUFDNUUsZ0JBQWdCLFVBQVUsR0FBRyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUM7SUFDbEYsWUFBWSxDQUFDLEdBQUc7SUFDaEIsWUFBWSxDQUFDLGtCQUFrQjtJQUMvQixnQkFBZ0IsSUFBSSxLQUFLLEdBQUcsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsSUFBSSxDQUFDO0lBQ2xGLGdCQUFnQixPQUFPLEdBQUcsSUFBSTtJQUM5QixnQkFBZ0IsTUFBTSxRQUFRLEdBQUcsTUFBTSxFQUFFLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQztJQUM1RSxnQkFBZ0IsVUFBVSxHQUFHLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQztJQUNsRixZQUFZLENBQUMsR0FBRztJQUNoQixZQUFZLENBQUMsa0JBQWtCO0lBQy9CLGdCQUFnQixJQUFJLEtBQUssR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLENBQUM7SUFDbEYsZ0JBQWdCLE9BQU8sR0FBRyxJQUFJO0lBQzlCLGdCQUFnQixNQUFNLFFBQVEsR0FBRyxNQUFNLEVBQUUsQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDO0lBQzVFLGdCQUFnQixVQUFVLEdBQUcsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDO0lBQ2xGLFlBQVksQ0FBQyxHQUFHO0lBQ2hCLFNBQVMsQ0FBQzs7SUFFVixRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDO0lBQzVDLFFBQVEsVUFBVSxHQUFHLE1BQU0sT0FBTyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxDQUFDO0lBQzNGLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQztJQUNyRCxRQUFRLFVBQVUsR0FBRyxJQUFJO0lBQ3pCLFFBQVEsVUFBVSxHQUFHLElBQUk7SUFDekIsUUFBUSxVQUFVLEdBQUcsSUFBSTs7SUFFekIsUUFBUSxJQUFJLFVBQVUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLENBQUM7SUFDNUMsSUFBSSxDQUFDLEdBQUc7SUFDUjs7SUFFQSxJQUFJLElBQUksS0FBSyxHQUFHLEVBQUU7O0lBRWxCLElBQUksZUFBZSxPQUFPLEVBQUU7SUFDNUIsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLGtCQUFrQixDQUFDO0lBQ3BELFFBQVEsS0FBSyxDQUFDLElBQUksR0FBRyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUMscUJBQXFCLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsT0FBTyxDQUFDO0lBQ2xKLElBQUk7O0lBRUosSUFBSSxJQUFJLFVBQVUsR0FBRyxPQUFPLEVBQUU7SUFDOUI7O0lBRUEsSUFBSSxJQUFJLElBQUk7O0lBRVosSUFBSSxlQUFlLFFBQVEsR0FBRztJQUM5QixRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsbUJBQW1CLENBQUM7SUFDckQsUUFBUSxJQUFJLEdBQUcsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDLHFCQUFxQixDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLFdBQVcsRUFBRSxNQUFNLEVBQUUsYUFBYSxFQUFFLE9BQU8sQ0FBQztJQUM3SSxJQUFJOztJQUVKLElBQUksSUFBSSxXQUFXLEdBQUcsUUFBUSxFQUFFO0lBQ2hDOztJQUVBLElBQUksZUFBZSxPQUFPLEdBQUc7SUFDN0IsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLG1CQUFtQixDQUFDO0lBQ3JELFFBQVEsS0FBSyxDQUFDLElBQUksR0FBRyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUMscUJBQXFCLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxhQUFhLEVBQUUsT0FBTyxDQUFDO0lBQ25KLElBQUk7O0lBRUosSUFBSSxJQUFJLFVBQVUsR0FBRyxPQUFPLEVBQUU7SUFDOUI7O0lBRUEsSUFBSSxJQUFJLFVBQVUsR0FBRyxDQUFDLGlCQUFpQjtJQUN2QyxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsa0JBQWtCLENBQUM7SUFDcEQsUUFBUSxLQUFLLENBQUMsSUFBSSxHQUFHLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQyxxQkFBcUIsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLE9BQU8sQ0FBQztJQUN0TCxJQUFJLENBQUMsR0FBRztJQUNSOztJQUVBLElBQUksV0FBVyxHQUFHLENBQUMsaUJBQWlCO0lBQ3BDLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQztJQUNwRCxRQUFRLE1BQU0sVUFBVTtJQUN4QixRQUFRLElBQUksR0FBRyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUMscUJBQXFCLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsT0FBTyxDQUFDO0lBQzNJLElBQUksQ0FBQyxHQUFHO0lBQ1I7OztJQUdBLElBQUksTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUU7SUFDL0IsSUFBSSxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRTs7SUFFL0IsSUFBSSxNQUFNLFVBQVU7SUFDcEIsSUFBSSxLQUFLLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFO0lBQ3ZELElBQUksS0FBSyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsRUFBRSxDQUFDOztJQUV2RSxJQUFJLE1BQU0sVUFBVTtJQUNwQixJQUFJLEtBQUssQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUU7SUFDdEQsSUFBSSxLQUFLLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxFQUFFLENBQUM7O0lBRXZFLElBQUksTUFBTSxXQUFXO0lBQ3JCLElBQUksSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUU7SUFDekMsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFD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LE1BQU0sRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFO0lBQzFGLElBQUksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQzFCLElBQUksTUFBTSxLQUFLLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRztJQUNsQyxJQUFJLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxVQUFVOztJQUV0QyxJQUFJLElBQUksU0FBUztJQUNqQixJQUFJLElBQUksTUFBTSxZQUFZLFNBQVMsRUFBRTtJQUNyQyxRQUFRLE1BQU0sUUFBUSxHQUFHLEVBQUU7SUFDM0IsUUFBUSxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU07SUFDakQsUUFBUSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzdHLFFBQVEsU0FBUyxHQUFHLENBQUMsR0FBRyxLQUFLLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEdBQUcsUUFBUSxFQUFFLElBQUksQ0FBQztJQUNqRyxJQUFJLENBQUMsTUFBTTtJQUNYLFFBQVEsTUFBTSxRQUFRLEdBQUcsSUFBSSxRQUFRLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUM7SUFDMUYsUUFBUSxTQUFTLEdBQUcsQ0FBQyxHQUFHLEtBQUssUUFBUSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDO0lBQzFELElBQUk7SUFDSixJQUFJLFNBQVMsV0FBVyxDQUFDLENBQUMsRUFBRTtJ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TSxJQUFJLEdBQUcsRUFBRTs7SUFFdkIsUUFBUSxNQUFNLE1BQU0sR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRTtJQUNqRCxRQUFRLE1BQU0sTUFBTSxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFO0lBQ2pELFFBQVEsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUU7O0lBRWpELFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDMUQsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLFVBQVUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztJQUMxRCxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzFELFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3BELFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxNQUFNLENBQUM7SUFDOUQsWUFBWSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDcEIsWUFBWSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDcEIs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SSxNQUFNLFVBQVUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBQzdCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTs7SUFFekIsUUFBUSxNQUFNLFNBQVMsR0FBRyxJQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDM0MsUUFBUSxNQUFNLFVBQVUsR0FBRyxJQUFJLFFBQVEsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDOztJQUV6RCxRQUFRLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLENBQUM7O0lBRXpDLFFBQVEsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUM7SUFDeEMsSUFBSTs7O0lBR0osSUFBSSxNQUFNLFVBQVUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBQzdCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTs7SUFFekIsUUFBUSxNQUFNLFNBQVMsR0FBRyxJQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDM0MsUUFBUSxNQUFNLFVBQVUsR0FBRyxJQUFJLFFBQVEsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDOztJQUV6RCxRQUFRLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxVQUFVLEVBQUUsSUFBSSxDQUFDO0lBQ3JELFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsV0FBVyxDQUFDLEdBQUcsSUFBSSxDQUFDOztJQUVuRSxRQUFRLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDO0lBQ3hDLElBQUk7O0lBRUosSUFBSSxNQUFNLFNBQVMsQ0FBQyxHQUFHLEVBQUU7SUFDekIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJO0lBQ3pCLFFBQVEsTUFBTSxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7O0lBRXpDLFFBQVEsTUFBTSxJQUFJLEdB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QUssRUFBRSxhQUFhLENBQUMsRUFBRTtJQUNyRCxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsOEJBQThCLENBQUM7SUFDaEUsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTs7SUFFSixJQUFJLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQy9DLFFBQVEsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDOUQsUUFBUSxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN4QyxRQUFRLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDdkUsSUFBSTs7SUFFSixJQUFJLElBQUksSUFBSSxHQUFHLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQyxjQUFjLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNuRCxJQUFJLElBQUksR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDOztJQUVsQyxJQUFJLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7SUFDaEQsSUFBSSxNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ2hELElBQUksTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxV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QUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFQSxNQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7SUFDMUgsUUFBUSxDQUFDLENBQUMsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUVBLE1BQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQzNELFFBQVEsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQzs7SUFFckIsSUFBSSxPQUFPLENBQUM7SUFDWjs7SUM3Q0E7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7Ozs7Ozs7Ozs7SUNqQkE7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7OztJQU1PLFNBQVMsUUFBUSxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUU7SUFDdEMsSUFBSSxNQUFNLEtBQUssR0FBRyxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUM3RSxJQUFJLE1BQU0sSUFBSSxHQUFHLEVBQUU7SUFDbkIsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzVCLFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0QyxJ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LEdBQUcsRUFBRSxDQUFDO0lBQ3pGLFFBQVEsTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBQ2xGLFFBQVEsTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBQ2xGLFFBQVEsTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBQ2xGLFFBQVEsTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7SUFDeEUsUUFBUSxNQUFNQSxXQUF3QixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2xFLFFBQVEsTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUM5RixRQUFRLE1BQU1BLFdBQXdCLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7SUFDMUYsUUFBUSxNQUFNQSxXQUF3QixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBQzFGLFFBQVEsTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQzs7SUFFMUYsUUFBUSxNQUFNLEtBQUssQ0FBQyxLQUFLLEVBQUU7SUFDM0IsSUFBSTs7O0lBR0o7O0lDL0RBO0lBQ0E7O0lBRUE7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBOzs7SUFNZSxlQUFlLE9BQU8sQ0FBQyxlQUFlLEVBQUUsZUFBZSxFQUFFLE1BQU0sRUFBRTs7SUFFaEYsSUFBSSxNQUFNLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLENBQUMsR0FBRyxNQUFNekMsYUFBd0IsQ0FBQyxlQUFlLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUM1RixJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEdBQUcsTUFBTXVCLGNBQW9CLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQzs7SUFFdEUsSUFBSSxNQUFNLEtBQUssR0FBRyxNQUFNZixhQUEwQixDQUFDLGVBQWUsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUNsRixJQUFJLE1BQU1tQixlQUFxQixDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDOztJQUVwRDs7SUFFQSxJQUFJLE1BQU1jLFdBQXdCLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQzdELElBQUksTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDN0QsSUFBSSxNQUFNQSxXQUF3QixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUM3RCxJQUFJLE1BQU1BLFdBQXdCLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQzdELElBQUksTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDN0QsSUFBSSxNQUFNQSxXQUF3QixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzs7SUFFN0QsSUFBSSxNQUFNLGNBQWMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUU7SUFDL0MsSUFBSSxNQUFNQSxXQUF3QixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQztJQUM5RCxJQUFJLE1BQU1BLFdBQXdCLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDO0lBQzlELElBQUksTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUM7O0lBRTlELElBQUksTUFBTSxLQUFLLENBQUMsS0FBSyxFQUFFO0lBQ3ZCLElBQUksTUFBTSxLQUFLLENBQUMsS0FBSyxFQUFFOztJQUV2Qjs7SUFFQSxJQUFJOztJQUVKLElBQUksZUFBZSxjQUFjLENBQUMsWUFBWSxFQUFFLFlBQVksRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFO0lBQ2pGLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxXQUFXLENBQUM7O0lBRWxFLFFBQVEsTUFBTWpELGlCQUE4QixDQUFDLEtBQUssRUFBRSxZQUFZLENBQUM7O0lBRWpFLFFBQVEsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUk7SUFDbkQsUUFBUSxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsUUFBUTtJQUN4QyxRQUFRLE1BQU1LLHdCQUFtQyxDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsWUFBWSxDQUFDO0lBQ2hGLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsU0FBUyxFQUFFO0lBQzVDLFlBQVksTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLFNBQVMsQ0FBQztJQUNsRCxZQUFZLE1BQU0sSUFBSSxHQUFHLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDNUMsWUFBWSxNQUFNLEtBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ25DLFFBQVE7SUFDUixRQUFRLE1BQU1DLGdCQUEyQixDQUFDLEtBQUssQ0FBQzs7SUFFaEQsUUFBK0I7SUFDL0IsWUFBWSxNQUFNLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDOUMsUUFBUTs7SUFFUixRQUFRLE1BQU1MLGVBQTRCLENBQUMsS0FBSyxDQUFDOztJQUVqRCxRQUFRLGVBQWUsbUJBQW1CLENBQUMsQ0FBQyxFQUFFO0lBQzlDLFlBQVksTUFBTSxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUM7SUFDbEMsWUFBWSxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ2pDLFlBQVksTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQzs7SUFFakMsWUFBWSxJQUFJLElBQUk7SUFDcEIsWUFBWSxJQUFJLEdBQUcsSUFBSSxTQUFTLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQzs7SUFFOUMsWUFBWSxNQUFNSSx3QkFBbUMsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLFlBQVksQ0FBQztJQUNwRixZQUFZLElBQXlCLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNuRCxnQkFBZ0IsTUFBTSxLQUFLLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRTtJQUNuRSxnQkFBZ0IsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLFVBQVUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFO0lBQ2hFLFlBQVksQ0FBQyxNQUFNO0lBQ25CLGdCQUFnQixNQUFNLEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFO0lBQy9ELFlBQVk7SUFDWixZQUFZLE1BQU1DLGdCQUEyQixDQUFDLEtBQUssRUFBRSxJQUFJLENBQUM7O0lBRTFELFlBQVksSUFBSSxHQUFHLE1BQU0sQ0FBQyxDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxXQUFXLENBQUM7SUFDN0YsWUFBWSxNQUFNLEtBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDOztJQUVuQztJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBOztJQUVBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBOzs7SUFHQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0EsUUFBUTs7O0lBR1IsSUFBSTtJQUNKOztJQ25KQTtJQUNBOztJQUVBOztJQUVBO0lBQ0E7SUFDQTtJQUNBOztJQUVBO0lBQ0E7SUFDQTtJQUNBOztJQUVBO0lBQ0E7SUFDQTs7O0lBTWUsZUFBZSxVQUFVLENBQUMsWUFBWSxFQUFFLE9BQU8sRUFBRTtJQUNoRSxJQUFJLE1BQU0sQ0FBQyxFQUFFLEVBQUUsUUFBUSxDQUFDLEdBQUcsTUFBTUUsYUFBd0IsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQzs7SUFFbEYsSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxHQUFHLE1BQU11QixjQUFvQixDQUFDLEVBQUUsRUFBRSxRQUFRLENBQUM7O0lBRW5FLElBQUksTUFBTSxJQUFJLEdBQUcsRUFBRTtJQUNuQixJQUFJLElBQUksQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDcEIsSUFBSSxJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUs7SUFDdEIsSUFBSSxJQUFJLENBQUMsYUFBYSxHQUFHLE1BQU1DLGlCQUF1QixDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDOztJQUUzRSxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBTSxhQUFhLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxPQUFPLENBQUM7SUFDekUsSUFBSSxJQUFJLENBQUMsS0FBSyxHQUFHLE1BQU0sYUFBYSxDQUFDLENBQUMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxJQUFJLEtBQUssR0FBRyxPQUFPLENBQUM7SUFDcEUsSUFBSSxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sYUFBYSxDQUFDLENBQUMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxJQUFJLEtBQUssR0FBRyxZQUFZLENBQUM7SUFDOUUsSUFBSSxJQUFJLENBQUMsU0FBUyxHQUFHLE1BQU0sYUFBYSxDQUFDLENBQUMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxJQUFJLEtBQUssR0FBRyxXQUFXLENBQUM7SUFDNUUsSUFBSSxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sYUFBYSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxFQUFFLFFBQVEsQ0FBQzs7SUFFM0QsSUFBSSxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sY0FBYyxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxDQUFDO0lBQzFELElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLGNBQWMsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQztJQUMxRCxJQUFJLElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSxjQUFjLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxhQUFhLENBQUM7SUFDcEUsSUFBSSxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sY0FBYyxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsWUFBWSxDQUFDOztJQUVsRSxJQUFJLE1BQU0sRUFBRSxDQUFDLEtBQUssRUFBRTs7SUFFcEIsSUFBSSxPQUFPLHlCQUF5QixDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDOzs7O0lBSXBELElBQUksZUFBZSxhQUFhLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFO0lBQzdFLFFBQVEsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQztJQUNsQyxRQUFRLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7O0lBRTNCLFFBQVEsTUFBTSxHQUFHLEdBQUcsRUFBRTtJQUN0QixRQUFRLE1BQU0zQix3QkFBbUMsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQztJQUMxRSxRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDdkMsWUFBWSxJQUFJLENBQUMsT0FBTyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDakYsWUFBWSxNQUFNLElBQUksR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQzFDLFlBQVksR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztJQUMzQyxRQUFRO0lBQ1IsUUFBUSxNQUFNQyxnQkFBMkIsQ0FBQyxFQUFFLENBQUM7O0lBRTdDLFFBQVEsT0FBTyxHQUFHO0lBQ2xCLElBQUk7O0lBRUosSUFBSSxlQUFlLGNBQWMsQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRTtJQUNyRSxRQUFRLE1BQU0sQ0FBQyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUM7SUFDbEMsUUFBUSxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDOztJQUUzQixRQUFRLE1BQU0sR0FBRyxHQUFHLEVBQUU7SUFDdEIsUUFBUSxNQUFNRCx3QkFBbUMsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQztJQUMxRSxRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDckMsWUFBWSxJQUFJLE9BQU8sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxXQUFXLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkUsWUFBWSxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRTtJQUN2QixZQUFZLE1BQU0sT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDcEMsWUFBWSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzFDLGdCQUFnQixJQUFJLENBQUMsT0FBTyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ2hHLGdCQUFnQixNQUFNLElBQUksR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQzlDLGdCQUFnQixHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2xELFlBQVk7SUFDWixRQUFRO0lBQ1IsUUFBUSxNQUFNQyxnQkFBMkIsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDO0lBQ25ELFFBQVEsT0FBTyxHQUFHO0lBQ2xCLElBQUk7OztJQUdKOztJQ3ZGQTtJQUNBOztJQUVBOztJQUVBO0lBQ0E7SUFDQTtJQUNBOztJQUVBO0lBQ0E7SUFDQTtJQUNBOztJQUVBO0lBQ0E7SUFDQTs7Ozs7Ozs7Ozs7Ozs7Ozs7SUNqQkE7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7O0lBRWUsU0FBUyxTQUFTLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUU7SUFDdEQsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDbEQsUUFBUSxjQUFjLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMzQyxJQUFJO0lBQ0osSUFBSSxTQUFTLGNBQWMsQ0FBQyxDQUFDLEVBQUU7SUFDL0IsUUFBUSxNQUFNLE1BQU0sR0FBRyxDQUFDLEVBQUUsS0FBSztJQUMvQixZQUFZLElBQUksQ0FBQyxHQUFHLEVBQUU7SUFDdEIsWUFBWSxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN4QyxZQUFZLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEtBQUs7SUFDakMsZ0JBQWdCLElBQUksSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBQzlDLGdCQUFnQixJQUFJLElBQUksSUFBSSxLQUFLLEVBQUUsSUFBSSxHQUFHLEdBQUc7O0lBRTdDLGdCQUFnQixJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RELGdCQUFnQixJQUFJLEVBQUUsSUFBSSxHQUFHLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQztJQUN2QyxnQkFBZ0IsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFLEVBQUUsR0FBRyxHQUFHLENBQUM7SUFDekMsZ0JBQWdCLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLEVBQUU7SUFDdEQsZ0JBQWdCLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLEVBQUU7SUFDdEMsZ0JBQWdCLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxLQUFLLElBQUk7SUFDbEMsWUFBWSxDQUFDLENBQUM7SUFDZCxZQUFZLE9BQU8sQ0FBQztJQUNwQixRQUFRLENBQUM7SUFDVCxRQUFRLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ3ZGLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDbEMsSUFBSTs7SUFFSjs7SUM1Q0EsTUFBTTRDLGVBQWEsR0FBRyxPQUFPOztJQUU3QixNQUFNQyxpQkFBZSxHQUFHO0lBQ3hCLElBQUksR0FBRyxFQUFFLFNBQVMsR0FBRyxFQUFFLElBQUksRUFBRTtJQUM3QixRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUU7SUFDMUIsWUFBWSxPQUFPLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDO0lBQ3ZDLFFBQVEsQ0FBQyxNQUFNLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FBQztJQUMvQixJQUFJLENBQUM7SUFDTCxJQUFJLEdBQUcsRUFBRSxTQUFTLEdBQUcsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFO0lBQ3BDLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRTtJQUMxQixZQUFZLE9BQU8sR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDO0lBQzlDLFFBQVEsQ0FBQyxNQUFNO0lBQ2YsWUFBWSxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSztJQUM3QixZQUFZLE9BQU8sSUFBSTtJQUN2QixRQUFRO0lBQ1IsSUFBSTtJQUNKLENBQUM7O3NCQUVELE1BQU0sU0FBUyxDQUFDO0lBQ2hCLElBQUksV0FBVyxDQUFDLENBQUMsUUFBUSxFQUFFO0lBQzNCLFFBQVEsSUFBSSxDQUFDLE1BQU0sR0FBRyxRQUFRLElBQUksQ0FBQztJQUNuQyxRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxLQUFLLENBQUNELGVBQWEsQ0FBQzs7SUFFM0MsUUFBUSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUMsRUFBRUEsZUFBYSxFQUFFO0lBQ3BELFlBQVksSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUNBLGVBQWEsQ0FBQyxHQUFHLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUNBLGVBQWEsRUFBRSxRQUFRLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDeEYsUUFBUTtJQUNSLFFBQVEsT0FBTyxJQUFJO0lBQ25CLElBQUk7SUFDSixJQUFJLElBQUksQ0FBQyxHQUFHO0lBQ1osUUFBUSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUMvQyxZQUFZLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkQsUUFBUTtJQUNSLElBQUk7O0lBRUosSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQ2pCLFFBQVEsTUFBTSxHQUFHLEdBQUcsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsQyxRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUM5RCxRQUFRLE9BQU8sR0FBRztJQUNsQixJQUFJO0lBQ0osSUFBSSxVQUFVLENBQUMsR0FBRyxFQUFFO0lBQ3BCLFFBQVEsR0FBRyxHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUM7SUFDM0IsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBR0EsZUFBYSxDQUFDO0lBQ3BELFFBQVEsTUFBTSxJQUFJLEdBQUcsR0FBRyxHQUFHQSxlQUFhO0lBQ3hDLFFBQVEsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsU0FBUztJQUNoRSxJQUFJO0lBQ0osSUFBSSxVQUFVLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRTtJQUMzQixRQUFRLEdBQUcsR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDO0lBQzNCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEdBQUdBLGVBQWEsQ0FBQztJQUNwRCxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFO0lBQzdCLFlBQVksSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLEtBQUssQ0FBQ0EsZUFBYSxDQUFDO0lBQ3JELFFBQVE7SUFDUixRQUFRLE1BQU0sSUFBSSxHQUFHLEdBQUcsR0FBR0EsZUFBYTtJQUN4QyxRQUFRLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSztJQUNwQyxRQUFRLElBQUksR0FBRyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sR0FBRyxHQUFHLENBQUMsQ0FBQztJQUNuRCxRQUFRLE9BQU8sSUFBSTtJQUNuQixJQUFJO0lBQ0osSUFBSSxPQUFPLEdBQUc7SUFDZCxRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUlFLFVBQVEsRUFBRTtJQUNuQyxRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUM5QyxZQUFZLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUM3QixnQkFBZ0IsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3pELG9CQUFvQixJQUFJLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxXQUFXLEVBQUU7SUFDL0Qsd0JBQXdCLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDRixlQUFhLENBQUMsQ0FBQyxDQUFDO0lBQ3BELG9CQUFvQjtJQUNwQixnQkFBZ0I7SUFDaEIsWUFBWTtJQUNaLFFBQVE7SUFDUixRQUFRLE9BQU8sSUFBSTtJQUNuQixJQUFJO0lBQ0o7O3FCQUVBLE1BQU0sUUFBUSxDQUFDO0lBQ2YsSUFBSSxXQUFXLEVBQUUsUUFBUSxHQUFHO0lBQzVCLFFBQVEsTUFBTSxHQUFHLEdBQUcsSUFBSUcsV0FBUyxDQUFDLFFBQVEsQ0FBQztJQUMzQyxRQUFRLE1BQU0sTUFBTSxHQUFHLElBQUksS0FBSyxDQUFDLEdBQUcsRUFBRUYsaUJBQWUsQ0FBQztJQUN0RCxRQUFRLE9BQU8sTUFBTTtJQUNyQixJQUFJO0lBQ0o7O0lDMUVPLGVBQWUsSUFBSSxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRTtJQUNyRSxJQUFJLFNBQVMsR0FBRyxTQUFTLElBQUksSUFBSSxDQUFDLEVBQUU7SUFHcEMsSUFBSSxNQUFNLEVBQUUsRUFBRSxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUM7O0lBRXpELElBQUksTUFBTSxLQUFLLEdBQUcsTUFBTSxFQUFFLENBQUMsSUFBSSxFQUFFOztJQUVqQyxJQUFJLFFBQVEsSUFBSSxRQUFRLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQztJQUNsRTs7O0lBR0EsTUFBTSxRQUFRLENBQUM7O0lBRWYsSUFBSSxXQUFXLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRTtJQUMxRCxRQUFRLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUTtJQUNoQyxRQUFRLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRTtJQUNwQixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUNwQixRQUFRLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDNUMsUUFBUSxPQUFPLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDLE9BQU8sRUFBRTtJQUM5QyxZQUFZLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQztJQUM5QixRQUFRO0lBQ1IsUUFBUSxJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxJQUFJO0lBQ25DLFFBQVEsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7SUFDdkUsUUFBUSxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsU0FBUyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQ3RFLFFBQVEsSUFBSSxDQUFDLEtBQUssR0FBRyxFQUFFO0lBQ3ZCLFFBQVEsSUFBSSxDQUFDLFlBQVksR0FBRyxFQUFFO0lBQzlCLFFBQVEsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLO0lBQzVCLFFBQVEsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLO0lBQzVCLFFBQVEsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFO0lBQ3pCLFFBQVEsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFO0lBQ3pCLElBQUk7O0lBRUosSUFBSSxTQUFTLENBQUMsQ0FBQyxFQUFFO0lBQ2pCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTtJQUN6QixRQUFRLE1BQU0sQ0FBQyxHQUFHLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sSUFBSTtJQUNsRCxZQUFZLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDO0lBQ25DLGdCQUFnQixJQUFJLEVBQUUsQ0FBQztJQUN2QixnQkFBZ0IsT0FBTyxFQUFFLE9BQU87SUFDaEMsZ0JBQWdCLE1BQU0sRUFBRTtJQUN4QixhQUFhLENBQUM7SUFDZCxRQUFRLENBQUMsQ0FBQztJQUNWLFFBQVEsSUFBSSxDQUFDLFlBQVksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDLENBQUM7SUFDcEQsUUFBUSxPQUFPLENBQUM7SUFDaEIsSUFBSTs7SUFFSixJQUFJLFlBQVksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQ3ZCLFFBQVEsTUFBTSxRQUFRLEdBQUcsRUFBRTtJQUMzQixRQUFRLE1BQU0sSUFBSSxDQUFDLElBQUk7SUFDdkIsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRTtJQUM5QixRQUFRLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZDLFFBQVEsSUFBSSxDQUFDLEdBQUcsRUFBRTtJQUNsQixRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUN2RCxZQUFZLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDL0QsUUFBUTtJQUNSLFFBQVEsSUFBSSxDQUFDLEVBQUUsUUFBUSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUM7SUFDaEQsUUFBUSxJQUFJLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxXQUFXLEVBQUU7SUFDakQsWUFBWSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUN0QyxZQUFZLFFBQVEsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ25DLFlBQVksUUFBUSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUN6RCxZQUFZLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3JFLFlBQVksSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDO0lBQ3RELFlBQVksSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ2xELFFBQVE7SUFDUixRQUFRLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDOztJQUUzQixRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRTtJQUNsRCxRQUFRLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN0QyxJQUFJOztJQUVKLElBQUksY0FBYyxDQUFDLENBQUMsRUFBRTtJQUN0QixRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7SUFDekIsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQixFQUFFLENBQUMsQ0FBQztJQUM5RCxRQUFRLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUNqQyxRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNyRCxZQUFZLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUM1RCxnQkFBZ0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRCxZQUFZO0lBQ1osUUFBUTtJQUNSLElBQUk7Ozs7SUFJSixJQUFJLFlBQVksR0FBRztJQUNuQixRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7O0lBRXpCLFFBQVEsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFO0lBQzFCLFFBQVEsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUU7O0lBRXpDLFFBQVEsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDOztJQUVoRCxRQUFRLE1BQU0sY0FBYyxHQUFHLEVBQUU7SUFDakMsUUFBUSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUM5QyxZQUFZLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFELFlBQVksSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksS0FBSyxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsY0FBYyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDekksUUFBUTs7SUFFUixRQUFRLElBQUksU0FBUyxHQUFHLElBQUksQ0FBQyxjQUFjLEdBQUcsUUFBUSxDQUFDLE1BQU07O0lBRTdELFFBQVEsTUFBTSxHQUFHLEdBQUcsRUFBRTs7SUFFdEI7SUFDQTtJQUNBLFFBQVE7SUFDUixZQUFZLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN2QyxnQkFBZ0IsQ0FBQyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxXQUFXO0lBQzVFLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQy9CLG9CQUFvQixjQUFjLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNoRCxZQUFZLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFO0lBQ2xELFlBQVksSUFBSSxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLFdBQVcsRUFBRTtJQUM3RCxnQkFBZ0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxHQUFHO0lBQ25ELGdCQUFnQixNQUFNLEdBQUcsR0FBRyxjQUFjLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDN0QsZ0JBQWdCLElBQUksR0FBRyxFQUFFLENBQUMsRUFBRSxjQUFjLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDekQsZ0JBQWdCLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFO0lBQ25ELG9CQUFvQixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztJQUM1RCxnQkFBZ0IsQ0FBQyxNQUFNO0lBQ3ZCLG9CQUFvQixJQUFJLENBQUMsT0FBTyxFQUFFO0lBQ2xDLGdCQUFnQjtJQUNoQixnQkFBZ0IsSUFBSSxDQUFDLFlBQVksQ0FBQyx1QkFBdUIsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDOztJQUVyRSxZQUFZLENBQUMsTUFBTTtJQUNuQixnQkFBZ0IsSUFBSSxTQUFTLEVBQUU7SUFDL0Isb0JBQW9CLFNBQVMsRUFBRTtJQUMvQixnQkFBZ0IsQ0FBQyxNQUFNO0lBQ3ZCLG9CQUFvQixNQUFNLEVBQUUsR0FBRyxjQUFjLENBQUMsS0FBSyxFQUFFO0lBQ3JELG9CQUFvQixJQUFJLENBQUMsWUFBWSxDQUFDLGlCQUFpQixFQUFFLEVBQUUsQ0FBQztJQUM1RCxvQkFBb0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN4RCxvQkFBb0IsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztJQUN6QyxvQkFBb0IsSUFBSSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLENBQUM7SUFDM0QsZ0JBQWdCOztJQUVoQixnQkFBZ0IsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUU7SUFDaEQsb0JBQW9CLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLFVBQVUsRUFBRTtJQUN4RCxvQkFBb0IsSUFBSSxDQUFDLE9BQU8sRUFBRTtJQUNsQyxvQkFBb0IsSUFBSSxDQUFDLFlBQVksQ0FBQyxvQkFBb0IsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQ3RFLGdCQUFnQixDQUFDLE1BQU07SUFDdkIsb0JBQW9CLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSTtJQUN2QyxvQkFBb0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsVUFBVSxFQUFFO0lBQ3hELG9CQUFvQixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUM7SUFDMUQsb0JBQW9CLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSTtJQUM5SCx3QkFBd0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxHQUFHLEdBQUcsQ0FBQyxTQUFTO0lBQ2xFLHdCQUF3QixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPO0lBQ3JFLHdCQUF3QixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU87SUFDNUQsd0JBQXdCLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzdELDRCQUE0QixPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFO0lBQ2hELHdCQUF3QjtJQUN4Qix3QkFBd0IsSUFBSSxDQUFDLFlBQVksQ0FBQyx1QkFBdUIsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQzdFLHdCQUF3QixPQUFPLEdBQUc7SUFDbEMsb0JBQW9CLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSztJQUNoQyx3QkFBd0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7SUFDeEMsb0JBQW9CLENBQUMsQ0FBQyxDQUFDO0lBQ3ZCLG9CQUFvQixJQUFJLENBQUMsWUFBWSxDQUFDLHdCQUF3QixFQUFFLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDMUUsZ0JBQWdCO0lBQ2hCLFlBQVk7SUFDWixRQUFRO0lBQ1I7O0lBRUEsUUFBUSxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxNQUFNO0lBQ3JDLFlBQVksSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLO0lBQ2hDLFlBQVksSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3RGLFlBQVksSUFBSSxDQUFDLFNBQVMsRUFBRTtJQUM1QixRQUFRLENBQUMsQ0FBQzs7SUFFVixRQUFRLFNBQVMsVUFBVSxHQUFHO0lBQzlCLFlBQVksSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUU7SUFDdkMsZ0JBQWdCLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFO0lBQzlDLGdCQUFnQixDQUFDLENBQUMsS0FBSyxHQUFHLEtBQUs7SUFDL0IsZ0JBQWdCLENBQUMsQ0FBQyxVQUFVLEdBQUcsQ0FBQztJQUNoQyxnQkFBZ0IsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3pCLGdCQUFnQixPQUFPLENBQUM7SUFDeEIsWUFBWSxDQUFDLE1BQU07SUFDbkIsZ0JBQWdCLE9BQU87SUFDdkIsb0JBQW9CLEtBQUssRUFBRSxLQUFLO0lBQ2hDLG9CQUFvQixJQUFJLEVBQUUsSUFBSSxVQUFVLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN2RCxvQkFBb0IsVUFBVSxFQUFFLENBQUM7SUFDakMsb0JBQW9CLElBQUksRUFBRTtJQUMxQixpQkFBaUI7SUFDakIsWUFBWTtJQUNaLFFBQVE7O0lBRVIsSUFBSTs7O0lBR0osSUFBSSxhQUFhLEdBQUc7SUFDcEIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJO0lBQ3pCLFFBQVEsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFOztJQUUxQixRQUFRLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQzs7SUFFaEQsUUFBUSxNQUFNLEdBQUcsR0FBRyxFQUFFOztJQUV0QixRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzlDLFlBQVksTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUQsWUFBWSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUU7SUFDNUIsZ0JBQWdCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSztJQUNsQyxnQkFBZ0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJO0lBQ25DLGdCQUFnQixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUk7SUFDbkMsZ0JBQWdCLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNO0lBQ2pILG9CQUFvQixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUs7SUFDeEMsb0JBQW9CO0lBQ3BCLGdCQUFnQixDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUs7SUFDNUIsb0JBQW9CLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDO0lBQ3RELG9CQUFvQixJQUFJLENBQUMsS0FBSyxHQUFHLEdBQUc7SUFDcEMsb0JBQW9CLElBQUksQ0FBQyxTQUFTLEVBQUU7SUFDcEMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDO0lBQ25CLFlBQVk7SUFDWixRQUFROztJQUVSLFFBQVEsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFO0lBQzFCLFlBQVksT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsTUFBTTtJQUN6QyxnQkFBZ0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLO0lBQ3BDLGdCQUFnQixZQUFZLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDM0QsZ0JBQWdCLElBQUksQ0FBQyxTQUFTLEVBQUU7SUFDaEMsZ0JBQWdCLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLFlBQVksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxRixZQUFZLENBQUMsQ0FBQztJQUNkLFFBQVE7SUFDUixJQUFJOztJQUVKLElBQUksYUFBYSxHQUFHO0lBQ3BCLFFBQVEsS0FBSyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFO0lBQ2xDLFlBQVksSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUM7SUFDN0MsUUFBUTtJQUNSLFFBQVEsT0FBTyxFQUFFO0lBQ2pCLElBQUk7O0lBRUosSUFBSSxNQUFNLEtBQUssQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFO0lBQzNCLFFBQVEsSUFBSSxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsRUFBRTtJQUNsQyxRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7SUFDekI7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0EsUUFBUSxJQUFJLE9BQU8sR0FBRyxJQUFJLFdBQVcsRUFBRSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUc7SUFDckQsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsVUFBVTtJQUN0QyxRQUFRLElBQUksSUFBSSxDQUFDLFNBQVMsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsU0FBUyxHQUFHLEdBQUcsR0FBRyxJQUFJLENBQUMsVUFBVTtJQUMxRixRQUFRLElBQUksSUFBSSxDQUFDLFlBQVk7SUFDN0IsWUFBWSxNQUFNLElBQUksS0FBSyxDQUFDLHdCQUF3QixDQUFDO0lBQ3JELFFBQVEsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN6RCxRQUFRLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQzs7SUFFL0UsUUFBUSxNQUFNLFlBQVksR0FBRyxFQUFFO0lBQy9CLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEYsUUFBUSxJQUFJLENBQUMsWUFBWSxFQUFFOztJQUUzQixRQUFRLElBQUksQ0FBQyxHQUFHLFNBQVM7SUFDekIsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDLFFBQVE7SUFDbkMsUUFBUSxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsVUFBVTtJQUMvQixRQUFRLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNwQixZQUFZLE1BQU0sWUFBWSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDM0MsWUFBWSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsS0FBSyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsSUFBSSxDQUFDO0lBQ3BFLFlBQVksTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDckYsWUFBWSxNQUFNLE9BQU8sR0FBRyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMzRSxZQUFZLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO0lBQ2hDLFlBQVksSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsSUFBSTtJQUN0QyxZQUFZLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxHQUFHO0lBQ3ZDLFlBQVksSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQ2xFLFlBQVksSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRTtJQUNwQyxnQkFBZ0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNyQyxZQUFZO0lBQ1osWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDbkIsWUFBWSxDQUFDLEdBQUc7SUFDaEIsWUFBWSxDQUFDLEdBQUcsQ0FBQztJQUNqQixZQUFZLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFlBQVksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxRSxRQUFRO0lBQ1IsSUFBSTs7SUFFSixJQUFJLE1BQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUU7SUFDekIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJO0lBQ3pCLFFBQVEsSUFBSSxJQUFJLEdBQUcsSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDO0lBQ3RDLFFBQVEsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQzs7SUFFbEQsUUFBUSxPQUFPLElBQUk7SUFDbkIsSUFBSTs7SUFFSixJQUFJLE1BQU0sWUFBWSxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRTtJQUNsRCxRQUFRLElBQUksR0FBRyxJQUFJLENBQUMsRUFBRTtJQUN0QixZQUFZO0lBQ1osUUFBUTtJQUNSLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTtJQUN6QixRQUFRLElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFHLEVBQUU7SUFDekQsWUFBWSxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDbkQsWUFBWSxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsU0FBUyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQzFFLFFBQVE7SUFDUixRQUFRLElBQUksT0FBTyxHQUFHLElBQUksV0FBVyxFQUFFLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRztJQUNyRCxRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUc7SUFDMUIsUUFBUSxJQUFJLElBQUksQ0FBQyxZQUFZO0lBQzdCLFlBQVksTUFBTSxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQztJQUNyRCxRQUFRLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7SUFDekQsUUFBUSxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQzs7SUFFbkUsUUFBUSxNQUFNLFlBQVksR0FBRyxFQUFFO0lBQy9CLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRXBGLFFBQVEsSUFBSSxDQUFDLFlBQVksRUFBRTs7SUFFM0IsUUFBUSxJQUFJLENBQUMsR0FBRyxTQUFTO0lBQ3pCLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxRQUFRO0lBQ25DO0lBQ0EsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLEdBQUcsR0FBRyxJQUFJLEdBQUcsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEdBQUc7SUFDcEYsUUFBUSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUU7SUFDcEIsWUFBWSxNQUFNLFlBQVksQ0FBQyxDQUFDLEdBQUcsU0FBUyxDQUFDO0lBQzdDLFlBQVksSUFBSSxDQUFDLFlBQVksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDLENBQUM7O0lBRXhEO0lBQ0EsWUFBWSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsS0FBSyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsSUFBSSxDQUFDO0lBQ3BFLFlBQVksTUFBTSxPQUFPLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzNHLFlBQVksT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDOUMsWUFBWSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBRzs7SUFFdkMsWUFBWSxJQUFJLENBQUMsWUFBWSxDQUFDLGlCQUFpQixFQUFFLENBQUMsQ0FBQzs7SUFFbkQsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDbkIsWUFBWSxDQUFDLEdBQUc7SUFDaEIsWUFBWSxDQUFDLEdBQUcsQ0FBQztJQUNqQixZQUFZLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLFlBQVksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0RixRQUFROztJQUVSLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsR0FBRzs7SUFFNUIsSUFBSTs7O0lBR0osSUFBSSxTQUFTLEdBQUc7SUFDaEIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJO0lBQ3pCLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUU7SUFDaEMsUUFBUSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUU7SUFDeEIsWUFBWSxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztJQUMvQyxRQUFRO0lBQ1IsUUFBUSxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFO0lBQ3RDLFFBQVEsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUN4RixRQUFRLElBQUksQ0FBQyxZQUFZLEVBQUU7SUFDM0IsSUFBSTs7SUFFSixJQUFJLEtBQUssR0FBRztJQUNaLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTtJQUN6QixRQUFRLElBQUksSUFBSSxDQUFDLFlBQVk7SUFDN0IsWUFBWSxNQUFNLElBQUksS0FBSyxDQUFDLHdCQUF3QixDQUFDO0lBQ3JELFFBQVEsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEtBQUs7SUFDaEQsWUFBWSxJQUFJLENBQUMsWUFBWSxHQUFHLE9BQU87SUFDdkMsWUFBWSxJQUFJLENBQUMsa0JBQWtCLEdBQUcsTUFBTTtJQUM1QyxZQUFZLElBQUksQ0FBQyxTQUFTLEVBQUU7SUFDNUIsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSztJQUNyQixZQUFZLElBQUksQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFO0lBQzNCLFFBQVEsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLO0lBQ3BCLFlBQVksSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUU7SUFDM0IsWUFBWSxPQUFPLEdBQUc7SUFDdEIsUUFBUSxDQUFDLENBQUM7SUFDVixJQUFJOztJQUVKLElBQUksTUFBTSxPQUFPLEdBQUc7SUFDcEIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJO0lBQ3pCLFFBQVEsTUFBTSxJQUFJLENBQUMsS0FBSyxFQUFFO0lBQzFCLFFBQVEsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQy9DLElBQUk7O0lBRUosSUFBSSxNQUFNLFVBQVUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBQzdCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTtJQUN6QixRQUFRLE1BQU0sU0FBUyxHQUFHLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQztJQUMzQyxRQUFRLE1BQU0sVUFBVSxHQUFHLElBQUksUUFBUSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7O0lBRXpELFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQzs7SUFFeEMsUUFBUSxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQztJQUN4QyxJQUFJOztJQUVKLElBQUksTUFBTSxVQUFVLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRTtJQUM3QixRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7O0lBRXpCLFFBQVEsTUFBTSxTQUFTLEdBQUcsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQzNDLFFBQVEsTUFBTSxVQUFVLEdBQUcsSUFBSSxRQUFRLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQzs7SUFFekQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDOztJQUV6QyxRQUFRLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDO0lBQ3hDLElBQUk7OztJQUdKLElBQUksTUFBTSxVQUFVLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRTtJQUM3QixRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7O0lBRXpCLFFBQVEsTUFBTSxTQUFTLEdBQUcsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQzNDLFFBQVEsTUFBTSxVQUFVLEdBQUcsSUFBSSxRQUFRLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQzs7SUFFekQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsVUFBVSxFQUFFLElBQUksQ0FBQztJQUNyRCxRQUFRLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxHQUFHLElBQUksQ0FBQzs7SUFFbkUsUUFBUSxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQztJQUN4QyxJQUFJOztJQUVKLElBQUksTUFBTSxTQUFTLENBQUMsR0FBRyxFQUFFO0lBQ3pCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTtJQUN6QixRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDOztJQUV6QyxRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUksV0FBVyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7O0lBRTlDLFFBQVEsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3RCLElBQUk7O0lBRUosSUFBSSxNQUFNLFNBQVMsQ0FBQyxHQUFHLEVBQUU7SUFDekIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJO0lBQ3pCLFFBQVEsTUFBTSxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7O0lBRXpDLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSSxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQzs7SUFFM0MsUUFBUSxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQztJQUN2QyxJQUFJOztJQUVKLElBQUksTUFBTSxTQUFTLENBQUMsR0FBRyxFQUFFO0lBQ3pCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTtJQUN6QixRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDOztJQUV6QyxRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUksV0FBVyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7O0lBRTlDLFFBQVEsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDOUMsSUFBSTs7SUFFSixJQUFJLE1BQU0sVUFBVSxDQUFDLEdBQUcsRUFBRTtJQUMxQixRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7O0lBRXpCLFFBQVEsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFO0lBQy9CLFlBQVksTUFBTSxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQztJQUNyRCxRQUFROztJQUVSLFFBQVEsSUFBSSxlQUFlLEdBQUcsT0FBTyxHQUFHLElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRztJQUN4RSxRQUFRLElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7O0lBRXJFLFFBQVEsSUFBSSxnQkFBZ0IsR0FBRyxLQUFLO0lBQ3BDLFFBQVEsSUFBSSxHQUFHLEdBQUcsRUFBRTs7SUFFcEIsUUFBUSxPQUFPLENBQUMsZ0JBQWdCLEVBQUU7SUFDbEM7SUFDQSxZQUFZLElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDO0lBQ3pELFlBQVksSUFBSSxDQUFDLFlBQVksRUFBRTtJQUMvQixZQUFZLE1BQU0sV0FBVztJQUM3QixZQUFZLElBQUksQ0FBQyxZQUFZLENBQUMsc0JBQXNCLEVBQUUsV0FBVyxDQUFDOztJQUVsRSxZQUFZLElBQUksWUFBWSxHQUFHLGVBQWUsR0FBRyxJQUFJLENBQUMsUUFBUTs7SUFFOUQsWUFBWSxNQUFNLFNBQVMsR0FBRyxJQUFJLFVBQVU7SUFDNUMsZ0JBQWdCLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU07SUFDbkQsZ0JBQWdCLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxZQUFZO0lBQ3RFLGdCQUFnQixJQUFJLENBQUMsUUFBUSxHQUFHO0lBQ2hDLGFBQWE7O0lBRWIsWUFBWSxJQUFJLGdCQUFnQixHQUFHLFNBQVMsQ0FBQyxTQUFTLENBQUMsT0FBTyxJQUFJLE9BQU8sS0FBSyxDQUFDLENBQUM7SUFDaEYsWUFBWSxnQkFBZ0IsR0FBRyxnQkFBZ0IsS0FBSyxFQUFFOztJQUV0RCxZQUFZLElBQUksZ0JBQWdCLEVBQUU7SUFDbEMsZ0JBQWdCLEdBQUcsSUFBSSxJQUFJLFdBQVcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ3JGLGdCQUFnQixJQUFJLENBQUMsR0FBRyxHQUFHLFdBQVcsR0FBRyxJQUFJLENBQUMsUUFBUSxHQUFHLFlBQVksR0FBRyxnQkFBZ0IsR0FBRyxDQUFDO0lBQzVGLFlBQVksQ0FBQyxNQUFNO0lBQ25CLGdCQUFnQixHQUFHLElBQUksSUFBSSxXQUFXLEVBQUUsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDO0lBQzFELGdCQUFnQixJQUFJLENBQUMsR0FBRyxHQUFHLFdBQVcsR0FBRyxJQUFJLENBQUMsUUFBUSxHQUFHLFlBQVksR0FBRyxTQUFTLENBQUMsTUFBTTtJQUN4RixZQUFZOztJQUVaLFlBQVksSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxVQUFVLEVBQUU7SUFDaEQsWUFBWSxJQUFJLENBQUMsWUFBWSxDQUFDLGlCQUFpQixFQUFFLFdBQVcsQ0FBQzs7SUFFN0QsWUFBWSxlQUFlLEdBQUcsSUFBSSxDQUFDLEdBQUc7SUFDdEMsWUFBWSxXQUFXLEVBQUU7O0lBRXpCLFlBQVksSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsWUFBWSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hGLFFBQVE7O0lBRVIsUUFBUSxPQUFPLEdBQUc7SUFDbEIsSUFBSTtJQUNKOztJQzNjTyxTQUFTbEYsY0FBWSxDQUFDLENBQUMsRUFBRTtJQUNoQyxJQUFJLE1BQU0sRUFBRSxHQUFHLElBQUksT0FBTyxFQUFFO0lBQzVCLElBQUksRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ1osSUFBSSxFQUFFLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVTtJQUNwQyxJQUFJLEVBQUUsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVO0lBQ3BDLElBQUksRUFBRSxDQUFDLFFBQVEsR0FBRyxJQUFJO0lBQ3RCLElBQUksRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDO0lBQ2QsSUFBSSxPQUFPLEVBQUU7SUFDYjs7SUFZQSxNQUFNQyxXQUFTLEdBQUcsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ25DLE1BQU1DLFlBQVUsR0FBRyxJQUFJLFFBQVEsQ0FBQ0QsV0FBUyxDQUFDLE1BQU0sQ0FBQztJQUNqRCxNQUFNRSxXQUFTLEdBQUcsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ25DLE1BQU1DLFlBQVUsR0FBRyxJQUFJLFFBQVEsQ0FBQ0QsV0FBUyxDQUFDLE1BQU0sQ0FBQzs7SUFFakQsTUFBTSxPQUFPLENBQUM7O0lBRWQsSUFBSSxXQUFXLEdBQUc7SUFDbEIsUUFBUSxJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDaEMsSUFBSTs7SUFFSixJQUFJLGVBQWUsQ0FBQyxNQUFNLEVBQUU7SUFDNUIsUUFBUSxJQUFJLE1BQU0sR0FBRyxJQUFJLENBQUMsU0FBUyxFQUFFO0lBQ3JDLFlBQVksTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUc7SUFDekMsZ0JBQWdCLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUMxQyxnQkFBZ0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFHLEdBQUcsQ0FBQztJQUNoRCxnQkFBZ0I7SUFDaEIsYUFBYTtJQUNiLFlBQVksTUFBTSxPQUFPLEdBQUcsSUFBSSxVQUFVLENBQUMsWUFBWSxDQUFDO0lBQ3hELFlBQVksT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztJQUNwQyxZQUFZLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLE9BQU87SUFDakMsWUFBWSxJQUFJLENBQUMsU0FBUyxHQUFHLFlBQVk7SUFDekMsUUFBUTtJQUNSLElBQUk7O0lBRUosSUFBSSxNQUFNLEtBQUssQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFO0lBQzNCLFFBQVEsTUFBTSxJQUFJLEVBQUUsSUFBSTtJQUN4QixRQUFRLElBQUksT0FBTyxHQUFHLElBQUksV0FBVyxFQUFFLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRztJQUNyRCxRQUFRLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDOztJQUV0RSxRQUFRLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUM7O0lBRW5ELFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxHQUFHLENBQUM7O0lBRTFDLFFBQVEsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxVQUFVOztJQUUxRixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxVQUFVO0lBQ3hDLElBQUk7O0lBRUosSUFBSSxNQUFNLFlBQVksQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUU7SUFDbkQsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJO0lBQ3pCLFFBQVEsSUFBSSxPQUFPLEdBQUcsSUFBSSxXQUFXLEVBQUUsR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHO0lBQ3JELFFBQVEsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFO0lBQzNCLFlBQVksSUFBSSxHQUFHLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQztJQUNwRixRQUFRO0lBQ1IsUUFBUSxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7O0lBRXZDLFFBQVEsTUFBTSxPQUFPLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxHQUFHLEVBQUUsR0FBRyxDQUFDOztJQUU3RixRQUFRLFFBQVEsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQzs7SUFFckMsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsR0FBRyxHQUFHO0lBQzVCLElBQUk7O0lBRUosSUFBSSxNQUFNLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO0lBQ3pCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTs7SUFFekIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsQ0FBQyxHQUFHLENBQUM7SUFDeEMsUUFBUSxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDOztJQUVsRCxRQUFRLE9BQU8sSUFBSTtJQUNuQixJQUFJOztJQUVKLElBQUksS0FBSyxHQUFHO0lBQ1osUUFBUSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFO0lBQ3RELFlBQVksSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDO0lBQzlELFFBQVE7SUFDUixJQUFJOztJQUVKLElBQUksTUFBTSxPQUFPLEdBQUc7SUFDcEIsSUFBSTs7O0lBR0osSUFBSSxNQUFNLFVBQVUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBQzdCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTs7SUFFekIsUUFBUUQsWUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQzs7SUFFeEMsUUFBUSxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUNELFdBQVMsRUFBRSxHQUFHLENBQUM7SUFDeEMsSUFBSTs7SUFFSixJQUFJLE1BQU0sVUFBVSxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDN0IsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJOztJQUV6QixRQUFRQyxZQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDOztJQUV6QyxRQUFRLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQ0QsV0FBUyxFQUFFLEdBQUcsQ0FBQztJQUN4QyxJQUFJOzs7SUFHSixJQUFJLE1BQU0sVUFBVSxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDN0IsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJOztJQUV6QixRQUFRRyxZQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsVUFBVSxFQUFFLElBQUksQ0FBQztJQUNyRCxRQUFRQSxZQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxXQUFXLENBQUMsR0FBRyxJQUFJLENBQUM7O0lBRW5FLFFBQVEsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDRCxXQUFTLEVBQUUsR0FBRyxDQUFDO0lBQ3hDLElBQUk7OztJQUdKLElBQUksTUFBTSxTQUFTLENBQUMsR0FBRyxFQUFFO0lBQ3pCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTtJQUN6QixRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDOztJQUV6QyxRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUksV0FBVyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7O0lBRTlDLFFBQVEsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3RCLElBQUk7O0lBRUosSUFBSSxNQUFNLFNBQVMsQ0FBQyxHQUFHLEVBQUU7SUFDekIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJO0lBQ3pCLFFBQVEsTUFBTSxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7O0lBRXpDLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSSxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQzs7SUFFM0MsUUFBUSxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQztJQUN2QyxJQUFJOztJQUVKLElBQUksTUFBTSxTQUFTLENBQUMsR0FBRyxFQUFFO0lBQ3pCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTtJQUN6QixRQUFRLE1BQU0sQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDOztJQUV6QyxRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUksV0FBVyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7O0lBRTlDLFFBQVEsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDOUMsSUFBSTs7SUFFSixJQUFJLE1BQU0sVUFBVSxDQUFDLEdBQUcsRUFBRTtJQUMxQixRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7O0lBRXpCLFFBQVEsSUFBSSxlQUFlLEdBQUcsT0FBTyxHQUFHLElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRzs7SUFFeEUsUUFBUSxJQUFJLGVBQWUsR0FBRyxJQUFJLENBQUMsU0FBUyxFQUFFO0lBQzlDLFlBQVksSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFO0lBQy9CLGdCQUFnQixNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixDQUFDO0lBQ3hELFlBQVk7SUFDWixZQUFZLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDO0lBQ3JDLFFBQVE7SUFDUixRQUFRLE1BQU0sU0FBUyxHQUFHLElBQUksVUFBVTtJQUN4QyxZQUFZLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU07SUFDOUIsWUFBWSxlQUFlO0lBQzNCLFlBQVksSUFBSSxDQUFDLFNBQVMsR0FBRztJQUM3QixTQUFTOztJQUVULFFBQVEsSUFBSSxnQkFBZ0IsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLE9BQU8sSUFBSSxPQUFPLEtBQUssQ0FBQyxDQUFDO0lBQzVFLFFBQVEsSUFBSSxnQkFBZ0IsR0FBRyxnQkFBZ0IsS0FBSyxFQUFFOztJQUV0RCxRQUFRLElBQUksR0FBRyxHQUFHLEVBQUU7SUFDcEIsUUFBUSxJQUFJLGdCQUFnQixFQUFFO0lBQzlCLFlBQVksR0FBRyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLGdCQUFnQixDQUFDLENBQUM7SUFDaEYsWUFBWSxJQUFJLENBQUMsR0FBRyxHQUFHLGVBQWUsR0FBRyxnQkFBZ0IsR0FBRyxDQUFDO0lBQzdELFFBQVEsQ0FBQyxNQUFNO0lBQ2YsWUFBWSxJQUFJLENBQUMsR0FBRyxHQUFHLGVBQWU7SUFDdEMsUUFBUTtJQUNSLFFBQVEsT0FBTyxHQUFHO0lBQ2xCLElBQUk7SUFDSjs7SUM1TEEsTUFBTSxTQUFTLEdBQUcsQ0FBQyxFQUFFLEVBQUU7O0lBa0JoQixTQUFTSCxjQUFZLENBQUMsQ0FBQyxFQUFFO0lBQ2hDLElBQUksTUFBTSxFQUFFLEdBQUcsSUFBSSxVQUFVLEVBQUU7SUFDL0IsSUFBSSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUM7SUFDWixJQUFJLEVBQUUsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsU0FBUyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVTtJQUNwRixJQUFJLEVBQUUsQ0FBQyxRQUFRLEdBQUcsSUFBSTtJQUN0QixJQUFJLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUNkLElBQUksT0FBTyxFQUFFO0lBQ2I7O0lBV0EsTUFBTSxTQUFTLEdBQUcsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ25DLE1BQU0sVUFBVSxHQUFHLElBQUksUUFBUSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDakQsTUFBTSxTQUFTLEdBQUcsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ25DLE1BQU0sVUFBVSxHQUFHLElBQUksUUFBUSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7O0lBRWpELE1BQU0sVUFBVSxDQUFDOztJQUVqQixJQUFJLFdBQVcsR0FBRztJQUNsQixRQUFRLElBQUksQ0FBQyxRQUFRLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNoQyxJQUFJOztJQUVKLElBQUksZUFBZSxDQUFDLE1BQU0sRUFBRTs7SUFFNUIsUUFBUSxJQUFJLE1BQU0sSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFOztJQUV0QyxRQUFRLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDOztJQUV4RSxRQUFRLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDN0QsUUFBUSxLQUFLLElBQUksQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3RFLFlBQVksTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsU0FBUyxHQUFHLE1BQU0sR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsU0FBUztJQUNsRixZQUFZLE1BQU0sQ0FBQyxHQUFHLElBQUksVUFBVSxDQUFDLE9BQU8sQ0FBQztJQUM3QyxZQUFZLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNoRSxZQUFZLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7SUFDOUIsUUFBUTtJQUNSLFFBQVEsSUFBSSxDQUFDLFNBQVMsR0FBRyxNQUFNO0lBQy9CLElBQUk7O0lBRUosSUFBSSxNQUFNLEtBQUssQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFO0lBQzNCLFFBQVEsTUFBTSxJQUFJLEVBQUUsSUFBSTtJQUN4QixRQUFRLElBQUksT0FBTyxHQUFHLElBQUksV0FBVyxFQUFFLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRztJQUNyRCxRQUFRLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDOztJQUV0RSxRQUFRLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUM7O0lBRW5ELFFBQVEsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEdBQUcsU0FBUyxDQUFDOztJQUVyRCxRQUFRLElBQUksQ0FBQyxHQUFHLFNBQVM7SUFDekIsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsU0FBUztJQUMvQixRQUFRLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxVQUFVO0lBQy9CLFFBQVEsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFO0lBQ3BCLFlBQVksTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLFNBQVMsS0FBSyxTQUFTLEVBQUUsQ0FBQyxJQUFJLENBQUM7SUFDNUQsWUFBWSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNwRixZQUFZLE1BQU0sT0FBTyxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZFLFlBQVksT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUM7SUFDaEMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDbkIsWUFBWSxDQUFDLEdBQUc7SUFDaEIsWUFBWSxDQUFDLEdBQUcsQ0FBQztJQUNqQixRQUFROztJQUVSLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDLFVBQVU7SUFDeEMsSUFBSTs7SUFFSixJQUFJLE1BQU0sWUFBWSxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRTtJQUNsRCxRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7SUFDekIsUUFBUSxJQUFJLE9BQU8sR0FBRyxJQUFJLFdBQVcsRUFBRSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUc7SUFDckQsUUFBUSxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7SUFDM0IsWUFBWSxJQUFJLEdBQUcsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixDQUFDO0lBQ3BGLFFBQVE7SUFDUixRQUFRLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQzs7SUFFdkMsUUFBUSxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBRyxTQUFTLENBQUM7O0lBRXJELFFBQVEsSUFBSSxDQUFDLEdBQUcsU0FBUztJQUN6QixRQUFRLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxTQUFTO0lBQy9CO0lBQ0EsUUFBUSxJQUFJLENBQUMsR0FBRyxHQUFHO0lBQ25CLFFBQVEsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFO0lBQ3BCO0lBQ0EsWUFBWSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsU0FBUyxLQUFLLFNBQVMsRUFBRSxDQUFDLElBQUksQ0FBQztJQUM1RCxZQUFZLE1BQU0sT0FBTyxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZFLFlBQVksT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDOUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDbkIsWUFBWSxDQUFDLEdBQUc7SUFDaEIsWUFBWSxDQUFDLEdBQUcsQ0FBQztJQUNqQixRQUFROztJQUVSLFFBQVEsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLEdBQUcsR0FBRztJQUM1QixJQUFJOztJQUVKLElBQUksTUFBTSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRTtJQUN6QixRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7SUFDekIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsQ0FBQyxHQUFHLENBQUM7O0lBRXhDLFFBQVEsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQzs7SUFFbEQsUUFBUSxPQUFPLElBQUk7SUFDbkIsSUFBSTs7SUFFSixJQUFJLEtBQUssR0FBRztJQUNaLElBQUk7O0lBRUosSUFBSSxNQUFNLE9BQU8sR0FBRztJQUNwQixJQUFJOzs7SUFHSixJQUFJLE1BQU0sVUFBVSxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDN0IsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJOztJQUV6QixRQUFRLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUM7O0lBRXhDLFFBQVEsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUM7SUFDeEMsSUFBSTs7SUFFSixJQUFJLE1BQU0sVUFBVSxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDN0IsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJOztJQUV6QixRQUFRLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLENBQUM7O0lBRXpDLFFBQVEsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUM7SUFDeEMsSUFBSTs7O0lBR0osSUFBSSxNQUFNLFVBQVUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBQzdCLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSTs7SUFFekIsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsVUFBVSxFQUFFLElBQUksQ0FBQztJQUNyRCxRQUFRLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxHQUFHLElBQUksQ0FBQzs7SUFFbkUsUUFBUSxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQztJQUN4QyxJQUFJOzs7SUFHSixJQUFJLE1BQU0sU0FBUyxDQUFDLEdBQUcsRUFBRTtJQUN6QixRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUk7SUFDekIsUUFBUSxNQUFNLENBQUMsR0FBRyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQzs7SUFFekMsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJLFdBQVcsQ0FBQyxDQUFD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QUFNLFdBQVcsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUUsSUFBSSxNQUFNLFVBQVUsR0FBRyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQztJQUMzRCxJQUFJLEtBQUssR0FBRyxJQUFJLFVBQVUsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztJQUNyRCxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDMUIsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUM7SUFDaEYsSUFBSSxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNELElBQUksTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3RCxJQUFJLEtBQUssR0FBRyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsTUFBTSxDQUFDO0lBQzFGLElBQUksS0FBSyxHQUFHLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDO0lBQ3BFLElBQUksTUFBTWpELGlCQUE4QixDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7SUFD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Q0FBQzs7SUFFbEUsSUFBSSxNQUFNLFdBQVcsQ0FBQyxLQUFLLEVBQUU7SUFDN0IsSUFBSSxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUU7SUFDM0IsSUFBSSxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUU7O0lBRTNCLElBQUksT0FBTyxJQUFJOztJQUVmLElBQUksZUFBZSxNQUFNLENBQUMsRUFBRSxFQUFFO0lBQzlCLFFBQVEsTUFBTSxJQUFJLEdBQUcsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDbkQsUUFBUSxPQUFPLEtBQUssQ0FBQyxFQUFFLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNwRCxJQUFJOztJQUVKLElBQUksZUFBZSxNQUFNLENBQUMsRUFBRSxFQUFFO0lBQzlCLFFBQVEsTUFBTSxJQUFJLEdBQUcsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDbkQsUUFBUSxPQUFPLEtBQUssQ0FBQyxFQUFFLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNwRCxJQUFJOzs7SUFHSixJQUFJLFNBQVMsbUJBQW1CLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRTtJQUN6QyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsVUFBVSxLQUFLLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxPQUFPLEtBQUs7SUFDdkUsUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEtBQUs7SUFDdkUsUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRSxPQUFPLEtBQUs7SUFDeEUsUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxPQUFPLEtBQUs7SUFDekUsUUFBUSxJQUFJLENBQUN6QixXQUFnQixDQUFDLEVBQUUsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLE9BQU8sS0FBSztJQUN6RSxRQUFRLE9BQU8sSUFBSTtJQUNuQixJQUFJOzs7SUFHSjs7SUMzTkE7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7O0lBUUEsTUFBTSxTQUFTLEdBQUdLLFdBQWM7Ozs7SUFNakIsZUFBZSxvQkFBb0IsQ0FBQyxZQUFZLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUU7O0lBRXJHLElBQUksSUFBSSxFQUFFO0lBQ1YsSUFBSSxNQUFNLENBQUMsRUFBRSxFQUFFLFFBQVEsQ0FBQyxHQUFHLE1BQU0vQixhQUF3QixDQUFDLFlBQVksRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ2xGLElBQUksTUFBTSxJQUFJLEdBQUcsTUFBTUssWUFBb0IsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQztJQUNoRSxJQUFJLElBQUksSUFBSSxDQUFDLFFBQVEsSUFBSSxTQUFTLEVBQUU7SUFDcEMsUUFBUSxNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDO0lBQ25ELElBQUk7O0lBRUosSUFBSSxNQUFNLEtBQUssR0FBRyxNQUFNWCxhQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUN4QyxJQUFJLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDOztJQUUvQixJQUFJLE1BQU0sU0FBUyxHQUFHLE1BQU11RCxhQUF1QixDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDOztJQUV4RSxJQUFJLE1BQU0saUJBQWlCLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUMzRCxJQUFJLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO0lBQzlDLElBQUksSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzdCLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3pELFFBQVEsTUFBTSxDQUFDLEdBQUcsU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7SUFDNUMsUUFBUSxNQUFNLFNBQVMsR0FBR0csV0FBZ0IsQ0FBQyxpQkFBaUIsQ0FBQzs7SUFFN0QsUUFBUSxNQUFNLENBQUMsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztJQUM5QyxRQUFRLE1BQU0sQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDOztJQUUvQyxRQUFRLElBQUksQ0FBQzFCLFdBQWdCLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxVQUFVLENBQUMsRUFBRTtJQUNqRSxZQUFZLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLDJCQUEyQixDQUFDLENBQUM7SUFDbEUsWUFBWSxPQUFPLEtBQUs7SUFDeEIsUUFBUTs7SUFFUixRQUFRLE1BQU0sV0FBVyxHQUFHLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLFVBQVUsQ0FBQzs7SUFFekQsUUFBUSxFQUFFLEdBQUcsTUFBTSxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUM3RixRQUFRLElBQUksRUFBRSxLQUFLLElBQUksRUFBRTtJQUN6QixZQUFZLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLG9EQUFvRCxDQUFDLENBQUM7SUFDM0YsWUFBWSxPQUFPLEtBQUs7SUFDeEIsUUFBUTs7SUFFUixRQUFRLEVBQUUsR0FBRyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQyxVQUFVLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQ3hGLFFBQVEsSUFBSSxFQUFFLEtBQUssSUFBSSxFQUFFO0lBQ3pCLFlBQVksT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsNkNBQTZDLENBQUMsQ0FBQztJQUNwRixZQUFZLE9BQU8sS0FBSztJQUN4QixRQUFROztJQUVSLFFBQVEsSUFBSSxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsRUFBRTtJQUN6QixZQUFZLE1BQU0sR0FBRyxHQUFHLE1BQU1SLG1CQUF3QixDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLGdCQUFnQixDQUFDO0lBQ3hGLFlBQVksTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDO0lBQ3pELFlBQVksTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDMUUsWUFBWSxNQUFNLGNBQWMsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFDdEcsWUFBWSxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLGFBQWEsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksRUFBRTtJQUNuRSxnQkFBZ0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsMENBQTBDLENBQUMsQ0FBQztJQUNyRixnQkFBZ0IsT0FBTyxLQUFLO0lBQzVCLFlBQVk7SUFDWixZQUFZLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssSUFBSSxFQUFFO0lBQ3JFLGdCQUFnQixPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQywyQ0FBMkMsQ0FBQyxDQUFDO0lBQ3RGLGdCQUFnQixPQUFPLEtBQUs7SUFDNUIsWUFBWTtJQUNaLFFBQVE7O0lBRVIsUUFBUSxVQUFVLENBQUMsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzs7SUFFL0MsUUFBUSxNQUFNLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDaEUsUUFBUSxVQUFVLENBQUMsa0JBQWtCLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzs7SUFFaEQsUUFBUSxDQUFDLENBQUMsZ0JBQWdCLEdBQUcsa0JBQWtCLENBQUMsTUFBTSxFQUFFOztJQUV4RCxRQUFRLFFBQVEsR0FBRyxDQUFDLENBQUMsVUFBVTtJQUMvQixJQUFJOzs7SUFHSixJQUFJLE1BQU0sQ0FBQyxFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxZQUFZLENBQUMsR0FBRyxNQUFNbEIsYUFBd0IsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUN4RyxJQUFJLE1BQU0sUUFBUSxHQUFHLE1BQU1LLFlBQW9CLENBQUMsTUFBTSxFQUFFLFlBQVksRUFBRSxLQUFLLENBQUM7O0lBRTVFLElBQUksSUFBSSxRQUFRLENBQUMsUUFBUSxJQUFJLFNBQVMsRUFBRTtJQUN4QyxRQUFRLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUM7SUFDdkQsSUFBSTs7SUFFSixJQUFJLE1BQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFdBQVcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUN6QyxXQUFXLFFBQVEsQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLEdBQUc7SUFDbkMsV0FBVyxRQUFRLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDcEMsSUFBSTtJQUNKLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQztJQUM5RCxRQUFRLE9BQU8sS0FBSztJQUNwQixJQUFJOztJQUVKLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLElBQUksSUFBSSxDQUFDLEtBQUs7SUFDdkMsV0FBVyxRQUFRLENBQUMsT0FBTyxLQUFLLElBQUksQ0FBQyxPQUFPO0lBQzVDLFdBQVcsUUFBUSxDQUFDLFVBQVUsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ2xELElBQUk7SUFDSixRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsd0NBQXdDLENBQUM7SUFDMUUsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTs7SUFFSixJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRTtJQUM1RCxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLENBQUM7SUFDNUQsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTtJQUNKLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFO0lBQzFELFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQztJQUMzRCxRQUFRLE9BQU8sS0FBSztJQUNwQixJQUFJO0lBQ0osSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsU0FBUyxDQUFDLEVBQUU7SUFDMUQsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLHlCQUF5QixDQUFDO0lBQzNELFFBQVEsT0FBTyxLQUFLO0lBQ3BCLElBQUk7SUFDSixJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRTtJQUM1RCxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLENBQUM7SUFDNUQsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTtJQUNKLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDLEVBQUU7SUFDakQsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLDBCQUEwQixDQUFDO0lBQzVELFFBQVEsT0FBTyxLQUFLO0lBQ3BCLElBQUk7SUFDSixJQUFJLEVBQUUsR0FBRyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDbEYsSUFBSSxJQUFJLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDckIsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLDBCQUEwQixDQUFDO0lBQzVELFFBQVEsT0FBTyxLQUFLO0lBQ3BCLElBQUk7O0lBRUosSUFBSSxNQUFNLGFBQWEsR0FBRyxNQUFNNEMsYUFBdUIsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLFlBQVksQ0FBQztJQUNwRixJQUFJLElBQUksQ0FBQ3ZCLFdBQWdCLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxhQUFhLENBQUMsTUFBTSxDQUFDLEVBQUU7SUFDbkUsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxDQUFDO0lBQ3BFLFFBQVEsT0FBTyxLQUFLO0lBQ3BCLElBQUk7O0lBRUo7SUFDQSxJQUFJLElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxHQUFHLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFO0lBQ2hFLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQztJQUNwRSxRQUFRLE9BQU8sS0FBSztJQUNwQixJQUFJOztJQUVKLElBQUksSUFBSSxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLEdBQUcsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUU7SUFDdEQsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxDQUFDO0lBQ3BFLFFBQVEsT0FBTyxLQUFLO0lBQ3BCLElBQUk7O0lBRUosSUFBSSxJQUFJLEVBQUU7SUFDVixJQUFJLEVBQUUsR0FBRyxNQUFNMkIsY0FBMkIsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDO0lBQ2pGLElBQUksSUFBSSxDQUFDLEVBQUUsRUFBRTtJQUNiLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyx1Q0FBdUMsQ0FBQztJQUN6RSxRQUFRLE9BQU8sS0FBSztJQUNwQixJQUFJOztJQUVKLElBQUksRUFBRSxHQUFHLE1BQU1BLGNBQTJCLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLENBQUMsQ0FBQztJQUNqRixJQUFJLElBQUksQ0FBQyxFQUFFLEVBQUU7SUFDYixRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsaUNBQWlDLENBQUM7SUFDbkUsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTs7SUFFSixJQUFJLEVBQUUsR0FBRyxNQUFNQSxjQUEyQixDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUM7SUFDakYsSUFBSSxJQUFJLENBQUMsRUFBRSxFQUFFO0lBQ2IsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLDRCQUE0QixDQUFDO0lBQzlELFFBQVEsT0FBTyxLQUFLO0lBQ3BCLElBQUk7O0lBRUosSUFBSSxFQUFFLEdBQUcsTUFBTUEsY0FBMkIsQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDO0lBQ2pGLElBQUksSUFBSSxDQUFDLEVBQUUsRUFBRTtJQUNiLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQztJQUMvRCxRQUFRLE9BQU8sS0FBSztJQUNwQixJQUFJOztJQUVKLElBQUksRUFBRSxHQUFHLE1BQU1BLGNBQTJCLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLENBQUMsQ0FBQztJQUNqRixJQUFJLElBQUksQ0FBQyxFQUFFLEVBQUU7SUFDYixRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsNkJBQTZCLENBQUM7SUFDL0QsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTs7SUFFSjtJQUNBLElBQUksRUFBRSxHQUFHLE1BQU0sbUJBQW1CLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsVUFBVSxFQUFFLFdBQVcsQ0FBQztJQUNsSSxJQUFJLElBQUksRUFBRSxHQUFHLElBQUksRUFBRTtJQUNuQixRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLENBQUM7SUFDNUQsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTs7SUFFSjtJQUNBLElBQUksRUFBRSxHQUFHLE1BQU0sVUFBVSxFQUFFO0lBQzNCLElBQUksSUFBSSxFQUFFLEdBQUcsSUFBSSxFQUFFO0lBQ25CLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQywwQkFBMEIsQ0FBQztJQUM1RCxRQUFRLE9BQU8sS0FBSztJQUNwQixJQUFJOztJQUVKLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQy9CLFVBQWUsQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLGdCQUFnQixDQUFDLENBQUM7O0lBRWhGLElBQUksTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFO0lBQ3BCLElBQUksTUFBTSxNQUFNLENBQUMsS0FBSyxFQUFFOztJQUV4QixJQUFJLEtBQUssSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDNUQsUUFBUSxNQUFNLENBQUMsR0FBRyxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUM1QyxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsMkJBQTJCLENBQUM7SUFDNUQsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDQSxVQUFlLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixFQUFFLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNySCxRQUFRLElBQUksQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLEVBQUU7SUFDekIsWUFBWSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsa0JBQWtCLEVBQUVhLGFBQWtCLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM1RixZQUFZLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyx1QkFBdUIsRUFBRSxDQUFDLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDO0lBQ25GLFFBQVE7SUFDUixJQUFJO0lBQ0osSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLDJCQUEyQixDQUFDOztJQUV4RCxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDOztJQUV2QyxJQUFJLE9BQU8sSUFBSTs7O0lBR2YsSUFBSSxlQUFlLG1CQUFtQixDQUFDLFNBQVMsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFO0lBQ3ZILFFBQVEsTUFBTSxjQUFjLEdBQUcsQ0FBQyxFQUFFLEVBQUU7SUFDcEMsUUFBUSxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDO0lBQ2xDLFFBQVEsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMzQixRQUFRLE1BQU10Qyx3QkFBbUMsQ0FBQyxHQUFHLEVBQUUsU0FBUyxFQUFFLFNBQVMsQ0FBQztJQUM1RSxRQUFRLE1BQU1BLHdCQUFtQyxDQUFDLEdBQUcsRUFBRSxTQUFTLEVBQUUsU0FBUyxDQUFDOztJQUU1RSxRQUFRLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQyxJQUFJO0lBQ3ZCLFFBQVEsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLElBQUk7O0lBRXZCLFFBQVEsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxFQUFFOztJQUV6RCxRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxJQUFJLGNBQWMsRUFBRTtJQUN0RCxZQUFZLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxpQkFBaUIsRUFBRSxXQUFXLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUN6RixZQUFZLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxHQUFHLENBQUMsRUFBRSxjQUFjLENBQUM7SUFDM0QsWUFBWSxNQUFNLE1BQU0sR0FBRyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUMvQyxZQUFZLE1BQU0sTUFBTSxHQUFHLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDOztJQUUvQyxZQUFZLE1BQU0sT0FBTyxHQUFHdUMsY0FBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOztJQUVwRCxZQUFZLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDO0lBQzlELFlBQVksTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUM7O0lBRTlELFlBQVksRUFBRSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUM5QixZQUFZLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDOUIsUUFBUTtJQUNSLFFBQVEsTUFBTXRDLGdCQUEyQixDQUFDLEdBQUcsQ0FBQztJQUM5QyxRQUFRLE1BQU1BLGdCQUEyQixDQUFDLEdBQUcsQ0FBQzs7SUFFOUMsUUFBUSxJQUFJLE9BQU8sSUFBSSxDQUFDLEVBQUUsT0FBTyxJQUFJOztJQUVyQyxRQUFRLEVBQUUsR0FBRyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDO0lBQ3hELFFBQVEsSUFBSSxFQUFFLEtBQUssSUFBSSxFQUFFLE9BQU8sS0FBSzs7SUFFckMsUUFBUSxPQUFPLElBQUk7SUFDbkIsSUFBSTs7SUFFSixJQUFJLGVBQWUsVUFBVSxHQUFHO0lBQ2hDLFFBQVEsTUFBTSxjQUFjLEdBQUcsQ0FBQyxFQUFFLEVBQUU7SUFDcEMsUUFBUSxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsRUFBRTtJQUMxQixRQUFRLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFO0lBQzNCLFFBQVEsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQzs7SUFFM0IsUUFBUSxNQUFNLENBQUMsRUFBRSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsWUFBWSxDQUFDLEdBQUcsTUFBTUUsYUFBd0IsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQzs7SUFFNUcsUUFBUSxJQUFJLE1BQU0sR0FBRyxJQUFJLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUM7O0lBRTlELFFBQVEsTUFBTSxJQUFJLEVBQUUsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ2hDLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNoQyxZQUFZLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBR3FDLFlBQWlCLENBQUNELGNBQW1CLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2xFLFFBQVE7SUFDUixRQUFRLE1BQU0sR0FBRyxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQztJQUNwQyxRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNoRCxZQUFZLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDO0lBQ3JDLFlBQVksRUFBRSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQzdDLFFBQVE7SUFDUixRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDOztJQUVqRSxRQUFRLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQyxJQUFJO0lBQ3ZCLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxJQUFJLGNBQWMsRUFBRTtJQUM5RCxZQUFZLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxzQkFBc0IsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ3JGLFlBQVksTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsRUFBRSxjQUFjLENBQUM7O0lBRW5FLFlBQVksTUFBTSxLQUFLLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ25HLFlBQVksTUFBTSxLQUFLLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDOztJQUU5RSxZQUFZLE1BQU0sS0FBSyxHQUFHLE1BQU0sYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUM7SUFDM0QsWUFBWSxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ2xFLFlBQVksTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUM7O0lBRTFELFlBQVksRUFBRSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM3QixRQUFROztJQUVSOztJQUVBLFFBQVEsTUFBTSxHQUFHLE1BQU0sRUFBRSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQztJQUNuRDtJQUNBOzs7SUFHQSxRQUFRLElBQUksS0FBSzs7SUFFakIsUUFBUSxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDLENBQUMsRUFBRTtJQUMvQixZQUFZLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkMsUUFBUSxDQUFDLE1BQU07SUFDZixZQUFZLE1BQU0sT0FBTyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN0QyxZQUFZLE1BQU0sZ0JBQWdCLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQztJQUM5RCxZQUFZLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRyxFQUFFLGdCQUFnQixFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUM7SUFDckQsUUFBUTs7SUFFUjtJQUNBLFFBQVEsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsS0FBSztJQUNyRSxRQUFRLE1BQU0sR0FBRyxNQUFNLEVBQUUsQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUM7SUFDM0QsUUFBUSxNQUFNLEdBQUcsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUNyQyxRQUFRLE1BQU0sR0FBRyxNQUFNLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUM7O0lBRXJELFFBQVEsTUFBTXZDLHdCQUFtQyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ2xFLFFBQVEsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLElBQUk7SUFDdkIsUUFBUSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLElBQUksY0FBYyxFQUFFO0lBQzlELFlBQVksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLDJCQUEyQixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDMUYsWUFBWSxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxFQUFFLGNBQWMsQ0FBQzs7SUFFbkUsWUFBWSxNQUFNLElBQUksR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUM1QyxZQUFZLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDbEUsWUFBWSxNQUFNLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQzs7SUFFekQsWUFBWSxFQUFFLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzdCLFFBQVE7SUFDUixRQUFRLE1BQU1DLGdCQUEyQixDQUFDLEVBQUUsQ0FBQzs7SUFFN0MsUUFBUSxFQUFFLEdBQUcsTUFBTSxTQUFTLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsVUFBVSxDQUFDO0lBQ2pGLFFBQVEsSUFBSSxFQUFFLEtBQUssSUFBSSxFQUFFLE9BQU8sS0FBSzs7O0lBR3JDLFFBQVEsT0FBTyxJQUFJOztJQUVuQixJQUFJOztJQUVKLElBQUksZUFBZSxhQUFhLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRTtJQUMvQyxRQUFRLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2xDLFFBQVEsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLFVBQVUsR0FBRyxFQUFFO0lBQzdDLFFBQVEsTUFBTSxXQUFXLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxXQUFXO0lBQy9DLFFBQVEsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxXQUFXLENBQUM7SUFDbEUsUUFBUSxNQUFNLFVBQVUsR0FBRyxFQUFFO0lBQzdCLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUMxQyxZQUFZLElBQUksQ0FBQztJQUNqQixZQUFZLElBQUksQ0FBQyxFQUFFLFdBQVcsQ0FBQyxDQUFDLEVBQUU7SUFDbEMsZ0JBQWdCLENBQUMsR0FBRyxnQkFBZ0I7SUFDcEMsWUFBWSxDQUFDLE1BQU07SUFDbkIsZ0JBQWdCLENBQUMsR0FBRyxPQUFPLEdBQUcsQ0FBQyxDQUFDLGdCQUFnQjtJQUNoRCxZQUFZO0lBQ1osWUFBWSxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUU7O0lBRXRCLFlBQVksTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7SUFDNUYsWUFBWSxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQztJQUM1RixZQUFZLFVBQVUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3BFLFFBQVE7OztJQUdSLFFBQVEsTUFBTSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQzs7SUFFcEQsUUFBUSxNQUFNLFdBQVcsR0FBRyxJQUFJLFVBQVUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO0lBQ3RELFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUNoQixRQUFRLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzVDLFlBQVksV0FBVyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzVDLFlBQVksQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVO0lBQ3RDLFFBQVE7O0lBRVIsUUFBUSxPQUFPLFdBQVc7SUFDMUIsSUFBSTs7O0lBR0osSUFBSSxlQUFlLG1CQUFtQixDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUU7SUFDckQsUUFBUSxNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNuQyxRQUFRLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3JDLFFBQVEsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHO0lBQzVDLFFBQVEsTUFBTSxJQUFJLEdBQUcsRUFBRTtJQUN2QixRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ3pELFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDekQsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDN0QsUUFBUSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3RDLFlBQVksSUFBSSxDQUFDLElBQUksQ0FBQztJQUN0QixnQkFBZ0IsR0FBRyxFQUFFLE1BQU07SUFDM0IsZ0JBQWdCLE1BQU0sRUFBRSxlQUFlO0lBQ3ZDLGdCQUFnQixNQUFNLEVBQUU7SUFDeEIsb0JBQW9CLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQztJQUMzQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQzNDLG9CQUFvQixDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFDN0M7SUFDQSxhQUFhLENBQUM7SUFDZCxRQUFRO0lBQ1IsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxFQUFFO0lBQ3JFLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ3BCLFlBQVksQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDO0lBQzFCLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ3BCLFNBQVMsQ0FBQyxDQUFDO0lBQ1gsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQzs7SUFFakUsUUFBUSxNQUFNLEdBQUcsR0FBRyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQzs7SUFFcEQsUUFBUSxPQUFPLEdBQUc7SUFDbEIsSUFBSTs7SUFFSjs7SUNoYUE7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7OztJQUtlLGVBQWUsb0JBQW9CLENBQUMsWUFBWSxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFOztJQUVyRztJQUNBLElBQUksTUFBTSxZQUFZLEdBQUcsQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDO0lBQ3pDLElBQUksTUFBTSxPQUFPLENBQUMsWUFBWSxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsTUFBTSxDQUFDOztJQUVuRSxJQUFJLE9BQU8sTUFBTSxvQkFBb0IsQ0FBQyxZQUFZLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxNQUFNLENBQUM7SUFDdkY7O0lDN0JBO0lBQ0E7O0lBRUE7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBOzs7SUFXZSxlQUFlLGdCQUFnQixDQUFDLFdBQVcsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUU7O0lBRWhHLElBQUksTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxHQUFHLE1BQU1FLGFBQXdCLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDbEcsSUFBSSxNQUFNLElBQUksR0FBRyxNQUFNSyxZQUFvQixDQUFDLEtBQUssRUFBRSxRQUFRLENBQUM7SUFDNUQsSUFBSSxJQUFJLElBQUksQ0FBQyxRQUFRLElBQUksU0FBUyxFQUFFO0lBQ3BDLFFBQVEsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQztJQUNuRCxJQUFJOztJQUVKLElBQUksTUFBTSxLQUFLLEdBQUcsTUFBTVgsYUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7O0lBRXhDLElBQUksTUFBTSxTQUFTLEdBQUcsTUFBTXVELGFBQXVCLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxRQUFRLENBQUM7O0lBRTNFLElBQUksTUFBTSxLQUFLLEdBQUcsTUFBTXpDLGFBQTBCLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDOzs7SUFHOUUsSUFBSSxNQUFNLEdBQUcsR0FBRyxNQUFNOEIsWUFBaUIsQ0FBQyxPQUFPLENBQUM7O0lBRWhELElBQUksTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBQzFELElBQUksZ0JBQWdCLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDN0MsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDekQsUUFBUWdCLFVBQWdCLENBQUMsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDN0UsSUFBSTs7SUFFSixJQUFJLE1BQU0sZUFBZSxHQUFHLEVBQUU7SUFDOUIsSUFBSSxlQUFlLENBQUMsS0FBSyxHQUFHLEVBQUU7SUFDOUIsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUM7SUFDeEQsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN6RSxJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDL0gsSUFBSUMsTUFBWSxDQUFDLGdCQUFnQixFQUFFLEtBQUssRUFBRSxlQUFlLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztJQUNyRSxJQUFJQSxNQUFZLENBQUMsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQ3RFLElBQUksZUFBZSxDQUFDLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQyxNQUFNLEVBQUU7SUFDMUQsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxFQUFFLGVBQWUsQ0FBQyxVQUFVLENBQUM7SUFDN0UsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxlQUFlLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDOztJQUVqSSxJQUFJLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxlQUFlLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUNyRixJQUFJLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxlQUFlLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQzs7SUFFckYsSUFBSSxlQUFlLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxVQUFVOztJQUVoRCxJQUFJLGVBQWUsQ0FBQyxJQUFJLEdBQUcsQ0FBQztJQUM1QixJQUFJLElBQUksSUFBSSxFQUFFLGVBQWUsQ0FBQyxJQUFJLEdBQUcsSUFBSTs7SUFFekMsSUFBSSxTQUFTLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUM7O0lBRWpELElBQUksTUFBTUwsV0FBcUIsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDOztJQUU1QztJQUNBLElBQUksTUFBTVQsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7O0lBRTdEO0lBQ0EsSUFBSSxNQUFNQSxXQUF3QixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzs7SUFFN0Q7SUFDQSxJQUFJLE1BQU1BLFdBQXdCLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDOztJQUU3RDtJQUNBLElBQUksTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7O0lBRTdEO0lBQ0EsSUFBSSxNQUFNQSxXQUF3QixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzs7SUFFN0QsSUFBSSxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUMvRCxJQUFJLE1BQU0saUJBQWlCLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxNQUFNLENBQUM7SUFDakgsSUFBSSxNQUFNLGlCQUFpQixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsTUFBTSxDQUFDOztJQUVqSCxJQUFJLE1BQU1VLGNBQXdCLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxTQUFTLENBQUM7O0lBRTNELElBQUksTUFBTSxLQUFLLENBQUMsS0FBSyxFQUFFO0lBQ3ZCLElBQUksTUFBTSxLQUFLLENBQUMsS0FBSyxFQUFFOztJQUV2QixJQUFJLE1BQU0sa0JBQWtCLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUM1RCxJQUFJRyxVQUFnQixDQUFDLGtCQUFrQixFQUFFLEtBQUssRUFBRSxlQUFlLENBQUM7O0lBRWhFLElBQUksTUFBTSxnQkFBZ0IsR0FBRyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUU7O0lBRXhELElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQ2hDLFVBQWUsQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLGdCQUFnQixDQUFDLENBQUM7SUFDaEYsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDQSxVQUFlLENBQUMsZ0JBQWdCLEVBQUUscUJBQXFCLENBQUMsQ0FBQzs7SUFFckYsSUFBSSxPQUFPLGdCQUFnQjtJQUMzQjs7SUMzR0E7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7Ozs7SUFZZSxlQUFlLE1BQU0sQ0FBQyxXQUFXLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxFQUFFO0lBQzlHLElBQUksTUFBTSxVQUFVLEdBQUdrQixhQUFrQixDQUFDLGFBQWEsQ0FBQztJQUN4RCxJQUFJLE9BQU8sQ0FBQyxVQUFVLENBQUMsVUFBVSxJQUFJLENBQUM7SUFDdEMsWUFBWSxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUMsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDO0lBQzNELElBQUk7SUFDSixRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsZ0VBQWdFLENBQUM7SUFDbEcsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTtJQUNKLElBQUksSUFBSSxVQUFVLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRTtJQUNoQyxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsNENBQTRDLENBQUM7SUFDOUUsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTs7SUFFSixJQUFJLGdCQUFnQixHQUFHLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQztJQUNqRCxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLElBQUksZ0JBQWdCLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDdEQsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLHVEQUF1RCxDQUFDO0lBQ3pGLFFBQVEsT0FBTyxLQUFLO0lBQ3BCLElBQUk7OztJQUdKLElBQUksTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxHQUFHLE1BQU14QyxhQUF3QixDQUFDLFdBQVcsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ2xHLElBQUksTUFBTSxJQUFJLEdBQUcsTUFBTUssWUFBb0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDOztJQUU1RCxJQUFJLElBQUksSUFBSSxDQUFDLFFBQVEsSUFBSSxTQUFTLEVBQUU7SUFDcEMsUUFBUSxNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDO0lBQ25ELElBQUk7OztJQUdKLElBQUksTUFBTSxLQUFLLEdBQUcsTUFBTVgsYUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7O0lBRXhDLElBQUksTUFBTSxTQUFTLEdBQUcsTUFBTXVELGFBQXVCLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxRQUFRLENBQUM7O0lBRTNFLElBQUksTUFBTSxLQUFLLEdBQUcsTUFBTXpDLGFBQTBCLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDOztJQUU5RSxJQUFJLE1BQU0sR0FBRyxHQUFHLE1BQU1VLG1CQUF3QixDQUFDLFVBQVUsRUFBRSxnQkFBZ0IsQ0FBQzs7SUFFNUUsSUFBSSxNQUFNLGdCQUFnQixHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FDMUQsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQztJQUM3QyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUN6RCxRQUFRb0MsVUFBZ0IsQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3RSxJQUFJOztJQUVKLElBQUksTUFBTSxlQUFlLEdBQUcsRUFBRTtJQUM5QixJQUFJLGVBQWUsQ0FBQyxLQUFLLEdBQUcsRUFBRTtJQUM5QixJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztJQUN4RCxJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3pFLElBQUksZUFBZSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsZUFBZSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMvSCxJQUFJQyxNQUFZLENBQUMsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ3JFLElBQUlBLE1BQVksQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsZUFBZSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUM7SUFDdEUsSUFBSSxlQUFlLENBQUMsVUFBVSxHQUFHLGdCQUFnQixDQUFDLE1BQU0sRUFBRTtJQUMxRCxJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLFFBQVEsQ0FBQyxLQUFLLEVBQUUsZUFBZSxDQUFDLFVBQVUsQ0FBQztJQUM3RSxJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7O0lBRWpJLElBQUksSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQ3JGLElBQUksSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDOztJQUVyRixJQUFJLGVBQWUsQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLFVBQVU7O0lBRWhELElBQUksZUFBZSxDQUFDLElBQUksR0FBRyxDQUFDO0lBQzVCLElBQUksZUFBZSxDQUFDLGdCQUFnQixHQUFHLGdCQUFnQjtJQUN2RCxJQUFJLGVBQWUsQ0FBQyxVQUFVLEdBQUcsVUFBVTs7SUFFM0MsSUFBSSxJQUFJLElBQUksRUFBRSxlQUFlLENBQUMsSUFBSSxHQUFHLElBQUk7O0lBRXpDLElBQUksU0FBUyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDOztJQUVqRCxJQUFJLE1BQU1MLFdBQXFCLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQzs7SUFFNUM7SUFDQSxJQUFJLE1BQU1ULFdBQXdCLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDOztJQUU3RDtJQUNBLElBQUksTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7O0lBRTdEO0lBQ0EsSUFBSSxNQUFNQSxXQUF3QixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzs7SUFFN0Q7SUFDQSxJQUFJLE1BQU1BLFdBQXdCLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDOztJQUU3RDtJQUNBLElBQUksTUFBTUEsV0FBd0IsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7O0lBRTdELElBQUksTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDL0QsSUFBSSxNQUFNLGlCQUFpQixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsTUFBTSxDQUFDO0lBQ2pILElBQUksTUFBTSxpQkFBaUIsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLE1BQU0sQ0FBQzs7SUFFakgsSUFBSSxNQUFNVSxjQUF3QixDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsU0FBUyxDQUFDOztJQUUzRCxJQUFJLE1BQU0sS0FBSyxDQUFDLEtBQUssRUFBRTtJQUN2QixJQUFJLE1BQU0sS0FBSyxDQUFDLEtBQUssRUFBRTs7SUFFdkIsSUFBSSxNQUFNLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FDNUQsSUFBSUcsVUFBZ0IsQ0FBQyxrQkFBa0IsRUFBRSxLQUFLLEVBQUUsZUFBZSxDQUFDOztJQUVoRSxJQUFJLE1BQU0sZ0JBQWdCLEdBQUcsa0JBQWtCLENBQUMsTUFBTSxFQUFFOztJQUV4RCxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUNoQyxVQUFlLENBQUMsZ0JBQWdCLEVBQUUscUJBQXFCLENBQUMsQ0FBQzs7SUFFckYsSUFBSSxPQUFPLGdCQUFnQjtJQUMzQjs7SUM5SGUsZUFBZSxjQUFjLENBQUMsWUFBWSxFQUFFOztJQUUzRCxJQUFJLE1BQU0sSUFBSSxHQUFHLE1BQU0sUUFBUSxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUM7SUFDbkQsSUFBSSxPQUFPLElBQUksQ0FBQyxLQUFLO0lBQ3JCLElBQUksT0FBTyxJQUFJLENBQUMsQ0FBQzs7SUFFakIsSUFBSSxPQUFPLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUM7SUFDdkM7O0lDVkE7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7OztJQTRCZSxlQUFlLGlCQUFpQixDQUFDLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFO0lBQzdHLElBQUksTUFBTSxHQUFHLEdBQUcsTUFBTWdCLFlBQWlCLENBQUMsT0FBTyxDQUFDOztJQUVoRCxJQUFJLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztJQUN2QyxJQUFJLE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQzs7SUFFeEMsSUFBSSxNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMvQixJQUFJLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDOztJQUUvQixJQUFJLE1BQU0sTUFBTSxHQUFHLE1BQU0vRCxjQUFxQixDQUFDLGlCQUFpQixDQUFDO0lBQ2pFLElBQUksTUFBTSxJQUFJLEdBQUcsTUFBTUMsY0FBdUIsQ0FBQyxnQkFBZ0IsQ0FBQzs7O0lBR2hFLElBQUksTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEIsSUFBSSxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNwQixJQUFJLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3BCLElBQUksTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEIsSUFBSSxNQUFNLFNBQVMsR0FBRyxNQUFNLE1BQU0sRUFBRTtJQUNwQyxJQUFJLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUM7SUFDckQsSUFBSSxNQUFNLE9BQU8sQ0FBQyxNQUFNLENBQUM7SUFDekIsSUFBSSxNQUFNLFNBQVMsR0FBRyxNQUFNLE1BQU0sRUFBRTtJQUNwQyxJQUFJLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUM7SUFDckQsSUFBSSxNQUFNLE9BQU8sQ0FBQyxNQUFNLENBQUM7O0lBRXpCO0lBQ0EsSUFBSSxNQUFNLEdBQUcsR0FBRyxNQUFNLE1BQU0sQ0FBQyxTQUFTLEVBQUU7SUFDeEMsSUFBSSxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDO0lBQzlCLElBQUksTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQzs7SUFFdkI7SUFDQSxJQUFJLE1BQU0sRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLFNBQVMsRUFBRTtJQUN2QyxJQUFJLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7SUFDN0IsSUFBSSxNQUFNLDBCQUEwQixDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxjQUFjLEVBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQzs7SUFFL0g7SUFDQSxJQUFJLE1BQU0sRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLFNBQVMsRUFBRTtJQUN2QyxJQUFJLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7SUFDN0IsSUFBSSxNQUFNLDBCQUEwQixDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxjQUFjLEVBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQzs7SUFFL0g7SUFDQSxJQUFJLE1BQU0sRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLFNBQVMsRUFBRTtJQUN2QyxJQUFJLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7SUFDN0IsSUFBSSxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDOztJQUV0QjtJQUNBLElBQUksTUFBTSxHQUFHLEdBQUcsTUFBTSxNQUFNLENBQUMsU0FBUyxFQUFFO0lBQ3hDLElBQUksTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztJQUM5QixJQUFJLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7O0lBRXZCO0lBQ0EsSUFBSSxNQUFNLEdBQUcsR0FBRyxNQUFNLE1BQU0sQ0FBQyxTQUFTLEVBQUU7SUFDeEMsSUFBSSxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDO0lBQzlCLElBQUksTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQzs7O0lBR3ZCO0lBQ0E7SUFDQTtJQUNBLElBQUksTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBRTFELElBQUksTUFBTSxTQUFTLEdBQUcsRUFBRTtJQUN4QjtJQUNBLElBQUksU0FBUyxDQUFDLE1BQU0sSUFBSSxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQzdDLElBQUksZ0JBQWdCLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7O0lBRTdDLElBQUksTUFBTSxjQUFjLEdBQUcsTUFBTSxNQUFNLENBQUMsU0FBUyxFQUFFO0lBQ25ELElBQUksU0FBUyxDQUFDLGFBQWEsR0FBRyxFQUFFO0lBQ2hDLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUN6QyxRQUFRLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRTtJQUM5QixRQUFRLENBQUMsQ0FBQyxVQUFVLEdBQUcsTUFBTSxNQUFNLEVBQUU7SUFDckMsUUFBUSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxNQUFNLE1BQU0sRUFBRTtJQUNyQyxRQUFRLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLE1BQU0sTUFBTSxFQUFFO0lBQ3RDLFFBQVEsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsTUFBTSxNQUFNLEVBQUU7SUFDdkMsUUFBUSxDQUFDLENBQUMsVUFBVSxHQUFHLE1BQU0sTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDNUMsUUFBUSxTQUFTLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDdkMsUUFBUSxVQUFVLENBQUMsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUM5QyxJQUFJOztJQUVKLElBQUksTUFBTSxlQUFlLEdBQUcsRUFBRTtJQUM5QixJQUFJLGVBQWUsQ0FBQyxLQUFLLEdBQUcsRUFBRTtJQUM5QixJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLEtBQUs7SUFDeEMsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN6RSxJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ3hHLElBQUkrRSxNQUFZLENBQUMsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ3JFLElBQUlBLE1BQVksQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsZUFBZSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUM7SUFDdEUsSUFBSSxlQUFlLENBQUMsVUFBVSxHQUFHLGdCQUFnQixDQUFDLE1BQU0sRUFBRTtJQUMxRCxJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLFFBQVEsQ0FBQyxLQUFLLEVBQUUsZUFBZSxDQUFDLFVBQVUsQ0FBQztJQUM3RSxJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzFHLElBQUksZUFBZSxDQUFDLFVBQVUsR0FBRyxNQUFNO0lBQ3ZDLElBQUksZUFBZSxDQUFDLElBQUksR0FBRyxDQUFDO0lBQzVCLElBQUksU0FBUyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDOzs7SUFHakQ7SUFDQTtJQUNBOztJQUVBLElBQUksTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDdEMsSUFBSSxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUM7O0lBRXpELElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3pELFFBQVEsTUFBTSxDQUFDLEdBQUcsU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7SUFDNUMsUUFBUSxNQUFNLE9BQU8sQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDO0lBQ25DLFFBQVEsTUFBTSxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7SUFDbkMsUUFBUSxNQUFNLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztJQUNwQyxRQUFRLE1BQU0sT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQ3JDLFFBQVEsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUM7SUFDdEMsSUFBSTs7SUFFSixJQUFJLE1BQU0sa0JBQWtCLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUM1RCxJQUFJLFVBQVUsQ0FBQyxrQkFBa0IsRUFBRSxLQUFLLEVBQUUsZUFBZSxDQUFDOztJQUUxRCxJQUFJLE1BQU0sZ0JBQWdCLEdBQUcsa0JBQWtCLENBQUMsTUFBTSxFQUFFOztJQUV4RCxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUNqQyxVQUFlLENBQUMsZ0JBQWdCLEVBQUUscUJBQXFCLENBQUMsQ0FBQzs7SUFFckYsSUFBSSxNQUFNLElBQUksQ0FBQyxLQUFLLEVBQUU7SUFDdEIsSUFBSSxNQUFNLE1BQU0sQ0FBQyxLQUFLLEVBQUU7O0lBRXhCLElBQUksT0FBTyxnQkFBZ0I7O0lBRTNCLElBQUksZUFBZSxJQUFJLENBQUMsTUFBTSxFQUFFO0lBQ2hDLFFBQVEsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzVDLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsVUFBVSxFQUFFO0lBQ2hELFlBQVksTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLFVBQVUsQ0FBQztJQUNyRCxZQUFZLE1BQU0sSUFBSSxHQUFHLE1BQU0sTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDN0MsWUFBWSxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ2xDLFFBQVE7SUFDUixJQUFJOztJQUVKLElBQUksZUFBZSxNQUFNLEdBQUc7SUFDNUIsUUFBUSxNQUFNLElBQUksR0FBRyxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN2RCxRQUFRLE9BQU8sS0FBSyxDQUFDLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3BELElBQUk7O0lBRUosSUFBSSxlQUFlLE1BQU0sR0FBRztJQUM1QixRQUFRLE1BQU0sSUFBSSxHQUFHLE1BQU0sTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3ZELFFBQVEsT0FBTyxLQUFLLENBQUMsRUFBRSxDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDcEQsSUFBSTs7SUFFSixJQUFJLGVBQWUsT0FBTyxDQUFDLENBQUMsRUFBRTtJQUM5QixRQUFRLE1BQU0sSUFBSSxHQUFHLElBQUksVUFBVSxDQUFDLEdBQUcsQ0FBQztJQUN4QyxRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsaUJBQWlCLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDOUMsUUFBUSxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQzlCLElBQUk7O0lBRUosSUFBSSxlQUFlLE9BQU8sQ0FBQyxDQUFDLEVBQUU7SUFDOUIsUUFBUSxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsQ0FBQyxHQUFHLENBQUM7SUFDeEMsUUFBUSxLQUFLLENBQUMsRUFBRSxDQUFDLGlCQUFpQixDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzlDLFFBQVEsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztJQUM5QixJQUFJOzs7SUFHSjs7SUN0TUE7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7OztJQVFBLE1BQU0sbUJBQUN6RSxrQkFBZ0IsQ0FBQyxHQUFHLEtBQUs7O0lBRWpCLGVBQWUseUJBQXlCLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRTtJQUMxRSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsaUNBQWlDLENBQUM7O0lBRTlELElBQUksTUFBTSxDQUFDLEVBQUUsRUFBRSxRQUFRLENBQUMsR0FBRyxNQUFNbUQsYUFBd0IsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUM5RSxJQUFJLE1BQU0sSUFBSSxHQUFHLE1BQU1LLFlBQW9CLENBQUMsRUFBRSxFQUFFLFFBQVEsQ0FBQzs7SUFFekQsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLHVCQUF1QixHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7O0lBRXBFLElBQUksSUFBSSxHQUFHO0lBQ1gsSUFBSSxJQUFJLElBQUksQ0FBQyxRQUFRLEtBQUssU0FBUyxFQUFFO0lBQ3JDLFFBQVEsR0FBRyxHQUFHLE1BQU0sU0FBUyxDQUFDLElBQUksRUFBRSxFQUFFLEVBQUUsUUFBUSxDQUFDO0lBQ2pELElBQUksQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLFFBQVEsS0FBSyxPQUFPLEVBQUU7SUFDMUMsUUFBUSxHQUFHLEdBQUcsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDO0lBQ2pDLElBQUksQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLFVBQVUsSUFBSSxJQUFJLENBQUMsVUFBVSxLQUFLLGtCQUFrQixFQUFFO0lBQzFFLFFBQVEsR0FBRyxHQUFHLE1BQU0sY0FBYyxDQUFDLElBQVksQ0FBQztJQUNoRCxJQUFJLENBQUMsTUFBTTtJQUNYLFFBQVEsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQztJQUMxRCxJQUFJOztJQUVKLElBQUksTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFOztJQUVwQixJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsa0NBQWtDLENBQUM7O0lBRS9ELElBQUksT0FBTyxHQUFHO0lBQ2Q7OztJQUdBLGVBQWUsU0FBUyxDQUFDLElBQUksRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFO0lBQzdDLElBQUksTUFBTSxLQUFLLEdBQUcsTUFBTVgsYUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDeEMsSUFBSSxNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQzs7SUFFakMsSUFBSSxNQUFNLFNBQVMsR0FBRyxNQUFNLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDOztJQUUxRSxJQUFJLElBQUksSUFBSSxHQUFHO0lBQ2YsUUFBUSxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7SUFDL0IsUUFBUSxLQUFLLEVBQUUsS0FBSyxDQUFDLElBQUk7SUFDekIsUUFBUSxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87O0lBRTdCLFFBQVEsVUFBVSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7O0lBRXRELFFBQVEsU0FBUyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDcEQsUUFBUSxVQUFVLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUN0RCxRQUFRLFVBQVUsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDOztJQUV0RCxRQUFRLGVBQWUsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxTQUFTO0lBQ3BELEtBQUs7O0lBRUw7SUFDQTtJQUNBLElBQUksTUFBTUcsd0JBQW1DLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDOUQsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDaEIsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUM1QyxRQUFRLE1BQU0sSUFBSSxHQUFHLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDdkMsUUFBUSxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7SUFDekMsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDdkIsSUFBSTtJQUNKLElBQUksTUFBTUMsZ0JBQTJCLENBQUMsRUFBRSxDQUFDOztJQUV6QyxJQUFJLElBQUksR0FBR2pELGtCQUFnQixDQUFDLElBQUksQ0FBQzs7SUFFakMsSUFBSSxPQUFPLElBQUk7SUFDZjs7O0lBR0EsZUFBZSxPQUFPLENBQUMsSUFBSSxFQUFFO0lBQzdCLElBQUksTUFBTSxLQUFLLEdBQUcsTUFBTTZDLGFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDOztJQUV4QyxJQUFJLElBQUksSUFBSSxHQUFHO0lBQ2YsUUFBUSxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7SUFDL0IsUUFBUSxLQUFLLEVBQUUsS0FBSyxDQUFDLElBQUk7SUFDekIsUUFBUSxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87SUFDN0IsUUFBUSxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7O0lBRXpCLFFBQVEsRUFBRSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDdEMsUUFBUSxFQUFFLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQzs7SUFFdEMsUUFBUSxFQUFFLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN0QyxRQUFRLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3RDLFFBQVEsRUFBRSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDdEMsUUFBUSxFQUFFLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN0QyxRQUFRLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3RDLFFBQVEsRUFBRSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDdEMsUUFBUSxFQUFFLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN0QyxRQUFRLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDOztJQUV0QyxRQUFRLEdBQUcsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDOztJQUV4QyxRQUFRLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDO0lBQ25ELEtBQUs7O0lBRUwsSUFBSSxJQUFJLEdBQUc3QyxrQkFBZ0IsQ0FBQyxJQUFJLENBQUM7O0lBRWpDLElBQUksT0FBTyxJQUFJO0lBQ2Y7O0lBRUEsZUFBZSxjQUFjLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFB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QUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3QixZQUFZLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzdCLFlBQVksTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckQsWUFBWSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QyxZQUFZLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzlDLFlBQVksTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLFlBQVksTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEQsWUFBWSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDbkUsUUFBUTs7SUFFUixRQUFRLFNBQVMsd0JBQXdCLENBQUMsRUFBRSxFQUFFO0lBQzlDLFlBQVksSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUk7SUFDM0IsWUFBWSxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ3JCLFlBQVksTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxF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QUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakUsUUFBUTtJQUNSLFFBQVEsTUFBTSxlQUFlLENBQUMsTUFBTSxDQUFDO0lBQ3JDLElBQUk7O0lBRUosSUFBSSxlQUFlLFlBQVksR0FBRzs7SUFFbEM7SUFDQTtJQUNBLFFBQVEsTUFBTSxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQzFDLFFBQVEsTUFBTSxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ25DLFFBQVEsTUFBTSxlQUFlLENBQUMsTUFBTSxDQUFDOztJQUVyQztJQUNBOztJQUVBLFFBQVEsTUFBTSxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQzFDLFFBQVEsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDOUIsUUFBUSxNQUFNLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQzs7SUFFM0UsUUFBUSxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQztJQUM5QixRQUFRLE1BQU0sR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDOztJQUUzRSxRQUFRLE1BQU0sTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7SUFDcEMsUUFBUSxNQUFNLFdBQVcsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsQ0FBQztJQUM5QyxRQUFRLE1BQU0sTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7SUFDcEMsUUFBUSxNQUFNLFdBQVcsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsQ0FBQztJQUM5QyxRQUFRLE1BQU0sTUFBTSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUM1QyxRQUFRLE1BQU0sTUFBTSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN6QyxRQUFRLE1BQU0sTUFBTSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUM1QyxRQUFRLE1BQU0sTUFBTSxDQUFDLFVBQVUsQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDdkQsUUFBUSxNQUFNLE1BQU0sQ0FBQyxVQUFVLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUM7O0lBRXpELFFBQVEsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztJQUM5QixRQUFRLE1BQU0sTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7O0lBRTlCLFFBQVEsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzlDLFFBQVEsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzlDLFFBQVEsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzlDLFFBQVEsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzlDLFFBQVEsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDOztJQUU5QyxRQUFRLE1BQU0sTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM5QyxRQUFRLE1BQU0sTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FB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QUFNLFdBQVcsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQzVCLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDNUI7SUFDQSxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLEdBQUcsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDdkUsTUFBTSxLQUFLLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxHQUFHLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3ZFO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNPLFNBQVMsT0FBTyxDQUFDLENBQUMsRUFBRSxNQUFNLEdBQUcsRUFBRSxFQUFFO0lBQ3hDLElBQUksT0FBTyxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUM7SUFDN0I7SUFDQSxJQUFJLElBQUksTUFBTSxHQUFHLENBQUMsSUFBSSxNQUFNLEdBQUcsRUFBRTtJQUNqQyxRQUFRLE1BQU0sSUFBSSxLQUFLLENBQUMsaUNBQWlDLENBQUM7SUFDMUQsSUFBSSxNQUFNLENBQUMsR0FBRyxJQUFJLFdBQVcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3BDO0lBQ0EsSUFBSSxLQUFLLElBQUksS0FBSyxHQUFHLEVBQUUsR0FBRyxNQUFNLEVBQUUsS0FBSyxHQUFHLEVBQUUsRUFBRSxLQUFLLEVBQUUsRUFBRTtJQUN2RDtJQUNBLFFBQVEsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEVBQUU7SUFDbkMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3ZFLFFBQVEsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFO0lBQ3hDLFlBQVksTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUU7SUFDckMsWUFBWSxNQUFNLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRTtJQUNyQyxZQUFZLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDOUIsWUFBWSxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUNsQyxZQUFZLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDakQsWUFBWSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUNyRCxZQUFZLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRTtJQUM3QyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFO0lBQzlCLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFO0lBQ2xDLFlBQVk7SUFDWixRQUFRO0lBQ1I7SUFDQSxRQUFRLElBQUksSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkIsUUFBUSxJQUFJLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3ZCLFFBQVEsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNyQyxZQUFZLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDdEMsWUFBWSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLLENBQUM7SUFDL0MsWUFBWSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLLENBQUM7SUFDL0MsWUFBWSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ2pDLFlBQVksSUFBSSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDeEIsWUFBWSxJQUFJLEdBQUcsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDNUIsWUFBWSxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRTtJQUN0QixZQUFZLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRTtJQUMxQixRQUFRO0lBQ1I7SUFDQTtJQUNBO0lBQ0E7SUFDQSxRQUFRLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRTtJQUN6QyxZQUFZLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDeEUsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3hDLFlBQVksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDNUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM1QyxZQUFZLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzVDLFlBQVksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDNUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM1QyxZQUFZLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUU7SUFDdEMsWUFBWSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFO0lBQ3RDLFlBQVksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFO0lB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RSxDQUFDO0lBQ3RCLElBQUk7O0lBRUosSUFBSSxPQUFPLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFO0lBQzVDLFFBQVEsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7SUFDakMsUUFBUSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztJQUNqQyxRQUFRLElBQUksQ0FBQyxFQUFFLEVBQUU7O0lBRWpCLFFBQVEsTUFBTSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2hDLFFBQVEsTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQ2xDLFFBQVEsTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ2xDLFFBQVEsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDOztJQUVwQyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7O0lBRTFCLFFBQVEsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ2hDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3hDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDOztJQUV4QyxRQUFRLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUNqQyxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztJQUN6QyxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQzs7SUFFekMsUUFBUSxFQUFFLEdBQUcsRUFBRTtJQUNmLFFBQVEsSUFBSSxDQUFDLEVBQUU7SUFDZixZQUFZLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQztJQUN4QyxZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM5QyxZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM5QyxRQUFROztJQUVSLFFBQVEsT0FBTyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7SUFDdEIsSUFBSTs7SUFFSixJQUFJLE9BQU8sSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRTtJQUNuRCxRQUFRLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO0lBQ2pDLFFBQVEsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7SUFDakMsUUFBUSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQzs7SUFFakMsUUFBUSxJQUFJLENBQUMsRUFBRSxFQUFFOztJQUVqQixRQUFRLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNoQyxRQUFRLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUNsQyxRQUFRLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNsQyxRQUFRLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQzs7SUFFcEMsUUFBUSxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDaEMsUUFBUSxNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7SUFDbEMsUUFBUSxNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDbEMsUUFBUSxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUM7O0lBRXBDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQzs7SUFFNUIsUUFBUSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUM7SUFDbEMsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDMUMsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDMUMsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7O0lBRTFDLFFBQVEsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDO0lBQ25DLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzNDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzNDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzNDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzNDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDOztJQUUzQyxRQUFRLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQztJQUNwQyxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztJQUM1QyxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztJQUM1QyxR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QU0sRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2hELFlBQVksTUFBTSxJQUFJLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRTs7SUFFdkMsWUFBWSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsSUFBSSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQzdGLFFBQVE7SUFDUixJQUFJOztJQUVKLElBQUksU0FBUyxDQUFDLEtBQUssRUFBRTtJQUNyQixRQUFRLE1BQU0sWUFBWSxHQUFHLENBQUMsS0FBSyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ2hHLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMxRCxJQUFJOztJQUVKLElBQUksU0FBUyxDQUFDLEtBQUssRUFBRTtJQUNyQixRQUFRLE1BQU0sWUFBWSxHQUFHLENBQUMsS0FBSyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ2hHLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMxRCxJQUFJOztJQUVKO0lBQ0EsSUFBSSxXQUFXLENBQUMsS0FBSyxFQUFFO0lBQ3ZCLFFBQVEsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQUU7SUFDMUIsUUFBUSxNQUFNLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQzs7SUFFdkUsUUFBUSxNQUFNLE1BQU0sR0FBRyxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFO0lBQ2pFLFFBQVEsTUFBTSxJQUFJLEdBQUcsTUFBTSxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsSUFBSSxTQUFTLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN0RyxRQUFRLElBQUksR0FBRyxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUM7O0lBRS9EO0lBQ0EsUUFBUSxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7O0lBRWxFO0lBQ0EsUUFBUSxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7O0lBRXJDO0lBQ0EsUUFBUSxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQzs7SUFFckI7SUFDQSxRQUFRLElBQUksQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDLElBQUk7SUFDNUIsSUFBSTs7SUFFSjtJQUNBLElBQUksWUFBWSxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUU7SUFDM0IsUUFBUSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRTtJQUMxQixRQUFRLE1BQU0sTUFBTSxHQUFHLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDOztJQUVoRSxRQUFRLE1BQU0sTUFBTSxHQUFHLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUU7SUFDakUsUUFBUSxNQUFNLElBQUksR0FBRyxNQUFNLEdBQUcsQ0FBQyxJQUFJLEVBQUUsR0FBRyxJQUFJLFNBQVMsQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ3RHLFFBQVEsSUFBSSxHQUFHLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQzs7SUFFL0Q7SUFDQSxRQUFRLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQzs7SUFFNUU7SUFDQSxRQUFRLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDOztJQUU3QjtJQUNBLFFBQVEsR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUM7O0lBRXJCO0lBQ0EsUUFBUSxJQUFJLENBQUMsSUFBSSxHQUFHLEdBQUcsQ0FBQyxJQUFJO0lBQzVCLElBQUk7O0lBRUo7SUFDQSxJQUFJLEtBQUssQ0FBQyxVQUFVLEVBQUU7SUFDdEIsUUFBUSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRTtJ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LENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQzVCLGFBQWE7SUFDYixRQUFRO0lBQ1IsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQ3ZCLFlBQVksSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQzFDLFlBQVksSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDdEUsU0FBUyxFQUFFO0lBQ1gsWUFBWSxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDO0lBQ3pELFFBQVE7O0lBRVIsUUFBUSxJQUFJLENBQUMsSUFBSSxHQUFHLEtBQUs7SUFDekIsSUFBSTs7SUFFSixJQUFJLEtBQUssQ0FBQyxVQUFVLEVBQUUsVUFBVSxHQUFHLENBQUMsRUFBRTtJQUN0QyxRQUFRLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxVQUFVLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDN0MsWUFBWSxNQUFNLElBQUksR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQ3ZDLFlBQVksSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3RGLFFBQVE7O0lBRVIsUUFBUSxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDNUQsUUFB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QVksTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQztJQUNsRSxRQUFRO0lBQ1IsUUFBUSxJQUFJLFdBQVcsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLEVBQUU7SUFDM0QsWUFBWSxNQUFNLElBQUksS0FBSyxDQUFDLHFDQUFxQyxDQUFDO0lBQ2xFLFFBQVE7SUFDUixRQUFRLElBQUksV0FBVyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsRUFBRTtJQUMzRCxZQUFZLE1BQU0sSUFBSSxLQUFLLENBQUMscUNBQXFDLENBQUM7SUFDbEUsUUFBUSxDQUFDO0lBQ1QsSUFBSTs7SUFFSixJQUFJLGVBQWUsTUFBTSxHQUFHO0lBQzVCO0lBQ0E7SUFDQSxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsdUNBQXVDLENBQUM7SUFDekUsUUFBUSxVQUFVLENBQUMsS0FBSyxFQUFFOztJQUUxQixRQUFRLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQzVDLFFBQVEsVUFBVSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDNUMsUUFBUSxVQUFVLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUM1QyxRQUFRLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQzVDLFFBQVEsVUFBVSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDNUMsUUFBUSxVQUFVLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUM1QyxRQUFRLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQzVDLFFBQVEsVUFBVSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7O0lBRTVDO0lBQ0EsUUFBUSxLQUFL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QUN6RCxZQUFZLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLEdBQUcsR0FBRyxDQUFDOztJQUV6RDtJQUNBO0lBQ0EsWUFBWSxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDOztJQUVwRCxZQUFZLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQztJQUNyQyxZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDOztJQUU3QyxZQUFZLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN0RCxZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDOztJQUU3QyxZQUFZLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN0RCxZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDOztJQUU3QyxZQUFZLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDOztJQUVoRDtJQUNBLFlBQVksSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hHLFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRTdDLFlBQVksSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hHLFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRTdDLFlBQVksSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hHLFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRTdDLFlBQVksSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7O0lBRWhEO0lBQ0EsWUFBWSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLEdBQUcsR0FBRyxDQUFDLEVBQUUsR0FBRyxDQUFDO0lBQy9ELFlBQVksTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLFVBQVUsSUFBSSxHQUFHLENBQUM7O0lBRTlEO0lBQ0EsWUFBWSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLEdBQUcsR0FBRyxDQUFDLEVBQUUsR0FBRyxDQUFDO0lBQy9ELFlBQVksTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLFVBQVUsSUFBSSxHQUFHLENBQUM7O0lBRTlELFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzNDLFFBQVE7O0lBRVI7SUFDQTtJQUNBLFFBQVEsTUFBTSxHQUFHLE1BQU0sRUFBRSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUM7O0lBRTlDO0lBQ0E7SUFDQSxRQUFRLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2xELFlBQVksTUFBTSxLQUFLLEdBQUcsQ0FBQyxHQUFHLEdBQUc7O0lBRWpDLFlBQVksTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLEdBQUcsR0FBRyxDQUFDLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxHQUFHLEdBQUcsQ0FBQyxDQUFDO0lBQ2hHLFlBQVksTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDO0lBQ2hDLFFBQVE7O0lBRVI7SUFDQSxRQUFRLE9BQU8sQ0FBQyxDQUFDLEdBQUcsTUFBTTs7SUFFMUIsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUU7SUFDbEQsWUFBWSxNQUFNLElBQUks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Q0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUNwRCxZQUFZLE1BQU0sQ0FBQyxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUNwRCxZQUFZLE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsS0FBSyxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQyxDQUFDOztJQUV6RyxZQUFZLE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUN0RCxZQUFZLE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUN0RCxZQUFZLE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUN0RCxZQUFZLE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUN0RCxZQUFZLE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUN0RCxZQUFZLE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUMxRCxZQUFZLE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUMxRCxZQUFZLE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQzs7SUFFMUQsWUFBWSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzFFLFlBQVksTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUMxRSxZQUFZLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7O0lBRTFFLFlBQVksTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDbkMsWUFBWSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0csWUFBWSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNsRCxZQUFZLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO0lBQ3JDLFlBQVksTUFBTSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOztJQUVsSCxZQUFZLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJO0lBQzVCLFlBQVksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDbkQsZ0JBQWdCLE1BQU0sTUFBTSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUM7O0lBRTVELGdCQUFnQixNQUFNLElBQUksR0FBRyxXQUFXLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUM7SUFDdkUsZ0JBQWdCLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsQ0FBQzs7SUFFcEUsZ0JBQWdCLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNuRCxZQUFZOztJQUVaO0lBQ0EsWUFBWSxJQUFJLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQzlELFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUMvQixZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUM7O0lBRWpDLFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzFDLFlBQVksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDOztJQUU3QyxZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUMxQyxZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQzs7SUFFN0MsWUFBWSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDMUMsWUFBWSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7O0lBRTdDLFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUMvQixZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUM7O0lBRS9CO0lBQ0EsWUFBWSxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3BELFlBQVksSUFBSSxHQUFHLEdBQUcsQ0FBQztJQUN2QixZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUM7SUFDcEMsWUFBWSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFL0MsWUFBWSxJQUFJLEdBQUcsR0FBRyxDQUFDO0lBQ3ZCLFlBQVksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNyRCxZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDOztJQUUvQyxZQUFZLElBQUksR0FBRyxHQUFHLENBQUM7SUFDdkIsWUFBWSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3JELFlBQVksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRS9DLFlBQVksSUFBSSxHQUFHLEdBQUcsQ0FBQzs7SUFFdkIsWUFBWSxJQUFJLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUNwRixZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDO0lBQzdDLFlBQVksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRS9DO0lBQ0EsWUFBWSxJQUFJLEdBQUcsR0FBRyxDQUFDO0lBQ3ZCLFlBQVksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztJQUMxRCxZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDOztJQUUvQyxZQUFZLElBQUksR0FBRyxHQUFHLENBQUM7SUFDdkIsWUFBWSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzFELFlBQVksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRS9DLFlBQVksSUFBSSxHQUFHLEdBQUcsQ0FBQztJQUN2QixZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDMUQsWUFBWSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFL0MsWUFBWSxJQUFJLEdBQUcsR0FBRyxFQUFFO0lBQ3hCLFlBQVksSUFBSSxDQUFDLEVBQUUsRUFBRSxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUM7O0lBRXJGLFlBQVksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7SUFDN0MsWUFBWSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFL0M7SUFDQSxZQUFZLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUM7SUFDdEMsWUFBWSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsV0FBVyxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEUsWUFBWSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLE1BQU0sQ0FBQzs7SUFFOUMsWUFBWSxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxXQUFXLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2RSxZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsTUFBTSxDQUFDOzs7SUFHaEQsWUFBWSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQzFELFlBQVksSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQzs7SUFFL0QsWUFBWSxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUNyQyxZQUFZLE9BQU8sQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDOztJQUV2QyxZQUFZLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDL0MsUUFBUTs7SUFFUjtJQUNBLFFBQVEsSUFBSSxNQUFNO0lBQ2xCLFlBQVksTUFBTSxDQUFDLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQztJQUNoRCxRQUFRLFdBQVcsQ0FBQyxDQUFDLEdBQUcsTUFBTSxVQUFVLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQzs7SUFFbEY7SUFDQSxRQUFRLElBQUksTUFBTTtJQUNsQixZQUFZLE1BQU0sQ0FBQyxLQUFLLENBQUMsc0JBQXNCLENBQUM7SUFDaEQsUUFBUSxXQUFXLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQzs7SUFFL0M7SUFDQSxRQUFRLElBQUksTUFBTTtJQUNsQixZQUFZLE1BQU0sQ0FBQyxLQUFLLENBQUMsdUJBQXVCLENBQUM7SUFDakQsUUFBUSxXQUFXLENBQUMsRUFBRSxHQUFHLE1BQU0sVUFBVSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUM7O0lBRXBGO0lBQ0EsUUFBUSxXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDOztJQUV6QztJQUNBLFFBQVEsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxJQUFJLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRTtJQUMvRCxZQUFZLE1BQU0sSUFBSSxLQUFLLENBQUMscUNBQXFDLENBQUM7SUFDbEUsUUFBUTs7SUFFUjtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQSxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsc0NBQXNDLENBQUM7SUFDeEUsUUFBUSxXQUFXLENBQUMsRUFBRSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQztJQUNsRyxRQUFRLFdBQVcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDO0lBQ2xHLFFBQVEsV0FBVyxDQUFDLEVBQUUsR0FBRyxJQUFJLFVBQVUsQ0FBQyxJQUFJLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUM7O0lBRWxHLFFBQVEsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3hFLFFBQVEsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsT0FBTyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNsRixRQUFRLFdBQVcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLENBQUMsRUFBRSxPQUFPLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7O0lBRWhHO0lBQ0EsUUFBUSxXQUFXLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7O0lBRWpFO0lBQ0E7SUFDQSxRQUFRLE1BQU0sU0FBUyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM3RSxRQUFRLFdBQVcsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUM7SUFDNUMsUUFBUSxXQUFXLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7O0lBRWpFO0lBQ0E7SUFDQSxRQUFRLE1BQU0sVUFBVSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM5RSxRQUFRLFdBQVcsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUM7SUFDN0MsSUFBSTs7SUFFSixJQUFJLGVBQWUsTUFBTSxHQUFHO0lBQzVCLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQywwQkFBMEIsQ0FBQzs7SUFFNUQ7SUFDQSxRQUFRLFVBQVUsQ0FBQyxLQUFLLEVBQUU7SUFDMUIsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUM7SUFDOUMsUUFBUSxVQUFVLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM5RCxRQUFRLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzlELFFBQVEsVUFBVSxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7O0lBRTlELFFBQVEsVUFBVSxDQUFDLEVBQUUsR0FBRyxVQUFVLENBQUMsWUFBWSxFQUFFO0lBQ2pELFFBQVEsVUFBVSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEU7SUFDQSxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMscUJBQXFCLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7O0lBRXpGO0lBQ0EsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDNUUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDNUUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDNUUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbEYsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbEYsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDOUUsSUFBSTs7SUFFSixJQUFJLGVBQWUsTUFBTSxHQUFHO0lBQzVCLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQztJQUMzRDtJQUNBO0lBQ0EsUUFBUSxVQUFVLENBQUMsS0FBSyxFQUFFO0lBQzFCLFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO0lBQzNDLFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNELFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNELFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNELFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzVELFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzVELFFBQVEsVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDOztJQUU1RCxRQUFRLFVBQVUsQ0FBQyxDQUFDLEdBQUcsRUFBRTtJQUN6QixRQUFRLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxDQUFDLFlBQVksRUFBRTtJQUNuRCxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsb0JBQW9CLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDOztJQUV6RixRQUFRLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDcEMsWUFBWSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRSxRQUFROztJQUVSO0lBQ0EsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLDJDQUEyQyxDQUFDO0lBQzdFLFFBQVEsTUFBTSxRQUFRLEVBQUU7O0lBRXhCO0lBQ0EsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLHdEQUF3RCxDQUFDO0lBQzFGLFFBQVEsVUFBVSxFQUFFOztJQUVwQjtJQUNBLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyx5REFBeUQsQ0FBQztJQUMzRixRQUFRLFdBQVcsRUFBRTs7SUFFckIsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLDJCQUEyQixDQUFDO0lBQzdELFFBQVEsSUFBSSxTQUFTLEdBQUcsTUFBTSxXQUFXLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxLQUFLLENBQUM7SUFDOUUsUUFBUSxJQUFJLFVBQVUsR0FBRyxNQUFNLFdBQVcsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQzs7SUFFakY7SUFDQSxRQUFRLEtBQUssQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQztJQUM3QyxRQUFRLEtBQUssQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQztJQUMvQyxJQUFJOztJQUVKLElBQUksZUFBZSxRQUFRLEdBQUc7SUFDOUIsUUFBUSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTtJQUMzQjtJQUNBO0lBQ0EsUUFBUSxXQUFXLENBQUMsRUFBRSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUM7SUFDOUUsUUFBUSxXQUFXLENBQUMsRUFBRSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUM7SUFDOUUsUUFBUSxXQUFXLENBQUMsRUFBRSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUM7SUFDOUUsUUFBUSxXQUFXLENBQUMsRUFBRSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUM7SUFDOUUsUUFBUSxXQUFXLENBQUMsRUFBRSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUM7O0lBRTlFO0lBQ0EsUUFBUSxNQUFNLE1BQU0sQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDekcsUUFBUSxNQUFNLE1BQU0sQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDekcsUUFBUSxNQUFNLE1BQU0sQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDekcsUUFBUSxNQUFNLE1BQU0sQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDekcsUUFBUSxNQUFNLE1BQU0sQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRztJQUNBLFFBQVEsVUFBVSxDQUFDLEdBQUcsR0FBRyxVQUFVLENBQUMsRUFBRTtJQUN0QyxRQUFRLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzdDLFlBQVksVUFBVSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7SUFDdEQsUUFBUTs7SUFFUixRQUFRLFVBQVUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUM7O0lBRXRELFFBQVEsTUFBTSxDQUFDLEdBQUcsRUFBRTs7SUFFcEIsUUFBUSxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDdkMsUUFBUSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRztJQUN0QixRQUFRLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDN0QsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENB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QUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbEQsUUFBUSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFM0MsUUFBUSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLEVBQUUsR0FBRyxDQUFDLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFMUUsUUFBUSxJQUFJLEdBQUcsR0FBRyxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQU07SUFDMUMsUUFBUSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDN0UsUUFBUSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFM0MsUUFBUSxJQUFJLEdBQUcsR0FBRyxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQU07SUFDMUMsUUFBUSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDN0UsUUFBUSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFM0MsUUFBUSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUM7SUFDakMsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUM7SUFDbEQsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFekMsUUFBUSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsTUFBTSxDQUFDOztJQUVyRCxRQUFRLFdBQVcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDOztJQUVqRyxRQUFRLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsT0FBTyxDQUFDO0lBQ2xELFFBQVEsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQztJQUNuRSxRQUFRLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUM7SUFDbkUsUUFBUSxXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDO0lBQ25FLFFBQVEsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztJQUN6QyxRQUFRLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQzVDLFFBQVEsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDMUUsUUFBUSxXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQzs7SUFFNUMsUUFBUSxJQUFJLEdBQUcsR0FBRyxVQUFVLENBQUMsY0FBYyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQztJQUMxRSxRQUFRLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDaEQsUUFBUSxHQUFHLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLEdBQUcsQ0FBQztJQUMvQyxRQUFRLEdBQUcsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztJQUMvQixRQUFRLEdBQUcsQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQzs7SUFFcEMsUUFBUSxXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7O0lBRTlCLFFBQVEsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNoRyxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUM7O0lBRTNCLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7O0lBRTlELFFBQVEsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO0lBQ25DLElBQUk7O0lBRUosSUFBSSxTQUFTLFVBQVUsR0FBRztJQUMxQixRQUFRLFdBQVcsQ0FBQyxHQUFHLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxTQUFTLENBQUMsT0FBTyxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDOztJQUV6RixRQUFRLFdBQVcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFDMUMsUUFBUSxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0QsUUFBUSxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0QsUUFBUSxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0QsUUFBUSxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEUsUUFBUSxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRWhFLFFBQVEsV0FBVyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDcEYsUUFBUSxXQUFXLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNwRixRQUFRLFdBQVcs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QUFVLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNsQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ2xDLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDbEMsSUFBSSxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztJQUNwQyxJQUFJLEdBQUcsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO0lBQ3BDLElBQUksR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7SUFDcEMsSUFBSSxHQUFHLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUM1QyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQzVDLElBQUksR0FBRyxDQUFDLE1BQU0sR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDNUMsSUFBSSxHQUFHLENBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQztJQUM5QyxJQUFJLEdBQUcsQ0FBQyxPQUFPLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDO0lBQzlDLElBQUksR0FBRyxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7SUFDOUMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQztJQUN0QyxJQUFJLEdBQUcsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ3hDLElBQUksT0FBTyxHQUFHO0lBQ2Q7O0lBRUEsU0FBU0gsY0FBWSxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7SUFDakMsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTtJQUN2QixJQUFJLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFO0lBQ3ZCLElBQUksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUU7SUFDdkIsSUFBSSxNQUFNLEdBQUcsR0FBRyxFQUFFO0lBQ2xCLElBQUksR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDakMsSUFBSSxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUNqQyxJQUFJLEdBQUcsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ2pDLElBQUksR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDakMsSUFBSSxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUNqQyxJQUFJLEdBQUcsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ2pDLElBQUksR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDakMsSUFBSSxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUNqQyxJQUFJLEdBQUcsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ2pDLElBQUksR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDakMsSUFBSSxHQUFHLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQzs7SUFFbkMsSUFBSSxPQUFPLEdBQUc7SUFDZDs7SUFFQSxTQUFTLGlCQUFpQixDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUU7SUFDekMsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTtJQUN2QixJQUFJLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLEtBQUs7SUFDMUMsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxLQUFLO0lBQzFDLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sS0FBSztJQUMxQyxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLEtBQUs7SUFDMUMsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsT0FBTyxLQUFLO0lBQzNDLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLE9BQU8sS0FBSztJQUMzQyxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxPQUFPLEtBQUs7SUFDM0MsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsT0FBTyxLQUFLO0lBQzVDLElBQUksSUFBSSxDQUFDLEVBQUUs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Q0FBQyxLQUFLLEVBQUU7SUFDdEIsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7SUFDaEMsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDdEMsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDdEMsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDdEMsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7SUFDdkMsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7SUFDdkMsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7SUFDdkMsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUU7SUFDZCxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxDQUFDLFlBQVksRUFBRTs7SUFFeEMsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOztJQUVwRTtJQUNBLElBQUksVUFBVSxDQUFDLEtBQUssRUFBRTtJQUN0QixJQUFJLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDO0lBQzFDLElBQUksVUFBVSxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7SUFDM0MsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxZQUFZLEVBQUU7O0lBRXJDLElBQUksT0FBTyxHQUFH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QyxNQUFNLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUMxRSxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDOztJQUV2QyxJQUFJLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzFFLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRXZDLElBQUksSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRXBELElBQUksSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUM7SUFDMUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQztJQUNsQyxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDOztJQUVyQyxJQUFJLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDOztJQUV6QyxJQUFJLE9BQU8sRUFBRTtJQUNiOztJQUVBLFNBQVMsVUFBVSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUU7SUFDdEQsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTtJQUN2QixJQUFJLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFO0lBQ3ZCO0lBQ0EsSUFBSSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNsRSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3BELElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDcEQsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNwRCxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDOztJQUUxQixJQUFJLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsRUFBRSxDQUFDOztJQUV6RCxJQUFJLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7SUFDdkUsSUFBSSxNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDO0lBQ3RGLElBQUksTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFdEYsSUFBSSxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFMUUsSUFBSSxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQzs7SUFFdkQsSUFBSSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRTFFLElBQUksTUFBTSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7SUFDdEcsSUFBSSxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQztJQUN0RyxJQUFJLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDOztJQUVoRixJQUFJLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQy9EO0lBQ0EsSUFBSSxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsRUFBRTtJQUMxQixJQUFJLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsR0FBRyxDQUFDO0lBQ3RELElBQUksTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2xFLElBQUksSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDakQsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLEVBQUUsQ0FBQzs7SUFFdEMsSUFBSSxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDOztJQUVwRCxJQUFJLE9BQU8sQ0FBQztJQUNaOztJQUVBLFNBQVMsVUFBVSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUU7SUFDckQsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTs7SUFFdkIsSUFBSSxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzdELElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0QsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMzRCxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pELElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRXpELElBQUksT0FBTyxHQUFHO0lBQ2Q7O0lBRUEsU0FBUyxVQUFVLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFO0lBQ2xELElBQUksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUU7SUFDdkIsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTs7SUFFdkIsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNyRSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3hELElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDeEQsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN6RCxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3pELElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxLQUFL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RUFBRSxFQUFFLE1BQU0sR0FBRyxNQUFNLEdBQUcsR0FBRztJQUMvQyxRQUFRLE1BQU0sR0FBRyxNQUFNLEdBQUdrRSxNQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RDLElBQUk7O0lBRUosSUFBSSxPQUFPLENBQUMsQ0FBQyxFQUFFQSxNQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkQsSUFBSSxDQUFDLEVBQUVBLE1BQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFQSxNQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QyxJQUFJLENBQUMsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUVBLE1BQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzlDLElBQUksQ0FBQyxFQUFFQSxNQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDOUMsSUFBSSxDQUFDLEVBQUVBLE1BQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFQSxNQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNoRCxJQUFJLENBQUMsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUVBLE1BQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2hELElBQUksQ0FBQyxFQUFFQSxNQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEQsSUFBSSxDQUFDLEVBQUVBLE1BQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFQSxNQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsRCxJQUFJLENBQUMsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUVBLE1BQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BELElBQUksQ0FBQyxFQUFFQSxNQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM1QixJQUFJLENBQUMsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUIsSUFBSSxDQUFDLEVBQUVBLE1BQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzVCLElBQUksQ0FBQyxFQUFFQSxNQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3QixJQUFJLENBQUMsRUFBRUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDN0IsSUFBSSxDQUFDLEVBQUVBLE1BQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENB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VUFBVSxJQUFJLFVBQVUsS0FBSyxTQUFTLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUM1RyxRQUFRLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUU7SUFDdkMsUUFBUSxNQUFNLFlBQVksR0FBRyxDQUFDLEtBQUssSUFBSSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDM0QsUUFBUSxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUU7O0lBRTlCLFFBQVEsSUFBSSxVQUFVLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxTQUFTLENBQUMsWUFBWSxHQUFHLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQzs7SUFFbkcsUUFBUSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzVDLFlBQVksTUFBTSxJQUFJLEdBQUcsQ0FBQyxHQUFHLEdBQUc7SUFDaEMsWUFBWSxNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDLENBQUM7O0lBRXZDLFlBQVksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDN0MsZ0JBQWdCLElBQUksSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsS0FBSyxTQUFTLEVBQUU7SUFDdkQsb0JBQW9CLElBQUksQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksR0FBRyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUMvSCxnQkFBZ0I7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SyxDQUFDLEtBQUssRUFBRSxLQUFLLEdBQUcsR0FBRyxDQUFDO0lBQzlELGdCQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDO0lBQzFDLGdCQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFckQsZ0JBQWdCLElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLEdBQUcsR0FBRyxDQUFDO0lBQzlELGdCQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzNELGdCQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFckQsZ0JBQWdCLElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLEdBQUcsR0FBRyxDQUFDO0lBQzlELGdCQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzNELGdCQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFckQsZ0JBQWdCLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDOztJQUUxRDtJQUNBLGdCQUFnQixJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxHQUFHLEdBQUcsQ0FBQztJQUM5RCxnQkFBZ0IsSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRyxnQkFBZ0IsSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRXJELGdCQUFnQixJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxHQUFHLEdBQUcsQ0FBQztJQUM5RCxnQkFBZ0IsSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRyxnQkFBZ0IsSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRXJELGdCQUFnQixJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxHQUFHLEdBQUcsQ0FBQztJQUM5RCxnQkFBZ0IsSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRyxnQkFBZ0IsSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRXJELGdCQUFnQixJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQzs7SUFFMUQ7SUFDQSxnQkFBZ0IsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxHQUFHLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQztJQUNuRSxnQkFBZ0IsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLFVBQVUsSUFBSSxHQUFHLENBQUM7O0lBRWxFO0lBQ0EsZ0JBQWdCLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssR0FBRyxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUM7SUFDbkUsZ0JBQWdCLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxVQUFVLElBQUksR0FBRyxDQUFDOztJQUVsRTtJQUNBLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDL0MsWUFBWTtJQUNaO0lBQ0E7SUFDQSxZQUFZLE1BQU0sR0FBRyxNQUFNLEVBQUUsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDOztJQUVsRDtJQUNBO0lBQ0EsWUFBWSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUN0RCxnQkFBZ0IsTUFBTSxLQUFLLEdBQUcsQ0FBQyxHQUFHLEdBQUc7O0lBRXJDLGdCQUFnQixNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssR0FBRyxHQUFHLENBQUMsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLEdBQUcsR0FBRyxDQUFDLENBQUM7SUFDcEcsZ0JBQWdCLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQztJQUNwQyxZQUFZO0lBQ1o7SUFDQSxZQUFZLE9BQU8sQ0FBQyxDQUFDLEdBQUcsTUFBTTs7SUFFOUIsWUFBWSxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUU7SUFDdEQsZ0JBQWdCLE1BQU0sSUFBSSxLQUFLLENBQUMsaUNBQWlDLENBQUM7SUFDbEUsWUFBWTs7SUFFWjtJQUNBLFlBQVksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxzQkFBc0IsQ0FBQztJQUMzRCxZQUFZLFdBQVcsQ0FBQyxDQUFDLEdBQUcsTUFBTSxVQUFVLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQzs7SUFFdEY7SUFDQSxZQUFZLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUM7SUFDMUQsWUFBWSxXQUFXLENBQUMsQ0FBQyxHQUFHLE1BQU0sV0FBVyxDQUFDLGNBQWMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDOztJQUU3RjtJQUNBLFlBQVksV0FBVyxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRWhHO0lBQ0EsWUFBWSxJQUFJLFdBQVcsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLEVBQUU7SUFDL0QsZ0JBQWdCLE1BQU0sSUFBSSxLQUFLLENBQUMscUNBQXFDLENBQUM7SUFDdEUsWUFBWTs7SUFFWixZQUFZLE9BQU8sT0FBTyxDQUFDLENBQUM7SUFDNUIsUUFBUTs7SUFFUixRQUFRLGVBQWUsU0FBUyxHQUFHO0lBQ25DLFlBQVksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyw4QkFBOEIsQ0FBQzs7SUFFbkUsWUFBWSxPQUFPLENBQUMsRUFBRSxHQUFHLElBQUksU0FBUyxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUM7SUFDbkQsWUFBWSxPQUFPLENBQUMsR0FBRyxHQUFHLElBQUksU0FBUyxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUM7O0lBRXBEO0lBQ0EsWUFBWSxJQUFJLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRztJQUM5QixZQUFZLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUMxRCxnQkFBZ0IsSUFBSSxNQUFNLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxNQUFNLEtBQUssQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLGtCQUFrQixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDOztJQUUzSCxnQkFBZ0IsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUM7O0lBRS9DLGdCQUFnQixNQUFNLENBQUMsR0FBRyxXQUFXLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzVELGdCQUFnQixNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRTNIO0lBQ0E7SUFDQSxnQkFBZ0IsTUFBTSxTQUFTLEdBQUcsV0FBVyxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzlGLGdCQUFnQixJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxTQUFTLENBQUM7SUFDN0QsZ0JBQWdCLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLFNBQVMsQ0FBQzs7SUFFL0MsZ0JBQWdCLE9BQU8sQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDO0lBQzNDLGdCQUFnQixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQzs7SUFFN0M7SUFDQSxnQkFBZ0IsS0FBSyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQztJQUMzRCxZQUFZOztJQUVaO0lBQ0EsWUFBWSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDO0lBQzVELFlBQVksV0FBVyxDQUFDLEVBQUUsR0FBRyxNQUFNLFVBQVUsQ0FBQyxlQUFlLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDOztJQUV4RjtJQUNBLFlBQVksV0FBVyxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDOztJQUVqRTtJQUNBLFlBQVksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyx3QkFBd0IsQ0FBQztJQUM3RCxZQUFZLFdBQVcsQ0FBQyxHQUFHLEdBQUcsTUFBTSxVQUFVLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQzs7SUFFMUY7SUFDQSxZQUFZLFdBQVcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUM7O0lBRS9DO0lBQ0EsWUFBWSxJQUFJLFdBQVcsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLEVBQUU7SUFDaEUsZ0JBQWdCLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLENBQUM7SUFDdkUsWUFBWTs7SUFFWixZQUFZLE9BQU8sT0FBTyxDQUFDLEVBQUU7SUFDN0IsWUFBWSxPQUFPLE9BQU8sQ0FBQyxHQUFHO0lBQzlCLFlBQVksT0FBTyxXQUFXLENBQUMsR0FBRztJQUNsQyxRQUFROztJQUVSLFFBQVEsZUFBZSxTQUFTLEdBQUc7SUFDbkMsWUFBWSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLDhCQUE4QixDQUFDOztJQUVuRSxZQUFZLE9BQU8sQ0FBQyxFQUFFLEdBQUcsSUFBSSxTQUFTLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQztJQUNuRCxZQUFZLE9BQU8sQ0FBQyxHQUFHLEdBQUcsSUFBSSxTQUFTLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQzs7SUFFcEQ7SUFDQSxZQUFZLElBQUksS0FBSyxHQUFHLEVBQUUsQ0FBQyxHQUFHO0lBQzlCLFlBQVksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzFELGdCQUFnQixJQUFJLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLE1BQU0sS0FBSyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsa0JBQWtCLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRTNILGdCQUFnQixNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztJQUMvQyxnQkFBZ0IsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDOUQsZ0JBQWdCLE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDOztJQUVqRCxnQkFBZ0IsTUFBTSxDQUFDLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO0lBQ3hELGdCQUFnQixNQUFNLENBQUMsR0FBRyxXQUFXLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7SUFDeEQsZ0JBQWdCLE1BQU0sQ0FBQyxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUN4RCxnQkFBZ0IsTUFBTSxDQUFDLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO0lBQ3hELGdCQUFnQixNQUFNLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEtBQUssSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQzs7SUFFN0csZ0JBQWdCLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMzSCxnQkFBZ0IsTUFBTSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOztJQUU5SCxnQkFBZ0IsTUFBTSxNQUFNLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO0lBQ2xFLGdCQUFnQixNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7SUFDbEUsZ0JBQWdCLE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQzs7SUFFbEU7SUFDQTtJQUNBOztJQUVBO0lBQ0EsZ0JBQWdCLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUM7O0lBRTVELGdCQUFnQixJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUM7SUFDMUMsZ0JBQWdCLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDOztJQUVuRCxnQkFBZ0IsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzNELGdCQUFnQixHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFbkQsZ0JBQWdCLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMzRCxnQkFBZ0IsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRW5ELGdCQUFnQixJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2pFLGdCQUFnQixJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLEVBQUUsR0FBRyxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQ25FOztJQUVBO0lBQ0EsZ0JBQWdCLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNwRSxnQkFBZ0IsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRW5ELGdCQUFnQixJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxD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QUNyQixRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUc7SUFDNUIsUUFBUSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3BDLFlBQVksS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDMUQsUUFBUTs7SUFFUixRQUFRLEtBQUssQ0FBQyxFQUFFLEdBQUcsRUFBRTtJQUNyQixRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUc7SUFDNUIsUUFBUSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3BDLFlBQVksS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDMUQsUUFBUTs7SUFFUixRQUFRLEtBQUssQ0FBQyxFQUFFLEdBQUcsRUFBRTtJQUNyQixRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUc7SUFDNUIsUUFBUSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFO0lBQzdCLFFBQVEsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7O0lBRXhDO0lBQ0EsUUFBUSxLQUFLLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDckIsUUFBUSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksR0FBRyxFQUFFO0lBQzFCLFFBQVEsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLE1BQU0sQ0FBQztJQUM3RCxRQUFRLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDcEMsWUFBWSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEUsUUFBUTs7SUFFUjtJQUNBLFFBQVEsS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBQ3JCLFFBQVEsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEdBQUcsRUFBRTtJQUMxQixRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdEQsUUFBUSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3BDLFlBQVksS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BFLFFBQVE7O0lBRVI7SUFDQSxRQUFRLEtBQUssQ0FBQyxFQUFFLEdBQUcsRUFBRTtJQUNyQixRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxHQUFHLEVBQUU7SUFDMUIsUUFBUSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQztJQUM1RCxRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNoRSxRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFaEUsUUFBUSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksR0FBRyxFQUFFO0lBQzFCO0lBQ0E7SUFDQSxRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUM1RCxRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNoRSxRQUFRLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFaEU7SUFDQSxRQUFRLFVBQVUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7O0lBRTdFLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQzs7SUFFbkY7SUFDQSxRQUFRLFdBQVcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQztJQUM5RSxRQUFRLFdBQVcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQztJQUM5RSxRQUFRLFdBQVcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQztJQUM5RSxRQUFRLFdBQVcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQztJQUM5RSxRQUFRLFdBQVcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQzs7SUFFOUU7SUFDQSxRQUFRLE1BQU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RyxRQUFRLE1BQU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RyxRQUFRLE1BQU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RyxRQUFRLE1BQU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RyxRQUFRLE1BQU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFekc7SUFDQSxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsMkJBQTJCLENBQUM7SUFDNUQsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDekUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDekUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDekUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDekUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDekUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDN0UsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDN0UsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDN0UsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdkUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdkUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdkUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7O0lBRXZFLFFBQVEsVUFBVSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDekUsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDM0UsUUFBUSxLQUFLLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDM0UsSUFBSTs7SUFFSixJQUFJLGVBQWUsTUFBTSxHQUFHO0lBQzVCLFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyw2QkFBNkIsQ0FBQztJQUM5RDtJQUNBLFFBQVEsTUFBTSxVQUFVLEdBQUcsSUFBSSxtQkFBbUIsQ0FBQyxLQUFLLENBQUM7SUFDekQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUM7SUFDL0MsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDeEQsUUFBUSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDeEQsUUFBUSxVQUFVLENBQUMsS0FBSyxHQUFHLFVBQVUsQ0FBQyxZQUFZLEVBQUU7SUFDcEQsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLHdCQUF3QixHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDOztJQUV6RjtJ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Q0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzFGLG9CQUFvQixLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDMUYsb0JBQW9CLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUMxRixvQkFBb0IsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3hFLG9CQUFvQixLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQztJQUNqRixRQUFROztJQUVSLFFBQVEsZUFBZSxXQUFXLEdBQUc7SUFDckMsWUFBWSxXQUFXLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQyxrQkFBa0I7SUFDNUQsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3ZGLG9CQUFvQixLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDeEUsb0JBQW9CLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDO0lBQ2pGLFFBQVE7SUFDUixJQUFJOztJQUVKLElBQUksU0FBUywyQkFBMkIsR0FBRztJQUMzQztJQUNBLFFBQVEsSUFBSSxHQUFHLEdBQUcsVUFBVSxDQUFDLEVBQUU7SUFDL0IsUUFBUSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUM3QyxZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztJQUNoQyxRQUFRO0lBQ1IsUUFBUSxTQUFTLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQzs7SUFFN0M7SUFDQTs7SUFFQTtJQUNBLFFBQVEsV0FBVyxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQzs7SUFFbEUsUUFBUSxXQUFXLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDOztJQUVsRSxRQUFRLFdBQVcsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDOztJQUVoSDtJQUNBLFFBQVEsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQzs7SUFFOUMsUUFBUSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRztJQUN0QixRQUFRLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDdkMsWUFBWSxTQUFTLENBQUMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2hHLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzNDLFFBQVE7O0lBRVIsUUFBUSxJQUFJLGNBQWMsR0FBRyxFQUFFLENBQUMsR0FBRztJQUNuQyxRQUFRLEtBQUssTUFBTSxPQUFPLElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRTtJQUN4RCxZQUFZLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRTtJQUN2QyxnQkFBZ0IsS0FBSyxNQUFNLFVBQVUsSUFBSSxPQUFPLEVBQUU7SUFDbEQsb0JBQW9CLGNBQWMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLGNBQWMsRUFBRSxVQUFVLENBQUM7SUFDdkUsZ0JBQWdCO0lBQ2hCLFlBQVksQ0FBQyxNQUFNO0lBQ25CLGdCQUFnQixjQUFjLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxjQUFjLEVBQUUsT0FBTyxDQUFDO0lBQ2hFLFlBQVk7SUFDWixRQUFRO0lBQ1IsUUFBUSxPQUFPLEVBQUUsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDOztJQUVyQztJQUNBLFFBQVEsU0FBUyxXQUFXLENBQUMsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFO0lBQ3pELFlBQVksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUU7SUFDL0IsWUFBWSxNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsTUFBTTtJQUNwQztJQUNBLFlBQVksTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNyRTtJQUNBLFlBQVksTUFBTSxFQUFFLEdBQUcsRUFBRTtJQUN6QixZQUFZLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDMUMsZ0JBQWdCLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDO0lBQ3pELGdCQUFnQixNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEQ7SUFDQSxnQkFBZ0IsU0FBUyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxJQUFJLENBQUM7SUFDakYsWUFBWTtJQUNaO0lBQ0EsWUFBWSxPQUFPLEVBQUU7SUFDckIsUUFBUTs7SUFFUixRQUFRLFNBQVMsV0FBVyxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRTtJQUN6RCxZQUFZLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFO0lBQy9CLFlBQVksTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLE1BQU07SUFDcEM7SUFDQSxZQUFZLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDckU7SUFDQSxZQUFZLE1BQU0sRUFBRSxHQUFHLEVBQUU7SUFDekIsWUFBWSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQzFDLGdCQUFnQixNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsQ0FBQztJQUN6RCxnQkFBZ0IsTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2hEO0lBQ0EsZ0JBQWdCLFNBQVMsQ0FBQyxDQUFDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDOztJQUVqRixZQUFZO0lBQ1o7SUFDQSxZQUFZLE9BQU8sRUFBRTtJQUNyQixRQUFROztJQUVSLFFBQVEsU0FBUyxXQUFXLENBQUMsU0FBUyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFO0lBQ3hFLFlBQVksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUU7SUFDL0I7SUFDQSxZQUFZLE1BQU0sRUFBRSxHQUFHLEVBQUU7SUFDekI7SUFDQSxZQUFZLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0MsWUFBWSxNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxHQUFHLENBQUM7SUFDNUMsWUFBWSxJQUFJLElBQUksR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxRQUFRLENBQUM7SUFDN0MsWUFBWSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3hDLGdCQUFnQixNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDMUMsZ0JBQWdCLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqRDtJQUNBLGdCQUFnQixTQUFTLENBQUMsQ0FBQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNoRjtJQUNBLFlBQVk7SUFDWjtJQUNBLFlBQVksTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNoRCxZQUFZLE1BQU0sUUFBUSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQztJQUM1QyxZQUFZLElBQUksR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxRQUFRLENBQUM7SUFDekMsWUFBWSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ3hDLGdCQUFnQixNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDM0MsZ0JBQWdCLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsRDtJQUNBLGdCQUFnQixTQUFTLENBQUMsQ0FBQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNyRixZQUFZO0lBQ1o7SUFDQSxZQUFZLE9BQU8sRUFBRTtJQUNyQixRQUFRO0lBQ1IsSUFBSTtJQUNKOztJQ3J3Q0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7O0lBS0EsTUFBTSxxQkFBQ3hELG9CQUFrQixDQUFDLEdBQUcsS0FBSzs7SUFFbkIsZUFBZSxlQUFlLENBQUMsTUFBTSxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUU7SUFDMUgsSUFBSSxNQUFNLEtBQUssR0FBR0Esb0JBQWtCLENBQUMsTUFBTSxDQUFDOztJQUU1QyxJQUFJLE1BQU0sSUFBSSxFQUFFLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQzs7SUFFN0I7SUFDQSxJQUFJLE1BQU00RCxhQUFjLENBQUMsS0FBSyxFQUFFLFlBQVksRUFBRSxJQUFJLEVBQUUsZUFBZSxDQUFDOztJQUVwRTtJQUNBLElBQUksT0FBTyxNQUFNLFdBQVcsQ0FBQyxZQUFZLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxhQUFhLENBQUM7SUFDdkU7O0lDaENBO0lBQ0E7O0lBRUE7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQTtJQUNBOzs7SUFRQSxNQUFNLHNCQUFFNUQsb0JBQWtCLEVBQUUsR0FBRyxLQUFLOztJQUVyQixlQUFlLFlBQVksQ0FBQyxZQUFZLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUU7SUFDekYsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDOztJQUV0RCxJQUFJLFlBQVksR0FBR0Esb0JBQWtCLENBQUMsWUFBWSxDQUFDO0lBQ25ELElBQUksTUFBTSxHQUFHQSxvQkFBa0IsQ0FBQyxNQUFNLENBQUM7O0lBRXZDLElBQUksTUFBTSxLQUFLLEdBQUcsTUFBTThELGdCQUF1QixDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUM7O0lBRW5FLElBQUksTUFBTSxFQUFFLEdBQUcsWUFBWSxDQUFDLEtBQUssRUFBRSxZQUFZLENBQUM7O0lBRWhEOztJQUVBLElBQUksTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQztJQUMxQyxJQUFJLEtBQUssQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDOztJQUVqQyxJQUFJLE1BQU0sYUFBYSxHQUFHOUQsb0JBQWtCLENBQUMsY0FBYyxDQUFDOztJQUU1RCxJQUFJLElBQUksYUFBYSxDQUFDLE1BQU0sS0FBSyxFQUFFLENBQUMsT0FBTyxFQUFFO0lBQzdDLFFBQVEsTUFBTSxDQUFDLEtBQUssQ0FBQyxpREFBaUQsQ0FBQztJQUN2RSxRQUFRLE9BQU8sS0FBSztJQUNwQixJQUFJOztJQUVKLElBQUksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUU7O0lBRXZCLElBQUksSUFBSSxNQUFNLEVBQUU7SUFDaEIsUUFBUSxNQUFNLENBQUMsSUFBSSxDQUFDLDhCQUE4QixDQUFDO0lBQ25ELFFBQVEsTUFBTSxDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQztJQUMvQyxRQUFRLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxpQkFBaUIsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNyRCxRQUFRLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxpQkFBaUIsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNuRCxRQUFRLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDeEQsUUFBUSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDckQsUUFBUSxNQUFNLENBQUMsSUFBSSxDQUFDLDhCQUE4QixDQUFDO0lBQ25ELElBQUk7O0lBRUo7SUFDQSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMscUNBQXFDLENBQUM7SUFDbEUsSUFBSSxJQUFJLENBQUMscUJBQXFCLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsRUFBRTtJQUNsRCxRQUFRLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsaUNBQWlDLENBQUM7SUFDbkUsUUFBUSxPQUFPLEtBQUs7SUFDcEIsSUFBSTs7SUFFSjtJQUNBLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxvQ0FBb0MsQ0FBQztJQUNqRSxJQUFJLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEVBQUU7SUFDNUMsUUFBUSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxDQUFDO0lBQ3BFLFFBQVEsT0FBTyxLQUFLO0lBQ3BCLElBQUk7O0lBRUo7SUFDQSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsc0NBQXNDLENBQUM7SUFDbkUsSUFBSSxJQUFJLENBQUMsb0JBQW9CLENBQUMsS0FBSyxFQUFFLGFBQWEsQ0FBQyxFQUFFO0lBQ3JELFFBQVEsSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQztJQUNoRSxRQUFRLE9BQU8sS0FBSztJQUNwQixJQUFJOztJQUVKO0lBQ0E7SUFDQSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0JBQXdCLENBQUM7SUFDckQsSUFBSSxNQUFNLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxHQUFHLGlCQUFpQixDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLGFBQWEsRUFBRSxNQUFNLENBQUM7O0lBRTVGO0lBQ0EsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLGdEQUFnRCxDQUFDO0lBQzdFLElBQUksVUFBVSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQztJQUNsRCxJQUFJLFVBQVUsQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDOztJQUU1QztJQUNBLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxrQ0FBa0MsQ0FBQztJQUMvRCxJQUFJLE1BQU0sYUFBYSxHQUFHLE1BQU0sMEJBQTBCLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxFQUFFLENBQUM7O0lBRWpGO0lBQ0EsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLHlDQUF5QyxDQUFDO0lBQ3RFLElBQUksTUFBTSxFQUFFLEdBQUcsV0FBVyxDQUFDLEtBQUssRUFBRSxhQUFhLEVBQUUsYUFBYSxDQUFDOztJQUUvRDtJQUNBLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQztJQUNoRCxJQUFJLE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQyxLQUFLLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDOztJQUVqRTtJQUNBLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQztJQUNoRCxJQUFJLE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQyxLQUFLLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQzs7SUFFckU7SUFDQSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUM7SUFDaEQsSUFBSSxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsYUFBYSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDOztJQUV2RixJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDO0lBQzVDLElBQUksTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxLQUFLLENBQUM7O0lBRTNELElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUM7SUFDNUMsSUFBSSxNQUFNLENBQUMsR0FBRyxRQUFRLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDOztJQUVoRSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDO0lBQzVDLElBQUksTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsVUFBVSxDQUFDOztJQUVoRCxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsMkNBQTJDLENBQUM7SUFDeEUsSUFBSSxNQUFNLEdBQUcsR0FBRyxNQUFNLGNBQWMsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7O0lBRTNFLElBQUksSUFBSSxNQUFNLEVBQUU7SUFDaEIsUUFBUSxJQUFJLEdBQUcsRUFBRTtJQUNqQixZQUFZLE1BQU0sQ0FBQyxJQUFJLENBQUMsNkJBQTZCLENBQUM7SUFDdEQsUUFBUSxDQUFDLE1BQU07SUFDZixZQUFZLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDO0lBQ3hDLFFBQVE7SUFDUixJQUFJOztJQUVKLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQzs7SUFFdkQsSUFBSSxPQUFPLEdBQUc7O0lBRWQ7O0lBRUEsU0FBUyxZQUFZLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtJQUNqQyxJQUFJLE1BQU0sR0FBRyxHQUFHLEVBQUU7SUFDbEIsSUFBSSxHQUFHLENBQUMsRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDdkMsSUFBSSxHQUFHLENBQUMsRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDdkMsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDckM7SUFDQSxJQUFJLEdBQUcsQ0FBQyxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN2QyxJQUFJLEdBQUcsQ0FBQyxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN2QyxJQUFJLEdBQUcsQ0FBQyxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN2QyxJQUFJLEdBQUcsQ0FBQyxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN2QyxJQUFJLEdBQUcsQ0FBQyxHQUFHLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQztJQUN6QyxJQUFJLEdBQUcsQ0FBQyxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN2QyxJQUFJLE9BQU8sR0FBRztJQUNkOztJQUVBLFNBQVMscUJBQXFCLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUU7SUFDakQsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTtJQUN2QixJQUFJLE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUU7SUFDMUMsV0FBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRTtJQUMxQyxXQUFXLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFO0lBQzFDLFdBQVcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUU7SUFDMUMsV0FBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDNUI7O0lBRUEsU0FBUyx1QkFBdUIsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFO0lBQy9DLElBQUksT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQzVEOztJQUVBLFNBQVMsc0JBQXNCLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRTtJQUNuRCxJQUFJLE9BQU8sdUJBQXVCLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDdkU7O0lBRUEsU0FBUyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFO0lBQzNDLElBQUksT0FBTyxzQkFBc0IsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFO0lBQzdELFdBQVcsc0JBQXNCLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRTtJQUM3RCxXQUFXLHNCQUFzQixDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUU7SUFDN0QsV0FBVyxzQkFBc0IsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFO0lBQzdELFdBQVcsc0JBQXNCLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRTtJQUM3RCxXQUFXLHNCQUFzQixDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUU7SUFDN0QsV0FBVyxzQkFBc0IsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFO0lBQzdELFdBQVcsc0JBQXNCLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRTtJQUM3RCxXQUFXLHNCQUFzQixDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDNUQsV0FBVyxzQkFBc0IsQ0FBQyxL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QyxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDaEMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUNoQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ2hDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDaEMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUNoQyxJQUFJLElBQUksRUFBRSxHQUFHLEVBQUU7SUFDZixJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRTtJQUNqQixJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDNUIsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUNoQyxJQUFJLElBQUksRUFBRSxHQUFHLEVBQUU7SUFDZixJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRTtJQUNqQixJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7O0lBRTVCO0lBQ0E7SUFDQTs7SUFFQTtJQUNBLElBQUksS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBQ2pCLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEdBQUcsRUFBRTtJQUN0QixJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQztJQUM5QyxJQUFJLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDaEMsUUFBUSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRCxJQUFJOztJQUVKO0lBQ0EsSUFBSSxLQUFLLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDakIsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksR0FBRyxFQUFFO0lBQ3RCLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsRCxJQUFJLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDaEMsUUFBUSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRCxJQUFJOztJQUVKO0lBQ0EsSUFBSSxLQUFLLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFDakIsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksR0FBRyxFQUFFO0lBQ3RCLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUM7SUFDeEQsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RCxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDOztJQUV0RCxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxHQUFHLEVBQUU7SUFDdEI7SUFDQTtJQUNBLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ3RELElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdEQsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFdEQ7SUFDQSxJQUFJLFVBQVUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDekUsSUFBSSxVQUFVLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQzs7SUFFMUQsSUFBSSxVQUFVLENBQUMsR0FBRyxHQUFHLFVBQVUsQ0FBQyxFQUFFO0lBQ2xDLElBQUksRUFBRSxDQUFDLFVBQVUsR0FBRyxDQUFDO0lBQ3JCLElBQUksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDdkMsUUFBUSxVQUFVLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztJQUNsRCxRQUFRLEVBQUUsQ0FBQyxVQUFVLElBQUksQ0FBQztJQUMxQixJQUFJOztJQUVKLElBQUksVUFBVSxDQUFDLEtBQUssRUFBRTtJQUN0QixJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO0lBQ2hDLElBQUksVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztJQUM5QyxJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7SUFDOUMsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO0lBQzlDLElBQUksVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztJQUM5QyxJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7SUFDOUMsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO0lBQzlDLElBQUksVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztJQUM5QyxJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7SUFDOUMsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBQzdDLElBQUksVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztJQUM3QyxJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFDN0MsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBQzdDLElBQUksVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztJQUM5QyxJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUM7SUFDL0MsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDO0lBQy9DLElBQUksVUFBVSxDQUFDLEtBQUssR0FBRyxVQUFVLENBQUMsWUFBWSxFQUFFOztJQUVoRCxJQUFJLFVBQVUsQ0FBQyxLQUFLLEVBQUU7SUFDdEIsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUM7SUFDMUMsSUFBSSxVQUFVLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7SUFDckQsSUFBSSxVQUFVLENBQUMsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxZQUFZLEVBQUU7O0lBRTVDLElBQUksSUFBSSxNQUFNLEVBQUU7SUFDaEIsUUFBUSxNQUFNLENBQUMsSUFBSSxDQUFDLHdCQUF3QixHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzVFLFFBQVEsTUFBTSxDQUFDLElBQUksQ0FBQyx3QkFBd0IsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM3RSxRQUFRLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0JBQXdCLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDMUUsUUFBUSxNQUFNLENBQUMsSUFBSSxDQUFDLHdCQUF3QixHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzdFLFFBQVEsTUFBTSxDQUFDLElBQUksQ0FBQyx3QkFBd0IsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RSxJQUFJOztJQUVKLElBQUksT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRTtJQUNuRDs7SUFFQSxlQUFlLDBCQUEwQixDQUFDLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFO0lBQ2pFLElBQUksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUU7O0lBRXZCLElBQUksTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQztJQUN4QyxJQUFJLE1BQU0sTUFBTSxHQUFHLElBQUksU0FBUyxDQUFDLElBQUksR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQzlDLElBQUksSUFBSSxNQUFNLEdBQUcsSUFBSSxTQUFTLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUM7O0lBRTVDLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUc7SUFDbEIsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ25DLFFBQVEsTUFBTSxLQUFLLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFO0lBQy9CLFFBQVEsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDO0lBQ25ELFFBQVEsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQztJQUNoRixRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzNCLElBQUk7O0lBRUosSUFBSSxNQUFNLEdBQUcsTUFBTSxFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQzs7SUFFMUMsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFO0lBQ2QsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ25DLFFBQVEsTUFBTSxLQUFLLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFO0lBQy9CLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNqRyxJQUFJO0lBQ0osSUFBSSxPQUFPLENBQUM7SUFDWjs7SUFFQSxTQUFTLFdBQVcsQ0FBQyxLQUFLLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFBRTtJQUMxRCxJQUFJLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFOztJQUV2QixJQUFJLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJO0lBQ3BCLElBQUksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDbkQsUUFBUSxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4QyxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxhQUFhLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEQsSUFBSTtJQUNKLElBQUksT0FBTyxFQUFFO0lBQ2I7O0lBRUEsU0FBUyxTQUFTLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRTtJQUM1RCxJQUFJLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFOztJQUV2QixJQUFJLE1BQU0sRUFBRSxHQUFHLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUM7O0lBRXJGOztJQUVBO0lBQ0EsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDOztJQUVsRCxJQUFJLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJO0lBQ3JCLElBQUksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNoQyxRQUFRLElBQUksVUFBVSxHQUFHLEVBQUU7SUFDM0IsUUFBUSxVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3hDLFFBQVEsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNwQyxZQUFZLFVBQVUsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkUsUUFBUTs7SUFFUixRQUFRLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRixRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BFLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEUsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNwRSxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BFLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEUsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFcEUsUUFBUSxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUMsSUFBSTs7SUFFSixJQUFJLE9BQU8sR0FBRztJQUNkOztJQUVBLFNBQVMsU0FBUyxDQUFDLEtBQUssRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFO0lBQ2hFLElBQUksTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEVBQUU7O0lBRXZCLElBQUksTUFBTSxFQUFFLEdBQUcsbUJBQW1CLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQzs7SUFFckY7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUM7SUFDbkQsSUFBSSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBQzlELElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ25HLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztJQUN6QyxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDdkIsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFckM7SUFDQSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsbUNBQW1DLENBQUM7O0lBRWhFLElBQUksSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUk7SUFDckIsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2hDLFFBQVEsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3BDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RSxRQUFRLE1BQU0sV0FBVyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkQsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqRSxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7O0lBRTFFLFFBQVEsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzVDLElBQUk7O0lBRUosSUFBSSxPQUFPLEdBQUc7SUFDZDs7SUFFQSxTQUFTLFNBQVMsQ0FBQyxLQUFLLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUU7SUFDM0UsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTs7SUFFdkIsSUFBSSxNQUFNLElBQUksR0FBRyxtQkFBbUIsQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDOztJQUV4SDtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxzQkFBc0IsQ0FBQztJQUNuRCxJQUFJLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQztJQUNoRCxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxTQUFTLENBQUM7SUFDOUIsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQzs7SUFFckM7SUFDQSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUM7SUFDbkQsSUFBSSxNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLEVBQUUsQ0FBQztJQUN6RCxJQUFJLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlFLElBQUksTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDN0YsSUFBSSxNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM3RixJQUFJLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFN0UsSUFBSSxNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3JILElBQUksTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNySCxJQUFJLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDckgsSUFBSSxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7O0lBRTlFLElBQUksSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDO0lBQzdCLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUM7O0lBRXJDO0lBQ0EsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLG1DQUFtQyxDQUFDO0lBQ2hFLElBQUksSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUk7SUFDckIsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2hDLFFBQVEsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDOztJQUVoRSxRQUFRLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QyxJQUFJOztJQUVKLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsQ0FBQztJQUNoRSxJQUFJLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDaEMsUUFBUSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM5RixRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDOztJQUVuRixRQUFRLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEQsSUFBSTs7SUFFSixJQUFJLE9BQU8sR0FBRztJQUNkOztJQUVBLFNBQVMsUUFBUSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUU7SUFDdkQsSUFBSSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRTtJQUN2QixJQUFJLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxFQUFFOztJQUV2QixJQUFJLElBQUksS0FBSyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RCxJQUFJLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDaEMsUUFBUSxLQUFLLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckUsSUFBSTs7SUFFSixJQUFJLFVBQVUsQ0FBQyxJQUFJLEdBQUcsS0FBSzs7SUFFM0IsSUFBSSxJQUFJLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdEQsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2hDLFFBQVEsS0FBSyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JFLElBQUk7O0lBRUosSUFBSSxJQUFJLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdEQsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2hDLFFBQVEsS0FBSyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JFLElBQUk7SUFDSixJQUFJLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7SUFDaEMsUUFBUSxLQUFLLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckUsSUFBSTs7SUFFSixJQUFJLFVBQVUsQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ3pFLElBQUksVUFBVSxDQUFDLFNBQVMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDOztJQUVwRixJQUFJLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLFNBQVMsQ0FBQztJQUNuRSxJQUFJLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLFNBQVMsQ0FBQzs7SUFFbkUsSUFBSSxPQUFPLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENB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QyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDOztJQUVoRCxJQUFJLElBQUksSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZFLElBQUksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUNsQyxRQUFRLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUNsRCxRQUFRLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFL0MsUUFBUSxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQzs7SUFFbkQsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDO0lBQ2hDLElBQUk7O0lBRUosSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENB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QyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEUsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEcsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEcsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0YsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDN0YsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEcsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ3RDLElBQUksQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUNqQjs7SUN0REE7SUFDQTs7SUFFQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7SUFDQTs7SUFFQTtJQUNBO0lBQ0E7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7IiwieF9nb29nbGVfaWdub3JlTGlzdCI6WzcsOCw5LDEwLDE3LDE4LDE5LDIwLDIxLDIyLDQ0LDQ1LDQ2LDQ3LDQ4LDQ5LDc1XX0= diff --git a/build/snarkjs.min.js b/build/snarkjs.min.js index 77c7aac4..7640ee06 100644 --- a/build/snarkjs.min.js +++ b/build/snarkjs.min.js @@ -1 +1,227 @@ -var snarkjs=function(A){"use strict";const t=[0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4];function i(A,t){return t&&10!=t?16==t?"0x"==A.slice(0,2)?BigInt(A):BigInt("0x"+A):void 0:BigInt(A)}const I=i;function g(A){const i=A.toString(16);return 4*(i.length-1)+t[parseInt(i[0],16)]}function e(A){return BigInt(A)>BigInt(t)}const Q=a,B=C;function o(A){return(BigInt(A)&BigInt(1))==BigInt(1)}function s(A){let t=BigInt(A);const i=[];for(;t;)t&BigInt(1)?i.push(1):i.push(0),t>>=BigInt(1);return i}function r(A){if(A>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("Number too big");return Number(A)}function E(A,t){return BigInt(A)+BigInt(t)}function f(A,t){return BigInt(A)-BigInt(t)}function w(A){return-BigInt(A)}function h(A,t){return BigInt(A)*BigInt(t)}function l(A,t){return BigInt(A)**BigInt(t)}function c(A,t){return BigInt(A)/BigInt(t)}function D(A,t){return BigInt(A)%BigInt(t)}function u(A,t){return BigInt(A)==BigInt(t)}function d(A,t){return BigInt(A)>BigInt(t)}function y(A,t){return BigInt(A)>=BigInt(t)}function p(A,t){return BigInt(A)&BigInt(t)}function m(A,t,i,I){const g="0000000"+i.toString(16),e=new Uint32Array(A.buffer,A.byteOffset+t,I/4),n=1+(4*(g.length-7)-1>>5);for(let A=0;A>5);for(let A=0;Ae[e.length-t-1]=A.toString(16).padStart(8,"0")),i(e.join(""),16)}function N(A,t,I){I=I||A.byteLength,t=t||0;const g=new DataView(A.buffer,A.byteOffset+t,I),e=new Array(I/4);for(let A=0;A=0?BigInt(A):-BigInt(A)},add:E,band:p,bitLength:g,bits:s,bor:function(A,t){return BigInt(A)|BigInt(t)},bxor:function(A,t){return BigInt(A)^BigInt(t)},div:c,e:I,eq:u,exp:function(A,t){return BigInt(A)**BigInt(t)},fromArray:function(A,t){let i=BigInt(0);t=BigInt(t);for(let I=0;I>=BigInt(1)}return i},neg:w,neq:function(A,t){return BigInt(A)!=BigInt(t)},one:M,pow:l,shiftLeft:a,shiftRight:C,shl:Q,shr:B,square:function(A){return BigInt(A)*BigInt(A)},sub:f,toArray:function(A,t){const i=[];let I=BigInt(A);for(t=BigInt(t);I;)i.unshift(Number(I%t)),I/=t;return i},toLEBuff:L,toNumber:r,toRprBE:F,toRprLE:m,toString:U,zero:b});function S(A,t,i){if(n(i))return A.one;const I=s(i);if(0==I.length)return A.one;let g=t;for(let i=I.length-2;i>=0;i--)g=A.square(g),I[i]&&(g=A.mul(g,t));return g}function k(A){if(A.m%2==1)if(u(D(A.p,4),1))if(u(D(A.p,8),1))if(u(D(A.p,16),1))!function(A){A.sqrt_q=l(A.p,A.m),A.sqrt_s=0,A.sqrt_t=f(A.sqrt_q,1);for(;!o(A.sqrt_t);)A.sqrt_s=A.sqrt_s+1,A.sqrt_t=c(A.sqrt_t,2);let t=A.one;for(;A.eq(t,A.one);){const i=A.random();A.sqrt_z=A.pow(i,A.sqrt_t),t=A.pow(A.sqrt_z,2**(A.sqrt_s-1))}A.sqrt_tm1d2=c(f(A.sqrt_t,1),2),A.sqrt=function(A){const t=this;if(t.isZero(A))return t.zero;let i=t.pow(A,t.sqrt_tm1d2);const I=t.pow(t.mul(t.square(i),A),2**(t.sqrt_s-1));if(t.eq(I,t.negone))return null;let g=t.sqrt_s,e=t.mul(A,i),n=t.mul(e,i),a=t.sqrt_z;for(;!t.eq(n,t.one);){let A=t.square(n),I=1;for(;!t.eq(A,t.one);)A=t.square(A),I++;i=a;for(let A=0;A>>0,A[g]=(A[g]^A[t])>>>0,A[g]=(A[g]<<16|A[g]>>>16&65535)>>>0,A[I]=A[I]+A[g]>>>0,A[i]=(A[i]^A[I])>>>0,A[i]=(A[i]<<12|A[i]>>>20&4095)>>>0,A[t]=A[t]+A[i]>>>0,A[g]=(A[g]^A[t])>>>0,A[g]=(A[g]<<8|A[g]>>>24&255)>>>0,A[I]=A[I]+A[g]>>>0,A[i]=(A[i]^A[I])>>>0,A[i]=(A[i]<<7|A[i]>>>25&127)>>>0}function R(A){v(A,0,4,8,12),v(A,1,5,9,13),v(A,2,6,10,14),v(A,3,7,11,15),v(A,0,5,10,15),v(A,1,6,11,12),v(A,2,7,8,13),v(A,3,4,9,14)}class J{constructor(A){A=A||[0,0,0,0,0,0,0,0],this.state=[1634760805,857760878,2036477234,1797285236,A[0],A[1],A[2],A[3],A[4],A[5],A[6],A[7],0,0,0,0],this.idx=16,this.buff=new Array(16)}nextU32(){return 16==this.idx&&this.update(),this.buff[this.idx++]}nextU64(){return E(h(this.nextU32(),4294967296),this.nextU32())}nextBool(){return!(1&~this.nextU32())}update(){for(let A=0;A<16;A++)this.buff[A]=this.state[A];for(let A=0;A<10;A++)R(this.buff);for(let A=0;A<16;A++)this.buff[A]=this.buff[A]+this.state[A]>>>0;this.idx=0,this.state[12]=this.state[12]+1>>>0,0==this.state[12]&&(this.state[13]=this.state[13]+1>>>0,0==this.state[13]&&(this.state[14]=this.state[14]+1>>>0,0==this.state[14]&&(this.state[15]=this.state[15]+1>>>0)))}}var P={};function x(A){let t=new Uint8Array(A);if(P&&P.randomFillSync)P.randomFillSync(t);else if(void 0!==globalThis.crypto&&globalThis.crypto.getRandomValues)for(let i=0;i>>0;return t}let Y=null;function q(){return Y||(Y=new J(function(){const A=x(32),t=new Uint32Array(A.buffer),i=[];for(let A=0;A<8;A++)i.push(t[A]);return i}()),Y)}class Z{constructor(A,t,i){this.F=t,this.G=A,this.opMulGF=i;let I=t.sqrt_t||t.t,g=t.sqrt_s||t.s,e=t.one;for(;t.eq(t.pow(e,t.half),t.one);)e=t.add(e,t.one);this.w=new Array(g+1),this.wi=new Array(g+1),this.w[g]=this.F.pow(e,I),this.wi[g]=this.F.inv(this.w[g]);let n=g-1;for(;n>=0;)this.w[n]=this.F.square(this.w[n+1]),this.wi[n]=this.F.square(this.wi[n+1]),n--;this.roots=[],this._setRoots(Math.min(g,15))}_setRoots(A){for(let t=A;t>=0&&!this.roots[t];t--){let A=this.F.one;const i=1<>1,a=j(A,t,i-1,I,2*g),C=j(A,t,i-1,I+g,2*g),Q=new Array(e);for(let t=0;t>this.one,this.bitLength=g(this.p),this.mask=(this.one<>this.one;this.nqr=this.two;let i=this.pow(this.nqr,t);for(;!this.eq(i,this.negone);)this.nqr=this.nqr+this.one,i=this.pow(this.nqr,t);for(this.s=0,this.t=this.negone;(this.t&this.one)==this.zero;)this.s=this.s+1,this.t=this.t>>this.one;this.nqr_to_t=this.pow(this.nqr,this.t),k(this),this.FFT=new Z(this,this,this.mul.bind(this)),this.fft=this.FFT.fft.bind(this.FFT),this.ifft=this.FFT.ifft.bind(this.FFT),this.w=this.FFT.w,this.wi=this.FFT.wi,this.shift=this.square(this.nqr),this.k=this.exp(this.nqr,2**this.s)}e(A,t){let i;if(t?16==t&&(i=BigInt("0x"+A)):i=BigInt(A),i<0){let A=-i;return A>=this.p&&(A%=this.p),this.p-A}return i>=this.p?i%this.p:i}add(A,t){const i=A+t;return i>=this.p?i-this.p:i}sub(A,t){return A>=t?A-t:this.p-t+A}neg(A){return A?this.p-A:A}mul(A,t){return A*t%this.p}mulScalar(A,t){return A*this.e(t)%this.p}square(A){return A*A%this.p}eq(A,t){return A==t}neq(A,t){return A!=t}lt(A,t){return(A>this.half?A-this.p:A)<(t>this.half?t-this.p:t)}gt(A,t){return(A>this.half?A-this.p:A)>(t>this.half?t-this.p:t)}leq(A,t){return(A>this.half?A-this.p:A)<=(t>this.half?t-this.p:t)}geq(A,t){return(A>this.half?A-this.p:A)>=(t>this.half?t-this.p:t)}div(A,t){return this.mul(A,this.inv(t))}idiv(A,t){if(!t)throw new Error("Division by zero");return A/t}inv(A){if(!A)throw new Error("Division by zero");let t=this.zero,i=this.p,I=this.one,g=A%this.p;for(;g;){let A=i/g;[t,I]=[I,t-A*I],[i,g]=[g,i-A*g]}return t=this.p?i-this.p:i}bor(A,t){const i=(A|t)&this.mask;return i>=this.p?i-this.p:i}bxor(A,t){const i=(A^t)&this.mask;return i>=this.p?i-this.p:i}bnot(A){const t=A^this.mask;return t>=this.p?t-this.p:t}shl(A,t){if(Number(t)=this.p?i-this.p:i}{const i=this.p-t;return Number(i)>i:this.zero}}shr(A,t){if(Number(t)>t;{const i=this.p-t;if(Number(i)=this.p?t-this.p:t}return 0}}land(A,t){return A&&t?this.one:this.zero}lor(A,t){return A||t?this.one:this.zero}lnot(A){return A?this.zero:this.one}sqrt_old(A){if(A==this.zero)return this.zero;if(this.pow(A,this.negone>>this.one)!=this.one)return null;let t=this.s,i=this.nqr_to_t,I=this.pow(A,this.t),g=this.pow(A,this.add(this.t,this.one)>>this.one);for(;I!=this.one;){let A=this.square(I),e=1;for(;A!=this.one;)e++,A=this.square(A);let n=i;for(let A=0;Athis.p>>this.one&&(g=this.neg(g)),g}normalize(A,t){if((A=BigInt(A,t))<0){let t=-A;return t>=this.p&&(t%=this.p),this.p-t}return A>=this.p?A%this.p:A}random(){const A=2*this.bitLength/8;let t=this.zero;for(let i=0;ithis.half&&10==t){i="-"+(this.p-A).toString(t)}else i=A.toString(t);return i}isZero(A){return A==this.zero}fromRng(A){let t;do{t=this.zero;for(let i=0;i=this.p);return t=t*this.Ri%this.p,t}fft(A){return this.FFT.fft(A)}ifft(A){return this.FFT.ifft(A)}toRprLE(A,t,i){m(A,t,i,8*this.n64)}toRprBE(A,t,i){F(A,t,i,8*this.n64)}toRprBEM(A,t,i){return this.toRprBE(A,t,this.mul(this.R,i))}toRprLEM(A,t,i){return this.toRprLE(A,t,this.mul(this.R,i))}fromRprLE(A,t){return G(A,t,this.n8)}fromRprBE(A,t){return N(A,t,this.n8)}fromRprLEM(A,t){return this.mul(this.fromRprLE(A,t),this.Ri)}fromRprBEM(A,t){return this.mul(this.fromRprBE(A,t),this.Ri)}toObject(A){return A}}function T(A,t){let i=A;void 0===t&&0==(t=Math.floor((g(A)-1)/8)+1)&&(t=1);const I=new Uint8Array(t),e=new DataView(I.buffer);let n=0;for(;n>=BigInt(32)):n+2<=t?(e.setUint16(n,Number(i&BigInt(65535)),!0),n+=2,i>>=BigInt(16)):(e.setUint8(n,Number(i&BigInt(255)),!0),n+=1,i>>=BigInt(8));if(i)throw new Error("Number does not fit in this length");return I}const W=[];for(let A=0;A<256;A++)W[A]=V(A,8);function V(A,t){let i=0,I=A;for(let A=0;A>=1;return i}function X(A,t){return(W[A>>>24]|W[A>>>16&255]<<8|W[A>>>8&255]<<16|W[255&A]<<24)>>>32-t}function K(A){return(4294901760&A?(A&=4294901760,16):0)|(4278255360&A?(A&=4278255360,8):0)|(4042322160&A?(A&=4042322160,4):0)|(3435973836&A?(A&=3435973836,2):0)|!!(2863311530&A)}function _(A,t){const i=new Uint8Array(t*A.length);for(let I=0;I0;)i>=4?(i-=4,t+=BigInt(g.getUint32(i))<=2?(i-=2,t+=BigInt(g.getUint16(i))<0;)e-4>=0?(e-=4,g.setUint32(e,Number(i&BigInt(4294967295))),i>>=BigInt(32)):e-2>=0?(e-=2,g.setUint16(e,Number(i&BigInt(65535))),i>>=BigInt(16)):(e-=1,g.setUint8(e,Number(i&BigInt(255))),i>>=BigInt(8));if(i)throw new Error("Number does not fit in this length");return I},bitReverse:X,buffReverseBits:function(A,t){const i=A.byteLength/t,I=K(i);if(i!=1<i){const I=A.slice(g*t,(g+1)*t);A.set(A.slice(i*t,(i+1)*t),g*t),A.set(I,i*t)}}},buffer2array:$,leBuff2int:function(A){let t=BigInt(0),i=0;const I=new DataView(A.buffer,A.byteOffset,A.byteLength);for(;i{i[I]=A(t[I])}),i}return t},stringifyFElements:function A(t,i){if("bigint"==typeof i||void 0!==i.eq)return i.toString(10);if(i instanceof Uint8Array)return t.toString(t.e(i));if(Array.isArray(i))return i.map(A.bind(this,t));if("object"==typeof i){const I={};return Object.keys(i).forEach(g=>{I[g]=A(t,i[g])}),I}return i},unstringifyBigInts:function A(t){if("string"==typeof t&&/^[0-9]+$/.test(t))return BigInt(t);if("string"==typeof t&&/^0x[0-9a-fA-F]+$/.test(t))return BigInt(t);if(Array.isArray(t))return t.map(A);if("object"==typeof t){if(null===t)return null;const i={};return Object.keys(t).forEach(I=>{i[I]=A(t[I])}),i}return t},unstringifyFElements:function A(t,i){if("string"==typeof i&&/^[0-9]+$/.test(i))return t.e(i);if("string"==typeof i&&/^0x[0-9a-fA-F]+$/.test(i))return t.e(i);if(Array.isArray(i))return i.map(A.bind(this,t));if("object"==typeof i){if(null===i)return null;const I={};return Object.keys(i).forEach(g=>{I[g]=A(t,i[g])}),I}return i}});const tA=1<<30;class iA{constructor(A){this.buffers=[],this.byteLength=A;for(let t=0;t0;){const A=n+a>tA?tA-n:a,t=new Uint8Array(this.buffers[e].buffer,this.buffers[e].byteOffset+n,A);if(A==i)return t.slice();g||(g=i<=tA?new Uint8Array(i):new iA(i)),g.set(t,i-a),a-=A,e++,n=0}return g}set(A,t){void 0===t&&(t=0);const i=A.byteLength;if(0==i)return;const I=Math.floor(t/tA);if(I==Math.floor((t+i-1)/tA))return A instanceof iA&&1==A.buffers.length?this.buffers[I].set(A.buffers[0],t%tA):this.buffers[I].set(A,t%tA);let g=I,e=t%tA,n=i;for(;n>0;){const t=e+n>tA?tA-e:n,I=A.slice(i-n,i-n+t);new Uint8Array(this.buffers[g].buffer,this.buffers[g].byteOffset+e,t).set(I),n-=t,g++,e=0}}}function IA(A,t,i,I){return async function(g){const e=Math.floor(g.byteLength/i);if(e*i!==g.byteLength)throw new Error("Invalid buffer size");const n=Math.floor(e/A.concurrency),a=[];for(let C=0;C=0;A--)this.w[A]=this.square(this.w[A+1]);if(!this.eq(this.w[0],this.one))throw new Error("Error calculating roots of unity");this.batchToMontgomery=IA(A,t+"_batchToMontgomery",this.n8,this.n8),this.batchFromMontgomery=IA(A,t+"_batchFromMontgomery",this.n8,this.n8)}op2(A,t,i){return this.tm.setBuff(this.pOp1,t),this.tm.setBuff(this.pOp2,i),this.tm.instance.exports[this.prefix+A](this.pOp1,this.pOp2,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}op2Bool(A,t,i){return this.tm.setBuff(this.pOp1,t),this.tm.setBuff(this.pOp2,i),!!this.tm.instance.exports[this.prefix+A](this.pOp1,this.pOp2)}op1(A,t){return this.tm.setBuff(this.pOp1,t),this.tm.instance.exports[this.prefix+A](this.pOp1,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}op1Bool(A,t){return this.tm.setBuff(this.pOp1,t),!!this.tm.instance.exports[this.prefix+A](this.pOp1,this.pOp3)}add(A,t){return this.op2("_add",A,t)}eq(A,t){return this.op2Bool("_eq",A,t)}isZero(A){return this.op1Bool("_isZero",A)}sub(A,t){return this.op2("_sub",A,t)}neg(A){return this.op1("_neg",A)}inv(A){return this.op1("_inverse",A)}toMontgomery(A){return this.op1("_toMontgomery",A)}fromMontgomery(A){return this.op1("_fromMontgomery",A)}mul(A,t){return this.op2("_mul",A,t)}div(A,t){return this.tm.setBuff(this.pOp1,A),this.tm.setBuff(this.pOp2,t),this.tm.instance.exports[this.prefix+"_inverse"](this.pOp2,this.pOp2),this.tm.instance.exports[this.prefix+"_mul"](this.pOp1,this.pOp2,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}square(A){return this.op1("_square",A)}isSquare(A){return this.op1Bool("_isSquare",A)}sqrt(A){return this.op1("_sqrt",A)}exp(A,t){return t instanceof Uint8Array||(t=L(I(t))),this.tm.setBuff(this.pOp1,A),this.tm.setBuff(this.pOp2,t),this.tm.instance.exports[this.prefix+"_exp"](this.pOp1,this.pOp2,t.byteLength,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}isNegative(A){return this.op1Bool("_isNegative",A)}e(A,t){if(A instanceof Uint8Array)return A;let i=I(A,t);e(i)?(i=w(i),d(i,this.p)&&(i=D(i,this.p)),i=f(this.p,i)):d(i,this.p)&&(i=D(i,this.p));const g=T(i,this.n8);return this.toMontgomery(g)}toString(A,t){return U(G(this.fromMontgomery(A),0),t)}fromRng(A){let t;const i=new Uint8Array(this.n8);do{t=b;for(let i=0;i>>1&1431655765))<<2|A>>>2&858993459))<<4|A>>>4&252645135))<<8|A>>>8&16711935)<<16|A>>>16)>>>0}function n(A,t,i){const I=A.byteLength/t,g=32-i;if(3&t||3&A.byteOffset){const i=new Uint8Array(t);for(let n=0;n>>g;if(n>>2,n=new Uint32Array(A.buffer,A.byteOffset,A.byteLength>>>2);for(let A=0;A>>g;if(AI.buffer.byteLength){const g=I.buffer.byteLength/65536;let e=Math.floor((i[0]+A)/65536)+1;e>t&&(e=t),I.grow(e-g)}return g}function C(A){const t=a(A.byteLength);return B(t,A),t}function Q(A,t){return new Uint8Array(I.buffer,A,t)}function B(A,t){new Uint8Array(I.buffer).set(new Uint8Array(t),A)}return function(A){if(clearTimeout(void 0),"INIT"===A[0].cmd)return async function(A){let e;if(A.code instanceof WebAssembly.Module)e=A.code;else{const t=new Uint8Array(A.code);e=await WebAssembly.compile(t)}if(I=new WebAssembly.Memory({initial:A.init,maximum:t}),i=await WebAssembly.instantiate(e,{env:{memory:I}}),A.batchCode){let t;t=A.batchCode instanceof WebAssembly.Module?A.batchCode:await WebAssembly.compile(new Uint8Array(A.batchCode));const e=i.exports,n=async(A,i,g)=>(await WebAssembly.instantiate(t,{env:{memory:I},curve:{f_mul:e[A+"_mul"],f_square:e[A+"_square"],f_add:e[A+"_add"],f_sub:e[A+"_sub"],f_neg:e[A+"_neg"],f_inverse:e[A+"_inverse"],f_isZero:e[A+"_isZero"],f_conj:e[g],g_add:e[i+"_add"],g_addMixed:e[i+"_addMixed"],g_double:e[i+"_double"],g_zero:e[i+"_zero"],g_isZero:e[i+"_isZero"]}})).exports,a=A.n8f;if(g={},e.f1m_mul&&e.g1m_addMixed){const t=await n("f1m","g1m","f1m_copy"),i=A.glv&&t.multiexpAffineGLV?t.multiexpAffineGLV:t.multiexpAffine;g.g1m_multiexpAffineBatch=(A,t,I,g,e)=>i(A,t,I,g,e,a),g.g1m_multiexpAffineBatchNoGlv=(A,i,I,g,e)=>t.multiexpAffine(A,i,I,g,e,a)}if(e.f2m_mul&&e.g2m_addMixed){const t=await n("f2m","g2m","f2m_conjugate"),i=A.glv&&t.multiexpAffineGLS?t.multiexpAffineGLS:t.multiexpAffine;g.g2m_multiexpAffineBatch=(A,t,I,g,e)=>i(A,t,I,g,e,2*a),g.g2m_multiexpAffineBatchNoGls=(A,i,I,g,e)=>t.multiexpAffine(A,i,I,g,e,2*a)}}}(A[0]);const e={vars:[],out:[]},o=new Uint32Array(I.buffer,0,1)[0];for(let t=0;t{this.reject=t,this.resolve=A})}}class oA{constructor(A){this.worker=A,this.initialized=!1,this.initializing=!1,this.working=!1,this.pendingDeferred=null,this.onMsg=null,this.onError=null}}let sA;class rA{constructor(){this.actionQueue=[],this.oldPFree=0}_makeOnMsg(A,t){const i=this;return async function(I){const g=I&&I.data?I.data:I;if(i.pool[A]!==t)return"terminated"===g.status?(t.worker.removeEventListener("message",t.onMsg),void t.worker.removeEventListener("error",t.onError)):(!g.status&&t.working&&(t.working=!1,t.pendingDeferred.resolve(g)),void await i.processWorks());if(g.error)throw t.working=!1,t.pendingDeferred.reject(new Error("Worker error: "+g.error)),t.initializing&&(t.initializing=!1,i.pool[A]=null),new Error("Worker error: "+g.error);if(g.status)if("initialized"===g.status)t.initializing=!1,t.initialized=!0;else{if("want_to_terminate"===g.status)return i.pool[A]=null,t.worker.postMessage([{cmd:"TERMINATE"}]),void await i.processWorks();if("terminated"===g.status)return t.worker.removeEventListener("message",t.onMsg),t.worker.removeEventListener("error",t.onError),i.pool[A]=null,void(t.working&&(t.pendingDeferred.reject(new Error(`Worker at slot ${A} terminated unexpectedly while processing task`)),t.working=!1))}t.working=!1,t.pendingDeferred.resolve(g),await i.processWorks()}}_makeOnError(A,t){const i=this;return function(I){throw i.pool[A]===t&&(t.working=!1,t.initialized=!1,t.pendingDeferred&&t.pendingDeferred.reject(new Error("Worker error: "+I.message))),new Error("Worker error: "+I.message)}}startWorker(A){const t=new Worker(function(){if(void 0!==sA)return sA;const A='(function thread(self) {\n const MAXMEM = 32767;\n let instance;\n let memory;\n let batchFns = null; // batch-affine MSM entry points (per-group wrappers)\n let terminationTimeout = 1500; // milliseconds\n let terminationTimer;\n\n if (self) {\n self.onmessage = function(e) {\n let data;\n if (e.data) {\n data = e.data;\n } else {\n data = e;\n }\n\n try {\n if (data[0].cmd === "INIT") {\n init(data[0]).then(function() {\n self.postMessage({status: "initialized"});\n // Start idle timer only after init completes so it never\n // fires during async WASM compilation.\n scheduleTermination();\n });\n return; // skip the scheduleTermination() call at the bottom\n } else if (data[0].cmd === "TERMINATE") {\n terminate();\n } else {\n let terminateAfterTask = false;\n if (data[data.length-1].cmd === "TERMINATE") {\n terminateAfterTask = true;\n data.pop();\n }\n const res = runTask(data);\n let transfers = [];\n for (let i=0; i (await WebAssembly.instantiate(batchModule, {\n env: { "memory": memory },\n curve: {\n f_mul: ex[f + "_mul"], f_square: ex[f + "_square"], f_add: ex[f + "_add"],\n f_sub: ex[f + "_sub"], f_neg: ex[f + "_neg"], f_inverse: ex[f + "_inverse"],\n f_isZero: ex[f + "_isZero"], f_conj: ex[conj],\n g_add: ex[g + "_add"], g_addMixed: ex[g + "_addMixed"],\n g_double: ex[g + "_double"], g_zero: ex[g + "_zero"], g_isZero: ex[g + "_isZero"],\n },\n })).exports;\n const n8f = data.n8f;\n batchFns = {};\n if (ex.f1m_mul && ex.g1m_addMixed) {\n // f_conj is only used by the G2 GLS path; wire a harmless copy for G1\n const b = await mkBatch("f1m", "g1m", "f1m_copy");\n // GLV path (bn254 G1 endomorphism) when the curve advertises it;\n // the wasm falls back internally for unexpected sizes.\n const useGlv = data.glv && b.multiexpAffineGLV;\n const fn = useGlv ? b.multiexpAffineGLV : b.multiexpAffine;\n batchFns["g1m_multiexpAffineBatch"] = (pB, pS, sS, n, pr) => fn(pB, pS, sS, n, pr, n8f);\n // NoGlv variant, selectable per call ({glv: "disabled"} option)\n batchFns["g1m_multiexpAffineBatchNoGlv"] = (pB, pS, sS, n, pr) => b.multiexpAffine(pB, pS, sS, n, pr, n8f);\n }\n if (ex.f2m_mul && ex.g2m_addMixed) {\n const b = await mkBatch("f2m", "g2m", "f2m_conjugate");\n // GLS (bn254 G2 endomorphism) when the curve advertises it; the\n // wasm gates internally on chunk size and falls back to batch.\n // The NoGls variant is selectable per call ({gls:false} option).\n const useGls = data.glv && b.multiexpAffineGLS;\n const fn2 = useGls ? b.multiexpAffineGLS : b.multiexpAffine;\n batchFns["g2m_multiexpAffineBatch"] = (pB, pS, sS, n, pr) => fn2(pB, pS, sS, n, pr, n8f * 2);\n batchFns["g2m_multiexpAffineBatchNoGls"] = (pB, pS, sS, n, pr) => b.multiexpAffine(pB, pS, sS, n, pr, n8f * 2);\n }\n }\n\n if (data.terminationTimeout) {\n terminationTimeout = data.terminationTimeout;\n }\n }\n\n\n\n // Reverse the low `bits` of a 32-bit integer (O(1) bit-twiddle).\n function rev32(x) {\n x = ((x & 0x55555555) << 1) | ((x >>> 1) & 0x55555555);\n x = ((x & 0x33333333) << 2) | ((x >>> 2) & 0x33333333);\n x = ((x & 0x0f0f0f0f) << 4) | ((x >>> 4) & 0x0f0f0f0f);\n x = ((x & 0x00ff00ff) << 8) | ((x >>> 8) & 0x00ff00ff);\n x = (x << 16) | (x >>> 16);\n return x >>> 0;\n }\n\n // In-place bit-reversal permutation of fixed-size (sIn-byte) elements.\n // Works for any element size, like the old pure-JS buffReverseBits. When\n // the elements are 4-byte aligned it swaps Uint32Array lanes (no BigInt\n // boxing, no allocation); otherwise it falls back to a byte-wise swap with\n // a single reused temp buffer. Either way it touches no WASM linear memory.\n function reverseInPlace(u8, sIn, bits) {\n const n = u8.byteLength / sIn;\n const shift = 32 - bits;\n if (((sIn & 3) === 0) && ((u8.byteOffset & 3) === 0)) {\n const lanes = sIn >>> 2;\n const u32 = new Uint32Array(u8.buffer, u8.byteOffset, u8.byteLength >>> 2);\n for (let i = 0; i < n; i++) {\n const ri = rev32(i) >>> shift;\n if (i < ri) {\n let a = i * lanes;\n let b = ri * lanes;\n for (let l = 0; l < lanes; l++) {\n const t = u32[a + l];\n u32[a + l] = u32[b + l];\n u32[b + l] = t;\n }\n }\n }\n } else {\n const tmp = new Uint8Array(sIn); // one reused temp, not one per swap\n for (let i = 0; i < n; i++) {\n const ri = rev32(i) >>> shift;\n if (i < ri) {\n const ao = i * sIn;\n const bo = ri * sIn;\n tmp.set(u8.subarray(ao, ao + sIn));\n u8.copyWithin(ao, bo, bo + sIn);\n u8.set(tmp, bo);\n }\n }\n }\n }\n\n function alloc(length) {\n const u32 = new Uint32Array(memory.buffer, 0, 1);\n while (u32[0] & 3) u32[0]++; // Return always aligned pointers\n const res = u32[0];\n u32[0] += length;\n if (u32[0] + length > memory.buffer.byteLength) {\n const currentPages = memory.buffer.byteLength / 0x10000;\n let requiredPages = Math.floor((u32[0] + length) / 0x10000)+1;\n if (requiredPages>MAXMEM) requiredPages=MAXMEM;\n memory.grow(requiredPages-currentPages);\n }\n return res;\n }\n\n function allocBuffer(buffer) {\n const p = alloc(buffer.byteLength);\n setBuffer(p, buffer);\n return p;\n }\n\n function getBuffer(pointer, length) {\n return new Uint8Array(memory.buffer, pointer, length);\n }\n\n function setBuffer(pointer, buffer) {\n const u8 = new Uint8Array(memory.buffer);\n u8.set(new Uint8Array(buffer), pointer);\n }\n\n function runTask(task) {\n clearTimeout(terminationTimer);\n if (task[0].cmd === "INIT") {\n return init(task[0]);\n }\n const ctx = {\n vars: [],\n out: []\n };\n const u32a = new Uint32Array(memory.buffer, 0, 1);\n const oldAlloc = u32a[0];\n for (let i=0; i plain\n // in-module variant when the batch module is unavailable\n // (same 5-arg signature)\n if (!fn) {\n const base = fname.replace(/Batch(NoGls|NoGlv)?$/, "");\n fn = instance.exports[base];\n }\n }\n fn(...params);\n }\n break;\n }\n case "GET":\n ctx.out[task[i].out] = getBuffer(ctx.vars[task[i].var], task[i].len).slice();\n break;\n default:\n throw new Error("Invalid cmd");\n }\n }\n const u32b = new Uint32Array(memory.buffer, 0, 1);\n u32b[0] = oldAlloc;\n\n return ctx.out;\n }\n\n function scheduleTermination() {\n clearTimeout(terminationTimer);\n if (terminationTimeout > 0) {\n terminationTimer = setTimeout(() => {\n // 2-phase termination: notify main thread first; close only after\n // it acks with TERMINATE. This prevents the race where the main\n // thread dispatches a task to a worker that has already closed.\n if (self) self.postMessage({status: "want_to_terminate"});\n }, terminationTimeout);\n }\n }\n\n function terminate() {\n clearTimeout(terminationTimer);\n if (self) {\n self.postMessage({status: "terminated"});\n self.close();\n }\n }\n\n return runTask;\n})(self)';if(QA)sA="data:application/javascript;base64,"+Buffer.from(A).toString("base64");else if(globalThis?.Blob&&globalThis.URL&&globalThis.URL.createObjectURL){const t=(new TextEncoder).encode(A),i=new Blob([t],{type:"application/javascript"});sA=URL.createObjectURL(i)}else sA="data:application/javascript;base64,"+globalThis.btoa(A);return sA}()),i=new oA(t);this.pool[A]=i,i.onMsg=this._makeOnMsg(A,i),i.onError=this._makeOnError(A,i),t.addEventListener("message",i.onMsg),t.addEventListener("error",i.onError),i.initializing=!0,this.postAction(A,[{cmd:"INIT",init:25,code:this.wasmModule,batchCode:this.batchWasmModule,n8f:this.n8f,glv:this.glv}]).then(()=>{i.initialized=!0})}startSyncOp(){if(0!==this.oldPFree)throw new Error("Sync operation in progress");this.oldPFree=this.u32[0]}endSyncOp(){if(0===this.oldPFree)throw new Error("No sync operation in progress");this.u32[0]=this.oldPFree,this.oldPFree=0}async postAction(A,t,i,I){const g=this.pool[A];if(!g||g.working)throw new Error("Posting a job to a working worker");return g.working=!0,g.pendingDeferred=I||new BA,await g.worker.postMessage(t,i),g.pendingDeferred.promise}async processWorks(){for(let A=0;A0;A++){const t=this.pool[A];if(t&&t.initialized&&!t.working){const t=this.actionQueue.shift();await this.postAction(A,t.data,t.transfers,t.deferred)}}if(this.actionQueue.length>0){let A=0;for(let t=0;t=this.actionQueue.length)break;A++,this.startWorker(t)}}}}async queueAction(A,t){const i=new BA;if(this.singleThread){const t=this.taskManager(A);i.resolve(t)}else this.actionQueue.push({data:A,transfers:t,deferred:i}),await this.processWorks();return i.promise}resetMemory(){this.u32[0]=this.initalPFree}allocBuff(A){const t=this.alloc(A.byteLength);return this.setBuff(t,A),t}getBuff(A,t){return this.u8.slice(A,A+t)}setBuff(A,t){this.u8.set(new Uint8Array(t),A)}alloc(A){for(;3&this.u32[0];)this.u32[0]++;const t=this.u32[0];return this.u32[0]+=A,t}async terminate(){for(let A=0;Ag&&(a=g),a<4096&&(a=4096),a}(n,C),h=new Set,l=[];for(let t=0;t=o;)await Promise.race(h);E&&E.debug(`Multiexp start: ${f}: ${I}/${n}`);const g=(async()=>{const t=await A(I*a,i*a),g=e.slice(I*C,(I+i)*C),o=await Q(t,g,B,s,r,f);return E&&E.debug(`Multiexp end: ${f}: ${I}/${n}`),o})(),c=g.finally(()=>h.delete(c));h.add(c),l.push(c)}const c=await Promise.all(l);let D=i.zero;for(let A=c.length-1;A>=0;A--)D=i.add(D,c[A]);return D}function o(A,t,i){const I=e(i),g=Math.floor(A/I);let n=0;if(g>0&&(n=Math.floor(t.byteLength/g),n*g!==t.byteLength))throw new Error("Scalar size does not match");return{sGIn:I,nPoints:g,sScalar:n}}async function s(A,t,i,I,g,e,n){const{sGIn:a,nPoints:C,sScalar:Q}=o(A.byteLength,t,i);return B((t,i)=>A.slice(t,t+i),t,C,a,Q,i,1/0,I,g,e,n)}i.multiExp=async function(A,t,i,I){return s(A,t,"jacobian","disabled","auto",i,I)},i.multiExpAffine=async function(A,t,i,I,g){return s(A,t,"affine",n(g),a(g),i,I)},i.multiExpAffineChunked=async function(A,t,i,g,e,C){if("function"!=typeof A)throw new Error(`${e||"multiExpAffineChunked"}: basesReader must be a function (byteOffset, byteLength) => Promise`);const{sGIn:Q,nPoints:s,sScalar:r}=o(t,i,"affine");return B(A,i,s,Q,r,"affine",I.concurrency+2,n(C),a(C),g,e)}}function hA(A,t){const i=A[t],I=A.Fr,g=i.tm;async function e(A,a,C,Q,B,o,s){C=C||"affine",Q=Q||"affine";let r,E,f,w,h,l,c,D;"G1"==t?("affine"==C?(r=2*i.F.n8,w="g1m_batchToJacobian"):r=3*i.F.n8,E=3*i.F.n8,a&&(D="g1m_fftFinal"),c="g1m_fftJoin",l="g1m_fftMix","affine"==Q?(f=2*i.F.n8,h="g1m_batchToAffine"):f=3*i.F.n8):"G2"==t?("affine"==C?(r=2*i.F.n8,w="g2m_batchToJacobian"):r=3*i.F.n8,E=3*i.F.n8,a&&(D="g2m_fftFinal"),c="g2m_fftJoin",l="g2m_fftMix","affine"==Q?(f=2*i.F.n8,h="g2m_batchToAffine"):f=3*i.F.n8):"Fr"==t&&(r=i.n8,E=i.n8,f=i.n8,a&&(D="frm_fftFinal"),l="frm_fftMix",c="frm_fftJoin");let u=!1;Array.isArray(A)?(A=_(A,r),u=!0):s&&ArrayBuffer.isView(A)||(A=A.slice(0,A.byteLength));const d=A.byteLength/r,y=K(d);if(1<1<<28?new iA(2*o[0].byteLength):new Uint8Array(2*o[0].byteLength);return s.set(o[0]),s.set(o[1],o[0].byteLength),s}(A,C,Q,B,o):await async function(A,t,i,g,a){let C,Q;C=A.slice(0,A.byteLength/2),Q=A.slice(A.byteLength/2,A.byteLength);const B=[];[C,Q]=await n(C,Q,"fftJoinExt",I.one,I.shift,t,"jacobian",g,a),B.push(e(C,!1,"jacobian",i,g,a)),B.push(e(Q,!1,"jacobian",i,g,a));const o=await Promise.all(B);let s;s=o[0].byteLength>1<<28?new iA(2*o[0].byteLength):new Uint8Array(2*o[0].byteLength);return s.set(o[0]),s.set(o[1],o[0].byteLength),s}(A,C,Q,B,o),u?$(t,f):t}let p,m,F;a&&(p=I.inv(I.e(d))),A=await async function(A,t,i){return(await g.queueAction([{cmd:"REVERSE",src:A,sIn:t,bits:i}],[A.buffer]))[0]}(A,r,y);let G=Math.min(16384,d),N=d/G;for(;N=16;)N*=2,G/=2;const U=K(G),L=[];B&&B.debug(`${o}: fft ${y} mix start: ${N}`);for(let t=0;t0;t--)m.set(F[t],A),A+=G*f,delete F[t];m.set(F[0].slice(0,(G-1)*f),A),delete F[0]}else for(let A=0;A65536&&(D=65536);const u=[];for(let t=0;t(o&&o.debug(`${s}: fftJoinExt End: ${t}/${c}`),A)))}const d=await Promise.all(u);let y,p;c*w>1<<28?(y=new iA(c*w),p=new iA(c*w)):(y=new Uint8Array(c*w),p=new Uint8Array(c*w));let m=0;for(let A=0;AI.s+1)throw C&&C.error("lagrangeEvaluations input too big"),new Error("lagrangeEvaluations input too big");let r=A.slice(0,A.byteLength/2),E=A.slice(A.byteLength/2,A.byteLength);const f=I.exp(I.shift,o/2),w=I.inv(I.sub(I.one,f));[r,E]=await n(r,E,"prepareLagrangeEvaluation",w,I.shiftInv,g,"jacobian",C,Q+" prep");const h=[];let l;return h.push(e(r,!0,"jacobian",a,C,Q+" t0")),h.push(e(E,!0,"jacobian",a,C,Q+" t1")),[r,E]=await Promise.all(h),l=r.byteLength>1<<28?new iA(2*r.byteLength):new Uint8Array(2*r.byteLength),l.set(r),l.set(E,r.byteLength),l},i.fftMix=async function(A){const e=3*i.F.n8;let n,a;if("G1"==t)n="g1m_fftMix",a="g1m_fftJoin";else if("G2"==t)n="g2m_fftMix",a="g2m_fftJoin";else{if("Fr"!=t)throw new Error("Invalid group");n="frm_fftMix",a="frm_fftJoin"}const C=Math.floor(A.byteLength/e),Q=K(C);let B=1<=0;A--)r.set(s[A][0],E),E+=s[A][0].byteLength;return r}}async function lA(A){const t=await async function(A,t){const i=new rA;i.memory=new WebAssembly.Memory({initial:25}),i.u8=new Uint8Array(i.memory.buffer),i.u32=new Uint32Array(i.memory.buffer);const I=await WebAssembly.compile(A.code);if(i.instance=await WebAssembly.instantiate(I,{env:{memory:i.memory}}),QA||globalThis?.Worker||(t=!0),i.singleThread=t,i.initalPFree=i.u32[0],i.pq=A.pq,i.pr=A.pr,i.pG1gen=A.pG1gen,i.pG1zero=A.pG1zero,i.pG2gen=A.pG2gen,i.pG2zero=A.pG2zero,i.pOneT=A.pOneT,i.code=A.code,i.wasmModule=I,i.batchCode=A.batchCode,i.batchWasmModule=A.batchCode?await WebAssembly.compile(A.batchCode):void 0,i.n8f=A.n8q,i.glv=!!A.glv,t)i.taskManager=CA(),await i.taskManager([{cmd:"INIT",init:25,code:i.code.slice(),batchCode:i.batchCode?i.batchCode.slice():void 0,n8f:i.n8f,glv:i.glv}]),i.concurrency=1;else{i.pool=[];let A=2;"object"==typeof navigator&&navigator.hardwareConcurrency?A=navigator.hardwareConcurrency:P&&P.cpus&&(A=P.cpus().length),0===A&&(A=2),A>64&&(A=64),i.concurrency=A}return i}(A.wasm,A.singleThread),i={};return i.q=I(A.wasm.q.toString()),i.r=I(A.wasm.r.toString()),i.name=A.name,i.tm=t,i.prePSize=A.wasm.prePSize,i.preQSize=A.wasm.preQSize,i.Fr=new gA(t,"frm",A.n8r,A.r),i.F1=new gA(t,"f1m",A.n8q,A.q),i.F2=new eA(t,"f2m",i.F1),i.G1=new aA(t,"g1m",i.F1,A.wasm.pG1gen,A.wasm.pG1b,A.cofactorG1),i.G2=new aA(t,"g2m",i.F2,A.wasm.pG2gen,A.wasm.pG2b,A.cofactorG2),i.F6=new nA(t,"f6m",i.F2),i.F12=new eA(t,"ftm",i.F6),i.Gt=i.F12,EA(i,"G1"),EA(i,"G2"),EA(i,"Fr"),wA(i,"G1"),wA(i,"G2"),hA(i,"G1"),hA(i,"G2"),hA(i,"Fr"),function(A){const t=A.tm;A.pairing=function(i,I){t.startSyncOp();const g=t.allocBuff(A.G1.toJacobian(i)),e=t.allocBuff(A.G2.toJacobian(I)),n=t.alloc(A.Gt.n8);t.instance.exports[A.name+"_pairing"](g,e,n);const a=t.getBuff(n,A.Gt.n8);return t.endSyncOp(),a},A.pairingEq=async function(){let i,I;arguments.length%2==1?(i=arguments[arguments.length-1],I=(arguments.length-1)/2):(i=A.Gt.one,I=arguments.length/2);const g=[];for(let i=0;i0&&"="===A[t-1]&&i++,t>1&&"="===A[t-2]&&i++;const I=(3*t>>2)-i,g=new Uint8Array(I);let e=0;for(let i=0;i>4),e>2),e{t.pendingLoads.push({page:A,resolve:i,reject:I})});return t.__statusPage("After Load request: ",A),i}__statusPage(A,t){const i=[],I=this;if(!I.logHistory)return;i.push("=="+A+" "+t);let g="";for(let A=0;A "+t.history[A][i][I])}_triggerLoad(){const A=this;if(A.reading)return;if(0==A.pendingLoads.length)return;const t=Object.keys(A.pages),i=[];for(let I=0;I0&&(void 0!==A.pages[A.pendingLoads[0].page]||I>0||i.length>0);){const t=A.pendingLoads.shift();if(void 0!==A.pages[t.page]){A.pages[t.page].pendingOps++;const I=i.indexOf(t.page);I>=0&&i.splice(I,1),A.pages[t.page].loading?A.pages[t.page].loading.push(t):t.resolve(),A.__statusPage("After Load (cached): ",t.page)}else{if(I)I--;else{const t=i.shift();A.__statusPage("Before Unload: ",t),A.avBuffs.unshift(A.pages[t]),delete A.pages[t],A.__statusPage("After Unload: ",t)}t.page>=A.totalPages?(A.pages[t.page]=e(),t.resolve(),A.__statusPage("After Load (new): ",t.page)):(A.reading=!0,A.pages[t.page]=e(),A.pages[t.page].loading=[t],g.push(A.fd.read(A.pages[t.page].buff,0,A.pageSize,t.page*A.pageSize).then(i=>{A.pages[t.page].size=i.bytesRead;const I=A.pages[t.page].loading;delete A.pages[t.page].loading;for(let A=0;A{t.reject(A)})),A.__statusPage("After Load (loading): ",t.page))}}function e(){if(A.avBuffs.length>0){const t=A.avBuffs.shift();return t.dirty=!1,t.pendingOps=1,t.size=0,t}return{dirty:!1,buff:new Uint8Array(A.pageSize),pendingOps:1,size:0}}Promise.all(g).then(()=>{A.reading=!1,A.pendingLoads.length>0&&setImmediate(A._triggerLoad.bind(A)),A._tryClose()})}_triggerWrite(){const A=this;if(A.writing)return;const t=Object.keys(A.pages),i=[];for(let I=0;I{g.writing=!1},t=>{console.log("ERROR Writing: "+t),A.error=t,A._tryClose()})))}A.writing&&Promise.all(i).then(()=>{A.writing=!1,setImmediate(A._triggerWrite.bind(A)),A._tryClose(),A.pendingLoads.length>0&&setImmediate(A._triggerLoad.bind(A))})}_getDirtyPage(){for(let A in this.pages)if(this.pages[A].dirty)return A;return-1}_rangeHasCachedPages(A,t){const i=Math.floor(A/this.pageSize),I=Math.floor((A+t-1)/this.pageSize);for(const A of Object.keys(this.pages)){const t=+A;if(t>=i&&t<=I)return!0}return!1}async write(A,t){if(0==A.byteLength)return;const i=this;if(void 0===t&&(t=i.pos),i.pos=t+A.byteLength,i.totalSize=i.directWriteThreshold&&ArrayBuffer.isView(A)&&!i._rangeHasCachedPages(t,A.byteLength)){let I=0;for(;Ii.totalPages&&(i.totalPages=g+1))}const I=Math.floor(t/i.pageSize),g=Math.floor((t+A.byteLength-1)/i.pageSize),e=[];for(let A=I;A<=g;A++)e.push(i._loadPage(A));i._triggerLoad();let n=I,a=t%i.pageSize,C=A.byteLength;for(;C>0;){await e[n-I];const t=a+C>i.pageSize?i.pageSize-a:C,g=A.slice(A.byteLength-C,A.byteLength-C+t);new Uint8Array(i.pages[n].buff.buffer,a,t).set(g),i.pages[n].dirty=!0,i.pages[n].pendingOps--,i.pages[n].size=Math.max(a+t,i.pages[n].size),n>=i.totalPages&&(i.totalPages=n+1),C-=t,n++,a=0,i.writing||setImmediate(i._triggerWrite.bind(i))}}async read(A,t){let i=new Uint8Array(A);return await this.readToBuffer(i,0,A,t),i}_rangeHasDirtyPages(A,t){const i=Math.floor(A/this.pageSize),I=Math.floor((A+t-1)/this.pageSize);for(const A of Object.keys(this.pages)){const t=+A;if(t>=i&&t<=I){const A=this.pages[t];if(A.dirty||A.writing)return!0}}return!1}async readToBuffer(A,t,i,I){if(0==i)return;const g=this;if(void 0===I&&(I=g.pos),g.pos=I+i,g.pendingClose)throw new Error("Reading a closing file");if(i>=g.directReadThreshold&&ArrayBuffer.isView(A)&&!g._rangeHasDirtyPages(I,i)){let e=I+i>g.totalSize?g.totalSize-I:i;e<0&&(e=0);let n=0;for(;ng.pageSize*g.maxPagesLoaded*.8){const A=Math.floor(1.1*i);this.maxPagesLoaded=Math.floor(A/g.pageSize)+1}const e=Math.floor(I/g.pageSize),n=Math.floor((I+i-1)/g.pageSize),a=[];for(let A=e;A<=n;A++)a.push(g._loadPage(A));g._triggerLoad();let C=e,Q=I%g.pageSize,B=I+i>g.totalSize?i-(I+i-g.totalSize):i;for(;B>0;){await a[C-e],g.__statusPage("After Await (read): ",C);const I=Q+B>g.pageSize?g.pageSize-Q:B,n=new Uint8Array(g.pages[C].buff.buffer,g.pages[C].buff.byteOffset+Q,I);A.set(n,t+i-B),g.pages[C].pendingOps--,g.__statusPage("After Op done: ",C),B-=I,C++,Q=0,g.pendingLoads.length>0&&setImmediate(g._triggerLoad.bind(g))}this.pos=I+i}_tryClose(){const A=this;if(!A.pendingClose)return;A.error&&A.pendingCloseReject(A.error);A._getDirtyPage()>=0||A.writing||A.reading||A.pendingLoads.length>0||A.pendingClose()}close(){const A=this;if(A.pendingClose)throw new Error("Closing the file twice");return new Promise((t,i)=>{A.pendingClose=t,A.pendingCloseReject=i,A._tryClose()}).then(()=>{A.fd.close()},t=>{throw A.fd.close(),t})}async discard(){await this.close(),await bA.promises.unlink(this.fileName)}async writeULE32(A,t){const i=new Uint8Array(4);new DataView(i.buffer).setUint32(0,A,!0),await this.write(i,t)}async writeUBE32(A,t){const i=new Uint8Array(4);new DataView(i.buffer).setUint32(0,A,!1),await this.write(i,t)}async writeULE64(A,t){const i=new Uint8Array(8),I=new DataView(i.buffer);I.setUint32(0,4294967295&A,!0),I.setUint32(4,Math.floor(A/4294967296),!0),await this.write(i,t)}async readULE32(A){const t=await this.read(4,A);return new Uint32Array(t.buffer)[0]}async readUBE32(A){const t=await this.read(4,A);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(A){const t=await this.read(8,A),i=new Uint32Array(t.buffer);return 4294967296*i[1]+i[0]}async readString(A){const t=this;if(t.pendingClose)throw new Error("Reading a closing file");let i=void 0===A?t.pos:A,I=Math.floor(i/t.pageSize),g=!1,e="";for(;!g;){let A=t._loadPage(I);t._triggerLoad(),await A,t.__statusPage("After Await (read): ",I);let n=i%t.pageSize;const a=new Uint8Array(t.pages[I].buff.buffer,t.pages[I].buff.byteOffset+n,t.pageSize-n);let C=a.findIndex(A=>0===A);g=-1!==C,g?(e+=(new TextDecoder).decode(a.slice(0,C)),t.pos=I*this.pageSize+n+C+1):(e+=(new TextDecoder).decode(a),t.pos=I*this.pageSize+n+a.length),t.pages[I].pendingOps--,t.__statusPage("After Op done: ",I),i=t.pos,I++,t.pendingLoads.length>0&&setImmediate(t._triggerLoad.bind(t))}return e}};const SA=new Uint8Array(4),kA=new DataView(SA.buffer),vA=new Uint8Array(8),RA=new DataView(vA.buffer);let JA=class{constructor(){this.pageSize=16384}_resizeIfNeeded(A){if(A>this.allocSize){const t=Math.max(this.allocSize+(1<<20),Math.floor(1.1*this.allocSize),A),i=new Uint8Array(t);i.set(this.o.data),this.o.data=i,this.allocSize=t}}async write(A,t){if(void 0===t&&(t=this.pos),this.readOnly)throw new Error("Writing a read only file");this._resizeIfNeeded(t+A.byteLength),this.o.data.set(A.slice(),t),t+A.byteLength>this.totalSize&&(this.totalSize=t+A.byteLength),this.pos=t+A.byteLength}async readToBuffer(A,t,i,I){if(void 0===I&&(I=this.pos),this.readOnly&&I+i>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(I+i);const g=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+I,i);A.set(g,t),this.pos=I+i}async read(A,t){const i=new Uint8Array(A);return await this.readToBuffer(i,0,A,t),i}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(A,t){kA.setUint32(0,A,!0),await this.write(SA,t)}async writeUBE32(A,t){kA.setUint32(0,A,!1),await this.write(SA,t)}async writeULE64(A,t){RA.setUint32(0,4294967295&A,!0),RA.setUint32(4,Math.floor(A/4294967296),!0),await this.write(vA,t)}async readULE32(A){const t=await this.read(4,A);return new Uint32Array(t.buffer)[0]}async readUBE32(A){const t=await this.read(4,A);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(A){const t=await this.read(8,A),i=new Uint32Array(t.buffer);return 4294967296*i[1]+i[0]}async readString(A){const t=this;let i=void 0===A?t.pos:A;if(i>this.totalSize){if(this.readOnly)throw new Error("Reading out of bounds");this._resizeIfNeeded(A)}const I=new Uint8Array(t.o.data.buffer,i,this.totalSize-i);let g=I.findIndex(A=>0===A),e="";return-1!==g?(e=(new TextDecoder).decode(I.slice(0,g)),t.pos=i+g+1):t.pos=i,e}};const PA=1<<22;const xA=new Uint8Array(4),YA=new DataView(xA.buffer),qA=new Uint8Array(8),ZA=new DataView(qA.buffer);let zA=class{constructor(){this.pageSize=16384}_resizeIfNeeded(A){if(A<=this.totalSize)return;if(this.readOnly)throw new Error("Reading out of file bounds");const t=Math.floor((A-1)/PA)+1;for(let i=Math.max(this.o.data.length-1,0);i0;){const t=g+e>PA?PA-g:e,n=A.slice(A.byteLength-e,A.byteLength-e+t);new Uint8Array(i.o.data[I].buffer,g,t).set(n),e-=t,I++,g=0}this.pos=t+A.byteLength}async readToBuffer(A,t,i,I){const g=this;if(void 0===I&&(I=g.pos),this.readOnly&&I+i>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(I+i);let e=Math.floor(I/PA),n=I%PA,a=i;for(;a>0;){const I=n+a>PA?PA-n:a,C=new Uint8Array(g.o.data[e].buffer,n,I);A.set(C,t+i-a),a-=I,e++,n=0}this.pos=I+i}async read(A,t){const i=new Uint8Array(A);return await this.readToBuffer(i,0,A,t),i}close(){}async discard(){}async writeULE32(A,t){YA.setUint32(0,A,!0),await this.write(xA,t)}async writeUBE32(A,t){YA.setUint32(0,A,!1),await this.write(xA,t)}async writeULE64(A,t){ZA.setUint32(0,4294967295&A,!0),ZA.setUint32(4,Math.floor(A/4294967296),!0),await this.write(qA,t)}async readULE32(A){const t=await this.read(4,A);return new Uint32Array(t.buffer)[0]}async readUBE32(A){const t=await this.read(4,A);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(A){const t=await this.read(8,A),i=new Uint32Array(t.buffer);return 4294967296*i[1]+i[0]}async readString(A){const t=this;let i=void 0===A?t.pos:A;if(i>this.totalSize){if(this.readOnly)throw new Error("Reading out of bounds");this._resizeIfNeeded(A)}let I=!1,g="";for(;!I;){let A=Math.floor(i/PA),e=i%PA;if(void 0===t.o.data[A])throw new Error("ERROR");let n=Math.min(2048,t.o.data[A].length-e);const a=new Uint8Array(t.o.data[A].buffer,e,n);let C=a.findIndex(A=>0===A);I=-1!==C,I?(g+=(new TextDecoder).decode(a.slice(0,C)),t.pos=A*PA+e+C+1):(g+=(new TextDecoder).decode(a),t.pos=A*PA+e+a.length),i=t.pos}return g}};const jA="undefined"!=typeof process&&null!=process.versions&&null!=process.versions.node;async function OA(A,t,i){if("string"==typeof A&&(A={type:"file",fileName:A,cacheSize:t||65536,pageSize:i||8192}),"file"==A.type)return await MA(A.fileName,578,A.cacheSize,A.pageSize);if("mem"==A.type)return function(A){const t=A.initialSize||1<<20,i=new JA;return i.o=A,i.o.data=new Uint8Array(t),i.allocSize=t,i.totalSize=0,i.readOnly=!1,i.pos=0,i}(A);if("bigMem"==A.type)return function(A){const t=A.initialSize||0,i=new zA;i.o=A;const I=t?Math.floor((t-1)/PA)+1:0;i.o.data=[];for(let A=0;Ai)throw new Error("Version not supported");const C=await e.readULE32();let Q=[];for(let A=0;A1)throw new Error(A.fileName+": Section Duplicated "+i);A.pos=t[i][0].p,A.readingSection=t[i][0]}async function At(A,t){if(void 0===A.readingSection)throw new Error("Not reading a section");if(!t&&A.pos-A.readingSection.p!=A.readingSection.size)throw new Error("Invalid section size reading");delete A.readingSection}async function tt(A,t,i,I){const g=new Uint8Array(i);UA.toRprLE(g,0,t,i),await A.write(g,I)}async function it(A,t,i){const I=await A.read(t,i);return UA.fromRprLE(I,0,t)}async function It(A,t,i,I,g){void 0===g&&(g=t[I][0].size);const e=A.pageSize;await $A(A,t,I),await KA(i,I);for(let t=0;tt[i][0].size)throw new Error("Reading out of the range of the section");let e;return e=g=0)i=await pA(I);else{if(!(["BLS12381"].indexOf(g)>=0))throw new Error(`Curve not supported: ${A}`);i=await FA(I)}return i}var rt=Object.freeze({__proto__:null,getCurveFromName:st,getCurveFromQ:ot,getCurveFromR:Bt});function Et(A,t=""){if("number"!=typeof A){throw new TypeError(`${t&&`"${t}" `}expected number, got ${typeof A}`)}if(!Number.isSafeInteger(A)||A<0){throw new RangeError(`${t&&`"${t}" `}expected integer >= 0, got ${A}`)}}function ft(A,t,i=""){const I=(g=A)instanceof Uint8Array||ArrayBuffer.isView(g)&&"Uint8Array"===g.constructor.name&&"BYTES_PER_ELEMENT"in g&&1===g.BYTES_PER_ELEMENT;var g;const e=A?.length,n=void 0!==t;if(!I||n&&e!==t){const g=(i&&`"${i}" `)+"expected Uint8Array"+(n?` of length ${t}`:"")+", got "+(I?`length=${e}`:"type="+typeof A);if(!I)throw new TypeError(g);throw new RangeError(g)}return A}function wt(A,t=!0){if(A.destroyed)throw new Error("Hash instance has been destroyed");if(t&&A.finished)throw new Error("Hash#digest() has already been called")}function ht(A,t){ft(A,void 0,"digestInto() output");const i=t.outputLen;if(A.length='+i)}function lt(A){return new Uint32Array(A.buffer,A.byteOffset,Math.floor(A.byteLength/4))}function ct(...A){for(let t=0;t68===new Uint8Array(new Uint32Array([287454020]).buffer)[0])();function ut(A){return A<<24&4278190080|A<<8&16711680|A>>>8&65280|A>>>24&255}const dt=Dt?A=>A:A=>ut(A)>>>0;const yt=Dt?A=>A:function(A){for(let t=0;tA(i).update(t).digest(),I=A(void 0);return i.outputLen=I.outputLen,i.blockLen=I.blockLen,i.canXOF=I.canXOF,i.create=t=>A(t),Object.assign(i,t),Object.freeze(i)}const mt=Uint8Array.from([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3,11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4,7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8,9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13,2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9,12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11,13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10,6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5,10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3,11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4,7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8,9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13,2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9]),Ft=BigInt(2**32-1),Gt=BigInt(32);function Nt(A,t=!1){return t?{h:Number(A&Ft),l:Number(A>>Gt&Ft)}:{h:0|Number(A>>Gt&Ft),l:0|Number(A&Ft)}}const Ut=(A,t,i)=>A>>>i|t<<32-i,Lt=(A,t,i)=>A<<32-i|t>>>i,bt=(A,t,i)=>A>>>i-32|t<<64-i;function Mt(A,t,i,I){const g=(t>>>0)+(I>>>0);return{h:A+i+(g/2**32|0)|0,l:0|g}}const Ht=(A,t,i)=>(A>>>0)+(t>>>0)+(i>>>0),St=(A,t,i,I)=>t+i+I+(A/2**32|0)|0,kt=Uint32Array.from([4089235720,1779033703,2227873595,3144134277,4271175723,1013904242,1595750129,2773480762,2917565137,1359893119,725511199,2600822924,4215389547,528734635,327033209,1541459225]),vt=new Uint32Array(32);function Rt(A,t,i,I,g,e){const n=g[e],a=g[e+1];let C=vt[2*A],Q=vt[2*A+1],B=vt[2*t],o=vt[2*t+1],s=vt[2*i],r=vt[2*i+1],E=vt[2*I],f=vt[2*I+1],w=Ht(C,B,n);var h,l;Q=St(w,Q,o,a),C=0|w,({Dh:f,Dl:E}={Dh:f^Q,Dl:E^C}),({Dh:f,Dl:E}={Dh:(l=E,l),Dl:(h=f,h)}),({h:r,l:s}=Mt(r,s,f,E)),({Bh:o,Bl:B}={Bh:o^r,Bl:B^s}),({Bh:o,Bl:B}={Bh:Ut(o,B,24),Bl:Lt(o,B,24)}),vt[2*A]=C,vt[2*A+1]=Q,vt[2*t]=B,vt[2*t+1]=o,vt[2*i]=s,vt[2*i+1]=r,vt[2*I]=E,vt[2*I+1]=f}function Jt(A,t,i,I,g,e){const n=g[e],a=g[e+1];let C=vt[2*A],Q=vt[2*A+1],B=vt[2*t],o=vt[2*t+1],s=vt[2*i],r=vt[2*i+1],E=vt[2*I],f=vt[2*I+1],w=Ht(C,B,n);var h,l,c;Q=St(w,Q,o,a),C=0|w,({Dh:f,Dl:E}={Dh:f^Q,Dl:E^C}),({Dh:f,Dl:E}={Dh:Ut(f,E,16),Dl:Lt(f,E,16)}),({h:r,l:s}=Mt(r,s,f,E)),({Bh:o,Bl:B}={Bh:o^r,Bl:B^s}),({Bh:o,Bl:B}={Bh:(h=o,l=B,c=63,h<<64-c|l>>>c-32),Bl:bt(o,B,63)}),vt[2*A]=C,vt[2*A+1]=Q,vt[2*t]=B,vt[2*t+1]=o,vt[2*i]=s,vt[2*i+1]=r,vt[2*I]=E,vt[2*I+1]=f}class Pt{buffer;buffer32;finished=!1;destroyed=!1;length=0;pos=0;blockLen;outputLen;canXOF=!1;constructor(A,t){Et(A),Et(t),this.blockLen=A,this.outputLen=t,this.buffer=new Uint8Array(A),this.buffer32=lt(this.buffer)}update(A){wt(this),ft(A);const{blockLen:t,buffer:i,buffer32:I}=this,g=A.length,e=A.byteOffset,n=A.buffer;for(let a=0;a>>8*t}digest(){const{buffer:A,outputLen:t}=this;this.digestInto(A);const i=A.slice(0,t);return this.destroy(),i}_cloneInto(A){const{buffer:t,length:i,finished:I,destroyed:g,outputLen:e,pos:n}=this;return A||=new this.constructor({dkLen:e}),A.set(...this.get()),A.buffer.set(t),A.destroyed=g,A.finished=I,A.length=i,A.pos=n,A.outputLen=e,A}clone(){return this._cloneInto()}}class xt extends Pt{v0l=0|kt[0];v0h=0|kt[1];v1l=0|kt[2];v1h=0|kt[3];v2l=0|kt[4];v2h=0|kt[5];v3l=0|kt[6];v3h=0|kt[7];v4l=0|kt[8];v4h=0|kt[9];v5l=0|kt[10];v5h=0|kt[11];v6l=0|kt[12];v6h=0|kt[13];v7l=0|kt[14];v7h=0|kt[15];constructor(A={}){const t=void 0===A.dkLen?64:A.dkLen;super(128,t),function(A,t={},i,I,g){if(Et(i),A<=0||A>i)throw new Error("outputLen bigger than keyLen");const{key:e,salt:n,personalization:a}=t;if(void 0!==e&&(e.length<1||e.length>i))throw new Error('"key" expected to be undefined or of length=1..'+i);void 0!==n&&ft(n,I,"salt"),void 0!==a&&ft(a,g,"personalization")}(t,A,64,16,16);let{key:i,personalization:I,salt:g}=A,e=0;if(void 0!==i&&(ft(i,void 0,"key"),e=i.length),this.v0l^=this.outputLen|e<<8|65536|1<<24,void 0!==g){ft(g,void 0,"salt");const A=lt(g);this.v4l^=dt(A[0]),this.v4h^=dt(A[1]),this.v5l^=dt(A[2]),this.v5h^=dt(A[3])}if(void 0!==I){ft(I,void 0,"personalization");const A=lt(I);this.v6l^=dt(A[0]),this.v6h^=dt(A[1]),this.v7l^=dt(A[2]),this.v7h^=dt(A[3])}if(void 0!==i){const A=new Uint8Array(this.blockLen);A.set(i),this.update(A)}}get(){let{v0l:A,v0h:t,v1l:i,v1h:I,v2l:g,v2h:e,v3l:n,v3h:a,v4l:C,v4h:Q,v5l:B,v5h:o,v6l:s,v6h:r,v7l:E,v7h:f}=this;return[A,t,i,I,g,e,n,a,C,Q,B,o,s,r,E,f]}set(A,t,i,I,g,e,n,a,C,Q,B,o,s,r,E,f){this.v0l=0|A,this.v0h=0|t,this.v1l=0|i,this.v1h=0|I,this.v2l=0|g,this.v2h=0|e,this.v3l=0|n,this.v3h=0|a,this.v4l=0|C,this.v4h=0|Q,this.v5l=0|B,this.v5h=0|o,this.v6l=0|s,this.v6h=0|r,this.v7l=0|E,this.v7h=0|f}compress(A,t,i){this.get().forEach((A,t)=>vt[t]=A),vt.set(kt,16);let{h:I,l:g}=Nt(BigInt(this.length));vt[24]=kt[8]^g,vt[25]=kt[9]^I,i&&(vt[28]=~vt[28],vt[29]=~vt[29]);let e=0;const n=mt;for(let i=0;i<12;i++)Rt(0,4,8,12,A,t+2*n[e++]),Jt(0,4,8,12,A,t+2*n[e++]),Rt(1,5,9,13,A,t+2*n[e++]),Jt(1,5,9,13,A,t+2*n[e++]),Rt(2,6,10,14,A,t+2*n[e++]),Jt(2,6,10,14,A,t+2*n[e++]),Rt(3,7,11,15,A,t+2*n[e++]),Jt(3,7,11,15,A,t+2*n[e++]),Rt(0,5,10,15,A,t+2*n[e++]),Jt(0,5,10,15,A,t+2*n[e++]),Rt(1,6,11,12,A,t+2*n[e++]),Jt(1,6,11,12,A,t+2*n[e++]),Rt(2,7,8,13,A,t+2*n[e++]),Jt(2,7,8,13,A,t+2*n[e++]),Rt(3,4,9,14,A,t+2*n[e++]),Jt(3,4,9,14,A,t+2*n[e++]);this.v0l^=vt[0]^vt[16],this.v0h^=vt[1]^vt[17],this.v1l^=vt[2]^vt[18],this.v1h^=vt[3]^vt[19],this.v2l^=vt[4]^vt[20],this.v2h^=vt[5]^vt[21],this.v3l^=vt[6]^vt[22],this.v3h^=vt[7]^vt[23],this.v4l^=vt[8]^vt[24],this.v4h^=vt[9]^vt[25],this.v5l^=vt[10]^vt[26],this.v5h^=vt[11]^vt[27],this.v6l^=vt[12]^vt[28],this.v6h^=vt[13]^vt[29],this.v7l^=vt[14]^vt[30],this.v7h^=vt[15]^vt[31],ct(vt)}destroy(){this.destroyed=!0,ct(this.buffer32),this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)}}const Yt=pt(A=>new xt(A));var qt={},Zt={};function zt(A){return(4294901760&A?(A&=4294901760,16):0)|(4278255360&A?(A&=4278255360,8):0)|(4042322160&A?(A&=4042322160,4):0)|(3435973836&A?(A&=3435973836,2):0)|!!(2863311530&A)}function jt(A,t){const i=new DataView(A.buffer,A.byteOffset,A.byteLength);let I="";for(let A=0;A<4;A++){A>0&&(I+="\n"),I+="\t\t";for(let t=0;t<4;t++)t>0&&(I+=" "),I+=i.getUint32(16*A+4*t).toString(16).padStart(8,"0")}return t&&(I=t+"\n"+I),I}function Ot(A,t){if(A.byteLength!=t.byteLength)return!1;for(var i=new Int8Array(A),I=new Int8Array(t),g=0;g!=A.byteLength;g++)if(i[g]!=I[g])return!1;return!0}function Tt(A){return A.clone()}function Wt(A){const t=A.subarray(0,128),i=lt(A.subarray(128)),I=Yt.create({dkLen:64});I.buffer.set(t),I.v0l=0|i[0],I.v0h=0|i[1],I.v1l=0|i[2],I.v1h=0|i[3],I.v2l=0|i[4],I.v2h=0|i[5],I.v3l=0|i[6],I.v3h=0|i[7],I.v4l=0|i[8],I.v4h=0|i[9],I.v5l=0|i[10],I.v5h=0|i[11],I.v6l=0|i[12],I.v6h=0|i[13],I.v7l=0|i[14],I.v7h=0|i[15];const g=2**32,e=i[16]+i[17]*g,n=i[18]+i[19]*g;return I.length=e+n,I.pos=n,I}function Vt(A){const t=new Uint8Array(216),i=lt(t.subarray(128));return t.set(A.buffer),i[0]=A.v0l,i[1]=A.v0h,i[2]=A.v1l,i[3]=A.v1h,i[4]=A.v2l,i[5]=A.v2h,i[6]=A.v3l,i[7]=A.v3h,i[8]=A.v4l,i[9]=A.v4h,i[10]=A.v5l,i[11]=A.v5h,i[12]=A.v6l,i[13]=A.v6h,i[14]=A.v7l,i[15]=A.v7h,i[18]=A.pos,i[16]=A.length-A.pos,t}async function Xt(A,t,i,I,g){if(A.G1.isZero(t))return!1;if(A.G1.isZero(i))return!1;if(A.G2.isZero(I))return!1;if(A.G2.isZero(g))return!1;return await A.pairingEq(t,g,A.G1.neg(i),I)}function Kt(){if("undefined"!=typeof window&&"function"==typeof window.prompt)return window.prompt("Enter a random text. (Entropy): ","");{const A=qt.createInterface({input:process.stdin,output:process.stdout});return new Promise(t=>{A.question("Enter a random text. (Entropy): ",A=>t(A))})}}function _t(A){let t=new Uint8Array(A);if(Zt&&Zt.randomFillSync)Zt.randomFillSync(t);else{if(void 0===globalThis.crypto||!globalThis.crypto.getRandomValues)throw new Error("No secure random source available");for(let i=0;i>>0,I=1):(i=4294967296,I=1<>>0);let g=A;for(let A=0;A{i[I]=ei(A,t[I])}),i}return"bigint"==typeof t||void 0!==t.eq?t.toString(10):t}const ni=10;async function ai(A,t){await KA(A,1),await A.writeULE32(1),await _A(A);const i=await ot(t.q);await KA(A,2);const I=i.q,g=8*(Math.floor((UA.bitLength(I)-1)/64)+1),e=i.r,n=8*(Math.floor((UA.bitLength(e)-1)/64)+1);await A.writeULE32(g),await tt(A,I,g),await A.writeULE32(n),await tt(A,e,n),await A.writeULE32(t.nVars),await A.writeULE32(t.nPublic),await A.writeULE32(t.domainSize),await Ci(A,i,t.vk_alpha_1),await Ci(A,i,t.vk_beta_1),await Qi(A,i,t.vk_beta_2),await Qi(A,i,t.vk_gamma_2),await Ci(A,i,t.vk_delta_1),await Qi(A,i,t.vk_delta_2),await _A(A)}async function Ci(A,t,i){const I=new Uint8Array(2*t.G1.F.n8);t.G1.toRprLEM(I,0,i),await A.write(I)}async function Qi(A,t,i){const I=new Uint8Array(2*t.G2.F.n8);t.G2.toRprLEM(I,0,i),await A.write(I)}async function Bi(A,t,i){const I=await A.read(2*t.G1.F.n8),g=t.G1.fromRprLEM(I,0);return i?t.G1.toObject(g):g}async function oi(A,t,i){const I=await A.read(2*t.G2.F.n8),g=t.G2.fromRprLEM(I,0);return i?t.G2.toObject(g):g}async function si(A,t,i,I){await $A(A,t,1);const g=await A.readULE32();if(await At(A),1===g)return await async function(A,t,i,I){const g={protocol:"groth16"};await $A(A,t,2);const e=await A.readULE32();g.n8q=e,g.q=await it(A,e);const n=await A.readULE32();return g.n8r=n,g.r=await it(A,n),g.curve=await ot(g.q,I),g.nVars=await A.readULE32(),g.nPublic=await A.readULE32(),g.domainSize=await A.readULE32(),g.power=zt(g.domainSize),g.vk_alpha_1=await Bi(A,g.curve,i),g.vk_beta_1=await Bi(A,g.curve,i),g.vk_beta_2=await oi(A,g.curve,i),g.vk_gamma_2=await oi(A,g.curve,i),g.vk_delta_1=await Bi(A,g.curve,i),g.vk_delta_2=await oi(A,g.curve,i),await At(A),g}(A,t,i,I);if(2===g)return await async function(A,t,i,I){const g={protocol:"plonk"};await $A(A,t,2);const e=await A.readULE32();g.n8q=e,g.q=await it(A,e);const n=await A.readULE32();return g.n8r=n,g.r=await it(A,n),g.curve=await ot(g.q,I),g.nVars=await A.readULE32(),g.nPublic=await A.readULE32(),g.domainSize=await A.readULE32(),g.power=zt(g.domainSize),g.nAdditions=await A.readULE32(),g.nConstraints=await A.readULE32(),g.k1=await A.read(n),g.k2=await A.read(n),g.Qm=await Bi(A,g.curve,i),g.Ql=await Bi(A,g.curve,i),g.Qr=await Bi(A,g.curve,i),g.Qo=await Bi(A,g.curve,i),g.Qc=await Bi(A,g.curve,i),g.S1=await Bi(A,g.curve,i),g.S2=await Bi(A,g.curve,i),g.S3=await Bi(A,g.curve,i),g.X_2=await oi(A,g.curve,i),await At(A),g}(A,t,i,I);if(10===g)return await async function(A,t,i,I){const g={protocol:"fflonk"};g.protocolId=ni,await $A(A,t,2);const e=await A.readULE32();g.n8q=e,g.q=await it(A,e),g.curve=await ot(g.q,I);const n=await A.readULE32();return g.n8r=n,g.r=await it(A,n),g.nVars=await A.readULE32(),g.nPublic=await A.readULE32(),g.domainSize=await A.readULE32(),g.power=zt(g.domainSize),g.nAdditions=await A.readULE32(),g.nConstraints=await A.readULE32(),g.k1=await A.read(n),g.k2=await A.read(n),g.w3=await A.read(n),g.w4=await A.read(n),g.w8=await A.read(n),g.wr=await A.read(n),g.X_2=await oi(A,g.curve,i),g.C0=await Bi(A,g.curve,i),await At(A),g}(A,t,i,I);throw new Error("Protocol not supported: ")}async function ri(A,t,i){const I={delta:{}};I.deltaAfter=await Bi(A,t,i),I.delta.g1_s=await Bi(A,t,i),I.delta.g1_sx=await Bi(A,t,i),I.delta.g2_spx=await oi(A,t,i),I.transcript=await A.read(64),I.type=await A.readULE32();const g=await A.readULE32(),e=A.pos;let n=0;for(;A.pos-e0){const t=new Uint8Array(I);await A.writeULE32(t.byteLength),await A.write(t)}else await A.writeULE32(0)}async function wi(A,t,i){await KA(A,10),await A.write(i.csHash),await A.writeULE32(i.contributions.length);for(let I=0;I{pi(A)},t)}(i,Number(I.memoryLogging)>1?Number(I.memoryLogging):1e3)}try{return await async function(A,t,i,I){const{fd:g,sections:e}=await VA(t,"wtns",2,1<<25,1<<23),n=await ci(g,e),{fd:a,sections:C}=await VA(A,"zkey",2,1<<25,1<<23),Q=await si(a,C,void 0,I);if("groth16"!=Q.protocol)throw new Error("zkey file is not groth16");if(!UA.eq(Q.r,n.q))throw new Error("Curve of the witness does not match the curve of the proving key");if(n.nWitness!=Q.nVars)throw new Error(`Invalid witness length. Circuit: ${Q.nVars}, witness: ${n.nWitness}`);const B=Q.curve,o=B.Fr,s=B.G1,r=B.G2;I=I||{};const E=I.msmBatching||"auto";if("auto"!==E&&"enabled"!==E&&"disabled"!==E)throw new Error(`groth16Prove: invalid msmBatching "${E}" (expected "auto", "enabled" or "disabled")`);const f=I.msmGlv||"auto",w=I.msmGls||"auto";for(const[A,t]of[["msmGlv",f],["msmGls",w]])if("auto"!==t&&"disabled"!==t)throw new Error(`groth16Prove: invalid ${A} "${t}" (expected "auto" or "disabled")`);const h={batch:E,glv:f,gls:w},l=zt(Q.domainSize);i&&i.debug("Reading Wtns");const c=await gt(g,e,2),D=A=>{const t=C[A][0].p,i=C[A][0].size;return async(I,g)=>{if(I+g>i)throw new Error(`groth16Prove: read out of range of section ${A}`);const e=new Uint8Array(g);return await a.readToBuffer(e,0,g,t+I),e}};let u,d,y,p=async function(){let A,t,g;await async function(){i&&i.debug("Reading Coeffs");const e=await gt(a,C,4);if(i&&i.debug("Building ABC"),"js"===I.buildABC)[A,t,g]=await async function(A,t,i,I,g){const e=A.Fr.n8,n=12+t.n8r,a=(I.byteLength-4)/n,C=new iA(t.domainSize*e),Q=new iA(t.domainSize*e),B=new iA(t.domainSize*e),o=[C,Q];for(let t=0;tA[Math.floor(i/t)].getUint32(i%t,!0)}else{const A=new DataView(I.buffer,I.byteOffset,I.byteLength);B=t=>A.getUint32(t,!0)}function o(A){let t=0,i=B(0);for(;tA?i=I-1:gE<1<<30?new Uint8Array(E):new iA(E),w=f(),h=f(),l=f(),c=new Set,D=[];for(let t=0;t=n;)await Promise.race(c);g&&g.debug(`buildABCStream: ${t}/${e}`);const u=(async()=>{const t=I.slice(E,f),g=(f-E)/C,e=new Uint8Array(g*a),n=new Uint32Array(t.buffer,t.byteOffset,t.byteLength>>2),Q=C>>2;if(!(!i.buffer||3&i.byteOffset||32!==a)){const A=new Uint32Array(i.buffer,i.byteOffset,i.byteLength>>2),t=new Uint32Array(e.buffer);for(let i=0;ic.delete(d));c.add(d),D.push(d)}return await Promise.all(D),[w,h,l]}function pi(A){if(!A)return;const t=process.memoryUsage();A.info(" "," Heap:",(Math.round(t.heapUsed/1024/1024*100)/100+" MB").padEnd(12)," / ",(Math.round(t.heapTotal/1024/1024*100)/100+" MB").padEnd(12)," RSS:",(Math.round(t.rss/1024/1024*100)/100+" MB").padEnd(12)," External:",(Math.round(t.external/1024/1024*100)/100+" MB").padEnd(12)," ArrBuffers:",(Math.round(t.arrayBuffers/1024/1024*100)/100+" MB").padEnd(12),"")}async function mi(A,t,i,I){if(i=i||262144,"number"!=typeof t&&["w+","wx+","r","ax+","a+"].indexOf(t)<0)throw new Error("Invalid open option");const g=await bA.promises.open(A,t),e=await g.stat();return new Fi(g,e,i,I,A)}let Fi=class{constructor(A,t,i,I,g){for(this.fileName=g,this.fd=A,this.pos=0,this.pageSize=I||256;this.pageSize{t.pendingLoads.push({page:A,resolve:i,reject:I})});return t.__statusPage("After Load request: ",A),i}__statusPage(A,t){const i=[],I=this;if(!I.logHistory)return;i.push("=="+A+" "+t);let g="";for(let A=0;A "+t.history[A][i][I])}_triggerLoad(){const A=this;if(A.reading)return;if(0==A.pendingLoads.length)return;const t=Object.keys(A.pages),i=[];for(let I=0;I0&&(void 0!==A.pages[A.pendingLoads[0].page]||I>0||i.length>0);){const t=A.pendingLoads.shift();if(void 0!==A.pages[t.page]){A.pages[t.page].pendingOps++;const I=i.indexOf(t.page);I>=0&&i.splice(I,1),A.pages[t.page].loading?A.pages[t.page].loading.push(t):t.resolve(),A.__statusPage("After Load (cached): ",t.page)}else{if(I)I--;else{const t=i.shift();A.__statusPage("Before Unload: ",t),A.avBuffs.unshift(A.pages[t]),delete A.pages[t],A.__statusPage("After Unload: ",t)}t.page>=A.totalPages?(A.pages[t.page]=e(),t.resolve(),A.__statusPage("After Load (new): ",t.page)):(A.reading=!0,A.pages[t.page]=e(),A.pages[t.page].loading=[t],g.push(A.fd.read(A.pages[t.page].buff,0,A.pageSize,t.page*A.pageSize).then(i=>{A.pages[t.page].size=i.bytesRead;const I=A.pages[t.page].loading;delete A.pages[t.page].loading;for(let A=0;A{t.reject(A)})),A.__statusPage("After Load (loading): ",t.page))}}function e(){if(A.avBuffs.length>0){const t=A.avBuffs.shift();return t.dirty=!1,t.pendingOps=1,t.size=0,t}return{dirty:!1,buff:new Uint8Array(A.pageSize),pendingOps:1,size:0}}Promise.all(g).then(()=>{A.reading=!1,A.pendingLoads.length>0&&setImmediate(A._triggerLoad.bind(A)),A._tryClose()})}_triggerWrite(){const A=this;if(A.writing)return;const t=Object.keys(A.pages),i=[];for(let I=0;I{g.writing=!1},t=>{console.log("ERROR Writing: "+t),A.error=t,A._tryClose()})))}A.writing&&Promise.all(i).then(()=>{A.writing=!1,setImmediate(A._triggerWrite.bind(A)),A._tryClose(),A.pendingLoads.length>0&&setImmediate(A._triggerLoad.bind(A))})}_getDirtyPage(){for(let A in this.pages)if(this.pages[A].dirty)return A;return-1}async write(A,t){if(0==A.byteLength)return;const i=this;if(void 0===t&&(t=i.pos),i.pos=t+A.byteLength,i.totalSize0;){await e[n-I];const t=a+C>i.pageSize?i.pageSize-a:C,g=A.slice(A.byteLength-C,A.byteLength-C+t);new Uint8Array(i.pages[n].buff.buffer,a,t).set(g),i.pages[n].dirty=!0,i.pages[n].pendingOps--,i.pages[n].size=Math.max(a+t,i.pages[n].size),n>=i.totalPages&&(i.totalPages=n+1),C-=t,n++,a=0,i.writing||setImmediate(i._triggerWrite.bind(i))}}async read(A,t){let i=new Uint8Array(A);return await this.readToBuffer(i,0,A,t),i}async readToBuffer(A,t,i,I){if(0==i)return;const g=this;if(i>g.pageSize*g.maxPagesLoaded*.8){const A=Math.floor(1.1*i);this.maxPagesLoaded=Math.floor(A/g.pageSize)+1}if(void 0===I&&(I=g.pos),g.pos=I+i,g.pendingClose)throw new Error("Reading a closing file");const e=Math.floor(I/g.pageSize),n=Math.floor((I+i-1)/g.pageSize),a=[];for(let A=e;A<=n;A++)a.push(g._loadPage(A));g._triggerLoad();let C=e,Q=I%g.pageSize,B=I+i>g.totalSize?i-(I+i-g.totalSize):i;for(;B>0;){await a[C-e],g.__statusPage("After Await (read): ",C);const I=Q+B>g.pageSize?g.pageSize-Q:B,n=new Uint8Array(g.pages[C].buff.buffer,g.pages[C].buff.byteOffset+Q,I);A.set(n,t+i-B),g.pages[C].pendingOps--,g.__statusPage("After Op done: ",C),B-=I,C++,Q=0,g.pendingLoads.length>0&&setImmediate(g._triggerLoad.bind(g))}this.pos=I+i}_tryClose(){const A=this;if(!A.pendingClose)return;A.error&&A.pendingCloseReject(A.error);A._getDirtyPage()>=0||A.writing||A.reading||A.pendingLoads.length>0||A.pendingClose()}close(){const A=this;if(A.pendingClose)throw new Error("Closing the file twice");return new Promise((t,i)=>{A.pendingClose=t,A.pendingCloseReject=i,A._tryClose()}).then(()=>{A.fd.close()},t=>{throw A.fd.close(),t})}async discard(){await this.close(),await bA.promises.unlink(this.fileName)}async writeULE32(A,t){const i=new Uint8Array(4);new DataView(i.buffer).setUint32(0,A,!0),await this.write(i,t)}async writeUBE32(A,t){const i=new Uint8Array(4);new DataView(i.buffer).setUint32(0,A,!1),await this.write(i,t)}async writeULE64(A,t){const i=new Uint8Array(8),I=new DataView(i.buffer);I.setUint32(0,4294967295&A,!0),I.setUint32(4,Math.floor(A/4294967296),!0),await this.write(i,t)}async readULE32(A){const t=await this.read(4,A);return new Uint32Array(t.buffer)[0]}async readUBE32(A){const t=await this.read(4,A);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(A){const t=await this.read(8,A),i=new Uint32Array(t.buffer);return 4294967296*i[1]+i[0]}async readString(A){const t=this;if(t.pendingClose)throw new Error("Reading a closing file");let i=void 0===A?t.pos:A,I=Math.floor(i/t.pageSize),g=!1,e="";for(;!g;){let A=t._loadPage(I);t._triggerLoad(),await A,t.__statusPage("After Await (read): ",I);let n=i%t.pageSize;const a=new Uint8Array(t.pages[I].buff.buffer,t.pages[I].buff.byteOffset+n,t.pageSize-n);let C=a.findIndex(A=>0===A);g=-1!==C,g?(e+=(new TextDecoder).decode(a.slice(0,C)),t.pos=I*this.pageSize+n+C+1):(e+=(new TextDecoder).decode(a),t.pos=I*this.pageSize+n+a.length),t.pages[I].pendingOps--,t.__statusPage("After Op done: ",I),i=t.pos,I++,t.pendingLoads.length>0&&setImmediate(t._triggerLoad.bind(t))}return e}};const Gi=new Uint8Array(4),Ni=new DataView(Gi.buffer),Ui=new Uint8Array(8),Li=new DataView(Ui.buffer);let bi=class{constructor(){this.pageSize=16384}_resizeIfNeeded(A){if(A>this.allocSize){const t=Math.max(this.allocSize+(1<<20),Math.floor(1.1*this.allocSize),A),i=new Uint8Array(t);i.set(this.o.data),this.o.data=i,this.allocSize=t}}async write(A,t){if(void 0===t&&(t=this.pos),this.readOnly)throw new Error("Writing a read only file");this._resizeIfNeeded(t+A.byteLength),this.o.data.set(A.slice(),t),t+A.byteLength>this.totalSize&&(this.totalSize=t+A.byteLength),this.pos=t+A.byteLength}async readToBuffer(A,t,i,I){if(void 0===I&&(I=this.pos),this.readOnly&&I+i>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(I+i);const g=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+I,i);A.set(g,t),this.pos=I+i}async read(A,t){const i=new Uint8Array(A);return await this.readToBuffer(i,0,A,t),i}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(A,t){Ni.setUint32(0,A,!0),await this.write(Gi,t)}async writeUBE32(A,t){Ni.setUint32(0,A,!1),await this.write(Gi,t)}async writeULE64(A,t){Li.setUint32(0,4294967295&A,!0),Li.setUint32(4,Math.floor(A/4294967296),!0),await this.write(Ui,t)}async readULE32(A){const t=await this.read(4,A);return new Uint32Array(t.buffer)[0]}async readUBE32(A){const t=await this.read(4,A);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(A){const t=await this.read(8,A),i=new Uint32Array(t.buffer);return 4294967296*i[1]+i[0]}async readString(A){const t=this;let i=void 0===A?t.pos:A;if(i>this.totalSize){if(this.readOnly)throw new Error("Reading out of bounds");this._resizeIfNeeded(A)}const I=new Uint8Array(t.o.data.buffer,i,this.totalSize-i);let g=I.findIndex(A=>0===A),e="";return-1!==g?(e=(new TextDecoder).decode(I.slice(0,g)),t.pos=i+g+1):t.pos=i,e}};const Mi=1<<22;const Hi=new Uint8Array(4),Si=new DataView(Hi.buffer),ki=new Uint8Array(8),vi=new DataView(ki.buffer);let Ri=class{constructor(){this.pageSize=16384}_resizeIfNeeded(A){if(A<=this.totalSize)return;if(this.readOnly)throw new Error("Reading out of file bounds");const t=Math.floor((A-1)/Mi)+1;for(let i=Math.max(this.o.data.length-1,0);i0;){const t=g+e>Mi?Mi-g:e,n=A.slice(A.byteLength-e,A.byteLength-e+t);new Uint8Array(i.o.data[I].buffer,g,t).set(n),e-=t,I++,g=0}this.pos=t+A.byteLength}async readToBuffer(A,t,i,I){const g=this;if(void 0===I&&(I=g.pos),this.readOnly&&I+i>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(I+i);let e=Math.floor(I/Mi),n=I%Mi,a=i;for(;a>0;){const I=n+a>Mi?Mi-n:a,C=new Uint8Array(g.o.data[e].buffer,n,I);A.set(C,t+i-a),a-=I,e++,n=0}this.pos=I+i}async read(A,t){const i=new Uint8Array(A);return await this.readToBuffer(i,0,A,t),i}close(){}async discard(){}async writeULE32(A,t){Si.setUint32(0,A,!0),await this.write(Hi,t)}async writeUBE32(A,t){Si.setUint32(0,A,!1),await this.write(Hi,t)}async writeULE64(A,t){vi.setUint32(0,4294967295&A,!0),vi.setUint32(4,Math.floor(A/4294967296),!0),await this.write(ki,t)}async readULE32(A){const t=await this.read(4,A);return new Uint32Array(t.buffer)[0]}async readUBE32(A){const t=await this.read(4,A);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(A){const t=await this.read(8,A),i=new Uint32Array(t.buffer);return 4294967296*i[1]+i[0]}async readString(A){const t=this;let i=void 0===A?t.pos:A;if(i>this.totalSize){if(this.readOnly)throw new Error("Reading out of bounds");this._resizeIfNeeded(A)}let I=!1,g="";for(;!I;){let A=Math.floor(i/Mi),e=i%Mi;if(void 0===t.o.data[A])throw new Error("ERROR");let n=Math.min(2048,t.o.data[A].length-e);const a=new Uint8Array(t.o.data[A].buffer,e,n);let C=a.findIndex(A=>0===A);I=-1!==C,I?(g+=(new TextDecoder).decode(a.slice(0,C)),t.pos=A*Mi+e+C+1):(g+=(new TextDecoder).decode(a),t.pos=A*Mi+e+a.length),i=t.pos}return g}};async function Ji(A,t,i){if("string"==typeof A&&(A={type:"file",fileName:A,cacheSize:65536,pageSize:8192}),"file"==A.type)return await mi(A.fileName,578,A.cacheSize,A.pageSize);if("mem"==A.type)return function(A){const t=A.initialSize||1<<20,i=new bi;return i.o=A,i.o.data=new Uint8Array(t),i.allocSize=t,i.totalSize=0,i.readOnly=!1,i.pos=0,i}(A);if("bigMem"==A.type)return function(A){const t=A.initialSize||0,i=new Ri;i.o=A;const I=t?Math.floor((t-1)/Mi)+1:0;i.o.data=[];for(let A=0;A0;)i.unshift(0),A--}return i}async function zi(A,t){let i,I,g;t=t||{};let e=1,n=0,a=0,C=!1;if(A instanceof WebAssembly.Instance)i=A,C=!0;else{let C=32767;if(t.memorySize&&(C=parseInt(t.memorySize),C<0))throw new Error("Invalid memory size");let Q=!1;for(;!Q;)try{g=new WebAssembly.Memory({initial:C}),Q=!0}catch(A){if(C<=1)throw A;console.warn("Could not allocate "+1024*C*64+" bytes. This may cause severe instability. Trying with "+1024*C*64/2+" bytes"),C=Math.floor(C/2)}const s=await WebAssembly.compile(A);let r="",E="";i=await WebAssembly.instantiate(s,{env:{memory:g},runtime:{printDebug:function(A){console.log("printDebug:",A)},exceptionHandler:function(A){let t;throw t=1===A?"Signal not found. ":2===A?"Too many signals set. ":3===A?"Signal already set. ":4===A?"Assert Failed. ":5===A?"Not enough memory. ":6===A?"Input signal array access exceeds the size. ":"Unknown error. ",console.error("ERROR: ",A,r),new Error(t+r)},printErrorMessage:function(){r+=B()+"\n"},writeBufferMessage:function(){const A=B();"\n"===A?(console.log(E),E=""):(""!==E&&(E+=" "),E+=A)},showSharedRWMemory:function(){const A=i.exports.getFieldNumLen32(),t=new Uint32Array(A);for(let I=0;I=2&&(n>=1||a>=7)){""!==E&&(E+=" ");const A=UA.fromArray(t,4294967296).toString();E+=A}else console.log(UA.fromArray(t,4294967296))},error:function(A,i,g,e,n,a){let C;throw C=7===A?o(i)+" "+I.getFr(e).toString()+" != "+I.getFr(n).toString()+" "+o(a):9===A?o(i)+" "+I.getFr(e).toString()+" "+o(n):5===A&&t.sym?o(i)+" "+t.sym.labelIdx2Name[n]:o(i)+" "+g+" "+e+" "+n+" "+a,console.log("ERROR: ",A,C),new Error(C)},log:function(A){console.log(I.getFr(A).toString())},logGetSignal:function(A,i){t.logGetSignal&&t.logGetSignal(A,I.getFr(i))},logSetSignal:function(A,i){t.logSetSignal&&t.logSetSignal(A,I.getFr(i))},logStartComponent:function(A){t.logStartComponent&&t.logStartComponent(A)},logFinishComponent:function(A){t.logFinishComponent&&t.logFinishComponent(A)}}})}"function"==typeof i.exports.getVersion&&(e=i.exports.getVersion()),"function"==typeof i.exports.getMinorVersion&&(n=i.exports.getMinorVersion()),"function"==typeof i.exports.getPatchVersion&&(a=i.exports.getPatchVersion());const Q=t&&(t.sanityCheck||t.logGetSignal||t.logSetSignal||t.logStartComponent||t.logFinishComponent);if(2===e)I=new Oi(i,Q);else{if(1!==e)throw new Error(`Unsupported circom version: ${e}`);if(C)throw new Error("Loading code from WebAssembly instance is not supported for circom version 1");I=new ji(g,i,Q)}return I;function B(){let A="",t=i.exports.getMessageChar();for(;0!==t;)A+=String.fromCharCode(t),t=i.exports.getMessageChar();return A}function o(A){const t=new Uint8Array(g.buffer),i=[];for(let I=0;t[A+I]>0;I++)i.push(t[A+I]);return String.fromCharCode.apply(null,i)}}class ji{constructor(A,t,i){this.memory=A,this.i32=new Uint32Array(A.buffer),this.instance=t,this.n32=(this.instance.exports.getFrLen()>>2)-2;const I=this.instance.exports.getPRawPrime(),g=new Array(this.n32);for(let A=0;A>2)+A];this.prime=UA.fromArray(g,4294967296),this.Fr=new O(this.prime),this.mask32=UA.fromString("FFFFFFFF",16),this.NVars=this.instance.exports.getNVars(),this.n64=Math.floor((this.Fr.bitLength-1)/64)+1,this.R=this.Fr.e(UA.shiftLeft(1,64*this.n64)),this.RInv=this.Fr.inv(this.R),this.sanityCheck=i}circom_version(){return 1}async _doCalculateWitness(A,t){this.instance.exports.init(this.sanityCheck||t?1:0);const i=this.allocInt(),I=this.allocFr();Object.keys(A).forEach(t=>{const g=qi(t),e=parseInt(g.slice(0,8),16),n=parseInt(g.slice(8,16),16);try{this.instance.exports.getSignalOffset32(i,0,e,n)}catch(A){throw new Error(`Signal ${t} is not an input of the circuit.`)}const a=this.getInt(i),C=xi(A[t]);for(let A=0;A>2]}setInt(A,t){this.i32[A>>2]=t}getFr(A){const t=this,i=A>>2;if(2147483648&t.i32[i+1]){const A=new Array(t.n32);for(let I=0;I>2]=g,void(i.i32[1+(A>>2)]=0)}i.i32[A>>2]=0,i.i32[1+(A>>2)]=2147483648;const e=UA.toArray(t,4294967296);for(let t=0;t>2)+t]=I>=0?e[I]:0}}}class Oi{constructor(A,t){this.instance=A,this.version=this.instance.exports.getVersion(),this.n32=this.instance.exports.getFieldNumLen32(),this.instance.exports.getRawPrime();const i=new Uint32Array(this.n32);for(let A=0;A{const i=qi(t),g=parseInt(i.slice(0,8),16),e=parseInt(i.slice(8,16),16),n=xi(A[t]);if("function"==typeof this.instance.exports.getInputSignalSize){let A=this.instance.exports.getInputSignalSize(g,e);if(A<0)throw new Error(`Signal ${t} not found\n`);if(n.lengthA)throw new Error(`Too many values for input signal ${t}\n`)}for(let A=0;A1)throw new Error(A.fileName+": File has more than one header");A.pos=t[1][0].p;const i=await A.readULE32(),I=await A.read(i),g=UA.fromRprLE(I),e=await ot(g);if(8*e.F1.n64!=i)throw new Error(A.fileName+": Invalid size");const n=await A.readULE32(),a=await A.readULE32();if(A.pos-t[1][0].p!=t[1][0].size)throw new Error("Invalid PTau header size");return{curve:e,power:n,ceremonyPower:a}}function aI(A,t,i,I){const g={tau:{},alpha:{},beta:{}};return g.tau.g1_s=e(),g.tau.g1_sx=e(),g.alpha.g1_s=e(),g.alpha.g1_sx=e(),g.beta.g1_s=e(),g.beta.g1_sx=e(),g.tau.g2_spx=n(),g.alpha.g2_spx=n(),g.beta.g2_spx=n(),g;function e(){let g;return g=I?i.G1.fromRprLEM(A,t):i.G1.fromRprUncompressed(A,t),t+=2*i.G1.F.n8,g}function n(){let g;return g=I?i.G2.fromRprLEM(A,t):i.G2.fromRprUncompressed(A,t),t+=2*i.G2.F.n8,g}}function CI(A,t,i,I,g){async function e(I){g?i.G1.toRprLEM(A,t,I):i.G1.toRprUncompressed(A,t,I),t+=2*i.F1.n8}async function n(I){g?i.G2.toRprLEM(A,t,I):i.G2.toRprUncompressed(A,t,I),t+=2*i.F2.n8}return e(I.tau.g1_s),e(I.tau.g1_sx),e(I.alpha.g1_s),e(I.alpha.g1_sx),e(I.beta.g1_s),e(I.beta.g1_sx),n(I.tau.g2_spx),n(I.alpha.g2_spx),n(I.beta.g2_spx),A}async function QI(A,t){const i={};i.tauG1=await C(),i.tauG2=await Q(),i.alphaG1=await C(),i.betaG1=await C(),i.betaG2=await Q(),i.key=await async function(A,t,i){return aI(await A.read(2*t.F1.n8*6+2*t.F2.n8*3),0,t,i)}(A,t,!0),i.partialHash=await A.read(216),i.nextChallenge=await A.read(64),i.type=await A.readULE32();const I=new Uint8Array(2*t.G1.F.n8*6+2*t.G2.F.n8*3);CI(I,0,t,i.key,!1);const g=Wt(i.partialHash);g.update(I),i.responseHash=g.digest();const e=await A.readULE32(),n=A.pos;let a=0;for(;A.pos-n1)throw new Error(A.fileName+": File has more than one contributions section");A.pos=i[7][0].p;const I=await A.readULE32(),g=[];for(let i=0;i0){const t=new Uint8Array(e);await A.writeULE32(t.byteLength),await A.write(t)}else await A.writeULE32(0);async function n(i){t.G1.toRprLEM(I,0,i),await A.write(I)}async function a(i){t.G2.toRprLEM(g,0,i),await A.write(g)}}async function sI(A,t,i){await A.writeULE32(7);const I=A.pos;await A.writeULE64(0),await A.writeULE32(i.length);for(let I=0;I=256)return e&&e.error("Maximum length of beacon hash is 255 bytes"),!1;if((g=parseInt(g))<10||g>63)return e&&e.error("Invalid numIterationsExp. (Must be between 10 and 63)"),!1;const{fd:a,sections:C}=await VA(A,"ptau",1),{curve:Q,power:B,ceremonyPower:o}=await nI(a,C);if(B!=o)return e&&e.error("This file has been reduced. You cannot contribute into a reduced file."),!1;C[12]&&e&&e.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again.");const s=await BI(a,Q,C),r={name:i,type:1,numIterationsExp:g,beaconHash:n};let E;E=s.length>0?s[s.length-1].nextChallenge:rI(Q,B,e),r.key=await EI(Q,E,n,g);const f=Yt.create({dkLen:64});f.update(E);const w=await XA(t,"ptau",1,7);await eI(w,Q,B);const h=[];let l;l=await d(2,"G1",2**B*2-1,Q.Fr.e(1),r.key.tau.prvKey,"tauG1",e),r.tauG1=l[1],l=await d(3,"G2",2**B,Q.Fr.e(1),r.key.tau.prvKey,"tauG2",e),r.tauG2=l[1],l=await d(4,"G1",2**B,r.key.alpha.prvKey,r.key.tau.prvKey,"alphaTauG1",e),r.alphaG1=l[0],l=await d(5,"G1",2**B,r.key.beta.prvKey,r.key.tau.prvKey,"betaTauG1",e),r.betaG1=l[0],l=await d(6,"G2",1,r.key.beta.prvKey,r.key.tau.prvKey,"betaTauG2",e),r.betaG2=l[0],r.partialHash=Vt(f);const c=new Uint8Array(2*Q.F1.n8*6+2*Q.F2.n8*3);CI(c,0,Q,r.key,!1),f.update(new Uint8Array(c));const D=f.digest();e&&e.info(jt(D,"Contribution Response Hash imported: "));const u=Yt.create({dkLen:64});return u.update(D),await y(w,"G1",2,2**B*2-1,"tauG1",e),await y(w,"G2",3,2**B,"tauG2",e),await y(w,"G1",4,2**B,"alphaTauG1",e),await y(w,"G1",5,2**B,"betaTauG1",e),await y(w,"G2",6,1,"betaG2",e),r.nextChallenge=u.digest(),e&&e.info(jt(r.nextChallenge,"Next Challenge Hash: ")),s.push(r),await sI(w,Q,s),await a.close(),await w.close(),D;async function d(A,t,i,I,g,e,n){const B=[];a.pos=C[A][0].p,await KA(w,A),h[A]=w.pos;const o=Q[t],s=2*o.F.n8,r=Math.floor((1<<20)/s);let E=I;for(let A=0;A1;)Q/=2,B+=1;if(2**B!=C)throw new Error("Invalid file size");g&&g.debug("Power to tau size: "+B);const o=await ti(I),s=await Ji(i),r=Yt.create({dkLen:64});for(let A=0;A{g.debug(t+".g1_s: "+A.G1.toString(w[t].g1_s,16)),g.debug(t+".g1_sx: "+A.G1.toString(w[t].g1_sx,16)),g.debug(t+".g2_sp: "+A.G2.toString(w[t].g2_sp,16)),g.debug(t+".g2_spx: "+A.G2.toString(w[t].g2_spx,16)),g.debug("")});const h=Yt.create({dkLen:64});await s.write(f),h.update(f),await lI(e,s,h,A,"G1",2**B*2-1,A.Fr.one,w.tau.prvKey,"COMPRESSED","tauG1",g),await lI(e,s,h,A,"G2",2**B,A.Fr.one,w.tau.prvKey,"COMPRESSED","tauG2",g),await lI(e,s,h,A,"G1",2**B,w.alpha.prvKey,w.tau.prvKey,"COMPRESSED","alphaTauG1",g),await lI(e,s,h,A,"G1",2**B,w.beta.prvKey,w.tau.prvKey,"COMPRESSED","betaTauG1",g),await lI(e,s,h,A,"G2",1,w.beta.prvKey,w.tau.prvKey,"COMPRESSED","betaTauG2",g);const l=new Uint8Array(2*A.F1.n8*6+2*A.F2.n8*3);CI(l,0,A,w,!1),await s.write(l),h.update(l);const c=h.digest();g&&g.info(jt(c,"Contribution Response Hash: ")),await s.close(),await e.close()},contribute:async function(A,t,i,I,g){const{fd:e,sections:n}=await VA(A,"ptau",1),{curve:a,power:C,ceremonyPower:Q}=await nI(e,n);if(C!=Q)throw g&&g.error("This file has been reduced. You cannot contribute into a reduced file."),new Error("This file has been reduced. You cannot contribute into a reduced file.");n[12]&&g&&g.warn("WARNING: Contributing into a file that has phase2 calculated. You will have to prepare phase2 again.");const B=await BI(e,a,n),o={name:i,type:0};let s;const r=await ti(I);s=B.length>0?B[B.length-1].nextChallenge:rI(a,C,g),o.key=gI(a,s,r);const E=Yt.create({dkLen:64});E.update(s);const f=await XA(t,"ptau",1,7);await eI(f,a,C);const w=[];let h;h=await u(2,"G1",2**C*2-1,a.Fr.e(1),o.key.tau.prvKey,"tauG1"),o.tauG1=h[1],h=await u(3,"G2",2**C,a.Fr.e(1),o.key.tau.prvKey,"tauG2"),o.tauG2=h[1],h=await u(4,"G1",2**C,o.key.alpha.prvKey,o.key.tau.prvKey,"alphaTauG1"),o.alphaG1=h[0],h=await u(5,"G1",2**C,o.key.beta.prvKey,o.key.tau.prvKey,"betaTauG1"),o.betaG1=h[0],h=await u(6,"G2",1,o.key.beta.prvKey,o.key.tau.prvKey,"betaTauG2"),o.betaG2=h[0],o.partialHash=Vt(E);const l=new Uint8Array(2*a.F1.n8*6+2*a.F2.n8*3);CI(l,0,a,o.key,!1),E.update(new Uint8Array(l));const c=E.digest();g&&g.info(jt(c,"Contribution Response Hash imported: "));const D=Yt.create({dkLen:64});return D.update(c),await d(f,"G1",2,2**C*2-1,"tauG1"),await d(f,"G2",3,2**C,"tauG2"),await d(f,"G1",4,2**C,"alphaTauG1"),await d(f,"G1",5,2**C,"betaTauG1"),await d(f,"G2",6,1,"betaG2"),o.nextChallenge=D.digest(),g&&g.info(jt(o.nextChallenge,"Next Challenge Hash: ")),B.push(o),await sI(f,a,B),await e.close(),await f.close(),c;async function u(A,t,i,I,C,Q){const B=[];e.pos=n[A][0].p,await KA(f,A),w[A]=f.pos;const o=a[t],s=2*o.F.n8,r=Math.floor((1<<20)/s);let h=I;for(let A=0;A0?o[o.length-1].nextChallenge:rI(Q,B,e);const c=await XA(i,"ptau",1,g?7:2);await eI(c,Q,B);const D=await h.read(64);if(Ot(n,l)&&(l=D,o[o.length-1].nextChallenge=l),!Ot(D,l))throw new Error("Wrong contribution. This contribution is not based on the previous hash");const u=Yt.create({dkLen:64});u.update(D);const d=[];let y;y=await F(h,c,"G1",2,2**B*2-1,[1],"tauG1"),s.tauG1=y[0],y=await F(h,c,"G2",3,2**B,[1],"tauG2"),s.tauG2=y[0],y=await F(h,c,"G1",4,2**B,[0],"alphaG1"),s.alphaG1=y[0],y=await F(h,c,"G1",5,2**B,[0],"betaG1"),s.betaG1=y[0],y=await F(h,c,"G2",6,1,[0],"betaG2"),s.betaG2=y[0],s.partialHash=Vt(u);const p=await h.read(2*Q.F1.n8*6+2*Q.F2.n8*3);s.key=aI(p,0,Q,!1),u.update(new Uint8Array(p));const m=u.digest();if(e&&e.info(jt(m,"Contribution Response Hash imported: ")),g){const A=Yt.create({dkLen:64});A.update(m),await G(A,c,"G1",2,2**B*2-1,"tauG1",e),await G(A,c,"G2",3,2**B,"tauG2",e),await G(A,c,"G1",4,2**B,"alphaTauG1",e),await G(A,c,"G1",5,2**B,"betaTauG1",e),await G(A,c,"G2",6,1,"betaG2",e),s.nextChallenge=A.digest(),e&&e.info(jt(s.nextChallenge,"Next Challenge Hash: "))}else s.nextChallenge=n;return o.push(s),await sI(c,Q,o),await h.close(),await c.close(),await a.close(),s.nextChallenge;async function F(A,t,i,I,n,a,C){return g?await async function(A,t,i,I,g,n,a){const C=Q[i],B=C.F.n8,o=2*C.F.n8,s=[];await KA(t,I);const r=Math.floor((1<<24)/o);d[I]=t.pos;for(let i=0;i=i&&t=t&&g1?C[C.length-2]:Q;const o=C[C.length-1];if(t&&t.debug("Validating contribution #"+C[C.length-1].id),!await wI(e,o,B,t))return!1;const s=Yt.create({dkLen:64});s.update(o.responseHash),t&&t.debug("Verifying powers in tau*G1 section");const r=await D(2,"G1","tauG1",2**n*2-1,[0,1],t);if(i=await fI(e,r.R1,r.R2,e.G2.g,o.tauG2),!0!==i)return t&&t.error("tauG1 section. Powers do not match"),!1;if(!e.G1.eq(e.G1.g,r.singularPoints[0]))return t&&t.error("First element of tau*G1 section must be the generator"),!1;if(!e.G1.eq(o.tauG1,r.singularPoints[1]))return t&&t.error("Second element of tau*G1 section does not match the one in the contribution section"),!1;t&&t.debug("Verifying powers in tau*G2 section");const E=await D(3,"G2","tauG2",2**n,[0,1],t);if(i=await fI(e,e.G1.g,o.tauG1,E.R1,E.R2),!0!==i)return t&&t.error("tauG2 section. Powers do not match"),!1;if(!e.G2.eq(e.G2.g,E.singularPoints[0]))return t&&t.error("First element of tau*G2 section must be the generator"),!1;if(!e.G2.eq(o.tauG2,E.singularPoints[1]))return t&&t.error("Second element of tau*G2 section does not match the one in the contribution section"),!1;t&&t.debug("Verifying powers in alpha*tau*G1 section");const f=await D(4,"G1","alphatauG1",2**n,[0],t);if(i=await fI(e,f.R1,f.R2,e.G2.g,o.tauG2),!0!==i)return t&&t.error("alphaTauG1 section. Powers do not match"),!1;if(!e.G1.eq(o.alphaG1,f.singularPoints[0]))return t&&t.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"),!1;t&&t.debug("Verifying powers in beta*tau*G1 section");const w=await D(5,"G1","betatauG1",2**n,[0],t);if(i=await fI(e,w.R1,w.R2,e.G2.g,o.tauG2),!0!==i)return t&&t.error("betaTauG1 section. Powers do not match"),!1;if(!e.G1.eq(o.betaG1,w.singularPoints[0]))return t&&t.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"),!1;const h=await async function(A){const t=e.G2,i=2*t.F.n8,n=new Uint8Array(i);if(!g[6])throw A.error("File has no BetaG2 section"),new Error("File has no BetaG2 section");if(g[6].length>1)throw A.error("File has no BetaG2 section"),new Error("File has more than one GetaG2 section");I.pos=g[6][0].p;const a=await I.read(i),C=t.fromRprLEM(a);return t.toRprUncompressed(n,0,C),s.update(n),C}(t);if(!e.G2.eq(o.betaG2,h))return t&&t.error("betaG2 element in betaG2 section does not match the one in the contribution section"),!1;const l=s.digest();if(n==a&&!Ot(l,o.nextChallenge))return t&&t.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"),!1;t&&t.info(jt(l,"Next challenge hash: ")),c(o,B);for(let A=C.length-2;A>=0;A--){const i=C[A],I=A>0?C[A-1]:Q;if(!await wI(e,i,I,t))return!1;c(i,I)}if(t&&t.info("-----------------------------------------------------"),g[12]&&g[13]&&g[14]&&g[15]){let A;if(A=await u("G1",2,12,"tauG1",t),!A)return!1;if(A=await u("G2",3,13,"tauG2",t),!A)return!1;if(A=await u("G1",4,14,"alphaTauG1",t),!A)return!1;if(A=await u("G1",5,15,"betaTauG1",t),!A)return!1}else t&&t.warn('this file does not contain phase2 precalculated values. Please run: \n snarkjs "powersoftau preparephase2" to prepare this file to be used in the phase2 ceremony.');return await I.close(),t&&t.info("Powers of Tau Ok!"),!0;function c(A,i){if(!t)return;t.info("-----------------------------------------------------"),t.info(`Contribution #${A.id}: ${A.name||""}`),t.info(jt(A.nextChallenge,"Next Challenge: "));const I=new Uint8Array(2*e.G1.F.n8*6+2*e.G2.F.n8*3);CI(I,0,e,A.key,!1);const g=Wt(A.partialHash);g.update(I);const n=g.digest();t.info(jt(n,"Response Hash:")),t.info(jt(i.nextChallenge,"Response Hash:")),1==A.type&&(t.info(`Beacon generator: ${gi(A.beaconHash)}`),t.info(`Beacon iterations Exp: ${A.numIterationsExp}`))}async function D(A,t,i,n,a,C){const Q=e[t],B=2*Q.F.n8;await $A(I,g,A);const o=[];let r=Q.zero,E=Q.zero,f=Q.zero;for(let A=0;A0){const A=Q.fromRprLEM(g,0),t=Ai(_t(4),0);r=Q.add(r,Q.timesScalar(f,t)),E=Q.add(E,Q.timesScalar(A,t))}const h=await Q.multiExpAffine(g.slice(0,(t-1)*B),w),l=await Q.multiExpAffine(g.slice(B),w);r=Q.add(r,h),E=Q.add(E,l),f=Q.fromRprLEM(g,(t-1)*B);for(let i=0;i=A&&I=this.length&&(this.length=A+1),!0}getKeys(){const A=new yI;for(let t=0;t{t.pendingLoads.push({page:A,resolve:i,reject:I})});return t.__statusPage("After Load request: ",A),i}__statusPage(A,t){const i=[],I=this;if(!I.logHistory)return;i.push("=="+A+" "+t);let g="";for(let A=0;A "+t.history[A][i][I])}_triggerLoad(){const A=this;if(A.reading)return;if(0==A.pendingLoads.length)return;const t=Object.keys(A.pages),i=[];for(let I=0;I0&&(void 0!==A.pages[A.pendingLoads[0].page]||I>0||i.length>0);){const t=A.pendingLoads.shift();if(void 0!==A.pages[t.page]){A.pages[t.page].pendingOps++;const I=i.indexOf(t.page);I>=0&&i.splice(I,1),A.pages[t.page].loading?A.pages[t.page].loading.push(t):t.resolve(),A.__statusPage("After Load (cached): ",t.page)}else{if(I)I--;else{const t=i.shift();A.__statusPage("Before Unload: ",t),A.avBuffs.unshift(A.pages[t]),delete A.pages[t],A.__statusPage("After Unload: ",t)}t.page>=A.totalPages?(A.pages[t.page]=e(),t.resolve(),A.__statusPage("After Load (new): ",t.page)):(A.reading=!0,A.pages[t.page]=e(),A.pages[t.page].loading=[t],g.push(A.fd.read(A.pages[t.page].buff,0,A.pageSize,t.page*A.pageSize).then(i=>{A.pages[t.page].size=i.bytesRead;const I=A.pages[t.page].loading;delete A.pages[t.page].loading;for(let A=0;A{t.reject(A)})),A.__statusPage("After Load (loading): ",t.page))}}function e(){if(A.avBuffs.length>0){const t=A.avBuffs.shift();return t.dirty=!1,t.pendingOps=1,t.size=0,t}return{dirty:!1,buff:new Uint8Array(A.pageSize),pendingOps:1,size:0}}Promise.all(g).then(()=>{A.reading=!1,A.pendingLoads.length>0&&setImmediate(A._triggerLoad.bind(A)),A._tryClose()})}_triggerWrite(){const A=this;if(A.writing)return;const t=Object.keys(A.pages),i=[];for(let I=0;I{g.writing=!1},t=>{console.log("ERROR Writing: "+t),A.error=t,A._tryClose()})))}A.writing&&Promise.all(i).then(()=>{A.writing=!1,setImmediate(A._triggerWrite.bind(A)),A._tryClose(),A.pendingLoads.length>0&&setImmediate(A._triggerLoad.bind(A))})}_getDirtyPage(){for(let A in this.pages)if(this.pages[A].dirty)return A;return-1}async write(A,t){if(0==A.byteLength)return;const i=this;if(void 0===t&&(t=i.pos),i.pos=t+A.byteLength,i.totalSize0;){await e[n-I];const t=a+C>i.pageSize?i.pageSize-a:C,g=A.slice(A.byteLength-C,A.byteLength-C+t);new Uint8Array(i.pages[n].buff.buffer,a,t).set(g),i.pages[n].dirty=!0,i.pages[n].pendingOps--,i.pages[n].size=Math.max(a+t,i.pages[n].size),n>=i.totalPages&&(i.totalPages=n+1),C-=t,n++,a=0,i.writing||setImmediate(i._triggerWrite.bind(i))}}async read(A,t){let i=new Uint8Array(A);return await this.readToBuffer(i,0,A,t),i}async readToBuffer(A,t,i,I){if(0==i)return;const g=this;if(i>g.pageSize*g.maxPagesLoaded*.8){const A=Math.floor(1.1*i);this.maxPagesLoaded=Math.floor(A/g.pageSize)+1}if(void 0===I&&(I=g.pos),g.pos=I+i,g.pendingClose)throw new Error("Reading a closing file");const e=Math.floor(I/g.pageSize),n=Math.floor((I+i-1)/g.pageSize),a=[];for(let A=e;A<=n;A++)a.push(g._loadPage(A));g._triggerLoad();let C=e,Q=I%g.pageSize,B=I+i>g.totalSize?i-(I+i-g.totalSize):i;for(;B>0;){await a[C-e],g.__statusPage("After Await (read): ",C);const I=Q+B>g.pageSize?g.pageSize-Q:B,n=new Uint8Array(g.pages[C].buff.buffer,g.pages[C].buff.byteOffset+Q,I);A.set(n,t+i-B),g.pages[C].pendingOps--,g.__statusPage("After Op done: ",C),B-=I,C++,Q=0,g.pendingLoads.length>0&&setImmediate(g._triggerLoad.bind(g))}this.pos=I+i}_tryClose(){const A=this;if(!A.pendingClose)return;A.error&&A.pendingCloseReject(A.error);A._getDirtyPage()>=0||A.writing||A.reading||A.pendingLoads.length>0||A.pendingClose()}close(){const A=this;if(A.pendingClose)throw new Error("Closing the file twice");return new Promise((t,i)=>{A.pendingClose=t,A.pendingCloseReject=i,A._tryClose()}).then(()=>{A.fd.close()},t=>{throw A.fd.close(),t})}async discard(){await this.close(),await bA.promises.unlink(this.fileName)}async writeULE32(A,t){const i=new Uint8Array(4);new DataView(i.buffer).setUint32(0,A,!0),await this.write(i,t)}async writeUBE32(A,t){const i=new Uint8Array(4);new DataView(i.buffer).setUint32(0,A,!1),await this.write(i,t)}async writeULE64(A,t){const i=new Uint8Array(8),I=new DataView(i.buffer);I.setUint32(0,4294967295&A,!0),I.setUint32(4,Math.floor(A/4294967296),!0),await this.write(i,t)}async readULE32(A){const t=await this.read(4,A);return new Uint32Array(t.buffer)[0]}async readUBE32(A){const t=await this.read(4,A);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(A){const t=await this.read(8,A),i=new Uint32Array(t.buffer);return 4294967296*i[1]+i[0]}async readString(A){const t=this;if(t.pendingClose)throw new Error("Reading a closing file");let i=void 0===A?t.pos:A,I=Math.floor(i/t.pageSize),g=!1,e="";for(;!g;){let A=t._loadPage(I);t._triggerLoad(),await A,t.__statusPage("After Await (read): ",I);let n=i%t.pageSize;const a=new Uint8Array(t.pages[I].buff.buffer,t.pages[I].buff.byteOffset+n,t.pageSize-n);let C=a.findIndex(A=>0===A);g=-1!==C,g?(e+=(new TextDecoder).decode(a.slice(0,C)),t.pos=I*this.pageSize+n+C+1):(e+=(new TextDecoder).decode(a),t.pos=I*this.pageSize+n+a.length),t.pages[I].pendingOps--,t.__statusPage("After Op done: ",I),i=t.pos,I++,t.pendingLoads.length>0&&setImmediate(t._triggerLoad.bind(t))}return e}}const mI=new Uint8Array(4),FI=new DataView(mI.buffer),GI=new Uint8Array(8),NI=new DataView(GI.buffer);class UI{constructor(){this.pageSize=16384}_resizeIfNeeded(A){if(A>this.allocSize){const t=Math.max(this.allocSize+(1<<20),Math.floor(1.1*this.allocSize),A),i=new Uint8Array(t);i.set(this.o.data),this.o.data=i,this.allocSize=t}}async write(A,t){if(void 0===t&&(t=this.pos),this.readOnly)throw new Error("Writing a read only file");this._resizeIfNeeded(t+A.byteLength),this.o.data.set(A.slice(),t),t+A.byteLength>this.totalSize&&(this.totalSize=t+A.byteLength),this.pos=t+A.byteLength}async readToBuffer(A,t,i,I){if(void 0===I&&(I=this.pos),this.readOnly&&I+i>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(I+i);const g=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+I,i);A.set(g,t),this.pos=I+i}async read(A,t){const i=new Uint8Array(A);return await this.readToBuffer(i,0,A,t),i}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(A,t){FI.setUint32(0,A,!0),await this.write(mI,t)}async writeUBE32(A,t){FI.setUint32(0,A,!1),await this.write(mI,t)}async writeULE64(A,t){NI.setUint32(0,4294967295&A,!0),NI.setUint32(4,Math.floor(A/4294967296),!0),await this.write(GI,t)}async readULE32(A){const t=await this.read(4,A);return new Uint32Array(t.buffer)[0]}async readUBE32(A){const t=await this.read(4,A);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(A){const t=await this.read(8,A),i=new Uint32Array(t.buffer);return 4294967296*i[1]+i[0]}async readString(A){const t=this;let i=void 0===A?t.pos:A;if(i>this.totalSize){if(this.readOnly)throw new Error("Reading out of bounds");this._resizeIfNeeded(A)}const I=new Uint8Array(t.o.data.buffer,i,this.totalSize-i);let g=I.findIndex(A=>0===A),e="";return-1!==g?(e=(new TextDecoder).decode(I.slice(0,g)),t.pos=i+g+1):t.pos=i,e}}const LI=1<<22;const bI=new Uint8Array(4),MI=new DataView(bI.buffer),HI=new Uint8Array(8),SI=new DataView(HI.buffer);class kI{constructor(){this.pageSize=16384}_resizeIfNeeded(A){if(A<=this.totalSize)return;if(this.readOnly)throw new Error("Reading out of file bounds");const t=Math.floor((A-1)/LI)+1;for(let i=Math.max(this.o.data.length-1,0);i0;){const t=g+e>LI?LI-g:e,n=A.slice(A.byteLength-e,A.byteLength-e+t);new Uint8Array(i.o.data[I].buffer,g,t).set(n),e-=t,I++,g=0}this.pos=t+A.byteLength}async readToBuffer(A,t,i,I){const g=this;if(void 0===I&&(I=g.pos),this.readOnly&&I+i>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(I+i);let e=Math.floor(I/LI),n=I%LI,a=i;for(;a>0;){const I=n+a>LI?LI-n:a,C=new Uint8Array(g.o.data[e].buffer,n,I);A.set(C,t+i-a),a-=I,e++,n=0}this.pos=I+i}async read(A,t){const i=new Uint8Array(A);return await this.readToBuffer(i,0,A,t),i}close(){}async discard(){}async writeULE32(A,t){MI.setUint32(0,A,!0),await this.write(bI,t)}async writeUBE32(A,t){MI.setUint32(0,A,!1),await this.write(bI,t)}async writeULE64(A,t){SI.setUint32(0,4294967295&A,!0),SI.setUint32(4,Math.floor(A/4294967296),!0),await this.write(HI,t)}async readULE32(A){const t=await this.read(4,A);return new Uint32Array(t.buffer)[0]}async readUBE32(A){const t=await this.read(4,A);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(A){const t=await this.read(8,A),i=new Uint32Array(t.buffer);return 4294967296*i[1]+i[0]}async readString(A){const t=this;let i=void 0===A?t.pos:A;if(i>this.totalSize){if(this.readOnly)throw new Error("Reading out of bounds");this._resizeIfNeeded(A)}let I=!1,g="";for(;!I;){let A=Math.floor(i/LI),e=i%LI;if(void 0===t.o.data[A])throw new Error("ERROR");let n=Math.min(2048,t.o.data[A].length-e);const a=new Uint8Array(t.o.data[A].buffer,e,n);let C=a.findIndex(A=>0===A);I=-1!==C,I?(g+=(new TextDecoder).decode(a.slice(0,C)),t.pos=A*LI+e+C+1):(g+=(new TextDecoder).decode(a),t.pos=A*LI+e+a.length),i=t.pos}return g}}async function vI(A,t,i){if(A instanceof Uint8Array&&(A={type:"mem",data:A}),"string"==typeof A){A={type:"mem",data:await fetch(A).then(function(A){return A.arrayBuffer()}).then(function(A){return new Uint8Array(A)})}}if("file"==A.type)return await async function(A,t,i,I){i=i||262144;const g=await bA.promises.open(A,t),e=await g.stat();return new pI(g,e,i,I,A)}(A.fileName,0,A.cacheSize,A.pageSize);if("mem"==A.type)return await function(A){const t=new UI;return t.o=A,t.allocSize=A.data.byteLength,t.totalSize=A.data.byteLength,t.readOnly=!0,t.pos=0,t}(A);if("bigMem"==A.type)return await function(A){const t=new kI;return t.o=A,t.totalSize=(A.data.length-1)*LI+A.data[A.data.length-1].byteLength,t.readOnly=!0,t.pos=0,t}(A);throw new Error("Invalid FastFile type: "+A.type)}async function RI(A,t,i){if(void 0!==A.readingSection)throw new Error("Already reading a section");if(!t[i])throw new Error(A.fileName+": Missing section "+i);if(t[i].length>1)throw new Error(A.fileName+": Section Duplicated "+i);A.pos=t[i][0].p,A.readingSection=t[i][0]}async function JI(A,t){if(void 0===A.readingSection)throw new Error("Not reading a section");if(A.pos-A.readingSection.p!=A.readingSection.size)throw new Error("Invalid section size reading");delete A.readingSection}async function PI(A,t,i,I,g){if((I=void 0===I?0:I)+(g=void 0===g?t[i][0].size-I:g)>t[i][0].size)throw new Error("Reading out of the range of the section");let e;return e=g<1<<30?new Uint8Array(g):new iA(g),await A.readToBuffer(e,0,g,t[i][0].p+I),e}async function xI(A,t,i){let I;I="object"==typeof i?i:void 0===i?{singleThread:!1}:{singleThread:i};const g={};if(await RI(A,t,1),g.n8=await A.readULE32(),g.prime=await async function(A,t,i){const I=await A.read(t,i);return UA.fromRprLE(I,0,t)}(A,g.n8),I.F){if(I.F.p!=g.prime)throw new Error("Different Prime");g.F=I.F}else if(I.getFieldFromPrime)g.F=await I.getFieldFromPrime(g.prime,I.singleThread);else if(I.getCurveFromPrime)g.curve=await I.getCurveFromPrime(g.prime,I.singleThread),g.F=g.curve.Fr;else try{g.curve=await async function(A,t){let i;if(u(A,NA))i=await pA(t);else{if(!u(A,GA))throw new Error(`Curve not supported: ${U(A)}`);i=await FA(t)}return i}(g.prime,I.singleThread),g.F=g.curve.Fr}catch{g.F=new O(g.prime)}return g.nVars=await A.readULE32(),g.nOutputs=await A.readULE32(),g.nPubInputs=await A.readULE32(),g.nPrvInputs=await A.readULE32(),g.nLabels=await A.readULE64(),g.nConstraints=await A.readULE32(),g.useCustomGates=void 0!==t[4]&&null!==t[4]&&void 0!==t[5]&&null!==t[5],await JI(A),g}async function YI(A,t,i){if("object"!=typeof i)throw new Error("readR1csFd: options must be an object");i.loadConstraints=!("loadConstraints"in i)||i.loadConstraints,i.loadMap="loadMap"in i&&i.loadMap,i.loadCustomGates=!("loadCustomGates"in i)||i.loadCustomGates;const I=await xI(A,t,i);return i.loadConstraints&&(I.constraints=await async function(A,t,i,I,g){let e;e="object"==typeof I?I:void 0===I?{}:{logger:I,loggerCtx:g};const n=await PI(A,t,2);let a,C=0;a=i.nConstraints>1<<20?new yI:[];for(let A=0;A1<<20?new yI:[];for(let A=0;A1<<20?new yI:[];for(let A=0;Ai)throw new Error("Version not supported");const n=await I.readULE32();let a=[];for(let A=0;A{let I="";return Object.keys(i).forEach(g=>{let e=t.varIdx2Name[g];"one"==e&&(e="1");let n=A.curve.Fr.toString(i[g]);"1"==n&&(n=""),"-1"==n&&(n="-"),""!=I&&"-"!=n[0]&&(n="+"+n),""!=I&&(n=" "+n),I=I+n+e}),I},e=`[ ${g(I[0])} ] * [ ${g(I[1])} ] - [ ${g(I[2])} ] = 0`;i&&i.info(e)}}});async function OI(A){const t={labelIdx2Name:["one"],varIdx2Name:["one"],componentIdx2Name:[]},i=await Pi(A),I=await i.read(i.totalSize),g=new TextDecoder("utf-8").decode(I).split("\n");for(let A=0;A Reading r1cs file");const{fd:I,sections:g}=await VA(A,"r1cs",1,1<<22,1<<24),e=await YI(I,g,{loadConstraints:!1,loadCustomGates:!1});i&&i.info("> Reading witness file");const{fd:n,sections:a}=await VA(t,"wtns",2,1<<22,1<<24),C=await ci(n,a);if(!UA.eq(e.prime,C.q))throw new Error("Curve of the witness does not match the curve of the proving key");const Q=await gt(n,a,2);await n.close();const B=(await Bt(e.prime)).Fr,o=B.n8,s=await gt(I,g,2);i&&(i.info("----------------------------"),i.info(" WITNESS CHECK"),i.info(` Curve: ${e.curve.name}`),i.info(` Vars (wires): ${e.nVars}`),i.info(` Outputs: ${e.nOutputs}`),i.info(` Public Inputs: ${e.nPubInputs}`),i.info(` Private Inputs: ${e.nPrvInputs}`),i.info(` Labels: ${e.nLabels}`),i.info(` Constraints: ${e.nConstraints}`),i.info(` Custom Gates: ${e.useCustomGates}`),i.info("----------------------------")),i&&i.info("> Checking witness correctness");let r=0,E=!0;for(let A=0;A{const I=function(A){return B.fromRprLE(Q.slice(A*o,A*o+o))}(i),g=A[i];t=B.add(t,B.mul(I,g))}),t}function w(){const A={},t=s.slice(r,r+4);r+=4;const i=new DataView(t.buffer).getUint32(0,!0),I=s.slice(r,r+(4+e.n8)*i);r+=(4+e.n8)*i;const g=new DataView(I.buffer);for(let t=0;t=this.length&&(this.length=A+1),!0}getKeys(){const A=new _I;for(let t=0;tC)return I&&I.error(`circuit too big for this power of tau ceremony. ${o.nConstraints}*2 > 2**${C}`),-1;if(!n[12])return I&&I.error("Powers of tau is not prepared."),-1;const w=o.nOutputs+o.nPubInputs,h=2**f;await KA(s,1),await s.writeULE32(1),await _A(s),await KA(s,2);const l=a.q,c=8*(Math.floor((UA.bitLength(l)-1)/64)+1),D=a.r,u=8*(Math.floor((UA.bitLength(D)-1)/64)+1),d=UA.mod(UA.shl(1,8*u),D),y=a.Fr.e(UA.mod(UA.mul(d,d),D));let p,m,F;await s.writeULE32(c),await tt(s,l,c),await s.writeULE32(u),await tt(s,D,u),await s.writeULE32(o.nVars),await s.writeULE32(w),await s.writeULE32(h),p=await e.read(r,n[4][0].p),await s.write(p),p=await a.G1.batchLEMtoU(p),g.update(p),m=await e.read(r,n[5][0].p),await s.write(m),m=await a.G1.batchLEMtoU(m),g.update(m),F=await e.read(E,n[6][0].p),await s.write(F),F=await a.G2.batchLEMtoU(F),g.update(F);const G=new Uint8Array(r);a.G1.toRprLEM(G,0,a.G1.g);const N=new Uint8Array(E);a.G2.toRprLEM(N,0,a.G2.g);const U=new Uint8Array(r);a.G1.toRprUncompressed(U,0,a.G1.g);const L=new Uint8Array(E);a.G2.toRprUncompressed(L,0,a.G2.g),await s.write(N),await s.write(G),await s.write(N),g.update(L),g.update(U),g.update(L),await _A(s),I&&I.info(T()),I&&I.info("Reading r1cs");let b=await gt(Q,B,2);await Q.close();let M=new _I(o.nVars),H=new _I(o.nVars),S=new _I(o.nVars),k=new _I(o.nVars-w-1),v=new Array(w+1);I&&I.info(T()),I&&I.info("Reading tauG1");let R=await gt(e,n,12,(h-1)*r,h*r);I&&I.info("Reading tauG2");let J=await gt(e,n,13,(h-1)*E,h*E);I&&I.info("Reading alphatauG1");let P=await gt(e,n,14,(h-1)*r,h*r);I&&I.info("Reading betatauG1");let x=await gt(e,n,15,(h-1)*r,h*r);I&&I.info(T()),I&&I.info("processConstraints"),await async function(){const A=new Uint8Array(12+a.Fr.n8),t=new DataView(A.buffer),i=new Uint8Array(a.Fr.n8);a.Fr.toRprLE(i,0,a.Fr.e(1));let g=0;function e(){const A=b.slice(g,g+4);g+=4;return new DataView(A.buffer).getUint32(0,!0)}const n=new _I;for(let A=0;A=0?a.Fr.fromRprLE(b.slice(I[3],I[3]+a.Fr.n8),0):a.Fr.fromRprLE(i,0);const e=a.Fr.mul(g,y);a.Fr.toRprLE(A,12,e),C.set(A,B),B+=A.length}await s.write(C),await _A(s)}(),I&&I.info(T()),I&&I.info("composeAndWritePoints"),await q(3,"G1",v,"IC"),v=null,I&&I.info(T()),I&&I.info("writeHs"),await async function(){await KA(s,9);const A=new iA(h*r);if(f(I&&I.debug(`Writing points end ${e}: ${B}/${i.length}`),A))),Q+=g,A++}const B=await Promise.all(C);for(let A=0;A32768?(r=new iA(f*e),E=new iA(f*a.Fr.n8)):(r=new Uint8Array(f*e),E=new Uint8Array(f*a.Fr.n8));let w=0,h=0;const l=[R,J,P,x],c=new Uint8Array(a.Fr.n8);a.Fr.toRprLE(c,0,a.Fr.e(1));let D=0;for(let A=0;A=0?E.set(b.slice(t[A][g][2],t[A][g][2]+a.Fr.n8),D*a.Fr.n8):E.set(c,D*a.Fr.n8),D++;if(t.length>1){const A=[];A.push({cmd:"ALLOCSET",var:0,buff:r}),A.push({cmd:"ALLOCSET",var:1,buff:E}),A.push({cmd:"ALLOC",var:2,len:t.length*n}),w=0,h=0;let i=0;for(let I=0;I=0;A--){const t=B.contributions[A];I&&I.info("-------------------------"),I&&I.info(jt(t.contributionHash,`contribution #${A+1} ${t.name?t.name:""}:`)),1==t.type&&(I&&I.info(`Beacon generator: ${gi(t.beaconHash)}`),I&&I.info(`Beacon iterations Exp: ${t.numIterationsExp}`))}return I&&I.info("-------------------------"),I&&I.info("ZKey Ok!"),!0;async function l(A,t){const i=2*C.G1.F.n8,I=A.byteLength/i,g=C.tm.concurrency,e=Math.floor(I/g),n=[];for(let i=0;i Detected protocol: "+g.protocol),"groth16"===g.protocol)e=await async function(A,t,i){const I=await ot(A.q),g=2*I.G1.F.n8,e=await I.pairing(A.vk_alpha_1,A.vk_beta_2);let n={protocol:A.protocol,curve:I.name,nPublic:A.nPublic,vk_alpha_1:I.G1.toObject(A.vk_alpha_1),vk_beta_2:I.G2.toObject(A.vk_beta_2),vk_gamma_2:I.G2.toObject(A.vk_gamma_2),vk_delta_2:I.G2.toObject(A.vk_delta_2),vk_alphabeta_12:I.Gt.toObject(e)};await $A(t,i,3),n.IC=[];for(let i=0;i<=A.nPublic;i++){const A=await t.read(g),i=I.G1.toObject(A);n.IC.push(i)}return await At(t),n=ig(n),n}(g,i,I);else if("plonk"===g.protocol)e=await async function(A){const t=await ot(A.q);let i={protocol:A.protocol,curve:t.name,nPublic:A.nPublic,power:A.power,k1:t.Fr.toObject(A.k1),k2:t.Fr.toObject(A.k2),Qm:t.G1.toObject(A.Qm),Ql:t.G1.toObject(A.Ql),Qr:t.G1.toObject(A.Qr),Qo:t.G1.toObject(A.Qo),Qc:t.G1.toObject(A.Qc),S1:t.G1.toObject(A.S1),S2:t.G1.toObject(A.S2),S3:t.G1.toObject(A.S3),X_2:t.G2.toObject(A.X_2),w:t.Fr.toObject(t.Fr.w[A.power])};return i=ig(i),i}(g);else{if(!g.protocolId||g.protocolId!==ni)throw new Error("zkey file protocol unrecognized");e=await async function(A){const t=await ot(A.q);let i={protocol:A.protocol,curve:t.name,nPublic:A.nPublic,power:A.power,k1:t.Fr.toObject(A.k1),k2:t.Fr.toObject(A.k2),w:t.Fr.toObject(t.Fr.w[A.power]),w3:t.Fr.toObject(A.w3),w4:t.Fr.toObject(A.w4),w8:t.Fr.toObject(A.w8),wr:t.Fr.toObject(A.wr),X_2:t.G2.toObject(A.X_2),C0:t.G1.toObject(A.C0)};return ig(i)}(g)}return await i.close(),t&&t.info("EXPORT VERIFICATION KEY FINISHED"),e}const{unstringifyBigInts:gg,stringifyBigInts:eg}=LA;async function ng(A,t,i){i&&i.info("FFLONK EXPORT SOLIDITY VERIFIER STARTED");const I=await st(A.curve);let g=B(A.w3);A.w3_2=o(I.Fr.square(g));let e=B(A.w4);A.w4_2=o(I.Fr.square(e)),A.w4_3=o(I.Fr.mul(I.Fr.square(e),e));let n=B(A.w8),a=I.Fr.one;for(let t=1;t<8;t++)a=I.Fr.mul(a,n),A["w8_"+t]=o(a);let C=t[A.protocol];i&&i.info("FFLONK EXPORT SOLIDITY VERIFIER FINISHED");const{default:Q}=await Promise.resolve().then(function(){return $g});return Q.render(C,A);function B(A){const t=gg(A);return I.Fr.fromObject(t)}function o(A){const t=I.Fr.toObject(A);return eg(t)}}var ag=Object.freeze({__proto__:null,beacon:async function(A,t,i,I,g,e){const n=Ii(I);if(0==n.byteLength||2*n.byteLength!=I.length)return e&&e.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"),!1;if(n.length>=256)return e&&e.error("Maximum length of beacon hash is 255 bytes"),!1;if((g=parseInt(g))<10||g>63)return e&&e.error("Invalid numIterationsExp. (Must be between 10 and 63)"),!1;const{fd:a,sections:C}=await VA(A,"zkey",2),Q=await si(a,C);if("groth16"!=Q.protocol)throw new Error("zkey file is not groth16");const B=await ot(Q.q),o=await Ei(a,B,C),s=await XA(t,"zkey",1,10),r=await ii(n,g),E=Yt.create({dkLen:64});E.update(o.csHash);for(let A=0;As.contributions.length)return g&&g.error("The impoerted file does not include new contributions"),!1;for(let A=0;A{const I=this.curve.G1.toObject(this.polynomials[i]);A?t.polynomials[i]=I:t[i]=I}),Object.keys(this.evaluations).forEach(i=>{const I=this.curve.Fr.toObject(this.evaluations[i]);A?t.evaluations[i]=I:t[i]=I}),t}fromObjectProof(A){this.resetProof(),Object.keys(A.polynomials).forEach(t=>{this.polynomials[t]=this.curve.G1.fromObject(A.polynomials[t])}),Object.keys(A.evaluations).forEach(t=>{this.evaluations[t]=this.curve.Fr.fromObject(A.evaluations[t])})}}const Qg=BigInt(0),Bg=BigInt(1),og=BigInt(2),sg=BigInt(7),rg=BigInt(256),Eg=BigInt(113),fg=[],wg=[],hg=[];for(let A=0,t=Bg,i=1,I=0;A<24;A++){[i,I]=[I,(2*i+3*I)%5],fg.push(2*(5*I+i)),wg.push((A+1)*(A+2)/2%64);let g=Qg;for(let A=0;A<7;A++)t=(t<>sg)*Eg)%rg,t&og&&(g^=Bg<<(Bg<i>32?((A,t,i)=>t<>>64-i)(A,t,i):((A,t,i)=>A<>>32-i)(A,t,i),dg=(A,t,i)=>i>32?((A,t,i)=>A<>>64-i)(A,t,i):((A,t,i)=>t<>>32-i)(A,t,i);class yg{state;pos=0;posOut=0;finished=!1;state32;destroyed=!1;blockLen;suffix;outputLen;canXOF;enableXOF=!1;rounds;constructor(A,t,i,I=!1,g=24){if(this.blockLen=A,this.suffix=t,this.outputLen=i,this.enableXOF=I,this.canXOF=I,this.rounds=g,Et(i,"outputLen"),!(024)throw new Error('"rounds" expected integer 1..24');const i=new Uint32Array(10);for(let I=24-t;I<24;I++){for(let t=0;t<10;t++)i[t]=A[t]^A[t+10]^A[t+20]^A[t+30]^A[t+40];for(let t=0;t<10;t+=2){const I=(t+8)%10,g=(t+2)%10,e=i[g],n=i[g+1],a=ug(e,n,1)^i[I],C=dg(e,n,1)^i[I+1];for(let i=0;i<50;i+=10)A[t+i]^=a,A[t+i+1]^=C}let t=A[2],g=A[3];for(let i=0;i<24;i++){const I=wg[i],e=ug(t,g,I),n=dg(t,g,I),a=fg[i];t=A[a],g=A[a+1],A[a]=e,A[a+1]=n}for(let t=0;t<50;t+=10){const i=A[t],I=A[t+1],g=A[t+2],e=A[t+3];A[t]^=~A[t+2]&A[t+4],A[t+1]^=~A[t+3]&A[t+5],A[t+2]^=~A[t+4]&A[t+6],A[t+3]^=~A[t+5]&A[t+7],A[t+4]^=~A[t+6]&A[t+8],A[t+5]^=~A[t+7]&A[t+9],A[t+6]^=~A[t+8]&i,A[t+7]^=~A[t+9]&I,A[t+8]^=~i&g,A[t+9]^=~I&e}A[0]^=cg[I],A[1]^=Dg[I]}ct(i)}(this.state32,this.rounds),yt(this.state32),this.posOut=0,this.pos=0}update(A){wt(this),ft(A);const{blockLen:t,state:i}=this,I=A.length;for(let g=0;g=i&&this.keccak();const e=Math.min(i-this.posOut,g-I);A.set(t.subarray(this.posOut,this.posOut+e),I),this.posOut+=e,I+=e}return A}xofInto(A){if(!this.enableXOF)throw new Error("XOF is not possible for this instance");return this.writeInto(A)}xof(A){return Et(A),this.xofInto(new Uint8Array(A))}digestInto(A){if(ht(A,this),this.finished)throw new Error("digest() was already called");this.writeInto(A.subarray(0,this.outputLen)),this.destroy()}digest(){const A=new Uint8Array(this.outputLen);return this.digestInto(A),A}destroy(){this.destroyed=!0,ct(this.state)}_cloneInto(A){const{blockLen:t,suffix:i,outputLen:I,rounds:g,enableXOF:e}=this;return A||=new yg(t,i,I,e,g),A.blockLen=t,A.state32.set(this.state32),A.pos=this.pos,A.posOut=this.posOut,A.finished=this.finished,A.rounds=g,A.suffix=i,A.outputLen=I,A.enableXOF=e,A.canXOF=this.canXOF,A.destroyed=this.destroyed,A}}const pg=((A,t,i,I={})=>pt(()=>new yg(t,A,i),I))(1,136,32);class mg{constructor(A){this.G1=A.G1,this.Fr=A.Fr,this.reset()}reset(){this.data=[]}addPolCommitment(A){this.data.push({type:0,data:A})}addScalar(A){this.data.push({type:1,data:A})}getChallenge(){if(0===this.data.length)throw new Error("Keccak256Transcript: No data to generate a transcript");let A=0,t=0;this.data.forEach(i=>0===i.type?A++:t++);let i=new Uint8Array(t*this.Fr.n8+A*this.G1.F.n8*2),I=0;for(let A=0;A32768?new iA(A.length*I.n8):new Uint8Array(A.length*I.n8);for(let t=0;t32768?new iA(I*g.n8):new Uint8Array(I*g.n8);return e.set(A.coef.slice(),0),new Gg(e,t,i)}isEqual(A){const t=this.degree();if(t!==A.degree())return!1;for(let i=0;i32768?new iA((this.length()+A.length)*this.Fr.n8):new Uint8Array((this.length()+A.length)*this.Fr.n8);t.set(this.coef,0);for(let i=0;ithis.coef.byteLength?this.Fr.zero:this.coef.slice(t,t+this.Fr.n8)}setCoef(A,t){if(A>this.length()-1)throw new Error("Coef index is not available");this.coef.set(t,A*this.Fr.n8)}static async to4T(A,t,i,I){i=i||[];let g=await I.ifft(A);const e=4*t>32768?new iA(4*t*I.n8):new Uint8Array(4*t*I.n8);e.set(g,0);const n=await I.fft(e);if(0===i.length)return[g,n];const a=t+i.length>32768?new iA((t+i.length)*I.n8):new Uint8Array((t+i.length)*I.n8);a.set(g,0);for(let A=0;A0;A--){const t=A*this.Fr.n8;if(!this.Fr.eq(this.Fr.zero,this.coef.slice(t,t+this.Fr.n8)))return A}return 0}evaluate(A){let t=this.Fr.zero;for(let i=this.degree()+1;i>0;i--){let I=i*this.Fr.n8;const g=this.coef.slice(I-this.Fr.n8,I);t=this.Fr.add(g,this.Fr.mul(t,A))}return t}fastEvaluate(A){const t=this.Fr;let i=this.degree()+1,I=parseInt(i/3),g=i-3*I,e=[],n=[];n[0]=t.one;for(let i=0;i<3;i++){e[i]=t.zero;for(let a=2===i?I+g:I;a>0;a--)e[i]=t.add(this.getCoef(i*I+a-1),t.mul(e[i],A)),0===i&&(n[0]=t.mul(n[0],A))}for(let A=1;A<3;A++)e[0]=t.add(e[0],t.mul(n[A-1],e[A])),n[A]=t.mul(n[A-1],n[0]);return e[0]}add(A,t){let i=!1;A.length()>this.length()&&(i=!0);const I=this.length(),g=A.length();for(let e=0;ethis.length()&&(i=!0);const I=this.length(),g=A.length();for(let e=0;e32768?new iA(i*t.n8):new Uint8Array(i*t.n8);let g=new Gg(I,this.curve,this.logger);g.coef.set(this.coef.slice(0,(i-1)*t.n8),32),this.mulScalar(t.neg(A)),g.add(this),this.coef=g.coef}byXNSubValue(A,t){const i=this.Fr,I=!(this.length()-A-1>=this.degree())?this.length()+A:this.length(),g=I>32768?new iA(I*i.n8):new Uint8Array(I*i.n8);let e=new Gg(g,this.curve,this.logger);e.coef.set(this.coef.slice(0,32*(this.degree()+1)),32*A),this.mulScalar(t),e.add(this),this.coef=e.coef}divBy(A){const t=this.Fr,i=this.degree(),I=A.degree();let g=new Gg(this.coef,this.curve,this.logger);this.coef=this.length()>32768?new iA(this.length()*t.n8):new Uint8Array(this.length()*t.n8);for(let e=i-I;e>=0;e--){this.setCoef(e,t.div(g.getCoef(e+I),A.getCoef(I)));for(let i=0;i<=I;i++)g.setCoef(e+i,t.sub(g.getCoef(e+i),t.mul(this.getCoef(e),A.getCoef(i))))}return g}divByMonic(A,t){const i=this.Fr;let I=this.degree(),g=this.length()>32768?new iA(this.length()*i.n8):new Uint8Array(this.length()*i.n8),e=new Gg(g,this.curve,this.logger),n=[];for(let t=0;t=0&&!(C<0);C-=a){let I=g;n[I]=i.add(this.getCoef(C+A),i.mul(n[I],t)),e.setCoef(C,n[I])}this.coef=e.coef}divByVanishing(A,t){if(this.degree()32768?new iA(this.length()*i.n8):new Uint8Array(this.length()*i.n8);for(let g=this.length()-1;g>=A;g--){let e=I.getCoef(g);i.eq(i.zero,e)||(I.setCoef(g,i.zero),I.setCoef(g-A,i.add(I.getCoef(g-A),i.mul(t,e))),this.setCoef(g-A,i.add(this.getCoef(g-A),e)))}return I}divByVanishing2(A,t){if(this.degree()32768?new iA(this.length()*i.n8):new Uint8Array(this.length()*i.n8);let g=this.length()-A,e=Math.floor(g/3),n=g-2*e;console.log(g),console.log(e+" "+n);for(let g=0;g<3;g++){console.log("> Thread "+g);for(let a=0===g?n:e;a>0;a--){let C=a-1;0!==g&&(C+=(g-1)*e+n);let Q=C+A,B=I.getCoef(Q);i.eq(i.zero,B)||(I.setCoef(Q,i.zero),I.setCoef(C,i.add(I.getCoef(C),i.mul(t,B))),this.setCoef(C,i.add(this.getCoef(C),B)),console.log(C+" <-- "+Q))}}return this.print(),I}fastDivByVanishing(A){const t=this.Fr;for(let i=0;i32768?new iA(this.length()*t.n8):new Uint8Array(this.length()*t.n8),this.curve,this.logger),o=this.coef;this.coef=B.coef,B.coef=o;for(let A=0;A0;A--){let i=A-1,g=i*C+Q;E[i]=[];for(let n=0;n32768?new iA(this.length()*this.Fr.n8):new Uint8Array(this.length()*this.Fr.n8);t.set(this.Fr.zero,(this.length()-1)*this.Fr.n8),t.set(this.coef.slice((this.length()-1)*this.Fr.n8,this.length()*this.Fr.n8),(this.length()-2)*this.Fr.n8);for(let i=this.length()-3;i>=0;i--){let I=i*this.Fr.n8;t.set(this.Fr.add(this.coef.slice(I+this.Fr.n8,I+2*this.Fr.n8),this.Fr.mul(A,t.slice(I+this.Fr.n8,I+2*this.Fr.n8))),i*this.Fr.n8)}if(!this.Fr.eq(this.coef.slice(0,this.Fr.n8),this.Fr.mul(this.Fr.neg(A),t.slice(0,this.Fr.n8))))throw new Error("Polynomial does not divide");this.coef=t}divZh(A,t=4){for(let t=0;tA*(t-1)-t&&!this.Fr.isZero(g))throw new Error("Polynomial is not divisible")}return this}divByZerofier(A,t){let i=this.Fr;const I=i.inv(t),g=i.neg(I);let e=i.eq(i.one,g),n=i.eq(i.negone,g);if(!e)for(let t=0;tthis.length()-A-1&&!this.Fr.isZero(C))throw new Error("Polynomial is not divisible")}return this}byX(){const A=this.length()+1>32768?new iA(this.coef.byteLength+this.Fr.n8):new Uint8Array(this.coef.byteLength+this.Fr.n8);A.set(this.Fr.zero,0),A.set(this.coef,this.Fr.n8),this.coef=A}static async expX(A,t,i=!1){const I=A.Fr;if(t<1)throw new Error("Compute a new polynomial to a zero or negative number is not allowed");if(1===t)return await Gg.fromEvaluations(A.coef,A.curve,A.logger);const g=i?A.degree():A.length()-1,e=g*t+1>32768?new iA((g*t+1)*I.n8):new Uint8Array((g*t+1)*I.n8);e.set(A.getCoef(0),0);for(let i=1;i<=g;i++){const g=i*I.n8,n=A.getCoef(i);e.set(n,g*t)}return new Gg(e,A.curve,A.logger)}split(A,t,i){if(A<1)throw new Error(`Polynomials can't be split in ${A} parts`);if(1===A)return[this];if(0!==i.length&&i.length32768?new iA(n):new Uint8Array(n);g[t]=new Gg(a,this.curve,this.logger);const C=t*I,Q=e?this.coef.byteLength:(t+1)*I;if(g[t].coef.set(this.coef.slice(C,Q),0),e||g[t].coef.set(i[t],I),0!==t){const A=this.Fr.sub(g[t].coef.slice(0,this.Fr.n8),i[t-1]);g[t].coef.set(A,0)}e&&g[t].truncate()}return g}truncate(){const A=this.degree();if(A+132768?new iA((A+1)*this.Fr.n8):new Uint8Array((A+1)*this.Fr.n8);t.set(this.coef.slice(0,(A+1)*this.Fr.n8),0),this.coef=t}}static lagrangePolynomialInterpolation(A,t,i){const I=i.Fr;let g=e(0);for(let t=1;t32768?new iA(A.length*I.n8):new Uint8Array(A.length*I.n8);e=new Gg(g,i),e.setCoef(0,I.neg(A[t])),e.setCoef(1,I.one)}else e.byXSubValue(A[t]);let n=e.evaluate(A[g]);n=I.inv(n);const a=I.mul(t[g],n);return e.mulScalar(a),e}}static zerofierPolynomial(A,t){const i=t.Fr;let I=A.length+1>32768?new iA((A.length+1)*i.n8):new Uint8Array((A.length+1)*i.n8),g=new Gg(I,t);g.setCoef(0,i.neg(A[0])),g.setCoef(1,i.one);for(let t=1;t=0;i--){const I=this.getCoef(i);A.eq(A.zero,I)||(A.isNegative(I)?t+=" - ":i!==this.degree()&&(t+=" + "),t+=A.toString(I),i>0&&(t+=i>1?"x^"+i:"x"))}console.log(t)}async multiExponentiation(A,t){const i=this.coef.byteLength/this.Fr.n8,I=A.slice(0,i*this.G1.F.n8*2),g=await this.Fr.batchFromMontgomery(this.coef);let e=await this.G1.multiExpAffine(I,g,this.logger,t);return e=this.G1.toAffine(e),e}}class Ng{constructor(A,t,i){this.eval=A,this.curve=t,this.Fr=t.Fr,this.logger=i}static async fromPolynomial(A,t,i,I){const g=new iA(A.length()*t*i.Fr.n8);g.set(A.coef,0);const e=await i.Fr.fft(g);return new Ng(e,i,I)}getEvaluation(A){const t=A*this.Fr.n8;if(t+this.Fr.n8>this.eval.byteLength)throw new Error("Evaluations.getEvaluation() out of bounds");return this.eval.slice(t,t+this.Fr.n8)}length(){let A=this.eval.byteLength/this.Fr.n8;if(A!==Math.floor(this.eval.byteLength/this.Fr.n8))throw new Error("Polynomial evaluations buffer has incorrect size");return 0===A&&this.logger.warn("Polynomial has length zero"),A}}const{stringifyBigInts:Ug}=LA;async function Lg(A,t,i,I){const{fd:g,sections:e}=await VA(t,"wtns",2,1<<25,1<<23);i&&i.debug("> Reading witness file");const n=await ci(g,e);i&&i.debug("> Reading zkey file");const{fd:a,sections:C}=await VA(A,"zkey",2,1<<25,1<<23),Q=await si(a,C,void 0,I);if("plonk"!=Q.protocol)throw new Error("zkey file is not plonk");if(!UA.eq(Q.r,n.q))throw new Error("Curve of the witness does not match the curve of the proving key");if(n.nWitness!=Q.nVars-Q.nAdditions)throw new Error(`Invalid witness length. Circuit: ${Q.nVars}, witness: ${n.nWitness}, ${Q.nAdditions}`);const B=Q.curve,o=B.Fr,s=B.Fr.n8,r=Q.domainSize*s;i&&(i.debug("----------------------------"),i.debug(" PLONK PROVE SETTINGS"),i.debug(` Curve: ${B.name}`),i.debug(` Circuit power: ${Q.power}`),i.debug(` Domain size: ${Q.domainSize}`),i.debug(` Vars: ${Q.nVars}`),i.debug(` Public vars: ${Q.nPublic}`),i.debug(` Constraints: ${Q.nConstraints}`),i.debug(` Additions: ${Q.nAdditions}`),i.debug("----------------------------")),i&&i.debug("> Reading witness file data");const E=await gt(g,e,2);E.set(o.zero,0);const f=new iA(s*Q.nAdditions);let w={},h={},l={},c={},D=new Cg(B,i);const u=new mg(B);i&&i.debug("> Reading Section 3. Additions"),await async function(){i&&i.debug("··· Computing additions");const A=await gt(a,C,3),t=8+2*s;for(let I=0;I Reading Section 12. Sigma1, Sigma2 & Sigma 3"),i&&i.debug("··· Reading Sigma polynomials "),h.Sigma1=new Gg(new iA(r),B,i),h.Sigma2=new Gg(new iA(r),B,i),h.Sigma3=new Gg(new iA(r),B,i),await a.readToBuffer(h.Sigma1.coef,0,r,C[12][0].p),await a.readToBuffer(h.Sigma2.coef,0,r,C[12][0].p+5*r),await a.readToBuffer(h.Sigma3.coef,0,r,C[12][0].p+10*r),i&&i.debug("··· Reading Sigma evaluations"),l.Sigma1=new Ng(new iA(4*r),B,i),l.Sigma2=new Ng(new iA(4*r),B,i),l.Sigma3=new Ng(new iA(4*r),B,i),await a.readToBuffer(l.Sigma1.eval,0,4*r,C[12][0].p+r),await a.readToBuffer(l.Sigma2.eval,0,4*r,C[12][0].p+6*r),await a.readToBuffer(l.Sigma3.eval,0,4*r,C[12][0].p+11*r),i&&i.debug("> Reading Section 14. Powers of Tau");const d=await gt(a,C,14);let y=[];for(let A=1;A<=Q.nPublic;A++){const t=E.slice(A*o.n8,A*o.n8+o.n8);y.push(UA.fromRprLE(t))}i&&i.debug(""),i&&i.debug("> ROUND 1"),await async function(){c.b=[];for(let A=1;A<=11;A++)c.b[A]=B.Fr.random();i&&i.debug("> Computing A, B, C wire polynomials");await async function(){i&&i.debug("··· Reading data from zkey file");w.A=new iA(r),w.B=new iA(r),w.C=new iA(r);const A=await gt(a,C,4),t=await gt(a,C,5),I=await gt(a,C,6);for(let i=0;i=Q.domainSize+2)throw new Error("A Polynomial is not well calculated");if(h.B.degree()>=Q.domainSize+2)throw new Error("B Polynomial is not well calculated");if(h.C.degree()>=Q.domainSize+2)throw new Error("C Polynomial is not well calculated")}(),i&&i.debug("> Computing A, B, C MSM");let A=await h.A.multiExponentiation(d,"A"),t=await h.B.multiExponentiation(d,"B"),I=await h.C.multiExponentiation(d,"C");return D.addPolynomial("A",A),D.addPolynomial("B",t),D.addPolynomial("C",I),0}(),i&&i.debug("> ROUND 2"),await async function(){i&&i.debug("> Computing challenges beta and gamma");u.reset(),u.addPolCommitment(Q.Qm),u.addPolCommitment(Q.Ql),u.addPolCommitment(Q.Qr),u.addPolCommitment(Q.Qo),u.addPolCommitment(Q.Qc),u.addPolCommitment(Q.S1),u.addPolCommitment(Q.S2),u.addPolCommitment(Q.S3);for(let A=0;A Computing Z polynomial");await async function(){i&&i.debug("··· Computing Z evaluations");let A=new iA(r),t=new iA(r);A.set(o.one,0),t.set(o.one,0);let I=o.one;for(let i=0;i=Q.domainSize+3)throw new Error("Z Polynomial is not well calculated");delete w.Z}(),i&&i.debug("> Computing Z MSM");let A=await h.Z.multiExponentiation(d,"Z");D.addPolynomial("Z",A)}(),i&&i.debug("> ROUND 3"),await async function(){i&&i.debug("> Computing challenge alpha");u.reset(),u.addScalar(c.beta),u.addScalar(c.gamma),u.addPolCommitment(D.getPolynomial("Z")),c.alpha=u.getChallenge(),c.alpha2=o.square(c.alpha),i&&i.debug("··· challenges.alpha: "+o.toString(c.alpha,16));i&&i.debug("> Computing T polynomial");await async function(){i&&i.debug("··· Reading sections 8, 9, 7, 10, 11. Q selectors");l.QL=new Ng(new iA(4*r),B,i),l.QR=new Ng(new iA(4*r),B,i),l.QM=new Ng(new iA(4*r),B,i),l.QO=new Ng(new iA(4*r),B,i),l.QC=new Ng(new iA(4*r),B,i),await a.readToBuffer(l.QL.eval,0,4*r,C[8][0].p+r),await a.readToBuffer(l.QR.eval,0,4*r,C[9][0].p+r),await a.readToBuffer(l.QM.eval,0,4*r,C[7][0].p+r),await a.readToBuffer(l.QO.eval,0,4*r,C[10][0].p+r),await a.readToBuffer(l.QC.eval,0,4*r,C[11][0].p+r),l.Lagrange=new Ng(new iA(4*r*Q.nPublic),B,i);for(let A=0;A=3*Q.domainSize+6)throw new Error("T Polynomial is not well calculated");i&&i.debug("··· Computing T1, T2, T3 polynomials");h.T1=new Gg(new iA((Q.domainSize+1)*s),B,i),h.T2=new Gg(new iA((Q.domainSize+1)*s),B,i),h.T3=new Gg(new iA((Q.domainSize+6)*s),B,i),h.T1.coef.set(h.T.coef.slice(0,r),0),h.T2.coef.set(h.T.coef.slice(r,2*r),0),h.T3.coef.set(h.T.coef.slice(2*r,3*r+6*s),0),h.T1.setCoef(Q.domainSize,c.b[10]);const t=o.sub(h.T2.getCoef(0),c.b[10]);h.T2.setCoef(0,t),h.T2.setCoef(Q.domainSize,c.b[11]);const I=o.sub(h.T3.getCoef(0),c.b[11]);h.T3.setCoef(0,I)}(),i&&i.debug("> Computing T MSM");let A=await h.T1.multiExponentiation(d,"T1"),t=await h.T2.multiExponentiation(d,"T2"),I=await h.T3.multiExponentiation(d,"T3");D.addPolynomial("T1",A),D.addPolynomial("T2",t),D.addPolynomial("T3",I)}(),i&&i.debug("> ROUND 4"),await async function(){i&&i.debug("> Computing challenge xi");u.reset(),u.addScalar(c.alpha),u.addPolCommitment(D.getPolynomial("T1")),u.addPolCommitment(D.getPolynomial("T2")),u.addPolCommitment(D.getPolynomial("T3")),c.xi=u.getChallenge(),c.xiw=o.mul(c.xi,o.w[Q.power]),i&&i.debug("··· challenges.xi: "+o.toString(c.xi,16));D.addEvaluation("eval_a",h.A.evaluate(c.xi)),D.addEvaluation("eval_b",h.B.evaluate(c.xi)),D.addEvaluation("eval_c",h.C.evaluate(c.xi)),D.addEvaluation("eval_s1",h.Sigma1.evaluate(c.xi)),D.addEvaluation("eval_s2",h.Sigma2.evaluate(c.xi)),D.addEvaluation("eval_zw",h.Z.evaluate(c.xiw))}(),i&&i.debug("> ROUND 5"),await async function(){i&&i.debug("> Computing challenge v");u.reset(),u.addScalar(c.xi),u.addScalar(D.getEvaluation("eval_a")),u.addScalar(D.getEvaluation("eval_b")),u.addScalar(D.getEvaluation("eval_c")),u.addScalar(D.getEvaluation("eval_s1")),u.addScalar(D.getEvaluation("eval_s2")),u.addScalar(D.getEvaluation("eval_zw")),c.v=[],c.v[1]=u.getChallenge(),i&&i.debug("··· challenges.v: "+o.toString(c.v[1],16));for(let A=2;A<6;A++)c.v[A]=o.mul(c.v[A-1],c.v[1]);i&&i.debug("> Computing linearisation polynomial R(X)");await async function(){const A=B.Fr;h.QL=new Gg(new iA(r),B,i),h.QR=new Gg(new iA(r),B,i),h.QM=new Gg(new iA(r),B,i),h.QO=new Gg(new iA(r),B,i),h.QC=new Gg(new iA(r),B,i),await a.readToBuffer(h.QL.coef,0,r,C[8][0].p),await a.readToBuffer(h.QR.coef,0,r,C[9][0].p),await a.readToBuffer(h.QM.coef,0,r,C[7][0].p),await a.readToBuffer(h.QO.coef,0,r,C[10][0].p),await a.readToBuffer(h.QC.coef,0,r,C[11][0].p),c.xin=c.xi;for(let t=0;t Computing opening proof polynomial Wxi(X) polynomial");h.Wxi=new Gg(new iA(r+6*s),B,i),h.Wxi.add(h.R),h.Wxi.add(h.A,c.v[1]),h.Wxi.add(h.B,c.v[2]),h.Wxi.add(h.C,c.v[3]),h.Wxi.add(h.Sigma1,c.v[4]),h.Wxi.add(h.Sigma2,c.v[5]),h.Wxi.subScalar(o.mul(c.v[1],D.evaluations.eval_a)),h.Wxi.subScalar(o.mul(c.v[2],D.evaluations.eval_b)),h.Wxi.subScalar(o.mul(c.v[3],D.evaluations.eval_c)),h.Wxi.subScalar(o.mul(c.v[4],D.evaluations.eval_s1)),h.Wxi.subScalar(o.mul(c.v[5],D.evaluations.eval_s2)),void h.Wxi.divByZerofier(1,c.xi),i&&i.debug("> Computing opening proof polynomial Wxiw(X) polynomial");(async function(){h.Wxiw=Gg.fromPolynomial(h.Z,B,i),h.Wxiw.subScalar(D.evaluations.eval_zw),h.Wxiw.divByZerofier(1,c.xiw)})(),i&&i.debug("> Computing Wxi, Wxiw MSM");let A=await h.Wxi.multiExponentiation(d,"Wxi"),t=await h.Wxiw.multiExponentiation(d,"Wxiw");D.addPolynomial("Wxi",A),D.addPolynomial("Wxiw",t)}(),await a.close(),await g.close();let p=D.toObjectProof(!1);return p.protocol="plonk",p.curve=B.name,i&&i.debug("PLONK PROVER FINISHED"),{proof:Ug(p),publicSignals:Ug(y)};function m(A,t){const i=A.slice(t,t+4);return new DataView(i.buffer,i.byteOffset,i.byteLength).getUint32(0,!0)}function F(A){return Ai;){const t=g.shift(),i=g.shift(),I=t[0],e=i[0],n=l++,a=A.zero,C=A.neg(t[1]),Q=A.neg(i[1]),B=A.one,o=A.zero;w.push([I,e,n,a,C,Q,B,o]),h.push([I,e,t[1],i[1]]),g.push([n,A.one])}for(let A=0;A0?I.toString():i!=A.zero?"k":"0"}function C(t,i,C){const Q=a(t),B=a(i);if("0"===Q||"0"===B)I(C),n(C);else if("k"===Q){n(g(i,t[0],C))}else if("k"===B){n(g(t,i[0],C))}else!function(t,i,I){const g=e(t,1),n=e(i,1),a=e(I,1),C=g.s[0],Q=n.s[0],B=a.s[0],o=A.mul(g.coefs[0],n.coefs[0]),s=A.mul(g.coefs[0],n.k),r=A.mul(g.k,n.coefs[0]),E=A.neg(a.coefs[0]),f=A.sub(A.mul(g.k,n.k),a.k);w.push([C,Q,B,o,s,r,E,f])}(t,i,C)}for(let t=1;t<=c;t++){const i=t,I=0,g=0,e=A.zero,n=A.one,a=A.zero,C=A.zero,Q=A.zero;w.push([i,I,g,e,n,a,C,Q])}for(let A=0;Aa)return I&&I.error(`circuit too big for this power of tau ceremony. ${w.length} > 2**${a}`),-1;if(!e[12])return I&&I.error("Powers of tau is not prepared."),-1;const y=new iA(d*o),p=e[12][0].p+(2**u-1)*o;await g.readToBuffer(y,0,d*o,p);const[m,F]=function(){let A=E.two;for(;i(A,[],u);)E.add(A,E.one);let t=E.add(A,E.one);for(;i(t,[A],u);)E.add(t,E.one);return[A,t];function i(A,t,i){const I=2**i;let g=E.one;for(let e=0;e0?2:this.Fr.isZero(t)?0:1}normalizeLinearCombination(A){const t=Object.keys(A);for(let i=0;ig;){const I=n.shift(),g=n.shift(),e=A.nVars++,a=this.fnGetAdditionConstraint(I[0],g[0],e,this.Fr.neg(I[1]),this.Fr.neg(g[1]),this.Fr.zero,this.Fr.one,this.Fr.zero);t.push(a),i.push([I[0],g[0],I[1],g[1]]),n.push([e,this.Fr.one])}for(let A=0;Athis.n-1)throw new Error("CPolynomial:addPolynomial, cannot add a polynomial to a position greater than n-1");this.polynomials[A]=t}degree(){let A=this.polynomials.map((A,t)=>void 0===A?0:A.degree()*this.n+t);return Math.max(...A)}getPolynomial(){let A=this.polynomials.map(A=>void 0===A?0:A.degree());const t=this.degree(),i=2**(zt(t-1)+1),I=this.Fr.n8;let g=new Gg(new iA(i*I),this.curve,this.logger);for(let i=0;i Reading witness file");const{fd:g,sections:e}=await VA(t,"wtns",2,1<<25,1<<23),n=await ci(g,e);i&&i.info("> Reading zkey file");const{fd:a,sections:C}=await VA(A,"zkey",2,1<<25,1<<23),Q=await si(a,C,void 0,I);if(Q.protocolId!==ni)throw new Error("zkey file is not fflonk");if(!UA.eq(Q.r,n.q))throw new Error("Curve of the witness does not match the curve of the proving key");if(n.nWitness!==Q.nVars-Q.nAdditions)throw new Error(`Invalid witness length. Circuit: ${Q.nVars}, witness: ${n.nWitness}, ${Q.nAdditions}`);const B=Q.curve,o=B.Fr,s=B.Fr.n8,r=2*B.G1.F.n8,E=Q.domainSize*s;i&&(i.info("----------------------------"),i.info(" FFLONK PROVE SETTINGS"),i.info(` Curve: ${B.name}`),i.info(` Circuit power: ${Q.power}`),i.info(` Domain size: ${Q.domainSize}`),i.info(` Vars: ${Q.nVars}`),i.info(` Public vars: ${Q.nPublic}`),i.info(` Constraints: ${Q.nConstraints}`),i.info(` Additions: ${Q.nAdditions}`),i.info("----------------------------")),i&&i.info("> Reading witness file data");const f=await gt(g,e,2);await g.close(),f.set(o.zero,0);const w=new iA(Q.nAdditions*s);let h={},l={},c={},D={},u={},d={},y=new Cg(B,i);i&&i.info("> Reading Section 3. Additions"),await async function(){i&&i.info("··· Computing additions");const A=await gt(a,C,3),t=8+2*s;for(let I=0;I Reading Sections 12,13,14. Sigma1, Sigma2 & Sigma 3"),i&&i.info("··· Reading Sigma polynomials "),l.Sigma1=new Gg(new iA(E),B,i),l.Sigma2=new Gg(new iA(E),B,i),l.Sigma3=new Gg(new iA(E),B,i),await a.readToBuffer(l.Sigma1.coef,0,E,C[12][0].p),await a.readToBuffer(l.Sigma2.coef,0,E,C[13][0].p),await a.readToBuffer(l.Sigma3.coef,0,E,C[14][0].p),i&&i.info("··· Reading Sigma evaluations"),c.Sigma1=new Ng(new iA(4*E),B,i),c.Sigma2=new Ng(new iA(4*E),B,i),c.Sigma3=new Ng(new iA(4*E),B,i),await a.readToBuffer(c.Sigma1.eval,0,4*E,C[12][0].p+E),await a.readToBuffer(c.Sigma2.eval,0,4*E,C[13][0].p+E),await a.readToBuffer(c.Sigma3.eval,0,4*E,C[14][0].p+E),i&&i.info("> Reading Section 16. Powers of Tau");const p=new iA(16*Q.domainSize*r);await a.readToBuffer(p,0,(9*Q.domainSize+18)*r,C[16][0].p),globalThis.gc&&globalThis.gc(),i&&i.info(""),i&&i.info("> ROUND 1"),await async function(){u.b=[];for(let A=1;A<=9;A++)u.b[A]=o.random();i&&i.info("> Computing A, B, C wire polynomials");await async function(){i&&i.info("··· Reading data from zkey file");h.A=new iA(E),h.B=new iA(E),h.C=new iA(E);const A=await gt(a,C,4),t=await gt(a,C,5),I=await gt(a,C,6);for(let i=0;i=Q.domainSize)throw new Error("A Polynomial is not well calculated");if(l.B.degree()>=Q.domainSize)throw new Error("B Polynomial is not well calculated");if(l.C.degree()>=Q.domainSize)throw new Error("C Polynomial is not well calculated")}(),i&&i.info("> Computing T0 polynomial");await async function(){i&&i.info("··· Reading sections 7, 8, 9, 10, 11. Q selectors");c.QL=new Ng(new iA(4*E),B,i),c.QR=new Ng(new iA(4*E),B,i),c.QM=new Ng(new iA(4*E),B,i),c.QO=new Ng(new iA(4*E),B,i),c.QC=new Ng(new iA(4*E),B,i),await a.readToBuffer(c.QL.eval,0,4*E,C[7][0].p+E),await a.readToBuffer(c.QR.eval,0,4*E,C[8][0].p+E),await a.readToBuffer(c.QM.eval,0,4*E,C[9][0].p+E),await a.readToBuffer(c.QO.eval,0,4*E,C[10][0].p+E),await a.readToBuffer(c.QC.eval,0,4*E,C[11][0].p+E);const A=await gt(a,C,15);c.lagrange1=new Ng(A,B,i),h.T0=new iA(4*E),i&&i.info("··· Computing T0 evaluations");for(let A=0;A<4*Q.domainSize;A++){i&&0!==A&&A%1e5==0&&i.info(` T0 evaluation ${A}/${4*Q.domainSize}`);const t=c.A.getEvaluation(A),I=c.B.getEvaluation(A),g=c.C.getEvaluation(A),e=c.QL.getEvaluation(A),n=c.QR.getEvaluation(A),a=c.QM.getEvaluation(A),C=c.QO.getEvaluation(A),B=c.QC.getEvaluation(A);let r=o.zero;for(let t=0;t=2*Q.domainSize-2)throw new Error(`T0 Polynomial is not well calculated (degree is ${l.T0.degree()} and must be less than ${2*Q.domainSize+2}`);delete h.T0}(),i&&i.info("> Computing C1 polynomial");await async function(){let A=new qg(4,B,i);if(A.addPolynomial(0,l.A),A.addPolynomial(1,l.B),A.addPolynomial(2,l.C),A.addPolynomial(3,l.T0),l.C1=A.getPolynomial(),l.C1.degree()>=8*Q.domainSize-8)throw new Error("C1 Polynomial is not well calculated")}(),i&&i.info("> Computing C1 multi exponentiation");let A=await l.C1.multiExponentiation(p,"C1");return y.addPolynomial("C1",A),0}(),delete l.T0,delete c.QL,delete c.QR,delete c.QM,delete c.QO,delete c.QC,globalThis.gc&&globalThis.gc(),i&&i.info("> ROUND 2"),await async function(){i&&i.info("> Computing challenges beta and gamma");const A=new mg(B);A.addPolCommitment(Q.C0);for(let t=0;t Computing Z polynomial");await async function(){i&&i.info("··· Computing Z evaluations");let A=new iA(E),t=new iA(E);A.set(o.one,0),t.set(o.one,0);let I=o.one;for(let g=0;g=Q.domainSize+3)throw new Error("Z Polynomial is not well calculated");delete h.Z}(),i&&i.info("> Computing T1 polynomial");await async function(){i&&i.info("··· Computing T1 evaluations");h.T1=new iA(2*E),h.T1z=new iA(2*E);let A=o.one;for(let t=0;t<2*Q.domainSize;t++){i&&0!==t&&t%1e5==0&&i.info(` T1 evaluation ${t}/${4*Q.domainSize}`);const I=o.square(A),g=c.Z.getEvaluation(2*t),e=o.add(o.add(o.mul(u.b[7],I),o.mul(u.b[8],A)),u.b[9]),n=c.lagrange1.getEvaluation(Q.domainSize+2*t);let a=o.mul(o.sub(g,o.one),n),C=o.mul(e,n);h.T1.set(a,t*s),h.T1z.set(C,t*s),A=o.mul(A,o.w[Q.power+1])}i&&i.info("··· Computing T1 ifft");l.T1=await Gg.fromEvaluations(h.T1,B,i),l.T1.divByZerofier(Q.domainSize,o.one),i&&i.info("··· Computing T1z ifft");if(l.T1z=await Gg.fromEvaluations(h.T1z,B,i),l.T1.add(l.T1z),l.T1.degree()>=Q.domainSize+2)throw new Error("T1 Polynomial is not well calculated");delete h.T1,delete h.T1z,delete l.T1z}(),i&&i.info("> Computing T2 polynomial");await async function(){i&&i.info("··· Computing T2 evaluations");h.T2=new iA(4*E),h.T2z=new iA(4*E);let A=o.one;for(let t=0;t<4*Q.domainSize;t++){i&&0!==t&&t%1e5==0&&i.info(` T2 evaluation ${t}/${4*Q.domainSize}`);const I=o.square(A),g=o.mul(A,o.w[Q.power]),e=o.square(g),n=c.A.getEvaluation(t),a=c.B.getEvaluation(t),C=c.C.getEvaluation(t),B=c.Z.getEvaluation(t),r=c.Z.getEvaluation((4*Q.domainSize+4+t)%(4*Q.domainSize)),E=o.add(o.add(o.mul(u.b[7],I),o.mul(u.b[8],A)),u.b[9]),f=o.add(o.add(o.mul(u.b[7],e),o.mul(u.b[8],g)),u.b[9]),w=c.Sigma1.getEvaluation(t),l=c.Sigma2.getEvaluation(t),D=c.Sigma3.getEvaluation(t),d=o.mul(u.beta,A);let y=o.add(n,d);y=o.add(y,u.gamma);let p=o.add(a,o.mul(d,Q.k1));p=o.add(p,u.gamma);let m=o.add(C,o.mul(d,Q.k2));m=o.add(m,u.gamma);let F=o.mul(o.mul(o.mul(y,p),m),B),G=o.mul(o.mul(o.mul(y,p),m),E),N=o.add(n,o.mul(u.beta,w));N=o.add(N,u.gamma);let U=o.add(a,o.mul(u.beta,l));U=o.add(U,u.gamma);let L=o.add(C,o.mul(u.beta,D));L=o.add(L,u.gamma);let b=o.mul(o.mul(o.mul(N,U),L),r),M=o.mul(o.mul(o.mul(N,U),L),f),H=o.sub(F,b),S=o.sub(G,M);h.T2.set(H,t*s),h.T2z.set(S,t*s),A=o.mul(A,o.w[Q.power+2])}i&&i.info("··· Computing T2 ifft");l.T2=await Gg.fromEvaluations(h.T2,B,i),i&&i.info("··· Computing T2 / ZH");l.T2.divByZerofier(Q.domainSize,o.one),i&&i.info("··· Computing T2z ifft");if(l.T2z=await Gg.fromEvaluations(h.T2z,B,i),l.T2.add(l.T2z),l.T2.degree()>=3*Q.domainSize)throw new Error("T2 Polynomial is not well calculated");delete h.T2,delete h.T2z,delete l.T2z}(),i&&i.info("> Computing C2 polynomial");await async function(){let A=new qg(3,B,i);if(A.addPolynomial(0,l.Z),A.addPolynomial(1,l.T1),A.addPolynomial(2,l.T2),l.C2=A.getPolynomial(),l.C2.degree()>=9*Q.domainSize)throw new Error("C2 Polynomial is not well calculated")}(),i&&i.info("> Computing C2 multi exponentiation");let t=await l.C2.multiExponentiation(p,"C2");return y.addPolynomial("C2",t),0}(),delete h.A,delete h.B,delete h.C,delete c.A,delete c.B,delete c.C,delete c.Sigma1,delete c.Sigma2,delete c.Sigma3,delete c.lagrange1,delete c.Z,globalThis.gc&&globalThis.gc(),i&&i.info("> ROUND 3"),await async function(){i&&i.info("> Computing challenge xi");const A=new mg(B);A.addScalar(u.gamma),A.addPolCommitment(y.getPolynomial("C2")),u.xiSeed=A.getChallenge();const t=o.square(u.xiSeed);d.w8=[],d.w8[0]=o.one;for(let A=1;A<8;A++)d.w8[A]=o.mul(d.w8[A-1],Q.w8);d.w4=[],d.w4[0]=o.one;for(let A=1;A<4;A++)d.w4[A]=o.mul(d.w4[A-1],Q.w4);d.w3=[],d.w3[0]=o.one,d.w3[1]=Q.w3,d.w3[2]=o.square(Q.w3),d.S0={},d.S0.h0w8=[],d.S0.h0w8[0]=o.mul(t,u.xiSeed);for(let A=1;A<8;A++)d.S0.h0w8[A]=o.mul(d.S0.h0w8[0],d.w8[A]);d.S1={},d.S1.h1w4=[],d.S1.h1w4[0]=o.square(d.S0.h0w8[0]);for(let A=1;A<4;A++)d.S1.h1w4[A]=o.mul(d.S1.h1w4[0],d.w4[A]);d.S2={},d.S2.h2w3=[],d.S2.h2w3[0]=o.mul(d.S1.h1w4[0],t),d.S2.h2w3[1]=o.mul(d.S2.h2w3[0],d.w3[1]),d.S2.h2w3[2]=o.mul(d.S2.h2w3[0],d.w3[2]),d.S2.h3w3=[],d.S2.h3w3[0]=o.mul(d.S2.h2w3[0],Q.wr),d.S2.h3w3[1]=o.mul(d.S2.h3w3[0],d.w3[1]),d.S2.h3w3[2]=o.mul(d.S2.h3w3[0],d.w3[2]),u.xi=o.mul(o.square(d.S2.h2w3[0]),d.S2.h2w3[0]),i&&i.info("··· challenges.xi: "+o.toString(u.xi));l.QL=new Gg(new iA(E),B,i),l.QR=new Gg(new iA(E),B,i),l.QM=new Gg(new iA(E),B,i),l.QO=new Gg(new iA(E),B,i),l.QC=new Gg(new iA(E),B,i),await a.readToBuffer(l.QL.coef,0,E,C[7][0].p),await a.readToBuffer(l.QR.coef,0,E,C[8][0].p),await a.readToBuffer(l.QM.coef,0,E,C[9][0].p),await a.readToBuffer(l.QO.coef,0,E,C[10][0].p),await a.readToBuffer(l.QC.coef,0,E,C[11][0].p),i&&i.info("··· Computing evaluations");y.addEvaluation("ql",l.QL.evaluate(u.xi)),y.addEvaluation("qr",l.QR.evaluate(u.xi)),y.addEvaluation("qm",l.QM.evaluate(u.xi)),y.addEvaluation("qo",l.QO.evaluate(u.xi)),y.addEvaluation("qc",l.QC.evaluate(u.xi)),y.addEvaluation("s1",l.Sigma1.evaluate(u.xi)),y.addEvaluation("s2",l.Sigma2.evaluate(u.xi)),y.addEvaluation("s3",l.Sigma3.evaluate(u.xi)),y.addEvaluation("a",l.A.evaluate(u.xi)),y.addEvaluation("b",l.B.evaluate(u.xi)),y.addEvaluation("c",l.C.evaluate(u.xi)),y.addEvaluation("z",l.Z.evaluate(u.xi)),u.xiw=o.mul(u.xi,o.w[Q.power]),y.addEvaluation("zw",l.Z.evaluate(u.xiw)),y.addEvaluation("t1w",l.T1.evaluate(u.xiw)),y.addEvaluation("t2w",l.T2.evaluate(u.xiw))}(),delete l.A,delete l.B,delete l.C,delete l.Z,delete l.T1,delete l.T2,delete l.Sigma1,delete l.Sigma2,delete l.Sigma3,delete l.QL,delete l.QR,delete l.QM,delete l.QC,delete l.QO,globalThis.gc&&globalThis.gc(),i&&i.info("> ROUND 4"),await async function(){i&&i.info("> Computing challenge alpha");const A=new mg(B);A.addScalar(u.xiSeed),A.addScalar(y.getEvaluation("ql")),A.addScalar(y.getEvaluation("qr")),A.addScalar(y.getEvaluation("qm")),A.addScalar(y.getEvaluation("qo")),A.addScalar(y.getEvaluation("qc")),A.addScalar(y.getEvaluation("s1")),A.addScalar(y.getEvaluation("s2")),A.addScalar(y.getEvaluation("s3")),A.addScalar(y.getEvaluation("a")),A.addScalar(y.getEvaluation("b")),A.addScalar(y.getEvaluation("c")),A.addScalar(y.getEvaluation("z")),A.addScalar(y.getEvaluation("zw")),A.addScalar(y.getEvaluation("t1w")),A.addScalar(y.getEvaluation("t2w")),u.alpha=A.getChallenge(),i&&i.info("··· challenges.alpha: "+o.toString(u.alpha));i&&i.info("> Reading C0 polynomial");l.C0=new Gg(new iA(8*E),B,i),await a.readToBuffer(l.C0.coef,0,8*E,C[17][0].p),i&&i.info("> Computing R0 polynomial");(function(){if(l.R0=Gg.lagrangePolynomialInterpolation([d.S0.h0w8[0],d.S0.h0w8[1],d.S0.h0w8[2],d.S0.h0w8[3],d.S0.h0w8[4],d.S0.h0w8[5],d.S0.h0w8[6],d.S0.h0w8[7]],[l.C0.evaluate(d.S0.h0w8[0]),l.C0.evaluate(d.S0.h0w8[1]),l.C0.evaluate(d.S0.h0w8[2]),l.C0.evaluate(d.S0.h0w8[3]),l.C0.evaluate(d.S0.h0w8[4]),l.C0.evaluate(d.S0.h0w8[5]),l.C0.evaluate(d.S0.h0w8[6]),l.C0.evaluate(d.S0.h0w8[7])],B),l.R0.degree()>7)throw new Error("R0 Polynomial is not well calculated")})(),i&&i.info("> Computing R1 polynomial");(function(){if(l.R1=Gg.lagrangePolynomialInterpolation([d.S1.h1w4[0],d.S1.h1w4[1],d.S1.h1w4[2],d.S1.h1w4[3]],[l.C1.evaluate(d.S1.h1w4[0]),l.C1.evaluate(d.S1.h1w4[1]),l.C1.evaluate(d.S1.h1w4[2]),l.C1.evaluate(d.S1.h1w4[3])],B),l.R1.degree()>3)throw new Error("R1 Polynomial is not well calculated")})(),i&&i.info("> Computing R2 polynomial");(function(){if(l.R2=Gg.lagrangePolynomialInterpolation([d.S2.h2w3[0],d.S2.h2w3[1],d.S2.h2w3[2],d.S2.h3w3[0],d.S2.h3w3[1],d.S2.h3w3[2]],[l.C2.evaluate(d.S2.h2w3[0]),l.C2.evaluate(d.S2.h2w3[1]),l.C2.evaluate(d.S2.h2w3[2]),l.C2.evaluate(d.S2.h3w3[0]),l.C2.evaluate(d.S2.h3w3[1]),l.C2.evaluate(d.S2.h3w3[2])],B),l.R2.degree()>5)throw new Error("R2 Polynomial is not well calculated")})(),i&&i.info("> Computing F polynomial");await async function(){i&&i.info("··· Computing F polynomial");l.F=Gg.fromPolynomial(l.C0,B,i),l.F.sub(l.R0),l.F.divByZerofier(8,u.xi);let A=Gg.fromPolynomial(l.C1,B,i);A.sub(l.R1),A.mulScalar(u.alpha),A.divByZerofier(4,u.xi);let t=Gg.fromPolynomial(l.C2,B,i);if(t.sub(l.R2),t.mulScalar(o.square(u.alpha)),t.divByZerofier(3,u.xi),t.divByZerofier(3,u.xiw),l.F.add(A),l.F.add(t),l.F.degree()>=9*Q.domainSize-6)throw new Error("F Polynomial is not well calculated")}(),i&&i.info("> Computing W1 multi exponentiation");let t=await l.F.multiExponentiation(p,"W1");return y.addPolynomial("W1",t),0}(),globalThis.gc&&globalThis.gc(),i&&i.info("> ROUND 5"),await async function(){i&&i.info("> Computing challenge y");const A=new mg(B);A.addScalar(u.alpha),A.addPolCommitment(y.getPolynomial("W1")),u.y=A.getChallenge(),i&&i.info("··· challenges.y: "+o.toString(u.y));i&&i.info("> Computing L polynomial");await async function(){i&&i.info("··· Computing L polynomial");const A=l.R0.evaluate(u.y),t=l.R1.evaluate(u.y),I=l.R2.evaluate(u.y);let g=o.sub(u.y,d.S0.h0w8[0]);for(let A=1;A<8;A++)g=o.mul(g,o.sub(u.y,d.S0.h0w8[A]));let e=o.sub(u.y,d.S1.h1w4[0]);for(let A=1;A<4;A++)e=o.mul(e,o.sub(u.y,d.S1.h1w4[A]));let n=o.sub(u.y,d.S2.h2w3[0]);for(let A=1;A<3;A++)n=o.mul(n,o.sub(u.y,d.S2.h2w3[A]));for(let A=0;A<3;A++)n=o.mul(n,o.sub(u.y,d.S2.h3w3[A]));let a=o.mul(e,n),C=o.mul(u.alpha,o.mul(g,n)),s=o.mul(o.square(u.alpha),o.mul(g,e));D.denH1=e,D.denH2=n,l.L=Gg.fromPolynomial(l.C0,B,i),l.L.subScalar(A),l.L.mulScalar(a);let r=Gg.fromPolynomial(l.C1,B,i);r.subScalar(t),r.mulScalar(C);let E=Gg.fromPolynomial(l.C2,B,i);E.subScalar(I),E.mulScalar(s),l.L.add(r),l.L.add(E),i&&i.info("> Computing ZT polynomial");await async function(){l.ZT=Gg.zerofierPolynomial([d.S0.h0w8[0],d.S0.h0w8[1],d.S0.h0w8[2],d.S0.h0w8[3],d.S0.h0w8[4],d.S0.h0w8[5],d.S0.h0w8[6],d.S0.h0w8[7],d.S1.h1w4[0],d.S1.h1w4[1],d.S1.h1w4[2],d.S1.h1w4[3],d.S2.h2w3[0],d.S2.h2w3[1],d.S2.h2w3[2],d.S2.h3w3[0],d.S2.h3w3[1],d.S2.h3w3[2]],B)}();const f=l.ZT.evaluate(u.y);if(l.F.mulScalar(f),l.L.sub(l.F),l.L.degree()>=9*Q.domainSize)throw new Error("L Polynomial is not well calculated");delete h.L}(),i&&i.info("> Computing ZTS2 polynomial");await async function(){l.ZTS2=Gg.zerofierPolynomial([d.S1.h1w4[0],d.S1.h1w4[1],d.S1.h1w4[2],d.S1.h1w4[3],d.S2.h2w3[0],d.S2.h2w3[1],d.S2.h2w3[2],d.S2.h3w3[0],d.S2.h3w3[1],d.S2.h3w3[2]],B)}();let t=l.ZTS2.evaluate(u.y);t=o.inv(t),l.L.mulScalar(t);const I=Gg.fromCoefficientsArray([o.neg(u.y),o.one],B);i&&i.info("> Computing W' = L / ZTS2 polynomial");const g=l.L.divBy(I);if(g.degree()>0)throw new Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${g.degree()} and should be 0`);if(l.L.degree()>=9*Q.domainSize-1)throw new Error("Degree of L(X)/(ZTS2(y)(X-y)) is not correct");i&&i.info("> Computing W' multi exponentiation");let e=await l.L.multiExponentiation(p,"W2");return y.addPolynomial("W2",e),0}(),delete l.C0,delete l.C1,delete l.C2,delete l.R1,delete l.R2,delete l.F,delete l.L,delete l.ZT,delete l.ZTS2,await a.close(),globalThis.gc&&globalThis.gc(),y.addEvaluation("inv",function(){let A=u.xi;for(let t=0;t Reading PTau file");const{fd:g,sections:e}=await VA(t,"ptau",1,1<<22,1<<24);if(!e[12])throw new Error("Powers of Tau is not well prepared. Section 12 missing.");I&&I.info("> Getting curve from PTau settings");const{curve:n}=await nI(g,e);I&&I.info("> Reading r1cs file");const{fd:a,sections:C}=await VA(A,"r1cs",1,1<<22,1<<24),Q=await YI(a,C,{loadConstraints:!1,loadCustomGates:!0});if(Q.prime!==n.r)throw new Error("r1cs curve does not match powers of tau ceremony curve");const B=n.Fr,o=n.Fr.n8,s=2*n.G1.F.n8,r=2*n.G2.F.n8;let E,f={},w={},h={nVars:Q.nVars,nPublic:Q.nOutputs+Q.nPubInputs};const l=new _I;let c=new _I;if(I&&I.info("> Processing FFlonk constraints"),await async function(A,t,i){for(let t=0;t computing k1 and k2");const[D,u]=function(){let A=B.two;for(;i(A,[],h.cirPower);)B.add(A,B.one);let t=B.add(A,B.one);for(;i(t,[A],h.cirPower);)B.add(t,B.one);return[A,t];function i(A,t,i){const I=2**i;let g=B.one;for(let e=0;e computing w3");const d=function(){let A=B.e(31624),t=UA.div(3648040478639879203707734290876212514758060733402672390616367364429301415936n,UA.e(3));return B.exp(A,t)}();I&&I.info("> computing w4");const y=B.w[2];I&&I.info("> computing w8");const p=B.w[3];I&&I.info("> computing wr");const m=function(A,t){const i=t.e(467799165886069610036046866799264026481344299079011762026774533774345988080n);return t.exp(i,2**(28-A))}(h.cirPower,n.Fr);return await async function(){I&&I.info("> Writing the zkey file");const A=await XA(i,"zkey",1,17,1<<22,1<<24);I&&I.info("··· Writing Section 1. Zkey Header");await async function(A){await KA(A,1),await A.writeULE32(ni),await _A(A)}(A),I&&I.info("··· Writing Section 3. Additions");await async function(A){await KA(A,3);const t=new Uint8Array(8+2*o),i=new DataView(t.buffer);for(let g=0;g=8*h.domainSize)throw new Error("C0 Polynomial is not well calculated");await KA(A,17),await A.write(f.C0.coef),await _A(A)}(A),globalThis.gc&&globalThis.gc();I&&I.info("··· Writing Section 2. FFlonk Header");await async function(A){await KA(A,2);const t=n.q,i=8*(Math.floor((UA.bitLength(t)-1)/64)+1);await A.writeULE32(i),await tt(A,t,i);const I=n.r,a=8*(Math.floor((UA.bitLength(I)-1)/64)+1);let C;await A.writeULE32(a),await tt(A,I,a),await A.writeULE32(h.nVars),await A.writeULE32(h.nPublic),await A.writeULE32(h.domainSize),await A.writeULE32(c.length),await A.writeULE32(l.length),await A.write(D),await A.write(u),await A.write(d),await A.write(y),await A.write(p),await A.write(m),C=await g.read(r,e[3][0].p+r),await A.write(C);let Q=await f.C0.multiExponentiation(E,"C0");await A.write(Q),await _A(A)}(A),globalThis.gc&&globalThis.gc();I&&I.info("> Writing the zkey file finished");await A.close()}(),await a.close(),await g.close(),I&&I.info("FFLONK SETUP FINISHED"),0;async function F(A,t,i,g){await KA(A,t);for(let t=0;t Checking commitments belong to G1"),!function(A,t,i){const I=A.G1;return I.isValid(t.polynomials.C1)&&I.isValid(t.polynomials.C2)&&I.isValid(t.polynomials.W1)&&I.isValid(t.polynomials.W2)&&I.isValid(i.C0)}(g,n,e))return I&&I.error("Proof commitments are not valid"),!1;if(I&&I.info("> Checking evaluations belong to F"),!function(A,t){return Wg(A,t.evaluations.ql)&&Wg(A,t.evaluations.qr)&&Wg(A,t.evaluations.qm)&&Wg(A,t.evaluations.qo)&&Wg(A,t.evaluations.qc)&&Wg(A,t.evaluations.s1)&&Wg(A,t.evaluations.s2)&&Wg(A,t.evaluations.s3)&&Wg(A,t.evaluations.a)&&Wg(A,t.evaluations.b)&&Wg(A,t.evaluations.c)&&Wg(A,t.evaluations.z)&&Wg(A,t.evaluations.zw)&&Wg(A,t.evaluations.t1w)&&Wg(A,t.evaluations.t2w)}(g,n))return I&&I.error("Proof evaluations are not valid."),!1;if(I&&I.info("> Checking public inputs belong to F"),!function(A,t){for(let i=0;i Computing challenges");const{challenges:Q,roots:B}=function(A,t,i,I,g){const e=A.Fr,n={},a={},C=new mg(A);C.addPolCommitment(i.C0);for(let A=0;A Computing Zero polynomial evaluation Z_H(xi)"),Q.zh=C.sub(Q.xiN,C.one),Q.invzh=C.inv(Q.zh),I&&I.info("> Computing Lagrange evaluations");const o=await async function(A,t,i){const I=A.Fr,g=Math.max(1,i.nPublic),e=new iA(g*I.n8);let n=new iA(g*I.n8),a=I.one;for(let A=0;A Computing polynomial identities PI(X)");const s=function(A,t,i){const I=A.Fr;let g=I.zero;for(let A=0;A Computing r0(y)");const r=function(A,t,i,I,g){const e=I.Fr,n=Vg(i.S0.h0w8,t.y,t.xi,I);g&&g.info("··· Computing r0(y)");let a=e.zero;for(let t=0;t<8;t++){let I=[];I[1]=i.S0.h0w8[t];for(let A=2;A<8;A++)I[A]=e.mul(I[A-1],i.S0.h0w8[t]);let g=e.add(A.evaluations.ql,e.mul(A.evaluations.qr,I[1]));g=e.add(g,e.mul(A.evaluations.qo,I[2])),g=e.add(g,e.mul(A.evaluations.qm,I[3])),g=e.add(g,e.mul(A.evaluations.qc,I[4])),g=e.add(g,e.mul(A.evaluations.s1,I[5])),g=e.add(g,e.mul(A.evaluations.s2,I[6])),g=e.add(g,e.mul(A.evaluations.s3,I[7])),a=e.add(a,e.mul(g,n[t]))}return a}(n,Q,B,g,I);I&&I.info("> Computing r1(y)");const E=function(A,t,i,I,g,e){const n=g.Fr,a=Vg(i.S1.h1w4,t.y,t.xi,g);e&&e.info("··· Computing T0(xi)");let C=n.mul(A.evaluations.ql,A.evaluations.a);C=n.add(C,n.mul(A.evaluations.qr,A.evaluations.b)),C=n.add(C,n.mul(A.evaluations.qm,n.mul(A.evaluations.a,A.evaluations.b))),C=n.add(C,n.mul(A.evaluations.qo,A.evaluations.c)),C=n.add(C,A.evaluations.qc),C=n.add(C,I),C=n.mul(C,t.invzh),e&&e.info("··· Computing C1(h_1ω_4^i) values");let Q=n.zero;for(let t=0;t<4;t++){let I=A.evaluations.a;I=n.add(I,n.mul(i.S1.h1w4[t],A.evaluations.b));const g=n.square(i.S1.h1w4[t]);I=n.add(I,n.mul(g,A.evaluations.c)),I=n.add(I,n.mul(n.mul(g,i.S1.h1w4[t]),C)),Q=n.add(Q,n.mul(I,a[t]))}return Q}(n,Q,B,s,g,I);I&&I.info("> Computing r2(y)");const f=function(A,t,i,I,g,e,n){const a=e.Fr,C=function(A,t,i,I,g){const e=g.Fr,n=[],a=A[0].length,C=a*A.length,Q=e.exp(t,C),B=e.mul(e.add(i,I),e.exp(t,a)),o=e.mul(i,I),s=e.add(e.sub(Q,B),o);let r=e.mul(e.mul(e.e(a),A[0][0]),e.sub(i,I));for(let i=0;i Computing F");const w=function(A,t,i,I,g){const e=A.G1,n=A.Fr;let a=n.sub(I.y,g.S0.h0w8[0]);for(let A=1;A<8;A++)a=n.mul(a,n.sub(I.y,g.S0.h0w8[A]));I.temp=a;let C=n.sub(I.y,g.S1.h1w4[0]);for(let A=1;A<4;A++)C=n.mul(C,n.sub(I.y,g.S1.h1w4[A]));let Q=n.sub(I.y,g.S2.h2w3[0]);for(let A=1;A<3;A++)Q=n.mul(Q,n.sub(I.y,g.S2.h2w3[A]));for(let A=0;A<3;A++)Q=n.mul(Q,n.sub(I.y,g.S2.h3w3[A]));I.quotient1=n.mul(I.alpha,n.div(a,C)),I.quotient2=n.mul(n.square(I.alpha),n.div(a,Q));let B=e.timesFr(t.polynomials.C1,I.quotient1),o=e.timesFr(t.polynomials.C2,I.quotient2);return e.add(i.C0,e.add(B,o))}(g,n,e,Q,B);I&&I.info("> Computing E");const h=function(A,t,i,I,g,e,n){const a=A.G1,C=A.Fr;let Q=C.mul(e,i.quotient1),B=C.mul(n,i.quotient2);return a.timesFr(a.one,C.add(g,C.add(Q,B)))}(g,0,Q,0,r,E,f);I&&I.info("> Computing J");const l=function(A,t,i){const I=A.G1;return I.timesFr(t.polynomials.W1,i.temp)}(g,n,Q);I&&I.info("> Validate all evaluations with a pairing");const c=await async function(A,t,i,I,g,e,n){const a=A.G1;let C=a.timesFr(t.polynomials.W2,i.y);C=a.add(a.sub(a.sub(g,e),n),C);const Q=A.G2.one,B=t.polynomials.W2,o=I.X_2;return await A.pairingEq(a.neg(C),Q,B,o)}(g,n,Q,e,w,h,l);return I&&(c?I.info("PROOF VERIFIED SUCCESSFULLY"):I.warn("Invalid Proof")),I&&I.info("FFLONK VERIFIER FINISHED"),c}}),$g=Object.freeze({__proto__:null,default:{}});return A.curves=rt,A.fflonk=_g,A.groth16=AI,A.plonk=Rg,A.powersOfTau=cI,A.r1cs=jI,A.wtns=WI,A.zKey=ag,A}({}); +var snarkjs=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=Object.defineProperty,n=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(e){throw n=[e],e}},r=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},i=r({ModuleBuilder:()=>o,buildBls12381:()=>c,buildBn128:()=>s,default:()=>l}),a,o,s,c,l,u=n((()=>{a=()=>{throw Error(`wasm codegen toolchain is not included in the snarkjs browser bundle (only needed when building a curve with custom wasm plugins)`)},o=class{constructor(){a()}},s=a,c=a,l={}})),d=Object.create,f=Object.defineProperty,p=Object.getOwnPropertyDescriptor,m=Object.getOwnPropertyNames,h=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty,_=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),v=(e,t)=>{let n={};for(var r in e)f(n,r,{get:e[r],enumerable:!0});return t||f(n,Symbol.toStringTag,{value:`Module`}),n},y=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=m(t),a=0,o=i.length,s;at[e]).bind(null,s),enumerable:!(r=p(t,s))||r.enumerable});return e},b=(e,t,n)=>(n=e==null?{}:d(h(e)),y(t||!e||!e.__esModule?f(n,`default`,{value:e,enumerable:!0}):n,e)),x=v({abs:()=>le,add:()=>ne,band:()=>ve,bitLength:()=>E,bits:()=>P,bor:()=>ye,bxor:()=>be,div:()=>ue,e:()=>w,eq:()=>fe,exp:()=>ce,fromArray:()=>T,fromRprBE:()=>De,fromRprLE:()=>Ee,fromString:()=>C,geq:()=>_e,gt:()=>he,isNegative:()=>D,isOdd:()=>ee,isZero:()=>O,land:()=>xe,leq:()=>ge,lnot:()=>Ce,lor:()=>Se,lt:()=>me,mod:()=>de,mul:()=>ae,naf:()=>N,neg:()=>ie,neq:()=>pe,one:()=>je,pow:()=>se,shiftLeft:()=>k,shiftRight:()=>A,shl:()=>j,shr:()=>M,square:()=>oe,sub:()=>re,toArray:()=>te,toLEBuff:()=>ke,toNumber:()=>F,toRprBE:()=>Te,toRprLE:()=>we,toString:()=>Oe,zero:()=>Ae}),S=[0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4];function C(e,t){if(!t||t==10)return BigInt(e);if(t==16)return e.slice(0,2)==`0x`?BigInt(e):BigInt(`0x`+e)}var w=C;function T(e,t){let n=BigInt(0);t=BigInt(t);for(let r=0;r>BigInt(t)}var j=k,M=A;function ee(e){return(BigInt(e)&BigInt(1))==BigInt(1)}function N(e){let t=BigInt(e),n=[];for(;t;){if(t&BigInt(1)){let e=2-Number(t%BigInt(4));n.push(e),t-=BigInt(e)}else n.push(0);t>>=BigInt(1)}return n}function P(e){let t=BigInt(e),n=[];for(;t;)t&BigInt(1)?n.push(1):n.push(0),t>>=BigInt(1);return n}function F(e){if(e>BigInt(2**53-1))throw Error(`Number too big`);return Number(e)}function te(e,t){let n=[],r=BigInt(e);for(t=BigInt(t);r;)n.unshift(Number(r%t)),r/=t;return n}function ne(e,t){return BigInt(e)+BigInt(t)}function re(e,t){return BigInt(e)-BigInt(t)}function ie(e){return-BigInt(e)}function ae(e,t){return BigInt(e)*BigInt(t)}function oe(e){return BigInt(e)*BigInt(e)}function se(e,t){return BigInt(e)**BigInt(t)}function ce(e,t){return BigInt(e)**BigInt(t)}function le(e){return BigInt(e)>=0?BigInt(e):-BigInt(e)}function ue(e,t){return BigInt(e)/BigInt(t)}function de(e,t){return BigInt(e)%BigInt(t)}function fe(e,t){return BigInt(e)==BigInt(t)}function pe(e,t){return BigInt(e)!=BigInt(t)}function me(e,t){return BigInt(e)BigInt(t)}function ge(e,t){return BigInt(e)<=BigInt(t)}function _e(e,t){return BigInt(e)>=BigInt(t)}function ve(e,t){return BigInt(e)&BigInt(t)}function ye(e,t){return BigInt(e)|BigInt(t)}function be(e,t){return BigInt(e)^BigInt(t)}function xe(e,t){return BigInt(e)&&BigInt(t)}function Se(e,t){return BigInt(e)||BigInt(t)}function Ce(e){return!BigInt(e)}function we(e,t,n,r){let i=`0000000`+n.toString(16),a=new Uint32Array(e.buffer,e.byteOffset+t,r/4),o=((i.length-7)*4-1>>5)+1;for(let e=0;e>5)+1;for(let e=0;ei[i.length-t-1]=e.toString(16).padStart(8,`0`)),C(i.join(``),16)}function De(e,t,n){n||=e.byteLength,t||=0;let r=new DataView(e.buffer,e.byteOffset+t,n),i=Array(n/4);for(let e=0;e>=1;return n}function Pe(e,t,n){if(O(n))return e.one;let r=P(n);if(r.length==0)return e.one;let i=t;for(let n=r.length-2;n>=0;n--)i=e.square(i),r[n]&&(i=e.mul(i,t));return i}function Fe(e){if(e.m%2==1)if(fe(de(e.p,4),1))if(fe(de(e.p,8),1))if(fe(de(e.p,16),1))Ie(e);else if(fe(de(e.p,16),9))Le(e);else throw Error(`Field withot sqrt`);else if(fe(de(e.p,8),5))Re(e);else throw Error(`Field withot sqrt`);else fe(de(e.p,4),3)&&ze(e);else{let t=de(se(e.p,e.m/2),4);t==1?Be(e):t==3?Ve(e):He(e)}}function Ie(e){for(e.sqrt_q=se(e.p,e.m),e.sqrt_s=0,e.sqrt_t=re(e.sqrt_q,1);!ee(e.sqrt_t);)e.sqrt_s+=1,e.sqrt_t=ue(e.sqrt_t,2);let t=e.one;for(;e.eq(t,e.one);){let n=e.random();e.sqrt_z=e.pow(n,e.sqrt_t),t=e.pow(e.sqrt_z,2**(e.sqrt_s-1))}e.sqrt_tm1d2=ue(re(e.sqrt_t,1),2),e.sqrt=function(e){let t=this;if(t.isZero(e))return t.zero;let n=t.pow(e,t.sqrt_tm1d2),r=t.pow(t.mul(t.square(n),e),2**(t.sqrt_s-1));if(t.eq(r,t.negone))return null;let i=t.sqrt_s,a=t.mul(e,n),o=t.mul(a,n),s=t.sqrt_z;for(;!t.eq(o,t.one);){let e=t.square(o),r=1;for(;!t.eq(e,t.one);)e=t.square(e),r++;n=s;for(let e=0;e>>0,e[i]=(e[i]^e[t])>>>0,e[i]=(e[i]<<16|e[i]>>>16&65535)>>>0,e[r]=e[r]+e[i]>>>0,e[n]=(e[n]^e[r])>>>0,e[n]=(e[n]<<12|e[n]>>>20&4095)>>>0,e[t]=e[t]+e[n]>>>0,e[i]=(e[i]^e[t])>>>0,e[i]=(e[i]<<8|e[i]>>>24&255)>>>0,e[r]=e[r]+e[i]>>>0,e[n]=(e[n]^e[r])>>>0,e[n]=(e[n]<<7|e[n]>>>25&127)>>>0}function We(e){Ue(e,0,4,8,12),Ue(e,1,5,9,13),Ue(e,2,6,10,14),Ue(e,3,7,11,15),Ue(e,0,5,10,15),Ue(e,1,6,11,12),Ue(e,2,7,8,13),Ue(e,3,4,9,14)}var Ge=class{constructor(e){e||=[0,0,0,0,0,0,0,0],this.state=[1634760805,857760878,2036477234,1797285236,e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],0,0,0,0],this.idx=16,this.buff=Array(16)}nextU32(){return this.idx==16&&this.update(),this.buff[this.idx++]}nextU64(){return ne(ae(this.nextU32(),4294967296),this.nextU32())}nextBool(){return(this.nextU32()&1)==1}update(){for(let e=0;e<16;e++)this.buff[e]=this.state[e];for(let e=0;e<10;e++)We(this.buff);for(let e=0;e<16;e++)this.buff[e]=this.buff[e]+this.state[e]>>>0;this.idx=0,this.state[12]=this.state[12]+1>>>0,this.state[12]==0&&(this.state[13]=this.state[13]+1>>>0,this.state[13]==0&&(this.state[14]=this.state[14]+1>>>0,this.state[14]==0&&(this.state[15]=this.state[15]+1>>>0)))}},Ke=b(_(((e,t)=>{t.exports={}}))(),1);function qe(e){let t=new Uint8Array(e);if(Ke.default&&Ke.default.randomFillSync)Ke.default.randomFillSync(t);else if(globalThis.crypto!==void 0&&globalThis.crypto.getRandomValues)for(let n=0;n>>0;return t}function Je(){let e=qe(32),t=new Uint32Array(e.buffer),n=[];for(let e=0;e<8;e++)n.push(t[e]);return n}var Ye=null;function Xe(){return Ye||(Ye=new Ge(Je()),Ye)}var Ze=class{constructor(e,t,n){this.F=t,this.G=e,this.opMulGF=n;let r=t.sqrt_t||t.t,i=t.sqrt_s||t.s,a=t.one;for(;t.eq(t.pow(a,t.half),t.one);)a=t.add(a,t.one);this.w=Array(i+1),this.wi=Array(i+1),this.w[i]=this.F.pow(a,r),this.wi[i]=this.F.inv(this.w[i]);let o=i-1;for(;o>=0;)this.w[o]=this.F.square(this.w[o+1]),this.wi[o]=this.F.square(this.wi[o+1]),o--;this.roots=[],this._setRoots(Math.min(i,15))}_setRoots(e){for(let t=e;t>=0&&!this.roots[t];t--){let e=this.F.one,n=1<>1,s=$e(e,t,n-1,r,i*2),c=$e(e,t,n-1,r+i,i*2),l=Array(a);for(let t=0;t>this.one,this.bitLength=E(this.p),this.mask=(this.one<>this.one;this.nqr=this.two;let n=this.pow(this.nqr,t);for(;!this.eq(n,this.negone);)this.nqr+=this.one,n=this.pow(this.nqr,t);for(this.s=0,this.t=this.negone;(this.t&this.one)==this.zero;)this.s+=1,this.t>>=this.one;this.nqr_to_t=this.pow(this.nqr,this.t),Fe(this),this.FFT=new Ze(this,this,this.mul.bind(this)),this.fft=this.FFT.fft.bind(this.FFT),this.ifft=this.FFT.ifft.bind(this.FFT),this.w=this.FFT.w,this.wi=this.FFT.wi,this.shift=this.square(this.nqr),this.k=this.exp(this.nqr,2**this.s)}e(e,t){let n;if(t?t==16&&(n=BigInt(`0x`+e)):n=BigInt(e),n<0){let e=-n;return e>=this.p&&(e%=this.p),this.p-e}else return n>=this.p?n%this.p:n}add(e,t){let n=e+t;return n>=this.p?n-this.p:n}sub(e,t){return e>=t?e-t:this.p-t+e}neg(e){return e&&this.p-e}mul(e,t){return e*t%this.p}mulScalar(e,t){return e*this.e(t)%this.p}square(e){return e*e%this.p}eq(e,t){return e==t}neq(e,t){return e!=t}lt(e,t){return(e>this.half?e-this.p:e)<(t>this.half?t-this.p:t)}gt(e,t){return(e>this.half?e-this.p:e)>(t>this.half?t-this.p:t)}leq(e,t){return(e>this.half?e-this.p:e)<=(t>this.half?t-this.p:t)}geq(e,t){return(e>this.half?e-this.p:e)>=(t>this.half?t-this.p:t)}div(e,t){return this.mul(e,this.inv(t))}idiv(e,t){if(!t)throw Error(`Division by zero`);return e/t}inv(e){if(!e)throw Error(`Division by zero`);let t=this.zero,n=this.p,r=this.one,i=e%this.p;for(;i;){let e=n/i;[t,r]=[r,t-e*r],[n,i]=[i,n-e*i]}return t=this.p?n-this.p:n}bor(e,t){let n=(e|t)&this.mask;return n>=this.p?n-this.p:n}bxor(e,t){let n=(e^t)&this.mask;return n>=this.p?n-this.p:n}bnot(e){let t=e^this.mask;return t>=this.p?t-this.p:t}shl(e,t){if(Number(t)=this.p?n-this.p:n}else{let n=this.p-t;return Number(n)>n:this.zero}}shr(e,t){if(Number(t)>t;{let n=this.p-t;if(Number(n)=this.p?t-this.p:t}else return 0}}land(e,t){return e&&t?this.one:this.zero}lor(e,t){return e||t?this.one:this.zero}lnot(e){return e?this.zero:this.one}sqrt_old(e){if(e==this.zero)return this.zero;if(this.pow(e,this.negone>>this.one)!=this.one)return null;let t=this.s,n=this.nqr_to_t,r=this.pow(e,this.t),i=this.pow(e,this.add(this.t,this.one)>>this.one);for(;r!=this.one;){let e=this.square(r),a=1;for(;e!=this.one;)a++,e=this.square(e);let o=n;for(let e=0;ethis.p>>this.one&&(i=this.neg(i)),i}normalize(e,t){if(e=BigInt(e,t),e<0){let t=-e;return t>=this.p&&(t%=this.p),this.p-t}else return e>=this.p?e%this.p:e}random(){let e=this.bitLength*2/8,t=this.zero;for(let n=0;nthis.half&&t==10?`-`+(this.p-e).toString(t):e.toString(t),n}isZero(e){return e==this.zero}fromRng(e){let t;do{t=this.zero;for(let n=0;n=this.p);return t=t*this.Ri%this.p,t}fft(e){return this.FFT.fft(e)}ifft(e){return this.FFT.ifft(e)}toRprLE(e,t,n){we(e,t,n,this.n64*8)}toRprBE(e,t,n){Te(e,t,n,this.n64*8)}toRprBEM(e,t,n){return this.toRprBE(e,t,this.mul(this.R,n))}toRprLEM(e,t,n){return this.toRprLE(e,t,this.mul(this.R,n))}fromRprLE(e,t){return Ee(e,t,this.n8)}fromRprBE(e,t){return De(e,t,this.n8)}fromRprLEM(e,t){return this.mul(this.fromRprLE(e,t),this.Ri)}fromRprBEM(e,t){return this.mul(this.fromRprBE(e,t),this.Ri)}toObject(e){return e}},tt=v({array2buffer:()=>ht,beBuff2int:()=>it,beInt2Buff:()=>at,bitReverse:()=>ft,buffReverseBits:()=>mt,buffer2array:()=>gt,leBuff2int:()=>ot,leInt2Buff:()=>st,log2:()=>pt,stringifyBigInts:()=>nt,stringifyFElements:()=>ct,unstringifyBigInts:()=>rt,unstringifyFElements:()=>lt});function nt(e){if(typeof e==`bigint`||e.eq!==void 0)return e.toString(10);if(e instanceof Uint8Array)return Ee(e,0);if(Array.isArray(e))return e.map(nt);if(typeof e==`object`){let t={};return Object.keys(e).forEach(n=>{t[n]=nt(e[n])}),t}else return e}function rt(e){if(typeof e==`string`&&/^[0-9]+$/.test(e)||typeof e==`string`&&/^0x[0-9a-fA-F]+$/.test(e))return BigInt(e);if(Array.isArray(e))return e.map(rt);if(typeof e==`object`){if(e===null)return null;let t={};return Object.keys(e).forEach(n=>{t[n]=rt(e[n])}),t}else return e}function it(e){let t=BigInt(0),n=e.length,r=0,i=new DataView(e.buffer,e.byteOffset,e.byteLength);for(;n>0;)n>=4?(n-=4,t+=BigInt(i.getUint32(n))<=2?(n-=2,t+=BigInt(i.getUint16(n))<0;)a-4>=0?(a-=4,i.setUint32(a,Number(n&BigInt(4294967295))),n>>=BigInt(32)):a-2>=0?(a-=2,i.setUint16(a,Number(n&BigInt(65535))),n>>=BigInt(16)):(--a,i.setUint8(a,Number(n&BigInt(255))),n>>=BigInt(8));if(n)throw Error(`Number does not fit in this length`);return r}function ot(e){let t=BigInt(0),n=0,r=new DataView(e.buffer,e.byteOffset,e.byteLength);for(;n>=BigInt(32)):a+2<=t?(i.setUint16(a,Number(n&BigInt(65535)),!0),a+=2,n>>=BigInt(16)):(i.setUint8(a,Number(n&BigInt(255)),!0),a+=1,n>>=BigInt(8));if(n)throw Error(`Number does not fit in this length`);return r}function ct(e,t){if(typeof t==`bigint`||t.eq!==void 0)return t.toString(10);if(t instanceof Uint8Array)return e.toString(e.e(t));if(Array.isArray(t))return t.map(ct.bind(this,e));if(typeof t==`object`){let n={};return Object.keys(t).forEach(r=>{n[r]=ct(e,t[r])}),n}else return t}function lt(e,t){if(typeof t==`string`&&/^[0-9]+$/.test(t)||typeof t==`string`&&/^0x[0-9a-fA-F]+$/.test(t))return e.e(t);if(Array.isArray(t))return t.map(lt.bind(this,e));if(typeof t==`object`){if(t===null)return null;let n={};return Object.keys(t).forEach(r=>{n[r]=lt(e,t[r])}),n}else return t}var ut=[];for(let e=0;e<256;e++)ut[e]=dt(e,8);function dt(e,t){let n=0,r=e;for(let e=0;e>=1;return n}function ft(e,t){return(ut[e>>>24]|ut[e>>>16&255]<<8|ut[e>>>8&255]<<16|ut[e&255]<<24)>>>32-t}function pt(e){return(e&4294901760?(e&=4294901760,16):0)|(e&4278255360?(e&=4278255360,8):0)|(e&4042322160?(e&=4042322160,4):0)|(e&3435973836?(e&=3435973836,2):0)|(e&2863311530)!=0}function mt(e,t){let n=e.byteLength/t,r=pt(n);if(n!=1<n){let r=e.slice(i*t,(i+1)*t);e.set(e.slice(n*t,(n+1)*t),i*t),e.set(r,n*t)}}}function ht(e,t){let n=new Uint8Array(t*e.length);for(let r=0;r0;){let t=s+c>_t?_t-s:c,n=new Uint8Array(this.buffers[o].buffer,this.buffers[o].byteOffset+s,t);if(t==r)return n.slice();a||=r<=_t?new Uint8Array(r):new e(r),a.set(n,r-c),c-=t,o++,s=0}return a}set(t,n){n===void 0&&(n=0);let r=t.byteLength;if(r==0)return;let i=Math.floor(n/_t);if(i==Math.floor((n+r-1)/_t))return t instanceof e&&t.buffers.length==1?this.buffers[i].set(t.buffers[0],n%_t):this.buffers[i].set(t,n%_t);let a=i,o=n%_t,s=r;for(;s>0;){let e=o+s>_t?_t-o:s,n=t.slice(r-s,r-s+e);new Uint8Array(this.buffers[a].buffer,this.buffers[a].byteOffset+o,e).set(n),s-=e,a++,o=0}}};function vt(e,t,n,r){return async function(i){let a=Math.floor(i.byteLength/n);if(a*n!==i.byteLength)throw Error(`Invalid buffer size`);let o=Math.floor(a/e.concurrency),s=[];for(let c=0;c=0;e--)this.w[e]=this.square(this.w[e+1]);if(!this.eq(this.w[0],this.one))throw Error(`Error calculating roots of unity`);this.batchToMontgomery=vt(e,t+`_batchToMontgomery`,this.n8,this.n8),this.batchFromMontgomery=vt(e,t+`_batchFromMontgomery`,this.n8,this.n8)}op2(e,t,n){return this.tm.setBuff(this.pOp1,t),this.tm.setBuff(this.pOp2,n),this.tm.instance.exports[this.prefix+e](this.pOp1,this.pOp2,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}op2Bool(e,t,n){return this.tm.setBuff(this.pOp1,t),this.tm.setBuff(this.pOp2,n),!!this.tm.instance.exports[this.prefix+e](this.pOp1,this.pOp2)}op1(e,t){return this.tm.setBuff(this.pOp1,t),this.tm.instance.exports[this.prefix+e](this.pOp1,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}op1Bool(e,t){return this.tm.setBuff(this.pOp1,t),!!this.tm.instance.exports[this.prefix+e](this.pOp1,this.pOp3)}add(e,t){return this.op2(`_add`,e,t)}eq(e,t){return this.op2Bool(`_eq`,e,t)}isZero(e){return this.op1Bool(`_isZero`,e)}sub(e,t){return this.op2(`_sub`,e,t)}neg(e){return this.op1(`_neg`,e)}inv(e){return this.op1(`_inverse`,e)}toMontgomery(e){return this.op1(`_toMontgomery`,e)}fromMontgomery(e){return this.op1(`_fromMontgomery`,e)}mul(e,t){return this.op2(`_mul`,e,t)}div(e,t){return this.tm.setBuff(this.pOp1,e),this.tm.setBuff(this.pOp2,t),this.tm.instance.exports[this.prefix+`_inverse`](this.pOp2,this.pOp2),this.tm.instance.exports[this.prefix+`_mul`](this.pOp1,this.pOp2,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}square(e){return this.op1(`_square`,e)}isSquare(e){return this.op1Bool(`_isSquare`,e)}sqrt(e){return this.op1(`_sqrt`,e)}exp(e,t){return t instanceof Uint8Array||(t=ke(w(t))),this.tm.setBuff(this.pOp1,e),this.tm.setBuff(this.pOp2,t),this.tm.instance.exports[this.prefix+`_exp`](this.pOp1,this.pOp2,t.byteLength,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}isNegative(e){return this.op1Bool(`_isNegative`,e)}e(e,t){if(e instanceof Uint8Array)return e;let n=w(e,t);D(n)?(n=ie(n),he(n,this.p)&&(n=de(n,this.p)),n=re(this.p,n)):he(n,this.p)&&(n=de(n,this.p));let r=st(n,this.n8);return this.toMontgomery(r)}toString(e,t){return Oe(Ee(this.fromMontgomery(e),0),t)}fromRng(e){let t,n=new Uint8Array(this.n8);do{t=Ae;for(let n=0;n(await WebAssembly.instantiate(t,{env:{memory:r},curve:{f_mul:a[e+`_mul`],f_square:a[e+`_square`],f_add:a[e+`_add`],f_sub:a[e+`_sub`],f_neg:a[e+`_neg`],f_inverse:a[e+`_inverse`],f_isZero:a[e+`_isZero`],f_conj:a[i],g_add:a[n+`_add`],g_addMixed:a[n+`_addMixed`],g_double:a[n+`_double`],g_zero:a[n+`_zero`],g_isZero:a[n+`_isZero`]}})).exports,s=e.n8f;if(i={},a.f1m_mul&&a.g1m_addMixed){let t=await o(`f1m`,`g1m`,`f1m_copy`),n=e.glv&&t.multiexpAffineGLV?t.multiexpAffineGLV:t.multiexpAffine;i.g1m_multiexpAffineBatch=(e,t,r,i,a)=>n(e,t,r,i,a,s),i.g1m_multiexpAffineBatchNoGlv=(e,n,r,i,a)=>t.multiexpAffine(e,n,r,i,a,s)}if(a.f2m_mul&&a.g2m_addMixed){let t=await o(`f2m`,`g2m`,`f2m_conjugate`),n=e.glv&&t.multiexpAffineGLS?t.multiexpAffineGLS:t.multiexpAffine;i.g2m_multiexpAffineBatch=(e,t,r,i,a)=>n(e,t,r,i,a,s*2),i.g2m_multiexpAffineBatchNoGls=(e,n,r,i,a)=>t.multiexpAffine(e,n,r,i,a,s*2)}}e.terminationTimeout&&(a=e.terminationTimeout)}function c(e){return e=(e&1431655765)<<1|e>>>1&1431655765,e=(e&858993459)<<2|e>>>2&858993459,e=(e&252645135)<<4|e>>>4&252645135,e=(e&16711935)<<8|e>>>8&16711935,e=e<<16|e>>>16,e>>>0}function l(e,t,n){let r=e.byteLength/t,i=32-n;if(!(t&3)&&!(e.byteOffset&3)){let n=t>>>2,a=new Uint32Array(e.buffer,e.byteOffset,e.byteLength>>>2);for(let e=0;e>>i;if(e>>i;if(ar.buffer.byteLength){let i=r.buffer.byteLength/65536,a=Math.floor((n[0]+e)/65536)+1;a>t&&(a=t),r.grow(a-i)}return i}function d(e){let t=u(e.byteLength);return p(t,e),t}function f(e,t){return new Uint8Array(r.buffer,e,t)}function p(e,t){new Uint8Array(r.buffer).set(new Uint8Array(t),e)}function m(e){if(clearTimeout(o),e[0].cmd===`INIT`)return s(e[0]);let t={vars:[],out:[]},a=new Uint32Array(r.buffer,0,1)[0];for(let r=0;r0&&(o=setTimeout(()=>{e&&e.postMessage({status:`want_to_terminate`})},a))}function g(){clearTimeout(o),e&&(e.postMessage({status:`terminated`}),e.close())}return m}var wt=25,Tt=typeof process<`u`&&process.versions!=null&&process.versions.node!=null,Et=class{constructor(){this.promise=new Promise((e,t)=>{this.reject=t,this.resolve=e})}},Dt=class{constructor(e){this.worker=e,this.initialized=!1,this.initializing=!1,this.working=!1,this.pendingDeferred=null,this.onMsg=null,this.onError=null}},Ot;function kt(){if(Ot!==void 0)return Ot;let e=`(function thread(self) { + const MAXMEM = 32767; + let instance; + let memory; + let batchFns = null; + let terminationTimeout = 1500; + let terminationTimer; + if (self) self.onmessage = function(e) { + let data; + if (e.data) data = e.data; + else data = e; + try { + if (data[0].cmd === "INIT") { + init(data[0]).then(function() { + self.postMessage({ status: "initialized" }); + scheduleTermination(); + }); + return; + } else if (data[0].cmd === "TERMINATE") terminate(); + else { + let terminateAfterTask = false; + if (data[data.length - 1].cmd === "TERMINATE") { + terminateAfterTask = true; + data.pop(); + } + const res = runTask(data); + let transfers = []; + for (let i = 0; i < res.length; i++) if (res[i] instanceof Uint8Array) transfers.push(res[i].buffer); + self.postMessage(res, transfers); + if (terminateAfterTask) terminate(); + } + } catch (err) { + self.postMessage({ error: err.message }); + } + scheduleTermination(); + }; + async function init(data) { + let wasmModule; + if (data.code instanceof WebAssembly.Module) wasmModule = data.code; + else { + const code = new Uint8Array(data.code); + wasmModule = await WebAssembly.compile(code); + } + memory = new WebAssembly.Memory({ + initial: data.init, + maximum: MAXMEM + }); + instance = await WebAssembly.instantiate(wasmModule, { env: { "memory": memory } }); + if (data.batchCode) { + let batchModule; + if (data.batchCode instanceof WebAssembly.Module) batchModule = data.batchCode; + else batchModule = await WebAssembly.compile(new Uint8Array(data.batchCode)); + const ex = instance.exports; + const mkBatch = async (f, g, conj) => (await WebAssembly.instantiate(batchModule, { + env: { "memory": memory }, + curve: { + f_mul: ex[f + "_mul"], + f_square: ex[f + "_square"], + f_add: ex[f + "_add"], + f_sub: ex[f + "_sub"], + f_neg: ex[f + "_neg"], + f_inverse: ex[f + "_inverse"], + f_isZero: ex[f + "_isZero"], + f_conj: ex[conj], + g_add: ex[g + "_add"], + g_addMixed: ex[g + "_addMixed"], + g_double: ex[g + "_double"], + g_zero: ex[g + "_zero"], + g_isZero: ex[g + "_isZero"] + } + })).exports; + const n8f = data.n8f; + batchFns = {}; + if (ex.f1m_mul && ex.g1m_addMixed) { + const b = await mkBatch("f1m", "g1m", "f1m_copy"); + const fn = data.glv && b.multiexpAffineGLV ? b.multiexpAffineGLV : b.multiexpAffine; + batchFns["g1m_multiexpAffineBatch"] = (pB, pS, sS, n, pr) => fn(pB, pS, sS, n, pr, n8f); + batchFns["g1m_multiexpAffineBatchNoGlv"] = (pB, pS, sS, n, pr) => b.multiexpAffine(pB, pS, sS, n, pr, n8f); + } + if (ex.f2m_mul && ex.g2m_addMixed) { + const b = await mkBatch("f2m", "g2m", "f2m_conjugate"); + const fn2 = data.glv && b.multiexpAffineGLS ? b.multiexpAffineGLS : b.multiexpAffine; + batchFns["g2m_multiexpAffineBatch"] = (pB, pS, sS, n, pr) => fn2(pB, pS, sS, n, pr, n8f * 2); + batchFns["g2m_multiexpAffineBatchNoGls"] = (pB, pS, sS, n, pr) => b.multiexpAffine(pB, pS, sS, n, pr, n8f * 2); + } + } + if (data.terminationTimeout) terminationTimeout = data.terminationTimeout; + } + function rev32(x) { + x = (x & 1431655765) << 1 | x >>> 1 & 1431655765; + x = (x & 858993459) << 2 | x >>> 2 & 858993459; + x = (x & 252645135) << 4 | x >>> 4 & 252645135; + x = (x & 16711935) << 8 | x >>> 8 & 16711935; + x = x << 16 | x >>> 16; + return x >>> 0; + } + function reverseInPlace(u8, sIn, bits) { + const n = u8.byteLength / sIn; + const shift = 32 - bits; + if ((sIn & 3) === 0 && (u8.byteOffset & 3) === 0) { + const lanes = sIn >>> 2; + const u32 = new Uint32Array(u8.buffer, u8.byteOffset, u8.byteLength >>> 2); + for (let i = 0; i < n; i++) { + const ri = rev32(i) >>> shift; + if (i < ri) { + let a = i * lanes; + let b = ri * lanes; + for (let l = 0; l < lanes; l++) { + const t = u32[a + l]; + u32[a + l] = u32[b + l]; + u32[b + l] = t; + } + } + } + } else { + const tmp = new Uint8Array(sIn); + for (let i = 0; i < n; i++) { + const ri = rev32(i) >>> shift; + if (i < ri) { + const ao = i * sIn; + const bo = ri * sIn; + tmp.set(u8.subarray(ao, ao + sIn)); + u8.copyWithin(ao, bo, bo + sIn); + u8.set(tmp, bo); + } + } + } + } + function alloc(length) { + const u32 = new Uint32Array(memory.buffer, 0, 1); + while (u32[0] & 3) u32[0]++; + const res = u32[0]; + u32[0] += length; + if (u32[0] + length > memory.buffer.byteLength) { + const currentPages = memory.buffer.byteLength / 65536; + let requiredPages = Math.floor((u32[0] + length) / 65536) + 1; + if (requiredPages > MAXMEM) requiredPages = MAXMEM; + memory.grow(requiredPages - currentPages); + } + return res; + } + function allocBuffer(buffer) { + const p = alloc(buffer.byteLength); + setBuffer(p, buffer); + return p; + } + function getBuffer(pointer, length) { + return new Uint8Array(memory.buffer, pointer, length); + } + function setBuffer(pointer, buffer) { + new Uint8Array(memory.buffer).set(new Uint8Array(buffer), pointer); + } + function runTask(task) { + clearTimeout(terminationTimer); + if (task[0].cmd === "INIT") return init(task[0]); + const ctx = { + vars: [], + out: [] + }; + const oldAlloc = new Uint32Array(memory.buffer, 0, 1)[0]; + for (let i = 0; i < task.length; i++) switch (task[i].cmd) { + case "REVERSE": { + const t = task[i]; + reverseInPlace(t.src, t.sIn, t.bits); + ctx.out[0] = t.src; + break; + } + case "ALLOCSET": + ctx.vars[task[i].var] = allocBuffer(task[i].buff); + break; + case "ALLOC": + ctx.vars[task[i].var] = alloc(task[i].len); + break; + case "SET": + setBuffer(ctx.vars[task[i].var], task[i].buff); + break; + case "CALL": { + const params = []; + for (let j = 0; j < task[i].params.length; j++) { + const p = task[i].params[j]; + if (typeof p.var !== "undefined") params.push(ctx.vars[p.var] + (p.offset || 0)); + else if (typeof p.val != "undefined") params.push(p.val); + } + { + const fname = task[i].fnName; + let fn = batchFns ? batchFns[fname] : void 0; + if (!fn) { + fn = instance.exports[fname]; + if (!fn) { + const base = fname.replace(/Batch(NoGls|NoGlv)?$/, ""); + fn = instance.exports[base]; + } + } + fn(...params); + } + break; + } + case "GET": + ctx.out[task[i].out] = getBuffer(ctx.vars[task[i].var], task[i].len).slice(); + break; + default: throw new Error("Invalid cmd"); + } + const u32b = new Uint32Array(memory.buffer, 0, 1); + u32b[0] = oldAlloc; + return ctx.out; + } + function scheduleTermination() { + clearTimeout(terminationTimer); + if (terminationTimeout > 0) terminationTimer = setTimeout(() => { + if (self) self.postMessage({ status: "want_to_terminate" }); + }, terminationTimeout); + } + function terminate() { + clearTimeout(terminationTimer); + if (self) { + self.postMessage({ status: "terminated" }); + self.close(); + } + } + return runTask; +})(self)`;if(Tt)Ot=`data:application/javascript;base64,`+Buffer.from(e).toString(`base64`);else if(globalThis?.Blob&&globalThis.URL&&globalThis.URL.createObjectURL){let t=new TextEncoder().encode(e),n=new Blob([t],{type:`application/javascript`});Ot=URL.createObjectURL(n)}else Ot=`data:application/javascript;base64,`+globalThis.btoa(e);return Ot}async function At(e,t){let n=new jt;n.memory=new WebAssembly.Memory({initial:wt}),n.u8=new Uint8Array(n.memory.buffer),n.u32=new Uint32Array(n.memory.buffer);let r=await WebAssembly.compile(e.code);if(n.instance=await WebAssembly.instantiate(r,{env:{memory:n.memory}}),!Tt&&!globalThis?.Worker&&(t=!0),n.singleThread=t,n.initalPFree=n.u32[0],n.pq=e.pq,n.pr=e.pr,n.pG1gen=e.pG1gen,n.pG1zero=e.pG1zero,n.pG2gen=e.pG2gen,n.pG2zero=e.pG2zero,n.pOneT=e.pOneT,n.code=e.code,n.wasmModule=r,n.batchCode=e.batchCode,n.batchWasmModule=e.batchCode?await WebAssembly.compile(e.batchCode):void 0,n.n8f=e.n8q,n.glv=!!e.glv,t)n.taskManager=Ct(),await n.taskManager([{cmd:`INIT`,init:wt,code:n.code.slice(),batchCode:n.batchCode?n.batchCode.slice():void 0,n8f:n.n8f,glv:n.glv}]),n.concurrency=1;else{n.pool=[];let e=2;typeof navigator==`object`&&navigator.hardwareConcurrency?e=navigator.hardwareConcurrency:Ke.default&&Ke.default.cpus&&(e=Ke.default.cpus().length),e===0&&(e=2),e>64&&(e=64),n.concurrency=e}return n}var jt=class{constructor(){this.actionQueue=[],this.oldPFree=0}_makeOnMsg(e,t){let n=this;return async function(r){let i=r&&r.data?r.data:r;if(n.pool[e]!==t){if(i.status===`terminated`){t.worker.removeEventListener(`message`,t.onMsg),t.worker.removeEventListener(`error`,t.onError);return}!i.status&&t.working&&(t.working=!1,t.pendingDeferred.resolve(i)),await n.processWorks();return}if(i.error)throw t.working=!1,t.pendingDeferred.reject(Error(`Worker error: `+i.error)),t.initializing&&(t.initializing=!1,n.pool[e]=null),Error(`Worker error: `+i.error);if(i.status){if(i.status===`initialized`)t.initializing=!1,t.initialized=!0;else if(i.status===`want_to_terminate`){n.pool[e]=null,t.worker.postMessage([{cmd:`TERMINATE`}]),await n.processWorks();return}else if(i.status===`terminated`){t.worker.removeEventListener(`message`,t.onMsg),t.worker.removeEventListener(`error`,t.onError),n.pool[e]=null,t.working&&=(t.pendingDeferred.reject(Error(`Worker at slot ${e} terminated unexpectedly while processing task`)),!1);return}}t.working=!1,t.pendingDeferred.resolve(i),await n.processWorks()}}_makeOnError(e,t){let n=this;return function(r){throw n.pool[e]===t&&(t.working=!1,t.initialized=!1,t.pendingDeferred&&t.pendingDeferred.reject(Error(`Worker error: `+r.message))),Error(`Worker error: `+r.message)}}startWorker(e){let t=new Worker(kt()),n=new Dt(t);this.pool[e]=n,n.onMsg=this._makeOnMsg(e,n),n.onError=this._makeOnError(e,n),t.addEventListener(`message`,n.onMsg),t.addEventListener(`error`,n.onError),n.initializing=!0,this.postAction(e,[{cmd:`INIT`,init:wt,code:this.wasmModule,batchCode:this.batchWasmModule,n8f:this.n8f,glv:this.glv}]).then(()=>{n.initialized=!0})}startSyncOp(){if(this.oldPFree!==0)throw Error(`Sync operation in progress`);this.oldPFree=this.u32[0]}endSyncOp(){if(this.oldPFree===0)throw Error(`No sync operation in progress`);this.u32[0]=this.oldPFree,this.oldPFree=0}async postAction(e,t,n,r){let i=this.pool[e];if(!i||i.working)throw Error(`Posting a job to a working worker`);return i.working=!0,i.pendingDeferred=r||new Et,await i.worker.postMessage(t,n),i.pendingDeferred.promise}async processWorks(){for(let e=0;e0;e++){let t=this.pool[e];if(t&&t.initialized&&!t.working){let t=this.actionQueue.shift();await this.postAction(e,t.data,t.transfers,t.deferred)}}if(this.actionQueue.length>0){let e=0;for(let t=0;t=this.actionQueue.length)break;e++,this.startWorker(t)}}}async queueAction(e,t){let n=new Et;if(this.singleThread){let t=this.taskManager(e);n.resolve(t)}else this.actionQueue.push({data:e,transfers:t,deferred:n}),await this.processWorks();return n.promise}resetMemory(){this.u32[0]=this.initalPFree}allocBuff(e){let t=this.alloc(e.byteLength);return this.setBuff(t,e),t}getBuff(e,t){return this.u8.slice(e,e+t)}setBuff(e,t){this.u8.set(new Uint8Array(t),e)}alloc(e){for(;this.u32[0]&3;)this.u32[0]++;let t=this.u32[0];return this.u32[0]+=e,t}async terminate(){for(let e=0;ei&&(c=i),c=s;)await Promise.race(h);f&&f.debug(`Multiexp start: ${p}: ${_}/${r}`);let v=(async()=>{let n=await d(await e(_*i,u*i),t.slice(_*a,(_+u)*a),o,c,l,p);return f&&f.debug(`Multiexp end: ${p}: ${_}/${r}`),n})().finally(()=>h.delete(v));h.add(v),g.push(v)}let _=await Promise.all(g),v=n.zero;for(let e=_.length-1;e>=0;e--)v=n.add(v,_[e]);return v}function p(e,t,n){let r=o(n),i=Math.floor(e/r),a=0;if(i>0&&(a=Math.floor(t.byteLength/i),a*i!==t.byteLength))throw Error(`Scalar size does not match`);return{sGIn:r,nPoints:i,sScalar:a}}async function m(e,t,n,r,i,a,o){let{sGIn:s,nPoints:c,sScalar:l}=p(e.byteLength,t,n);return f((t,n)=>e.slice(t,t+n),t,c,s,l,n,1/0,r,i,a,o)}n.multiExp=async function(e,t,n,r){return m(e,t,`jacobian`,`disabled`,`auto`,n,r)},n.multiExpAffine=async function(e,t,n,r,i){return m(e,t,`affine`,s(i),c(i),n,r)},n.multiExpAffineChunked=async function(e,t,n,i,a,o){if(typeof e!=`function`)throw Error(`${a||`multiExpAffineChunked`}: basesReader must be a function (byteOffset, byteLength) => Promise`);let{sGIn:l,nPoints:u,sScalar:d}=p(t,n,`affine`);return f(e,n,u,l,d,`affine`,r.concurrency+2,s(o),c(o),i,a)}}function It(e,t){let n=e[t],r=e.Fr,i=n.tm;async function a(e,t,n){return(await i.queueAction([{cmd:`REVERSE`,src:e,sIn:t,bits:n}],[e.buffer]))[0]}async function o(e,o,l,u,d,f,p){l||=`affine`,u||=`affine`;let m,h,g,_,v,y,b,x;t==`G1`?(l==`affine`?(m=n.F.n8*2,_=`g1m_batchToJacobian`):m=n.F.n8*3,h=n.F.n8*3,o&&(x=`g1m_fftFinal`),b=`g1m_fftJoin`,y=`g1m_fftMix`,u==`affine`?(g=n.F.n8*2,v=`g1m_batchToAffine`):g=n.F.n8*3):t==`G2`?(l==`affine`?(m=n.F.n8*2,_=`g2m_batchToJacobian`):m=n.F.n8*3,h=n.F.n8*3,o&&(x=`g2m_fftFinal`),b=`g2m_fftJoin`,y=`g2m_fftMix`,u==`affine`?(g=n.F.n8*2,v=`g2m_batchToAffine`):g=n.F.n8*3):t==`Fr`&&(m=n.n8,h=n.n8,g=n.n8,o&&(x=`frm_fftFinal`),y=`frm_fftMix`,b=`frm_fftJoin`);let S=!1;Array.isArray(e)?(e=ht(e,m),S=!0):(!p||!ArrayBuffer.isView(e))&&(e=e.slice(0,e.byteLength));let C=e.byteLength/m,w=pt(C);if(1<=16;)k*=2,O/=2;let A=pt(O),j=[];d&&d.debug(`${f}: fft ${w} mix start: ${k}`);for(let t=0;t0;t--)E.set(D[t],e),e+=O*g,delete D[t];E.set(D[0].slice(0,(O-1)*g),e),delete D[0]}else for(let e=0;e1<<28?new I(d[0].byteLength*2):new Uint8Array(d[0].byteLength*2),f.set(d[0]),f.set(d[1],d[0].byteLength),f}async function c(e,t,n,i,a){let s,c;s=e.slice(0,e.byteLength/2),c=e.slice(e.byteLength/2,e.byteLength);let u=[];u.push(o(s,!0,t,`jacobian`,i,a)),u.push(o(c,!0,t,`jacobian`,i,a)),[s,c]=await Promise.all(u);let d=await l(s,c,`fftJoinExtInv`,r.one,r.shiftInv,`jacobian`,n,i,a),f;return f=d[0].byteLength>1<<28?new I(d[0].byteLength*2):new Uint8Array(d[0].byteLength*2),f.set(d[0]),f.set(d[1],d[0].byteLength),f}async function l(e,a,o,s,c,l,u,d,f){let p=65536,m,h,g,_,v,y;if(t==`G1`)l==`affine`?(v=n.F.n8*2,h=`g1m_batchToJacobian`):v=n.F.n8*3,y=n.F.n8*3,m=`g1m_`+o,u==`affine`?(g=`g1m_batchToAffine`,_=n.F.n8*2):_=n.F.n8*3;else if(t==`G2`)l==`affine`?(v=n.F.n8*2,h=`g2m_batchToJacobian`):v=n.F.n8*3,m=`g2m_`+o,y=n.F.n8*3,u==`affine`?(g=`g2m_batchToAffine`,_=n.F.n8*2):_=n.F.n8*3;else if(t==`Fr`)v=r.n8,_=r.n8,y=r.n8,m=`frm_`+o;else throw Error(`Invalid group`);if(e.byteLength!=a.byteLength)throw Error(`Invalid buffer size`);let b=Math.floor(e.byteLength/v);if(b!=1<p&&(x=p);let S=[];for(let t=0;t(d&&d.debug(`${f}: fftJoinExt End: ${t}/${b}`),e)))}let C=await Promise.all(S),w,T;b*_>1<<28?(w=new I(b*_),T=new I(b*_)):(w=new Uint8Array(b*_),T=new Uint8Array(b*_));let E=0;for(let e=0;er.s+1)throw s&&s.error(`lagrangeEvaluations input too big`),Error(`lagrangeEvaluations input too big`);let p=e.slice(0,e.byteLength/2),m=e.slice(e.byteLength/2,e.byteLength),h=r.exp(r.shift,d/2),g=r.inv(r.sub(r.one,h));[p,m]=await l(p,m,`prepareLagrangeEvaluation`,g,r.shiftInv,i,`jacobian`,s,c+` prep`);let _=[];_.push(o(p,!0,`jacobian`,a,s,c+` t0`)),_.push(o(m,!0,`jacobian`,a,s,c+` t1`)),[p,m]=await Promise.all(_);let v;return v=p.byteLength>1<<28?new I(p.byteLength*2):new Uint8Array(p.byteLength*2),v.set(p),v.set(m,p.byteLength),v},n.fftMix=async function(e){let a=n.F.n8*3,o,s;if(t==`G1`)o=`g1m_fftMix`,s=`g1m_fftJoin`;else if(t==`G2`)o=`g2m_fftMix`,s=`g2m_fftJoin`;else if(t==`Fr`)o=`frm_fftMix`,s=`frm_fftJoin`;else throw Error(`Invalid group`);let c=Math.floor(e.byteLength/a),l=pt(c),u=1<=0;e--)p.set(f[e][0],m),m+=f[e][0].byteLength;return p}}async function Lt(e){let t=await At(e.wasm,e.singleThread),n={};return n.q=w(e.wasm.q.toString()),n.r=w(e.wasm.r.toString()),n.name=e.name,n.tm=t,n.prePSize=e.wasm.prePSize,n.preQSize=e.wasm.preQSize,n.Fr=new yt(t,`frm`,e.n8r,e.r),n.F1=new yt(t,`f1m`,e.n8q,e.q),n.F2=new bt(t,`f2m`,n.F1),n.G1=new St(t,`g1m`,n.F1,e.wasm.pG1gen,e.wasm.pG1b,e.cofactorG1),n.G2=new St(t,`g2m`,n.F2,e.wasm.pG2gen,e.wasm.pG2b,e.cofactorG2),n.F6=new xt(t,`f6m`,n.F2),n.F12=new bt(t,`ftm`,n.F6),n.Gt=n.F12,Mt(n,`G1`),Mt(n,`G2`),Mt(n,`Fr`),Ft(n,`G1`),Ft(n,`G2`),It(n,`G1`),It(n,`G2`),It(n,`Fr`),Nt(n),n.array2buffer=function(e,t){let n=new Uint8Array(t*e.length);for(let r=0;r0&&e[t-1]===`=`&&n++,t>1&&e[t-2]===`=`&&n++;let r=(t*3>>2)-n,i=new Uint8Array(r),a=0;for(let n=0;n>4),a>2),a(u(),i)),{buildBn128:r}=await Promise.resolve().then(()=>(u(),i)),a=new e;a.setMemory(25),r(a),t&&t(a),n.code=a.build(),n.pq=a.modules.f1m.pq,n.pr=a.modules.frm.pq,n.pG1gen=a.modules.bn128.pG1gen,n.pG1zero=a.modules.bn128.pG1zero,n.pG1b=a.modules.bn128.pG1b,n.pG2gen=a.modules.bn128.pG2gen,n.pG2zero=a.modules.bn128.pG2zero,n.pG2b=a.modules.bn128.pG2b,n.pOneT=a.modules.bn128.pOneT,n.prePSize=a.modules.bn128.prePSize,n.preQSize=a.modules.bn128.preQSize,n.n8q=32,n.n8r=32,n.q=a.modules.bn128.q,n.r=a.modules.bn128.r}n.batchCode=$t(Yt),n.glv=!0;let r={name:`bn128`,wasm:n,q:w(`21888242871839275222246405745257275088696311157297823662689037894645226208583`),r:w(`21888242871839275222246405745257275088548364400416034343698204186575808495617`),n8q:32,n8r:32,cofactorG2:w(`30644e72e131a029b85045b68181585e06ceecda572a2489345f2299c0f9fa8d`,16),singleThread:!!e},a=await Lt(r);return a.terminate=async function(){r.singleThread||(en=null,await this.tm.terminate())},e||(en=a),a}var nn=`AGFzbQEAAAABjwERYAJ/fwBgA39/fwBgAX8Bf2AEf39/fwBgBX9/f39/AGABfwBgAn9/AX9gBn9/f39/fwBgA39/fwF/YAh/f39/f39/fwBgAn9+AGAEf39/fwF/YAp/f39/f39/f39/AGAFf39/f38Bf2AHf39/f39/fwF/YAl/f39/f39/f38Bf2ALf39/f39/f39/f38BfwIPAQNlbnYGbWVtb3J5AgAZA68CrQIABQIFBgYICAEAAAoDAQIBAQAAAQAAAAACAgAFAQMEAQEDAAIABQIFBgYICAEAAAMBAgEBAAABAAAAAAICAAUBAwQBAQMAAgEAAAICAgUFAAAABgYGAAABAQEAAAEBAQAAAAAAAgIBAAEAAAAAAQEBAQELBwkECQQDAwADAgAABAcHAQEHAAMMBAMCBQABAQABAQAAAwICBAMAAgICBQUAAAAGBgYAAAEBAQAAAQEBAAAAAAACAgEAAAAAAAEBAQEBCQQJBAMDAQADAAAEBwcBAQcBAAMAAAQHBwEBBwEBBAQEBAQAAgIFBQABAAEBAAIGAAMCBAMAAgIFBQABAQABAQAAAAAGAAMCAgQDAAIBAwQBAAAAAAAAAAAAAAICAgIAAAEAAAAACA0ODxABB74nvQIJaW50cV9jb3B5AAAJaW50cV96ZXJvAAEIaW50cV9vbmUAAwtpbnRxX2lzWmVybwACB2ludHFfZXEABAhpbnRxX2d0ZQAFCGludHFfYWRkAAYIaW50cV9zdWIABwhpbnRxX211bAAIC2ludHFfc3F1YXJlAAkOaW50cV9zcXVhcmVPbGQACghpbnRxX2RpdgAMD2ludHFfaW52ZXJzZU1vZAANCGYxbV9jb3B5AAAIZjFtX3plcm8AAQpmMW1faXNaZXJvAAIGZjFtX2VxAAQHZjFtX2FkZAAPB2YxbV9zdWIAEAdmMW1fbmVnABEOZjFtX2lzTmVnYXRpdmUAGAlmMW1faXNPbmUADghmMW1fc2lnbgAZC2YxbV9tUmVkdWN0ABIHZjFtX211bAATCmYxbV9zcXVhcmUAFA1mMW1fc3F1YXJlT2xkABUSZjFtX2Zyb21Nb250Z29tZXJ5ABcQZjFtX3RvTW9udGdvbWVyeQAWC2YxbV9pbnZlcnNlABoHZjFtX29uZQAbCGYxbV9sb2FkABwPZjFtX3RpbWVzU2NhbGFyAB0HZjFtX2V4cAAhEGYxbV9iYXRjaEludmVyc2UAHghmMW1fc3FydAAiDGYxbV9pc1NxdWFyZQAjFWYxbV9iYXRjaFRvTW9udGdvbWVyeQAfF2YxbV9iYXRjaEZyb21Nb250Z29tZXJ5ACAJaW50cl9jb3B5ACQJaW50cl96ZXJvACUIaW50cl9vbmUAJwtpbnRyX2lzWmVybwAmB2ludHJfZXEAKAhpbnRyX2d0ZQApCGludHJfYWRkACoIaW50cl9zdWIAKwhpbnRyX211bAAsC2ludHJfc3F1YXJlAC0OaW50cl9zcXVhcmVPbGQALghpbnRyX2RpdgAvD2ludHJfaW52ZXJzZU1vZAAwCGZybV9jb3B5ACQIZnJtX3plcm8AJQpmcm1faXNaZXJvACYGZnJtX2VxACgHZnJtX2FkZAAyB2ZybV9zdWIAMwdmcm1fbmVnADQOZnJtX2lzTmVnYXRpdmUAOwlmcm1faXNPbmUAMQhmcm1fc2lnbgA8C2ZybV9tUmVkdWN0ADUHZnJtX211bAA2CmZybV9zcXVhcmUANw1mcm1fc3F1YXJlT2xkADgSZnJtX2Zyb21Nb250Z29tZXJ5ADoQZnJtX3RvTW9udGdvbWVyeQA5C2ZybV9pbnZlcnNlAD0HZnJtX29uZQA+CGZybV9sb2FkAD8PZnJtX3RpbWVzU2NhbGFyAEAHZnJtX2V4cABEEGZybV9iYXRjaEludmVyc2UAQQhmcm1fc3FydABFDGZybV9pc1NxdWFyZQBGFWZybV9iYXRjaFRvTW9udGdvbWVyeQBCF2ZybV9iYXRjaEZyb21Nb250Z29tZXJ5AEMGZnJfYWRkADIGZnJfc3ViADMGZnJfbmVnADQGZnJfbXVsAEcJZnJfc3F1YXJlAEgKZnJfaW52ZXJzZQBJDWZyX2lzTmVnYXRpdmUASgdmcl9jb3B5ACQHZnJfemVybwAlBmZyX29uZQA+CWZyX2lzWmVybwAmBWZyX2VxACgMZzFtX211bHRpZXhwAHUSZzFtX211bHRpZXhwX2NodW5rAHQSZzFtX211bHRpZXhwQWZmaW5lAHcYZzFtX211bHRpZXhwQWZmaW5lX2NodW5rAHYKZzFtX2lzWmVybwBMEGcxbV9pc1plcm9BZmZpbmUASwZnMW1fZXEAVAtnMW1fZXFNaXhlZABTDGcxbV9lcUFmZmluZQBSCGcxbV9jb3B5AFAOZzFtX2NvcHlBZmZpbmUATwhnMW1femVybwBODmcxbV96ZXJvQWZmaW5lAE0KZzFtX2RvdWJsZQBWEGcxbV9kb3VibGVBZmZpbmUAVQdnMW1fYWRkAFkMZzFtX2FkZE1peGVkAFgNZzFtX2FkZEFmZmluZQBXB2cxbV9uZWcAWw1nMW1fbmVnQWZmaW5lAFoHZzFtX3N1YgBeDGcxbV9zdWJNaXhlZABdDWcxbV9zdWJBZmZpbmUAXBJnMW1fZnJvbU1vbnRnb21lcnkAYBhnMW1fZnJvbU1vbnRnb21lcnlBZmZpbmUAXxBnMW1fdG9Nb250Z29tZXJ5AGIWZzFtX3RvTW9udGdvbWVyeUFmZmluZQBhD2cxbV90aW1lc1NjYWxhcgB4FWcxbV90aW1lc1NjYWxhckFmZmluZQB5DWcxbV9ub3JtYWxpemUAZwpnMW1fTEVNdG9VAGkKZzFtX0xFTXRvQwBqCmcxbV9VdG9MRU0AawpnMW1fQ3RvTEVNAGwPZzFtX2JhdGNoTEVNdG9VAG0PZzFtX2JhdGNoTEVNdG9DAG4PZzFtX2JhdGNoVXRvTEVNAG8PZzFtX2JhdGNoQ3RvTEVNAHAMZzFtX3RvQWZmaW5lAGMOZzFtX3RvSmFjb2JpYW4AURFnMW1fYmF0Y2hUb0FmZmluZQBmE2cxbV9iYXRjaFRvSmFjb2JpYW4AcQtnMW1faW5DdXJ2ZQBlEWcxbV9pbkN1cnZlQWZmaW5lAGQXZnJtX19yZXZlcnNlUGVybXV0YXRpb24Aegdmcm1fZmZ0AH0IZnJtX2lmZnQAfgpmcm1fcmF3ZmZ0AHsLZnJtX2ZmdEpvaW4Afw5mcm1fZmZ0Sm9pbkV4dACAARFmcm1fZmZ0Sm9pbkV4dEludgCBAQpmcm1fZmZ0TWl4AIIBDGZybV9mZnRGaW5hbACDAR1mcm1fcHJlcGFyZUxhZ3JhbmdlRXZhbHVhdGlvbgCEAQhwb2xfemVybwCFAQ9wb2xfY29uc3RydWN0TEMAhgEMcWFwX2J1aWxkQUJDAIcBC3FhcF9qb2luQUJDAIgBDHFhcF9iYXRjaEFkZACJAQpmMm1faXNaZXJvAEsJZjJtX2lzT25lAIoBCGYybV96ZXJvAE0HZjJtX29uZQCLAQhmMm1fY29weQCMAQdmMm1fbXVsAI0BCGYybV9tdWwxAI4BCmYybV9zcXVhcmUAjwEHZjJtX2FkZACQAQdmMm1fc3ViAJEBB2YybV9uZWcAkgEIZjJtX3NpZ24AlQENZjJtX2Nvbmp1Z2F0ZQBaEmYybV9mcm9tTW9udGdvbWVyeQBfEGYybV90b01vbnRnb21lcnkAYQZmMm1fZXEAUgtmMm1faW52ZXJzZQCTAQdmMm1fZXhwAJgBD2YybV90aW1lc1NjYWxhcgCUARBmMm1fYmF0Y2hJbnZlcnNlAJcBCGYybV9zcXJ0AJkBDGYybV9pc1NxdWFyZQCaAQ5mMm1faXNOZWdhdGl2ZQCWAQxnMm1fbXVsdGlleHAAwgESZzJtX211bHRpZXhwX2NodW5rAMEBEmcybV9tdWx0aWV4cEFmZmluZQDEARhnMm1fbXVsdGlleHBBZmZpbmVfY2h1bmsAwwEKZzJtX2lzWmVybwCcARBnMm1faXNaZXJvQWZmaW5lAJsBBmcybV9lcQCkAQtnMm1fZXFNaXhlZACjAQxnMm1fZXFBZmZpbmUAogEIZzJtX2NvcHkAoAEOZzJtX2NvcHlBZmZpbmUAnwEIZzJtX3plcm8AngEOZzJtX3plcm9BZmZpbmUAnQEKZzJtX2RvdWJsZQCmARBnMm1fZG91YmxlQWZmaW5lAKUBB2cybV9hZGQAqQEMZzJtX2FkZE1peGVkAKgBDWcybV9hZGRBZmZpbmUApwEHZzJtX25lZwCrAQ1nMm1fbmVnQWZmaW5lAKoBB2cybV9zdWIArgEMZzJtX3N1Yk1peGVkAK0BDWcybV9zdWJBZmZpbmUArAESZzJtX2Zyb21Nb250Z29tZXJ5ALABGGcybV9mcm9tTW9udGdvbWVyeUFmZmluZQCvARBnMm1fdG9Nb250Z29tZXJ5ALIBFmcybV90b01vbnRnb21lcnlBZmZpbmUAsQEPZzJtX3RpbWVzU2NhbGFyAMUBFWcybV90aW1lc1NjYWxhckFmZmluZQDGAQ1nMm1fbm9ybWFsaXplALcBCmcybV9MRU10b1UAuAEKZzJtX0xFTXRvQwC5AQpnMm1fVXRvTEVNALoBCmcybV9DdG9MRU0AuwEPZzJtX2JhdGNoTEVNdG9VALwBD2cybV9iYXRjaExFTXRvQwC9AQ9nMm1fYmF0Y2hVdG9MRU0AvgEPZzJtX2JhdGNoQ3RvTEVNAL8BDGcybV90b0FmZmluZQCzAQ5nMm1fdG9KYWNvYmlhbgChARFnMm1fYmF0Y2hUb0FmZmluZQC2ARNnMm1fYmF0Y2hUb0phY29iaWFuAMABC2cybV9pbkN1cnZlALUBEWcybV9pbkN1cnZlQWZmaW5lALQBC2cxbV90aW1lc0ZyAMcBF2cxbV9fcmV2ZXJzZVBlcm11dGF0aW9uAMgBB2cxbV9mZnQAygEIZzFtX2lmZnQAywEKZzFtX3Jhd2ZmdADJAQtnMW1fZmZ0Sm9pbgDMAQ5nMW1fZmZ0Sm9pbkV4dADNARFnMW1fZmZ0Sm9pbkV4dEludgDOAQpnMW1fZmZ0TWl4AM8BDGcxbV9mZnRGaW5hbADQAR1nMW1fcHJlcGFyZUxhZ3JhbmdlRXZhbHVhdGlvbgDRAQtnMm1fdGltZXNGcgDSARdnMm1fX3JldmVyc2VQZXJtdXRhdGlvbgDTAQdnMm1fZmZ0ANUBCGcybV9pZmZ0ANYBCmcybV9yYXdmZnQA1AELZzJtX2ZmdEpvaW4A1wEOZzJtX2ZmdEpvaW5FeHQA2AERZzJtX2ZmdEpvaW5FeHRJbnYA2QEKZzJtX2ZmdE1peADaAQxnMm1fZmZ0RmluYWwA2wEdZzJtX3ByZXBhcmVMYWdyYW5nZUV2YWx1YXRpb24A3AERZzFtX3RpbWVzRnJBZmZpbmUA3QERZzJtX3RpbWVzRnJBZmZpbmUA3gERZnJtX2JhdGNoQXBwbHlLZXkA3wERZzFtX2JhdGNoQXBwbHlLZXkA4AEWZzFtX2JhdGNoQXBwbHlLZXlNaXhlZADhARFnMm1fYmF0Y2hBcHBseUtleQDiARZnMm1fYmF0Y2hBcHBseUtleU1peGVkAOMBCmY2bV9pc1plcm8A5QEJZjZtX2lzT25lAOYBCGY2bV96ZXJvAOcBB2Y2bV9vbmUA6AEIZjZtX2NvcHkA6QEHZjZtX211bADqAQpmNm1fc3F1YXJlAOsBB2Y2bV9hZGQA7AEHZjZtX3N1YgDtAQdmNm1fbmVnAO4BCGY2bV9zaWduAO8BEmY2bV9mcm9tTW9udGdvbWVyeQCwARBmNm1fdG9Nb250Z29tZXJ5ALIBBmY2bV9lcQDwAQtmNm1faW52ZXJzZQDxAQdmNm1fZXhwAPUBD2Y2bV90aW1lc1NjYWxhcgDyARBmNm1fYmF0Y2hJbnZlcnNlAPQBDmY2bV9pc05lZ2F0aXZlAPMBCmZ0bV9pc1plcm8A9wEJZnRtX2lzT25lAPgBCGZ0bV96ZXJvAPkBB2Z0bV9vbmUA+gEIZnRtX2NvcHkA+wEHZnRtX211bAD8AQhmdG1fbXVsMQD9AQpmdG1fc3F1YXJlAP4BB2Z0bV9hZGQA/wEHZnRtX3N1YgCAAgdmdG1fbmVnAIECCGZ0bV9zaWduAIgCDWZ0bV9jb25qdWdhdGUAggISZnRtX2Zyb21Nb250Z29tZXJ5AIQCEGZ0bV90b01vbnRnb21lcnkAgwIGZnRtX2VxAIUCC2Z0bV9pbnZlcnNlAIYCB2Z0bV9leHAAiwIPZnRtX3RpbWVzU2NhbGFyAIcCEGZ0bV9iYXRjaEludmVyc2UAigIIZnRtX3NxcnQAjAIMZnRtX2lzU3F1YXJlAI0CDmZ0bV9pc05lZ2F0aXZlAIkCEWZ0bV9mcm9iZW5pdXNNYXAwAJICEWZ0bV9mcm9iZW5pdXNNYXAxAJMCEWZ0bV9mcm9iZW5pdXNNYXAyAJQCEWZ0bV9mcm9iZW5pdXNNYXAzAJUCEWZ0bV9mcm9iZW5pdXNNYXA0AJYCEWZ0bV9mcm9iZW5pdXNNYXA1AJcCEWZ0bV9mcm9iZW5pdXNNYXA2AJgCEWZ0bV9mcm9iZW5pdXNNYXA3AJkCEWZ0bV9mcm9iZW5pdXNNYXA4AJoCEWZ0bV9mcm9iZW5pdXNNYXA5AJsCE2JsczEyMzgxX3BhaXJpbmdFcTEApwITYmxzMTIzODFfcGFpcmluZ0VxMgCoAhNibHMxMjM4MV9wYWlyaW5nRXEzAKkCE2JsczEyMzgxX3BhaXJpbmdFcTQAqgITYmxzMTIzODFfcGFpcmluZ0VxNQCrAhBibHMxMjM4MV9wYWlyaW5nAKwCEmJsczEyMzgxX3ByZXBhcmVHMQCgAhJibHMxMjM4MV9wcmVwYXJlRzIAoQITYmxzMTIzODFfbWlsbGVyTG9vcACiAhxibHMxMjM4MV9maW5hbEV4cG9uZW50aWF0aW9uAKYCH2JsczEyMzgxX2ZpbmFsRXhwb25lbnRpYXRpb25PbGQAowIaYmxzMTIzODFfX2N5Y2xvdG9taWNTcXVhcmUApAIaYmxzMTIzODFfX2N5Y2xvdG9taWNFeHBfdzAApQIIZjZtX211bDEAjgIJZjZtX211bDAxAI8CCmZ0bV9tdWwwMTQAkAIRZzFtX2luR3JvdXBBZmZpbmUAnAILZzFtX2luR3JvdXAAnQIRZzJtX2luR3JvdXBBZmZpbmUAngILZzJtX2luR3JvdXAAnwIK7dgErQI+ACABIAApAwA3AwAgASAAKQMINwMIIAEgACkDEDcDECABIAApAxg3AxggASAAKQMgNwMgIAEgACkDKDcDKAssACAAQgA3AwAgAEIANwMIIABCADcDECAAQgA3AxggAEIANwMgIABCADcDKAtEACAAKQMoUAR+IAApAyBQBH4gACkDGFAEfiAAKQMQUAR+IAApAwhQBH4gACkDAAVCAQsFQgELBUIBCwVCAQsFQgELUAssACAAQgE3AwAgAEIANwMIIABCADcDECAAQgA3AxggAEIANwMgIABCADcDKAtiACAAKQMoIAEpAyhRBH8gACkDICABKQMgUQR/IAApAxggASkDGFEEfyAAKQMQIAEpAxBRBH8gACkDCCABKQMIUQR/IAApAwAgASkDAFEFQQALBUEACwVBAAsFQQALBUEACwu3AQAgACkDKCABKQMoVAR/QQAFIAApAyggASkDKFYEf0EBBSAAKQMgIAEpAyBUBH9BAAUgACkDICABKQMgVgR/QQEFIAApAxggASkDGFQEf0EABSAAKQMYIAEpAxhWBH9BAQUgACkDECABKQMQVAR/QQAFIAApAxAgASkDEFYEf0EBBSAAKQMIIAEpAwhUBH9BAAUgACkDCCABKQMIVgR/QQEFIAApAwAgASkDAFoLCwsLCwsLCwsLC6QCAQF+IAIgADUCACABNQIAfCIDPgIAIAIgADUCBCABNQIEfCADQiCIfCIDPgIEIAIgADUCCCABNQIIfCADQiCIfCIDPgIIIAIgADUCDCABNQIMfCADQiCIfCIDPgIMIAIgADUCECABNQIQfCADQiCIfCIDPgIQIAIgADUCFCABNQIUfCADQiCIfCIDPgIUIAIgADUCGCABNQIYfCADQiCIfCIDPgIYIAIgADUCHCABNQIcfCADQiCIfCIDPgIcIAIgADUCICABNQIgfCADQiCIfCIDPgIgIAIgADUCJCABNQIkfCADQiCIfCIDPgIkIAIgADUCKCABNQIofCADQiCIfCIDPgIoIAIgADUCLCABNQIsfCADQiCIfCIDPgIsIANCIIinC/gCAQF+IAIgADUCACABNQIAfSIDQv////8Pgz4CACACIAA1AgQgATUCBH0gA0Igh3wiA0L/////D4M+AgQgAiAANQIIIAE1Agh9IANCIId8IgNC/////w+DPgIIIAIgADUCDCABNQIMfSADQiCHfCIDQv////8Pgz4CDCACIAA1AhAgATUCEH0gA0Igh3wiA0L/////D4M+AhAgAiAANQIUIAE1AhR9IANCIId8IgNC/////w+DPgIUIAIgADUCGCABNQIYfSADQiCHfCIDQv////8Pgz4CGCACIAA1AhwgATUCHH0gA0Igh3wiA0L/////D4M+AhwgAiAANQIgIAE1AiB9IANCIId8IgNC/////w+DPgIgIAIgADUCJCABNQIkfSADQiCHfCIDQv////8Pgz4CJCACIAA1AiggATUCKH0gA0Igh3wiA0L/////D4M+AiggAiAANQIsIAE1Aix9IANCIId8IgNC/////w+DPgIsIANCIIenC84fARl+IAQgADUCACIFIAE1AgAiBn4gA0L/////D4N8IgNCIIh8IQQgAiADPgIAIARCIIghAyADIAUgATUCBCIHfiAEQv////8Pg3wiBEIgiHwhAyADIAA1AgQiCCAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AgQgA0IgiCEEIAQgBSABNQIIIgl+IANC/////w+DfCIDQiCIfCEEIAQgByAIfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AggiCiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AgggBEIgiCEDIAMgBSABNQIMIgt+IARC/////w+DfCIEQiCIfCEDIAMgCCAJfiAEQv////8Pg3wiBEIgiHwhAyADIAcgCn4gBEL/////D4N8IgRCIIh8IQMgAyAANQIMIgwgBn4gBEL/////D4N8IgRCIIh8IQMgAiAEPgIMIANCIIghBCAEIAUgATUCECINfiADQv////8Pg3wiA0IgiHwhBCAEIAggC34gA0L/////D4N8IgNCIIh8IQQgBCAJIAp+IANC/////w+DfCIDQiCIfCEEIAQgByAMfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AhAiDiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AhAgBEIgiCEDIAMgBSABNQIUIg9+IARC/////w+DfCIEQiCIfCEDIAMgCCANfiAEQv////8Pg3wiBEIgiHwhAyADIAogC34gBEL/////D4N8IgRCIIh8IQMgAyAJIAx+IARC/////w+DfCIEQiCIfCEDIAMgByAOfiAEQv////8Pg3wiBEIgiHwhAyADIAA1AhQiECAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AhQgA0IgiCEEIAQgBSABNQIYIhF+IANC/////w+DfCIDQiCIfCEEIAQgCCAPfiADQv////8Pg3wiA0IgiHwhBCAEIAogDX4gA0L/////D4N8IgNCIIh8IQQgBCALIAx+IANC/////w+DfCIDQiCIfCEEIAQgCSAOfiADQv////8Pg3wiA0IgiHwhBCAEIAcgEH4gA0L/////D4N8IgNCIIh8IQQgBCAANQIYIhIgBn4gA0L/////D4N8IgNCIIh8IQQgAiADPgIYIARCIIghAyADIAUgATUCHCITfiAEQv////8Pg3wiBEIgiHwhAyADIAggEX4gBEL/////D4N8IgRCIIh8IQMgAyAKIA9+IARC/////w+DfCIEQiCIfCEDIAMgDCANfiAEQv////8Pg3wiBEIgiHwhAyADIAsgDn4gBEL/////D4N8IgRCIIh8IQMgAyAJIBB+IARC/////w+DfCIEQiCIfCEDIAMgByASfiAEQv////8Pg3wiBEIgiHwhAyADIAA1AhwiFCAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AhwgA0IgiCEEIAQgBSABNQIgIhV+IANC/////w+DfCIDQiCIfCEEIAQgCCATfiADQv////8Pg3wiA0IgiHwhBCAEIAogEX4gA0L/////D4N8IgNCIIh8IQQgBCAMIA9+IANC/////w+DfCIDQiCIfCEEIAQgDSAOfiADQv////8Pg3wiA0IgiHwhBCAEIAsgEH4gA0L/////D4N8IgNCIIh8IQQgBCAJIBJ+IANC/////w+DfCIDQiCIfCEEIAQgByAUfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AiAiFiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AiAgBEIgiCEDIAMgBSABNQIkIhd+IARC/////w+DfCIEQiCIfCEDIAMgCCAVfiAEQv////8Pg3wiBEIgiHwhAyADIAogE34gBEL/////D4N8IgRCIIh8IQMgAyAMIBF+IARC/////w+DfCIEQiCIfCEDIAMgDiAPfiAEQv////8Pg3wiBEIgiHwhAyADIA0gEH4gBEL/////D4N8IgRCIIh8IQMgAyALIBJ+IARC/////w+DfCIEQiCIfCEDIAMgCSAUfiAEQv////8Pg3wiBEIgiHwhAyADIAcgFn4gBEL/////D4N8IgRCIIh8IQMgAyAANQIkIhggBn4gBEL/////D4N8IgRCIIh8IQMgAiAEPgIkIANCIIghBCAEIAUgATUCKCIZfiADQv////8Pg3wiA0IgiHwhBCAEIAggF34gA0L/////D4N8IgNCIIh8IQQgBCAKIBV+IANC/////w+DfCIDQiCIfCEEIAQgDCATfiADQv////8Pg3wiA0IgiHwhBCAEIA4gEX4gA0L/////D4N8IgNCIIh8IQQgBCAPIBB+IANC/////w+DfCIDQiCIfCEEIAQgDSASfiADQv////8Pg3wiA0IgiHwhBCAEIAsgFH4gA0L/////D4N8IgNCIIh8IQQgBCAJIBZ+IANC/////w+DfCIDQiCIfCEEIAQgByAYfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AigiGiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AiggBEIgiCEDIAMgBSABNQIsIht+IARC/////w+DfCIEQiCIfCEDIAMgCCAZfiAEQv////8Pg3wiBEIgiHwhAyADIAogF34gBEL/////D4N8IgRCIIh8IQMgAyAMIBV+IARC/////w+DfCIEQiCIfCEDIAMgDiATfiAEQv////8Pg3wiBEIgiHwhAyADIBAgEX4gBEL/////D4N8IgRCIIh8IQMgAyAPIBJ+IARC/////w+DfCIEQiCIfCEDIAMgDSAUfiAEQv////8Pg3wiBEIgiHwhAyADIAsgFn4gBEL/////D4N8IgRCIIh8IQMgAyAJIBh+IARC/////w+DfCIEQiCIfCEDIAMgByAafiAEQv////8Pg3wiBEIgiHwhAyADIAA1AiwiBSAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AiwgA0IgiCEEIAQgCCAbfiADQv////8Pg3wiA0IgiHwhBCAEIAogGX4gA0L/////D4N8IgNCIIh8IQQgBCAMIBd+IANC/////w+DfCIDQiCIfCEEIAQgDiAVfiADQv////8Pg3wiA0IgiHwhBCAEIBAgE34gA0L/////D4N8IgNCIIh8IQQgBCARIBJ+IANC/////w+DfCIDQiCIfCEEIAQgDyAUfiADQv////8Pg3wiA0IgiHwhBCAEIA0gFn4gA0L/////D4N8IgNCIIh8IQQgBCALIBh+IANC/////w+DfCIDQiCIfCEEIAQgCSAafiADQv////8Pg3wiA0IgiHwhBCAEIAUgB34gA0L/////D4N8IgNCIIh8IQQgAiADPgIwIARCIIghAyADIAogG34gBEL/////D4N8IgRCIIh8IQMgAyAMIBl+IARC/////w+DfCIEQiCIfCEDIAMgDiAXfiAEQv////8Pg3wiBEIgiHwhAyADIBAgFX4gBEL/////D4N8IgRCIIh8IQMgAyASIBN+IARC/////w+DfCIEQiCIfCEDIAMgESAUfiAEQv////8Pg3wiBEIgiHwhAyADIA8gFn4gBEL/////D4N8IgRCIIh8IQMgAyANIBh+IARC/////w+DfCIEQiCIfCEDIAMgCyAafiAEQv////8Pg3wiBEIgiHwhAyADIAUgCX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgI0IANCIIghBCAEIAwgG34gA0L/////D4N8IgNCIIh8IQQgBCAOIBl+IANC/////w+DfCIDQiCIfCEEIAQgECAXfiADQv////8Pg3wiA0IgiHwhBCAEIBIgFX4gA0L/////D4N8IgNCIIh8IQQgBCATIBR+IANC/////w+DfCIDQiCIfCEEIAQgESAWfiADQv////8Pg3wiA0IgiHwhBCAEIA8gGH4gA0L/////D4N8IgNCIIh8IQQgBCANIBp+IANC/////w+DfCIDQiCIfCEEIAQgBSALfiADQv////8Pg3wiA0IgiHwhBCACIAM+AjggBEIgiCEDIAMgDiAbfiAEQv////8Pg3wiBEIgiHwhAyADIBAgGX4gBEL/////D4N8IgRCIIh8IQMgAyASIBd+IARC/////w+DfCIEQiCIfCEDIAMgFCAVfiAEQv////8Pg3wiBEIgiHwhAyADIBMgFn4gBEL/////D4N8IgRCIIh8IQMgAyARIBh+IARC/////w+DfCIEQiCIfCEDIAMgDyAafiAEQv////8Pg3wiBEIgiHwhAyADIAUgDX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgI8IANCIIghBCAEIBAgG34gA0L/////D4N8IgNCIIh8IQQgBCASIBl+IANC/////w+DfCIDQiCIfCEEIAQgFCAXfiADQv////8Pg3wiA0IgiHwhBCAEIBUgFn4gA0L/////D4N8IgNCIIh8IQQgBCATIBh+IANC/////w+DfCIDQiCIfCEEIAQgESAafiADQv////8Pg3wiA0IgiHwhBCAEIAUgD34gA0L/////D4N8IgNCIIh8IQQgAiADPgJAIARCIIghAyADIBIgG34gBEL/////D4N8IgRCIIh8IQMgAyAUIBl+IARC/////w+DfCIEQiCIfCEDIAMgFiAXfiAEQv////8Pg3wiBEIgiHwhAyADIBUgGH4gBEL/////D4N8IgRCIIh8IQMgAyATIBp+IARC/////w+DfCIEQiCIfCEDIAMgBSARfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AkQgA0IgiCEEIAQgFCAbfiADQv////8Pg3wiA0IgiHwhBCAEIBYgGX4gA0L/////D4N8IgNCIIh8IQQgBCAXIBh+IANC/////w+DfCIDQiCIfCEEIAQgFSAafiADQv////8Pg3wiA0IgiHwhBCAEIAUgE34gA0L/////D4N8IgNCIIh8IQQgAiADPgJIIARCIIghAyADIBYgG34gBEL/////D4N8IgRCIIh8IQMgAyAYIBl+IARC/////w+DfCIEQiCIfCEDIAMgFyAafiAEQv////8Pg3wiBEIgiHwhAyADIAUgFX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgJMIANCIIghBCAEIBggG34gA0L/////D4N8IgNCIIh8IQQgBCAZIBp+IANC/////w+DfCIDQiCIfCEEIAQgBSAXfiADQv////8Pg3wiA0IgiHwhBCACIAM+AlAgBEIgiCEDIAMgGiAbfiAEQv////8Pg3wiBEIgiHwhAyADIAUgGX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgJUIANCIIghBCAEIAUgG34gA0L/////D4N8IgNCIIh8IQQgAiADPgJYIAIgBD4CXAu8GQEQfiADIAA1AgAiBiAGfiACQv////8Pg3wiAkIgiHwhAyABIAI+AgAgAyIEQiCIIQUgADUCBCIHIAZ+IgJCIIhCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CBCADIgRCIIghBSAANQIIIgggBn4iAkIgiEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgByAHfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CCCADIgRCIIghBSAANQIMIgkgBn4iAkIgiCEDIAMgByAIfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CDCADIgRCIIghBSAANQIQIgogBn4iAkIgiCEDIAMgByAJfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAggCH4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AhAgAyIEQiCIIQUgADUCFCILIAZ+IgJCIIghAyADIAcgCn4gAkL/////D4N8IgJCIIh8IQMgAyAIIAl+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIUIAMiBEIgiCEFIAA1AhgiDCAGfiICQiCIIQMgAyAHIAt+IAJC/////w+DfCICQiCIfCEDIAMgCCAKfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAkgCX4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AhggAyIEQiCIIQUgADUCHCINIAZ+IgJCIIghAyADIAcgDH4gAkL/////D4N8IgJCIIh8IQMgAyAIIAt+IAJC/////w+DfCICQiCIfCEDIAMgCSAKfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CHCADIgRCIIghBSAANQIgIg4gBn4iAkIgiCEDIAMgByANfiACQv////8Pg3wiAkIgiHwhAyADIAggDH4gAkL/////D4N8IgJCIIh8IQMgAyAJIAt+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgCiAKfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CICADIgRCIIghBSAANQIkIg8gBn4iAkIgiCEDIAMgByAOfiACQv////8Pg3wiAkIgiHwhAyADIAggDX4gAkL/////D4N8IgJCIIh8IQMgAyAJIAx+IAJC/////w+DfCICQiCIfCEDIAMgCiALfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CJCADIgRCIIghBSAANQIoIhAgBn4iAkIgiCEDIAMgByAPfiACQv////8Pg3wiAkIgiHwhAyADIAggDn4gAkL/////D4N8IgJCIIh8IQMgAyAJIA1+IAJC/////w+DfCICQiCIfCEDIAMgCiAMfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAsgC34gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AiggAyIEQiCIIQUgADUCLCIRIAZ+IgJCIIghAyADIAcgEH4gAkL/////D4N8IgJCIIh8IQMgAyAIIA9+IAJC/////w+DfCICQiCIfCEDIAMgCSAOfiACQv////8Pg3wiAkIgiHwhAyADIAogDX4gAkL/////D4N8IgJCIIh8IQMgAyALIAx+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIsIAMiBEIgiCEFIAcgEX4iAkIgiCEDIAMgCCAQfiACQv////8Pg3wiAkIgiHwhAyADIAkgD34gAkL/////D4N8IgJCIIh8IQMgAyAKIA5+IAJC/////w+DfCICQiCIfCEDIAMgCyANfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAwgDH4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AjAgAyIEQiCIIQUgCCARfiICQiCIIQMgAyAJIBB+IAJC/////w+DfCICQiCIfCEDIAMgCiAPfiACQv////8Pg3wiAkIgiHwhAyADIAsgDn4gAkL/////D4N8IgJCIIh8IQMgAyAMIA1+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgI0IAMiBEIgiCEFIAkgEX4iAkIgiCEDIAMgCiAQfiACQv////8Pg3wiAkIgiHwhAyADIAsgD34gAkL/////D4N8IgJCIIh8IQMgAyAMIA5+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgDSANfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4COCADIgRCIIghBSAKIBF+IgJCIIghAyADIAsgEH4gAkL/////D4N8IgJCIIh8IQMgAyAMIA9+IAJC/////w+DfCICQiCIfCEDIAMgDSAOfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CPCADIgRCIIghBSALIBF+IgJCIIghAyADIAwgEH4gAkL/////D4N8IgJCIIh8IQMgAyANIA9+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgDiAOfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CQCADIgRCIIghBSAMIBF+IgJCIIghAyADIA0gEH4gAkL/////D4N8IgJCIIh8IQMgAyAOIA9+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgJEIAMiBEIgiCEFIA0gEX4iAkIgiCEDIAMgDiAQfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIA8gD34gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AkggAyIEQiCIIQUgDiARfiICQiCIIQMgAyAPIBB+IAJC/////w+DfCICQiCIfEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgJMIAMiBEIgiCEFIA8gEX4iAkIgiEIBhiACQv////8Pg0IBhiICQiCIfCEDIAMgECAQfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CUCADIgRCIIghBSAQIBF+IgJCIIhCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CVCADIgRCIIghBUIAIQJCACEDIAMgESARfiACQv////8Pg3wiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CWCABIAM+AlwLCgAgACAAIAEQCAtBACAAIAA1AAAgAXwiAT4AACABQiCIIQEDQCABUEUEQCAAQQRqIgA1AAAgAXwhASAAIAE+AAAgAUIgiCEBDAELCwuEBAIDfgF/IAAgA0GIASADGyIDEAAgAUEoEAAgAkHYACACGyIHEAFBuAEQAUEvIQBBLyEBA0AgAUEoai0AACABQQNGckUEQCABQQFrIQEMAQsLIAFBJWo1AABCAXwiBkIBUQRAQgBCAIAaCwNAAkADQCAAIANqLQAAIABBB0ZyRQRAIABBAWshAAwBCwsgACADakEHaykAACAGgCEFIAAgAWtBBGshAgNAIAVCgICAgHCDUCACQQBOcUUEQCAFQgiIIQUgAkEBaiECDAELCyAFUARAIANBKBAFRQ0BQgEhBUEAIQILQegBQSg1AAAgBX4iBD4AAEHsAUEsNQAAIAV+IARCIIh8IgQ+AABB8AFBMDUAACAFfiAEQiCIfCIEPgAAQfQBQTQ1AAAgBX4gBEIgiHwiBD4AAEH4AUE4NQAAIAV+IARCIIh8IgQ+AABB/AFBPDUAACAFfiAEQiCIfCIEPgAAQYACQcAANQAAIAV+IARCIIh8IgQ+AABBhAJBxAA1AAAgBX4gBEIgiHwiBD4AAEGIAkHIADUAACAFfiAEQiCIfCIEPgAAQYwCQcwANQAAIAV+IARCIIh8IgQ+AABBkAJB0AA1AAAgBX4gBEIgiHwiBD4AAEGUAkHUADUAACAFfiAEQiCIfD4AACADQegBIAJrIAMQBxogAiAHaiAFEAsMAQsLC44CAQp/QZgCIQNBmAIQAUHIAiEIIAFByAIQAEH4AiEJQfgCEANBqAMhBiAAQagDEABB2AMhC0GIBCEKQZgFIQQDQCAGEAJFBEAgCCAGIAsgChAMIAsgCUG4BBAIIAcEfyAFBH9BuAQgAxAFBH9BuAQgAyAEEAcaQQAFIANBuAQgBBAHGkEBCwVBuAQgAyAEEAYaQQELBSAFBH9BuAQgAyAEEAYaQQAFIANBuAQQBQR/IANBuAQgBBAHGkEABUG4BCADIAQQBxpBAQsLCyEMIAMhACAJIQMgBCEJIAAhBCAFIQcgDCEFIAghACAGIQggCiEGIAAhCgwBCwsgBwRAIAEgAyACEAcaBSADIAIQAAsLCQAgAEGoBhAECywAIAAgASACEAYEQCACQcgFIAIQBxoFIAJByAUQBQRAIAJByAUgAhAHGgsLCxcAIAAgASACEAcEQCACQcgFIAIQBhoLCwsAQdgGIAAgARAQC8YhAQN+IAAgADUCAEL9//P/DyIEIAA1AgB+Qv////8PgyIDQcgFNQIAfnwiAj4CACAAIAA1AgQgAkIgiHxBzAU1AgAgA358IgI+AgQgACAANQIIIAJCIIh8QdAFNQIAIAN+fCICPgIIIAAgADUCDCACQiCIfEHUBTUCACADfnwiAj4CDCAAIAA1AhAgAkIgiHxB2AU1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QdwFNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEHgBTUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxB5AU1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QegFNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEHsBTUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxB8AU1AgAgA358IgI+AiggACAANQIsIAJCIIh8QfQFNQIAIAN+fCICPgIsQfgIIAJCIIg+AgAgACAANQIEIAA1AgQgBH5C/////w+DIgNByAU1AgB+fCICPgIEIAAgADUCCCACQiCIfEHMBTUCACADfnwiAj4CCCAAIAA1AgwgAkIgiHxB0AU1AgAgA358IgI+AgwgACAANQIQIAJCIIh8QdQFNQIAIAN+fCICPgIQIAAgADUCFCACQiCIfEHYBTUCACADfnwiAj4CFCAAIAA1AhggAkIgiHxB3AU1AgAgA358IgI+AhggACAANQIcIAJCIIh8QeAFNQIAIAN+fCICPgIcIAAgADUCICACQiCIfEHkBTUCACADfnwiAj4CICAAIAA1AiQgAkIgiHxB6AU1AgAgA358IgI+AiQgACAANQIoIAJCIIh8QewFNQIAIAN+fCICPgIoIAAgADUCLCACQiCIfEHwBTUCACADfnwiAj4CLCAAIAA1AjAgAkIgiHxB9AU1AgAgA358IgI+AjBB/AggAkIgiD4CACAAIAA1AgggADUCCCAEfkL/////D4MiA0HIBTUCAH58IgI+AgggACAANQIMIAJCIIh8QcwFNQIAIAN+fCICPgIMIAAgADUCECACQiCIfEHQBTUCACADfnwiAj4CECAAIAA1AhQgAkIgiHxB1AU1AgAgA358IgI+AhQgACAANQIYIAJCIIh8QdgFNQIAIAN+fCICPgIYIAAgADUCHCACQiCIfEHcBTUCACADfnwiAj4CHCAAIAA1AiAgAkIgiHxB4AU1AgAgA358IgI+AiAgACAANQIkIAJCIIh8QeQFNQIAIAN+fCICPgIkIAAgADUCKCACQiCIfEHoBTUCACADfnwiAj4CKCAAIAA1AiwgAkIgiHxB7AU1AgAgA358IgI+AiwgACAANQIwIAJCIIh8QfAFNQIAIAN+fCICPgIwIAAgADUCNCACQiCIfEH0BTUCACADfnwiAj4CNEGACSACQiCIPgIAIAAgADUCDCAANQIMIAR+Qv////8PgyIDQcgFNQIAfnwiAj4CDCAAIAA1AhAgAkIgiHxBzAU1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QdAFNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEHUBTUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxB2AU1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QdwFNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEHgBTUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxB5AU1AgAgA358IgI+AiggACAANQIsIAJCIIh8QegFNQIAIAN+fCICPgIsIAAgADUCMCACQiCIfEHsBTUCACADfnwiAj4CMCAAIAA1AjQgAkIgiHxB8AU1AgAgA358IgI+AjQgACAANQI4IAJCIIh8QfQFNQIAIAN+fCICPgI4QYQJIAJCIIg+AgAgACAANQIQIAA1AhAgBH5C/////w+DIgNByAU1AgB+fCICPgIQIAAgADUCFCACQiCIfEHMBTUCACADfnwiAj4CFCAAIAA1AhggAkIgiHxB0AU1AgAgA358IgI+AhggACAANQIcIAJCIIh8QdQFNQIAIAN+fCICPgIcIAAgADUCICACQiCIfEHYBTUCACADfnwiAj4CICAAIAA1AiQgAkIgiHxB3AU1AgAgA358IgI+AiQgACAANQIoIAJCIIh8QeAFNQIAIAN+fCICPgIoIAAgADUCLCACQiCIfEHkBTUCACADfnwiAj4CLCAAIAA1AjAgAkIgiHxB6AU1AgAgA358IgI+AjAgACAANQI0IAJCIIh8QewFNQIAIAN+fCICPgI0IAAgADUCOCACQiCIfEHwBTUCACADfnwiAj4COCAAIAA1AjwgAkIgiHxB9AU1AgAgA358IgI+AjxBiAkgAkIgiD4CACAAIAA1AhQgADUCFCAEfkL/////D4MiA0HIBTUCAH58IgI+AhQgACAANQIYIAJCIIh8QcwFNQIAIAN+fCICPgIYIAAgADUCHCACQiCIfEHQBTUCACADfnwiAj4CHCAAIAA1AiAgAkIgiHxB1AU1AgAgA358IgI+AiAgACAANQIkIAJCIIh8QdgFNQIAIAN+fCICPgIkIAAgADUCKCACQiCIfEHcBTUCACADfnwiAj4CKCAAIAA1AiwgAkIgiHxB4AU1AgAgA358IgI+AiwgACAANQIwIAJCIIh8QeQFNQIAIAN+fCICPgIwIAAgADUCNCACQiCIfEHoBTUCACADfnwiAj4CNCAAIAA1AjggAkIgiHxB7AU1AgAgA358IgI+AjggACAANQI8IAJCIIh8QfAFNQIAIAN+fCICPgI8IAAgADUC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AlRBoAkgAkIgiD4CACAAIAA1AiwgADUCLCAEfkL/////D4MiA0HIBTUCAH58IgI+AiwgACAANQIwIAJCIIh8QcwFNQIAIAN+fCICPgIwIAAgADUCNCACQiCIfEHQBTUCACADfnwiAj4CNCAAIAA1AjggAkIgiHxB1AU1AgAgA358IgI+AjggACAANQI8IAJCIIh8QdgFNQIAIAN+fCICPgI8IAAgADUCQCACQiCIfEHcBTUCACADfnwiAj4CQCAAIAA1AkQgAkIgiHxB4AU1AgAgA358IgI+AkQgACAANQJIIAJCIIh8QeQFNQIAIAN+fCICPgJIIAAgADUCTCACQiCIfEHoBTUCACADfnwiAj4CTCAAIAA1AlAgAkIgiHxB7AU1AgAgA358IgI+AlAgACAANQJUIAJCIIh8QfAFNQIAIAN+fCICPgJUIAAgADUCWCACQiCIfEH0BTUCACADfnwiAj4CWEGkCSACQiCIPgIAQfgIIABBMGogARAPC/Q+ARt+IAUgATUCACIEIAA1AgAiEn58IgNC/////w+DIQUgBiAANQIEIhMgBH58IANCIIh8IgNC/////w+DIQYgByAANQIIIhQgBH58IANCIIh8IgNC/////w+DIQcgCCAANQIMIhUgBH58IANCIIh8IgNC/////w+DIQggCSAANQIQIhYgBH58IANCIIh8IgNC/////w+DIQkgCiAANQIUIhcgBH58IANCIIh8IgNC/////w+DIQogCyAANQIYIhggBH58IANCIIh8IgNC/////w+DIQsgDCAANQIcIhkgBH58IANCIIh8IgNC/////w+DIQwgDSAANQIgIhogBH58IANCIIh8IgNC/////w+DIQ0gDiAANQIkIhsgBH58IANCIIh8IgNC/////w+DIQ4gDyAANQIoIhwgBH58IANCIIh8IgNC/////w+DIQ8gECAANQIsIh0gBH58IANCIIh8IgNC/////w+DIRAgA0IgiCERIAUgBUL9//P/D35C/////w+DIgRCq9X+/w9+fEIgiCAGIARC///7zwt+fHwiA0L/////D4MhBSAHIARC///Pigt+fCADQiCIfCIDQv////8PgyEGIAggBEL+/6/1AX58IANCIIh8IgNC/////w+DIQcgCSAEQqTsw7UPfnwgA0IgiHwiA0L/////D4MhCCAKIARCoKXDuQZ+fCADQiCIfCIDQv////8PgyEJIAsgBEK/pZScD358IANCIIh8IgNC/////w+DIQogDCAEQoSX3aMGfnwgA0IgiHwiA0L/////D4MhCyANIARC19mumgR+fCADQiCIfCIDQv////8PgyEMIA4gBEK2z+7YBH58IANCIIh8IgNC/////w+DIQ0gDyAEQprN/8sDfnwgA0IgiHwiA0L/////D4MhDiAQIARC6qOE0AF+fCADQiCIfCIDQv////8PgyEPIBEgA0IgiHwhECAFIBIgATUCBCIEfnwiA0L/////D4MhBSAGIAQgE358IANCIIh8IgNC/////w+DIQYgByAEIBR+fCADQiCIfCIDQv////8PgyEHIAggBCAVfnwgA0IgiHwiA0L/////D4MhCCAJIAQgFn58IANCIIh8IgNC/////w+DIQkgCiAEIBd+fCADQiCIfCIDQv////8PgyEKIAsgBCAYfnwgA0IgiHwiA0L/////D4MhCyAMIAQgGX58IANCIIh8IgNC/////w+DIQwgDSAEIBp+fCADQiCIfCIDQv////8PgyENIA4gBCAbfnwgA0IgiHwiA0L/////D4MhDiAPIAQgHH58IANCIIh8IgNC/////w+DIQ8gECAEIB1+fCADQiCIfCIDQv////8PgyEQIANCIIghESAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DIQUgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4MhBiAIIARC/v+v9QF+fCADQiCIfCIDQv////8PgyEHIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DIQggCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4MhCSALIARCv6WUnA9+fCADQiCIfCIDQv////8PgyEKIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DIQsgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4MhDCAOIARCts/u2AR+fCADQiCIfCIDQv////8PgyENIA8gBEKazf/LA358IANCIIh8IgNC/////w+DIQ4gECAEQuqjhNABfnwgA0IgiHwiA0L/////D4MhDyARIANCIIh8IRAgBSASIAE1AggiBH58IgNC/////w+DIQUgBiAEIBN+fCADQiCIfCIDQv////8PgyEGIAcgBCAUfnwgA0IgiHwiA0L/////D4MhByAIIAQgFX58IANCIIh8IgNC/////w+DIQggCSAEIBZ+fCADQiCIfCIDQv////8PgyEJIAogBCAXfnwgA0IgiHwiA0L/////D4MhCiALIAQgGH58IANCIIh8IgNC/////w+DIQsgDCAEIBl+fCADQiCIfCIDQv////8PgyEMIA0gBCAafnwgA0IgiHwiA0L/////D4MhDSAOIAQgG358IANCIIh8IgNC/////w+DIQ4gDyAEIBx+fCADQiCIfCIDQv////8PgyEPIBAgBCAdfnwgA0IgiHwiA0L/////D4MhECADQiCIIREgBSAFQv3/8/8PfkL/////D4MiBEKr1f7/D358QiCIIAYgBEL///vPC358fCIDQv////8PgyEFIAcgBEL//8+KC358IANCIIh8IgNC/////w+DIQYgCCAEQv7/r/UBfnwgA0IgiHwiA0L/////D4MhByAJIARCpOzDtQ9+fCADQiCIfCIDQv////8PgyEIIAogBEKgpcO5Bn58IANCIIh8IgNC/////w+DIQkgCyAEQr+llJwPfnwgA0IgiHwiA0L/////D4MhCiAMIARChJfdowZ+fCADQiCIfCIDQv////8PgyELIA0gBELX2a6aBH58IANCIIh8IgNC/////w+DIQwgDiAEQrbP7tgEfnwgA0IgiHwiA0L/////D4MhDSAPIARCms3/ywN+fCADQiCIfCIDQv////8PgyEOIBAgBELqo4TQAX58IANCIIh8IgNC/////w+DIQ8gESADQiCIfCEQIAUgEiABNQIMIgR+fCIDQv////8PgyEFIAYgBCATfnwgA0IgiHwiA0L/////D4MhBiAHIAQgFH58IANCIIh8IgNC/////w+DIQcgCCAEIBV+fCADQiCIfCIDQv////8PgyEIIAkgBCAWfnwgA0IgiHwiA0L/////D4MhCSAKIAQgF358IANCIIh8IgNC/////w+DIQogCyAEIBh+fCADQiCIfCIDQv////8PgyELIAwgBCAZfnwgA0IgiHwiA0L/////D4MhDCANIAQgGn58IANCIIh8IgNC/////w+DIQ0gDiAEIBt+fCADQiCIfCIDQv////8PgyEOIA8gBCAcfnwgA0IgiHwiA0L/////D4MhDyAQIAQgHX58IANCIIh8IgNC/////w+DIRAgA0IgiCERIAUgBUL9//P/D35C/////w+DIgRCq9X+/w9+fEIgiCAGIARC///7zwt+fHwiA0L/////D4MhBSAHIARC///Pigt+fCADQiCIfCIDQv////8PgyEGIAggBEL+/6/1AX58IANCIIh8IgNC/////w+DIQcgCSAEQqTsw7UPfnwgA0IgiHwiA0L/////D4MhCCAKIARCoKXDuQZ+fCADQiCIfCIDQv////8PgyEJIAsgBEK/pZScD358IANCIIh8IgNC/////w+DIQogDCAEQoSX3aMGfnwgA0IgiHwiA0L/////D4MhCyANIARC19mumgR+fCADQiCIfCIDQv////8PgyEMIA4gBEK2z+7YBH58IANCIIh8IgNC/////w+DIQ0gDyAEQprN/8sDfnwgA0IgiHwiA0L/////D4MhDiAQIARC6qOE0AF+fCADQiCIfCIDQv////8PgyEPIBEgA0IgiHwhECAFIBIgATUCECIEfnwiA0L/////D4MhBSAGIAQgE358IANCIIh8IgNC/////w+DIQYgByAEIBR+fCADQiCIfCIDQv////8PgyEHIAggBCAVfnwgA0IgiHwiA0L/////D4MhCCAJIAQgFn58IANCIIh8IgNC/////w+DIQkgCiAEIBd+fCADQiCIfCIDQv////8PgyEKIAsgBCAYfnwgA0IgiHwiA0L/////D4MhCyAMIAQgGX58IANCIIh8IgNC/////w+DIQwgDSAEIBp+fCADQiCIfCIDQv////8PgyENIA4gBCAbfnwgA0IgiHwiA0L/////D4MhDiAPIAQgHH58IANCIIh8IgNC/////w+DIQ8gECAEIB1+fCADQiCIfCIDQv////8PgyEQIANCIIghESAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DIQUgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4MhBiAIIARC/v+v9QF+fCADQiCIfCIDQv////8PgyEHIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DIQggCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4MhCSALIARCv6WUnA9+fCADQiCIfCIDQv////8PgyEKIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DIQsgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4MhDCAOIARCts/u2AR+fCADQiCIfCIDQv////8PgyENIA8gBEKazf/LA358IANCIIh8IgNC/////w+DIQ4gECAEQuqjhNABfnwgA0IgiHwiA0L/////D4MhDyARIANCIIh8IRAgBSASIAE1AhQiBH58IgNC/////w+DIQUgBiAEIBN+fCADQiCIfCIDQv////8PgyEGIAcgBCAUfnwgA0IgiHwiA0L/////D4MhByAIIAQgFX58IANCIIh8IgNC/////w+DIQggCSAEIBZ+fCADQiCIfCIDQv////8PgyEJIAogBCAXfnwgA0IgiHwiA0L/////D4MhCiALIAQgGH58IANCIIh8IgNC/////w+DIQsgDCAEIBl+fCADQiCIfCIDQv////8PgyEMIA0gBCAafnwgA0IgiHwiA0L/////D4MhDSAOIAQgG358IANCIIh8IgNC/////w+DIQ4gDyAEIBx+fCADQiCIfCIDQv////8PgyEPIBAgBCAdfnwgA0IgiHwiA0L/////D4MhECADQiCIIREgBSAFQv3/8/8PfkL/////D4MiBEKr1f7/D358QiCIIAYgBEL///vPC358fCIDQv////8PgyEFIAcgBEL//8+KC358IANCIIh8IgNC/////w+DIQYgCCAEQv7/r/UBfnwgA0IgiHwiA0L/////D4MhByAJIARCpOzDtQ9+fCADQiCIfCIDQv////8PgyEIIAogBEKgpcO5Bn58IANCIIh8IgNC/////w+DIQkgCyAEQr+llJwPfnwgA0IgiHwiA0L/////D4MhCiAMIARChJfdowZ+fCADQiCIfCIDQv////8PgyELIA0gBELX2a6aBH58IANCIIh8IgNC/////w+DIQwgDiAEQrbP7tgEfnwgA0IgiHwiA0L/////D4MhDSAPIARCms3/ywN+fCADQiCIfCIDQv////8PgyEOIBAgBELqo4TQAX58IANCIIh8IgNC/////w+DIQ8gESADQiCIfCEQIAUgEiABNQIYIgR+fCIDQv////8PgyEFIAYgBCATfnwgA0IgiHwiA0L/////D4MhBiAHIAQgFH58IANCIIh8IgNC/////w+DIQcgCCAEIBV+fCADQiCIfCIDQv////8PgyEIIAkgBCAWfnwgA0IgiHwiA0L/////D4MhCSAKIAQgF358IANCIIh8IgNC/////w+DIQogCyAEIBh+fCADQiCIfCIDQv////8PgyELIAwgBCAZfnwgA0IgiHwiA0L/////D4MhDCANIAQgGn58IANCIIh8IgNC/////w+DIQ0gDiAEIBt+fCADQiCIfCIDQv////8PgyEOIA8gBCAcfnwgA0IgiHwiA0L/////D4MhDyAQIAQgHX58IANCIIh8IgNC/////w+DIRAgA0IgiCERIAUgBUL9//P/D35C/////w+DIgRCq9X+/w9+fEIgiCAGIARC///7zwt+fHwiA0L/////D4MhBSAHIARC///Pigt+fCADQiCIfCIDQv////8PgyEGIAggBEL+/6/1AX58IANCIIh8IgNC/////w+DIQcgCSAEQqTsw7UPfnwgA0IgiHwiA0L/////D4MhCCAKIARCoKXDuQZ+fCADQiCIfCIDQv////8PgyEJIAsgBEK/pZScD358IANCIIh8IgNC/////w+DIQogDCAEQoSX3aMGfnwgA0IgiHwiA0L/////D4MhCyANIARC19mumgR+fCADQiCIfCIDQv////8PgyEMIA4gBEK2z+7YBH58IANCIIh8IgNC/////w+DIQ0gDyAEQprN/8sDfnwgA0IgiHwiA0L/////D4MhDiAQIARC6qOE0AF+fCADQiCIfCIDQv////8PgyEPIBEgA0IgiHwhECAFIBIgATUCHCIEfnwiA0L/////D4MhBSAGIAQgE358IANCIIh8IgNC/////w+DIQYgByAEIBR+fCADQiCIfCIDQv////8PgyEHIAggBCAVfnwgA0IgiHwiA0L/////D4MhCCAJIAQgFn58IANCIIh8IgNC/////w+DIQkgCiAEIBd+fCADQiCIfCIDQv////8PgyEKIAsgBCAYfnwgA0IgiHwiA0L/////D4MhCyAMIAQgGX58IANCIIh8IgNC/////w+DIQwgDSAEIBp+fCADQiCIfCIDQv////8PgyENIA4gBCAbfnwgA0IgiHwiA0L/////D4MhDiAPIAQgHH58IANCIIh8IgNC/////w+DIQ8gECAEIB1+fCADQiCIfCIDQv////8PgyEQIANCIIghESAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DIQUgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4MhBiAIIARC/v+v9QF+fCADQiCIfCIDQv////8PgyEHIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DIQggCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4MhCSALIARCv6WUnA9+fCADQiCIfCIDQv////8PgyEKIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DIQsgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4MhDCAOIARCts/u2AR+fCADQiCIfCIDQv////8PgyENIA8gBEKazf/LA358IANCIIh8IgNC/////w+DIQ4gECAEQuqjhNABfnwgA0IgiHwiA0L/////D4MhDyARIANCIIh8IRAgBSASIAE1AiAiBH58IgNC/////w+DIQUgBiAEIBN+fCADQiCIfCIDQv////8PgyEGIAcgBCAUfnwgA0IgiHwiA0L/////D4MhByAIIAQgFX58IANCIIh8IgNC/////w+DIQggCSAEIBZ+fCADQiCIfCIDQv////8PgyEJIAogBCAXfnwgA0IgiHwiA0L/////D4MhCiALIAQgGH58IANCIIh8IgNC/////w+DIQsgDCAEIBl+fCADQiCIfCIDQv////8PgyEMIA0gBCAafnwgA0IgiHwiA0L/////D4MhDSAOIAQgG358IANCIIh8IgNC/////w+DIQ4gDyAEIBx+fCADQiCIfCIDQv////8PgyEPIBAgBCAdfnwgA0IgiHwiA0L/////D4MhECADQiCIIREgBSAFQv3/8/8PfkL/////D4MiBEKr1f7/D358QiCIIAYgBEL///vPC358fCIDQv////8PgyEFIAcgBEL//8+KC358IANCIIh8IgNC/////w+DIQYgCCAEQv7/r/UBfnwgA0IgiHwiA0L/////D4MhByAJIARCpOzDtQ9+fCADQiCIfCIDQv////8PgyEIIAogBEKgpcO5Bn58IANCIIh8IgNC/////w+DIQkgCyAEQr+llJwPfnwgA0IgiHwiA0L/////D4MhCiAMIARChJfdowZ+fCADQiCIfCIDQv////8PgyELIA0gBELX2a6aBH58IANCIIh8IgNC/////w+DIQwgDiAEQrbP7tgEfnwgA0IgiHwiA0L/////D4MhDSAPIARCms3/ywN+fCADQiCIfCIDQv////8PgyEOIBAgBELqo4TQAX58IANCIIh8IgNC/////w+DIQ8gESADQiCIfCEQIAUgEiABNQIkIgR+fCIDQv////8PgyEFIAYgBCATfnwgA0IgiHwiA0L/////D4MhBiAHIAQgFH58IANCIIh8IgNC/////w+DIQcgCCAEIBV+fCADQiCIfCIDQv////8PgyEIIAkgBCAWfnwgA0IgiHwiA0L/////D4MhCSAKIAQgF358IANCIIh8IgNC/////w+DIQogCyAEIBh+fCADQiCIfCIDQv////8PgyELIAwgBCAZfnwgA0IgiHwiA0L/////D4MhDCANIAQgGn58IANCIIh8IgNC/////w+DIQ0gDiAEIBt+fCADQiCIfCIDQv////8PgyEOIA8gBCAcfnwgA0IgiHwiA0L/////D4MhDyAQIAQgHX58IANCIIh8IgNC/////w+DIRAgA0IgiCERIAUgBUL9//P/D35C/////w+DIgRCq9X+/w9+fEIgiCAGIARC///7zwt+fHwiA0L/////D4MhBSAHIARC///Pigt+fCADQiCIfCIDQv////8PgyEGIAggBEL+/6/1AX58IANCIIh8IgNC/////w+DIQcgCSAEQqTsw7UPfnwgA0IgiHwiA0L/////D4MhCCAKIARCoKXDuQZ+fCADQiCIfCIDQv////8PgyEJIAsgBEK/pZScD358IANCIIh8IgNC/////w+DIQogDCAEQoSX3aMGfnwgA0IgiHwiA0L/////D4MhCyANIARC19mumgR+fCADQiCIfCIDQv////8PgyEMIA4gBEK2z+7YBH58IANCIIh8IgNC/////w+DIQ0gDyAEQprN/8sDfnwgA0IgiHwiA0L/////D4MhDiAQIARC6qOE0AF+fCADQiCIfCIDQv////8PgyEPIBEgA0IgiHwhECAFIBIgATUCKCIEfnwiA0L/////D4MhBSAGIAQgE358IANCIIh8IgNC/////w+DIQYgByAEIBR+fCADQiCIfCIDQv////8PgyEHIAggBCAVfnwgA0IgiHwiA0L/////D4MhCCAJIAQgFn58IANCIIh8IgNC/////w+DIQkgCiAEIBd+fCADQiCIfCIDQv////8PgyEKIAsgBCAYfnwgA0IgiHwiA0L/////D4MhCyAMIAQgGX58IANCIIh8IgNC/////w+DIQwgDSAEIBp+fCADQiCIfCIDQv////8PgyENIA4gBCAbfnwgA0IgiHwiA0L/////D4MhDiAPIAQgHH58IANCIIh8IgNC/////w+DIQ8gECAEIB1+fCADQiCIfCIDQv////8PgyEQIANCIIghESAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DIQUgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4MhBiAIIARC/v+v9QF+fCADQiCIfCIDQv////8PgyEHIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DIQggCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4MhCSALIARCv6WUnA9+fCADQiCIfCIDQv////8PgyEKIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DIQsgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4MhDCAOIARCts/u2AR+fCADQiCIfCIDQv////8PgyENIA8gBEKazf/LA358IANCIIh8IgNC/////w+DIQ4gECAEQuqjhNABfnwgA0IgiHwiA0L/////D4MhDyARIANCIIh8IRAgBSASIAE1AiwiBH58IgNC/////w+DIQUgBiAEIBN+fCADQiCIfCIDQv////8PgyEGIAcgBCAUfnwgA0IgiHwiA0L/////D4MhByAIIAQgFX58IANCIIh8IgNC/////w+DIQggCSAEIBZ+fCADQiCIfCIDQv////8PgyEJIAogBCAXfnwgA0IgiHwiA0L/////D4MhCiALIAQgGH58IANCIIh8IgNC/////w+DIQsgDCAEIBl+fCADQiCIfCIDQv////8PgyEMIA0gBCAafnwgA0IgiHwiA0L/////D4MhDSAOIAQgG358IANCIIh8IgNC/////w+DIQ4gDyAEIBx+fCADQiCIfCIDQv////8PgyEPIBAgBCAdfnwgA0IgiHwiA0L/////D4MhECADQiCIIREgAiAFIAVC/f/z/w9+Qv////8PgyIEQqvV/v8PfnxCIIggBiAEQv//+88Lfnx8IgNC/////w+DPgIAIAIgByAEQv//z4oLfnwgA0IgiHwiA0L/////D4M+AgQgAiAIIARC/v+v9QF+fCADQiCIfCIDQv////8Pgz4CCCACIAkgBEKk7MO1D358IANCIIh8IgNC/////w+DPgIMIAIgCiAEQqClw7kGfnwgA0IgiHwiA0L/////D4M+AhAgAiALIARCv6WUnA9+fCADQiCIfCIDQv////8Pgz4CFCACIAwgBEKEl92jBn58IANCIIh8IgNC/////w+DPgIYIAIgDSAEQtfZrpoEfnwgA0IgiHwiA0L/////D4M+AhwgAiAOIARCts/u2AR+fCADQiCIfCIDQv////8Pgz4CICACIA8gBEKazf/LA358IANCIIh8IgNC/////w+DPgIkIAIgECAEQuqjhNABfnwgA0IgiHwiA0L/////D4M+AiggAiARIANCIIh8PgIsIAJByAUQBQRAIAJByAUgAhAHGgsLiEABG34gCiAANQIAIhEgEX58IgJC/////w+DIQogECAANQIEIhMgEX4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIRAgA0IgiEIBhiACQiCIfCAPIAA1AggiFCARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQ8gA0IgiEIBhiACQiCIfCAOIAA1AgwiFSARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQ4gA0IgiEIBhiACQiCIfCANIAA1AhAiFiARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQ0gA0IgiEIBhiACQiCIfCAMIAA1AhQiFyARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIAA1AhgiGCARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAJIAA1AhwiGSARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQkgA0IgiEIBhiACQiCIfCAIIAA1AiAiGiARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIAA1AiQiGyARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIAA1AigiHCARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQYgA0IgiEIBhiACQiCIfCAEIBEgADUCLCIRfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIBIgAkIgiHwhEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIBAgEyATfnwiAkL/////D4MhECAPIBMgFH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQ8gA0IgiEIBhiACQiCIfCAOIBMgFX4iA0L/////D4NCAYZ8fCICQv////8PgyEOIANCIIhCAYYgAkIgiHwgDSATIBZ+IgNC/////w+DQgGGfHwiAkL/////D4MhDSADQiCIQgGGIAJCIIh8IAwgEyAXfiIDQv////8Pg0IBhnx8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIBMgGH4iA0L/////D4NCAYZ8fCICQv////8PgyELIANCIIhCAYYgAkIgiHwgCSATIBl+IgNC/////w+DQgGGfHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAggEyAafiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBMgG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiATIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESATfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIA8gFCAUfnwiAkL/////D4MhDyAOIBQgFX4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQ4gA0IgiEIBhiACQiCIfCANIBQgFn4iA0L/////D4NCAYZ8fCICQv////8PgyENIANCIIhCAYYgAkIgiHwgDCAUIBd+IgNC/////w+DQgGGfHwiAkL/////D4MhDCADQiCIQgGGIAJCIIh8IAsgFCAYfiIDQv////8Pg0IBhnx8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAJIBQgGX4iA0L/////D4NCAYZ8fCICQv////8PgyEJIANCIIhCAYYgAkIgiHwgCCAUIBp+IgNC/////w+DQgGGfHwiAkL/////D4MhCCADQiCIQgGGIAJCIIh8IAcgFCAbfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIBQgHH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCARIBR+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCESIAogCkL9//P/D35C/////w+DIgNCq9X+/w9+fEIgiCAQIANC///7zwt+fHwiAkL/////D4MhCiAPIANC///Pigt+fCACQiCIfCICQv////8PgyEQIA4gA0L+/6/1AX58IAJCIIh8IgJC/////w+DIQ8gDSADQqTsw7UPfnwgAkIgiHwiAkL/////D4MhDiAMIANCoKXDuQZ+fCACQiCIfCICQv////8PgyENIAsgA0K/pZScD358IAJCIIh8IgJC/////w+DIQwgCSADQoSX3aMGfnwgAkIgiHwiAkL/////D4MhCyAIIANC19mumgR+fCACQiCIfCICQv////8PgyEJIAcgA0K2z+7YBH58IAJCIIh8IgJC/////w+DIQggBiADQprN/8sDfnwgAkIgiHwiAkL/////D4MhByAEIANC6qOE0AF+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCASIAJCIIh8IQUgDiAVIBV+fCICQv////8PgyEOIA0gFSAWfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhDSADQiCIQgGGIAJCIIh8IAwgFSAXfiIDQv////8Pg0IBhnx8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIBUgGH4iA0L/////D4NCAYZ8fCICQv////8PgyELIANCIIhCAYYgAkIgiHwgCSAVIBl+IgNC/////w+DQgGGfHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAggFSAafiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBUgG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAVIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAVfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIA0gFiAWfnwiAkL/////D4MhDSAMIBYgF34iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIBYgGH4iA0L/////D4NCAYZ8fCICQv////8PgyELIANCIIhCAYYgAkIgiHwgCSAWIBl+IgNC/////w+DQgGGfHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAggFiAafiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBYgG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAWIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAWfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAwgFyAXfnwiAkL/////D4MhDCALIBcgGH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAJIBcgGX4iA0L/////D4NCAYZ8fCICQv////8PgyEJIANCIIhCAYYgAkIgiHwgCCAXIBp+IgNC/////w+DQgGGfHwiAkL/////D4MhCCADQiCIQgGGIAJCIIh8IAcgFyAbfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIBcgHH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCARIBd+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCESIAogCkL9//P/D35C/////w+DIgNCq9X+/w9+fEIgiCAQIANC///7zwt+fHwiAkL/////D4MhCiAPIANC///Pigt+fCACQiCIfCICQv////8PgyEQIA4gA0L+/6/1AX58IAJCIIh8IgJC/////w+DIQ8gDSADQqTsw7UPfnwgAkIgiHwiAkL/////D4MhDiAMIANCoKXDuQZ+fCACQiCIfCICQv////8PgyENIAsgA0K/pZScD358IAJCIIh8IgJC/////w+DIQwgCSADQoSX3aMGfnwgAkIgiHwiAkL/////D4MhCyAIIANC19mumgR+fCACQiCIfCICQv////8PgyEJIAcgA0K2z+7YBH58IAJCIIh8IgJC/////w+DIQggBiADQprN/8sDfnwgAkIgiHwiAkL/////D4MhByAEIANC6qOE0AF+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCASIAJCIIh8IQUgCyAYIBh+fCICQv////8PgyELIAkgGCAZfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAggGCAafiIDQv////8Pg0IBhnx8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBggG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAYIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAYfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAkgGSAZfnwiAkL/////D4MhCSAIIBkgGn4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQggA0IgiEIBhiACQiCIfCAHIBkgG34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAZIBx+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAZfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAggGiAafnwiAkL/////D4MhCCAHIBogG34iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIBogHH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCARIBp+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCESIAogCkL9//P/D35C/////w+DIgNCq9X+/w9+fEIgiCAQIANC///7zwt+fHwiAkL/////D4MhCiAPIANC///Pigt+fCACQiCIfCICQv////8PgyEQIA4gA0L+/6/1AX58IAJCIIh8IgJC/////w+DIQ8gDSADQqTsw7UPfnwgAkIgiHwiAkL/////D4MhDiAMIANCoKXDuQZ+fCACQiCIfCICQv////8PgyENIAsgA0K/pZScD358IAJCIIh8IgJC/////w+DIQwgCSADQoSX3aMGfnwgAkIgiHwiAkL/////D4MhCyAIIANC19mumgR+fCACQiCIfCICQv////8PgyEJIAcgA0K2z+7YBH58IAJCIIh8IgJC/////w+DIQggBiADQprN/8sDfnwgAkIgiHwiAkL/////D4MhByAEIANC6qOE0AF+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCASIAJCIIh8IQUgByAbIBt+fCICQv////8PgyEHIAYgGyAcfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgESAbfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAYgHCAcfnwiAkL/////D4MhBiAEIBEgHH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghEiAKIApC/f/z/w9+Qv////8PgyIDQqvV/v8PfnxCIIggECADQv//+88Lfnx8IgJC/////w+DIQogDyADQv//z4oLfnwgAkIgiHwiAkL/////D4MhECAOIANC/v+v9QF+fCACQiCIfCICQv////8PgyEPIA0gA0Kk7MO1D358IAJCIIh8IgJC/////w+DIQ4gDCADQqClw7kGfnwgAkIgiHwiAkL/////D4MhDSALIANCv6WUnA9+fCACQiCIfCICQv////8PgyEMIAkgA0KEl92jBn58IAJCIIh8IgJC/////w+DIQsgCCADQtfZrpoEfnwgAkIgiHwiAkL/////D4MhCSAHIANCts/u2AR+fCACQiCIfCICQv////8PgyEIIAYgA0Kazf/LA358IAJCIIh8IgJC/////w+DIQcgBCADQuqjhNABfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgEiACQiCIfCEFIAQgESARfnwiAkL/////D4MhBCAFIAJCIIh8IgJC/////w+DIQUgAkIgiCESIAEgCiAKQv3/8/8PfkL/////D4MiA0Kr1f7/D358QiCIIBAgA0L///vPC358fCICQv////8Pgz4CACABIA8gA0L//8+KC358IAJCIIh8IgJC/////w+DPgIEIAEgDiADQv7/r/UBfnwgAkIgiHwiAkL/////D4M+AgggASANIANCpOzDtQ9+fCACQiCIfCICQv////8Pgz4CDCABIAwgA0KgpcO5Bn58IAJCIIh8IgJC/////w+DPgIQIAEgCyADQr+llJwPfnwgAkIgiHwiAkL/////D4M+AhQgASAJIANChJfdowZ+fCACQiCIfCICQv////8Pgz4CGCABIAggA0LX2a6aBH58IAJCIIh8IgJC/////w+DPgIcIAEgByADQrbP7tgEfnwgAkIgiHwiAkL/////D4M+AiAgASAGIANCms3/ywN+fCACQiCIfCICQv////8Pgz4CJCABIAQgA0Lqo4TQAX58IAJCIIh8IgJC/////w+DPgIoIAEgBSACQiCIfCICQv////8Pgz4CLCASIAJCIIh8pwRAIAFByAUgARAHGgUgAUHIBRAFBEAgAUHIBSABEAcaCwsLCgAgACAAIAEQEwsLACAAQfgFIAEQEwsVACAAQfgREABBqBIQAUH4ESABEBILEQAgAEHYEhAXQdgSQbgHEAULIwAgABACBEBBAA8LIABBiBMQF0GIE0G4BxAFBEBBfw8LQQELFwAgACABEBcgAUHIBSABEA0gASABEBYLCQBBqAYgABAAC7wBAQJ/IAIQAUEwIQMDQCABIANPBEAgA0EwRgRAQbgTEBsFQbgTQfgFQbgTEBMLIABBuBNB6BMQEyACQegTIAIQDyAAQTBqIQAgA0EwaiEDDAELCyABQTBwIgRFBEAPC0HoExABQQAhAQNAIAEgBEZFBEAgASAALQAAOgDoEyAAQQFqIQAgAUEBaiEBDAELCyADQTBGBEBBuBMQGwVBuBNB+AVBuBMQEwtB6BNBuBNB6BMQEyACQegTIAIQDwscACABIAJBmBQQHEGYFEGYFBAWIABBmBQgAxATC+EBAQJ/QQBBACgCACIFIAJBAWpBMGxqNgIAIAUQGyAFQTBqIQUDQCACIAZHBEAgABACBEAgBUEwayAFEAAFIAAgBUEwayAFEBMLIAAgAWohACAFQTBqIQUgBkEBaiEGDAELCyAAIAFrIQAgAyACQQFrIARsaiECIAVBMGsiBSAFEBoDQCAGBEAgABACBEAgBSAFQTBrEAAgAhABBSAFQTBrQcgUEAAgBSAAIAVBMGsQEyAFQcgUIAIQEwsgACABayEAIAIgBGshAiAFQTBrIQUgBkEBayEGDAELC0EAIAU2AgALLQEBfwNAIAEgA0ZFBEAgACACEBYgAEEwaiEAIAJBMGohAiADQQFqIQMMAQsLCy0BAX8DQCABIANGRQRAIAAgAhAXIABBMGohACACQTBqIQIgA0EBaiEDDAELCwuXAgAgAkUEQCADEBsPCyAAQfgUEAAgAxAbA0AgAkEBayICIAFqLQAAIQAgAyADEBQgAEGAAU8EQCADQfgUIAMQEyAAQYABayEACyADIAMQFCAAQcAATwRAIANB+BQgAxATIABBQGohAAsgAyADEBQgAEEgTwRAIANB+BQgAxATIABBIGshAAsgAyADEBQgAEEQTwRAIANB+BQgAxATIABBEGshAAsgAyADEBQgAEEITwRAIANB+BQgAxATIABBCGshAAsgAyADEBQgAEEETwRAIANB+BQgAxATIABBBGshAAsgAyADEBQgAEECTwRAIANB+BQgAxATIABBAmshAAsgAyADEBQgAARAIANB+BQgAxATCyACDQALC9UBAQF/IAAQAgRAIAEQAQ8LQQEhAkGYCEGoFRAAIABB6AdBMEHYFRAhIABByAhBMEGIFhAhA0BB2BVBqAYQBEUEQEHYFUG4FhAUQQEhAANAQbgWQagGEARFBEBBuBZBuBYQFCAAQQFqIQAMAQsLQagVQegWEAAgAiAAa0EBayECA0AgAgRAQegWQegWEBQgAkEBayECDAELCyAAIQJB6BZBqBUQFEHYFUGoFUHYFRATQYgWQegWQYgWEBMMAQsLQYgWEBgEQEGIFiABEBEFQYgWIAEQAAsLIAAgABACBEBBAQ8LIABBiAdBMEGYFxAhQZgXQagGEAQLKgAgASAAKQMANwMAIAEgACkDCDcDCCABIAApAxA3AxAgASAAKQMYNwMYCx4AIABCADcDACAAQgA3AwggAEIANwMQIABCADcDGAssACAAKQMYUAR+IAApAxBQBH4gACkDCFAEfiAAKQMABUIBCwVCAQsFQgELUAseACAAQgE3AwAgAEIANwMIIABCADcDECAAQgA3AxgLQAAgACkDGCABKQMYUQR/IAApAxAgASkDEFEEfyAAKQMIIAEpAwhRBH8gACkDACABKQMAUQVBAAsFQQALBUEACwtzACAAKQMYIAEpAxhUBH9BAAUgACkDGCABKQMYVgR/QQEFIAApAxAgASkDEFQEf0EABSAAKQMQIAEpAxBWBH9BAQUgACkDCCABKQMIVAR/QQAFIAApAwggASkDCFYEf0EBBSAAKQMAIAEpAwBaCwsLCwsLC8QBAQF+IAIgADUCACABNQIAfCIDPgIAIAIgADUCBCABNQIEfCADQiCIfCIDPgIEIAIgADUCCCABNQIIfCADQiCIfCIDPgIIIAIgADUCDCABNQIMfCADQiCIfCIDPgIMIAIgADUCECABNQIQfCADQiCIfCIDPgIQIAIgADUCFCABNQIUfCADQiCIfCIDPgIUIAIgADUCGCABNQIYfCADQiCIfCIDPgIYIAIgADUCHCABNQIcfCADQiCIfCIDPgIcIANCIIinC/wBAQF+IAIgADUCACABNQIAfSIDQv////8Pgz4CACACIAA1AgQgATUCBH0gA0Igh3wiA0L/////D4M+AgQgAiAANQIIIAE1Agh9IANCIId8IgNC/////w+DPgIIIAIgADUCDCABNQIMfSADQiCHfCIDQv////8Pgz4CDCACIAA1AhAgATUCEH0gA0Igh3wiA0L/////D4M+AhAgAiAANQIUIAE1AhR9IANCIId8IgNC/////w+DPgIUIAIgADUCGCABNQIYfSADQiCHfCIDQv////8Pgz4CGCACIAA1AhwgATUCHH0gA0Igh3wiA0L/////D4M+AhwgA0Igh6cL5g4BEX4gBCAANQIAIgUgATUCACIGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AgAgBEIgiCEDIAMgBSABNQIEIgd+IARC/////w+DfCIEQiCIfCEDIAMgADUCBCIIIAZ+IARC/////w+DfCIEQiCIfCEDIAIgBD4CBCADQiCIIQQgBCAFIAE1AggiCX4gA0L/////D4N8IgNCIIh8IQQgBCAHIAh+IANC/////w+DfCIDQiCIfCEEIAQgADUCCCIKIAZ+IANC/////w+DfCIDQiCIfCEEIAIgAz4CCCAEQiCIIQMgAyAFIAE1AgwiC34gBEL/////D4N8IgRCIIh8IQMgAyAIIAl+IARC/////w+DfCIEQiCIfCEDIAMgByAKfiAEQv////8Pg3wiBEIgiHwhAyADIAA1AgwiDCAGfiAEQv////8Pg3wiBEIgiHwhAyACIAQ+AgwgA0IgiCEEIAQgBSABNQIQIg1+IANC/////w+DfCIDQiCIfCEEIAQgCCALfiADQv////8Pg3wiA0IgiHwhBCAEIAkgCn4gA0L/////D4N8IgNCIIh8IQQgBCAHIAx+IANC/////w+DfCIDQiCIfCEEIAQgADUCECIOIAZ+IANC/////w+DfCIDQiCIfCEEIAIgAz4CECAEQiCIIQMgAyAFIAE1AhQiD34gBEL/////D4N8IgRCIIh8IQMgAyAIIA1+IARC/////w+DfCIEQiCIfCEDIAMgCiALfiAEQv////8Pg3wiBEIgiHwhAyADIAkgDH4gBEL/////D4N8IgRCIIh8IQMgAyAHIA5+IARC/////w+DfCIEQiCIfCEDIAMgADUCFCIQIAZ+IARC/////w+DfCIEQiCIfCEDIAIgBD4CFCADQiCIIQQgBCAFIAE1AhgiEX4gA0L/////D4N8IgNCIIh8IQQgBCAIIA9+IANC/////w+DfCIDQiCIfCEEIAQgCiANfiADQv////8Pg3wiA0IgiHwhBCAEIAsgDH4gA0L/////D4N8IgNCIIh8IQQgBCAJIA5+IANC/////w+DfCIDQiCIfCEEIAQgByAQfiADQv////8Pg3wiA0IgiHwhBCAEIAA1AhgiEiAGfiADQv////8Pg3wiA0IgiHwhBCACIAM+AhggBEIgiCEDIAMgBSABNQIcIhN+IARC/////w+DfCIEQiCIfCEDIAMgCCARfiAEQv////8Pg3wiBEIgiHwhAyADIAogD34gBEL/////D4N8IgRCIIh8IQMgAyAMIA1+IARC/////w+DfCIEQiCIfCEDIAMgCyAOfiAEQv////8Pg3wiBEIgiHwhAyADIAkgEH4gBEL/////D4N8IgRCIIh8IQMgAyAHIBJ+IARC/////w+DfCIEQiCIfCEDIAMgADUCHCIFIAZ+IARC/////w+DfCIEQiCIfCEDIAIgBD4CHCADQiCIIQQgBCAIIBN+IANC/////w+DfCIDQiCIfCEEIAQgCiARfiADQv////8Pg3wiA0IgiHwhBCAEIAwgD34gA0L/////D4N8IgNCIIh8IQQgBCANIA5+IANC/////w+DfCIDQiCIfCEEIAQgCyAQfiADQv////8Pg3wiA0IgiHwhBCAEIAkgEn4gA0L/////D4N8IgNCIIh8IQQgBCAFIAd+IANC/////w+DfCIDQiCIfCEEIAIgAz4CICAEQiCIIQMgAyAKIBN+IARC/////w+DfCIEQiCIfCEDIAMgDCARfiAEQv////8Pg3wiBEIgiHwhAyADIA4gD34gBEL/////D4N8IgRCIIh8IQMgAyANIBB+IARC/////w+DfCIEQiCIfCEDIAMgCyASfiAEQv////8Pg3wiBEIgiHwhAyADIAUgCX4gBEL/////D4N8IgRCIIh8IQMgAiAEPgIkIANCIIghBCAEIAwgE34gA0L/////D4N8IgNCIIh8IQQgBCAOIBF+IANC/////w+DfCIDQiCIfCEEIAQgDyAQfiADQv////8Pg3wiA0IgiHwhBCAEIA0gEn4gA0L/////D4N8IgNCIIh8IQQgBCAFIAt+IANC/////w+DfCIDQiCIfCEEIAIgAz4CKCAEQiCIIQMgAyAOIBN+IARC/////w+DfCIEQiCIfCEDIAMgECARfiAEQv////8Pg3wiBEIgiHwhAyADIA8gEn4gBEL/////D4N8IgRCIIh8IQMgAyAFIA1+IARC/////w+DfCIEQiCIfCEDIAIgBD4CLCADQiCIIQQgBCAQIBN+IANC/////w+DfCIDQiCIfCEEIAQgESASfiADQv////8Pg3wiA0IgiHwhBCAEIAUgD34gA0L/////D4N8IgNCIIh8IQQgAiADPgIwIARCIIghAyADIBIgE34gBEL/////D4N8IgRCIIh8IQMgAyAFIBF+IARC/////w+DfCIEQiCIfCEDIAIgBD4CNCADQiCIIQQgBCAFIBN+IANC/////w+DfCIDQiCIfCEEIAIgAz4COCACIAQ+AjwLzg0BDH4gAyAANQIAIgYgBn4gAkL/////D4N8IgJCIIh8IQMgASACPgIAIAMiBEIgiCEFIAA1AgQiByAGfiICQiCIQgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AgQgAyIEQiCIIQUgADUCCCIIIAZ+IgJCIIhCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAcgB34gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AgggAyIEQiCIIQUgADUCDCIJIAZ+IgJCIIghAyADIAcgCH4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AgwgAyIEQiCIIQUgADUCECIKIAZ+IgJCIIghAyADIAcgCX4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyAIIAh+IAJC/////w+DfCICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIQIAMiBEIgiCEFIAA1AhQiCyAGfiICQiCIIQMgAyAHIAp+IAJC/////w+DfCICQiCIfCEDIAMgCCAJfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CFCADIgRCIIghBSAANQIYIgwgBn4iAkIgiCEDIAMgByALfiACQv////8Pg3wiAkIgiHwhAyADIAggCn4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyAJIAl+IAJC/////w+DfCICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIYIAMiBEIgiCEFIAA1AhwiDSAGfiICQiCIIQMgAyAHIAx+IAJC/////w+DfCICQiCIfCEDIAMgCCALfiACQv////8Pg3wiAkIgiHwhAyADIAkgCn4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AhwgAyIEQiCIIQUgByANfiICQiCIIQMgAyAIIAx+IAJC/////w+DfCICQiCIfCEDIAMgCSALfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAogCn4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AiAgAyIEQiCIIQUgCCANfiICQiCIIQMgAyAJIAx+IAJC/////w+DfCICQiCIfCEDIAMgCiALfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CJCADIgRCIIghBSAJIA1+IgJCIIghAyADIAogDH4gAkL/////D4N8IgJCIIh8QgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyALIAt+IAJC/////w+DfCICQiCIfCEDIAMgAkL/////D4MgBEL/////D4N8IgJCIIh8IAV8IQMgASACPgIoIAMiBEIgiCEFIAogDX4iAkIgiCEDIAMgCyAMfiACQv////8Pg3wiAkIgiHxCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAJC/////w+DIARC/////w+DfCICQiCIfCAFfCEDIAEgAj4CLCADIgRCIIghBSALIA1+IgJCIIhCAYYgAkL/////D4NCAYYiAkIgiHwhAyADIAwgDH4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AjAgAyIEQiCIIQUgDCANfiICQiCIQgGGIAJC/////w+DQgGGIgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AjQgAyIEQiCIIQVCACECQgAhAyADIA0gDX4gAkL/////D4N8IgJCIIh8IQMgAyACQv////8PgyAEQv////8Pg3wiAkIgiHwgBXwhAyABIAI+AjggASADPgI8CwoAIAAgACABECwLsgMCA34BfyAAIANBiBggAxsiAxAkIAFByBcQJCACQegXIAIbIgcQJUGoGBAlQR8hAEEfIQEDQCABQcgXai0AACABQQNGckUEQCABQQFrIQEMAQsLIAFBxRdqNQAAQgF8IgZCAVEEQEIAQgCAGgsDQAJAA0AgACADai0AACAAQQdGckUEQCAAQQFrIQAMAQsLIAAgA2pBB2spAAAgBoAhBCAAIAFrQQRrIQIDQCAEQoCAgIBwg1AgAkEATnFFBEAgBEIIiCEEIAJBAWohAgwBCwsgBFAEQCADQcgXEClFDQFCASEEQQAhAgtByBhByBc1AAAgBH4iBT4AAEHMGEHMFzUAACAEfiAFQiCIfCIFPgAAQdAYQdAXNQAAIAR+IAVCIIh8IgU+AABB1BhB1Bc1AAAgBH4gBUIgiHwiBT4AAEHYGEHYFzUAACAEfiAFQiCIfCIFPgAAQdwYQdwXNQAAIAR+IAVCIIh8IgU+AABB4BhB4Bc1AAAgBH4gBUIgiHwiBT4AAEHkGEHkFzUAACAEfiAFQiCIfD4AACADQcgYIAJrIAMQKxogAiAHaiAEEAsMAQsLC44CAQp/QegYIQNB6BgQJUGIGSEIIAFBiBkQJEGoGSEJQagZECdByBkhBiAAQcgZECRB6BkhC0GIGiEKQegaIQQDQCAGECZFBEAgCCAGIAsgChAvIAsgCUGoGhAsIAcEfyAFBH9BqBogAxApBH9BqBogAyAEECsaQQAFIANBqBogBBArGkEBCwVBqBogAyAEECoaQQELBSAFBH9BqBogAyAEECoaQQAFIANBqBoQKQR/IANBqBogBBArGkEABUGoGiADIAQQKxpBAQsLCyEMIAMhACAJIQMgBCEJIAAhBCAFIQcgDCEFIAghACAGIQggCiEGIAAhCgwBCwsgBwRAIAEgAyACECsaBSADIAIQJAsLCQAgAEHIGxAoCywAIAAgASACECoEQCACQYgbIAIQKxoFIAJBiBsQKQRAIAJBiBsgAhArGgsLCxcAIAAgASACECsEQCACQYgbIAIQKhoLCwsAQegbIAAgARAzC7YPAQN+IAAgADUCAEL/////DyIEIAA1AgB+Qv////8PgyIDQYgbNQIAfnwiAj4CACAAIAA1AgQgAkIgiHxBjBs1AgAgA358IgI+AgQgACAANQIIIAJCIIh8QZAbNQIAIAN+fCICPgIIIAAgADUCDCACQiCIfEGUGzUCACADfnwiAj4CDCAAIAA1AhAgAkIgiHxBmBs1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QZwbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGgGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBpBs1AgAgA358IgI+AhxBqB0gAkIgiD4CACAAIAA1AgQgADUCBCAEfkL/////D4MiA0GIGzUCAH58IgI+AgQgACAANQIIIAJCIIh8QYwbNQIAIAN+fCICPgIIIAAgADUCDCACQiCIfEGQGzUCACADfnwiAj4CDCAAIAA1AhAgAkIgiHxBlBs1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QZgbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGcGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBoBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QaQbNQIAIAN+fCICPgIgQawdIAJCIIg+AgAgACAANQIIIAA1AgggBH5C/////w+DIgNBiBs1AgB+fCICPgIIIAAgADUCDCACQiCIfEGMGzUCACADfnwiAj4CDCAAIAA1AhAgAkIgiHxBkBs1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QZQbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGYGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBnBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QaAbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGkGzUCACADfnwiAj4CJEGwHSACQiCIPgIAIAAgADUCDCAANQIMIAR+Qv////8PgyIDQYgbNQIAfnwiAj4CDCAAIAA1AhAgAkIgiHxBjBs1AgAgA358IgI+AhAgACAANQIUIAJCIIh8QZAbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGUGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBmBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QZwbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGgGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBpBs1AgAgA358IgI+AihBtB0gAkIgiD4CACAAIAA1AhAgADUCECAEfkL/////D4MiA0GIGzUCAH58IgI+AhAgACAANQIUIAJCIIh8QYwbNQIAIAN+fCICPgIUIAAgADUCGCACQiCIfEGQGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBlBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QZgbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGcGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBoBs1AgAgA358IgI+AiggACAANQIsIAJCIIh8QaQbNQIAIAN+fCICPgIsQbgdIAJCIIg+AgAgACAANQIUIAA1AhQgBH5C/////w+DIgNBiBs1AgB+fCICPgIUIAAgADUCGCACQiCIfEGMGzUCACADfnwiAj4CGCAAIAA1AhwgAkIgiHxBkBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QZQbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGYGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBnBs1AgAgA358IgI+AiggACAANQIsIAJCIIh8QaAbNQIAIAN+fCICPgIsIAAgADUCMCACQiCIfEGkGzUCACADfnwiAj4CMEG8HSACQiCIPgIAIAAgADUCGCAANQIYIAR+Qv////8PgyIDQYgbNQIAfnwiAj4CGCAAIAA1AhwgAkIgiHxBjBs1AgAgA358IgI+AhwgACAANQIgIAJCIIh8QZAbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGUGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBmBs1AgAgA358IgI+AiggACAANQIsIAJCIIh8QZwbNQIAIAN+fCICPgIsIAAgADUCMCACQiCIfEGgGzUCACADfnwiAj4CMCAAIAA1AjQgAkIgiHxBpBs1AgAgA358IgI+AjRBwB0gAkIgiD4CACAAIAA1AhwgADUCHCAEfkL/////D4MiA0GIGzUCAH58IgI+AhwgACAANQIgIAJCIIh8QYwbNQIAIAN+fCICPgIgIAAgADUCJCACQiCIfEGQGzUCACADfnwiAj4CJCAAIAA1AiggAkIgiHxBlBs1AgAgA358IgI+AiggACAANQIsIAJCIIh8QZgbNQIAIAN+fCICPgIsIAAgADUCMCACQiCIfEGcGzUCACADfnwiAj4CMCAAIAA1AjQgAkIgiHxBoBs1AgAgA358IgI+AjQgACAANQI4IAJCIIh8QaQbNQIAIAN+fCICPgI4QcQdIAJCIIg+AgBBqB0gAEEgaiABEDILiBwBE34gBSABNQIAIgQgADUCACIOfnwiA0L/////D4MhBSAGIAA1AgQiDyAEfnwgA0IgiHwiA0L/////D4MhBiAHIAA1AggiECAEfnwgA0IgiHwiA0L/////D4MhByAIIAA1AgwiESAEfnwgA0IgiHwiA0L/////D4MhCCAJIAA1AhAiEiAEfnwgA0IgiHwiA0L/////D4MhCSAKIAA1AhQiEyAEfnwgA0IgiHwiA0L/////D4MhCiALIAA1AhgiFCAEfnwgA0IgiHwiA0L/////D4MhCyAMIAA1AhwiFSAEfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIEIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIIIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIMIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIQIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIUIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIYIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gBSAFQv////8PfkL/////D4MiBHxCIIggBiAEQv////8Pfnx8IgNC/////w+DIQUgByAEQv63+f8PfnwgA0IgiHwiA0L/////D4MhBiAIIARCgsj2nQV+fCADQiCIfCIDQv////8PgyEHIAkgBEKFsIfNAH58IANCIIh8IgNC/////w+DIQggCiAEQoiw55kDfnwgA0IgiHwiA0L/////D4MhCSALIARCyPr1zAJ+fCADQiCIfCIDQv////8PgyEKIAwgBELTzrafB358IANCIIh8IgNC/////w+DIQsgDSADQiCIfCEMIAUgDiABNQIcIgR+fCIDQv////8PgyEFIAYgBCAPfnwgA0IgiHwiA0L/////D4MhBiAHIAQgEH58IANCIIh8IgNC/////w+DIQcgCCAEIBF+fCADQiCIfCIDQv////8PgyEIIAkgBCASfnwgA0IgiHwiA0L/////D4MhCSAKIAQgE358IANCIIh8IgNC/////w+DIQogCyAEIBR+fCADQiCIfCIDQv////8PgyELIAwgBCAVfnwgA0IgiHwiA0L/////D4MhDCADQiCIIQ0gAiAFIAVC/////w9+Qv////8PgyIEfEIgiCAGIARC/////w9+fHwiA0L/////D4M+AgAgAiAHIARC/rf5/w9+fCADQiCIfCIDQv////8Pgz4CBCACIAggBEKCyPadBX58IANCIIh8IgNC/////w+DPgIIIAIgCSAEQoWwh80AfnwgA0IgiHwiA0L/////D4M+AgwgAiAKIARCiLDnmQN+fCADQiCIfCIDQv////8Pgz4CECACIAsgBELI+vXMAn58IANCIIh8IgNC/////w+DPgIUIAIgDCAEQtPOtp8HfnwgA0IgiHwiA0L/////D4M+AhggAiANIANCIIh8PgIcIAJBiBsQKQRAIAJBiBsgAhArGgsLsB0BE34gCCAANQIAIg0gDX58IgJC/////w+DIQggDCAANQIEIg8gDX4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQwgA0IgiEIBhiACQiCIfCALIAA1AggiECANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAKIAA1AgwiESANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQogA0IgiEIBhiACQiCIfCAJIAA1AhAiEiANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQkgA0IgiEIBhiACQiCIfCAHIAA1AhQiEyANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIAA1AhgiFCANfiIDQv////8Pg0IBhnx8IgJC/////w+DIQYgA0IgiEIBhiACQiCIfCAEIA0gADUCHCINfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIA4gAkIgiHwhDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAwgDyAPfnwiAkL/////D4MhDCALIA8gEH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQsgA0IgiEIBhiACQiCIfCAKIA8gEX4iA0L/////D4NCAYZ8fCICQv////8PgyEKIANCIIhCAYYgAkIgiHwgCSAPIBJ+IgNC/////w+DQgGGfHwiAkL/////D4MhCSADQiCIQgGGIAJCIIh8IAcgDyATfiIDQv////8Pg0IBhnx8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIA8gFH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCANIA9+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCEOIAggCEL/////D35C/////w+DIgN8QiCIIAwgA0L/////D358fCICQv////8PgyEIIAsgA0L+t/n/D358IAJCIIh8IgJC/////w+DIQwgCiADQoLI9p0FfnwgAkIgiHwiAkL/////D4MhCyAJIANChbCHzQB+fCACQiCIfCICQv////8PgyEKIAcgA0KIsOeZA358IAJCIIh8IgJC/////w+DIQkgBiADQsj69cwCfnwgAkIgiHwiAkL/////D4MhByAEIANC0862nwd+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCAOIAJCIIh8IQUgCyAQIBB+fCICQv////8PgyELIAogECARfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhCiADQiCIQgGGIAJCIIh8IAkgECASfiIDQv////8Pg0IBhnx8IgJC/////w+DIQkgA0IgiEIBhiACQiCIfCAHIBAgE34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiAQIBR+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgDSAQfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAogESARfnwiAkL/////D4MhCiAJIBEgEn4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQkgA0IgiEIBhiACQiCIfCAHIBEgE34iA0L/////D4NCAYZ8fCICQv////8PgyEHIANCIIhCAYYgAkIgiHwgBiARIBR+IgNC/////w+DQgGGfHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgDSARfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAkgEiASfnwiAkL/////D4MhCSAHIBIgE34iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQcgA0IgiEIBhiACQiCIfCAGIBIgFH4iA0L/////D4NCAYZ8fCICQv////8PgyEGIANCIIhCAYYgAkIgiHwgBCANIBJ+IgNC/////w+DQgGGfHwiAkL/////D4MhBCAFIANCIIhCAYYgAkIgiHx8IgJC/////w+DIQUgAkIgiCEOIAggCEL/////D35C/////w+DIgN8QiCIIAwgA0L/////D358fCICQv////8PgyEIIAsgA0L+t/n/D358IAJCIIh8IgJC/////w+DIQwgCiADQoLI9p0FfnwgAkIgiHwiAkL/////D4MhCyAJIANChbCHzQB+fCACQiCIfCICQv////8PgyEKIAcgA0KIsOeZA358IAJCIIh8IgJC/////w+DIQkgBiADQsj69cwCfnwgAkIgiHwiAkL/////D4MhByAEIANC0862nwd+fCACQiCIfCICQv////8PgyEGIAUgAkIgiHwiAkL/////D4MhBCAOIAJCIIh8IQUgByATIBN+fCICQv////8PgyEHIAYgEyAUfiIDQv////8Pg0IBhnwgAkIgiHwiAkL/////D4MhBiADQiCIQgGGIAJCIIh8IAQgDSATfiIDQv////8Pg0IBhnx8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAYgFCAUfnwiAkL/////D4MhBiAEIA0gFH4iA0L/////D4NCAYZ8IAJCIIh8IgJC/////w+DIQQgBSADQiCIQgGGIAJCIIh8fCICQv////8PgyEFIAJCIIghDiAIIAhC/////w9+Qv////8PgyIDfEIgiCAMIANC/////w9+fHwiAkL/////D4MhCCALIANC/rf5/w9+fCACQiCIfCICQv////8PgyEMIAogA0KCyPadBX58IAJCIIh8IgJC/////w+DIQsgCSADQoWwh80AfnwgAkIgiHwiAkL/////D4MhCiAHIANCiLDnmQN+fCACQiCIfCICQv////8PgyEJIAYgA0LI+vXMAn58IAJCIIh8IgJC/////w+DIQcgBCADQtPOtp8HfnwgAkIgiHwiAkL/////D4MhBiAFIAJCIIh8IgJC/////w+DIQQgDiACQiCIfCEFIAQgDSANfnwiAkL/////D4MhBCAFIAJCIIh8IgJC/////w+DIQUgAkIgiCEOIAEgCCAIQv////8PfkL/////D4MiA3xCIIggDCADQv////8Pfnx8IgJC/////w+DPgIAIAEgCyADQv63+f8PfnwgAkIgiHwiAkL/////D4M+AgQgASAKIANCgsj2nQV+fCACQiCIfCICQv////8Pgz4CCCABIAkgA0KFsIfNAH58IAJCIIh8IgJC/////w+DPgIMIAEgByADQoiw55kDfnwgAkIgiHwiAkL/////D4M+AhAgASAGIANCyPr1zAJ+fCACQiCIfCICQv////8Pgz4CFCABIAQgA0LTzrafB358IAJCIIh8IgJC/////w+DPgIYIAEgBSACQiCIfCICQv////8Pgz4CHCAOIAJCIIh8pwRAIAFBiBsgARArGgUgAUGIGxApBEAgAUGIGyABECsaCwsLCgAgACAAIAEQNgsLACAAQagbIAEQNgsVACAAQaghECRByCEQJUGoISABEDULEQAgAEHoIRA6QeghQagcECkLIwAgABAmBEBBAA8LIABBiCIQOkGIIkGoHBApBEBBfw8LQQELFwAgACABEDogAUGIGyABEDAgASABEDkLCQBByBsgABAkC7wBAQJ/IAIQJUEgIQMDQCABIANPBEAgA0EgRgRAQagiED4FQagiQagbQagiEDYLIABBqCJByCIQNiACQcgiIAIQMiAAQSBqIQAgA0EgaiEDDAELCyABQR9xIgRFBEAPC0HIIhAlQQAhAQNAIAEgBEZFBEAgASAALQAAOgDIIiAAQQFqIQAgAUEBaiEBDAELCyADQSBGBEBBqCIQPgVBqCJBqBtBqCIQNgtByCJBqCJByCIQNiACQcgiIAIQMgscACABIAJB6CIQP0HoIkHoIhA5IABB6CIgAxA2C+EBAQJ/QQBBACgCACIFIAJBAWpBBXRqNgIAIAUQPiAFQSBqIQUDQCACIAZHBEAgABAmBEAgBUEgayAFECQFIAAgBUEgayAFEDYLIAAgAWohACAFQSBqIQUgBkEBaiEGDAELCyAAIAFrIQAgAyACQQFrIARsaiECIAVBIGsiBSAFED0DQCAGBEAgABAmBEAgBSAFQSBrECQgAhAlBSAFQSBrQYgjECQgBSAAIAVBIGsQNiAFQYgjIAIQNgsgACABayEAIAIgBGshAiAFQSBrIQUgBkEBayEGDAELC0EAIAU2AgALLQEBfwNAIAEgA0ZFBEAgACACEDkgAEEgaiEAIAJBIGohAiADQQFqIQMMAQsLCy0BAX8DQCABIANGRQRAIAAgAhA6IABBIGohACACQSBqIQIgA0EBaiEDDAELCwuXAgAgAkUEQCADED4PCyAAQagjECQgAxA+A0AgAkEBayICIAFqLQAAIQAgAyADEDcgAEGAAU8EQCADQagjIAMQNiAAQYABayEACyADIAMQNyAAQcAATwRAIANBqCMgAxA2IABBQGohAAsgAyADEDcgAEEgTwRAIANBqCMgAxA2IABBIGshAAsgAyADEDcgAEEQTwRAIANBqCMgAxA2IABBEGshAAsgAyADEDcgAEEITwRAIANBqCMgAxA2IABBCGshAAsgAyADEDcgAEEETwRAIANBqCMgAxA2IABBBGshAAsgAyADEDcgAEECTwRAIANBqCMgAxA2IABBAmshAAsgAyADEDcgAARAIANBqCMgAxA2CyACDQALC9UBAQF/IAAQJgRAIAEQJQ8LQSAhAkHoHEHIIxAkIABByBxBIEHoIxBEIABBiB1BIEGIJBBEA0BB6CNByBsQKEUEQEHoI0GoJBA3QQEhAANAQagkQcgbEChFBEBBqCRBqCQQNyAAQQFqIQAMAQsLQcgjQcgkECQgAiAAa0EBayECA0AgAgRAQcgkQcgkEDcgAkEBayECDAELCyAAIQJByCRByCMQN0HoI0HII0HoIxA2QYgkQcgkQYgkEDYMAQsLQYgkEDsEQEGIJCABEDQFQYgkIAEQJAsLIAAgABAmBEBBAQ8LIABBiBxBIEHoJBBEQegkQcgbECgLFQAgACABQYglEDZBiCVBqBsgAhA2CwoAIAAgACABEEcLCwAgAEGIGyABEDALCQAgAEGoHBApCw4AIAAQAiAAQTBqEAJxCwoAIABB4ABqEAILDQAgABABIABBMGoQAQsVACAAEAEgAEEwahAbIABB4ABqEAELegAgASAAKQMANwMAIAEgACkDCDcDCCABIAApAxA3AxAgASAAKQMYNwMYIAEgACkDIDcDICABIAApAyg3AyggASAAKQMwNwMwIAEgACkDODcDOCABIAApA0A3A0AgASAAKQNINwNIIAEgACkDUDcDUCABIAApA1g3A1gLugEAIAEgACkDADcDACABIAApAwg3AwggASAAKQMQNwMQIAEgACkDGDcDGCABIAApAyA3AyAgASAAKQMoNwMoIAEgACkDMDcDMCABIAApAzg3AzggASAAKQNANwNAIAEgACkDSDcDSCABIAApA1A3A1AgASAAKQNYNwNYIAEgACkDYDcDYCABIAApA2g3A2ggASAAKQNwNwNwIAEgACkDeDcDeCABIAApA4ABNwOAASABIAApA4gBNwOIAQsoACAAEEsEQCABEE4FIAFB4ABqEBsgAEEwaiABQTBqEAAgACABEAALCxUAIAAgARAEIABBMGogAUEwahAEcQtyAQF/IAAQTARAIAEQSw8LIAEQSwRAQQAPCyAAQeAAaiICEA4EQCAAIAEQUg8LIAJB2CUQFCABQdglQYgmEBMgAkHYJUG4JhATIAFBMGpBuCZB6CYQEyAAQYgmEAQEQCAAQTBqQegmEAQE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AEEwaiABQTBqEBELIgAgACABEAAgAEEwaiABQTBqEBEgAEHgAGogAUHgAGoQAAsSACABQeg+EFogAEHoPiACEFcLEgAgAUH4PxBaIABB+D8gAhBYCxQAIAFBiMEAEFsgAEGIwQAgAhBZCxQAIAAgARAXIABBMGogAUEwahAXCyIAIAAgARAXIABBMGogAUEwahAXIABB4ABqIAFB4ABqEBcLFAAgACABEBYgAEEwaiABQTBqEBYLIgAgACABEBYgAEEwaiABQTBqEBYgAEHgAGogAUHgAGoQFgtTACAAEEwEQCABEAEgAUEwahABBSAAQeAAakGYwgAQGkGYwgBByMIAEBRBmMIAQcjCAEH4wgAQEyAAQcjCACABEBMgAEEwakH4wgAgAUEwahATCws4ACAAQTBqQajDABAUIABB2MMAEBQgAEHYwwBB2MMAEBNB2MMAQaglQdjDABAPQajDAEHYwwAQBAsQACAAQYjEABBjQYjEABBkC5gBAQN/QQBBACgCACIEIAFBMGxqNgIAIABB4ABqQZABIAEgBEEwEB4gBCEDA0AgASAFRwRAIAMQAgRAIAIQASACQTBqEAEFIAMgAEEwakHoxAAQEyADIAMQFCADIAAgAhATIANB6MQAIAJBMGoQEwsgAEGQAWohACACQeAAaiECIANBMGohAyAFQQFqIQUMAQsLQQAgBDYCAAtUACAAEEwEQCABEE4FIABB4ABqQZjFABAaQZjFAEHIxQAQFEGYxQBByMUAQfjFABATIABByMUAIAEQEyAAQTBqQfjFACABQTBqEBMgAUHgAGoQGwsLMgAgASACakEBayEBA0AgASACSEUEQCABIAAtAAA6AAAgAUEBayEBIABBAWohAAwBCwsLLQAgABBLBEAgARBNDwsgAEGoxgAQX0GoxgBBMCABEGhB2MYAQTAgAUEwahBoC0MAIAAQSwRAIAEQASABQcAAOgAADwsgAEGIxwAQF0GIxwBBMCABEGggAEEwahAZQX9GBEAgASABLQAAQYABcjoAAAsLMgAgAC0AAEHAAHEEQCABEE0PCyAAQTBBuMcAEGggAEEwakEwQejHABBoQbjHACABEGELwQEBAn8gAC0AACICQcAAcQRAIAEQTQ8LIAJBgAFxIQMgAEHIyAAQAEHIyAAgAkE/cToAAEHIyABBMEGYyAAQaEGYyAAg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A2g3A2ggASAAKQNwNwNwIAEgACkDeDcDeCABIAApA4ABNwOAASABIAApA4gBNwOIASABIAApA5ABNwOQASABIAApA5gBNwOYASABIAApA6ABNwOgASABIAApA6gBNwOoASABIAApA7ABNwOwASABIAApA7gBNwO4AQuSAwAgASAAKQMANwMAIAEgACkDCDcDCCABIAApAxA3AxAgASAAKQMYNwMYIAEgACkDIDcDICABIAApAyg3AyggASAAKQMwNwMwIAEgACkDODcDOCABIAApA0A3A0AgASAAKQNINwNIIAEgACkDUDcDUCABIAApA1g3A1ggASAAKQNgNwNgIAEgACkDaDcDaCABIAApA3A3A3AgASAAKQN4NwN4IAEgACkDgAE3A4ABIAEgACkDiAE3A4gBIAEgACkDkAE3A5ABIAEgACkDmAE3A5gBIAEgACkDoAE3A6ABIAEgACkDqAE3A6gBIAEgACkDsAE3A7ABIAEgACkDuAE3A7gBIAEgACkDwAE3A8ABIAEgACkDyAE3A8gBIAEgACkD0AE3A9ABIAEgACkD2AE3A9gBIAEgACkD4AE3A+ABIAEgACkD6AE3A+gBIAEgACkD8AE3A/ABIAEgACkD+AE3A/gBIAEgACkDgAI3A4ACIAEgACkDiAI3A4gCIAEgACkDkAI3A5ACIAEgACkDmAI3A5gCCy8AIAAQmwEEQCABEJ4BBSABQcABahCLASAAQeAAaiABQeAAahCMASAAIAEQjAELCxcAIAAgARBSIABB4ABqIAFB4ABqEFJxC4YBAQF/IAAQnAEEQCABEJsBDwsgARCbAQRAQQAPCyAAQcABaiICEIoBBEAgACABEKIBDwsgAkHYhwEQjwEgAUHYhwFBuIgBEI0BIAJB2IcBQZiJARCNASABQeAAakGYiQFB+IkBEI0BIABBuIgBEFIEQCAAQeAAakH4iQEQUgRAQQEPCwtBAAvQAQECfyAAEJwBBEAgARCcAQ8LIAEQnAEEQEEADwsgAEHAAWoiAhCKAQRAIAEgABCjAQ8LIAFBwAFqIgMQigEEQCAAIAEQowEPCyACQdiKARCPASADQbiLARCPASAAQbiLAUGYjAEQjQEgAUHYigFB+IwBEI0BIAJB2IoBQdiNARCNASADQbiLAUG4jgEQjQEgAEHgAGpBuI4BQZiPARCNASABQeAA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AEHgAGoQTSAAQcABahBNCycAIAAgARCMASAAQeAAaiABQeAAahCMASAAQcABaiABQcABahCMAQvlAgAgACABQYjcAhCNASAAQeAAaiABQeAAakHo3AIQjQEgAEHAAWogAUHAAWpByN0CEI0BIAAgAEHgAGpBqN4CEJABIAEgAUHgAGpBiN8CEJABIAAgAEHAAWpB6N8CEJABIAEgAUHAAWpByOACEJABIABB4ABqIABBwAFqQajhAhCQASABQeAAaiABQcABakGI4gIQkAFBiNwCQejcAkHo4gIQkAFBiNwCQcjdAkHI4wIQkAFB6NwCQcjdAkGo5AIQkAFBqOECQYjiAiACEI0BIAJBqOQCIAIQkQEgAiACEOQBQYjcAiACIAIQkAFBqN4CQYjfAiACQeAAahCNASACQeAAakHo4gIgAkHgAGoQkQFByN0CQYjlAhDkASACQeAAakGI5QIgAkHgAGoQkAFB6N8CQcjgAiACQcABahCNASACQcABakHI4wIgAkHAAWoQkQEgAkHAAWpB6NwCIAJBwAFqEJABC4ECACAAQejlAhCPASAAIABB4ABqQcjmAhCNAUHI5gJByOYCQajnAhCQASAAIABB4ABqQYjoAhCRAUGI6AIgAEHAAWpBiOgCEJABQYjoAkGI6AIQjwEgAEHgAGogAEHAAWpB6OgCEI0BQejoAkHo6AJByOkCEJABIABBwAFqQajqAhCPAUHI6QIgARDkAUHo5QIgASABEJABQajqAiABQeAAahDkAUGo5wIgAUHgAGogAUHgAGoQkAFB6OUCQajqAiABQcABahCQAUHI6QIgAUHAAWogAUHAAWoQkQFBiOgCIAFBwAFqIAFBwAFqEJABQajnAiABQcABaiABQcABahCQAQs1ACAAIAEgAhCQASAAQeAAaiABQeAAaiACQeAAahCQASAAQcABaiABQcABaiACQcABahCQAQs1ACAAIAEgAhCRASAAQeAAaiABQeAAaiACQeAAahCRASAAQcABaiABQcABaiACQcABahCRAQsnACAAIAEQkgEgAEHgAGogAUHgAGoQkgEgAEHAAWogAUHAAWoQkgELKwEBfyAAQcABahCVASIBBEAgAQ8LIABB4ABqEJUBIgEEQCABDwsgABCVAQsmACAAIAEQUiAAQeAAaiABQeAAahBScSAAQcABaiABQcABahBScQurAgAgAEGI6wIQjwEgAEHgAGpB6OsCEI8BIABBwAFqQcjsAhCPASAAIABB4ABqQajtAhCNASAAIABBwAFqQYjuAhCNASAAQeAAaiAAQcABakHo7gIQjQFB6O4CQcjvAhDkAUGI6wJByO8CQcjvAhCRAUHI7AJBqPACEOQBQajwAkGo7QJBqPACEJEBQejrAkGI7gJBiPECEJEBIABBwAFqQajwAkHo8QIQjQEgAEHgAGpBiPECQcjyAhCNAUHo8QJByPICQejxAhCQAUHo8QJB6PECEOQBIABByO8CQcjyAhCNAUHI8gJB6PECQejxAhCQAUHo8QJB6PECEJMBQejxAkHI7wIgARCNAUHo8QJBqPACIAFB4ABqEI0BQejxAkGI8QIgAUHAAWoQjQELMwAgACABIAIgAxCUASAAQeAAaiABIAIgA0HgAGoQlAEgAEHAAWogASACIANBwAFqEJQBCysAIABBwAFqEEsEQCAAIABB4ABqIABB4ABqEEsbEJYBDwsgAEHAAWoQlgEL+AEBAn9BAEEAKAIAIgUgAkEBakGgAmxqNgIAIAUQ6AEgBUGgAmohBQNAIAIgBkcEQCAAEOUBBEAgBUGgAmsgBRDpAQUgACAFQaACayAFEOoBCyAAIAFqIQAgBUGgAmohBSAGQQFqIQYMAQsLIAAgAWshACADIAJBAWsgBGxqIQIgBUGgAmsiBSAFEPEBA0AgBgRAIAAQ5QEEQCAFIAVBoAJrEOkBIAIQ5wEFIAVBoAJrQajzAhDpASAFIAAgBUGgAmsQ6gEgBUGo8wIgAhDqAQsgACABayEAIAIgBGshAiAFQaACayEFIAZBAWshBgwBCwtBACAFNgIAC7MCACACRQRAIAMQ6AEPCyAAQcj1AhDpASADEOgBA0AgAkEBayICIAFqLQAAIQAgAyADEOsBIABBgAFPBEAgA0HI9QIgAxDqASAAQYABayEACyADIAMQ6wEgAEHAAE8EQCADQcj1AiADEOoBIABBQGohAAsgAyADEOsBIABBIE8EQCADQcj1AiADEOoBIABBIGshAAsgAyADEOsBIABBEE8EQCADQcj1AiADEOoBIABBEGshAAsgAyADEOsBIABBCE8EQCADQcj1AiADEOoBIABBCGshAAsgAyADEOsBIABBBE8EQCADQcj1AiADEOoBIABBBGshAAsgAyADEOsBIABBAk8EQCADQcj1AiADEOoBIABBAmshAAsgAyADEOsBIAAEQCADQcj1AiADEOoBCyACDQALCzIAIABB6PcCEIwBIABBwAFqIAEQ5AEgAEHgAGogAUHAAWoQjAFB6PcCIAFB4ABqEIwBCxEAIAAQ5QEgAEGgAmoQ5QFxCxEAIAAQ5gEgAEGgAmoQ5QFxCxAAIAAQ5wEgAEGgAmoQ5wELEAAgABDoASAAQaACahDnAQsYACAAIAEQ6QEgAEGgAmogAUGgAmoQ6QELhQEAIAAgAUHI+AIQ6gEgAEGgAmogAUGgAmpB6PoCEOoBIAAgAEGgAmpBiP0CEOwBIAEgAUGgAmpBqP8CEOwBQYj9AkGo/wJBiP0CEOoBQej6AiACEPYBQcj4AiACIAIQ7AFByPgCQej6AiACQaACahDsAUGI/QIgAkGgAmogAkGgAmoQ7QELHAAgACABIAIQ6gEgAEGgAmogASACQaACahDqAQt9ACAAIABBoAJqQciBAxDqASAAIABBoAJqQeiDAxDsASAAQaACakGIhgMQ9gEgAEGIhgNBiIYDEOwBQciBA0GoiAMQ9gFBqIgDQciBA0GoiAMQ7AFB6IMDQYiGAyABEOoBIAFBqIgDIAEQ7QFByIEDQciBAyABQaACahDsAQsgACAAIAEgAhDsASAAQaACaiABQaACaiACQaACahDsAQsgACAAIAEgAhDtASAAQaACaiABQaACaiACQaACahDtAQsYACAAIAEQ7gEgAEGgAmogAUGgAmoQ7gELGAAgACABEOkBIABBoAJqIAFBoAJqEO4BCxgAIAAgARCyASAAQaACaiABQaACahCyAQsYACAAIAEQsAEgAEGgAmogAUGgAmoQsAELGQAgACABEPABIABBoAJqIAFBoAJqEPABcQtqACAAQciKAxDrASAAQaACakHojAMQ6wFB6IwDQYiPAxD2AUHIigNBiI8DQYiPAxDtAUGIjwNBqJEDEPEBIABBqJEDIAEQ6gEgAEGgAmpBqJEDIAFBoAJqEOoBIAFBoAJqIAFBoAJqEO4BCyAAIAAgASACIAMQ8gEgAEGgAmogASACIANBoAJqEPIBCxoBAX8gAEGgAmoQ7wEiAQRAIAEPCyAAEO8BCx0AIABBoAJqEOUBBEAgABDzAQ8LIABBoAJqEPMBC/gBAQJ/QQBBACgCACIFIAJBAWpBwARsajYCACAFEPoBIAVBwARqIQUDQCACIAZHBEAgABD3AQRAIAVBwARrIAUQ+wEFIAAgBUHABGsgBRD8AQsgACABaiEAIAVBwARqIQUgBkEBaiEGDAELCyAAIAFrIQAgAyACQQFrIARsaiECIAVBwARrIgUgBRCGAgNAIAYEQCAAEPcBBEAgBSAFQcAEaxD7ASACEPkBBSAFQcAEa0HIkwMQ+wEgBSAAIAVBwARrEPwBIAVByJMDIAIQ/AELIAAgAWshACACIARrIQIgBUHABGshBSAGQQFrIQYMAQsLQQAgBTYCAAuzAgAgAkUEQCADEPoBDwsgAEGImAMQ+wEgAxD6AQNAIAJBAWsiAiABai0AACEAIAMgAxD+ASAAQYABTwRAIANBiJgDIAMQ/AEgAEGAAWshAAsgAyADEP4BIABBwABPBEAgA0GImAMgAxD8ASAAQUBqIQALIAMgAxD+ASAAQSBPBEAgA0GImAMgAxD8ASAAQSBrIQALIAMgAxD+ASAAQRBPBEAgA0GImAMgAxD8ASAAQRBrIQALIAMgAxD+ASAAQQhPBEAgA0GImAMgAxD8ASAAQQhrIQALIAMgAxD+ASAAQQRPBEAgA0GImAMgAxD8ASAAQQRrIQALIAMgAxD+ASAAQQJPBEAgA0GImAMgAxD8ASAAQQJrIQALIAMgAxD+ASAABEAgA0GImAMgAxD8AQsgAg0ACwvRAQBByK4DEPoBQciuA0HIrgMQgQIgAEHInANBoAJBiKEDEIsCQYihA0HIpQMQ/gEgAEHIpQNByKUDEPwBQcilA0GIqgMQggJBiKoDQcilA0GIqgMQ/AFBiKoDQciuAxCFAgRAAAtBiKEDIABBiLMDEPwBQcilA0HIrgMQhQIEQEHIrgMQ5wFB6LADEOgBQciuA0GIswMgARD8AQVByLcDEPoBQci3A0HIpQNByLcDEP8BQci3A0HongNBoAJByLcDEIsCQci3A0GIswMgARD8AQsLaQBB6MsDEPoBQejLA0HoywMQgQIgAEGIvANBoAJBqL4DEIsCQai+A0HowgMQ/gEgAEHowgNB6MIDEPwBQejCA0GoxwMQggJBqMcDQejCA0GoxwMQ/AFBqMcDQejLAxCFAgRAQQAPC0EBC3gAIAAgAEHgAGpB6NADEJABIABB4ABqIABBwAFqQcjRAxCQASAAQeAAaiABIAJBwAFqEI0BQcjRAyABIAIQjQEgAiACQcABaiACEJEBIAIgAhDkAUHo0AMgASACQeAAahCNASACQeAAaiACQcABaiACQeAAahCRAQvsAQAgACABQajSAxCNASAAQeAAaiACQYjTAxCNASAAIABB4ABqQejTAxCQASAAIABBwAFqQcjUAxCQASAAQeAAaiAAQcABaiADEJABIAMgAiADEI0BIANBiNMDIAMQkQEgAyADEOQBIANBqNIDIAMQkAEgASACIANB4ABqEJABIANB4ABqQejTAyADQeAAahCNASADQeAAakGo0gMgA0HgAGoQkQEgA0HgAGpBiNMDIANB4ABqEJEBQcjUAyABIANBwAFqEI0BIANBwAFqQajSAyADQcABahCRASADQcABakGI0wMgA0HAAWoQkAELkAEAIAAgASACQajVAxCPAiAAQaACaiADQcjXAxCOAiACIANB6NkDEJABIABBoAJqIAAgBEGgAmoQ7AEgBEGgAmogAUHo2QMgBEGgAmoQjwIgBEGgAmpBqNUDIARBoAJqEO0BIARBoAJqQcjXAyAEQaACahDtAUHI1wMgBBDpASAEIAQQ9gEgBEGo1QMgBBDsAQtQACABIABBMGpByNoDEBMgAUEwaiAAQTBqQfjaAxATIAFB4ABqIABBqNsDEBMgAUGQAWogAEHY2wMQEyACIAFBwAFqQajbA0HI2gMgAhCQAgtsACAAQYj+BCABEI0BIABB4ABqQej+BCABQeAAahCNASAAQcABakHI/wQgAUHAAWoQjQEgAEGgAmpBqIAFIAFBoAJqEI0BIABBgANqQYiBBSABQYADahCNASAAQeADakHogQUgAUHgA2oQjQELigIAIAAgARAAIABBMGogAUEwahARIAFByIIFIAEQjQEgAEHgAGogAUHgAGoQACAAQZABaiABQZABahARIAFB4ABqQaiDBSABQeAAahCNASAAQcABaiABQcABahAAIABB8AFqIAFB8AFqEBEgAUHAAWpBiIQFIAFBwAFqEI0BIABBoAJqIAFBoAJqEAAgAEHQAmogAUHQAmoQESABQaACakHohAUgAUGgAmoQjQEgAEGAA2ogAUGAA2oQACAAQbADaiABQbADahARIAFBgANqQciFBSABQYADahCNASAAQeADaiABQeADahAAIABBkARqIAFBkARqEBEgAUHgA2pBqIYFIAFB4ANqEI0BC2wAIABBiIcFIAEQjQEgAEHgAGpB6IcFIAFB4ABqEI0BIABBwAFqQciIBSABQcABahCNASAAQaACakGoiQUgAUGgAmoQjQEgAEGAA2pBiIoFIAFBgANqEI0BIABB4ANqQeiKBSABQeADahCNAQuKAgAgACABEAAgAEEwaiABQTBqEBEgAUHIiwUgARCNASAAQeAAaiABQeAAahAAIABBkAFqIAFBkAFqEBEgAUHgAGpBqIwFIAFB4ABqEI0BIABBwAFqIAFBwAFqEAAgAEHwAWogAUHwAWoQESABQcABakGIjQUgAUHAAWoQjQEgAEGgAmogAUGgAmoQACAAQdACaiABQdACahARIAFBoAJqQeiNBSABQaACahCNASAAQYADaiABQYADahAAIABBsANqIAFBsANqEBEgAUGAA2pByI4FIAFBgANqEI0BIABB4ANqIAFB4ANqEAAgAEGQBGogAUGQBGoQESABQeADakGojwUgAUHgA2oQjQELbAAgAEGIkAUgARCNASAAQeAAakHokAUgAUHgAGoQjQEgAEHAAWpByJEFIAFBwAFqEI0BIABBoAJqQaiSBSABQaACahCNASAAQYADakGIkwUgAUGAA2oQjQEgAEHgA2pB6JMFIAFB4ANqEI0BC4oCACAAIAEQACAAQTBqIAFBMGoQESABQciUBSABEI0BIABB4ABqIAFB4ABqEAAgAEGQAWogAUGQAWoQESABQeAAakGolQUgAUHgAGoQjQEgAEHAAWogAUHAAWoQACAAQfABaiABQfABahARIAFBwAFqQYiWBSABQcABahCNASAAQaACaiABQaACahAAIABB0AJqIAFB0AJqEBEgAUGgAmpB6JYFIAFBoAJqEI0BIABBgANqIAFBgANqEAAgAEGwA2ogAUGwA2oQESABQYADakHIlwUgAUGAA2oQjQEgAEHgA2ogAUHgA2oQACAAQZAEaiABQZAEahARIAFB4ANqQaiYBSABQeADahCNAQtsACAAQYiZBSABEI0BIABB4ABqQeiZBSABQeAAahCNASAAQcABakHImgUgAUHAAWoQjQEgAEGgAmpBqJsFIAFBoAJqEI0BIABBgANqQYicBSABQYADahCNASAAQeADakHonAUgAUHgA2oQjQELigIAIAAgARAAIABBMGogAUEwahARIAFByJ0FIAEQjQEgAEHgAGogAUHgAGoQACAAQZABaiABQZABahARIAFB4ABqQaieBSABQeAAahCNASAAQcABaiABQcABahAAIABB8AFqIAFB8AFqEBEgAUHAAWpBiJ8FIAFBwAFqEI0BIABBoAJqIAFBoAJqEAAgAEHQAmogAUHQAmoQESABQaACakHonwUgAUGgAmoQjQEgAEGAA2ogAUGAA2oQACAAQbADaiABQbADahARIAFBgANqQcigBSABQYADahCNASAAQeADaiABQeADahAAIABBkARqIAFBkARqEBEgAUHgA2pBqKEFIAFB4ANqEI0BC2wAIABBiKIFIAEQjQEgAEHgAGpB6KIFIAFB4ABqEI0BIABBwAFqQcijBSABQcABahCNASAAQaACakGopAUgAUGgAmoQjQEgAEGAA2pBiKUFIAFBgANqEI0BIABB4ANqQeilBSABQeADahCNAQuKAgAgACABEAAgAEEwaiABQTBqEBEgAUHIpgUgARCNASAAQeAAaiABQeAAahAAIABBkAFqIAFBkAFqEBEgAUHgAGpBqKcFIAFB4ABqEI0BIABBwAFqIAFBwAFqEAAgAEHwAWogAUHwAWoQESABQcABakGIqAUgAUHAAWoQjQEgAEGgAmogAUGgAmoQACAAQdACaiABQdACahARIAFBoAJqQeioBSABQaACahCNASAAQYADaiABQYADahAAIABBsANqIAFBsANqEBEgAUGAA2pByKkFIAFBgANqEI0BIABB4ANqIAFB4ANqEAAgAEGQBGogAUGQBGoQESABQeADakGoqgUgAUHgA2oQjQELgwEAIAAQSwRAQQEPCyAAEGRFBEBBAA8LIABBiKsFQfirBRATIABBMGpBqKwFEAAgAEG4qwVBiK0FEBMgAEEwakG4rQUQAEH4qwVB+KsFEFVB+KsFIABB+KsFEF1B+KsFQYitBUH4qwUQXUH4qwVB6KsFQRBB+KsFEHhB+KsFQYitBRBTCxEAIABB6K0FEGNB6K0FEJwCC7MCACAAEJsBBEBBAQ8LIAAQtAFFBEBBAA8LIABByK4FQfCwBRCNASAAQeAAakHIrgVB0LEFEI0BQfCwBUGorwVBsLIFEI4BQdCxBUGQswUQkgFB8LAFQfCzBRCSAUHQsQVB2K8FQdC0BRCNAUGwsgVB4LIF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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHongMLoAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQYi8AwugAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBqNADC0AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAABAAABAAEBAEGI/gQLYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB6P4EC2D9/wIAAAAJdgIADMQLAPTruljHU1eYSF9FV1JwU1jOd23sVqKXGgdck+SA+sNe9hUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQcj/BAtg/f8CAAAACXYCAAzECwD067pYx1NXmEhfRVdScFNYzndt7FailxoHXJPkgPrDXvYVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGogAULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBiIEFC2D9/wIAAAAJdgIADMQLAPTruljHU1eYSF9FV1JwU1jOd23sVqKXGgdck+SA+sNe9hUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQeiBBQtg/f8CAAAACXYCAAzECwD067pYx1NXmEhfRVdScFNYzndt7FailxoHXJPkgPrDXvYVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHIggULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBqIMFC2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABx8HGG5MkDzdKlzR9GIqtdlRuF069CcFiey7oBvg62jtJQ0INuffkDQYdjVGUg8BgAQYiEBQtgw0V1huTJDYnVpYUyUyLzKix+mzBmCIhQJBCIfowbDaJokNviT/DkFDqFZBU/beUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHohAULYGXUGbNSlQgHE4MKtZJfacaPIhfRzDzol+4p3LLKrlujTc6qXeqT4xzrZvuwDyLyCEbW5Uytavay7HxJ/GugQliU05kl1JVIz9DoqEC6nBvBid6g5csTOC6vf4SI2u8OEQBByIUFC2DaD6NaoqfPe3x+kirB3hfc8b5Oa9iNCC+n1HTahyDK0R28zpZmWaIt0of9u+1+Kw7aD6NaoqfPe3x+kirB3hfc8b5Oa9iNCC+n1HTahyDK0R28zpZmWaIt0of9u+1+Kw4AQaiGBQtgP+S8DfU82IKPAZ3fUz6BooHhZTylyvDGlf5QjVLPJXVrinn0UO2FSr3u+Gz9oB0XbMZC8grDJjdw/rbRqsEqfKIUS7r7B0CgKRQ0ZjJ8Ue9rItJOZbqVAN33hszscOMCAEGIhwULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB6IcFC2DoZIp5GzbxMCpazn6r3bjz93cVxjrKqBabAv10+C9qwm4ccGBmtzY2YGEbJKukGwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQciIBQtgcfBxhuTJA83Spc0fRiKrXZUbhdOvQnBYnsu6Ab4Oto7SUNCDbn35A0GHY1RlIPAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGoiQULYDq6jXkbNvvsLFqGkbjdAMGO2isj8Y/ADiFHyvHGPMHVBFx7v0cqIkdZXxzlhPEQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBiIoFC2Cuqvz////1Q/3/R+3y/7cyaZ3pokk66Ad6uzKDMfOo7GnA9KAejRTvBgL/PiazCgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQeiKBQtgw0V1huTJDYnVpYUyUyLzKix+mzBmCIhQJBCIfowbDaJokNviT/DkFDqFZBU/beUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHIiwULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBqIwFC2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9/wIAAAAJdgIADMQLAPTruljHU1eYSF9FV1JwU1jOd23sVqKXGgdck+SA+sNe9hUAQYiNBQtgrqr8////9UP9/0ft8v+3Mmmd6aJJOugHersygzHzqOxpwPSgHo0U7wYC/z4mswoEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHojQULYNGaXKVdWC8+g4HBhj0hlEIyN2KLyEQoOBg+EBn9Kq2SufB8rE9OeR3IXoJ9/JLVC9oPo1qip897fH6SKsHeF9zxvk5r2I0IL6fUdNqHIMrRHbzOlmZZoi3Sh/277X4rDgBByI4FC2DRmlylXVgvPoOBwYY9IZRCMjdii8hEKDgYPhAZ/SqtkrnwfKxPTnkdyF6CffyS1QvRmlylXVgvPoOBwYY9IZRCMjdii8hEKDgYPhAZ/SqtkrnwfKxPTnkdyF6CffyS1QsAQaiPBQtg2g+jWqKnz3t8fpIqwd4X3PG+TmvYjQgvp9R02ocgytEdvM6WZlmiLdKH/bvtfisO0ZpcpV1YLz6DgcGGPSGUQjI3YovIRCg4GD4QGf0qrZK58HysT055Hchegn38ktULAEGIkAULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB6JAFC2Bx8HGG5MkDzdKlzR9GIqtdlRuF069CcFiey7oBvg62jtJQ0INuffkDQYdjVGUg8BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQciRBQtg6GSKeRs28TAqWs5+q9248/d3FcY6yqgWmwL9dPgvasJuHHBgZrc2NmBhGySrpBsFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGokgULYOhkinkbNvEwKlrOfqvduPP3dxXGOsqoFpsC/XT4L2rCbhxwYGa3NjZgYRskq6QbBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBiJMFC2D9/wIAAAAJdgIADMQLAPTruljHU1eYSF9FV1JwU1jOd23sVqKXGgdck+SA+sNe9hUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQeiTBQtgcfBxhuTJA83Spc0fRiKrXZUbhdOvQnBYnsu6Ab4Oto7SUNCDbn35A0GHY1RlIPAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHIlAULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBqJUFC2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADoZIp5GzbxMCpazn6r3bjz93cVxjrKqBabAv10+C9qwm4ccGBmtzY2YGEbJKukGwUAQYiWBQtgOrqNeRs2++wsWoaRuN0AwY7aKyPxj8AOIUfK8cY8wdUEXHu/RyoiR1lfHOWE8RABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHolgULYGzGQvIKwyY3cP620arBKnyiFEu6+wdAoCkUNGYyfFHvayLSTmW6lQDd94bM7HDjAj/kvA31PNiCjwGd31M+gaKB4WU8pcrwxpX+UI1SzyV1a4p59FDthUq97vhs/aAdFwBByJcFC2DaD6NaoqfPe3x+kirB3hfc8b5Oa9iNCC+n1HTahyDK0R28zpZmWaIt0of9u+1+Kw7aD6NaoqfPe3x+kirB3hfc8b5Oa9iNCC+n1HTahyDK0R28zpZmWaIt0of9u+1+Kw4AQaiYBQtgRtblTK1q9rLsfEn8a6BCWJTTmSXUlUjP0OioQLqcG8GJ3qDlyxM4Lq9/hIja7w4RZdQZs1KVCAcTgwq1kl9pxo8iF9HMPOiX7incssquW6NNzqpd6pPjHOtm+7APIvIIAEGImQULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB6JkFC2D9/wIAAAAJdgIADMQLAPTruljHU1eYSF9FV1JwU1jOd23sVqKXGgdck+SA+sNe9hUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQciaBQtg/f8CAAAACXYCAAzECwD067pYx1NXmEhfRVdScFNYzndt7FailxoHXJPkgPrDXvYVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGomwULYK6q/P////VD/f9H7fL/tzJpnemiSTroB3q7MoMx86jsacD0oB6NFO8GAv8+JrMKBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBiJwFC2Cuqvz////1Q/3/R+3y/7cyaZ3pokk66Ad6uzKDMfOo7GnA9KAejRTvBgL/PiazCgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQeicBQtgrqr8////9UP9/0ft8v+3Mmmd6aJJOugHersygzHzqOxpwPSgHo0U7wYC/z4mswoEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHInQULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBqJ4FC2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABx8HGG5MkDzdKlzR9GIqtdlRuF069CcFiey7oBvg62jtJQ0INuffkDQYdjVGUg8BgAQYifBQtgw0V1huTJDYnVpYUyUyLzKix+mzBmCIhQJBCIfowbDaJokNviT/DkFDqFZBU/beUUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHonwULYEbW5Uytavay7HxJ/GugQliU05kl1JVIz9DoqEC6nBvBid6g5csTOC6vf4SI2u8OEWXUGbNSlQgHE4MKtZJfacaPIhfRzDzol+4p3LLKrlujTc6qXeqT4xzrZvuwDyLyCABByKAFC2DRmlylXVgvPoOBwYY9IZRCMjdii8hEKDgYPhAZ/SqtkrnwfKxPTnkdyF6CffyS1QvRmlylXVgvPoOBwYY9IZRCMjdii8hEKDgYPhAZ/SqtkrnwfKxPTnkdyF6CffyS1QsAQaihBQtgbMZC8grDJjdw/rbRqsEqfKIUS7r7B0CgKRQ0ZjJ8Ue9rItJOZbqVAN33hszscOMCP+S8DfU82IKPAZ3fUz6BooHhZTylyvDGlf5QjVLPJXVrinn0UO2FSr3u+Gz9oB0XAEGIogULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB6KIFC2DoZIp5GzbxMCpazn6r3bjz93cVxjrKqBabAv10+C9qwm4ccGBmtzY2YGEbJKukGwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQcijBQtgcfBxhuTJA83Spc0fRiKrXZUbhdOvQnBYnsu6Ab4Oto7SUNCDbn35A0GHY1RlIPAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGopAULYHHwcYbkyQPN0qXNH0Yiq12VG4XTr0JwWJ7LugG+DraO0lDQg259+QNBh2NUZSDwGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBiKUFC2D9/wIAAAAJdgIADMQLAPTruljHU1eYSF9FV1JwU1jOd23sVqKXGgdck+SA+sNe9hUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQeilBQtg6GSKeRs28TAqWs5+q9248/d3FcY6yqgWmwL9dPgvasJuHHBgZrc2NmBhGySrpBsFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHIpgULYP3/AgAAAAl2AgAMxAsA9Ou6WMdTV5hIX0VXUnBTWM53bexWopcaB1yT5ID6w172FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBqKcFC2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9/wIAAAAJdgIADMQLAPTruljHU1eYSF9FV1JwU1jOd23sVqKXGgdck+SA+sNe9hUAQYioBQtgrqr8////9UP9/0ft8v+3Mmmd6aJJOugHersygzHzqOxpwPSgHo0U7wYC/z4mswoEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHoqAULYNoPo1qip897fH6SKsHeF9zxvk5r2I0IL6fUdNqHIMrRHbzOlmZZoi3Sh/277X4rDtGaXKVdWC8+g4HBhj0hlEIyN2KLyEQoOBg+EBn9Kq2SufB8rE9OeR3IXoJ9/JLVCwBByKkFC2DaD6NaoqfPe3x+kirB3hfc8b5Oa9iNCC+n1HTahyDK0R28zpZmWaIt0of9u+1+Kw7aD6NaoqfPe3x+kirB3hfc8b5Oa9iNCC+n1HTahyDK0R28zpZmWaIt0of9u+1+Kw4AQaiqBQtg0ZpcpV1YLz6DgcGGPSGUQjI3YovIRCg4GD4QGf0qrZK58HysT055Hchegn38ktUL2g+jWqKnz3t8fpIqwd4X3PG+TmvYjQgvp9R02ocgytEdvM6WZlmiLdKH/bvtfisOAEGIqwULMHHwcYbkyQPN0qXNH0Yiq12VG4XTr0JwWJ7LugG+DraO0lDQg259+QNBh2NUZSDwGABBuKsFCzDoZIp5GzbxMCpazn6r3bjz93cVxjrKqBabAv10+C9qwm4ccGBmtzY2YGEbJKukGwUAQeirBQsQVVVVVQAAAABW4VVVAIxsOQBByK4FC2BUVQEAAAAEGAEAsDoFAFCFbyc8JXy1PGMCtesx7NEibqJM0fImYZHTlmUAGle4+xdXVf7////6of7/o3b5/1uZtM500SQd9AO9XZnBmHlU9jRgelCPRop3A4F/H5NZBQIAQaivBQswcfBxhuTJA83Spc0fRiKrXZUbhdOvQnBYnsu6Ab4Oto7SUNCDbn35A0GHY1RlIPAYAEHYrwULYNGaXKVdWC8+g4HBhj0hlEIyN2KLyEQoOBg+EBn9Kq2SufB8rE9OeR3IXoJ9/JLVC9GaXKVdWC8+g4HBhj0hlEIyN2KLyEQoOBg+EBn9Kq2SufB8rE9OeR3IXoJ9/JLVCwBBuLAFCwgAAAEAAAAB0gBB8MUFC6AEEHX1XbW5vMAk+4vmMIb5JYn01fvI+wZEoJEh0ZGEL45pgG8KZXGdPoCrTB0BL2wiGZFIF0d89mfXkoXYG4g/rx0W0u6e5GcaGLKuaXiMt+W8ez8EFJNT9q4acPI3JfZzKi1i6RDJ8a/UqcqSNDGDYhk9qL7CPi8uc6ovsJ/nx6ThG5bXf2NJbEV3gejciugIF5k5Nno/3jU2nHUxfJ8dnLAgqE7CE576fVcDpEdpxT+3zlz83LbBpKa8ZnA2gb0bdSfGC++jGAQQ4PmpcZu/SRcLtn0JkRJRHI8w5cZFg0nC162dsSOIbSyVVtXtTACSlfE+wD7sa0yt5kwEIK0fCo2UFc0JMV3F0As/LMBGTzM5V8A062JaO6V2Fh1BOEVyNDRG0FobehIpAVvIxXSkYV6W74YojvyNQxKfRe8vU5YSBMHNaXHuQCqyS7eOpkCcC01o9JCHESUfwNTIk8JrWRISYSd/g2QQ5N0kvxD7fwfzASvNC1efxJNGN0zyWwwatjrHmzWlDTXdrNfkkw1n0la2Gm64mZDTDSuOl0iBMhmIDms4FPQTsaSaDWPi3KAHGDN1k7vnJ6lvRkmtaKpH4/TqbxDW0AocDw86/4Pucshcg2CmuUNOB5ruz+n136rAqa3ex4yOaTAsPzWrdjcH0UM63LoXhYQXqRSNP6G6Y3PQB0V9P3uX1JMB7okKHGpJwKm94bclyNy1He4CAAAAAABBkNAFC0EAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAABAAABAP8AAQ==`,rn=3464,an=42968,on=43112,sn=4776,cn=43256,ln=43544,un=17272,dn=43832,fn=20448,pn=`4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787`,mn=`52435875175126190479447740508185965837690552500527637822603658699938581184513`,hn=null;async function gn(e,t){if(!e&&hn)return hn;let n={};if(!t)n.code=$t(nn),n.pq=712,n.pr=rn,n.pG1gen=an,n.pG1zero=on,n.pG1b=sn,n.pG2gen=cn,n.pG2zero=ln,n.pG2b=un,n.pOneT=dn,n.prePSize=288,n.preQSize=fn,n.n8q=48,n.n8r=32,n.q=pn,n.r=mn;else{let{ModuleBuilder:e}=await Promise.resolve().then(()=>(u(),i)),{buildBls12381:r}=await Promise.resolve().then(()=>(u(),i)),a=new e;a.setMemory(25),r(a),t&&t(a),n.code=a.build(),n.pq=a.modules.f1m.pq,n.pr=a.modules.frm.pq,n.pG1gen=a.modules.bls12381.pG1gen,n.pG1zero=a.modules.bls12381.pG1zero,n.pG1b=a.modules.bls12381.pG1b,n.pG2gen=a.modules.bls12381.pG2gen,n.pG2zero=a.modules.bls12381.pG2zero,n.pG2b=a.modules.bls12381.pG2b,n.pOneT=a.modules.bls12381.pOneT,n.prePSize=a.modules.bls12381.prePSize,n.preQSize=a.modules.bls12381.preQSize,n.n8q=48,n.n8r=32,n.q=a.modules.bls12381.q,n.r=a.modules.bls12381.r}n.batchCode=$t(Yt),n.glv=!0;let r={name:`bls12381`,wasm:n,q:w(`1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab`,16),r:w(`73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001`,16),n8q:48,n8r:32,cofactorG1:w(`0x396c8c005555e1568c00aaab0000aaab`,16),cofactorG2:w(`0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5`,16),singleThread:!!e},a=await Lt(r);return a.terminate=async function(){r.singleThread||(hn=null,await this.tm.terminate())},e||(hn=a),a}var _n=w(`73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001`,16),vn=w(`21888242871839275222246405745257275088548364400416034343698204186575808495617`);w(`1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab`,16),w(`21888242871839275222246405745257275088696311157297823662689037894645226208583`);async function yn(e,t,n){let r;if(fe(e,vn))r=await tn(t,n);else if(fe(e,_n))r=await gn(t,n);else throw Error(`Curve not supported: ${Oe(e)}`);return r}var L=x,bn=tt,xn=Object.create,Sn=Object.defineProperty,Cn=Object.getOwnPropertyDescriptor,wn=Object.getOwnPropertyNames,Tn=Object.getPrototypeOf,En=Object.prototype.hasOwnProperty,Dn=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),On=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=wn(t),a=0,o=i.length,s;at[e]).bind(null,s),enumerable:!(r=Cn(t,s))||r.enumerable});return e},kn=((e,t,n)=>(n=e==null?{}:xn(Tn(e)),On(t||!e||!e.__esModule?Sn(n,`default`,{value:e,enumerable:!0}):n,e)))(Dn(((e,t)=>{t.exports={}}))(),1);async function An(e,t,n,r){if(n||=4096*64,typeof t!=`number`&&[`w+`,`wx+`,`r`,`ax+`,`a+`].indexOf(t)<0)throw Error(`Invalid open option`);let i=await kn.default.promises.open(e,t);return new jn(i,await i.stat(),n,r,e)}var jn=class{constructor(e,t,n,r,i){for(this.fileName=i,this.fd=e,this.pos=0,this.pageSize=r||256;this.pageSize{t.pendingLoads.push({page:e,resolve:n,reject:r})});return t.__statusPage(`After Load request: `,e),n}__statusPage(e,t){let n=[],r=this;if(!r.logHistory)return;n.push(`==`+e+` `+t);let i=``;for(let e=0;e `+t.history[e][n][r])}_triggerLoad(){let e=this;if(e.reading||e.pendingLoads.length==0)return;let t=Object.keys(e.pages),n=[];for(let r=0;r0&&(e.pages[e.pendingLoads[0].page]!==void 0||r>0||n.length>0);){let t=e.pendingLoads.shift();if(e.pages[t.page]!==void 0){e.pages[t.page].pendingOps++;let r=n.indexOf(t.page);r>=0&&n.splice(r,1),e.pages[t.page].loading?e.pages[t.page].loading.push(t):t.resolve(),e.__statusPage(`After Load (cached): `,t.page)}else{if(r)r--;else{let t=n.shift();e.__statusPage(`Before Unload: `,t),e.avBuffs.unshift(e.pages[t]),delete e.pages[t],e.__statusPage(`After Unload: `,t)}t.page>=e.totalPages?(e.pages[t.page]=a(),t.resolve(),e.__statusPage(`After Load (new): `,t.page)):(e.reading=!0,e.pages[t.page]=a(),e.pages[t.page].loading=[t],i.push(e.fd.read(e.pages[t.page].buff,0,e.pageSize,t.page*e.pageSize).then(n=>{e.pages[t.page].size=n.bytesRead;let r=e.pages[t.page].loading;delete e.pages[t.page].loading;for(let e=0;e{t.reject(e)})),e.__statusPage(`After Load (loading): `,t.page))}}Promise.all(i).then(()=>{e.reading=!1,e.pendingLoads.length>0&&setImmediate(e._triggerLoad.bind(e)),e._tryClose()});function a(){if(e.avBuffs.length>0){let t=e.avBuffs.shift();return t.dirty=!1,t.pendingOps=1,t.size=0,t}else return{dirty:!1,buff:new Uint8Array(e.pageSize),pendingOps:1,size:0}}}_triggerWrite(){let e=this;if(e.writing)return;let t=Object.keys(e.pages),n=[];for(let r=0;r{i.writing=!1},t=>{console.log(`ERROR Writing: `+t),e.error=t,e._tryClose()})))}e.writing&&Promise.all(n).then(()=>{e.writing=!1,setImmediate(e._triggerWrite.bind(e)),e._tryClose(),e.pendingLoads.length>0&&setImmediate(e._triggerLoad.bind(e))})}_getDirtyPage(){for(let e in this.pages)if(this.pages[e].dirty)return e;return-1}_rangeHasCachedPages(e,t){let n=Math.floor(e/this.pageSize),r=Math.floor((e+t-1)/this.pageSize);for(let e of Object.keys(this.pages)){let t=+e;if(t>=n&&t<=r)return!0}return!1}async write(e,t){if(e.byteLength==0)return;let n=this;if(t===void 0&&(t=n.pos),n.pos=t+e.byteLength,n.totalSize=n.directWriteThreshold&&ArrayBuffer.isView(e)&&!n._rangeHasCachedPages(t,e.byteLength)){let r=0;for(;rn.totalPages&&(n.totalPages=i+1);return}let r=Math.floor(t/n.pageSize),i=Math.floor((t+e.byteLength-1)/n.pageSize),a=[];for(let e=r;e<=i;e++)a.push(n._loadPage(e));n._triggerLoad();let o=r,s=t%n.pageSize,c=e.byteLength;for(;c>0;){await a[o-r];let t=s+c>n.pageSize?n.pageSize-s:c,i=e.slice(e.byteLength-c,e.byteLength-c+t);new Uint8Array(n.pages[o].buff.buffer,s,t).set(i),n.pages[o].dirty=!0,n.pages[o].pendingOps--,n.pages[o].size=Math.max(s+t,n.pages[o].size),o>=n.totalPages&&(n.totalPages=o+1),c-=t,o++,s=0,n.writing||setImmediate(n._triggerWrite.bind(n))}}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}_rangeHasDirtyPages(e,t){let n=Math.floor(e/this.pageSize),r=Math.floor((e+t-1)/this.pageSize);for(let e of Object.keys(this.pages)){let t=+e;if(t>=n&&t<=r){let e=this.pages[t];if(e.dirty||e.writing)return!0}}return!1}async readToBuffer(e,t,n,r){if(n==0)return;let i=this;if(r===void 0&&(r=i.pos),i.pos=r+n,i.pendingClose)throw Error(`Reading a closing file`);if(n>=i.directReadThreshold&&ArrayBuffer.isView(e)&&!i._rangeHasDirtyPages(r,n)){let a=r+n>i.totalSize?i.totalSize-r:n;a<0&&(a=0);let o=0;for(;oi.pageSize*i.maxPagesLoaded*.8){let e=Math.floor(n*1.1);this.maxPagesLoaded=Math.floor(e/i.pageSize)+1}let a=Math.floor(r/i.pageSize),o=Math.floor((r+n-1)/i.pageSize),s=[];for(let e=a;e<=o;e++)s.push(i._loadPage(e));i._triggerLoad();let c=a,l=r%i.pageSize,u=r+n>i.totalSize?n-(r+n-i.totalSize):n;for(;u>0;){await s[c-a],i.__statusPage(`After Await (read): `,c);let r=l+u>i.pageSize?i.pageSize-l:u,o=new Uint8Array(i.pages[c].buff.buffer,i.pages[c].buff.byteOffset+l,r);e.set(o,t+n-u),i.pages[c].pendingOps--,i.__statusPage(`After Op done: `,c),u-=r,c++,l=0,i.pendingLoads.length>0&&setImmediate(i._triggerLoad.bind(i))}this.pos=r+n}_tryClose(){let e=this;e.pendingClose&&(e.error&&e.pendingCloseReject(e.error),!(e._getDirtyPage()>=0||e.writing||e.reading||e.pendingLoads.length>0)&&e.pendingClose())}close(){let e=this;if(e.pendingClose)throw Error(`Closing the file twice`);return new Promise((t,n)=>{e.pendingClose=t,e.pendingCloseReject=n,e._tryClose()}).then(()=>{e.fd.close()},t=>{throw e.fd.close(),t})}async discard(){await this.close(),await kn.default.promises.unlink(this.fileName)}async writeULE32(e,t){let n=this,r=new Uint8Array(4);new DataView(r.buffer).setUint32(0,e,!0),await n.write(r,t)}async writeUBE32(e,t){let n=this,r=new Uint8Array(4);new DataView(r.buffer).setUint32(0,e,!1),await n.write(r,t)}async writeULE64(e,t){let n=this,r=new Uint8Array(8),i=new DataView(r.buffer);i.setUint32(0,e&4294967295,!0),i.setUint32(4,Math.floor(e/4294967296),!0),await n.write(r,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this;if(t.pendingClose)throw Error(`Reading a closing file`);let n=e===void 0?t.pos:e,r=Math.floor(n/t.pageSize),i=!1,a=``;for(;!i;){let e=t._loadPage(r);t._triggerLoad(),await e,t.__statusPage(`After Await (read): `,r);let o=n%t.pageSize,s=new Uint8Array(t.pages[r].buff.buffer,t.pages[r].buff.byteOffset+o,t.pageSize-o),c=s.findIndex(e=>e===0);i=c!==-1,i?(a+=new TextDecoder().decode(s.slice(0,c)),t.pos=r*this.pageSize+o+c+1):(a+=new TextDecoder().decode(s),t.pos=r*this.pageSize+o+s.length),t.pages[r].pendingOps--,t.__statusPage(`After Op done: `,r),n=t.pos,r++,t.pendingLoads.length>0&&setImmediate(t._triggerLoad.bind(t))}return a}};function Mn(e){let t=e.initialSize||1<<20,n=new Rn;return n.o=e,n.o.data=new Uint8Array(t),n.allocSize=t,n.totalSize=0,n.readOnly=!1,n.pos=0,n}function Nn(e){let t=new Rn;return t.o=e,t.allocSize=e.data.byteLength,t.totalSize=e.data.byteLength,t.readOnly=!0,t.pos=0,t}var Pn=new Uint8Array(4),Fn=new DataView(Pn.buffer),In=new Uint8Array(8),Ln=new DataView(In.buffer),Rn=class{constructor(){this.pageSize=16384}_resizeIfNeeded(e){if(e>this.allocSize){let t=Math.max(this.allocSize+(1<<20),Math.floor(this.allocSize*1.1),e),n=new Uint8Array(t);n.set(this.o.data),this.o.data=n,this.allocSize=t}}async write(e,t){let n=this;if(t===void 0&&(t=n.pos),this.readOnly)throw Error(`Writing a read only file`);this._resizeIfNeeded(t+e.byteLength),this.o.data.set(e.slice(),t),t+e.byteLength>this.totalSize&&(this.totalSize=t+e.byteLength),this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+r,n);e.set(a,t),this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(e,t){let n=this;Fn.setUint32(0,e,!0),await n.write(Pn,t)}async writeUBE32(e,t){let n=this;Fn.setUint32(0,e,!1),await n.write(Pn,t)}async writeULE64(e,t){let n=this;Ln.setUint32(0,e&4294967295,!0),Ln.setUint32(4,Math.floor(e/4294967296),!0),await n.write(In,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);this._resizeIfNeeded(e)}let r=new Uint8Array(t.o.data.buffer,n,this.totalSize-n),i=r.findIndex(e=>e===0),a=i!==-1,o=``;return a?(o=new TextDecoder().decode(r.slice(0,i)),t.pos=n+i+1):t.pos=n,o}},R=1<<22;function zn(e){let t=e.initialSize||0,n=new Gn;n.o=e;let r=t?Math.floor((t-1)/R)+1:0;n.o.data=[];for(let e=0;e0;){let t=i+a>R?R-i:a,o=e.slice(e.byteLength-a,e.byteLength-a+t);new Uint8Array(n.o.data[r].buffer,i,t).set(o),a-=t,r++,i=0}this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=Math.floor(r/R),o=r%R,s=n;for(;s>0;){let r=o+s>R?R-o:s,c=new Uint8Array(i.o.data[a].buffer,o,r);e.set(c,t+n-s),s-=r,a++,o=0}this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){}async discard(){}async writeULE32(e,t){let n=this;Hn.setUint32(0,e,!0),await n.write(Vn,t)}async writeUBE32(e,t){let n=this;Hn.setUint32(0,e,!1),await n.write(Vn,t)}async writeULE64(e,t){let n=this;Wn.setUint32(0,e&4294967295,!0),Wn.setUint32(4,Math.floor(e/4294967296),!0),await n.write(Un,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);this._resizeIfNeeded(e)}let r=!1,i=``;for(;!r;){let e=Math.floor(n/R),a=n%R;if(t.o.data[e]===void 0)throw Error(`ERROR`);let o=Math.min(2048,t.o.data[e].length-a),s=new Uint8Array(t.o.data[e].buffer,a,o),c=s.findIndex(e=>e===0);r=c!==-1,r?(i+=new TextDecoder().decode(s.slice(0,c)),t.pos=e*R+a+c+1):(i+=new TextDecoder().decode(s),t.pos=e*R+a+s.length),n=t.pos}return i}},Kn=65536,qn=8192,Jn=typeof process<`u`&&process.versions!=null&&process.versions.node!=null;async function Yn(e,t,n){if(typeof e==`string`&&(e={type:`file`,fileName:e,cacheSize:t||Kn,pageSize:n||qn}),e.type==`file`)return await An(e.fileName,0,e.cacheSize,e.pageSize);if(e.type==`mem`)return Mn(e);if(e.type==`bigMem`)return zn(e);throw Error(`Invalid FastFile type: `+e.type)}async function Xn(e,t,n){if(e instanceof Uint8Array&&(e={type:`mem`,data:e}),Jn?typeof e==`string`&&(e={type:`file`,fileName:e,cacheSize:t||Kn,pageSize:n||qn}):typeof e==`string`&&(e={type:`mem`,data:await fetch(e).then(function(e){return e.arrayBuffer()}).then(function(e){return new Uint8Array(e)})}),e.type==`file`)return await An(e.fileName,0,e.cacheSize,e.pageSize);if(e.type==`mem`)return await Nn(e);if(e.type==`bigMem`)return await Bn(e);throw Error(`Invalid FastFile type: `+e.type)}var Zn=1<<30;async function z(e,t,n,r,i){let a=await Xn(e,r,i),o=await a.read(4),s=``;for(let e=0;e<4;e++)s+=String.fromCharCode(o[e]);if(s!=t)throw Error(e+`: Invalid File format`);if(await a.readULE32()>n)throw Error(`Version not supported`);let c=await a.readULE32(),l=[];for(let e=0;e1)throw Error(e.fileName+`: Section Duplicated `+n);e.pos=t[n][0].p,e.readingSection=t[n][0]}async function U(e,t){if(e.readingSection===void 0)throw Error(`Not reading a section`);if(!t&&e.pos-e.readingSection.p!=e.readingSection.size)throw Error(`Invalid section size reading`);delete e.readingSection}async function $n(e,t,n,r){let i=new Uint8Array(n);L.toRprLE(i,0,t,n),await e.write(i,r)}async function er(e,t,n){let r=await e.read(t,n);return L.fromRprLE(r,0,t)}async function W(e,t,n,r,i){i===void 0&&(i=t[r][0].size);let a=e.pageSize;await H(e,t,r),await B(n,r);for(let t=0;tt[n][0].size)throw Error(`Reading out of the range of the section`);let a;return a=ilr,getCurveFromQ:()=>cr,getCurveFromR:()=>sr}),rr=L.e(`73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001`,16),ir=L.e(`21888242871839275222246405745257275088548364400416034343698204186575808495617`),ar=L.e(`1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab`,16),or=L.e(`21888242871839275222246405745257275088696311157297823662689037894645226208583`);async function sr(e,t){let n,r=t&&t.singleThread;if(L.eq(e,ir))n=await tn(r);else if(L.eq(e,rr))n=await gn(r);else throw Error(`Curve not supported: ${L.toString(e)}`);return n}async function cr(e,t){let n,r=t&&t.singleThread;if(L.eq(e,or))n=await tn(r);else if(L.eq(e,ar))n=await gn(r);else throw Error(`Curve not supported: ${L.toString(e)}`);return n}async function lr(e,t){let n,r=t&&t.singleThread,i=a(e);if([`BN128`,`BN254`,`ALTBN128`].indexOf(i)>=0)n=await tn(r);else if([`BLS12381`].indexOf(i)>=0)n=await gn(r);else throw Error(`Curve not supported: ${e}`);return n;function a(e){return e.toUpperCase().match(/[A-Za-z0-9]+/g).join(``)}}function ur(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name===`Uint8Array`&&`BYTES_PER_ELEMENT`in e&&e.BYTES_PER_ELEMENT===1}function dr(e,t=``){if(typeof e!=`number`){let n=t&&`"${t}" `;throw TypeError(`${n}expected number, got ${typeof e}`)}if(!Number.isSafeInteger(e)||e<0){let n=t&&`"${t}" `;throw RangeError(`${n}expected integer >= 0, got ${e}`)}}function fr(e,t,n=``){let r=ur(e),i=e?.length,a=t!==void 0;if(!r||a&&i!==t){let o=n&&`"${n}" `,s=a?` of length ${t}`:``,c=r?`length=${i}`:`type=${typeof e}`,l=o+`expected Uint8Array`+s+`, got `+c;throw r?RangeError(l):TypeError(l)}return e}function pr(e,t=!0){if(e.destroyed)throw Error(`Hash instance has been destroyed`);if(t&&e.finished)throw Error(`Hash#digest() has already been called`)}function mr(e,t){fr(e,void 0,`digestInto() output`);let n=t.outputLen;if(e.length=`+n)}function hr(e){return new Uint32Array(e.buffer,e.byteOffset,Math.floor(e.byteLength/4))}function gr(...e){for(let t=0;t>>8&65280|e>>>24&255}var yr=_r?e=>e:e=>vr(e)>>>0;function br(e){for(let t=0;te:br;function Sr(e,t={}){let n=(t,n)=>e(n).update(t).digest(),r=e(void 0);return n.outputLen=r.outputLen,n.blockLen=r.blockLen,n.canXOF=r.canXOF,n.create=t=>e(t),Object.assign(n,t),Object.freeze(n)}var Cr=Uint8Array.from([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3,11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4,7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8,9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13,2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9,12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11,13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10,6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5,10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3,11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4,7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8,9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13,2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9]),wr=BigInt(2**32-1),Tr=BigInt(32);function Er(e,t=!1){return t?{h:Number(e&wr),l:Number(e>>Tr&wr)}:{h:Number(e>>Tr&wr)|0,l:Number(e&wr)|0}}function Dr(e,t=!1){let n=e.length,r=new Uint32Array(n),i=new Uint32Array(n);for(let a=0;ae>>>n|t<<32-n,kr=(e,t,n)=>e<<32-n|t>>>n,Ar=(e,t,n)=>e<<64-n|t>>>n-32,jr=(e,t,n)=>e>>>n-32|t<<64-n,Mr=(e,t)=>t,Nr=(e,t)=>e,Pr=(e,t,n)=>e<>>32-n,Fr=(e,t,n)=>t<>>32-n,Ir=(e,t,n)=>t<>>64-n,Lr=(e,t,n)=>e<>>64-n;function Rr(e,t,n,r){let i=(t>>>0)+(r>>>0);return{h:e+n+(i/2**32|0)|0,l:i|0}}var zr=(e,t,n)=>(e>>>0)+(t>>>0)+(n>>>0),Br=(e,t,n,r)=>t+n+r+(e/2**32|0)|0,Vr=Uint32Array.from([4089235720,1779033703,2227873595,3144134277,4271175723,1013904242,1595750129,2773480762,2917565137,1359893119,725511199,2600822924,4215389547,528734635,327033209,1541459225]),K=new Uint32Array(32);function Hr(e,t,n,r,i,a){let o=i[a],s=i[a+1],c=K[2*e],l=K[2*e+1],u=K[2*t],d=K[2*t+1],f=K[2*n],p=K[2*n+1],m=K[2*r],h=K[2*r+1],g=zr(c,u,o);l=Br(g,l,d,s),c=g|0,{Dh:h,Dl:m}={Dh:h^l,Dl:m^c},{Dh:h,Dl:m}={Dh:Mr(h,m),Dl:Nr(h,m)},{h:p,l:f}=Rr(p,f,h,m),{Bh:d,Bl:u}={Bh:d^p,Bl:u^f},{Bh:d,Bl:u}={Bh:Or(d,u,24),Bl:kr(d,u,24)},K[2*e]=c,K[2*e+1]=l,K[2*t]=u,K[2*t+1]=d,K[2*n]=f,K[2*n+1]=p,K[2*r]=m,K[2*r+1]=h}function Ur(e,t,n,r,i,a){let o=i[a],s=i[a+1],c=K[2*e],l=K[2*e+1],u=K[2*t],d=K[2*t+1],f=K[2*n],p=K[2*n+1],m=K[2*r],h=K[2*r+1],g=zr(c,u,o);l=Br(g,l,d,s),c=g|0,{Dh:h,Dl:m}={Dh:h^l,Dl:m^c},{Dh:h,Dl:m}={Dh:Or(h,m,16),Dl:kr(h,m,16)},{h:p,l:f}=Rr(p,f,h,m),{Bh:d,Bl:u}={Bh:d^p,Bl:u^f},{Bh:d,Bl:u}={Bh:Ar(d,u,63),Bl:jr(d,u,63)},K[2*e]=c,K[2*e+1]=l,K[2*t]=u,K[2*t+1]=d,K[2*n]=f,K[2*n+1]=p,K[2*r]=m,K[2*r+1]=h}function Wr(e,t={},n,r,i){if(dr(n),e<=0||e>n)throw Error(`outputLen bigger than keyLen`);let{key:a,salt:o,personalization:s}=t;if(a!==void 0&&(a.length<1||a.length>n))throw Error(`"key" expected to be undefined or of length=1..`+n);o!==void 0&&fr(o,r,`salt`),s!==void 0&&fr(s,i,`personalization`)}var Gr=class{buffer;buffer32;finished=!1;destroyed=!1;length=0;pos=0;blockLen;outputLen;canXOF=!1;constructor(e,t){dr(e),dr(t),this.blockLen=e,this.outputLen=t,this.buffer=new Uint8Array(e),this.buffer32=hr(this.buffer)}update(e){pr(this),fr(e);let{blockLen:t,buffer:n,buffer32:r}=this,i=e.length,a=e.byteOffset,o=e.buffer;for(let s=0;s>>8*t}digest(){let{buffer:e,outputLen:t}=this;this.digestInto(e);let n=e.slice(0,t);return this.destroy(),n}_cloneInto(e){let{buffer:t,length:n,finished:r,destroyed:i,outputLen:a,pos:o}=this;return e||=new this.constructor({dkLen:a}),e.set(...this.get()),e.buffer.set(t),e.destroyed=i,e.finished=r,e.length=n,e.pos=o,e.outputLen=a,e}clone(){return this._cloneInto()}},Kr=class extends Gr{v0l=Vr[0]|0;v0h=Vr[1]|0;v1l=Vr[2]|0;v1h=Vr[3]|0;v2l=Vr[4]|0;v2h=Vr[5]|0;v3l=Vr[6]|0;v3h=Vr[7]|0;v4l=Vr[8]|0;v4h=Vr[9]|0;v5l=Vr[10]|0;v5h=Vr[11]|0;v6l=Vr[12]|0;v6h=Vr[13]|0;v7l=Vr[14]|0;v7h=Vr[15]|0;constructor(e={}){let t=e.dkLen===void 0?64:e.dkLen;super(128,t),Wr(t,e,64,16,16);let{key:n,personalization:r,salt:i}=e,a=0;if(n!==void 0&&(fr(n,void 0,`key`),a=n.length),this.v0l^=this.outputLen|a<<8|16842752,i!==void 0){fr(i,void 0,`salt`);let e=hr(i);this.v4l^=yr(e[0]),this.v4h^=yr(e[1]),this.v5l^=yr(e[2]),this.v5h^=yr(e[3])}if(r!==void 0){fr(r,void 0,`personalization`);let e=hr(r);this.v6l^=yr(e[0]),this.v6h^=yr(e[1]),this.v7l^=yr(e[2]),this.v7h^=yr(e[3])}if(n!==void 0){let e=new Uint8Array(this.blockLen);e.set(n),this.update(e)}}get(){let{v0l:e,v0h:t,v1l:n,v1h:r,v2l:i,v2h:a,v3l:o,v3h:s,v4l:c,v4h:l,v5l:u,v5h:d,v6l:f,v6h:p,v7l:m,v7h:h}=this;return[e,t,n,r,i,a,o,s,c,l,u,d,f,p,m,h]}set(e,t,n,r,i,a,o,s,c,l,u,d,f,p,m,h){this.v0l=e|0,this.v0h=t|0,this.v1l=n|0,this.v1h=r|0,this.v2l=i|0,this.v2h=a|0,this.v3l=o|0,this.v3h=s|0,this.v4l=c|0,this.v4h=l|0,this.v5l=u|0,this.v5h=d|0,this.v6l=f|0,this.v6h=p|0,this.v7l=m|0,this.v7h=h|0}compress(e,t,n){this.get().forEach((e,t)=>K[t]=e),K.set(Vr,16);let{h:r,l:i}=Er(BigInt(this.length));K[24]=Vr[8]^i,K[25]=Vr[9]^r,n&&(K[28]=~K[28],K[29]=~K[29]);let a=0,o=Cr;for(let n=0;n<12;n++)Hr(0,4,8,12,e,t+2*o[a++]),Ur(0,4,8,12,e,t+2*o[a++]),Hr(1,5,9,13,e,t+2*o[a++]),Ur(1,5,9,13,e,t+2*o[a++]),Hr(2,6,10,14,e,t+2*o[a++]),Ur(2,6,10,14,e,t+2*o[a++]),Hr(3,7,11,15,e,t+2*o[a++]),Ur(3,7,11,15,e,t+2*o[a++]),Hr(0,5,10,15,e,t+2*o[a++]),Ur(0,5,10,15,e,t+2*o[a++]),Hr(1,6,11,12,e,t+2*o[a++]),Ur(1,6,11,12,e,t+2*o[a++]),Hr(2,7,8,13,e,t+2*o[a++]),Ur(2,7,8,13,e,t+2*o[a++]),Hr(3,4,9,14,e,t+2*o[a++]),Ur(3,4,9,14,e,t+2*o[a++]);this.v0l^=K[0]^K[16],this.v0h^=K[1]^K[17],this.v1l^=K[2]^K[18],this.v1h^=K[3]^K[19],this.v2l^=K[4]^K[20],this.v2h^=K[5]^K[21],this.v3l^=K[6]^K[22],this.v3h^=K[7]^K[23],this.v4l^=K[8]^K[24],this.v4h^=K[9]^K[25],this.v5l^=K[10]^K[26],this.v5h^=K[11]^K[27],this.v6l^=K[12]^K[28],this.v6h^=K[13]^K[29],this.v7l^=K[14]^K[30],this.v7h^=K[15]^K[31],gr(K)}destroy(){this.destroyed=!0,gr(this.buffer32),this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)}},q=Sr(e=>new Kr(e)),qr={},Jr=[];for(let e=0;e<256;e++)Jr[e]=Yr(e,8);function Yr(e,t){let n=0,r=e;for(let e=0;e>=1;return n}function Xr(e){return(e&4294901760?(e&=4294901760,16):0)|(e&4278255360?(e&=4278255360,8):0)|(e&4042322160?(e&=4042322160,4):0)|(e&3435973836?(e&=3435973836,2):0)|(e&2863311530)!=0}function J(e,t){let n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=``;for(let e=0;e<4;e++){e>0&&(r+=` +`),r+=` `;for(let t=0;t<4;t++)t>0&&(r+=` `),r+=n.getUint32(e*16+t*4).toString(16).padStart(8,`0`)}return t&&(r=t+` +`+r),r}function Zr(e,t){if(e.byteLength!=t.byteLength)return!1;for(var n=new Int8Array(e),r=new Int8Array(t),i=0;i!=e.byteLength;i++)if(n[i]!=r[i])return!1;return!0}function Qr(e){return e.clone()}function $r(e){let t=e.subarray(0,128),n=hr(e.subarray(128)),r=q.create({dkLen:64});r.buffer.set(t),r.v0l=n[0]|0,r.v0h=n[1]|0,r.v1l=n[2]|0,r.v1h=n[3]|0,r.v2l=n[4]|0,r.v2h=n[5]|0,r.v3l=n[6]|0,r.v3h=n[7]|0,r.v4l=n[8]|0,r.v4h=n[9]|0,r.v5l=n[10]|0,r.v5h=n[11]|0,r.v6l=n[12]|0,r.v6h=n[13]|0,r.v7l=n[14]|0,r.v7h=n[15]|0;let i=2**32,a=n[16]+n[17]*i,o=n[18]+n[19]*i;return r.length=a+o,r.pos=o,r}function ei(e){let t=new Uint8Array(216),n=hr(t.subarray(128));return t.set(e.buffer),n[0]=e.v0l,n[1]=e.v0h,n[2]=e.v1l,n[3]=e.v1h,n[4]=e.v2l,n[5]=e.v2h,n[6]=e.v3l,n[7]=e.v3h,n[8]=e.v4l,n[9]=e.v4h,n[10]=e.v5l,n[11]=e.v5h,n[12]=e.v6l,n[13]=e.v6h,n[14]=e.v7l,n[15]=e.v7h,n[18]=e.pos,n[16]=e.length-e.pos,t}async function ti(e,t,n,r,i){return e.G1.isZero(t)||e.G1.isZero(n)||e.G2.isZero(r)||e.G2.isZero(i)?!1:await e.pairingEq(t,i,e.G1.neg(n),r)}function ni(){if(typeof window<`u`&&typeof window.prompt==`function`)return window.prompt(`Enter a random text. (Entropy): `,``);{let e=qr.createInterface({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(`Enter a random text. (Entropy): `,e=>t(e))})}}function ri(e){let t=new Uint8Array(e);if(qr&&qr.randomFillSync)qr.randomFillSync(t);else if(globalThis.crypto!==void 0&&globalThis.crypto.getRandomValues)for(let n=0;n>>0,r=1):(n=4294967296,r=1<>>0);let i=e;for(let e=0;e{n[r]=ui(e,t[r])}),n}else if(typeof t==`bigint`||t.eq!==void 0)return t.toString(10);else return t}async function di(e,t){await B(e,1),await e.writeULE32(1),await V(e);let n=await cr(t.q);await B(e,2);let r=n.q,i=(Math.floor((L.bitLength(r)-1)/64)+1)*8,a=n.r,o=(Math.floor((L.bitLength(a)-1)/64)+1)*8;await e.writeULE32(i),await $n(e,r,i),await e.writeULE32(o),await $n(e,a,o),await e.writeULE32(t.nVars),await e.writeULE32(t.nPublic),await e.writeULE32(t.domainSize),await fi(e,n,t.vk_alpha_1),await fi(e,n,t.vk_beta_1),await pi(e,n,t.vk_beta_2),await pi(e,n,t.vk_gamma_2),await fi(e,n,t.vk_delta_1),await pi(e,n,t.vk_delta_2),await V(e)}async function fi(e,t,n){let r=new Uint8Array(t.G1.F.n8*2);t.G1.toRprLEM(r,0,n),await e.write(r)}async function pi(e,t,n){let r=new Uint8Array(t.G2.F.n8*2);t.G2.toRprLEM(r,0,n),await e.write(r)}async function Y(e,t,n){let r=await e.read(t.G1.F.n8*2),i=t.G1.fromRprLEM(r,0);return n?t.G1.toObject(i):i}async function mi(e,t,n){let r=await e.read(t.G2.F.n8*2),i=t.G2.fromRprLEM(r,0);return n?t.G2.toObject(i):i}async function hi(e,t,n,r){await H(e,t,1);let i=await e.readULE32();if(await U(e),i===1)return await gi(e,t,n,r);if(i===2)return await _i(e,t,n,r);if(i===10)return await vi(e,t,n,r);throw Error(`Protocol not supported: `)}async function gi(e,t,n,r){let i={};i.protocol=`groth16`,await H(e,t,2);let a=await e.readULE32();i.n8q=a,i.q=await er(e,a);let o=await e.readULE32();return i.n8r=o,i.r=await er(e,o),i.curve=await cr(i.q,r),i.nVars=await e.readULE32(),i.nPublic=await e.readULE32(),i.domainSize=await e.readULE32(),i.power=Xr(i.domainSize),i.vk_alpha_1=await Y(e,i.curve,n),i.vk_beta_1=await Y(e,i.curve,n),i.vk_beta_2=await mi(e,i.curve,n),i.vk_gamma_2=await mi(e,i.curve,n),i.vk_delta_1=await Y(e,i.curve,n),i.vk_delta_2=await mi(e,i.curve,n),await U(e),i}async function _i(e,t,n,r){let i={};i.protocol=`plonk`,await H(e,t,2);let a=await e.readULE32();i.n8q=a,i.q=await er(e,a);let o=await e.readULE32();return i.n8r=o,i.r=await er(e,o),i.curve=await cr(i.q,r),i.nVars=await e.readULE32(),i.nPublic=await e.readULE32(),i.domainSize=await e.readULE32(),i.power=Xr(i.domainSize),i.nAdditions=await e.readULE32(),i.nConstraints=await e.readULE32(),i.k1=await e.read(o),i.k2=await e.read(o),i.Qm=await Y(e,i.curve,n),i.Ql=await Y(e,i.curve,n),i.Qr=await Y(e,i.curve,n),i.Qo=await Y(e,i.curve,n),i.Qc=await Y(e,i.curve,n),i.S1=await Y(e,i.curve,n),i.S2=await Y(e,i.curve,n),i.S3=await Y(e,i.curve,n),i.X_2=await mi(e,i.curve,n),await U(e),i}async function vi(e,t,n,r){let i={};i.protocol=`fflonk`,i.protocolId=10,await H(e,t,2);let a=await e.readULE32();i.n8q=a,i.q=await er(e,a),i.curve=await cr(i.q,r);let o=await e.readULE32();return i.n8r=o,i.r=await er(e,o),i.nVars=await e.readULE32(),i.nPublic=await e.readULE32(),i.domainSize=await e.readULE32(),i.power=Xr(i.domainSize),i.nAdditions=await e.readULE32(),i.nConstraints=await e.readULE32(),i.k1=await e.read(o),i.k2=await e.read(o),i.w3=await e.read(o),i.w4=await e.read(o),i.w8=await e.read(o),i.wr=await e.read(o),i.X_2=await mi(e,i.curve,n),i.C0=await Y(e,i.curve,n),await U(e),i}async function yi(e,t){let{fd:n,sections:r}=await z(e,`zkey`,1),i=await hi(n,r,t),a=new et(i.r),o=L.mod(L.shl(1,i.n8r*8),i.r),s=a.inv(o),c=a.mul(s,s),l=await cr(i.q);await H(n,r,3),i.IC=[];for(let e=0;e<=i.nPublic;e++){let e=await Y(n,l,t);i.IC.push(e)}await U(n),await H(n,r,4);let u=await n.readULE32();i.ccoefs=[];for(let e=0;e0){let t=new Uint8Array(r);await e.writeULE32(t.byteLength),await e.write(t)}else await e.writeULE32(0)}async function Ci(e,t,n){await B(e,10),await e.write(n.csHash),await e.writeULE32(n.contributions.length);for(let r=0;r1?Number(r.memoryLogging):1e3));try{return await Ni(e,t,n,r)}finally{i&&(clearInterval(i),Ri(n))}}async function Ni(e,t,n,r){let{fd:i,sections:a}=await z(t,`wtns`,2,1<<25,1<<23),o=await ki(i,a),{fd:s,sections:c}=await z(e,`zkey`,2,1<<25,1<<23),l=await hi(s,c,void 0,r);if(l.protocol!=`groth16`)throw Error(`zkey file is not groth16`);if(!L.eq(l.r,o.q))throw Error(`Curve of the witness does not match the curve of the proving key`);if(o.nWitness!=l.nVars)throw Error(`Invalid witness length. Circuit: ${l.nVars}, witness: ${o.nWitness}`);let u=l.curve,d=u.Fr,f=u.G1,p=u.G2;r||={};let m=r.msmBatching||`auto`;if(m!==`auto`&&m!==`enabled`&&m!==`disabled`)throw Error(`groth16Prove: invalid msmBatching "${m}" (expected "auto", "enabled" or "disabled")`);let h=r.msmGlv||`auto`,g=r.msmGls||`auto`;for(let[e,t]of[[`msmGlv`,h],[`msmGls`,g]])if(t!==`auto`&&t!==`disabled`)throw Error(`groth16Prove: invalid ${e} "${t}" (expected "auto" or "disabled")`);let _={batch:m,glv:h,gls:g},v=Xr(l.domainSize);n&&n.debug(`Reading Wtns`);let y=await G(i,a,2),b=e=>{let t=c[e][0].p,n=c[e][0].size;return async(r,i)=>{if(r+i>n)throw Error(`groth16Prove: read out of range of section ${e}`);let a=new Uint8Array(i);return await s.readToBuffer(a,0,i,t+r),a}},x,S,C,w=(async function(){let e,t,i;await(async function(){n&&n.debug(`Reading Coeffs`);let a=await G(s,c,4);if(n&&n.debug(`Building ABC`),r.buildABC===`js`)[e,t,i]=await Pi(u,l,y,a,n);else if(r.buildABC===`stream`){let o=Fi(u,l,a,r);[e,t,i]=await Ii(u,l,y,a,n,o.nChunks,o.maxInFlight)}else{let o=Fi(u,l,a,r);n&&n.debug(`buildABC: stream nChunks=${o.nChunks} maxInFlight=${o.maxInFlight}`),[e,t,i]=await Ii(u,l,y,a,n,o.nChunks,o.maxInFlight)}})();let a=v===d.s?u.Fr.shift:u.Fr.w[v+1],o,f,p;await Promise.all([(async function(){let t=await d.ifft(e,``,``,n,`IFFT_A`,!0);e=null;let r=await d.batchApplyKey(t,d.e(1),a);o=await d.fft(r,``,``,n,`FFT_A`,!0)})(),(async function(){let e=await d.ifft(t,``,``,n,`IFFT_B`,!0);t=null;let r=await d.batchApplyKey(e,d.e(1),a);f=await d.fft(r,``,``,n,`FFT_B`,!0)})(),(async function(){let e=await d.ifft(i,``,``,n,`IFFT_C`,!0);i=null;let t=await d.batchApplyKey(e,d.e(1),a);p=await d.fft(t,``,``,n,`FFT_C`,!0)})()]),n&&n.debug(`Join ABC`),C=await Li(u,l,o,f,p,n),n&&n.debug(`Join ABC finished`),o=null,f=null,p=null,globalThis.gc&&globalThis.gc()})(),T={};async function E(){n&&n.debug(`Reading A Points`),T.pi_a=await u.G1.multiExpAffineChunked(b(5),c[5][0].size,y,n,`multiexp A`,_)}let D=E(),O;async function k(){n&&n.debug(`Reading B1 Points`),O=await u.G1.multiExpAffineChunked(b(6),c[6][0].size,y,n,`multiexp B1`,_)}let A=k();async function j(){n&&n.debug(`Reading B2 Points`),T.pi_b=await u.G2.multiExpAffineChunked(b(7),c[7][0].size,y,n,`multiexp B2`,_)}let M=j(),ee=(async function(){n&&n.debug(`Reading C Points`),T.pi_c=await u.G1.multiExpAffineChunked(b(8),c[8][0].size,y.slice((l.nPublic+1)*u.Fr.n8),n,`multiexp C`,_)})();S=(async function(){n&&n.debug(`Reading H Points`),await w,x=await u.G1.multiExpAffineChunked(b(9),c[9][0].size,C,n,`multiexp H`,_)})();let N=u.Fr.random(),P=u.Fr.random();await D,T.pi_a=f.add(T.pi_a,l.vk_alpha_1),T.pi_a=f.add(T.pi_a,f.timesFr(l.vk_delta_1,N)),await M,T.pi_b=p.add(T.pi_b,l.vk_beta_2),T.pi_b=p.add(T.pi_b,p.timesFr(l.vk_delta_2,P)),await A,O=f.add(O,l.vk_beta_1),O=f.add(O,f.timesFr(l.vk_delta_1,P)),await Promise.all([ee,S]),T.pi_c=f.add(T.pi_c,x),T.pi_c=f.add(T.pi_c,f.timesFr(T.pi_a,P)),T.pi_c=f.add(T.pi_c,f.timesFr(O,N)),T.pi_c=f.add(T.pi_c,f.timesFr(l.vk_delta_1,d.neg(d.mul(N,P))));let F=[];for(let e=1;e<=l.nPublic;e++){let t=y.slice(e*d.n8,e*d.n8+d.n8);F.push(L.fromRprLE(t))}return T.pi_a=f.toObject(f.toAffine(T.pi_a)),T.pi_b=p.toObject(p.toAffine(T.pi_b)),T.pi_c=f.toObject(f.toAffine(T.pi_c)),T.protocol=`groth16`,T.curve=u.name,await s.close(),await i.close(),T=ji(T),F=ji(F),{proof:T,publicSignals:F}}async function Pi(e,t,n,r,i){let a=e.Fr.n8,o=12+t.n8r,s=(r.byteLength-4)/o,c=new I(t.domainSize*a),l=new I(t.domainSize*a),u=new I(t.domainSize*a),d=[c,l];for(let t=0;te[Math.floor(n/t)].getUint32(n%t,!0)}else{let e=new DataView(r.buffer,r.byteOffset,r.byteLength);u=t=>e.getUint32(t,!0)}function d(e){let t=0,n=u(0);for(;te?n=r-1:im<1<<30?new Uint8Array(m):new I(m),g=h(),_=h(),v=h(),y=new Set,b=[];for(let t=0;t=o;)await Promise.race(y);i&&i.debug(`buildABCStream: ${t}/${a}`);let x=(async()=>{let t=r.slice(m,h),i=(h-m)/c,a=new Uint8Array(i*s),o=new Uint32Array(t.buffer,t.byteOffset,t.byteLength>>2),l=c>>2;if(n.buffer&&!(n.byteOffset&3)&&s===32){let e=new Uint32Array(n.buffer,n.byteOffset,n.byteLength>>2),t=new Uint32Array(a.buffer);for(let n=0;ny.delete(x));y.add(x),b.push(x)}return await Promise.all(b),[g,_,v]}async function Li(e,t,n,r,i,a){let o=65536,s=e.Fr.n8,c=Math.floor(n.byteLength/e.Fr.n8),l=[];for(let t=0;t{Ri(e)},t)}function Bi(e){let t=e.initialSize||1<<20,n=new Ki;return n.o=e,n.o.data=new Uint8Array(t),n.allocSize=t,n.totalSize=0,n.readOnly=!1,n.pos=0,n}function Vi(e){let t=new Ki;return t.o=e,t.allocSize=e.data.byteLength,t.totalSize=e.data.byteLength,t.readOnly=!0,t.pos=0,t}var Hi=new Uint8Array(4),Ui=new DataView(Hi.buffer),Wi=new Uint8Array(8),Gi=new DataView(Wi.buffer),Ki=class{constructor(){this.pageSize=16384}_resizeIfNeeded(e){if(e>this.allocSize){let t=Math.max(this.allocSize+(1<<20),Math.floor(this.allocSize*1.1),e),n=new Uint8Array(t);n.set(this.o.data),this.o.data=n,this.allocSize=t}}async write(e,t){let n=this;if(t===void 0&&(t=n.pos),this.readOnly)throw Error(`Writing a read only file`);this._resizeIfNeeded(t+e.byteLength),this.o.data.set(e.slice(),t),t+e.byteLength>this.totalSize&&(this.totalSize=t+e.byteLength),this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+r,n);e.set(a,t),this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(e,t){let n=this;Ui.setUint32(0,e,!0),await n.write(Hi,t)}async writeUBE32(e,t){let n=this;Ui.setUint32(0,e,!1),await n.write(Hi,t)}async writeULE64(e,t){let n=this;Gi.setUint32(0,e&4294967295,!0),Gi.setUint32(4,Math.floor(e/4294967296),!0),await n.write(Wi,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);this._resizeIfNeeded(e)}let r=new Uint8Array(t.o.data.buffer,n,this.totalSize-n),i=r.findIndex(e=>e===0),a=i!==-1,o=``;return a?(o=new TextDecoder().decode(r.slice(0,i)),t.pos=n+i+1):t.pos=n,o}},qi=1<<22;function Ji(e){let t=e.initialSize||0,n=new ea;n.o=e;let r=t?Math.floor((t-1)/qi)+1:0;n.o.data=[];for(let e=0;e0;){let t=i+a>qi?qi-i:a,o=e.slice(e.byteLength-a,e.byteLength-a+t);new Uint8Array(n.o.data[r].buffer,i,t).set(o),a-=t,r++,i=0}this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=Math.floor(r/qi),o=r%qi,s=n;for(;s>0;){let r=o+s>qi?qi-o:s,c=new Uint8Array(i.o.data[a].buffer,o,r);e.set(c,t+n-s),s-=r,a++,o=0}this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){}async discard(){}async writeULE32(e,t){let n=this;Zi.setUint32(0,e,!0),await n.write(Xi,t)}async writeUBE32(e,t){let n=this;Zi.setUint32(0,e,!1),await n.write(Xi,t)}async writeULE64(e,t){let n=this;$i.setUint32(0,e&4294967295,!0),$i.setUint32(4,Math.floor(e/4294967296),!0),await n.write(Qi,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);this._resizeIfNeeded(e)}let r=!1,i=``;for(;!r;){let e=Math.floor(n/qi),a=n%qi;if(t.o.data[e]===void 0)throw Error(`ERROR`);let o=Math.min(2048,t.o.data[e].length-a),s=new Uint8Array(t.o.data[e].buffer,a,o),c=s.findIndex(e=>e===0);r=c!==-1,r?(i+=new TextDecoder().decode(s.slice(0,c)),t.pos=e*qi+a+c+1):(i+=new TextDecoder().decode(s),t.pos=e*qi+a+s.length),n=t.pos}return i}};function ta(){throw Error(`File I/O is not supported in the browser`)}function na(e){return e instanceof Uint8Array?{type:`mem`,data:e}:(typeof e==`string`&&ta(),e)}async function ra(e){let t=await fetch(e).then(e=>e.arrayBuffer());return{type:`mem`,data:new Uint8Array(t)}}function ia(e,t,n){if(e.type===`file`&&ta(),e.type===`mem`)return t(e);if(e.type===`bigMem`)return n(e);throw Error(`Invalid FastFile type: `+e.type)}function aa(e){return ia(na(e),Bi,Ji)}async function oa(e){return e=typeof e==`string`?await ra(e):na(e),ia(e,Vi,Yi)}function sa(e){let t=[];return n(t,e),t;function n(e,t){if(Array.isArray(t))for(let r=0;r0;)n.unshift(0),e--}return n}async function da(e,t){let n,r,i;t||={};let a=1,o=0,s=0,c=!1;if(e instanceof WebAssembly.Instance)n=e,c=!0;else{let c=32767;if(t.memorySize&&(c=parseInt(t.memorySize),c<0))throw Error(`Invalid memory size`);let l=!1;for(;!l;)try{i=new WebAssembly.Memory({initial:c}),l=!0}catch(e){if(c<=1)throw e;console.warn(`Could not allocate `+c*1024*64+` bytes. This may cause severe instability. Trying with `+c*1024*64/2+` bytes`),c=Math.floor(c/2)}let f=await WebAssembly.compile(e),p=``,m=``;n=await WebAssembly.instantiate(f,{env:{memory:i},runtime:{printDebug:function(e){console.log(`printDebug:`,e)},exceptionHandler:function(e){let t;throw t=e===1?`Signal not found. `:e===2?`Too many signals set. `:e===3?`Signal already set. `:e===4?`Assert Failed. `:e===5?`Not enough memory. `:e===6?`Input signal array access exceeds the size. `:`Unknown error. `,console.error(`ERROR: `,e,p),Error(t+p)},printErrorMessage:function(){p+=u()+` +`},writeBufferMessage:function(){let e=u();e===` +`?(console.log(m),m=``):(m!==``&&(m+=` `),m+=e)},showSharedRWMemory:function(){let e=n.exports.getFieldNumLen32(),t=new Uint32Array(e);for(let r=0;r=2&&(o>=1||s>=7)){m!==``&&(m+=` `);let e=L.fromArray(t,4294967296).toString();m+=e}else console.log(L.fromArray(t,4294967296))},error:function(e,n,i,a,o,s){let c;throw c=e===7?d(n)+` `+r.getFr(a).toString()+` != `+r.getFr(o).toString()+` `+d(s):e===9?d(n)+` `+r.getFr(a).toString()+` `+d(o):e===5&&t.sym?d(n)+` `+t.sym.labelIdx2Name[o]:d(n)+` `+i+` `+a+` `+o+` `+s,console.log(`ERROR: `,e,c),Error(c)},log:function(e){console.log(r.getFr(e).toString())},logGetSignal:function(e,n){t.logGetSignal&&t.logGetSignal(e,r.getFr(n))},logSetSignal:function(e,n){t.logSetSignal&&t.logSetSignal(e,r.getFr(n))},logStartComponent:function(e){t.logStartComponent&&t.logStartComponent(e)},logFinishComponent:function(e){t.logFinishComponent&&t.logFinishComponent(e)}}})}typeof n.exports.getVersion==`function`&&(a=n.exports.getVersion()),typeof n.exports.getMinorVersion==`function`&&(o=n.exports.getMinorVersion()),typeof n.exports.getPatchVersion==`function`&&(s=n.exports.getPatchVersion());let l=t&&(t.sanityCheck||t.logGetSignal||t.logSetSignal||t.logStartComponent||t.logFinishComponent);if(a===2)r=new pa(n,l);else if(a===1){if(c)throw Error(`Loading code from WebAssembly instance is not supported for circom version 1`);r=new fa(i,n,l)}else throw Error(`Unsupported circom version: ${a}`);return r;function u(){let e=``,t=n.exports.getMessageChar();for(;t!==0;)e+=String.fromCharCode(t),t=n.exports.getMessageChar();return e}function d(e){let t=new Uint8Array(i.buffer),n=[];for(let r=0;t[e+r]>0;r++)n.push(t[e+r]);return String.fromCharCode.apply(null,n)}}var fa=class{constructor(e,t,n){this.memory=e,this.i32=new Uint32Array(e.buffer),this.instance=t,this.n32=(this.instance.exports.getFrLen()>>2)-2;let r=this.instance.exports.getPRawPrime(),i=Array(this.n32);for(let e=0;e>2)+e];this.prime=L.fromArray(i,4294967296),this.Fr=new et(this.prime),this.mask32=L.fromString(`FFFFFFFF`,16),this.NVars=this.instance.exports.getNVars(),this.n64=Math.floor((this.Fr.bitLength-1)/64)+1,this.R=this.Fr.e(L.shiftLeft(1,this.n64*64)),this.RInv=this.Fr.inv(this.R),this.sanityCheck=n}circom_version(){return 1}async _doCalculateWitness(e,t){this.instance.exports.init(this.sanityCheck||t?1:0);let n=this.allocInt(),r=this.allocFr();Object.keys(e).forEach(t=>{let i=la(t),a=parseInt(i.slice(0,8),16),o=parseInt(i.slice(8,16),16);try{this.instance.exports.getSignalOffset32(n,0,a,o)}catch{throw Error(`Signal ${t} is not an input of the circuit.`)}let s=this.getInt(n),c=sa(e[t]);for(let e=0;e>2]}setInt(e,t){this.i32[e>>2]=t}getFr(e){let t=this,n=e>>2;if(t.i32[n+1]&2147483648){let e=Array(t.n32);for(let r=0;r>2]=i,n.i32[(e>>2)+1]=0;return}n.i32[e>>2]=0,n.i32[(e>>2)+1]=2147483648;let a=L.toArray(t,4294967296);for(let t=0;t=0?n.i32[(e>>2)+2+t]=a[r]:n.i32[(e>>2)+2+t]=0}}},pa=class{constructor(e,t){this.instance=e,this.version=this.instance.exports.getVersion(),this.n32=this.instance.exports.getFieldNumLen32(),this.instance.exports.getRawPrime();let n=new Uint32Array(this.n32);for(let e=0;e{let n=la(t),i=parseInt(n.slice(0,8),16),a=parseInt(n.slice(8,16),16),o=sa(e[t]);if(typeof this.instance.exports.getInputSignalSize==`function`){let e=this.instance.exports.getInputSignalSize(i,a);if(e<0)throw Error(`Signal ${t} not found\n`);if(o.lengthe)throw Error(`Too many values for input signal ${t}\n`)}for(let e=0;eTa,fullProve:()=>_a,prove:()=>Mi,verify:()=>ya});function Da(e,t){let n=new DataView(t.buffer,t.byteOffset,t.byteLength),r=[];for(let e=0;e<8;e++)r[e]=n.getUint32(e*4);let i=new Ge(r);return e.G2.fromRng(i)}function Oa(e,t,n,r,i){let a=q.create({dkLen:64}),o=new Uint8Array([t]);a.update(o),a.update(n);let s=e.G1.toUncompressed(r);a.update(s);let c=e.G1.toUncompressed(i);return a.update(c),Da(e,a.digest())}function ka(e,t,n,r,i){return e.g1_s=t.G1.toAffine(t.G1.fromRng(i)),e.g1_sx=t.G1.toAffine(t.G1.timesFr(e.g1_s,e.prvKey)),e.g2_sp=t.G2.toAffine(Oa(t,n,r,e.g1_s,e.g1_sx)),e.g2_spx=t.G2.toAffine(t.G2.timesFr(e.g2_sp,e.prvKey)),e}function Aa(e,t,n){let r={tau:{},alpha:{},beta:{}};return r.tau.prvKey=e.Fr.fromRng(n),r.alpha.prvKey=e.Fr.fromRng(n),r.beta.prvKey=e.Fr.fromRng(n),ka(r.tau,e,0,t,n),ka(r.alpha,e,1,t,n),ka(r.beta,e,2,t,n),r}async function ja(e,t,n,r){r||=n,await e.writeULE32(1);let i=e.pos;await e.writeULE64(0),await e.writeULE32(t.F1.n64*8);let a=new Uint8Array(t.F1.n8);L.toRprLE(a,0,t.q,t.F1.n8),await e.write(a),await e.writeULE32(n),await e.writeULE32(r);let o=e.pos-i-8,s=e.pos;await e.writeULE64(o,i),e.pos=s}async function Ma(e,t){if(!t[1])throw Error(e.fileName+`: File has no header`);if(t[1].length>1)throw Error(e.fileName+`: File has more than one header`);e.pos=t[1][0].p;let n=await e.readULE32(),r=await e.read(n),i=await cr(L.fromRprLE(r));if(i.F1.n64*8!=n)throw Error(e.fileName+`: Invalid size`);let a=await e.readULE32(),o=await e.readULE32();if(e.pos-t[1][0].p!=t[1][0].size)throw Error(`Invalid PTau header size`);return{curve:i,power:a,ceremonyPower:o}}async function Na(e,t,n){return Pa(await e.read(t.F1.n8*2*6+t.F2.n8*2*3),0,t,n)}function Pa(e,t,n,r){let i={tau:{},alpha:{},beta:{}};return i.tau.g1_s=a(),i.tau.g1_sx=a(),i.alpha.g1_s=a(),i.alpha.g1_sx=a(),i.beta.g1_s=a(),i.beta.g1_sx=a(),i.tau.g2_spx=o(),i.alpha.g2_spx=o(),i.beta.g2_spx=o(),i;function a(){let i;return i=r?n.G1.fromRprLEM(e,t):n.G1.fromRprUncompressed(e,t),t+=n.G1.F.n8*2,i}function o(){let i;return i=r?n.G2.fromRprLEM(e,t):n.G2.fromRprUncompressed(e,t),t+=n.G2.F.n8*2,i}}function Fa(e,t,n,r,i){a(r.tau.g1_s),a(r.tau.g1_sx),a(r.alpha.g1_s),a(r.alpha.g1_sx),a(r.beta.g1_s),a(r.beta.g1_sx),o(r.tau.g2_spx),o(r.alpha.g2_spx),o(r.beta.g2_spx);async function a(r){i?n.G1.toRprLEM(e,t,r):n.G1.toRprUncompressed(e,t,r),t+=n.F1.n8*2}async function o(r){i?n.G2.toRprLEM(e,t,r):n.G2.toRprUncompressed(e,t,r),t+=n.F2.n8*2}return e}async function Ia(e,t,n,r){let i=new Uint8Array(t.F1.n8*2*6+t.F2.n8*2*3);Fa(i,0,t,n,r),await e.write(i)}async function La(e,t){let n={};n.tauG1=await c(),n.tauG2=await l(),n.alphaG1=await c(),n.betaG1=await c(),n.betaG2=await l(),n.key=await Na(e,t,!0),n.partialHash=await e.read(216),n.nextChallenge=await e.read(64),n.type=await e.readULE32();let r=new Uint8Array(t.G1.F.n8*2*6+t.G2.F.n8*2*3);Fa(r,0,t,n.key,!1);let i=$r(n.partialHash);i.update(r),n.responseHash=i.digest();let a=await e.readULE32(),o=e.pos,s=0;for(;e.pos-o1)throw Error(e.fileName+`: File has more than one contributions section`);e.pos=n[7][0].p;let r=await e.readULE32(),i=[];for(let n=0;n0){let t=new Uint8Array(a);await e.writeULE32(t.byteLength),await e.write(t)}else await e.writeULE32(0);async function o(n){t.G1.toRprLEM(r,0,n),await e.write(r)}async function s(n){t.G2.toRprLEM(i,0,n),await e.write(i)}}async function Ba(e,t,n){await e.writeULE32(7);let r=e.pos;await e.writeULE64(0),await e.writeULE32(n.length);for(let r=0;r0?d[d.length-1].nextChallenge:Va(l,u,a);let y=await Qn(n,`ptau`,1,i?7:2);await ja(y,l,u);let b=await _.read(64);if(Zr(o,v)&&(v=b,d[d.length-1].nextChallenge=v),!Zr(b,v))throw Error(`Wrong contribution. This contribution is not based on the previous hash`);let x=q.create({dkLen:64});x.update(b);let S=[],C;C=await E(_,y,`G1`,2,2**u*2-1,[1],`tauG1`),f.tauG1=C[0],C=await E(_,y,`G2`,3,2**u,[1],`tauG2`),f.tauG2=C[0],C=await E(_,y,`G1`,4,2**u,[0],`alphaG1`),f.alphaG1=C[0],C=await E(_,y,`G1`,5,2**u,[0],`betaG1`),f.betaG1=C[0],C=await E(_,y,`G2`,6,1,[0],`betaG2`),f.betaG2=C[0],f.partialHash=ei(x);let w=await _.read(l.F1.n8*2*6+l.F2.n8*2*3);f.key=Pa(w,0,l,!1),x.update(new Uint8Array(w));let T=x.digest();if(a&&a.info(J(T,`Contribution Response Hash imported: `)),i){let e=q.create({dkLen:64});e.update(T),await k(e,y,`G1`,2,2**u*2-1,`tauG1`,a),await k(e,y,`G2`,3,2**u,`tauG2`,a),await k(e,y,`G1`,4,2**u,`alphaTauG1`,a),await k(e,y,`G1`,5,2**u,`betaTauG1`,a),await k(e,y,`G2`,6,1,`betaG2`,a),f.nextChallenge=e.digest(),a&&a.info(J(f.nextChallenge,`Next Challenge Hash: `))}else f.nextChallenge=o;return d.push(f),await Ba(y,l,d),await _.close(),await y.close(),await s.close(),f.nextChallenge;async function E(e,t,n,r,a,o,s){return i?await D(e,t,n,r,a,o,s):await O(e,t,n,r,a,o,s)}async function D(e,t,n,r,i,o,s){let c=l[n],u=c.F.n8,d=c.F.n8*2,f=[];await B(t,r);let p=Math.floor((1<<24)/d);S[r]=t.pos;for(let n=0;n=n&&t=t&&i1?c[c.length-2]:l;let d=c[c.length-1];if(t&&t.debug(`Validating contribution #`+c[c.length-1].id),!await qa(a,d,u,t))return!1;let f=q.create({dkLen:64});f.update(d.responseHash),t&&t.debug(`Verifying powers in tau*G1 section`);let p=await x(2,`G1`,`tauG1`,2**o*2-1,[0,1],t);if(n=await Ka(a,p.R1,p.R2,a.G2.g,d.tauG2),n!==!0)return t&&t.error(`tauG1 section. Powers do not match`),!1;if(!a.G1.eq(a.G1.g,p.singularPoints[0]))return t&&t.error(`First element of tau*G1 section must be the generator`),!1;if(!a.G1.eq(d.tauG1,p.singularPoints[1]))return t&&t.error(`Second element of tau*G1 section does not match the one in the contribution section`),!1;t&&t.debug(`Verifying powers in tau*G2 section`);let m=await x(3,`G2`,`tauG2`,2**o,[0,1],t);if(n=await Ka(a,a.G1.g,d.tauG1,m.R1,m.R2),n!==!0)return t&&t.error(`tauG2 section. Powers do not match`),!1;if(!a.G2.eq(a.G2.g,m.singularPoints[0]))return t&&t.error(`First element of tau*G2 section must be the generator`),!1;if(!a.G2.eq(d.tauG2,m.singularPoints[1]))return t&&t.error(`Second element of tau*G2 section does not match the one in the contribution section`),!1;t&&t.debug(`Verifying powers in alpha*tau*G1 section`);let h=await x(4,`G1`,`alphatauG1`,2**o,[0],t);if(n=await Ka(a,h.R1,h.R2,a.G2.g,d.tauG2),n!==!0)return t&&t.error(`alphaTauG1 section. Powers do not match`),!1;if(!a.G1.eq(d.alphaG1,h.singularPoints[0]))return t&&t.error(`First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section`),!1;t&&t.debug(`Verifying powers in beta*tau*G1 section`);let g=await x(5,`G1`,`betatauG1`,2**o,[0],t);if(n=await Ka(a,g.R1,g.R2,a.G2.g,d.tauG2),n!==!0)return t&&t.error(`betaTauG1 section. Powers do not match`),!1;if(!a.G1.eq(d.betaG1,g.singularPoints[0]))return t&&t.error(`First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section`),!1;let _=await b(t);if(!a.G2.eq(d.betaG2,_))return t&&t.error(`betaG2 element in betaG2 section does not match the one in the contribution section`),!1;let v=f.digest();if(o==s&&!Zr(v,d.nextChallenge))return t&&t.error(`Hash of the values does not match the next challenge of the last contributor in the contributions section`),!1;t&&t.info(J(v,`Next challenge hash: `)),y(d,u);for(let e=c.length-2;e>=0;e--){let n=c[e],r=e>0?c[e-1]:l;if(!await qa(a,n,r,t))return!1;y(n,r,t)}if(t&&t.info(`-----------------------------------------------------`),!i[12]||!i[13]||!i[14]||!i[15])t&&t.warn(`this file does not contain phase2 precalculated values. Please run: + snarkjs "powersoftau preparephase2" to prepare this file to be used in the phase2 ceremony.`);else{let e;if(e=await S(`G1`,2,12,`tauG1`,t),!e||(e=await S(`G2`,3,13,`tauG2`,t),!e)||(e=await S(`G1`,4,14,`alphaTauG1`,t),!e)||(e=await S(`G1`,5,15,`betaTauG1`,t),!e))return!1}return await r.close(),t&&t.info(`Powers of Tau Ok!`),!0;function y(e,n){if(!t)return;t.info(`-----------------------------------------------------`),t.info(`Contribution #${e.id}: ${e.name||``}`),t.info(J(e.nextChallenge,`Next Challenge: `));let r=new Uint8Array(a.G1.F.n8*2*6+a.G2.F.n8*2*3);Fa(r,0,a,e.key,!1);let i=$r(e.partialHash);i.update(r);let o=i.digest();t.info(J(o,`Response Hash:`)),t.info(J(n.nextChallenge,`Response Hash:`)),e.type==1&&(t.info(`Beacon generator: ${li(e.beaconHash)}`),t.info(`Beacon iterations Exp: ${e.numIterationsExp}`))}async function b(e){let t=a.G2,n=t.F.n8*2,o=new Uint8Array(n);if(!i[6])throw e.error(`File has no BetaG2 section`),Error(`File has no BetaG2 section`);if(i[6].length>1)throw e.error(`File has no BetaG2 section`),Error(`File has more than one GetaG2 section`);r.pos=i[6][0].p;let s=await r.read(n),c=t.fromRprLEM(s);return t.toRprUncompressed(o,0,c),f.update(o),c}async function x(e,t,n,o,s,c){let l=65536,u=a[t],d=u.F.n8*2;await H(r,i,e);let p=[],m=u.zero,h=u.zero,g=u.zero;for(let e=0;e0){let e=u.fromRprLEM(i,0),t=ai(ri(4),0);m=u.add(m,u.timesScalar(g,t)),h=u.add(h,u.timesScalar(e,t))}let v=await u.multiExpAffine(i.slice(0,(t-1)*d),_),y=await u.multiExpAffine(i.slice(d),_);m=u.add(m,v),h=u.add(h,y),g=u.fromRprLEM(i,(t-1)*d);for(let n=0;n=e&&r1;)l/=2,u+=1;if(2**u!=c)throw Error(`Invalid file size`);i&&i.debug(`Power to tau size: `+u);let d=await oi(r),f=await aa(n),p=q.create({dkLen:64});for(let e=0;e{i.debug(t+`.g1_s: `+e.G1.toString(g[t].g1_s,16)),i.debug(t+`.g1_sx: `+e.G1.toString(g[t].g1_sx,16)),i.debug(t+`.g2_sp: `+e.G2.toString(g[t].g2_sp,16)),i.debug(t+`.g2_spx: `+e.G2.toString(g[t].g2_spx,16)),i.debug(``)});let _=q.create({dkLen:64});await f.write(h),_.update(h),await Xa(a,f,_,e,`G1`,2**u*2-1,e.Fr.one,g.tau.prvKey,`COMPRESSED`,`tauG1`,i),await Xa(a,f,_,e,`G2`,2**u,e.Fr.one,g.tau.prvKey,`COMPRESSED`,`tauG2`,i),await Xa(a,f,_,e,`G1`,2**u,g.alpha.prvKey,g.tau.prvKey,`COMPRESSED`,`alphaTauG1`,i),await Xa(a,f,_,e,`G1`,2**u,g.beta.prvKey,g.tau.prvKey,`COMPRESSED`,`betaTauG1`,i),await Xa(a,f,_,e,`G2`,1,g.beta.prvKey,g.tau.prvKey,`COMPRESSED`,`betaTauG2`,i);let v=new Uint8Array(e.F1.n8*2*6+e.F2.n8*2*3);Fa(v,0,e,g,!1),await f.write(v),_.update(v);let y=_.digest();i&&i.info(J(y,`Contribution Response Hash: `)),await f.close(),await a.close()}async function Qa(e,t,n,r,i,a){let o=ci(r);if(o.byteLength==0||o.byteLength*2!=r.length)return a&&a.error(`Invalid Beacon Hash. (It must be a valid hexadecimal sequence)`),!1;if(o.length>=256)return a&&a.error(`Maximum length of beacon hash is 255 bytes`),!1;if(i=parseInt(i),i<10||i>63)return a&&a.error(`Invalid numIterationsExp. (Must be between 10 and 63)`),!1;let{fd:s,sections:c}=await z(e,`ptau`,1),{curve:l,power:u,ceremonyPower:d}=await Ma(s,c);if(u!=d)return a&&a.error(`This file has been reduced. You cannot contribute into a reduced file.`),!1;c[12]&&a&&a.warn(`Contributing into a file that has phase2 calculated. You will have to prepare phase2 again.`);let f=await Ra(s,l,c),p={name:n,type:1,numIterationsExp:i,beaconHash:o},m;m=f.length>0?f[f.length-1].nextChallenge:Va(l,u,a),p.key=await Ha(l,m,o,i);let h=q.create({dkLen:64});h.update(m);let g=await Qn(t,`ptau`,1,7);await ja(g,l,u);let _=[],v;v=await S(2,`G1`,2**u*2-1,l.Fr.e(1),p.key.tau.prvKey,`tauG1`,a),p.tauG1=v[1],v=await S(3,`G2`,2**u,l.Fr.e(1),p.key.tau.prvKey,`tauG2`,a),p.tauG2=v[1],v=await S(4,`G1`,2**u,p.key.alpha.prvKey,p.key.tau.prvKey,`alphaTauG1`,a),p.alphaG1=v[0],v=await S(5,`G1`,2**u,p.key.beta.prvKey,p.key.tau.prvKey,`betaTauG1`,a),p.betaG1=v[0],v=await S(6,`G2`,1,p.key.beta.prvKey,p.key.tau.prvKey,`betaTauG2`,a),p.betaG2=v[0],p.partialHash=ei(h);let y=new Uint8Array(l.F1.n8*2*6+l.F2.n8*2*3);Fa(y,0,l,p.key,!1),h.update(new Uint8Array(y));let b=h.digest();a&&a.info(J(b,`Contribution Response Hash imported: `));let x=q.create({dkLen:64});return x.update(b),await C(g,`G1`,2,2**u*2-1,`tauG1`,a),await C(g,`G2`,3,2**u,`tauG2`,a),await C(g,`G1`,4,2**u,`alphaTauG1`,a),await C(g,`G1`,5,2**u,`betaTauG1`,a),await C(g,`G2`,6,1,`betaG2`,a),p.nextChallenge=x.digest(),a&&a.info(J(p.nextChallenge,`Next Challenge Hash: `)),f.push(p),await Ba(g,l,f),await s.close(),await g.close(),b;async function S(e,t,n,r,i,a,o){let u=[];s.pos=c[e][0].p,await B(g,e),_[e]=g.pos;let d=l[t],f=d.F.n8*2,p=Math.floor((1<<20)/f),m=r;for(let e=0;e0?u[u.length-1].nextChallenge:Va(s,c,i),d.key=Aa(s,f,p);let m=q.create({dkLen:64});m.update(f);let h=await Qn(t,`ptau`,1,7);await ja(h,s,c);let g=[],_;_=await x(2,`G1`,2**c*2-1,s.Fr.e(1),d.key.tau.prvKey,`tauG1`),d.tauG1=_[1],_=await x(3,`G2`,2**c,s.Fr.e(1),d.key.tau.prvKey,`tauG2`),d.tauG2=_[1],_=await x(4,`G1`,2**c,d.key.alpha.prvKey,d.key.tau.prvKey,`alphaTauG1`),d.alphaG1=_[0],_=await x(5,`G1`,2**c,d.key.beta.prvKey,d.key.tau.prvKey,`betaTauG1`),d.betaG1=_[0],_=await x(6,`G2`,1,d.key.beta.prvKey,d.key.tau.prvKey,`betaTauG2`),d.betaG2=_[0],d.partialHash=ei(m);let v=new Uint8Array(s.F1.n8*2*6+s.F2.n8*2*3);Fa(v,0,s,d.key,!1),m.update(new Uint8Array(v));let y=m.digest();i&&i.info(J(y,`Contribution Response Hash imported: `));let b=q.create({dkLen:64});return b.update(y),await S(h,`G1`,2,2**c*2-1,`tauG1`),await S(h,`G2`,3,2**c,`tauG2`),await S(h,`G1`,4,2**c,`alphaTauG1`),await S(h,`G1`,5,2**c,`betaTauG1`),await S(h,`G2`,6,1,`betaG2`),d.nextChallenge=b.digest(),i&&i.info(J(d.nextChallenge,`Next Challenge Hash: `)),u.push(d),await Ba(h,s,u),await a.close(),await h.close(),y;async function x(e,t,n,r,c,l){let u=[];a.pos=o[e][0].p,await B(h,e),g[e]=h.pos;let d=s[t],f=d.F.n8*2,p=Math.floor((1<<20)/f),_=r;for(let e=0;eQa,challengeContribute:()=>Za,contribute:()=>$a,convert:()=>no,exportChallenge:()=>Wa,exportJson:()=>ro,importResponse:()=>Ga,newAccumulator:()=>Ua,preparePhase2:()=>eo,truncate:()=>to,verify:()=>Ja});function ao(e,t,n){for(let t=0;t{let r=``;return Object.keys(n).forEach(i=>{let a=t.varIdx2Name[i];a==`one`&&(a=`1`);let o=e.curve.Fr.toString(n[i]);o==`1`&&(o=``),o==`-1`&&(o=`-`),r!=``&&o[0]!=`-`&&(o=`+`+o),r!=``&&(o=` `+o),r=r+o+a}),r},a=`[ ${i(r[0])} ] * [ ${i(r[1])} ] - [ ${i(r[2])} ] = 0`;n&&n.info(a)}}var oo=262144,so={get:function(e,t){return isNaN(t)?e[t]:e.getElement(t)},set:function(e,t,n){return isNaN(t)?(e[t]=n,!0):e.setElement(t,n)}},co=class{constructor(e){this.length=e||0,this.arr=Array(oo);for(let t=0;t=this.length&&(this.length=e+1),!0}getKeys(){let e=new lo;for(let t=0;t{t.pendingLoads.push({page:e,resolve:n,reject:r})});return t.__statusPage(`After Load request: `,e),n}__statusPage(e,t){let n=[],r=this;if(!r.logHistory)return;n.push(`==`+e+` `+t);let i=``;for(let e=0;e `+t.history[e][n][r])}_triggerLoad(){let e=this;if(e.reading||e.pendingLoads.length==0)return;let t=Object.keys(e.pages),n=[];for(let r=0;r0&&(e.pages[e.pendingLoads[0].page]!==void 0||r>0||n.length>0);){let t=e.pendingLoads.shift();if(e.pages[t.page]!==void 0){e.pages[t.page].pendingOps++;let r=n.indexOf(t.page);r>=0&&n.splice(r,1),e.pages[t.page].loading?e.pages[t.page].loading.push(t):t.resolve(),e.__statusPage(`After Load (cached): `,t.page)}else{if(r)r--;else{let t=n.shift();e.__statusPage(`Before Unload: `,t),e.avBuffs.unshift(e.pages[t]),delete e.pages[t],e.__statusPage(`After Unload: `,t)}t.page>=e.totalPages?(e.pages[t.page]=a(),t.resolve(),e.__statusPage(`After Load (new): `,t.page)):(e.reading=!0,e.pages[t.page]=a(),e.pages[t.page].loading=[t],i.push(e.fd.read(e.pages[t.page].buff,0,e.pageSize,t.page*e.pageSize).then(n=>{e.pages[t.page].size=n.bytesRead;let r=e.pages[t.page].loading;delete e.pages[t.page].loading;for(let e=0;e{t.reject(e)})),e.__statusPage(`After Load (loading): `,t.page))}}Promise.all(i).then(()=>{e.reading=!1,e.pendingLoads.length>0&&setImmediate(e._triggerLoad.bind(e)),e._tryClose()});function a(){if(e.avBuffs.length>0){let t=e.avBuffs.shift();return t.dirty=!1,t.pendingOps=1,t.size=0,t}else return{dirty:!1,buff:new Uint8Array(e.pageSize),pendingOps:1,size:0}}}_triggerWrite(){let e=this;if(e.writing)return;let t=Object.keys(e.pages),n=[];for(let r=0;r{i.writing=!1},t=>{console.log(`ERROR Writing: `+t),e.error=t,e._tryClose()})))}e.writing&&Promise.all(n).then(()=>{e.writing=!1,setImmediate(e._triggerWrite.bind(e)),e._tryClose(),e.pendingLoads.length>0&&setImmediate(e._triggerLoad.bind(e))})}_getDirtyPage(){for(let e in this.pages)if(this.pages[e].dirty)return e;return-1}async write(e,t){if(e.byteLength==0)return;let n=this;if(t===void 0&&(t=n.pos),n.pos=t+e.byteLength,n.totalSize0;){await a[o-r];let t=s+c>n.pageSize?n.pageSize-s:c,i=e.slice(e.byteLength-c,e.byteLength-c+t);new Uint8Array(n.pages[o].buff.buffer,s,t).set(i),n.pages[o].dirty=!0,n.pages[o].pendingOps--,n.pages[o].size=Math.max(s+t,n.pages[o].size),o>=n.totalPages&&(n.totalPages=o+1),c-=t,o++,s=0,n.writing||setImmediate(n._triggerWrite.bind(n))}}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}async readToBuffer(e,t,n,r){if(n==0)return;let i=this;if(n>i.pageSize*i.maxPagesLoaded*.8){let e=Math.floor(n*1.1);this.maxPagesLoaded=Math.floor(e/i.pageSize)+1}if(r===void 0&&(r=i.pos),i.pos=r+n,i.pendingClose)throw Error(`Reading a closing file`);let a=Math.floor(r/i.pageSize),o=Math.floor((r+n-1)/i.pageSize),s=[];for(let e=a;e<=o;e++)s.push(i._loadPage(e));i._triggerLoad();let c=a,l=r%i.pageSize,u=r+n>i.totalSize?n-(r+n-i.totalSize):n;for(;u>0;){await s[c-a],i.__statusPage(`After Await (read): `,c);let r=l+u>i.pageSize?i.pageSize-l:u,o=new Uint8Array(i.pages[c].buff.buffer,i.pages[c].buff.byteOffset+l,r);e.set(o,t+n-u),i.pages[c].pendingOps--,i.__statusPage(`After Op done: `,c),u-=r,c++,l=0,i.pendingLoads.length>0&&setImmediate(i._triggerLoad.bind(i))}this.pos=r+n}_tryClose(){let e=this;e.pendingClose&&(e.error&&e.pendingCloseReject(e.error),!(e._getDirtyPage()>=0||e.writing||e.reading||e.pendingLoads.length>0)&&e.pendingClose())}close(){let e=this;if(e.pendingClose)throw Error(`Closing the file twice`);return new Promise((t,n)=>{e.pendingClose=t,e.pendingCloseReject=n,e._tryClose()}).then(()=>{e.fd.close()},t=>{throw e.fd.close(),t})}async discard(){await this.close(),await qr.promises.unlink(this.fileName)}async writeULE32(e,t){let n=this,r=new Uint8Array(4);new DataView(r.buffer).setUint32(0,e,!0),await n.write(r,t)}async writeUBE32(e,t){let n=this,r=new Uint8Array(4);new DataView(r.buffer).setUint32(0,e,!1),await n.write(r,t)}async writeULE64(e,t){let n=this,r=new Uint8Array(8),i=new DataView(r.buffer);i.setUint32(0,e&4294967295,!0),i.setUint32(4,Math.floor(e/4294967296),!0),await n.write(r,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this;if(t.pendingClose)throw Error(`Reading a closing file`);let n=e===void 0?t.pos:e,r=Math.floor(n/t.pageSize),i=!1,a=``;for(;!i;){let e=t._loadPage(r);t._triggerLoad(),await e,t.__statusPage(`After Await (read): `,r);let o=n%t.pageSize,s=new Uint8Array(t.pages[r].buff.buffer,t.pages[r].buff.byteOffset+o,t.pageSize-o),c=s.findIndex(e=>e===0);i=c!==-1,i?(a+=new TextDecoder().decode(s.slice(0,c)),t.pos=r*this.pageSize+o+c+1):(a+=new TextDecoder().decode(s),t.pos=r*this.pageSize+o+s.length),t.pages[r].pendingOps--,t.__statusPage(`After Op done: `,r),n=t.pos,r++,t.pendingLoads.length>0&&setImmediate(t._triggerLoad.bind(t))}return a}};function po(e){let t=new vo;return t.o=e,t.allocSize=e.data.byteLength,t.totalSize=e.data.byteLength,t.readOnly=!0,t.pos=0,t}var mo=new Uint8Array(4),ho=new DataView(mo.buffer),go=new Uint8Array(8),_o=new DataView(go.buffer),vo=class{constructor(){this.pageSize=16384}_resizeIfNeeded(e){if(e>this.allocSize){let t=Math.max(this.allocSize+(1<<20),Math.floor(this.allocSize*1.1),e),n=new Uint8Array(t);n.set(this.o.data),this.o.data=n,this.allocSize=t}}async write(e,t){let n=this;if(t===void 0&&(t=n.pos),this.readOnly)throw Error(`Writing a read only file`);this._resizeIfNeeded(t+e.byteLength),this.o.data.set(e.slice(),t),t+e.byteLength>this.totalSize&&(this.totalSize=t+e.byteLength),this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+r,n);e.set(a,t),this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(e,t){let n=this;ho.setUint32(0,e,!0),await n.write(mo,t)}async writeUBE32(e,t){let n=this;ho.setUint32(0,e,!1),await n.write(mo,t)}async writeULE64(e,t){let n=this;_o.setUint32(0,e&4294967295,!0),_o.setUint32(4,Math.floor(e/4294967296),!0),await n.write(go,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);this._resizeIfNeeded(e)}let r=new Uint8Array(t.o.data.buffer,n,this.totalSize-n),i=r.findIndex(e=>e===0),a=i!==-1,o=``;return a?(o=new TextDecoder().decode(r.slice(0,i)),t.pos=n+i+1):t.pos=n,o}},yo=1<<22;function bo(e){let t=new To;return t.o=e,t.totalSize=(e.data.length-1)*yo+e.data[e.data.length-1].byteLength,t.readOnly=!0,t.pos=0,t}var xo=new Uint8Array(4),So=new DataView(xo.buffer),Co=new Uint8Array(8),wo=new DataView(Co.buffer),To=class{constructor(){this.pageSize=16384}_resizeIfNeeded(e){if(e<=this.totalSize)return;if(this.readOnly)throw Error(`Reading out of file bounds`);let t=Math.floor((e-1)/yo)+1;for(let n=Math.max(this.o.data.length-1,0);n0;){let t=i+a>yo?yo-i:a,o=e.slice(e.byteLength-a,e.byteLength-a+t);new Uint8Array(n.o.data[r].buffer,i,t).set(o),a-=t,r++,i=0}this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=Math.floor(r/yo),o=r%yo,s=n;for(;s>0;){let r=o+s>yo?yo-o:s,c=new Uint8Array(i.o.data[a].buffer,o,r);e.set(c,t+n-s),s-=r,a++,o=0}this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){}async discard(){}async writeULE32(e,t){let n=this;So.setUint32(0,e,!0),await n.write(xo,t)}async writeUBE32(e,t){let n=this;So.setUint32(0,e,!1),await n.write(xo,t)}async writeULE64(e,t){let n=this;wo.setUint32(0,e&4294967295,!0),wo.setUint32(4,Math.floor(e/4294967296),!0),await n.write(Co,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);this._resizeIfNeeded(e)}let r=!1,i=``;for(;!r;){let e=Math.floor(n/yo),a=n%yo;if(t.o.data[e]===void 0)throw Error(`ERROR`);let o=Math.min(2048,t.o.data[e].length-a),s=new Uint8Array(t.o.data[e].buffer,a,o),c=s.findIndex(e=>e===0);r=c!==-1,r?(i+=new TextDecoder().decode(s.slice(0,c)),t.pos=e*yo+a+c+1):(i+=new TextDecoder().decode(s),t.pos=e*yo+a+s.length),n=t.pos}return i}};async function Eo(e,t,n){if(e instanceof Uint8Array&&(e={type:`mem`,data:e}),typeof e==`string`&&(e={type:`mem`,data:await fetch(e).then(function(e){return e.arrayBuffer()}).then(function(e){return new Uint8Array(e)})}),e.type==`file`)return await uo(e.fileName,0,e.cacheSize,e.pageSize);if(e.type==`mem`)return await po(e);if(e.type==`bigMem`)return await bo(e);throw Error(`Invalid FastFile type: `+e.type)}async function Do(e,t,n,r,i){let a=await Eo(e,r,i),o=await a.read(4),s=``;for(let e=0;e<4;e++)s+=String.fromCharCode(o[e]);if(s!=t)throw Error(e+`: Invalid File format`);if(await a.readULE32()>n)throw Error(`Version not supported`);let c=await a.readULE32(),l=[];for(let e=0;e1)throw Error(e.fileName+`: Section Duplicated `+n);e.pos=t[n][0].p,e.readingSection=t[n][0]}async function ko(e,t){if(e.readingSection===void 0)throw Error(`Not reading a section`);if(!t&&e.pos-e.readingSection.p!=e.readingSection.size)throw Error(`Invalid section size reading`);delete e.readingSection}async function Ao(e,t,n){let r=await e.read(t,n);return L.fromRprLE(r,0,t)}async function jo(e,t,n,r,i){if(r=r===void 0?0:r,i=i===void 0?t[n][0].size-r:i,r+i>t[n][0].size)throw Error(`Reading out of the range of the section`);let a;return a=i<1<<30?new Uint8Array(i):new I(i),await e.readToBuffer(a,0,i,t[n][0].p+r),a}async function Mo(e,t,n){let r;r=typeof n==`object`?n:n===void 0?{singleThread:!1}:{singleThread:n};let i={};if(await Oo(e,t,1),i.n8=await e.readULE32(),i.prime=await Ao(e,i.n8),r.F){if(r.F.p!=i.prime)throw Error(`Different Prime`);i.F=r.F}else if(r.getFieldFromPrime)i.F=await r.getFieldFromPrime(i.prime,r.singleThread);else if(r.getCurveFromPrime)i.curve=await r.getCurveFromPrime(i.prime,r.singleThread),i.F=i.curve.Fr;else try{i.curve=await yn(i.prime,r.singleThread),i.F=i.curve.Fr}catch{i.F=new et(i.prime)}return i.nVars=await e.readULE32(),i.nOutputs=await e.readULE32(),i.nPubInputs=await e.readULE32(),i.nPrvInputs=await e.readULE32(),i.nLabels=await e.readULE64(),i.nConstraints=await e.readULE32(),i.useCustomGates=t[4]!==void 0&&t[4]!==null&&t[5]!==void 0&&t[5]!==null,await ko(e),i}async function No(e,t,n,r,i){let a;a=typeof r==`object`?r:r===void 0?{}:{logger:r,loggerCtx:i};let o=await jo(e,t,2),s=0,c;c=n.nConstraints>1<<20?new lo:[];for(let e=0;e1<<20?new lo:[];for(let e=0;e1<<20?new lo:[];for(let e=0;eHo,info:()=>Vo,print:()=>ao});async function Wo(e){let t={labelIdx2Name:[`one`],varIdx2Name:[`one`],componentIdx2Name:[]},n=await oa(e),r=await n.read(n.totalSize),i=new TextDecoder(`utf-8`).decode(r).split(` +`);for(let e=0;e `+t.toString())}),i.trigger&&(u||=await Wo(r),l.logStartComponent=function(e){a&&a.info(`START: `+u.componentIdx2Name[e])},l.logFinishComponent=function(e){a&&a.info(`FINISH: `+u.componentIdx2Name[e])}),l.sym=u;let d=await da(c,l),f=await d.calculateWitness(o,!0),p=await Qn(n,`wtns`,2,2);await Di(p,f,d.prime),await p.close()}async function qo(e){return await Ai(e)}async function Jo(e,t,n){n&&n.info(`WITNESS CHECKING STARTED`),n&&n.info(`> Reading r1cs file`);let{fd:r,sections:i}=await z(e,`r1cs`,1,1<<22,1<<24),a=await Fo(r,i,{loadConstraints:!1,loadCustomGates:!1});n&&n.info(`> Reading witness file`);let{fd:o,sections:s}=await z(t,`wtns`,2,1<<22,1<<24),c=await ki(o,s);if(!L.eq(a.prime,c.q))throw Error(`Curve of the witness does not match the curve of the proving key`);let l=await G(o,s,2);await o.close();let u=(await sr(a.prime)).Fr,d=u.n8,f=await G(r,i,2);n&&(n.info(`----------------------------`),n.info(` WITNESS CHECK`),n.info(` Curve: ${a.curve.name}`),n.info(` Vars (wires): ${a.nVars}`),n.info(` Outputs: ${a.nOutputs}`),n.info(` Public Inputs: ${a.nPubInputs}`),n.info(` Private Inputs: ${a.nPrvInputs}`),n.info(` Labels: ${a.nLabels}`),n.info(` Constraints: ${a.nConstraints}`),n.info(` Custom Gates: ${a.useCustomGates}`),n.info(`----------------------------`)),n&&n.info(`> Checking witness correctness`);let p=0,m=!0;for(let e=0;e{let r=_(n),i=e[n];t=u.add(t,u.mul(r,i))}),t}function g(){let e={},t=f.slice(p,p+4);p+=4;let n=new DataView(t.buffer).getUint32(0,!0),r=f.slice(p,p+(4+a.n8)*n);p+=(4+a.n8)*n;let i=new DataView(r.buffer);for(let t=0;tha,check:()=>Jo,debug:()=>Ko,exportJson:()=>qo}),Xo=262144,Zo={get:function(e,t){return isNaN(t)?e[t]:e.getElement(t)},set:function(e,t,n){return isNaN(t)?(e[t]=n,!0):e.setElement(t,n)}},Qo=class{constructor(e){this.length=e||0,this.arr=Array(Xo);for(let t=0;t=this.length&&(this.length=e+1),!0}getKeys(){let e=new $o;for(let t=0;tc)return r&&r.error(`circuit too big for this power of tau ceremony. ${d.nConstraints}*2 > 2**${c}`),-1;if(!o[12])return r&&r.error(`Powers of tau is not prepared.`),-1;let g=d.nOutputs+d.nPubInputs,_=2**h;await B(f,1),await f.writeULE32(1),await V(f),await B(f,2);let v=s.q,y=(Math.floor((L.bitLength(v)-1)/64)+1)*8,b=s.r,x=(Math.floor((L.bitLength(b)-1)/64)+1)*8,S=L.mod(L.shl(1,x*8),b),C=s.Fr.e(L.mod(L.mul(S,S),b));await f.writeULE32(y),await $n(f,v,y),await f.writeULE32(x),await $n(f,b,x),await f.writeULE32(d.nVars),await f.writeULE32(g),await f.writeULE32(_);let w;w=await a.read(p,o[4][0].p),await f.write(w),w=await s.G1.batchLEMtoU(w),i.update(w);let T;T=await a.read(p,o[5][0].p),await f.write(T),T=await s.G1.batchLEMtoU(T),i.update(T);let E;E=await a.read(m,o[6][0].p),await f.write(E),E=await s.G2.batchLEMtoU(E),i.update(E);let D=new Uint8Array(p);s.G1.toRprLEM(D,0,s.G1.g);let O=new Uint8Array(m);s.G2.toRprLEM(O,0,s.G2.g);let k=new Uint8Array(p);s.G1.toRprUncompressed(k,0,s.G1.g);let A=new Uint8Array(m);s.G2.toRprUncompressed(A,0,s.G2.g),await f.write(O),await f.write(D),await f.write(O),i.update(A),i.update(k),i.update(A),await V(f),r&&r.info(me()),r&&r.info(`Reading r1cs`);let j=await G(l,u,2);await l.close();let M=new $o(d.nVars),ee=new $o(d.nVars),N=new $o(d.nVars),P=new $o(d.nVars-g-1),F=Array(g+1);r&&r.info(me()),r&&r.info(`Reading tauG1`);let te=await G(a,o,12,(_-1)*p,_*p);r&&r.info(`Reading tauG2`);let ne=await G(a,o,13,(_-1)*m,_*m);r&&r.info(`Reading alphatauG1`);let re=await G(a,o,14,(_-1)*p,_*p);r&&r.info(`Reading betatauG1`);let ie=await G(a,o,15,(_-1)*p,_*p);r&&r.info(me()),r&&r.info(`processConstraints`),await se(),r&&r.info(me()),r&&r.info(`composeAndWritePoints`),await ce(3,`G1`,F,`IC`),F=null,r&&r.info(me()),r&&r.info(`writeHs`),await oe(),r&&r.info(me()),r&&r.info(`hashHPoints`),await ue(),r&&r.info(me()),r&&r.info(`composeAndWritePoints 8 G1 C`),await ce(8,`G1`,P,`C`),P=null,r&&r.info(me()),r&&r.info(`composeAndWritePoints 5 G1 A`),await ce(5,`G1`,M,`A`),M=null,r&&r.info(me()),r&&r.info(`composeAndWritePoints 6 G1 B1`),await ce(6,`G1`,ee,`B1`),ee=null,r&&r.info(me()),r&&r.info(`composeAndWritePoints 7 G2 B2`),await ce(7,`G2`,N,`B2`),N=null,r&&r.info(me()),r&&r.info(`Contributions section`);let ae=i.digest();return await B(f,10),await f.write(ae),await f.writeULE32(0),await V(f),r&&r.info(J(ae,`Circuit hash: `)),await f.close(),await a.close(),ae;async function oe(){await B(f,9);let e=new I(_*p);if(h=0?s.Fr.fromRprLE(j.slice(r[3],r[3]+s.Fr.n8),0):s.Fr.fromRprLE(n,0);let a=s.Fr.mul(i,C);s.Fr.toRprLE(e,12,a),c.set(e,u),u+=e.length}}async function ce(e,t,n,a){let o=32768,c=s[t];pe(n.length),await B(f,e);let l=[],u=0;for(;u(r&&r.debug(`Writing points end ${a}: ${d}/${n.length}`),e))),u+=i,e++}let d=await Promise.all(l);for(let e=0;e32768?(m=new I(p*a),h=new I(p*s.Fr.n8)):(m=new Uint8Array(p*a),h=new Uint8Array(p*s.Fr.n8));let g=0,_=0,v=[te,ne,re,ie],y=new Uint8Array(s.Fr.n8);s.Fr.toRprLE(y,0,s.Fr.e(1));let b=0;for(let e=0;e=0?h.set(j.slice(t[e][i][2],t[e][i][2]+s.Fr.n8),b*s.Fr.n8):h.set(y,b*s.Fr.n8),b++;if(t.length>1){let e=[];e.push({cmd:`ALLOCSET`,var:0,buff:m}),e.push({cmd:`ALLOCSET`,var:1,buff:h}),e.push({cmd:`ALLOC`,var:2,len:t.length*o}),g=0,_=0;let n=0;for(let r=0;rf.contributions.length)return i&&i.error(`The impoerted file does not include new contributions`),!1;for(let e=0;e=0;e--){let t=u.contributions[e];r&&r.info(`-------------------------`),r&&r.info(J(t.contributionHash,`contribution #${e+1} ${t.name?t.name:``}:`)),t.type==1&&(r&&r.info(`Beacon generator: ${li(t.beaconHash)}`),r&&r.info(`Beacon iterations Exp: ${t.numIterationsExp}`))}return r&&r.info(`-------------------------`),r&&r.info(`ZKey Ok!`),!0;async function v(e,t,n,a,o,s,l,u,d){let f=1<<20,p=c[e],m=p.F.n8*2;await H(t,n,s),await H(a,o,s);let h=p.zero,g=p.zero,_=n[s][0].size/m;for(let e=0;e<_;e+=f){r&&r.debug(`Same ratio check ${d}: ${e}/${_}`);let n=Math.min(_-e,f),i=await t.read(n*m),o=await a.read(n*m),s=ri(4*n),c=await p.multiExpAffine(i,s),l=await p.multiExpAffine(o,s);h=p.add(h,c),g=p.add(g,l)}return await U(t),await U(a),_==0?!0:(i=await rs(c,h,g,l,u),i===!0)}async function y(){let e=1<<20,n=c.G1,l=c.Fr,u=n.F.n8*2,{fd:d,sections:f}=await z(t,`ptau`,1),p=new I(s.domainSize*s.n8r),m=Array(8);for(let e=0;e<8;e++)m[e]=ai(ri(4),0);let g=new Ge(m);for(let e=0;e=256)return a&&a.error(`Maximum length of beacon hash is 255 bytes`),!1;if(i=parseInt(i),i<10||i>63)return a&&a.error(`Invalid numIterationsExp. (Must be between 10 and 63)`),!1;let{fd:s,sections:c}=await z(e,`zkey`,2),l=await hi(s,c);if(l.protocol!=`groth16`)throw Error(`zkey file is not groth16`);let u=await cr(l.q),d=await xi(s,u,c),f=await Qn(t,`zkey`,1,10),p=await si(o,i),m=q.create({dkLen:64});m.update(d.csHash);for(let e=0;e Detected protocol: `+i.protocol);let a;if(i.protocol===`groth16`)a=await fs(i,n,r);else if(i.protocol===`plonk`)a=await ps(i);else if(i.protocolId&&i.protocolId===10)a=await ms(i,t);else throw Error(`zkey file protocol unrecognized`);return await n.close(),t&&t.info(`EXPORT VERIFICATION KEY FINISHED`),a}async function fs(e,t,n){let r=await cr(e.q),i=r.G1.F.n8*2,a=await r.pairing(e.vk_alpha_1,e.vk_beta_2),o={protocol:e.protocol,curve:r.name,nPublic:e.nPublic,vk_alpha_1:r.G1.toObject(e.vk_alpha_1),vk_beta_2:r.G2.toObject(e.vk_beta_2),vk_gamma_2:r.G2.toObject(e.vk_gamma_2),vk_delta_2:r.G2.toObject(e.vk_delta_2),vk_alphabeta_12:r.Gt.toObject(a)};await H(t,n,3),o.IC=[];for(let n=0;n<=e.nPublic;n++){let e=await t.read(i),n=r.G1.toObject(e);o.IC.push(n)}return await U(t),o=us(o),o}async function ps(e){let t=await cr(e.q),n={protocol:e.protocol,curve:t.name,nPublic:e.nPublic,power:e.power,k1:t.Fr.toObject(e.k1),k2:t.Fr.toObject(e.k2),Qm:t.G1.toObject(e.Qm),Ql:t.G1.toObject(e.Ql),Qr:t.G1.toObject(e.Qr),Qo:t.G1.toObject(e.Qo),Qc:t.G1.toObject(e.Qc),S1:t.G1.toObject(e.S1),S2:t.G1.toObject(e.S2),S3:t.G1.toObject(e.S3),X_2:t.G2.toObject(e.X_2),w:t.Fr.toObject(t.Fr.w[e.power])};return n=us(n),n}async function ms(e,t){let n=await cr(e.q);return us({protocol:e.protocol,curve:n.name,nPublic:e.nPublic,power:e.power,k1:n.Fr.toObject(e.k1),k2:n.Fr.toObject(e.k2),w:n.Fr.toObject(n.Fr.w[e.power]),w3:n.Fr.toObject(e.w3),w4:n.Fr.toObject(e.w4),w8:n.Fr.toObject(e.w8),wr:n.Fr.toObject(e.wr),X_2:n.G2.toObject(e.X_2),C0:n.G1.toObject(e.C0)})}var hs=r({beacon:()=>ss,bellmanContribute:()=>ls,contribute:()=>os,exportBellman:()=>ts,exportJson:()=>cs,exportSolidityVerifier:()=>null,exportVerificationKey:()=>ds,importBellman:()=>ns,newZKey:()=>es,verifyFromInit:()=>is,verifyFromR1cs:()=>as});async function gs(e,t,n,r){globalThis.gc&&globalThis.gc();let{fd:i,sections:a}=await z(t,`ptau`,1,1<<22,1<<24),{curve:o,power:s}=await Ma(i,a),{fd:c,sections:l}=await z(e,`r1cs`,1,1<<22,1<<24),u=await Fo(c,l,{loadConstraints:!0,loadCustomGates:!0}),d=o.G1.F.n8*2,f=o.G1,p=o.G2.F.n8*2,m=o.Fr,h=o.Fr.n8;r&&r.info(`Reading r1cs`);let g=new $o,_=new $o,v=u.nVars,y=u.nOutputs+u.nPubInputs;await k(o.Fr,u,r),globalThis.gc&&globalThis.gc();let b=await Qn(n,`zkey`,1,14,1<<22,1<<24);if(u.prime!=o.r)return r&&r.error(`r1cs curve does not match powers of tau ceremony curve`),-1;let x=Xr(g.length-1)+1;x<3&&(x=3);let S=2**x;if(r&&r.info(`Plonk constraints: `+g.length),x>s)return r&&r.error(`circuit too big for this power of tau ceremony. ${g.length} > 2**${s}`),-1;if(!a[12])return r&&r.error(`Powers of tau is not prepared.`),-1;let C=new I(S*d),w=a[12][0].p+(2**x-1)*d;await i.readToBuffer(C,0,S*d,w);let[T,E]=te(),D={};await ee(3,`Additions`),globalThis.gc&&globalThis.gc(),await A(4,0,`Amap`),globalThis.gc&&globalThis.gc(),await A(5,1,`Bmap`),globalThis.gc&&globalThis.gc(),await A(6,2,`Cmap`),globalThis.gc&&globalThis.gc(),await j(7,3,`Qm`),globalThis.gc&&globalThis.gc(),await j(8,4,`Ql`),globalThis.gc&&globalThis.gc(),await j(9,5,`Qr`),globalThis.gc&&globalThis.gc(),await j(10,6,`Qo`),globalThis.gc&&globalThis.gc(),await j(11,7,`Qc`),globalThis.gc&&globalThis.gc(),await N(12,`sigma`),globalThis.gc&&globalThis.gc(),await P(13,`lagrange polynomials`),globalThis.gc&&globalThis.gc(),await B(b,14);let O=new I((S+6)*d);await i.readToBuffer(O,0,(S+6)*d,a[2][0].p),await b.write(O),await V(b),globalThis.gc&&globalThis.gc(),await F(),await b.close(),await c.close(),await i.close(),r&&r.info(`Setup Finished`);return;async function k(e,t,n){function r(e){let t=Object.keys(e);for(let n=0;nn;){let t=i.shift(),n=i.shift(),r=t[0],a=n[0],o=v++,s=e.zero,c=e.neg(t[1]),l=e.neg(n[1]),u=e.one,d=e.zero;g.push([r,a,o,s,c,l,u,d]),_.push([r,a,t[1],n[1]]),i.push([o,e.one])}for(let e=0;e0?r.toString():n==e.zero?`0`:`k`}function l(e,t,n){let a=c(e),l=c(t);a===`0`||l===`0`?(r(n),o(n)):a===`k`?o(i(t,e[0],n)):l===`k`?o(i(e,t[0],n)):s(e,t,n)}for(let t=1;t<=y;t++){let n=t,r=e.zero,i=e.one,a=e.zero,o=e.zero,s=e.zero;g.push([n,0,0,r,i,a,o,s])}for(let e=0;e{let r=this.curve.G1.toObject(this.polynomials[n]);e?t.polynomials[n]=r:t[n]=r}),Object.keys(this.evaluations).forEach(n=>{let r=this.curve.Fr.toObject(this.evaluations[n]);e?t.evaluations[n]=r:t[n]=r}),t}fromObjectProof(e){this.resetProof(),Object.keys(e.polynomials).forEach(t=>{this.polynomials[t]=this.curve.G1.fromObject(e.polynomials[t])}),Object.keys(e.evaluations).forEach(t=>{this.evaluations[t]=this.curve.Fr.fromObject(e.evaluations[t])})}},vs=BigInt(0),ys=BigInt(1),bs=BigInt(2),xs=BigInt(7),Ss=BigInt(256),Cs=BigInt(113),ws=[],Ts=[],Es=[];for(let e=0,t=ys,n=1,r=0;e<24;e++){[n,r]=[r,(2*n+3*r)%5],ws.push(2*(5*r+n)),Ts.push((e+1)*(e+2)/2%64);let i=vs;for(let e=0;e<7;e++)t=(t<>xs)*Cs)%Ss,t&bs&&(i^=ys<<(ys<n>32?Ir(e,t,n):Pr(e,t,n),js=(e,t,n)=>n>32?Lr(e,t,n):Fr(e,t,n);function Ms(e,t=24){if(dr(t,`rounds`),t<1||t>24)throw Error(`"rounds" expected integer 1..24`);let n=new Uint32Array(10);for(let r=24-t;r<24;r++){for(let t=0;t<10;t++)n[t]=e[t]^e[t+10]^e[t+20]^e[t+30]^e[t+40];for(let t=0;t<10;t+=2){let r=(t+8)%10,i=(t+2)%10,a=n[i],o=n[i+1],s=As(a,o,1)^n[r],c=js(a,o,1)^n[r+1];for(let n=0;n<50;n+=10)e[t+n]^=s,e[t+n+1]^=c}let t=e[2],i=e[3];for(let n=0;n<24;n++){let r=Ts[n],a=As(t,i,r),o=js(t,i,r),s=ws[n];t=e[s],i=e[s+1],e[s]=a,e[s+1]=o}for(let t=0;t<50;t+=10){let n=e[t],r=e[t+1],i=e[t+2],a=e[t+3];e[t]^=~e[t+2]&e[t+4],e[t+1]^=~e[t+3]&e[t+5],e[t+2]^=~e[t+4]&e[t+6],e[t+3]^=~e[t+5]&e[t+7],e[t+4]^=~e[t+6]&e[t+8],e[t+5]^=~e[t+7]&e[t+9],e[t+6]^=~e[t+8]&n,e[t+7]^=~e[t+9]&r,e[t+8]^=~n&i,e[t+9]^=~r&a}e[0]^=Os[r],e[1]^=ks[r]}gr(n)}var Ns=class e{state;pos=0;posOut=0;finished=!1;state32;destroyed=!1;blockLen;suffix;outputLen;canXOF;enableXOF=!1;rounds;constructor(e,t,n,r=!1,i=24){if(this.blockLen=e,this.suffix=t,this.outputLen=n,this.enableXOF=r,this.canXOF=r,this.rounds=i,dr(n,`outputLen`),!(0=n&&this.keccak();let a=Math.min(n-this.posOut,i-r);e.set(t.subarray(this.posOut,this.posOut+a),r),this.posOut+=a,r+=a}return e}xofInto(e){if(!this.enableXOF)throw Error(`XOF is not possible for this instance`);return this.writeInto(e)}xof(e){return dr(e),this.xofInto(new Uint8Array(e))}digestInto(e){if(mr(e,this),this.finished)throw Error(`digest() was already called`);this.writeInto(e.subarray(0,this.outputLen)),this.destroy()}digest(){let e=new Uint8Array(this.outputLen);return this.digestInto(e),e}destroy(){this.destroyed=!0,gr(this.state)}_cloneInto(t){let{blockLen:n,suffix:r,outputLen:i,rounds:a,enableXOF:o}=this;return t||=new e(n,r,i,o,a),t.blockLen=n,t.state32.set(this.state32),t.pos=this.pos,t.posOut=this.posOut,t.finished=this.finished,t.rounds=a,t.suffix=r,t.outputLen=i,t.enableXOF=o,t.canXOF=this.canXOF,t.destroyed=this.destroyed,t}},Ps=((e,t,n,r={})=>Sr(()=>new Ns(t,e,n),r))(1,136,32),Fs=0,Is=1,Ls=class{constructor(e){this.G1=e.G1,this.Fr=e.Fr,this.reset()}reset(){this.data=[]}addPolCommitment(e){this.data.push({type:Fs,data:e})}addScalar(e){this.data.push({type:Is,data:e})}getChallenge(){if(this.data.length===0)throw Error(`Keccak256Transcript: No data to generate a transcript`);let e=0,t=0;this.data.forEach(n=>Fs===n.type?e++:t++);let n=new Uint8Array(t*this.Fr.n8+e*this.G1.F.n8*2),r=0;for(let e=0;e32768?new I(t.length*i.n8):new Uint8Array(t.length*i.n8);for(let e=0;e32768?new I(i*a.n8):new Uint8Array(i*a.n8);return o.set(t.coef.slice(),0),new e(o,n,r)}isEqual(e){let t=this.degree();if(t!==e.degree())return!1;for(let n=0;n32768?new I((this.length()+e.length)*this.Fr.n8):new Uint8Array((this.length()+e.length)*this.Fr.n8);t.set(this.coef,0);for(let n=0;nthis.coef.byteLength?this.Fr.zero:this.coef.slice(t,t+this.Fr.n8)}setCoef(e,t){if(e>this.length()-1)throw Error(`Coef index is not available`);this.coef.set(t,e*this.Fr.n8)}static async to4T(e,t,n,r){n||=[];let i=await r.ifft(e),a=t*4>32768?new I(t*4*r.n8):new Uint8Array(t*4*r.n8);a.set(i,0);let o=await r.fft(a);if(n.length===0)return[i,o];let s=t+n.length>32768?new I((t+n.length)*r.n8):new Uint8Array((t+n.length)*r.n8);s.set(i,0);for(let e=0;e0;e--){let t=e*this.Fr.n8;if(!this.Fr.eq(this.Fr.zero,this.coef.slice(t,t+this.Fr.n8)))return e}return 0}evaluate(e){let t=this.Fr.zero;for(let n=this.degree()+1;n>0;n--){let r=n*this.Fr.n8,i=this.coef.slice(r-this.Fr.n8,r);t=this.Fr.add(i,this.Fr.mul(t,e))}return t}fastEvaluate(e){let t=this.Fr,n=this.degree()+1,r=parseInt(n/3),i=n-r*3,a=[],o=[];o[0]=t.one;for(let n=0;n<3;n++){a[n]=t.zero;let s=n===2?r+i:r;for(let i=s;i>0;i--)a[n]=t.add(this.getCoef(n*r+i-1),t.mul(a[n],e)),n===0&&(o[0]=t.mul(o[0],e))}for(let e=1;e<3;e++)a[0]=t.add(a[0],t.mul(o[e-1],a[e])),o[e]=t.mul(o[e-1],o[0]);return a[0]}add(e,t){let n=!1;e.length()>this.length()&&(n=!0);let r=this.length(),i=e.length();for(let a=0;athis.length()&&(n=!0);let r=this.length(),i=e.length();for(let a=0;a32768?new I(r*n.n8):new Uint8Array(r*n.n8),this.curve,this.logger);i.coef.set(this.coef.slice(0,(r-1)*n.n8),32),this.mulScalar(n.neg(t)),i.add(this),this.coef=i.coef}byXNSubValue(t,n){let r=this.Fr,i=this.length()-t-1>=this.degree()?this.length():this.length()+t,a=new e(i>32768?new I(i*r.n8):new Uint8Array(i*r.n8),this.curve,this.logger);a.coef.set(this.coef.slice(0,(this.degree()+1)*32),t*32),this.mulScalar(n),a.add(this),this.coef=a.coef}divBy(t){let n=this.Fr,r=this.degree(),i=t.degree(),a=new e(this.coef,this.curve,this.logger);this.coef=this.length()>32768?new I(this.length()*n.n8):new Uint8Array(this.length()*n.n8);for(let e=r-i;e>=0;e--){this.setCoef(e,n.div(a.getCoef(e+i),t.getCoef(i)));for(let r=0;r<=i;r++)a.setCoef(e+r,n.sub(a.getCoef(e+r),n.mul(this.getCoef(e),t.getCoef(r))))}return a}divByMonic(t,n){let r=this.Fr,i=this.degree(),a=new e(this.length()>32768?new I(this.length()*r.n8):new Uint8Array(this.length()*r.n8),this.curve,this.logger),o=[];for(let e=0;e=0&&!(l<0);l-=s){let i=e;o[i]=r.add(this.getCoef(l+t),r.mul(o[i],n)),a.setCoef(l,o[i]),c=(c+1)%t}this.coef=a.coef}divByVanishing(t,n){if(this.degree()32768?new I(this.length()*r.n8):new Uint8Array(this.length()*r.n8);for(let e=this.length()-1;e>=t;e--){let a=i.getCoef(e);r.eq(r.zero,a)||(i.setCoef(e,r.zero),i.setCoef(e-t,r.add(i.getCoef(e-t),r.mul(n,a))),this.setCoef(e-t,r.add(this.getCoef(e-t),a)))}return i}divByVanishing2(t,n){if(this.degree()32768?new I(this.length()*r.n8):new Uint8Array(this.length()*r.n8);let a=this.length()-t,o=Math.floor(a/3),s=a-2*o;console.log(a),console.log(o+` `+s);for(let e=0;e<3;e++){console.log(`> Thread `+e);for(let a=e===0?s:o;a>0;a--){let c=a-1;e!==0&&(c+=(e-1)*o+s);let l=c+t,u=i.getCoef(l);r.eq(r.zero,u)||(i.setCoef(l,r.zero),i.setCoef(c,r.add(i.getCoef(c),r.mul(n,u))),this.setCoef(c,r.add(this.getCoef(c),u)),console.log(c+` <-- `+l))}}return this.print(),i}fastDivByVanishing(t){let n=this.Fr;for(let r=0;r32768?new I(this.length()*n.n8):new Uint8Array(this.length()*n.n8),this.curve,this.logger),d=this.coef;this.coef=u.coef,u.coef=d;for(let e=0;e<5;e++){let t=(e+1)*c+l;for(let e=0;e0;e--){let t=e-1,r=t*c+l;m[t]=[];for(let a=0;a32768?new I(this.length()*this.Fr.n8):new Uint8Array(this.length()*this.Fr.n8);t.set(this.Fr.zero,(this.length()-1)*this.Fr.n8),t.set(this.coef.slice((this.length()-1)*this.Fr.n8,this.length()*this.Fr.n8),(this.length()-2)*this.Fr.n8);for(let n=this.length()-3;n>=0;n--){let r=n*this.Fr.n8;t.set(this.Fr.add(this.coef.slice(r+this.Fr.n8,r+2*this.Fr.n8),this.Fr.mul(e,t.slice(r+this.Fr.n8,r+2*this.Fr.n8))),n*this.Fr.n8)}if(!this.Fr.eq(this.coef.slice(0,this.Fr.n8),this.Fr.mul(this.Fr.neg(e),t.slice(0,this.Fr.n8))))throw Error(`Polynomial does not divide`);this.coef=t}divZh(e,t=4){for(let t=0;te*(t-1)-t&&!this.Fr.isZero(i))throw Error(`Polynomial is not divisible`)}return this}divByZerofier(e,t){let n=this.Fr,r=n.inv(t),i=n.neg(r),a=n.eq(n.one,i),o=n.eq(n.negone,i);if(!a)for(let t=0;tthis.length()-e-1&&!this.Fr.isZero(c))throw Error(`Polynomial is not divisible`)}return this}byX(){let e=this.length()+1>32768?new I(this.coef.byteLength+this.Fr.n8):new Uint8Array(this.coef.byteLength+this.Fr.n8);e.set(this.Fr.zero,0),e.set(this.coef,this.Fr.n8),this.coef=e}static async expX(t,n,r=!1){let i=t.Fr;if(n<1)throw Error(`Compute a new polynomial to a zero or negative number is not allowed`);if(n===1)return await e.fromEvaluations(t.coef,t.curve,t.logger);let a=r?t.degree():t.length()-1,o=a*n+1>32768?new I((a*n+1)*i.n8):new Uint8Array((a*n+1)*i.n8);o.set(t.getCoef(0),0);for(let e=1;e<=a;e++){let r=e*i.n8,a=t.getCoef(e);o.set(a,r*n)}return new e(o,t.curve,t.logger)}split(t,n,r){if(t<1)throw Error(`Polynomials can't be split in ${t} parts`);if(t===1)return[this];if(r.length!==0&&r.length32768?new I(s):new Uint8Array(s),this.curve,this.logger);let c=n*i,l=o?this.coef.byteLength:(n+1)*i;if(a[n].coef.set(this.coef.slice(c,l),0),o||a[n].coef.set(r[n],i),n!==0){let e=this.Fr.sub(a[n].coef.slice(0,this.Fr.n8),r[n-1]);a[n].coef.set(e,0)}o&&a[n].truncate()}return a}truncate(){let e=this.degree();if(e+132768?new I((e+1)*this.Fr.n8):new Uint8Array((e+1)*this.Fr.n8);t.set(this.coef.slice(0,(e+1)*this.Fr.n8),0),this.coef=t}}static lagrangePolynomialInterpolation(t,n,r){let i=r.Fr,a=o(0);for(let e=1;e32768?new I(t.length*i.n8):new Uint8Array(t.length*i.n8),r),o.setCoef(0,i.neg(t[n])),o.setCoef(1,i.one)):o.byXSubValue(t[n]));let s=o.evaluate(t[a]);s=i.inv(s);let c=i.mul(n[a],s);return o.mulScalar(c),o}}static zerofierPolynomial(t,n){let r=n.Fr,i=new e(t.length+1>32768?new I((t.length+1)*r.n8):new Uint8Array((t.length+1)*r.n8),n);i.setCoef(0,r.neg(t[0])),i.setCoef(1,r.one);for(let e=1;e=0;n--){let r=this.getCoef(n);e.eq(e.zero,r)||(e.isNegative(r)?t+=` - `:n!==this.degree()&&(t+=` + `),t+=e.toString(r),n>0&&(t+=n>1?`x^`+n:`x`))}console.log(t)}async multiExponentiation(e,t){let n=this.coef.byteLength/this.Fr.n8,r=e.slice(0,n*this.G1.F.n8*2),i=await this.Fr.batchFromMontgomery(this.coef),a=await this.G1.multiExpAffine(r,i,this.logger,t);return a=this.G1.toAffine(a),a}},Z=class e{constructor(e,t,n){this.eval=e,this.curve=t,this.Fr=t.Fr,this.logger=n}static async fromPolynomial(t,n,r,i){let a=new I(t.length()*n*r.Fr.n8);return a.set(t.coef,0),new e(await r.Fr.fft(a),r,i)}getEvaluation(e){let t=e*this.Fr.n8;if(t+this.Fr.n8>this.eval.byteLength)throw Error(`Evaluations.getEvaluation() out of bounds`);return this.eval.slice(t,t+this.Fr.n8)}length(){let e=this.eval.byteLength/this.Fr.n8;if(e!==Math.floor(this.eval.byteLength/this.Fr.n8))throw Error(`Polynomial evaluations buffer has incorrect size`);return e===0&&this.logger.warn(`Polynomial has length zero`),e}},{stringifyBigInts:zs}=bn;async function Bs(e,t,n,r){let{fd:i,sections:a}=await z(t,`wtns`,2,1<<25,1<<23);n&&n.debug(`> Reading witness file`);let o=await ki(i,a);n&&n.debug(`> Reading zkey file`);let{fd:s,sections:c}=await z(e,`zkey`,2,1<<25,1<<23),l=await hi(s,c,void 0,r);if(l.protocol!=`plonk`)throw Error(`zkey file is not plonk`);if(!L.eq(l.r,o.q))throw Error(`Curve of the witness does not match the curve of the proving key`);if(o.nWitness!=l.nVars-l.nAdditions)throw Error(`Invalid witness length. Circuit: ${l.nVars}, witness: ${o.nWitness}, ${l.nAdditions}`);let u=l.curve,d=u.Fr,f=u.Fr.n8,p=l.domainSize*f;n&&(n.debug(`----------------------------`),n.debug(` PLONK PROVE SETTINGS`),n.debug(` Curve: ${u.name}`),n.debug(` Circuit power: ${l.power}`),n.debug(` Domain size: ${l.domainSize}`),n.debug(` Vars: ${l.nVars}`),n.debug(` Public vars: ${l.nPublic}`),n.debug(` Constraints: ${l.nConstraints}`),n.debug(` Additions: ${l.nAdditions}`),n.debug(`----------------------------`)),n&&n.debug(`> Reading witness file data`);let m=await G(i,a,2);m.set(d.zero,0);let h=new I(f*l.nAdditions),g={},_={},v={},y={},b=new _s(u,n),x=new Ls(u);n&&n.debug(`> Reading Section 3. Additions`),await T(),n&&n.debug(`> Reading Section 12. Sigma1, Sigma2 & Sigma 3`),n&&n.debug(`··· Reading Sigma polynomials `),_.Sigma1=new X(new I(p),u,n),_.Sigma2=new X(new I(p),u,n),_.Sigma3=new X(new I(p),u,n),await s.readToBuffer(_.Sigma1.coef,0,p,c[12][0].p),await s.readToBuffer(_.Sigma2.coef,0,p,c[12][0].p+5*p),await s.readToBuffer(_.Sigma3.coef,0,p,c[12][0].p+10*p),n&&n.debug(`··· Reading Sigma evaluations`),v.Sigma1=new Z(new I(p*4),u,n),v.Sigma2=new Z(new I(p*4),u,n),v.Sigma3=new Z(new I(p*4),u,n),await s.readToBuffer(v.Sigma1.eval,0,p*4,c[12][0].p+p),await s.readToBuffer(v.Sigma2.eval,0,p*4,c[12][0].p+6*p),await s.readToBuffer(v.Sigma3.eval,0,p*4,c[12][0].p+11*p),n&&n.debug(`> Reading Section 14. Powers of Tau`);let S=await G(s,c,14),C=[];for(let e=1;e<=l.nPublic;e++){let t=m.slice(e*d.n8,e*d.n8+d.n8);C.push(L.fromRprLE(t))}n&&n.debug(``),n&&n.debug(`> ROUND 1`),await O(),n&&n.debug(`> ROUND 2`),await A(),n&&n.debug(`> ROUND 3`),await M(),n&&n.debug(`> ROUND 4`),await N(),n&&n.debug(`> ROUND 5`),await P(),await s.close(),await i.close();let w=b.toObjectProof(!1);return w.protocol=`plonk`,w.curve=u.name,n&&n.debug(`PLONK PROVER FINISHED`),{proof:zs(w),publicSignals:zs(C)};async function T(){n&&n.debug(`··· Computing additions`);let e=await G(s,c,3),t=8+f*2;for(let r=0;r Computing A, B, C wire polynomials`),await k(),n&&n.debug(`> Computing A, B, C MSM`);let e=await _.A.multiExponentiation(S,`A`),t=await _.B.multiExponentiation(S,`B`),r=await _.C.multiExponentiation(S,`C`);return b.addPolynomial(`A`,e),b.addPolynomial(`B`,t),b.addPolynomial(`C`,r),0}async function k(){n&&n.debug(`··· Reading data from zkey file`),g.A=new I(p),g.B=new I(p),g.C=new I(p);let e=await G(s,c,4),t=await G(s,c,5),r=await G(s,c,6);for(let n=0;n=l.domainSize+2)throw Error(`A Polynomial is not well calculated`);if(_.B.degree()>=l.domainSize+2)throw Error(`B Polynomial is not well calculated`);if(_.C.degree()>=l.domainSize+2)throw Error(`C Polynomial is not well calculated`)}async function A(){n&&n.debug(`> Computing challenges beta and gamma`),x.reset(),x.addPolCommitment(l.Qm),x.addPolCommitment(l.Ql),x.addPolCommitment(l.Qr),x.addPolCommitment(l.Qo),x.addPolCommitment(l.Qc),x.addPolCommitment(l.S1),x.addPolCommitment(l.S2),x.addPolCommitment(l.S3);for(let e=0;e Computing Z polynomial`),await j(),n&&n.debug(`> Computing Z MSM`);let e=await _.Z.multiExponentiation(S,`Z`);b.addPolynomial(`Z`,e)}async function j(){n&&n.debug(`··· Computing Z evaluations`);let e=new I(p),t=new I(p);e.set(d.one,0),t.set(d.one,0);let r=d.one;for(let n=0;n=l.domainSize+3)throw Error(`Z Polynomial is not well calculated`);delete g.Z}async function M(){n&&n.debug(`> Computing challenge alpha`),x.reset(),x.addScalar(y.beta),x.addScalar(y.gamma),x.addPolCommitment(b.getPolynomial(`Z`)),y.alpha=x.getChallenge(),y.alpha2=d.square(y.alpha),n&&n.debug(`··· challenges.alpha: `+d.toString(y.alpha,16)),n&&n.debug(`> Computing T polynomial`),await ee(),n&&n.debug(`> Computing T MSM`);let e=await _.T1.multiExponentiation(S,`T1`),t=await _.T2.multiExponentiation(S,`T2`),r=await _.T3.multiExponentiation(S,`T3`);b.addPolynomial(`T1`,e),b.addPolynomial(`T2`,t),b.addPolynomial(`T3`,r)}async function ee(){n&&n.debug(`··· Reading sections 8, 9, 7, 10, 11. Q selectors`),v.QL=new Z(new I(p*4),u,n),v.QR=new Z(new I(p*4),u,n),v.QM=new Z(new I(p*4),u,n),v.QO=new Z(new I(p*4),u,n),v.QC=new Z(new I(p*4),u,n),await s.readToBuffer(v.QL.eval,0,p*4,c[8][0].p+p),await s.readToBuffer(v.QR.eval,0,p*4,c[9][0].p+p),await s.readToBuffer(v.QM.eval,0,p*4,c[7][0].p+p),await s.readToBuffer(v.QO.eval,0,p*4,c[10][0].p+p),await s.readToBuffer(v.QC.eval,0,p*4,c[11][0].p+p),v.Lagrange=new Z(new I(p*4*l.nPublic),u,n);for(let e=0;e=l.domainSize*3+6)throw Error(`T Polynomial is not well calculated`);n&&n.debug(`··· Computing T1, T2, T3 polynomials`),_.T1=new X(new I((l.domainSize+1)*f),u,n),_.T2=new X(new I((l.domainSize+1)*f),u,n),_.T3=new X(new I((l.domainSize+6)*f),u,n),_.T1.coef.set(_.T.coef.slice(0,p),0),_.T2.coef.set(_.T.coef.slice(p,p*2),0),_.T3.coef.set(_.T.coef.slice(p*2,p*3+6*f),0),_.T1.setCoef(l.domainSize,y.b[10]);let t=d.sub(_.T2.getCoef(0),y.b[10]);_.T2.setCoef(0,t),_.T2.setCoef(l.domainSize,y.b[11]);let r=d.sub(_.T3.getCoef(0),y.b[11]);_.T3.setCoef(0,r)}async function N(){n&&n.debug(`> Computing challenge xi`),x.reset(),x.addScalar(y.alpha),x.addPolCommitment(b.getPolynomial(`T1`)),x.addPolCommitment(b.getPolynomial(`T2`)),x.addPolCommitment(b.getPolynomial(`T3`)),y.xi=x.getChallenge(),y.xiw=d.mul(y.xi,d.w[l.power]),n&&n.debug(`··· challenges.xi: `+d.toString(y.xi,16)),b.addEvaluation(`eval_a`,_.A.evaluate(y.xi)),b.addEvaluation(`eval_b`,_.B.evaluate(y.xi)),b.addEvaluation(`eval_c`,_.C.evaluate(y.xi)),b.addEvaluation(`eval_s1`,_.Sigma1.evaluate(y.xi)),b.addEvaluation(`eval_s2`,_.Sigma2.evaluate(y.xi)),b.addEvaluation(`eval_zw`,_.Z.evaluate(y.xiw))}async function P(){n&&n.debug(`> Computing challenge v`),x.reset(),x.addScalar(y.xi),x.addScalar(b.getEvaluation(`eval_a`)),x.addScalar(b.getEvaluation(`eval_b`)),x.addScalar(b.getEvaluation(`eval_c`)),x.addScalar(b.getEvaluation(`eval_s1`)),x.addScalar(b.getEvaluation(`eval_s2`)),x.addScalar(b.getEvaluation(`eval_zw`)),y.v=[],y.v[1]=x.getChallenge(),n&&n.debug(`··· challenges.v: `+d.toString(y.v[1],16));for(let e=2;e<6;e++)y.v[e]=d.mul(y.v[e-1],y.v[1]);n&&n.debug(`> Computing linearisation polynomial R(X)`),await F(),n&&n.debug(`> Computing opening proof polynomial Wxi(X) polynomial`),te(),n&&n.debug(`> Computing opening proof polynomial Wxiw(X) polynomial`),ne(),n&&n.debug(`> Computing Wxi, Wxiw MSM`);let e=await _.Wxi.multiExponentiation(S,`Wxi`),t=await _.Wxiw.multiExponentiation(S,`Wxiw`);b.addPolynomial(`Wxi`,e),b.addPolynomial(`Wxiw`,t)}async function F(){let e=u.Fr;_.QL=new X(new I(p),u,n),_.QR=new X(new I(p),u,n),_.QM=new X(new I(p),u,n),_.QO=new X(new I(p),u,n),_.QC=new X(new I(p),u,n),await s.readToBuffer(_.QL.coef,0,p,c[8][0].p),await s.readToBuffer(_.QR.coef,0,p,c[9][0].p),await s.readToBuffer(_.QM.coef,0,p,c[7][0].p),await s.readToBuffer(_.QO.coef,0,p,c[10][0].p),await s.readToBuffer(_.QC.coef,0,p,c[11][0].p),y.xin=y.xi;for(let t=0;tsc,fullProve:()=>Hs,prove:()=>Bs,setup:()=>gs,verify:()=>Ws});function lc(e,t){return[e,0,0,t.one,t.zero,t.zero,t.zero,t.zero]}function uc(e,t,n,r,i,a,o,s){return[e,t,n,r,i,a,o,s]}function dc(e,t,n,r,i,a,o,s,c){return[e,t,n,r,i,a,o,s]}var fc=0,pc=1,mc=2,hc=class{constructor(e,t,n,r,i){this.Fr=e,this.logger=i,this.fnGetAdditionConstraint=n,this.fnGetMultiplicationConstraint=r}processR1csConstraint(e,t,n,r){this.normalizeLinearCombination(t),this.normalizeLinearCombination(n),this.normalizeLinearCombination(r);let i=this.getLinearCombinationType(t),a=this.getLinearCombinationType(n);if(i===fc||a===fc)return this.processR1csAdditionConstraint(e,r);if(i===pc){let i=this.joinLinearCombinations(n,r,t[0]);return this.processR1csAdditionConstraint(e,i)}else if(a===pc){let i=this.joinLinearCombinations(t,r,n[0]);return this.processR1csAdditionConstraint(e,i)}else return this.processR1csMultiplicationConstraint(e,t,n,r)}getLinearCombinationType(e){let t=this.Fr.zero,n=0,r=Object.keys(e);for(let i=0;i0?mc:this.Fr.isZero(t)?fc:pc}normalizeLinearCombination(e){let t=Object.keys(e);for(let n=0;ni;){let r=o.shift(),i=o.shift(),a=e.nVars++,s=this.fnGetAdditionConstraint(r[0],i[0],a,this.Fr.neg(r[1]),this.Fr.neg(i[1]),this.Fr.zero,this.Fr.one,this.Fr.zero);t.push(s),n.push([r[0],i[0],r[1],i[1]]),o.push([a,this.Fr.one])}for(let e=0;ethis.n-1)throw Error(`CPolynomial:addPolynomial, cannot add a polynomial to a position greater than n-1`);this.polynomials[e]=t}degree(){let e=this.polynomials.map((e,t)=>e===void 0?0:e.degree()*this.n+t);return Math.max(...e)}getPolynomial(){let e=this.polynomials.map(e=>e===void 0?0:e.degree()),t=this.degree(),n=2**(Xr(t-1)+1),r=this.Fr.n8,i=new X(new I(n*r),this.curve,this.logger);for(let n=0;n Reading PTau file`);let{fd:i,sections:a}=await z(t,`ptau`,1,1<<22,1<<24);if(!a[12])throw Error(`Powers of Tau is not well prepared. Section 12 missing.`);r&&r.info(`> Getting curve from PTau settings`);let{curve:o}=await Ma(i,a);r&&r.info(`> Reading r1cs file`);let{fd:s,sections:c}=await z(e,`r1cs`,1,1<<22,1<<24),l=await Fo(s,c,{loadConstraints:!1,loadCustomGates:!0});if(l.prime!==o.r)throw Error(`r1cs curve does not match powers of tau ceremony curve`);let u=o.Fr,d=o.Fr.n8,f=o.G1.F.n8*2,p=o.G2.F.n8*2,m={},h={},g,_={nVars:l.nVars,nPublic:l.nOutputs+l.nPubInputs},v=new $o,y=new $o;if(r&&r.info(`> Processing FFlonk constraints`),await E(o.Fr,l,r),globalThis.gc&&globalThis.gc(),_.cirPower=Math.max(3,Xr(v.length+2-1)+1),_.domainSize=2**_.cirPower,a[2][0].size<(_.domainSize*9+18)*f)throw Error(`Powers of Tau is not big enough for this circuit size. Section 2 too small.`);if(a[3][0].size computing k1 and k2`);let[b,x]=ne();r&&r.info(`> computing w3`);let S=re();r&&r.info(`> computing w4`);let C=ie();r&&r.info(`> computing w8`);let w=ae();r&&r.info(`> computing wr`);let T=oe(_.cirPower,o.Fr);return await D(),await s.close(),await i.close(),r&&r.info(`FFLONK SETUP FINISHED`),0;async function E(e,t,n){for(let t=0;t<_.nPublic;t++)v.push(lc(t+1,e));let r=new hc(e,lc,uc,dc,n),i=await G(s,c,2),a=0;for(let e=0;e Writing the zkey file`);let e=await Qn(n,`zkey`,1,17,1<<22,1<<24);r&&r.info(`··· Writing Section 1. Zkey Header`),await O(e),r&&r.info(`··· Writing Section 3. Additions`),await k(e),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 4. A Map`),await A(e,4,0,`A map`),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 5. B Map`),await A(e,5,1,`B map`),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 6. C Map`),await A(e,6,2,`C map`),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 7. QL`),await j(e,7,3,`QL`),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 8. QR`),await j(e,8,4,`QR`),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 9. QM`),await j(e,9,5,`QM`),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 10. QO`),await j(e,10,6,`QO`),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 11. QC`),await j(e,11,7,`QC`),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Sections 12,13,14. Sigma1, Sigma2 & Sigma 3`),await M(e),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 15. Lagrange Polynomials`),await ee(e),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 16. Powers of Tau`),await N(e),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 17. C0`),await P(e),globalThis.gc&&globalThis.gc(),r&&r.info(`··· Writing Section 2. FFlonk Header`),await F(e),globalThis.gc&&globalThis.gc(),r&&r.info(`> Writing the zkey file finished`),await e.close()}async function O(e){await B(e,1),await e.writeULE32(10),await V(e)}async function k(e){await B(e,3);let t=new Uint8Array(8+2*d),n=new DataView(t.buffer);for(let i=0;i=8*_.domainSize)throw Error(`C0 Polynomial is not well calculated`);await B(e,17),await e.write(m.C0.coef),await V(e)}async function F(e){await B(e,2);let t=o.q,n=(Math.floor((L.bitLength(t)-1)/64)+1)*8;await e.writeULE32(n),await $n(e,t,n);let r=o.r,s=(Math.floor((L.bitLength(r)-1)/64)+1)*8;await e.writeULE32(s),await $n(e,r,s),await e.writeULE32(_.nVars),await e.writeULE32(_.nPublic),await e.writeULE32(_.domainSize),await e.writeULE32(y.length),await e.writeULE32(v.length),await e.write(b),await e.write(x),await e.write(S),await e.write(C),await e.write(w),await e.write(T);let c;c=await i.read(p,a[3][0].p+p),await e.write(c);let l=await m.C0.multiExponentiation(g,`C0`);await e.write(l),await V(e)}async function te(e,t){let[n,r]=await X.to4T(t,_.domainSize,[],u);return await e.write(n),await e.write(r),[n,r]}function ne(){let e=u.two;for(;n(e,[],_.cirPower);)u.add(e,u.one);let t=u.add(e,u.one);for(;n(t,[e],_.cirPower);)u.add(t,u.one);return[e,t];function n(e,t,n){let r=2**n,i=u.one;for(let a=0;a Reading witness file`);let{fd:i,sections:a}=await z(t,`wtns`,2,1<<25,1<<23),o=await ki(i,a);n&&n.info(`> Reading zkey file`);let{fd:s,sections:c}=await z(e,`zkey`,2,1<<25,1<<23),l=await hi(s,c,void 0,r);if(l.protocolId!==10)throw Error(`zkey file is not fflonk`);if(!L.eq(l.r,o.q))throw Error(`Curve of the witness does not match the curve of the proving key`);if(o.nWitness!==l.nVars-l.nAdditions)throw Error(`Invalid witness length. Circuit: ${l.nVars}, witness: ${o.nWitness}, ${l.nAdditions}`);let u=l.curve,d=u.Fr,f=u.Fr.n8,p=u.G1.F.n8*2,m=l.domainSize*f;n&&(n.info(`----------------------------`),n.info(` FFLONK PROVE SETTINGS`),n.info(` Curve: ${u.name}`),n.info(` Circuit power: ${l.power}`),n.info(` Domain size: ${l.domainSize}`),n.info(` Vars: ${l.nVars}`),n.info(` Public vars: ${l.nPublic}`),n.info(` Constraints: ${l.nConstraints}`),n.info(` Additions: ${l.nAdditions}`),n.info(`----------------------------`)),n&&n.info(`> Reading witness file data`);let h=await G(i,a,2);await i.close(),h.set(d.zero,0);let g=new I(l.nAdditions*f),_={},v={},y={},b={},x={},S={},C=new _s(u,n);n&&n.info(`> Reading Section 3. Additions`),await D(),n&&n.info(`> Reading Sections 12,13,14. Sigma1, Sigma2 & Sigma 3`),n&&n.info(`··· Reading Sigma polynomials `),v.Sigma1=new X(new I(m),u,n),v.Sigma2=new X(new I(m),u,n),v.Sigma3=new X(new I(m),u,n),await s.readToBuffer(v.Sigma1.coef,0,m,c[12][0].p),await s.readToBuffer(v.Sigma2.coef,0,m,c[13][0].p),await s.readToBuffer(v.Sigma3.coef,0,m,c[14][0].p),n&&n.info(`··· Reading Sigma evaluations`),y.Sigma1=new Z(new I(m*4),u,n),y.Sigma2=new Z(new I(m*4),u,n),y.Sigma3=new Z(new I(m*4),u,n),await s.readToBuffer(y.Sigma1.eval,0,m*4,c[12][0].p+m),await s.readToBuffer(y.Sigma2.eval,0,m*4,c[13][0].p+m),await s.readToBuffer(y.Sigma3.eval,0,m*4,c[14][0].p+m),n&&n.info(`> Reading Section 16. Powers of Tau`);let w=new I(l.domainSize*16*p);await s.readToBuffer(w,0,(l.domainSize*9+18)*p,c[16][0].p),globalThis.gc&&globalThis.gc(),n&&n.info(``),n&&n.info(`> ROUND 1`),await A(),delete v.T0,delete y.QL,delete y.QR,delete y.QM,delete y.QO,delete y.QC,globalThis.gc&&globalThis.gc(),n&&n.info(`> ROUND 2`),await j(),delete _.A,delete _.B,delete _.C,delete y.A,delete y.B,delete y.C,delete y.Sigma1,delete y.Sigma2,delete y.Sigma3,delete y.lagrange1,delete y.Z,globalThis.gc&&globalThis.gc(),n&&n.info(`> ROUND 3`),await M(),delete v.A,delete v.B,delete v.C,delete v.Z,delete v.T1,delete v.T2,delete v.Sigma1,delete v.Sigma2,delete v.Sigma3,delete v.QL,delete v.QR,delete v.QM,delete v.QC,delete v.QO,globalThis.gc&&globalThis.gc(),n&&n.info(`> ROUND 4`),await ee(),globalThis.gc&&globalThis.gc(),n&&n.info(`> ROUND 5`),await N(),delete v.C0,delete v.C1,delete v.C2,delete v.R1,delete v.R2,delete v.F,delete v.L,delete v.ZT,delete v.ZTS2,await s.close(),globalThis.gc&&globalThis.gc(),C.addEvaluation(`inv`,P());let T=C.toObjectProof();T.protocol=`fflonk`,T.curve=u.name;let E=[];for(let e=1;e<=l.nPublic;e++){let t=e*f,n=h.slice(t,t+f);E.push(L.fromRprLE(n))}return n&&n.info(`FFLONK PROVER FINISHED`),{proof:vc(T),publicSignals:vc(E)};async function D(){n&&n.info(`··· Computing additions`);let e=await G(s,c,3),t=8+f*2;for(let r=0;r Computing A, B, C wire polynomials`),await t(),n&&n.info(`> Computing T0 polynomial`),await r(),n&&n.info(`> Computing C1 polynomial`),await i(),n&&n.info(`> Computing C1 multi exponentiation`);let e=await v.C1.multiExponentiation(w,`C1`);return C.addPolynomial(`C1`,e),0;async function t(){n&&n.info(`··· Reading data from zkey file`),_.A=new I(m),_.B=new I(m),_.C=new I(m);let e=await G(s,c,4),t=await G(s,c,5),r=await G(s,c,6);for(let n=0;n=l.domainSize)throw Error(`A Polynomial is not well calculated`);if(v.B.degree()>=l.domainSize)throw Error(`B Polynomial is not well calculated`);if(v.C.degree()>=l.domainSize)throw Error(`C Polynomial is not well calculated`)}async function r(){n&&n.info(`··· Reading sections 7, 8, 9, 10, 11. Q selectors`),y.QL=new Z(new I(m*4),u,n),y.QR=new Z(new I(m*4),u,n),y.QM=new Z(new I(m*4),u,n),y.QO=new Z(new I(m*4),u,n),y.QC=new Z(new I(m*4),u,n),await s.readToBuffer(y.QL.eval,0,m*4,c[7][0].p+m),await s.readToBuffer(y.QR.eval,0,m*4,c[8][0].p+m),await s.readToBuffer(y.QM.eval,0,m*4,c[9][0].p+m),await s.readToBuffer(y.QO.eval,0,m*4,c[10][0].p+m),await s.readToBuffer(y.QC.eval,0,m*4,c[11][0].p+m),y.lagrange1=new Z(await G(s,c,15),u,n),_.T0=new I(m*4),n&&n.info(`··· Computing T0 evaluations`);for(let e=0;e=2*l.domainSize-2)throw Error(`T0 Polynomial is not well calculated (degree is ${v.T0.degree()} and must be less than ${2*l.domainSize+2}`);delete _.T0}async function i(){let e=new gc(4,u,n);if(e.addPolynomial(0,v.A),e.addPolynomial(1,v.B),e.addPolynomial(2,v.C),e.addPolynomial(3,v.T0),v.C1=e.getPolynomial(),v.C1.degree()>=8*l.domainSize-8)throw Error(`C1 Polynomial is not well calculated`)}}async function j(){n&&n.info(`> Computing challenges beta and gamma`);let e=new Ls(u);e.addPolCommitment(l.C0);for(let t=0;t Computing Z polynomial`),await r(),n&&n.info(`> Computing T1 polynomial`),await i(),n&&n.info(`> Computing T2 polynomial`),await a(),n&&n.info(`> Computing C2 polynomial`),await o(),n&&n.info(`> Computing C2 multi exponentiation`);let t=await v.C2.multiExponentiation(w,`C2`);return C.addPolynomial(`C2`,t),0;async function r(){n&&n.info(`··· Computing Z evaluations`);let e=new I(m),t=new I(m);e.set(d.one,0),t.set(d.one,0);let r=d.one;for(let i=0;i=l.domainSize+3)throw Error(`Z Polynomial is not well calculated`);delete _.Z}async function i(){n&&n.info(`··· Computing T1 evaluations`),_.T1=new I(m*2),_.T1z=new I(m*2);let e=d.one;for(let t=0;t=l.domainSize+2)throw Error(`T1 Polynomial is not well calculated`);delete _.T1,delete _.T1z,delete v.T1z}async function a(){n&&n.info(`··· Computing T2 evaluations`),_.T2=new I(m*4),_.T2z=new I(m*4);let e=d.one;for(let t=0;t=3*l.domainSize)throw Error(`T2 Polynomial is not well calculated`);delete _.T2,delete _.T2z,delete v.T2z}async function o(){let e=new gc(3,u,n);if(e.addPolynomial(0,v.Z),e.addPolynomial(1,v.T1),e.addPolynomial(2,v.T2),v.C2=e.getPolynomial(),v.C2.degree()>=9*l.domainSize)throw Error(`C2 Polynomial is not well calculated`)}}async function M(){n&&n.info(`> Computing challenge xi`);let e=new Ls(u);e.addScalar(x.gamma),e.addPolCommitment(C.getPolynomial(`C2`)),x.xiSeed=e.getChallenge();let t=d.square(x.xiSeed);S.w8=[],S.w8[0]=d.one;for(let e=1;e<8;e++)S.w8[e]=d.mul(S.w8[e-1],l.w8);S.w4=[],S.w4[0]=d.one;for(let e=1;e<4;e++)S.w4[e]=d.mul(S.w4[e-1],l.w4);S.w3=[],S.w3[0]=d.one,S.w3[1]=l.w3,S.w3[2]=d.square(l.w3),S.S0={},S.S0.h0w8=[],S.S0.h0w8[0]=d.mul(t,x.xiSeed);for(let e=1;e<8;e++)S.S0.h0w8[e]=d.mul(S.S0.h0w8[0],S.w8[e]);S.S1={},S.S1.h1w4=[],S.S1.h1w4[0]=d.square(S.S0.h0w8[0]);for(let e=1;e<4;e++)S.S1.h1w4[e]=d.mul(S.S1.h1w4[0],S.w4[e]);S.S2={},S.S2.h2w3=[],S.S2.h2w3[0]=d.mul(S.S1.h1w4[0],t),S.S2.h2w3[1]=d.mul(S.S2.h2w3[0],S.w3[1]),S.S2.h2w3[2]=d.mul(S.S2.h2w3[0],S.w3[2]),S.S2.h3w3=[],S.S2.h3w3[0]=d.mul(S.S2.h2w3[0],l.wr),S.S2.h3w3[1]=d.mul(S.S2.h3w3[0],S.w3[1]),S.S2.h3w3[2]=d.mul(S.S2.h3w3[0],S.w3[2]),x.xi=d.mul(d.square(S.S2.h2w3[0]),S.S2.h2w3[0]),n&&n.info(`··· challenges.xi: `+d.toString(x.xi)),v.QL=new X(new I(m),u,n),v.QR=new X(new I(m),u,n),v.QM=new X(new I(m),u,n),v.QO=new X(new I(m),u,n),v.QC=new X(new I(m),u,n),await s.readToBuffer(v.QL.coef,0,m,c[7][0].p),await s.readToBuffer(v.QR.coef,0,m,c[8][0].p),await s.readToBuffer(v.QM.coef,0,m,c[9][0].p),await s.readToBuffer(v.QO.coef,0,m,c[10][0].p),await s.readToBuffer(v.QC.coef,0,m,c[11][0].p),n&&n.info(`··· Computing evaluations`),C.addEvaluation(`ql`,v.QL.evaluate(x.xi)),C.addEvaluation(`qr`,v.QR.evaluate(x.xi)),C.addEvaluation(`qm`,v.QM.evaluate(x.xi)),C.addEvaluation(`qo`,v.QO.evaluate(x.xi)),C.addEvaluation(`qc`,v.QC.evaluate(x.xi)),C.addEvaluation(`s1`,v.Sigma1.evaluate(x.xi)),C.addEvaluation(`s2`,v.Sigma2.evaluate(x.xi)),C.addEvaluation(`s3`,v.Sigma3.evaluate(x.xi)),C.addEvaluation(`a`,v.A.evaluate(x.xi)),C.addEvaluation(`b`,v.B.evaluate(x.xi)),C.addEvaluation(`c`,v.C.evaluate(x.xi)),C.addEvaluation(`z`,v.Z.evaluate(x.xi)),x.xiw=d.mul(x.xi,d.w[l.power]),C.addEvaluation(`zw`,v.Z.evaluate(x.xiw)),C.addEvaluation(`t1w`,v.T1.evaluate(x.xiw)),C.addEvaluation(`t2w`,v.T2.evaluate(x.xiw))}async function ee(){n&&n.info(`> Computing challenge alpha`);let e=new Ls(u);e.addScalar(x.xiSeed),e.addScalar(C.getEvaluation(`ql`)),e.addScalar(C.getEvaluation(`qr`)),e.addScalar(C.getEvaluation(`qm`)),e.addScalar(C.getEvaluation(`qo`)),e.addScalar(C.getEvaluation(`qc`)),e.addScalar(C.getEvaluation(`s1`)),e.addScalar(C.getEvaluation(`s2`)),e.addScalar(C.getEvaluation(`s3`)),e.addScalar(C.getEvaluation(`a`)),e.addScalar(C.getEvaluation(`b`)),e.addScalar(C.getEvaluation(`c`)),e.addScalar(C.getEvaluation(`z`)),e.addScalar(C.getEvaluation(`zw`)),e.addScalar(C.getEvaluation(`t1w`)),e.addScalar(C.getEvaluation(`t2w`)),x.alpha=e.getChallenge(),n&&n.info(`··· challenges.alpha: `+d.toString(x.alpha)),n&&n.info(`> Reading C0 polynomial`),v.C0=new X(new I(m*8),u,n),await s.readToBuffer(v.C0.coef,0,m*8,c[17][0].p),n&&n.info(`> Computing R0 polynomial`),r(),n&&n.info(`> Computing R1 polynomial`),i(),n&&n.info(`> Computing R2 polynomial`),a(),n&&n.info(`> Computing F polynomial`),await o(),n&&n.info(`> Computing W1 multi exponentiation`);let t=await v.F.multiExponentiation(w,`W1`);return C.addPolynomial(`W1`,t),0;function r(){if(v.R0=X.lagrangePolynomialInterpolation([S.S0.h0w8[0],S.S0.h0w8[1],S.S0.h0w8[2],S.S0.h0w8[3],S.S0.h0w8[4],S.S0.h0w8[5],S.S0.h0w8[6],S.S0.h0w8[7]],[v.C0.evaluate(S.S0.h0w8[0]),v.C0.evaluate(S.S0.h0w8[1]),v.C0.evaluate(S.S0.h0w8[2]),v.C0.evaluate(S.S0.h0w8[3]),v.C0.evaluate(S.S0.h0w8[4]),v.C0.evaluate(S.S0.h0w8[5]),v.C0.evaluate(S.S0.h0w8[6]),v.C0.evaluate(S.S0.h0w8[7])],u),v.R0.degree()>7)throw Error(`R0 Polynomial is not well calculated`)}function i(){if(v.R1=X.lagrangePolynomialInterpolation([S.S1.h1w4[0],S.S1.h1w4[1],S.S1.h1w4[2],S.S1.h1w4[3]],[v.C1.evaluate(S.S1.h1w4[0]),v.C1.evaluate(S.S1.h1w4[1]),v.C1.evaluate(S.S1.h1w4[2]),v.C1.evaluate(S.S1.h1w4[3])],u),v.R1.degree()>3)throw Error(`R1 Polynomial is not well calculated`)}function a(){if(v.R2=X.lagrangePolynomialInterpolation([S.S2.h2w3[0],S.S2.h2w3[1],S.S2.h2w3[2],S.S2.h3w3[0],S.S2.h3w3[1],S.S2.h3w3[2]],[v.C2.evaluate(S.S2.h2w3[0]),v.C2.evaluate(S.S2.h2w3[1]),v.C2.evaluate(S.S2.h2w3[2]),v.C2.evaluate(S.S2.h3w3[0]),v.C2.evaluate(S.S2.h3w3[1]),v.C2.evaluate(S.S2.h3w3[2])],u),v.R2.degree()>5)throw Error(`R2 Polynomial is not well calculated`)}async function o(){n&&n.info(`··· Computing F polynomial`),v.F=X.fromPolynomial(v.C0,u,n),v.F.sub(v.R0),v.F.divByZerofier(8,x.xi);let e=X.fromPolynomial(v.C1,u,n);e.sub(v.R1),e.mulScalar(x.alpha),e.divByZerofier(4,x.xi);let t=X.fromPolynomial(v.C2,u,n);if(t.sub(v.R2),t.mulScalar(d.square(x.alpha)),t.divByZerofier(3,x.xi),t.divByZerofier(3,x.xiw),v.F.add(e),v.F.add(t),v.F.degree()>=9*l.domainSize-6)throw Error(`F Polynomial is not well calculated`)}}async function N(){n&&n.info(`> Computing challenge y`);let e=new Ls(u);e.addScalar(x.alpha),e.addPolCommitment(C.getPolynomial(`W1`)),x.y=e.getChallenge(),n&&n.info(`··· challenges.y: `+d.toString(x.y)),n&&n.info(`> Computing L polynomial`),await o(),n&&n.info(`> Computing ZTS2 polynomial`),await c();let t=v.ZTS2.evaluate(x.y);t=d.inv(t),v.L.mulScalar(t);let r=X.fromCoefficientsArray([d.neg(x.y),d.one],u);n&&n.info(`> Computing W' = L / ZTS2 polynomial`);let i=v.L.divBy(r);if(i.degree()>0)throw Error(`Degree of L(X)/(ZTS2(y)(X-y)) remainder is ${i.degree()} and should be 0`);if(v.L.degree()>=9*l.domainSize-1)throw Error(`Degree of L(X)/(ZTS2(y)(X-y)) is not correct`);n&&n.info(`> Computing W' multi exponentiation`);let a=await v.L.multiExponentiation(w,`W2`);return C.addPolynomial(`W2`,a),0;async function o(){n&&n.info(`··· Computing L polynomial`);let e=v.R0.evaluate(x.y),t=v.R1.evaluate(x.y),r=v.R2.evaluate(x.y),i=d.sub(x.y,S.S0.h0w8[0]);for(let e=1;e<8;e++)i=d.mul(i,d.sub(x.y,S.S0.h0w8[e]));let a=d.sub(x.y,S.S1.h1w4[0]);for(let e=1;e<4;e++)a=d.mul(a,d.sub(x.y,S.S1.h1w4[e]));let o=d.sub(x.y,S.S2.h2w3[0]);for(let e=1;e<3;e++)o=d.mul(o,d.sub(x.y,S.S2.h2w3[e]));for(let e=0;e<3;e++)o=d.mul(o,d.sub(x.y,S.S2.h3w3[e]));let c=d.mul(a,o),f=d.mul(x.alpha,d.mul(i,o)),p=d.mul(d.square(x.alpha),d.mul(i,a));b.denH1=a,b.denH2=o,v.L=X.fromPolynomial(v.C0,u,n),v.L.subScalar(e),v.L.mulScalar(c);let m=X.fromPolynomial(v.C1,u,n);m.subScalar(t),m.mulScalar(f);let h=X.fromPolynomial(v.C2,u,n);h.subScalar(r),h.mulScalar(p),v.L.add(m),v.L.add(h),n&&n.info(`> Computing ZT polynomial`),await s();let g=v.ZT.evaluate(x.y);if(v.F.mulScalar(g),v.L.sub(v.F),v.L.degree()>=9*l.domainSize)throw Error(`L Polynomial is not well calculated`);delete _.L}async function s(){v.ZT=X.zerofierPolynomial([S.S0.h0w8[0],S.S0.h0w8[1],S.S0.h0w8[2],S.S0.h0w8[3],S.S0.h0w8[4],S.S0.h0w8[5],S.S0.h0w8[6],S.S0.h0w8[7],S.S1.h1w4[0],S.S1.h1w4[1],S.S1.h1w4[2],S.S1.h1w4[3],S.S2.h2w3[0],S.S2.h2w3[1],S.S2.h2w3[2],S.S2.h3w3[0],S.S2.h3w3[1],S.S2.h3w3[2]],u)}async function c(){v.ZTS2=X.zerofierPolynomial([S.S1.h1w4[0],S.S1.h1w4[1],S.S1.h1w4[2],S.S1.h1w4[3],S.S2.h2w3[0],S.S2.h2w3[1],S.S2.h2w3[2],S.S2.h3w3[0],S.S2.h3w3[1],S.S2.h3w3[2]],u)}}function P(){let e=x.xi;for(let t=0;t Checking commitments belong to G1`),!Tc(i,o,a))return r&&r.error(`Proof commitments are not valid`),!1;if(r&&r.info(`> Checking evaluations belong to F`),!Oc(i,o))return r&&r.error(`Proof evaluations are not valid.`),!1;if(r&&r.info(`> Checking public inputs belong to F`),!kc(i,s))return r&&r.error(`Public inputs are not valid.`),!1;r&&r.info(`> Computing challenges`);let{challenges:l,roots:u}=Ac(i,o,a,s,r);r&&r.info(`> Computing Zero polynomial evaluation Z_H(xi)`),l.zh=c.sub(l.xiN,c.one),l.invzh=c.inv(l.zh),r&&r.info(`> Computing Lagrange evaluations`);let d=await jc(i,l,a);r&&r.info(`> Computing polynomial identities PI(X)`);let f=Mc(i,s,d);r&&r.info(`> Computing r0(y)`);let p=Nc(o,l,u,i,r);r&&r.info(`> Computing r1(y)`);let m=Pc(o,l,u,f,i,r);r&&r.info(`> Computing r2(y)`);let h=Fc(o,l,u,d[1],a,i,r);r&&r.info(`> Computing F`);let g=Ic(i,o,a,l,u);r&&r.info(`> Computing E`);let _=Lc(i,o,l,a,p,m,h);r&&r.info(`> Computing J`);let v=Rc(i,o,l);r&&r.info(`> Validate all evaluations with a pairing`);let y=await zc(i,o,l,a,g,_,v);return r&&(y?r.info(`PROOF VERIFIED SUCCESSFULLY`):r.warn(`Invalid Proof`)),r&&r.info(`FFLONK VERIFIER FINISHED`),y}function wc(e,t){let n=t;return n.k1=e.Fr.fromObject(t.k1),n.k2=e.Fr.fromObject(t.k2),n.w=e.Fr.fromObject(t.w),n.w3=e.Fr.fromObject(t.w3),n.w4=e.Fr.fromObject(t.w4),n.w8=e.Fr.fromObject(t.w8),n.wr=e.Fr.fromObject(t.wr),n.X_2=e.G2.fromObject(t.X_2),n.C0=e.G1.fromObject(t.C0),n}function Tc(e,t,n){let r=e.G1;return r.isValid(t.polynomials.C1)&&r.isValid(t.polynomials.C2)&&r.isValid(t.polynomials.W1)&&r.isValid(t.polynomials.W2)&&r.isValid(n.C0)}function Ec(e,t){return L.geq(t,0)&&L.lt(t,e.r)}function Dc(e,t){return Ec(e,L.fromRprLE(t))}function Oc(e,t){return Dc(e,t.evaluations.ql)&&Dc(e,t.evaluations.qr)&&Dc(e,t.evaluations.qm)&&Dc(e,t.evaluations.qo)&&Dc(e,t.evaluations.qc)&&Dc(e,t.evaluations.s1)&&Dc(e,t.evaluations.s2)&&Dc(e,t.evaluations.s3)&&Dc(e,t.evaluations.a)&&Dc(e,t.evaluations.b)&&Dc(e,t.evaluations.c)&&Dc(e,t.evaluations.z)&&Dc(e,t.evaluations.zw)&&Dc(e,t.evaluations.t1w)&&Dc(e,t.evaluations.t2w)}function kc(e,t){for(let n=0;nUc,exportSolidityVerifier:()=>null,fullProve:()=>xc,prove:()=>yc,setup:()=>_c,verify:()=>Cc});return Object.defineProperty(e,"curves",{enumerable:!0,get:function(){return nr}}),Object.defineProperty(e,"fflonk",{enumerable:!0,get:function(){return Wc}}),Object.defineProperty(e,"groth16",{enumerable:!0,get:function(){return Ea}}),Object.defineProperty(e,"plonk",{enumerable:!0,get:function(){return cc}}),Object.defineProperty(e,"powersOfTau",{enumerable:!0,get:function(){return io}}),Object.defineProperty(e,"r1cs",{enumerable:!0,get:function(){return Uo}}),Object.defineProperty(e,"wtns",{enumerable:!0,get:function(){return Yo}}),Object.defineProperty(e,"zKey",{enumerable:!0,get:function(){return hs}}),e})({}); \ No newline at end of file diff --git a/config/rollup.browser.esm.config.js b/config/rollup.browser.esm.config.js deleted file mode 100644 index 70597a7e..00000000 --- a/config/rollup.browser.esm.config.js +++ /dev/null @@ -1,53 +0,0 @@ -import { nodeResolve } from "@rollup/plugin-node-resolve"; -import commonJS from "@rollup/plugin-commonjs"; -import virtual from "@rollup/plugin-virtual"; -import replace from "@rollup/plugin-replace"; -// Needed by fastfile -import { O_TRUNC, O_CREAT, O_RDWR, O_EXCL, O_RDONLY } from "constants"; - -const empty = "export default {}"; -// We create a stub with these constants instead of including the entire constants definition -const constants = ` -export const O_TRUNC = ${O_TRUNC}; -export const O_CREAT = ${O_CREAT}; -export const O_RDWR = ${O_RDWR}; -export const O_EXCL = ${O_EXCL}; -export const O_RDONLY = ${O_RDONLY} -`; - -export default { - input: "main.js", - output: { - file: "build/browser.esm.js", - format: "es", - inlineDynamicImports: true, - }, - external: ["ffjavascript"], - plugins: [ - replace({ - // The current default is false, but they are changing it next version - preventAssignment: false, - "process.browser": true, - }), - virtual({ - fs: empty, - os: empty, - crypto: empty, - readline: empty, - ejs: empty, - events: empty, - stream: empty, - util: empty, - constants, - }), - nodeResolve({ - browser: true, - preferBuiltins: false, - exportConditions: ["module"], - }), - commonJS(), - ], - treeshake: { - preset: "smallest", - }, -}; diff --git a/config/rollup.cjs.config.js b/config/rollup.cjs.config.js deleted file mode 100644 index 003dc223..00000000 --- a/config/rollup.cjs.config.js +++ /dev/null @@ -1,19 +0,0 @@ -import fs from "fs"; -import { builtinModules as builtin } from "module"; - -const pkg = JSON.parse(fs.readFileSync("./package.json")); - -export default { - input: "main.js", - output: { - file: "build/main.cjs", - format: "cjs", - }, - external: [ - "@noble/hashes/blake2.js", - "@noble/hashes/utils.js", - "@noble/hashes/sha3.js", - ...Object.keys(pkg.dependencies), - ...builtin, - ] -}; diff --git a/config/rollup.cli.config.js b/config/rollup.cli.config.js deleted file mode 100644 index 23d3b4bf..00000000 --- a/config/rollup.cli.config.js +++ /dev/null @@ -1,20 +0,0 @@ -import fs from "fs"; -import { builtinModules as builtin } from "module"; - -const pkg = JSON.parse(fs.readFileSync("./package.json")); - -export default { - input: "cli.js", - output: { - file: "build/cli.cjs", - format: "cjs", - banner: "#!/usr/bin/node --expose-gc \n", - }, - external: [ - "@noble/hashes/blake2.js", - "@noble/hashes/utils.js", - "@noble/hashes/sha3.js", - ...Object.keys(pkg.dependencies), - ...builtin, - ] -}; diff --git a/config/rollup.iife.config.js b/config/rollup.iife.config.js deleted file mode 100644 index 045aa46b..00000000 --- a/config/rollup.iife.config.js +++ /dev/null @@ -1,71 +0,0 @@ -import { nodeResolve } from "@rollup/plugin-node-resolve"; -import commonJS from "@rollup/plugin-commonjs"; -import virtual from "@rollup/plugin-virtual"; -import replace from "@rollup/plugin-replace"; -import visualizer from "rollup-plugin-visualizer"; -// Needed by fastfile -import { O_TRUNC, O_CREAT, O_RDWR, O_EXCL, O_RDONLY } from "constants"; - -const empty = "export default {}"; -// Runtime wasm codegen toolchain (wasmbuilder + the wasmcurves generators). -// Only reachable through ffjavascript's custom-`plugins` curve-build path, -// which snarkjs never takes: the prebuilt vendored wasm is always used. -// `inlineDynamicImports` would otherwise fold the whole toolchain into the -// single-file bundle. IIFE output cannot keep external dynamic imports, so -// stub the packages with a clear error instead. -const wasmToolchainStub = (name) => ` -const err = () => { throw new Error("${name} is not included in the snarkjs browser bundle (only needed when building a curve with custom wasm plugins)"); }; -export class ModuleBuilder { constructor() { err(); } } -export const buildBn128 = err; -export const buildBls12381 = err; -export default {}; -`; -// We create a stub with these constants instead of including the entire constants definition -const constants = ` -export const O_TRUNC = ${O_TRUNC}; -export const O_CREAT = ${O_CREAT}; -export const O_RDWR = ${O_RDWR}; -export const O_EXCL = ${O_EXCL}; -export const O_RDONLY = ${O_RDONLY} -`; - -export default { - input: "main.js", - output: { - file: "build/snarkjs.js", - format: "iife", - sourcemap: "inline", - globals: { - os: "null" - }, - name: "snarkjs", - inlineDynamicImports: true, - }, - plugins: [ - virtual({ - fs: empty, - os: empty, - crypto: empty, - readline: empty, - ejs: empty, - events: empty, - stream: empty, - util: empty, - constants: constants, - wasmbuilder: wasmToolchainStub("wasmbuilder"), - wasmcurves: wasmToolchainStub("wasmcurves"), - }), - nodeResolve({ - browser: true, - preferBuiltins: false, - exportConditions: ["browser", "default", "module", "require"] - }), - commonJS(), - replace({ - // The current default is false, but they are changing it next version - preventAssignment: false, - "process.browser": !!process.env.BROWSER - }), - visualizer(), - ] -}; diff --git a/config/rollup.iife_min.config.js b/config/rollup.iife_min.config.js deleted file mode 100644 index 1805d65c..00000000 --- a/config/rollup.iife_min.config.js +++ /dev/null @@ -1,15 +0,0 @@ -import config from "./rollup.iife.config.js"; -import terser from "@rollup/plugin-terser"; - -export default { - ...config, - output: { - ...config.output, - file: "build/snarkjs.min.js", - sourcemap: false, - }, - plugins: [ - ...config.plugins, - terser(), - ] -}; diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..94a1b284 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,37 @@ +import js from "@eslint/js"; +import globals from "globals"; + +export default [ + { ignores: [".claude/**", "browser_tests/**", "build/**", "templates/**", "credentialAtomicQueryV3OnChain/**", "test/circuit2/**", "smart_contract_tests/**", "scripts/**"] }, + js.configs.recommended, + { + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: { + ...globals.node, + ...globals.browser, + describe: "readonly", + it: "readonly", + test: "readonly", + expect: "readonly", + beforeAll: "readonly", + afterAll: "readonly", + beforeEach: "readonly", + afterEach: "readonly", + vi: "readonly", + globalThis: "readonly", + }, + }, + rules: { + indent: ["error", 4], + "linebreak-style": ["warn", "unix"], + quotes: ["error", "double"], + semi: ["error", "always"], + // Unused function args are kept for API shape (logger, curve, Fr, ...). + "no-unused-vars": ["error", { "args": "none", "varsIgnorePattern": "^_", "caughtErrorsIgnorePattern": "^_" }], + // The prover deliberately nulls large buffers before globalThis.gc(). + "no-useless-assignment": "off", + }, + }, +]; diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index cdd87e82..00000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,28 +0,0 @@ -import js from "@eslint/js"; -import globals from "globals"; - -export default [ - { ignores: ["build/", "templates/", "browser_tests/", ".clinic/", "artifacts/", "cache/", "contracts/"] }, - js.configs.recommended, - { - languageOptions: { - ecmaVersion: 2022, - sourceType: "module", - globals: { - ...globals.node, - ...globals.mocha, - }, - }, - rules: { - // Unused function params are kept for API shape (logger, curve, ...). - "no-unused-vars": ["error", { args: "none" }], - // The prover deliberately nulls large buffers before globalThis.gc() - // to release memory early; this rule flags exactly that idiom. - "no-useless-assignment": "off", - "indent": ["error", 4], - "linebreak-style": ["error", "unix"], - "quotes": ["error", "double"], - "semi": ["error", "always"], - }, - }, -]; diff --git a/package-lock.json b/package-lock.json index d9d66c08..1872000d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,17 +24,55 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@rollup/plugin-commonjs": "^29.0.3", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^16.0.3", - "@rollup/plugin-replace": "^6.0.3", - "@rollup/plugin-terser": "^1.0.0", - "@rollup/plugin-virtual": "^3.0.2", + "@vitest/browser": "^4.1.2", + "@vitest/browser-playwright": "^4.1.2", "eslint": "^10.6.0", "globals": "^17.7.0", - "mocha": "^11.7.6", - "rollup": "^4.62.2", - "rollup-plugin-visualizer": "^7.0.1" + "playwright": "^1.59.0", + "rimraf": "^6.1.3", + "vite": "^8.0.3", + "vitest": "^4.1.2" + } + }, + "node_modules/@blazediff/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz", + "integrity": "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/@eslint-community/eslint-utils": { @@ -247,56 +285,6 @@ "ffjavascript": "git+https://github.com/iden3/ffjavascript.git#7e0a5850c1f1e9116a93e4845e9ea28bb694300e" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -304,15 +292,23 @@ "dev": true, "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@noble/hashes": { @@ -327,194 +323,27 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@rollup/plugin-commonjs": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.3.tgz", - "integrity": "sha512-ZaOxZceP7SOUW7Lqw5IRVweSQYWaeIPnXIGLiB690EBA3FGJTO40EEr2L5yZplJWsgTCogILRSpcAe7+U0Otdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "fdir": "^6.2.0", - "is-reference": "1.2.1", - "magic-string": "^0.30.3", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=16.0.0 || 14 >= 14.17" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-json": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", - "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.1.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", - "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-replace": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", - "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.30.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-terser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", - "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "serialize-javascript": "^7.0.3", - "smob": "^1.0.0", - "terser": "^5.17.4" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-virtual": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz", - "integrity": "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", - "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "node_modules/@oxc-project/types": { + "version": "0.137.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.137.0.tgz", + "integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==", "dev": true, "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", - "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", - "cpu": [ - "arm" - ], + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", - "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.3.tgz", + "integrity": "sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==", "cpu": [ "arm64" ], @@ -523,12 +352,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", - "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.3.tgz", + "integrity": "sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==", "cpu": [ "arm64" ], @@ -537,12 +369,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", - "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.3.tgz", + "integrity": "sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==", "cpu": [ "x64" ], @@ -551,26 +386,15 @@ "optional": true, "os": [ "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", - "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", - "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.3.tgz", + "integrity": "sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==", "cpu": [ "x64" ], @@ -579,46 +403,32 @@ "optional": true, "os": [ "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", - "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "glibc" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", - "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.3.tgz", + "integrity": "sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==", "cpu": [ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", - "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.3.tgz", + "integrity": "sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==", "cpu": [ "arm64" ], @@ -630,12 +440,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", - "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.3.tgz", + "integrity": "sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==", "cpu": [ "arm64" ], @@ -647,14 +460,17 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", - "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.3.tgz", + "integrity": "sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==", "cpu": [ - "loong64" + "ppc64" ], "dev": true, "libc": [ @@ -664,31 +480,37 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", - "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.3.tgz", + "integrity": "sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==", "cpu": [ - "loong64" + "s390x" ], "dev": true, "libc": [ - "musl" + "glibc" ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", - "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.3.tgz", + "integrity": "sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==", "cpu": [ - "ppc64" + "x64" ], "dev": true, "libc": [ @@ -698,14 +520,17 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", - "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.3.tgz", + "integrity": "sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==", "cpu": [ - "ppc64" + "x64" ], "dev": true, "libc": [ @@ -715,176 +540,123 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", - "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.3.tgz", + "integrity": "sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==", "cpu": [ - "riscv64" + "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ - "linux" - ] + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", - "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.3.tgz", + "integrity": "sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==", "cpu": [ - "riscv64" + "wasm32" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", - "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.3.tgz", + "integrity": "sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==", "cpu": [ - "s390x" + "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ - "linux" - ] + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", - "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.3.tgz", + "integrity": "sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==", "cpu": [ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", - "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", - "cpu": [ - "x64" + "win32" ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", - "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", - "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", - "cpu": [ - "arm64" - ], + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", - "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", - "cpu": [ - "arm64" - ], + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", - "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", - "cpu": [ - "ia32" - ], + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "tslib": "^2.4.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", - "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", - "cpu": [ - "x64" - ], + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", - "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", - "cpu": [ - "x64" - ], + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, "node_modules/@types/esrecurse": { "version": "4.3.1", @@ -907,12 +679,175 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "node_modules/@vitest/browser": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.9.tgz", + "integrity": "sha512-j1BKtWmPcqpMhmx/L9EPLgAJpCb0zKfwoWLmqBbxaogCXHjOwHFSEoHCBfnGtx93xKQwilZ26m+UOsHqHMkRNg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@blazediff/core": "1.9.1", + "@vitest/mocker": "4.1.9", + "@vitest/utils": "4.1.9", + "magic-string": "^0.30.21", + "pngjs": "^7.0.0", + "sirv": "^3.0.2", + "tinyrainbow": "^3.1.0", + "ws": "^8.19.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.1.9" + } + }, + "node_modules/@vitest/browser-playwright": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.9.tgz", + "integrity": "sha512-Bq1rOGf9waevzG3EOkO/dene6bvKTUsZMVg8S1i+WH3JcMjuXEjiahP9rAqZRELUqjBySOJsvvSWqK/B3wjKQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/browser": "4.1.9", + "@vitest/mocker": "4.1.9", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "playwright": "*", + "vitest": "4.1.9" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": false + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.9", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.9", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, "node_modules/acorn": { "version": "8.17.0", @@ -954,40 +889,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -1025,61 +936,14 @@ "node": "18 || 20 || >=22" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "dev": true, "license": "MIT", - "dependencies": { - "run-applescript": "^7.0.0" - }, "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/check-types": { @@ -1087,22 +951,6 @@ "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", "integrity": "sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==" }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/circom_runtime": { "version": "0.1.28", "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.28.tgz", @@ -1115,115 +963,13 @@ "calcwit": "calcwit.js" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1256,18 +1002,6 @@ } } }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1275,75 +1009,16 @@ "dev": true, "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-browser": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", - "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", - "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/diff": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "Apache-2.0", "engines": { - "node": ">=0.3.1" + "node": ">=8" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, "node_modules/ejs": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ejs/-/ejs-6.0.1.tgz", @@ -1356,23 +1031,13 @@ "node": ">=0.12.18" } }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true, "license": "MIT" }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1530,12 +1195,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1546,6 +1205,16 @@ "node": ">=0.10.0" } }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1633,15 +1302,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -1663,23 +1323,6 @@ "dev": true, "license": "ISC" }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1694,60 +1337,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", - "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1761,39 +1350,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { "version": "17.7.0", "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", @@ -1807,36 +1363,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -1865,34 +1391,6 @@ "node": ">=0.8.19" } }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1902,16 +1400,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1924,214 +1412,338 @@ "node": ">=0.10.0" } }, - "node_modules/is-in-ssh": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", - "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "ISC" }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true + "license": "MIT" }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "*" + "json-buffer": "3.0.1" } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/is-wsl": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", - "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", "dev": true, - "license": "MIT", + "license": "MPL-2.0", "dependencies": { - "is-inside-container": "^1.0.0" + "detect-libc": "^2.0.3" }, "engines": { - "node": ">=16" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC" + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" + "engines": { + "node": ">= 12.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.8.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "p-locate": "^5.0.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=10" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "p-locate": "^5.0.0" }, "engines": { "node": ">=10" @@ -2145,13 +1757,6 @@ "resolved": "https://registry.npmjs.org/logplease/-/logplease-1.2.15.tgz", "integrity": "sha512-jLlHnlsPSJjpwUfcNyUxXCl33AYg2cHhIf9QhGL2T4iPT0XPB+xP1LRKFPgIg1M/sg9kAJvy94w9CzBNrfnstA==" }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -2188,95 +1793,14 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/mocha": { - "version": "11.7.6", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.6.tgz", - "integrity": "sha512-nS9xOGbw2I3cjCpxwZAEJ9xK9lmJ08vEkQvLtz4du9ZrF9UrjRpeJGiIgl2Z+Qs++pmB4ecDe48Fwsh+j+j7xA==", - "dev": true, - "license": "MIT", - "dependencies": { - "browser-stdout": "^1.3.1", - "chokidar": "^4.0.1", - "debug": "^4.3.5", - "diff": "^7.0.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^10.4.5", - "he": "^1.2.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^9.0.5", - "ms": "^2.1.3", - "picocolors": "^1.1.1", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^9.2.0", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/mocha/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/ms": { @@ -2285,6 +1809,25 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2292,25 +1835,18 @@ "dev": true, "license": "MIT" }, - "node_modules/open": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", - "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "node_modules/obug": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", + "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], "license": "MIT", - "dependencies": { - "default-browser": "^5.4.0", - "define-lazy-prop": "^3.0.0", - "is-in-ssh": "^1.0.0", - "is-inside-container": "^1.0.0", - "powershell-utils": "^0.1.0", - "wsl-utils": "^0.3.0" - }, "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12.20.0" } }, "node_modules/optionator": { @@ -2387,33 +1923,17 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, @@ -2430,17 +1950,90 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/powershell-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", - "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "node_modules/playwright": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz", + "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.61.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz", + "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", "dev": true, "license": "MIT", "engines": { - "node": ">=20" + "node": ">=14.19.0" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^10 || ^12 || >=14" } }, "node_modules/prelude-ls": { @@ -2475,243 +2068,103 @@ "ffjavascript": "git+https://github.com/iden3/ffjavascript.git#7e0a5850c1f1e9116a93e4845e9ea28bb694300e" } }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "node_modules/rimraf": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "glob": "^13.0.3", + "package-json-from-dist": "^1.0.1" }, "bin": { - "resolve": "bin/resolve" + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rollup": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", - "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "node_modules/rimraf/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "@types/estree": "1.0.9" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.62.2", - "@rollup/rollup-android-arm64": "4.62.2", - "@rollup/rollup-darwin-arm64": "4.62.2", - "@rollup/rollup-darwin-x64": "4.62.2", - "@rollup/rollup-freebsd-arm64": "4.62.2", - "@rollup/rollup-freebsd-x64": "4.62.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", - "@rollup/rollup-linux-arm-musleabihf": "4.62.2", - "@rollup/rollup-linux-arm64-gnu": "4.62.2", - "@rollup/rollup-linux-arm64-musl": "4.62.2", - "@rollup/rollup-linux-loong64-gnu": "4.62.2", - "@rollup/rollup-linux-loong64-musl": "4.62.2", - "@rollup/rollup-linux-ppc64-gnu": "4.62.2", - "@rollup/rollup-linux-ppc64-musl": "4.62.2", - "@rollup/rollup-linux-riscv64-gnu": "4.62.2", - "@rollup/rollup-linux-riscv64-musl": "4.62.2", - "@rollup/rollup-linux-s390x-gnu": "4.62.2", - "@rollup/rollup-linux-x64-gnu": "4.62.2", - "@rollup/rollup-linux-x64-musl": "4.62.2", - "@rollup/rollup-openbsd-x64": "4.62.2", - "@rollup/rollup-openharmony-arm64": "4.62.2", - "@rollup/rollup-win32-arm64-msvc": "4.62.2", - "@rollup/rollup-win32-ia32-msvc": "4.62.2", - "@rollup/rollup-win32-x64-gnu": "4.62.2", - "@rollup/rollup-win32-x64-msvc": "4.62.2", - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-visualizer": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-7.0.1.tgz", - "integrity": "sha512-UJUT4+1Ho4OcWmPYU3sYXgUqI8B8Ayfe06MX7y0qCJ1K8aGoKtR/NDd/2nZqM7ADkrzny+I99Ul7GgyoiVNAgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "open": "^11.0.0", - "picomatch": "^4.0.2", - "source-map": "^0.7.4", - "yargs": "^18.0.0" - }, - "bin": { - "rollup-plugin-visualizer": "dist/bin/cli.js" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": ">=22" - }, - "peerDependencies": { - "rolldown": "1.x || ^1.0.0-beta || ^1.0.0-rc", - "rollup": "2.x || 3.x || 4.x" - }, - "peerDependenciesMeta": { - "rolldown": { - "optional": true - }, - "rollup": { - "optional": true - } - } - }, - "node_modules/rollup-plugin-visualizer/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rollup-plugin-visualizer/node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "node_modules/rimraf/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=20" + "node": "20 || >=22" } }, - "node_modules/rollup-plugin-visualizer/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/rollup-plugin-visualizer/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "node_modules/rimraf/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=18" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rollup-plugin-visualizer/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "node_modules/rolldown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz", + "integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "@oxc-project/types": "=0.137.0", + "@rolldown/pluginutils": "^1.0.0" }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/rollup-plugin-visualizer/node_modules/yargs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" + "bin": { + "rolldown": "bin/cli.mjs" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/rollup-plugin-visualizer/node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/run-applescript": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", - "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/serialize-javascript": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.6.tgz", - "integrity": "sha512-ATTK5Q4gFVg0YDp1my2vqygyvhcklD/UV5GIlYHooGTn/NogJqIzpetkD6E5kmuVULqz/S9inUL25XcAgDRJQg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=20.0.0" + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.3", + "@rolldown/binding-darwin-arm64": "1.1.3", + "@rolldown/binding-darwin-x64": "1.1.3", + "@rolldown/binding-freebsd-x64": "1.1.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.3", + "@rolldown/binding-linux-arm64-gnu": "1.1.3", + "@rolldown/binding-linux-arm64-musl": "1.1.3", + "@rolldown/binding-linux-ppc64-gnu": "1.1.3", + "@rolldown/binding-linux-s390x-gnu": "1.1.3", + "@rolldown/binding-linux-x64-gnu": "1.1.3", + "@rolldown/binding-linux-x64-musl": "1.1.3", + "@rolldown/binding-openharmony-arm64": "1.1.3", + "@rolldown/binding-wasm32-wasi": "1.1.3", + "@rolldown/binding-win32-arm64-msvc": "1.1.3", + "@rolldown/binding-win32-x64-msvc": "1.1.3" } }, "node_modules/shebang-command": { @@ -2737,216 +2190,104 @@ "node": ">=8" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/smob": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.6.2.tgz", - "integrity": "sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, - "engines": { - "node": ">= 8" - } + "license": "ISC" }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", "dev": true, "license": "MIT", "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, "license": "MIT" }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.2.2" + "fdir": "^6.5.0", + "picomatch": "^4.0.4" }, "engines": { - "node": ">=12" + "node": ">=12.0.0" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">=14.0.0" } }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/terser": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", - "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" + "node": ">=6" } }, "node_modules/tryer": { @@ -2954,6 +2295,14 @@ "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD", + "optional": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -2977,6 +2326,174 @@ "punycode": "^2.1.0" } }, + "node_modules/vite": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.0.tgz", + "integrity": "sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "~1.1.2", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, "node_modules/wasmbuilder": { "version": "0.0.16", "resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.16.tgz", @@ -3016,232 +2533,53 @@ "node": ">= 8" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "9.3.4", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", - "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "siginfo": "^2.0.0", + "stackback": "0.0.2" }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" + "bin": { + "why-is-node-running": "cli.js" }, "engines": { "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wsl-utils": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", - "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-wsl": "^3.1.0", - "powershell-utils": "^0.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", - "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "node": ">=10.0.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" }, - "engines": { - "node": ">=8" + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/yocto-queue": { diff --git a/package.json b/package.json index e14835d8..82d25293 100644 --- a/package.json +++ b/package.json @@ -25,14 +25,17 @@ "templates/" ], "scripts": { - "test": "mocha", - "testv12": "mocha test/fflonk.test.js test/fullprocess.js test/keypar_test.js test/polynomial.test.js", - "build": "npm run buildcjs && npm run buildcli && npm run buildiife && npm run buildiifemin && npm run buildesm", - "buildcjs": "rollup -c config/rollup.cjs.config.js", - "buildcli": "rollup -c config/rollup.cli.config.js", - "buildiife": "BROWSER=true rollup -c config/rollup.iife.config.js", - "buildiifemin": "BROWSER=true rollup -c config/rollup.iife_min.config.js", - "buildesm": "BROWSER=true rollup -c config/rollup.browser.esm.config.js" + "lint": "eslint .", + "clean": "rimraf build", + "pretest": "npm run build:node && npm run build:browser && npm run lint", + "test": "vitest run", + "test:node": "vitest run --project node-esm", + "test:watch": "vitest --project node-esm", + "build:node": "vite build", + "build:cli": "vite build --mode cli", + "build:browser": "vite build --mode browser", + "build:iife": "vite build --mode browser-iife", + "build": "npm run clean && npm run build:node && npm run build:cli && npm run build:browser && npm run build:iife" }, "bin": { "snarkjs": "build/cli.cjs" @@ -68,17 +71,14 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@rollup/plugin-commonjs": "^29.0.3", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^16.0.3", - "@rollup/plugin-replace": "^6.0.3", - "@rollup/plugin-terser": "^1.0.0", - "@rollup/plugin-virtual": "^3.0.2", + "@vitest/browser": "^4.1.2", + "@vitest/browser-playwright": "^4.1.2", "eslint": "^10.6.0", "globals": "^17.7.0", - "mocha": "^11.7.6", - "rollup": "^4.62.2", - "rollup-plugin-visualizer": "^7.0.1" + "playwright": "^1.59.0", + "rimraf": "^6.1.3", + "vite": "^8.0.3", + "vitest": "^4.1.2" }, "overrides": { "serialize-javascript": "^7.0.5", diff --git a/src/misc.js b/src/misc.js index e3d6bb34..d0aacad5 100644 --- a/src/misc.js +++ b/src/misc.js @@ -17,7 +17,6 @@ along with snarkJS. If not, see . */ -/* global window */ import { blake2b } from "@noble/hashes/blake2.js"; import { u32 } from "@noble/hashes/utils.js"; import readline from "readline"; diff --git a/test/fflonk.test.js b/test/fflonk.test.js index 5081a6b2..ed26c9f6 100644 --- a/test/fflonk.test.js +++ b/test/fflonk.test.js @@ -10,23 +10,23 @@ const { stringifyBigInts } = utils; describe("Fflonk test suite", function () { - const publicInputsFilename = path.join("test", "fflonk", "public.json"); - const proofFilename = path.join("test", "fflonk", "proof.json"); + const _publicInputsFilename = path.join("test", "fflonk", "public.json"); + const _proofFilename = path.join("test", "fflonk", "proof.json"); const r1csFilename = path.join("test", "fflonk", "circuit.r1cs"); const ptauFilename = path.join("test", "plonk_circuit", "powersOfTau15_final.ptau"); const zkeyFilename = path.join("test", "fflonk", "circuit.zkey"); const wtnsFilename = path.join("test", "fflonk", "witness.wtns"); const vkeyFilename = path.join("test", "fflonk", "circuit_vk.json"); - this.timeout(1000000000); + let curve; - before(async () => { + beforeAll(async () => { curve = await getCurveFromName("bn128"); }); - after(async () => { + afterAll(async () => { await curve.terminate(); }); diff --git a/test/fullprocess.js b/test/fullprocess.js index 21b312be..19383bde 100644 --- a/test/fullprocess.js +++ b/test/fullprocess.js @@ -4,7 +4,7 @@ import assert from "assert"; import path from "path"; describe("Full process", function () { - this.timeout(1000000000); + let curve; const ptau_0 = {type: "mem"}; @@ -27,11 +27,11 @@ describe("Full process", function () { let publicSignals; let publicSignalsWithAlias; - before( async () => { + beforeAll(async () => { curve = await getCurveFromName("bn128"); // curve.Fr.s = 10; }); - after( async () => { + afterAll(async () => { await curve.terminate(); // console.log(process._getActiveHandles()); // console.log(process._getActiveRequests()); diff --git a/test/groth16.test.js b/test/groth16.test.js new file mode 100644 index 00000000..67b98844 --- /dev/null +++ b/test/groth16.test.js @@ -0,0 +1,96 @@ +import * as snarkjs from "../main.js"; + +// Vitest browser tests are served from project root via Vite dev server, +// so browser paths need a leading slash; Node tests use CWD-relative paths. +const isBrowser = typeof window !== "undefined"; +const p = (rel) => (isBrowser ? `/${rel}` : rel); + +const r1cs = p("test/groth16/circuit.r1cs"); +const wasm = p("test/groth16/circuit.wasm"); + +describe("Groth16", function () { + let curve; + const ptau_0 = { type: "mem" }; + const ptau_1 = { type: "mem" }; + const ptau_beacon = { type: "mem" }; + const ptau_final = { type: "mem" }; + const zkey_0 = { type: "mem" }; + const zkey_1 = { type: "mem" }; + const zkey_final = { type: "mem" }; + const wtns = { type: "mem" }; + let vKey; + let proof; + let publicSignals; + + beforeAll(async () => { + curve = await snarkjs.curves.getCurveFromName("bn128"); + await snarkjs.powersOfTau.newAccumulator(curve, 11, ptau_0); + await snarkjs.powersOfTau.contribute(ptau_0, ptau_1, "C1", "Entropy1"); + await snarkjs.powersOfTau.beacon( + ptau_1, + ptau_beacon, + "B3", + "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + 10 + ); + await snarkjs.powersOfTau.preparePhase2(ptau_beacon, ptau_final); + }, 300_000); + + afterAll(async () => { + await curve.terminate(); + }); + + it("zkey new", async () => { + await snarkjs.zKey.newZKey(r1cs, ptau_final, zkey_0); + }); + + it("zkey contribute", async () => { + await snarkjs.zKey.contribute(zkey_0, zkey_1, "p2_C1", "pa_Entropy1"); + }); + + it("zkey beacon", async () => { + await snarkjs.zKey.beacon( + zkey_1, + zkey_final, + "B3", + "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + 10 + ); + }); + + it("zkey verify from r1cs", async () => { + const res = await snarkjs.zKey.verifyFromR1cs(r1cs, ptau_final, zkey_final); + expect(res).toBe(true); + }); + + it("zkey verify from init", async () => { + const res = await snarkjs.zKey.verifyFromInit(zkey_0, ptau_final, zkey_final); + expect(res).toBe(true); + }); + + it("zkey export verification key", async () => { + vKey = await snarkjs.zKey.exportVerificationKey(zkey_final); + expect(vKey).toBeTruthy(); + }); + + it("witness calculate", async () => { + await snarkjs.wtns.calculate({ a: 11, b: 2 }, wasm, wtns); + }); + + it("witness check", async () => { + await snarkjs.wtns.check(r1cs, wtns); + }); + + it("groth16 prove", async () => { + const res = await snarkjs.groth16.prove(zkey_final, wtns); + proof = res.proof; + publicSignals = res.publicSignals; + expect(proof).toBeTruthy(); + expect(publicSignals).toBeTruthy(); + }); + + it("groth16 verify", async () => { + const res = await snarkjs.groth16.verify(vKey, publicSignals, proof); + expect(res).toBe(true); + }); +}); diff --git a/test/keypar_test.js b/test/keypar_test.js index 3a7cc236..982436b6 100644 --- a/test/keypar_test.js +++ b/test/keypar_test.js @@ -6,14 +6,14 @@ import { Scalar } from "ffjavascript"; import { getG2sp } from "../src/keypair.js"; describe("keypair", function() { - this.timeout(10000); + let curve; - before( async () => { + beforeAll( async () => { curve = await getCurveFromName("bn128"); }); - after( async () => { + afterAll( async () => { await curve.terminate(); }); diff --git a/test/polynomial.test.js b/test/polynomial.test.js index a131e9a8..bcbd7586 100644 --- a/test/polynomial.test.js +++ b/test/polynomial.test.js @@ -10,17 +10,17 @@ function radomPolynomial(maxDegree, curve) { } describe("snarkjs: Polynomial tests", function () { - this.timeout(150000); + let curve; let sFr; - before(async () => { + beforeAll(async () => { curve = await getCurveFromName("bn128"); sFr = curve.Fr.n8; }); - after(async () => { + afterAll(async () => { await curve.terminate(); }); diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 00000000..d864c917 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,188 @@ +import { defineConfig } from "vite"; +import { builtinModules } from "module"; +import { readFileSync } from "fs"; +import { resolve } from "path"; +import { playwright } from "@vitest/browser-playwright"; + +const pkg = JSON.parse(readFileSync(resolve("package.json"), "utf-8")); + +// All declared dependencies + sub-paths treated as external in node/CLI builds +// (this keeps bfj/ejs external and lazily required, so the CLI starts fast). +const nodeExternal = [ + ...builtinModules, + ...Object.keys(pkg.dependencies || {}), +]; +const isNodeExternal = (id) => + nodeExternal.includes(id) || nodeExternal.some((e) => id.startsWith(e + "/")); + +// Browser ESM externalizes the sibling packages so the consumer's bundler +// dedupes them; the self-contained IIFE bundles them instead (see below). +const browserExternal = ["ffjavascript", "@iden3/binfileutils", "r1csfile"]; +const isBrowserExternal = (id) => + browserExternal.includes(id) || browserExternal.some((e) => id.startsWith(e + "/")); + +// Node-only source files excluded from browser builds (the Solidity exporters +// pull in ejs + fs). Returning an empty stub keeps them and their transitive +// deps out of the bundle. +const nodeOnlyFiles = new Set([ + resolve("src/zkey_export_solidityverifier.js"), + resolve("src/fflonk_export_solidity_verifier.js"), +]); +const stubNodeOnlyModules = { + name: "stub-node-only-modules", + load(id) { + if (nodeOnlyFiles.has(id)) return "export default null;"; + }, +}; + +const emptyStub = resolve("build-config/empty-stub.js"); +const constantsStub = resolve("build-config/constants-stub.js"); +const wasmToolchainStub = resolve("build-config/wasm-toolchain-stub.js"); +// Browser aliases: Node built-ins reachable only from node-specific code paths +// (getRandomBytes/getSHA256 fall back to globalThis.crypto) and the wasm codegen +// toolchain (custom-plugins path, never taken) are stubbed so the self-contained +// IIFE stays lean and free of unresolved `require` calls. +const browserAlias = { + fs: emptyStub, + os: emptyStub, + readline: emptyStub, + crypto: emptyStub, + constants: constantsStub, + wasmbuilder: wasmToolchainStub, + wasmcurves: wasmToolchainStub, +}; + +export default defineConfig(({ mode }) => { + if (mode === "cli") { + return { + plugins: [ + { + name: "fix-import-meta-url-cjs", + renderChunk(code) { + if (!code.includes("{}.url")) return null; + return { + code: code.replace( + /\{\}\.url/g, + "require('url').pathToFileURL(__filename).href" + ), + map: null, + }; + }, + }, + ], + build: { + lib: { + entry: "./cli.js", + formats: ["cjs"], + fileName: () => "cli.cjs", + }, + minify: false, + outDir: "build", + emptyOutDir: false, + rollupOptions: { + external: isNodeExternal, + output: { + banner: "#!/usr/bin/env node", + inlineDynamicImports: true, + }, + }, + }, + }; + } + + if (mode === "browser") { + return { + plugins: [stubNodeOnlyModules], + build: { + lib: { + entry: "./main.js", + name: "snarkjs", + formats: ["es"], + fileName: () => "browser.esm.js", + }, + outDir: "build", + emptyOutDir: false, + rollupOptions: { + external: isBrowserExternal, + }, + }, + define: { "process.browser": "true" }, + resolve: { conditions: ["browser"], alias: browserAlias }, + }; + } + + if (mode === "browser-iife") { + // Self-contained IIFE: bundles ffjavascript/binfileutils/r1csfile so a + // bare