From b9cfdbe29e5800d31591aaeec410b5e57055b78a Mon Sep 17 00:00:00 2001 From: flfeders Date: Thu, 24 Sep 2026 17:09:35 +0200 Subject: [PATCH] fix(scan): allow slower SANE network discovery --- agents/fedeo-device-agent/src/scan/sane.ts | 4 +++- agents/fedeo-device-agent/tests/scan.test.ts | 21 ++++++++++++++++++-- frontend/assets/device-agent/bundle.json | 2 +- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/agents/fedeo-device-agent/src/scan/sane.ts b/agents/fedeo-device-agent/src/scan/sane.ts index c65f5f73..33b7d9f7 100644 --- a/agents/fedeo-device-agent/src/scan/sane.ts +++ b/agents/fedeo-device-agent/src/scan/sane.ts @@ -20,7 +20,9 @@ export const hasSane = () => commandExists("scanimage") export const listScanners = async () => { if (!await hasSane()) return [] - const result = await runCommand("scanimage", ["-L"], { timeoutMs: 10_000 }) + // SANE also probes network backends; these can take more than ten seconds + // even when the USB scanner is already available. + const result = await runCommand("scanimage", ["-L"], { timeoutMs: 30_000 }) if (result.code !== 0) return [] return result.stdout.split(/\r?\n/) .map((line) => line.trim().match(/^device `([^']+)'/)?.[1]) diff --git a/agents/fedeo-device-agent/tests/scan.test.ts b/agents/fedeo-device-agent/tests/scan.test.ts index d2fd8182..232cbcb1 100644 --- a/agents/fedeo-device-agent/tests/scan.test.ts +++ b/agents/fedeo-device-agent/tests/scan.test.ts @@ -3,16 +3,21 @@ import test, { TestContext } from "node:test" import os from "node:os" import path from "node:path" import { chmod, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises" -import { runScan } from "../src/scan/sane.js" +import { listScanners, runScan } from "../src/scan/sane.js" import { commandExists, runCommand } from "../src/commands.js" import { AgentConfig, ScanJob } from "../src/types.js" const fakeScanner = `#!/usr/bin/env python3 -import json, os, sys +import json, os, sys, time from pathlib import Path from PIL import Image args = sys.argv[1:] Path(os.environ['SCAN_TEST_CALL']).write_text(json.dumps(args)) +if args == ['-L']: + time.sleep(float(os.environ.get('SCAN_TEST_DISCOVERY_DELAY', '0'))) + print("device " + chr(96) + "fujitsu:ScanSnap iX1600:test' is a FUJITSU scanner") + print("device " + chr(96) + "airscan:test' is a network scanner") + sys.exit(int(os.environ.get('SCAN_TEST_EXIT', '0'))) batch = next((arg.split('=', 1)[1] for arg in args if arg.startswith('--batch=')), None) single = args[args.index('--output-file') + 1] if '--output-file' in args else None count = int(os.environ.get('SCAN_TEST_PAGES', '4')) if batch else 1 @@ -52,6 +57,18 @@ const setup = async (t: TestContext) => { return { config, job, dir, args: async () => JSON.parse(await readFile(process.env.SCAN_TEST_CALL!, "utf8")) as string[] } } +test("scanner discovery waits for network probes beyond the former ten-second limit", async (t) => { + await setup(t) + process.env.SCAN_TEST_DISCOVERY_DELAY = "10.2" + assert.deepEqual(await listScanners(), ["fujitsu:ScanSnap iX1600:test", "airscan:test"]) +}) + +test("failed scanner discovery does not advertise devices from an unsuccessful command", async (t) => { + await setup(t) + process.env.SCAN_TEST_EXIT = "1" + assert.deepEqual(await listScanners(), []) +}) + test("duplex batch saves all pages as PDF, accepts NO_DOCS and passes A4 geometry", async (t) => { const { config, job, args } = await setup(t) process.env.SCAN_TEST_EMPTY_FINAL = "1" diff --git a/frontend/assets/device-agent/bundle.json b/frontend/assets/device-agent/bundle.json index c3b71491..84a2b6ed 100644 --- a/frontend/assets/device-agent/bundle.json +++ b/frontend/assets/device-agent/bundle.json @@ -10,7 +10,7 @@ "dist/main.js": "IyEvdXNyL2Jpbi9lbnYgbm9kZQppbXBvcnQgb3MgZnJvbSAibm9kZTpvcyI7CmltcG9ydCBwYXRoIGZyb20gIm5vZGU6cGF0aCI7CmltcG9ydCB7IHJtIH0gZnJvbSAibm9kZTpmcy9wcm9taXNlcyI7CmltcG9ydCB7IEZlZGVvQXBpIH0gZnJvbSAiLi9hcGkuanMiOwppbXBvcnQgeyBsb2FkQ29uZmlnIH0gZnJvbSAiLi9jb25maWcuanMiOwppbXBvcnQgeyBsb2cgfSBmcm9tICIuL2xvZ2dlci5qcyI7CmltcG9ydCB7IGxpc3RQcmludGVycyB9IGZyb20gIi4vcHJpbnQvY3Vwcy5qcyI7CmltcG9ydCB7IGhhc1NhbmUsIGxpc3RTY2FubmVycywgcnVuU2NhbiB9IGZyb20gIi4vc2Nhbi9zYW5lLmpzIjsKY29uc3Qgc2xlZXAgPSAobXMpID0+IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7CmNvbnN0IHN0cmluZ2lmeUVycm9yID0gKGVycm9yKSA9PiB7CiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikKICAgICAgICByZXR1cm4gZXJyb3IubWVzc2FnZTsKICAgIHJldHVybiBTdHJpbmcoZXJyb3IpOwp9Owpjb25zdCBtYWluID0gYXN5bmMgKCkgPT4gewogICAgY29uc3QgY29uZmlnID0gbG9hZENvbmZpZygpOwogICAgY29uc3QgYXBpID0gbmV3IEZlZGVvQXBpKGNvbmZpZyk7CiAgICBsb2cuaW5mbygiRkVERU8gR2Vyw6R0ZS1BZ2VudCBzdGFydGV0IiwgewogICAgICAgIHBsYXRmb3JtOiBwcm9jZXNzLnBsYXRmb3JtLAogICAgICAgIHdvcmtEaXI6IGNvbmZpZy53b3JrRGlyLAogICAgICAgIHBvbGxTZWNvbmRzOiBjb25maWcucG9sbFNlY29uZHMsCiAgICB9KTsKICAgIHdoaWxlICh0cnVlKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgY29uc3Qgc2Nhbm5lck5hbWVzID0gYXdhaXQgbGlzdFNjYW5uZXJzKCkuY2F0Y2goKGVycm9yKSA9PiB7CiAgICAgICAgICAgICAgICBsb2cud2FybigiU2Nhbm5lci1Fcmtlbm51bmcgZmVobGdlc2NobGFnZW4iLCBzdHJpbmdpZnlFcnJvcihlcnJvcikpOwogICAgICAgICAgICAgICAgcmV0dXJuIFtdOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgY29uc3QgcHJpbnRlck5hbWVzID0gYXdhaXQgbGlzdFByaW50ZXJzKCkuY2F0Y2goKCkgPT4gW10pOwogICAgICAgICAgICBjb25zdCBzY2FuQXZhaWxhYmxlID0gYXdhaXQgaGFzU2FuZSgpOwogICAgICAgICAgICBjb25zdCBoZWFydGJlYXRQYXlsb2FkID0gewogICAgICAgICAgICAgICAgY2FwYWJpbGl0aWVzOiB7CiAgICAgICAgICAgICAgICAgICAgc2Nhbjogc2NhbkF2YWlsYWJsZSwKICAgICAgICAgICAgICAgICAgICBwcmludDogcHJpbnRlck5hbWVzLmxlbmd0aCA+IDAsCiAgICAgICAgICAgICAgICAgICAgcGxhdGZvcm06IHByb2Nlc3MucGxhdGZvcm0sCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgc2Nhbm5lck5hbWVzLAogICAgICAgICAgICAgICAgcHJpbnRlck5hbWVzLAogICAgICAgICAgICAgICAgZGVidWdJbmZvOiB7CiAgICAgICAgICAgICAgICAgICAgaG9zdG5hbWU6IG9zLmhvc3RuYW1lKCksCiAgICAgICAgICAgICAgICAgICAgcmVsZWFzZTogb3MucmVsZWFzZSgpLAogICAgICAgICAgICAgICAgICAgIGFyY2g6IG9zLmFyY2goKSwKICAgICAgICAgICAgICAgICAgICBub2RlOiBwcm9jZXNzLnZlcnNpb24sCiAgICAgICAgICAgICAgICAgICAgdXB0aW1lU2Vjb25kczogTWF0aC5yb3VuZChvcy51cHRpbWUoKSksCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICB9OwogICAgICAgICAgICBjb25zdCBoZWFydGJlYXQgPSBhd2FpdCBhcGkuaGVhcnRiZWF0KGhlYXJ0YmVhdFBheWxvYWQpOwogICAgICAgICAgICBpZiAoaGVhcnRiZWF0LnBlbmRpbmdTY2FuSm9icyA+IDApIHsKICAgICAgICAgICAgICAgIGxvZy5pbmZvKGAke2hlYXJ0YmVhdC5wZW5kaW5nU2NhbkpvYnN9IFNjYW4tQXVmdHJhZy9BdWZ0csOkZ2Ugd2FydGVuYCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgbmV4dCA9IGF3YWl0IGFwaS5uZXh0U2NhbkpvYigpOwogICAgICAgICAgICBpZiAoIW5leHQuam9iKSB7CiAgICAgICAgICAgICAgICBhd2FpdCBzbGVlcChjb25maWcucG9sbFNlY29uZHMgKiAxMDAwKTsKICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGxvZy5pbmZvKCJTY2FuLUF1ZnRyYWcgd2lyZCBhdXNnZWbDvGhydCIsIHsKICAgICAgICAgICAgICAgIGpvYklkOiBuZXh0LmpvYi5pZCwKICAgICAgICAgICAgICAgIHRlbmFudElkOiBuZXh0LmpvYi50ZW5hbnRJZCwKICAgICAgICAgICAgICAgIHNjYW5uZXJOYW1lOiBuZXh0LmpvYi5zY2FubmVyTmFtZSB8fCBjb25maWcuc2Nhbm5lck5hbWUgfHwgImRlZmF1bHQiLAogICAgICAgICAgICB9KTsKICAgICAgICAgICAgLy8gS2VlcCBvbmxpbmUgc3RhdHVzIGZyZXNoIGR1cmluZyBsb25nIHNjYW5zIHdpdGhvdXQgcHJvYmluZyBhbiBvY2N1cGllZCBVU0Igc2Nhbm5lci4KICAgICAgICAgICAgbGV0IGhlYXJ0YmVhdFJ1bm5pbmcgPSBmYWxzZTsKICAgICAgICAgICAgY29uc3QgaGVhcnRiZWF0VGltZXIgPSBzZXRJbnRlcnZhbChhc3luYyAoKSA9PiB7CiAgICAgICAgICAgICAgICBpZiAoaGVhcnRiZWF0UnVubmluZykKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICBoZWFydGJlYXRSdW5uaW5nID0gdHJ1ZTsKICAgICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAgICAgYXdhaXQgYXBpLmhlYXJ0YmVhdChoZWFydGJlYXRQYXlsb2FkKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNhdGNoIChlcnJvcikgewogICAgICAgICAgICAgICAgICAgIGxvZy53YXJuKCJIZWFydGJlYXQgd8OkaHJlbmQgU2NhbiBmZWhsZ2VzY2hsYWdlbiIsIHN0cmluZ2lmeUVycm9yKGVycm9yKSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBmaW5hbGx5IHsKICAgICAgICAgICAgICAgICAgICBoZWFydGJlYXRSdW5uaW5nID0gZmFsc2U7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sIDMwXzAwMCk7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICBhd2FpdCBhcGkudXBkYXRlU2NhbkpvYlN0YXR1cyhuZXh0LmpvYi5pZCwgInJ1bm5pbmciKTsKICAgICAgICAgICAgICAgIGNvbnN0IGpvYklkID0gbmV4dC5qb2IuaWQ7CiAgICAgICAgICAgICAgICBjb25zdCByZXBvcnRQcm9ncmVzcyA9IGFzeW5jIChtZXNzYWdlKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgYXdhaXQgYXBpLnVwZGF0ZVNjYW5Kb2JTdGF0dXMoam9iSWQsICJydW5uaW5nIiwgbWVzc2FnZSkuY2F0Y2goKGVycm9yKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgICAgIGxvZy53YXJuKCJTY2FuLVN0YXR1cyBrb25udGUgbmljaHQgw7xiZXJ0cmFnZW4gd2VyZGVuIiwgc3RyaW5naWZ5RXJyb3IoZXJyb3IpKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgICBjb25zdCBzY2FuUmVzdWx0ID0gYXdhaXQgcnVuU2Nhbihjb25maWcsIG5leHQuam9iLCByZXBvcnRQcm9ncmVzcyk7CiAgICAgICAgICAgICAgICBhd2FpdCByZXBvcnRQcm9ncmVzcyhgJHtzY2FuUmVzdWx0LnBhZ2VDb3VudH0gU2VpdGVuIGdlc2Nhbm50LiAke3NjYW5SZXN1bHQud2FybmluZ3Muam9pbigiICIpfWAudHJpbSgpKTsKICAgICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAgICAgYXdhaXQgYXBpLnVwbG9hZFNjYW4oam9iSWQsIHNjYW5SZXN1bHQpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke3N0cmluZ2lmeUVycm9yKGVycm9yKX0gU2Nhbi1EYXRlaSBibGVpYnQgenVyIFdpZWRlcmhlcnN0ZWxsdW5nIHVudGVyICR7c2NhblJlc3VsdC5wYXRofS5gKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGF3YWl0IHJtKHBhdGguZGlybmFtZShzY2FuUmVzdWx0LnBhdGgpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSkuY2F0Y2goKGVycm9yKSA9PiB7CiAgICAgICAgICAgICAgICAgICAgbG9nLndhcm4oIlNjYW4gZ2VzcGVpY2hlcnQ7IHRlbXBvcsOkcmUgRGF0ZWllbiBrb25udGVuIG5pY2h0IGVudGZlcm50IHdlcmRlbiIsIHN0cmluZ2lmeUVycm9yKGVycm9yKSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGxvZy5pbmZvKCJTY2FuLUF1ZnRyYWcgYWJnZXNjaGxvc3NlbiIsIHsKICAgICAgICAgICAgICAgICAgICBqb2JJZDogbmV4dC5qb2IuaWQsCiAgICAgICAgICAgICAgICAgICAgZmlsZTogc2NhblJlc3VsdC5maWxlbmFtZSwKICAgICAgICAgICAgICAgICAgICBwYWdlczogc2NhblJlc3VsdC5wYWdlQ291bnQsCiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBzdHJpbmdpZnlFcnJvcihlcnJvcik7CiAgICAgICAgICAgICAgICBsb2cuZXJyb3IoIlNjYW4tQXVmdHJhZyBmZWhsZ2VzY2hsYWdlbiIsIHsKICAgICAgICAgICAgICAgICAgICBqb2JJZDogbmV4dC5qb2IuaWQsCiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSwKICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgYXdhaXQgYXBpLnVwZGF0ZVNjYW5Kb2JTdGF0dXMobmV4dC5qb2IuaWQsICJmYWlsZWQiLCBtZXNzYWdlKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBmaW5hbGx5IHsKICAgICAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwoaGVhcnRiZWF0VGltZXIpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNhdGNoIChlcnJvcikgewogICAgICAgICAgICBsb2cuZXJyb3IoIkFnZW50LVNjaGxlaWZlIGZlaGxnZXNjaGxhZ2VuIiwgc3RyaW5naWZ5RXJyb3IoZXJyb3IpKTsKICAgICAgICAgICAgYXdhaXQgc2xlZXAoY29uZmlnLnBvbGxTZWNvbmRzICogMTAwMCk7CiAgICAgICAgfQogICAgfQp9OwptYWluKCkuY2F0Y2goKGVycm9yKSA9PiB7CiAgICBsb2cuZXJyb3IoIkFnZW50IGtvbm50ZSBuaWNodCBnZXN0YXJ0ZXQgd2VyZGVuIiwgc3RyaW5naWZ5RXJyb3IoZXJyb3IpKTsKICAgIHByb2Nlc3MuZXhpdCgxKTsKfSk7Cg==", "dist/print/cups.js": "aW1wb3J0IHsgY29tbWFuZEV4aXN0cywgcnVuQ29tbWFuZCB9IGZyb20gIi4uL2NvbW1hbmRzLmpzIjsKZXhwb3J0IGNvbnN0IGhhc0N1cHMgPSAoKSA9PiBjb21tYW5kRXhpc3RzKCJscHN0YXQiKTsKZXhwb3J0IGNvbnN0IGxpc3RQcmludGVycyA9IGFzeW5jICgpID0+IHsKICAgIGlmICghYXdhaXQgaGFzQ3VwcygpKQogICAgICAgIHJldHVybiBbXTsKICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHJ1bkNvbW1hbmQoImxwc3RhdCIsIFsiLXAiXSwgeyB0aW1lb3V0TXM6IDEwXzAwMCB9KTsKICAgIGlmIChyZXN1bHQuY29kZSAhPT0gMCkKICAgICAgICByZXR1cm4gW107CiAgICByZXR1cm4gcmVzdWx0LnN0ZG91dAogICAgICAgIC5zcGxpdCgvXHI/XG4vKQogICAgICAgIC5tYXAoKGxpbmUpID0+IGxpbmUubWF0Y2goL15wcmludGVyXHMrKFxTKykvKT8uWzFdKQogICAgICAgIC5maWx0ZXIoKHByaW50ZXIpID0+IEJvb2xlYW4ocHJpbnRlcikpOwp9Owo=", "dist/scan/postprocess.js": "aW1wb3J0IHBhdGggZnJvbSAibm9kZTpwYXRoIjsKaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gIm5vZGU6dXJsIjsKaW1wb3J0IHsgcnVuQ29tbWFuZCB9IGZyb20gIi4uL2NvbW1hbmRzLmpzIjsKY29uc3QgYWdlbnRSb290ID0gcGF0aC5yZXNvbHZlKHBhdGguZGlybmFtZShmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCkpLCAiLi4vLi4iKTsKY29uc3QgZG9jdW1lbnRTY3JpcHQgPSBwYXRoLmpvaW4oYWdlbnRSb290LCAic2NyaXB0cy9zY2FuX2RvY3VtZW50LnB5Iik7CmV4cG9ydCBjb25zdCBjaGVja1NjYW5SdW50aW1lID0gYXN5bmMgKGNvbmZpZywgcG9zdHByb2Nlc3MpID0+IHsKICAgIGNvbnN0IGltcG9ydHMgPSBwb3N0cHJvY2VzcyAmJiBjb25maWcucG9zdHByb2Nlc3NTdHJpY3QgPyAiaW1wb3J0IFBJTCwgY3YyLCBudW1weSIgOiAiaW1wb3J0IFBJTCI7CiAgICB0cnkgewogICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHJ1bkNvbW1hbmQoY29uZmlnLnBvc3Rwcm9jZXNzUHl0aG9uLCBbIi1jIiwgaW1wb3J0c10sIHsgdGltZW91dE1zOiAxMF8wMDAgfSk7CiAgICAgICAgaWYgKHJlc3VsdC5jb2RlID09PSAwKQogICAgICAgICAgICByZXR1cm47CiAgICB9CiAgICBjYXRjaCB7CiAgICAgICAgLy8gUmVwb3J0IG1pc3NpbmcgcnVudGltZXMgYmVmb3JlIHRoZSBzY2FubmVyIGNvbnN1bWVzIGFueSBwYXBlci4KICAgIH0KICAgIHRocm93IG5ldyBFcnJvcigiUHl0aG9uL1BpbGxvdyAoYmVpIHN0cmlrdGVyIE5hY2hiZWFyYmVpdHVuZyB6dXPDpHR6bGljaCBPcGVuQ1YpIGZlaGx0LiBCaXR0ZSBucG0gcnVuIHNldHVwOm9wZW5jdiBhdXNmw7xocmVuIG9kZXIgcHl0aG9uMy1waWwgaW5zdGFsbGllcmVuLiIpOwp9OwpleHBvcnQgY29uc3QgY3JlYXRlU2NhbkRvY3VtZW50ID0gYXN5bmMgKGNvbmZpZywgcGFnZXMsIG91dHB1dFBhdGgsIHJlc29sdXRpb24sIHBvc3Rwcm9jZXNzLCBwcm9maWxlKSA9PiB7CiAgICBjb25zdCBhcmdzID0gW2RvY3VtZW50U2NyaXB0LCAiLS1vdXRwdXQiLCBvdXRwdXRQYXRoLCAiLS1yZXNvbHV0aW9uIiwgU3RyaW5nKHJlc29sdXRpb24pLCAiLS1wcm9maWxlIiwgcHJvZmlsZV07CiAgICBpZiAocG9zdHByb2Nlc3MpCiAgICAgICAgYXJncy5wdXNoKCItLXBvc3Rwcm9jZXNzIik7CiAgICBpZiAoY29uZmlnLnBvc3Rwcm9jZXNzU3RyaWN0KQogICAgICAgIGFyZ3MucHVzaCgiLS1zdHJpY3QiKTsKICAgIGFyZ3MucHVzaCgiLS1pbnB1dHMiLCAuLi5wYWdlcyk7CiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBydW5Db21tYW5kKGNvbmZpZy5wb3N0cHJvY2Vzc1B5dGhvbiwgYXJncywgewogICAgICAgIHRpbWVvdXRNczogY29uZmlnLnNjYW5UaW1lb3V0U2Vjb25kcyAqIDEwMDAsCiAgICB9KTsKICAgIGlmIChyZXN1bHQuY29kZSAhPT0gMCkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IocmVzdWx0LnN0ZGVyciB8fCAiU2Nhbi1EYXRlaSBrb25udGUgbmljaHQgZXJzdGVsbHQgd2VyZGVuIik7CiAgICBjb25zdCBkZXRhaWxzID0gSlNPTi5wYXJzZShyZXN1bHQuc3Rkb3V0KTsKICAgIHJldHVybiB7CiAgICAgICAgcGF0aDogb3V0cHV0UGF0aCwKICAgICAgICBmaWxlbmFtZTogcGF0aC5iYXNlbmFtZShvdXRwdXRQYXRoKSwKICAgICAgICBtaW1lVHlwZTogb3V0cHV0UGF0aC5lbmRzV2l0aCgiLnBkZiIpID8gImFwcGxpY2F0aW9uL3BkZiIgOiBvdXRwdXRQYXRoLmVuZHNXaXRoKCIucG5nIikgPyAiaW1hZ2UvcG5nIiA6ICJpbWFnZS90aWZmIiwKICAgICAgICAuLi5kZXRhaWxzLAogICAgfTsKfTsK", - "dist/scan/sane.js": "aW1wb3J0IHsgbWtkaXIsIG1rZHRlbXAsIHJlYWRkaXIsIHN0YXQgfSBmcm9tICJub2RlOmZzL3Byb21pc2VzIjsKaW1wb3J0IHBhdGggZnJvbSAibm9kZTpwYXRoIjsKaW1wb3J0IHsgY29tbWFuZEV4aXN0cywgcnVuQ29tbWFuZCB9IGZyb20gIi4uL2NvbW1hbmRzLmpzIjsKaW1wb3J0IHsgY2hlY2tTY2FuUnVudGltZSwgY3JlYXRlU2NhbkRvY3VtZW50IH0gZnJvbSAiLi9wb3N0cHJvY2Vzcy5qcyI7CmNvbnN0IHN0cmluZ1NldHRpbmcgPSAoc2V0dGluZ3MsIGtleSkgPT4gewogICAgY29uc3QgdmFsdWUgPSBzZXR0aW5nc1trZXldOwogICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gInN0cmluZyIgJiYgdmFsdWUudHJpbSgpID8gdmFsdWUudHJpbSgpIDogdW5kZWZpbmVkOwp9Owpjb25zdCBib29sZWFuU2V0dGluZyA9IChzZXR0aW5ncywga2V5LCBmYWxsYmFjaykgPT4gewogICAgY29uc3QgdmFsdWUgPSBzZXR0aW5nc1trZXldOwogICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gImJvb2xlYW4iKQogICAgICAgIHJldHVybiB2YWx1ZTsKICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICJzdHJpbmciKQogICAgICAgIHJldHVybiBbIjEiLCAidHJ1ZSIsICJ5ZXMiLCAiamEiLCAib24iXS5pbmNsdWRlcyh2YWx1ZS50cmltKCkudG9Mb3dlckNhc2UoKSk7CiAgICByZXR1cm4gZmFsbGJhY2s7Cn07CmV4cG9ydCBjb25zdCBoYXNTYW5lID0gKCkgPT4gY29tbWFuZEV4aXN0cygic2NhbmltYWdlIik7CmV4cG9ydCBjb25zdCBsaXN0U2Nhbm5lcnMgPSBhc3luYyAoKSA9PiB7CiAgICBpZiAoIWF3YWl0IGhhc1NhbmUoKSkKICAgICAgICByZXR1cm4gW107CiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBydW5Db21tYW5kKCJzY2FuaW1hZ2UiLCBbIi1MIl0sIHsgdGltZW91dE1zOiAxMF8wMDAgfSk7CiAgICBpZiAocmVzdWx0LmNvZGUgIT09IDApCiAgICAgICAgcmV0dXJuIFtdOwogICAgcmV0dXJuIHJlc3VsdC5zdGRvdXQuc3BsaXQoL1xyP1xuLykKICAgICAgICAubWFwKChsaW5lKSA9PiBsaW5lLnRyaW0oKS5tYXRjaCgvXmRldmljZSBgKFteJ10rKScvKT8uWzFdKQogICAgICAgIC5maWx0ZXIoKGRldmljZSkgPT4gQm9vbGVhbihkZXZpY2UpKTsKfTsKZXhwb3J0IGNvbnN0IHJ1blNjYW4gPSBhc3luYyAoY29uZmlnLCBqb2IsIHJlcG9ydFByb2dyZXNzID0gYXN5bmMgKCkgPT4geyB9KSA9PiB7CiAgICBpZiAoIWF3YWl0IGhhc1NhbmUoKSkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoInNjYW5pbWFnZSBpc3QgbmljaHQgaW5zdGFsbGllcnQgb2RlciBuaWNodCBpbSBQQVRIIik7CiAgICBjb25zdCBzZXR0aW5ncyA9IGpvYi5zZXR0aW5ncyB8fCB7fTsKICAgIGNvbnN0IGZvcm1hdCA9IHN0cmluZ1NldHRpbmcoc2V0dGluZ3MsICJmb3JtYXQiKSB8fCBjb25maWcuc2NhbkZvcm1hdDsKICAgIGlmICghWyJwZGYiLCAicG5nIiwgInRpZmYiXS5pbmNsdWRlcyhmb3JtYXQpKQogICAgICAgIHRocm93IG5ldyBFcnJvcigiU2Nhbi1Gb3JtYXQgbXVzcyBQREYsIFBORyBvZGVyIFRJRkYgc2VpbiIpOwogICAgY29uc3QgcmVzb2x1dGlvbiA9IE51bWJlcihzZXR0aW5ncy5yZXNvbHV0aW9uID8/IGNvbmZpZy5zY2FuUmVzb2x1dGlvbik7CiAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShyZXNvbHV0aW9uKSB8fCByZXNvbHV0aW9uIDwgNzUgfHwgcmVzb2x1dGlvbiA+IDEyMDApIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkRpZSBTY2FuLUF1ZmzDtnN1bmcgbXVzcyB6d2lzY2hlbiA3NSB1bmQgMTIwMCBkcGkgbGllZ2VuIik7CiAgICB9CiAgICBjb25zdCBtb2RlID0gc3RyaW5nU2V0dGluZyhzZXR0aW5ncywgIm1vZGUiKSB8fCBjb25maWcuc2Nhbk1vZGU7CiAgICBjb25zdCBzb3VyY2UgPSBzdHJpbmdTZXR0aW5nKHNldHRpbmdzLCAic291cmNlIikgfHwgY29uZmlnLnNjYW5Tb3VyY2U7CiAgICBjb25zdCBzY2FubmVyTmFtZSA9IGpvYi5zY2FubmVyTmFtZSB8fCBjb25maWcuc2Nhbm5lck5hbWU7CiAgICBjb25zdCBwYXBlclNpemUgPSBzdHJpbmdTZXR0aW5nKHNldHRpbmdzLCAicGFwZXJTaXplIikgfHwgImF1dG8iOwogICAgaWYgKCFbImF1dG8iLCAiQTQiLCAiTGV0dGVyIl0uaW5jbHVkZXMocGFwZXJTaXplKSkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIlVuYmVrYW5udGVzIFBhcGllcmZvcm1hdCIpOwogICAgY29uc3QgYmF0Y2ggPSBCb29sZWFuKHNvdXJjZSAmJiAvYWRmfGRvY3VtZW50IGZlZWRlci9pLnRlc3Qoc291cmNlKSk7CiAgICBpZiAoYmF0Y2ggJiYgZm9ybWF0ICE9PSAicGRmIikKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkbDvHIgRWluenVnLSB1bmQgRHVwbGV4LVNjYW5zIGJpdHRlIFBERiBhbHMgRm9ybWF0IHfDpGhsZW4iKTsKICAgIGNvbnN0IHBvc3Rwcm9jZXNzID0gYm9vbGVhblNldHRpbmcoc2V0dGluZ3MsICJwb3N0cHJvY2VzcyIsIGNvbmZpZy5zY2FuUG9zdHByb2Nlc3MpOwogICAgY29uc3QgcHJvZmlsZSA9IHN0cmluZ1NldHRpbmcoc2V0dGluZ3MsICJwb3N0cHJvY2Vzc1Byb2ZpbGUiKSB8fCBjb25maWcucG9zdHByb2Nlc3NQcm9maWxlOwogICAgaWYgKCFbImRvY3VtZW50IiwgInJlY2VpcHQiLCAicmF3Il0uaW5jbHVkZXMocHJvZmlsZSkpCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJVbmJla2FubnRlcyBOYWNoYmVhcmJlaXR1bmdzcHJvZmlsIik7CiAgICBhd2FpdCBjaGVja1NjYW5SdW50aW1lKGNvbmZpZywgcG9zdHByb2Nlc3MpOwogICAgLy8gRWFjaCBwaHlzaWNhbCBzY2FuIGhhcyBpdHMgb3duIGRpcmVjdG9yeS4gQSBmaWxlbmFtZSBjYW5ub3QgZXNjYXBlIGl0IG9yIG92ZXJ3cml0ZSBhbm90aGVyIGpvYi4KICAgIGF3YWl0IG1rZGlyKGNvbmZpZy53b3JrRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgbW9kZTogMG83MDAgfSk7CiAgICBjb25zdCBqb2JEaXIgPSBhd2FpdCBta2R0ZW1wKHBhdGguam9pbihwYXRoLnJlc29sdmUoY29uZmlnLndvcmtEaXIpLCAic2Nhbi0iKSk7CiAgICBjb25zdCByZXF1ZXN0ZWQgPSBwYXRoLmJhc2VuYW1lKChqb2IucmVxdWVzdGVkRmlsZW5hbWUgfHwgInNjYW4iKS5yZXBsYWNlKC9cXC9nLCAiLyIpKTsKICAgIGNvbnN0IHN0ZW0gPSByZXF1ZXN0ZWQucmVwbGFjZSgvXC5bXi5dKiQvLCAiIikucmVwbGFjZSgvW1x4MDAtXHgxZl0vZywgIiIpLnRyaW0oKSB8fCAic2NhbiI7CiAgICBjb25zdCBvdXRwdXRQYXRoID0gcGF0aC5qb2luKGpvYkRpciwgYCR7c3RlbX0uJHtmb3JtYXR9YCk7CiAgICB0cnkgewogICAgICAgIC8vIERldmljZS9zb3VyY2UgY29tZSBmaXJzdDogY2hhbmdpbmcgc291cmNlIGNhbiBjaGFuZ2UgdGhlIHJlbWFpbmluZyBTQU5FIG9wdGlvbnMuCiAgICAgICAgY29uc3QgYXJncyA9IFtdOwogICAgICAgIGlmIChzY2FubmVyTmFtZSkKICAgICAgICAgICAgYXJncy5wdXNoKCItLWRldmljZS1uYW1lIiwgc2Nhbm5lck5hbWUpOwogICAgICAgIGlmIChzb3VyY2UpCiAgICAgICAgICAgIGFyZ3MucHVzaCgiLS1zb3VyY2UiLCBzb3VyY2UpOwogICAgICAgIGFyZ3MucHVzaCgiLS1tb2RlIiwgbW9kZSwgIi0tcmVzb2x1dGlvbiIsIFN0cmluZyhyZXNvbHV0aW9uKSwgIi0tZm9ybWF0PXBuZyIpOwogICAgICAgIGlmIChwYXBlclNpemUgIT09ICJhdXRvIikgewogICAgICAgICAgICBjb25zdCBbd2lkdGgsIGhlaWdodF0gPSBwYXBlclNpemUgPT09ICJBNCIgPyBbMjEwLCAyOTddIDogWzIxNS45LCAyNzkuNF07CiAgICAgICAgICAgIGlmIChzY2FubmVyTmFtZT8uc3RhcnRzV2l0aCgiZnVqaXRzdToiKSkgewogICAgICAgICAgICAgICAgYXJncy5wdXNoKCItLXBhZ2Utd2lkdGgiLCBTdHJpbmcod2lkdGgpLCAiLS1wYWdlLWhlaWdodCIsIFN0cmluZyhoZWlnaHQpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBhcmdzLnB1c2goIi1sIiwgIjAiLCAiLXQiLCAiMCIsICIteCIsIFN0cmluZyh3aWR0aCksICIteSIsIFN0cmluZyhoZWlnaHQpKTsKICAgICAgICB9CiAgICAgICAgaWYgKGJhdGNoKSB7CiAgICAgICAgICAgIC8vIFJlbGF0aXZlIHBhdHRlcm4gYXZvaWRzIGludGVycHJldGluZyAnJScgaW4gYSB1c2VyLWNvbmZpZ3VyZWQgd29yayBkaXJlY3RvcnkuCiAgICAgICAgICAgIGFyZ3MucHVzaCgiLS1iYXRjaD1wYWdlLSUwNmQucG5nIiwgIi0tYmF0Y2gtc3RhcnQ9MSIsICItLWJhdGNoLWluY3JlbWVudD0xIik7CiAgICAgICAgfQogICAgICAgIGVsc2UgewogICAgICAgICAgICBhcmdzLnB1c2goIi0tb3V0cHV0LWZpbGUiLCAicGFnZS0wMDAwMDEucG5nIik7CiAgICAgICAgfQogICAgICAgIGF3YWl0IHJlcG9ydFByb2dyZXNzKGJhdGNoID8gIkRva3VtZW50ZSB3ZXJkZW4gZWluZ2V6b2dlbiB1bmQgZ2VzY2FubnQuLi4iIDogIlNlaXRlIHdpcmQgZ2VzY2FubnQuLi4iKTsKICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBydW5Db21tYW5kKCJzY2FuaW1hZ2UiLCBhcmdzLCB7CiAgICAgICAgICAgIGN3ZDogam9iRGlyLAogICAgICAgICAgICB0aW1lb3V0TXM6IGNvbmZpZy5zY2FuVGltZW91dFNlY29uZHMgKiAxMDAwLAogICAgICAgIH0pOwogICAgICAgIC8vIFNBTkVfU1RBVFVTX05PX0RPQ1MgKDcpIGlzIHRoZSBleHBlY3RlZCBlbmQgb2YgYW4gdW5saW1pdGVkIEFERiBiYXRjaC4KICAgICAgICAvLyBOZXZlciB0dXJuIHBhcGVyIGphbXMsIEkvTyBlcnJvcnMgb3IgY2FuY2VsZWQgc2NhbnMgaW50byBhIHN1Y2Nlc3NmdWwgcGFydGlhbCB1cGxvYWQuCiAgICAgICAgaWYgKHJlc3VsdC5jb2RlICE9PSAwICYmICEoYmF0Y2ggJiYgcmVzdWx0LmNvZGUgPT09IDcpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihyZXN1bHQuc3RkZXJyLnRyaW0oKSB8fCBgc2NhbmltYWdlIHd1cmRlIG1pdCBDb2RlICR7cmVzdWx0LmNvZGV9IGJlZW5kZXRgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgbmFtZXMgPSAoYXdhaXQgcmVhZGRpcihqb2JEaXIpKQogICAgICAgICAgICAuZmlsdGVyKChuYW1lKSA9PiAvXnBhZ2UtXGQrXC5wbmckLy50ZXN0KG5hbWUpKQogICAgICAgICAgICAuc29ydCgoYSwgYikgPT4gTnVtYmVyKGEubWF0Y2goL1xkKy8pWzBdKSAtIE51bWJlcihiLm1hdGNoKC9cZCsvKVswXSkpOwogICAgICAgIGNvbnN0IHBhZ2VzID0gW107CiAgICAgICAgZm9yIChjb25zdCBbaW5kZXgsIG5hbWVdIG9mIG5hbWVzLmVudHJpZXMoKSkgewogICAgICAgICAgICBjb25zdCBwYWdlID0gcGF0aC5qb2luKGpvYkRpciwgbmFtZSk7CiAgICAgICAgICAgIC8vIFNvbWUgc2NhbmltYWdlIHZlcnNpb25zIGxlYXZlIGEgemVyby1ieXRlIGZpbGUgZm9yIHRoZSBmaW5hbCBOT19ET0NTIGF0dGVtcHQuCiAgICAgICAgICAgIGlmICgoYXdhaXQgc3RhdChwYWdlKSkuc2l6ZSA9PT0gMCkgewogICAgICAgICAgICAgICAgaWYgKGJhdGNoICYmIHJlc3VsdC5jb2RlID09PSA3ICYmIGluZGV4ID09PSBuYW1lcy5sZW5ndGggLSAxKQogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnZvbGxzdMOkbmRpZ2UgU2Nhbi1TZWl0ZTogJHtuYW1lfWApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChOdW1iZXIobmFtZS5tYXRjaCgvXGQrLylbMF0pICE9PSBpbmRleCArIDEpCiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkltIFNjYW4gZmVobGVuIFNlaXRlbiIpOwogICAgICAgICAgICBwYWdlcy5wdXNoKHBhZ2UpOwogICAgICAgIH0KICAgICAgICBpZiAoIXBhZ2VzLmxlbmd0aCkKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJLZWluZSBTZWl0ZW4gZ2VzY2FubnQuIEJpdHRlIFBhcGllciBpbiBkZW4gRWluenVnIGxlZ2VuLiIpOwogICAgICAgIGlmIChzb3VyY2U/LnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoImR1cGxleCIpICYmIHBhZ2VzLmxlbmd0aCAlIDIgIT09IDApIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJEZXIgRHVwbGV4LVNjYW4gaXN0IHVudm9sbHN0w6RuZGlnOiBadSBlaW5lciBWb3JkZXJzZWl0ZSBmZWhsdCBkaWUgUsO8Y2tzZWl0ZS4iKTsKICAgICAgICB9CiAgICAgICAgYXdhaXQgcmVwb3J0UHJvZ3Jlc3MoYCR7cGFnZXMubGVuZ3RofSBTZWl0ZW4gZ2VzY2FubnQuIERhdGVpIHdpcmQgZXJzdGVsbHQuLi5gKTsKICAgICAgICByZXR1cm4gYXdhaXQgY3JlYXRlU2NhbkRvY3VtZW50KGNvbmZpZywgcGFnZXMsIG91dHB1dFBhdGgsIHJlc29sdXRpb24sIHBvc3Rwcm9jZXNzLCBwcm9maWxlKTsKICAgIH0KICAgIGNhdGNoIChlcnJvcikgewogICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke21lc3NhZ2V9IFJvaHNjYW5zIGJsZWliZW4genVyIFdpZWRlcmhlcnN0ZWxsdW5nIGluICR7am9iRGlyfS5gKTsKICAgIH0KfTsK", + "dist/scan/sane.js": "aW1wb3J0IHsgbWtkaXIsIG1rZHRlbXAsIHJlYWRkaXIsIHN0YXQgfSBmcm9tICJub2RlOmZzL3Byb21pc2VzIjsKaW1wb3J0IHBhdGggZnJvbSAibm9kZTpwYXRoIjsKaW1wb3J0IHsgY29tbWFuZEV4aXN0cywgcnVuQ29tbWFuZCB9IGZyb20gIi4uL2NvbW1hbmRzLmpzIjsKaW1wb3J0IHsgY2hlY2tTY2FuUnVudGltZSwgY3JlYXRlU2NhbkRvY3VtZW50IH0gZnJvbSAiLi9wb3N0cHJvY2Vzcy5qcyI7CmNvbnN0IHN0cmluZ1NldHRpbmcgPSAoc2V0dGluZ3MsIGtleSkgPT4gewogICAgY29uc3QgdmFsdWUgPSBzZXR0aW5nc1trZXldOwogICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gInN0cmluZyIgJiYgdmFsdWUudHJpbSgpID8gdmFsdWUudHJpbSgpIDogdW5kZWZpbmVkOwp9Owpjb25zdCBib29sZWFuU2V0dGluZyA9IChzZXR0aW5ncywga2V5LCBmYWxsYmFjaykgPT4gewogICAgY29uc3QgdmFsdWUgPSBzZXR0aW5nc1trZXldOwogICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gImJvb2xlYW4iKQogICAgICAgIHJldHVybiB2YWx1ZTsKICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICJzdHJpbmciKQogICAgICAgIHJldHVybiBbIjEiLCAidHJ1ZSIsICJ5ZXMiLCAiamEiLCAib24iXS5pbmNsdWRlcyh2YWx1ZS50cmltKCkudG9Mb3dlckNhc2UoKSk7CiAgICByZXR1cm4gZmFsbGJhY2s7Cn07CmV4cG9ydCBjb25zdCBoYXNTYW5lID0gKCkgPT4gY29tbWFuZEV4aXN0cygic2NhbmltYWdlIik7CmV4cG9ydCBjb25zdCBsaXN0U2Nhbm5lcnMgPSBhc3luYyAoKSA9PiB7CiAgICBpZiAoIWF3YWl0IGhhc1NhbmUoKSkKICAgICAgICByZXR1cm4gW107CiAgICAvLyBTQU5FIGFsc28gcHJvYmVzIG5ldHdvcmsgYmFja2VuZHM7IHRoZXNlIGNhbiB0YWtlIG1vcmUgdGhhbiB0ZW4gc2Vjb25kcwogICAgLy8gZXZlbiB3aGVuIHRoZSBVU0Igc2Nhbm5lciBpcyBhbHJlYWR5IGF2YWlsYWJsZS4KICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHJ1bkNvbW1hbmQoInNjYW5pbWFnZSIsIFsiLUwiXSwgeyB0aW1lb3V0TXM6IDMwXzAwMCB9KTsKICAgIGlmIChyZXN1bHQuY29kZSAhPT0gMCkKICAgICAgICByZXR1cm4gW107CiAgICByZXR1cm4gcmVzdWx0LnN0ZG91dC5zcGxpdCgvXHI/XG4vKQogICAgICAgIC5tYXAoKGxpbmUpID0+IGxpbmUudHJpbSgpLm1hdGNoKC9eZGV2aWNlIGAoW14nXSspJy8pPy5bMV0pCiAgICAgICAgLmZpbHRlcigoZGV2aWNlKSA9PiBCb29sZWFuKGRldmljZSkpOwp9OwpleHBvcnQgY29uc3QgcnVuU2NhbiA9IGFzeW5jIChjb25maWcsIGpvYiwgcmVwb3J0UHJvZ3Jlc3MgPSBhc3luYyAoKSA9PiB7IH0pID0+IHsKICAgIGlmICghYXdhaXQgaGFzU2FuZSgpKQogICAgICAgIHRocm93IG5ldyBFcnJvcigic2NhbmltYWdlIGlzdCBuaWNodCBpbnN0YWxsaWVydCBvZGVyIG5pY2h0IGltIFBBVEgiKTsKICAgIGNvbnN0IHNldHRpbmdzID0gam9iLnNldHRpbmdzIHx8IHt9OwogICAgY29uc3QgZm9ybWF0ID0gc3RyaW5nU2V0dGluZyhzZXR0aW5ncywgImZvcm1hdCIpIHx8IGNvbmZpZy5zY2FuRm9ybWF0OwogICAgaWYgKCFbInBkZiIsICJwbmciLCAidGlmZiJdLmluY2x1ZGVzKGZvcm1hdCkpCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJTY2FuLUZvcm1hdCBtdXNzIFBERiwgUE5HIG9kZXIgVElGRiBzZWluIik7CiAgICBjb25zdCByZXNvbHV0aW9uID0gTnVtYmVyKHNldHRpbmdzLnJlc29sdXRpb24gPz8gY29uZmlnLnNjYW5SZXNvbHV0aW9uKTsKICAgIGlmICghTnVtYmVyLmlzRmluaXRlKHJlc29sdXRpb24pIHx8IHJlc29sdXRpb24gPCA3NSB8fCByZXNvbHV0aW9uID4gMTIwMCkgewogICAgICAgIHRocm93IG5ldyBFcnJvcigiRGllIFNjYW4tQXVmbMO2c3VuZyBtdXNzIHp3aXNjaGVuIDc1IHVuZCAxMjAwIGRwaSBsaWVnZW4iKTsKICAgIH0KICAgIGNvbnN0IG1vZGUgPSBzdHJpbmdTZXR0aW5nKHNldHRpbmdzLCAibW9kZSIpIHx8IGNvbmZpZy5zY2FuTW9kZTsKICAgIGNvbnN0IHNvdXJjZSA9IHN0cmluZ1NldHRpbmcoc2V0dGluZ3MsICJzb3VyY2UiKSB8fCBjb25maWcuc2NhblNvdXJjZTsKICAgIGNvbnN0IHNjYW5uZXJOYW1lID0gam9iLnNjYW5uZXJOYW1lIHx8IGNvbmZpZy5zY2FubmVyTmFtZTsKICAgIGNvbnN0IHBhcGVyU2l6ZSA9IHN0cmluZ1NldHRpbmcoc2V0dGluZ3MsICJwYXBlclNpemUiKSB8fCAiYXV0byI7CiAgICBpZiAoIVsiYXV0byIsICJBNCIsICJMZXR0ZXIiXS5pbmNsdWRlcyhwYXBlclNpemUpKQogICAgICAgIHRocm93IG5ldyBFcnJvcigiVW5iZWthbm50ZXMgUGFwaWVyZm9ybWF0Iik7CiAgICBjb25zdCBiYXRjaCA9IEJvb2xlYW4oc291cmNlICYmIC9hZGZ8ZG9jdW1lbnQgZmVlZGVyL2kudGVzdChzb3VyY2UpKTsKICAgIGlmIChiYXRjaCAmJiBmb3JtYXQgIT09ICJwZGYiKQogICAgICAgIHRocm93IG5ldyBFcnJvcigiRsO8ciBFaW56dWctIHVuZCBEdXBsZXgtU2NhbnMgYml0dGUgUERGIGFscyBGb3JtYXQgd8OkaGxlbiIpOwogICAgY29uc3QgcG9zdHByb2Nlc3MgPSBib29sZWFuU2V0dGluZyhzZXR0aW5ncywgInBvc3Rwcm9jZXNzIiwgY29uZmlnLnNjYW5Qb3N0cHJvY2Vzcyk7CiAgICBjb25zdCBwcm9maWxlID0gc3RyaW5nU2V0dGluZyhzZXR0aW5ncywgInBvc3Rwcm9jZXNzUHJvZmlsZSIpIHx8IGNvbmZpZy5wb3N0cHJvY2Vzc1Byb2ZpbGU7CiAgICBpZiAoIVsiZG9jdW1lbnQiLCAicmVjZWlwdCIsICJyYXciXS5pbmNsdWRlcyhwcm9maWxlKSkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIlVuYmVrYW5udGVzIE5hY2hiZWFyYmVpdHVuZ3Nwcm9maWwiKTsKICAgIGF3YWl0IGNoZWNrU2NhblJ1bnRpbWUoY29uZmlnLCBwb3N0cHJvY2Vzcyk7CiAgICAvLyBFYWNoIHBoeXNpY2FsIHNjYW4gaGFzIGl0cyBvd24gZGlyZWN0b3J5LiBBIGZpbGVuYW1lIGNhbm5vdCBlc2NhcGUgaXQgb3Igb3ZlcndyaXRlIGFub3RoZXIgam9iLgogICAgYXdhaXQgbWtkaXIoY29uZmlnLndvcmtEaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBtb2RlOiAwbzcwMCB9KTsKICAgIGNvbnN0IGpvYkRpciA9IGF3YWl0IG1rZHRlbXAocGF0aC5qb2luKHBhdGgucmVzb2x2ZShjb25maWcud29ya0RpciksICJzY2FuLSIpKTsKICAgIGNvbnN0IHJlcXVlc3RlZCA9IHBhdGguYmFzZW5hbWUoKGpvYi5yZXF1ZXN0ZWRGaWxlbmFtZSB8fCAic2NhbiIpLnJlcGxhY2UoL1xcL2csICIvIikpOwogICAgY29uc3Qgc3RlbSA9IHJlcXVlc3RlZC5yZXBsYWNlKC9cLlteLl0qJC8sICIiKS5yZXBsYWNlKC9bXHgwMC1ceDFmXS9nLCAiIikudHJpbSgpIHx8ICJzY2FuIjsKICAgIGNvbnN0IG91dHB1dFBhdGggPSBwYXRoLmpvaW4oam9iRGlyLCBgJHtzdGVtfS4ke2Zvcm1hdH1gKTsKICAgIHRyeSB7CiAgICAgICAgLy8gRGV2aWNlL3NvdXJjZSBjb21lIGZpcnN0OiBjaGFuZ2luZyBzb3VyY2UgY2FuIGNoYW5nZSB0aGUgcmVtYWluaW5nIFNBTkUgb3B0aW9ucy4KICAgICAgICBjb25zdCBhcmdzID0gW107CiAgICAgICAgaWYgKHNjYW5uZXJOYW1lKQogICAgICAgICAgICBhcmdzLnB1c2goIi0tZGV2aWNlLW5hbWUiLCBzY2FubmVyTmFtZSk7CiAgICAgICAgaWYgKHNvdXJjZSkKICAgICAgICAgICAgYXJncy5wdXNoKCItLXNvdXJjZSIsIHNvdXJjZSk7CiAgICAgICAgYXJncy5wdXNoKCItLW1vZGUiLCBtb2RlLCAiLS1yZXNvbHV0aW9uIiwgU3RyaW5nKHJlc29sdXRpb24pLCAiLS1mb3JtYXQ9cG5nIik7CiAgICAgICAgaWYgKHBhcGVyU2l6ZSAhPT0gImF1dG8iKSB7CiAgICAgICAgICAgIGNvbnN0IFt3aWR0aCwgaGVpZ2h0XSA9IHBhcGVyU2l6ZSA9PT0gIkE0IiA/IFsyMTAsIDI5N10gOiBbMjE1LjksIDI3OS40XTsKICAgICAgICAgICAgaWYgKHNjYW5uZXJOYW1lPy5zdGFydHNXaXRoKCJmdWppdHN1OiIpKSB7CiAgICAgICAgICAgICAgICBhcmdzLnB1c2goIi0tcGFnZS13aWR0aCIsIFN0cmluZyh3aWR0aCksICItLXBhZ2UtaGVpZ2h0IiwgU3RyaW5nKGhlaWdodCkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGFyZ3MucHVzaCgiLWwiLCAiMCIsICItdCIsICIwIiwgIi14IiwgU3RyaW5nKHdpZHRoKSwgIi15IiwgU3RyaW5nKGhlaWdodCkpOwogICAgICAgIH0KICAgICAgICBpZiAoYmF0Y2gpIHsKICAgICAgICAgICAgLy8gUmVsYXRpdmUgcGF0dGVybiBhdm9pZHMgaW50ZXJwcmV0aW5nICclJyBpbiBhIHVzZXItY29uZmlndXJlZCB3b3JrIGRpcmVjdG9yeS4KICAgICAgICAgICAgYXJncy5wdXNoKCItLWJhdGNoPXBhZ2UtJTA2ZC5wbmciLCAiLS1iYXRjaC1zdGFydD0xIiwgIi0tYmF0Y2gtaW5jcmVtZW50PTEiKTsKICAgICAgICB9CiAgICAgICAgZWxzZSB7CiAgICAgICAgICAgIGFyZ3MucHVzaCgiLS1vdXRwdXQtZmlsZSIsICJwYWdlLTAwMDAwMS5wbmciKTsKICAgICAgICB9CiAgICAgICAgYXdhaXQgcmVwb3J0UHJvZ3Jlc3MoYmF0Y2ggPyAiRG9rdW1lbnRlIHdlcmRlbiBlaW5nZXpvZ2VuIHVuZCBnZXNjYW5udC4uLiIgOiAiU2VpdGUgd2lyZCBnZXNjYW5udC4uLiIpOwogICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHJ1bkNvbW1hbmQoInNjYW5pbWFnZSIsIGFyZ3MsIHsKICAgICAgICAgICAgY3dkOiBqb2JEaXIsCiAgICAgICAgICAgIHRpbWVvdXRNczogY29uZmlnLnNjYW5UaW1lb3V0U2Vjb25kcyAqIDEwMDAsCiAgICAgICAgfSk7CiAgICAgICAgLy8gU0FORV9TVEFUVVNfTk9fRE9DUyAoNykgaXMgdGhlIGV4cGVjdGVkIGVuZCBvZiBhbiB1bmxpbWl0ZWQgQURGIGJhdGNoLgogICAgICAgIC8vIE5ldmVyIHR1cm4gcGFwZXIgamFtcywgSS9PIGVycm9ycyBvciBjYW5jZWxlZCBzY2FucyBpbnRvIGEgc3VjY2Vzc2Z1bCBwYXJ0aWFsIHVwbG9hZC4KICAgICAgICBpZiAocmVzdWx0LmNvZGUgIT09IDAgJiYgIShiYXRjaCAmJiByZXN1bHQuY29kZSA9PT0gNykpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHJlc3VsdC5zdGRlcnIudHJpbSgpIHx8IGBzY2FuaW1hZ2Ugd3VyZGUgbWl0IENvZGUgJHtyZXN1bHQuY29kZX0gYmVlbmRldGApOwogICAgICAgIH0KICAgICAgICBjb25zdCBuYW1lcyA9IChhd2FpdCByZWFkZGlyKGpvYkRpcikpCiAgICAgICAgICAgIC5maWx0ZXIoKG5hbWUpID0+IC9ecGFnZS1cZCtcLnBuZyQvLnRlc3QobmFtZSkpCiAgICAgICAgICAgIC5zb3J0KChhLCBiKSA9PiBOdW1iZXIoYS5tYXRjaCgvXGQrLylbMF0pIC0gTnVtYmVyKGIubWF0Y2goL1xkKy8pWzBdKSk7CiAgICAgICAgY29uc3QgcGFnZXMgPSBbXTsKICAgICAgICBmb3IgKGNvbnN0IFtpbmRleCwgbmFtZV0gb2YgbmFtZXMuZW50cmllcygpKSB7CiAgICAgICAgICAgIGNvbnN0IHBhZ2UgPSBwYXRoLmpvaW4oam9iRGlyLCBuYW1lKTsKICAgICAgICAgICAgLy8gU29tZSBzY2FuaW1hZ2UgdmVyc2lvbnMgbGVhdmUgYSB6ZXJvLWJ5dGUgZmlsZSBmb3IgdGhlIGZpbmFsIE5PX0RPQ1MgYXR0ZW1wdC4KICAgICAgICAgICAgaWYgKChhd2FpdCBzdGF0KHBhZ2UpKS5zaXplID09PSAwKSB7CiAgICAgICAgICAgICAgICBpZiAoYmF0Y2ggJiYgcmVzdWx0LmNvZGUgPT09IDcgJiYgaW5kZXggPT09IG5hbWVzLmxlbmd0aCAtIDEpCiAgICAgICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVudm9sbHN0w6RuZGlnZSBTY2FuLVNlaXRlOiAke25hbWV9YCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKE51bWJlcihuYW1lLm1hdGNoKC9cZCsvKVswXSkgIT09IGluZGV4ICsgMSkKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiSW0gU2NhbiBmZWhsZW4gU2VpdGVuIik7CiAgICAgICAgICAgIHBhZ2VzLnB1c2gocGFnZSk7CiAgICAgICAgfQogICAgICAgIGlmICghcGFnZXMubGVuZ3RoKQogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIktlaW5lIFNlaXRlbiBnZXNjYW5udC4gQml0dGUgUGFwaWVyIGluIGRlbiBFaW56dWcgbGVnZW4uIik7CiAgICAgICAgaWYgKHNvdXJjZT8udG9Mb3dlckNhc2UoKS5pbmNsdWRlcygiZHVwbGV4IikgJiYgcGFnZXMubGVuZ3RoICUgMiAhPT0gMCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkRlciBEdXBsZXgtU2NhbiBpc3QgdW52b2xsc3TDpG5kaWc6IFp1IGVpbmVyIFZvcmRlcnNlaXRlIGZlaGx0IGRpZSBSw7xja3NlaXRlLiIpOwogICAgICAgIH0KICAgICAgICBhd2FpdCByZXBvcnRQcm9ncmVzcyhgJHtwYWdlcy5sZW5ndGh9IFNlaXRlbiBnZXNjYW5udC4gRGF0ZWkgd2lyZCBlcnN0ZWxsdC4uLmApOwogICAgICAgIHJldHVybiBhd2FpdCBjcmVhdGVTY2FuRG9jdW1lbnQoY29uZmlnLCBwYWdlcywgb3V0cHV0UGF0aCwgcmVzb2x1dGlvbiwgcG9zdHByb2Nlc3MsIHByb2ZpbGUpOwogICAgfQogICAgY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgY29uc3QgbWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7bWVzc2FnZX0gUm9oc2NhbnMgYmxlaWJlbiB6dXIgV2llZGVyaGVyc3RlbGx1bmcgaW4gJHtqb2JEaXJ9LmApOwogICAgfQp9Owo=", "dist/types.js": "ZXhwb3J0IHt9Owo=", "scripts/scan_document.py": "IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoiIiJBc3NlbWJsZSBvcmRlcmVkIHNjYW5uZXIgcGFnZXM7IE9wZW5DViBpcyBvcHRpb25hbCwgUERGIGNyZWF0aW9uIGlzIG5vdC4iIiIKaW1wb3J0IGFyZ3BhcnNlCmltcG9ydCBqc29uCmZyb20gcGF0aGxpYiBpbXBvcnQgUGF0aAoKZnJvbSBQSUwgaW1wb3J0IEltYWdlCgoKZGVmIGNyZWF0ZV9kb2N1bWVudChpbnB1dHMsIG91dHB1dCwgcmVzb2x1dGlvbiwgdXNlX3Bvc3Rwcm9jZXNzPUZhbHNlLCBwcm9maWxlPSJkb2N1bWVudCIsIHN0cmljdD1GYWxzZSk6CiAgICBpZiBub3QgaW5wdXRzOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoIktlaW5lIFNlaXRlbiB2b3JoYW5kZW4iKQogICAgb3V0cHV0ID0gUGF0aChvdXRwdXQpCiAgICBmaWxlX2Zvcm1hdCA9IHsiLnBkZiI6ICJQREYiLCAiLnBuZyI6ICJQTkciLCAiLnRpZmYiOiAiVElGRiJ9LmdldChvdXRwdXQuc3VmZml4Lmxvd2VyKCkpCiAgICBpZiBub3QgZmlsZV9mb3JtYXQ6CiAgICAgICAgcmFpc2UgVmFsdWVFcnJvcigiVW5iZWthbm50ZXMgQXVzZ2FiZWZvcm1hdCIpCiAgICBpZiBmaWxlX2Zvcm1hdCAhPSAiUERGIiBhbmQgbGVuKGlucHV0cykgIT0gMToKICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCJNZWhyc2VpdGlnZSBTY2FucyBiZW7DtnRpZ2VuIFBERiBhbHMgQXVzZ2FiZWZvcm1hdCIpCgogICAgd2FybmluZ3MgPSBbXQogICAgcHJvY2Vzc29yID0gTm9uZQogICAgaWYgdXNlX3Bvc3Rwcm9jZXNzOgogICAgICAgIHRyeToKICAgICAgICAgICAgZnJvbSBvcGVuY3ZfcG9zdHByb2Nlc3MgaW1wb3J0IHBvc3Rwcm9jZXNzCiAgICAgICAgICAgIHByb2Nlc3NvciA9IHBvc3Rwcm9jZXNzCiAgICAgICAgZXhjZXB0IEltcG9ydEVycm9yOgogICAgICAgICAgICBpZiBzdHJpY3Q6CiAgICAgICAgICAgICAgICByYWlzZQogICAgICAgICAgICB3YXJuaW5ncy5hcHBlbmQoIk9wZW5DViBmZWhsdDsgYWxsZSBTZWl0ZW4gd3VyZGVuIG9obmUgQmlsZGtvcnJla3R1ciDDvGJlcm5vbW1lbi4iKQoKICAgIHBhcnRpYWwgPSBvdXRwdXQud2l0aF9uYW1lKG91dHB1dC5uYW1lICsgIi5wYXJ0aWFsIikKICAgIHRyeToKICAgICAgICBmb3IgaW5kZXgsIGlucHV0X3BhdGggaW4gZW51bWVyYXRlKGlucHV0cyk6CiAgICAgICAgICAgIGlucHV0X3BhdGggPSBQYXRoKGlucHV0X3BhdGgpCiAgICAgICAgICAgIGltYWdlX3BhdGggPSBpbnB1dF9wYXRoCiAgICAgICAgICAgIGNvcnJlY3RlZCA9IGlucHV0X3BhdGgud2l0aF9uYW1lKGlucHV0X3BhdGguc3RlbSArICIuY29ycmVjdGVkLnBuZyIpCiAgICAgICAgICAgIGlmIHByb2Nlc3NvcjoKICAgICAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgICAgICBwcm9jZXNzb3IoaW5wdXRfcGF0aCwgY29ycmVjdGVkLCBwcm9maWxlKQogICAgICAgICAgICAgICAgICAgIGltYWdlX3BhdGggPSBjb3JyZWN0ZWQKICAgICAgICAgICAgICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgICAgICAgICAgICAgaWYgc3RyaWN0OgogICAgICAgICAgICAgICAgICAgICAgICByYWlzZQogICAgICAgICAgICAgICAgICAgIHdhcm5pbmdzLmFwcGVuZChmIlNlaXRlIHtpbmRleCArIDF9OiBCaWxka29ycmVrdHVyIGZlaGxnZXNjaGxhZ2VuOyBSb2hzY2FuIMO8YmVybm9tbWVuLiIpCgogICAgICAgICAgICAjIE9ubHkgb25lIGRlY29kZWQgcGFnZSBpcyBrZXB0IGluIG1lbW9yeSwgZXZlbiBmb3IgbGFyZ2UgZHVwbGV4IHN0YWNrcy4KICAgICAgICAgICAgd2l0aCBJbWFnZS5vcGVuKGltYWdlX3BhdGgpIGFzIGltYWdlOgogICAgICAgICAgICAgICAgd2l0aCBpbWFnZS5jb252ZXJ0KCJSR0IiKSBhcyByZ2I6CiAgICAgICAgICAgICAgICAgICAgaWYgZmlsZV9mb3JtYXQgPT0gIlBERiI6CiAgICAgICAgICAgICAgICAgICAgICAgIHJnYi5zYXZlKHBhcnRpYWwsICJQREYiLCByZXNvbHV0aW9uPXJlc29sdXRpb24sIHF1YWxpdHk9OTAsIGFwcGVuZD1pbmRleCA+IDApCiAgICAgICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICAgICAgcmdiLnNhdmUocGFydGlhbCwgZmlsZV9mb3JtYXQsIGRwaT0ocmVzb2x1dGlvbiwgcmVzb2x1dGlvbikpCiAgICAgICAgICAgIGNvcnJlY3RlZC51bmxpbmsobWlzc2luZ19vaz1UcnVlKQogICAgICAgIHBhcnRpYWwucmVwbGFjZShvdXRwdXQpCiAgICBmaW5hbGx5OgogICAgICAgIHBhcnRpYWwudW5saW5rKG1pc3Npbmdfb2s9VHJ1ZSkKCiAgICByZXR1cm4geyJwYWdlQ291bnQiOiBsZW4oaW5wdXRzKSwgIndhcm5pbmdzIjogd2FybmluZ3N9CgoKZGVmIG1haW4oKToKICAgIHBhcnNlciA9IGFyZ3BhcnNlLkFyZ3VtZW50UGFyc2VyKGRlc2NyaXB0aW9uPSJTY2FuLVNlaXRlbiB6dSBlaW5lciBEYXRlaSB6dXNhbW1lbmbDvGhyZW4iKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1pbnB1dHMiLCBuYXJncz0iKyIsIHJlcXVpcmVkPVRydWUpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCItLW91dHB1dCIsIHJlcXVpcmVkPVRydWUpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCItLXJlc29sdXRpb24iLCB0eXBlPWZsb2F0LCByZXF1aXJlZD1UcnVlKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1wcm9maWxlIiwgY2hvaWNlcz1bImRvY3VtZW50IiwgInJlY2VpcHQiLCAicmF3Il0sIGRlZmF1bHQ9ImRvY3VtZW50IikKICAgIHBhcnNlci5hZGRfYXJndW1lbnQoIi0tcG9zdHByb2Nlc3MiLCBhY3Rpb249InN0b3JlX3RydWUiKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1zdHJpY3QiLCBhY3Rpb249InN0b3JlX3RydWUiKQogICAgYXJncyA9IHBhcnNlci5wYXJzZV9hcmdzKCkKICAgIHByaW50KGpzb24uZHVtcHMoY3JlYXRlX2RvY3VtZW50KGFyZ3MuaW5wdXRzLCBhcmdzLm91dHB1dCwgYXJncy5yZXNvbHV0aW9uLCBhcmdzLnBvc3Rwcm9jZXNzLCBhcmdzLnByb2ZpbGUsIGFyZ3Muc3RyaWN0KSkpCgoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIG1haW4oKQo=", "scripts/opencv_postprocess.py": "IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwppbXBvcnQgYXJncGFyc2UKaW1wb3J0IG1hdGgKZnJvbSBwYXRobGliIGltcG9ydCBQYXRoCgppbXBvcnQgY3YyCmltcG9ydCBudW1weSBhcyBucApmcm9tIFBJTCBpbXBvcnQgSW1hZ2UKCgpkZWYgb3JkZXJfcG9pbnRzKHBvaW50cyk6CiAgICByZWN0ID0gbnAuemVyb3MoKDQsIDIpLCBkdHlwZT0iZmxvYXQzMiIpCiAgICBwb2ludF9zdW0gPSBwb2ludHMuc3VtKGF4aXM9MSkKICAgIHBvaW50X2RpZmYgPSBucC5kaWZmKHBvaW50cywgYXhpcz0xKQoKICAgIHJlY3RbMF0gPSBwb2ludHNbbnAuYXJnbWluKHBvaW50X3N1bSldCiAgICByZWN0WzJdID0gcG9pbnRzW25wLmFyZ21heChwb2ludF9zdW0pXQogICAgcmVjdFsxXSA9IHBvaW50c1tucC5hcmdtaW4ocG9pbnRfZGlmZildCiAgICByZWN0WzNdID0gcG9pbnRzW25wLmFyZ21heChwb2ludF9kaWZmKV0KICAgIHJldHVybiByZWN0CgoKZGVmIGZvdXJfcG9pbnRfdHJhbnNmb3JtKGltYWdlLCBwb2ludHMpOgogICAgcmVjdCA9IG9yZGVyX3BvaW50cyhwb2ludHMpCiAgICB0b3BfbGVmdCwgdG9wX3JpZ2h0LCBib3R0b21fcmlnaHQsIGJvdHRvbV9sZWZ0ID0gcmVjdAoKICAgIHdpZHRoX2EgPSBucC5saW5hbGcubm9ybShib3R0b21fcmlnaHQgLSBib3R0b21fbGVmdCkKICAgIHdpZHRoX2IgPSBucC5saW5hbGcubm9ybSh0b3BfcmlnaHQgLSB0b3BfbGVmdCkKICAgIG1heF93aWR0aCA9IGludChtYXgod2lkdGhfYSwgd2lkdGhfYikpCgogICAgaGVpZ2h0X2EgPSBucC5saW5hbGcubm9ybSh0b3BfcmlnaHQgLSBib3R0b21fcmlnaHQpCiAgICBoZWlnaHRfYiA9IG5wLmxpbmFsZy5ub3JtKHRvcF9sZWZ0IC0gYm90dG9tX2xlZnQpCiAgICBtYXhfaGVpZ2h0ID0gaW50KG1heChoZWlnaHRfYSwgaGVpZ2h0X2IpKQoKICAgIGRlc3RpbmF0aW9uID0gbnAuYXJyYXkoWwogICAgICAgIFswLCAwXSwKICAgICAgICBbbWF4X3dpZHRoIC0gMSwgMF0sCiAgICAgICAgW21heF93aWR0aCAtIDEsIG1heF9oZWlnaHQgLSAxXSwKICAgICAgICBbMCwgbWF4X2hlaWdodCAtIDFdLAogICAgXSwgZHR5cGU9ImZsb2F0MzIiKQoKICAgIG1hdHJpeCA9IGN2Mi5nZXRQZXJzcGVjdGl2ZVRyYW5zZm9ybShyZWN0LCBkZXN0aW5hdGlvbikKICAgIHJldHVybiBjdjIud2FycFBlcnNwZWN0aXZlKGltYWdlLCBtYXRyaXgsIChtYXhfd2lkdGgsIG1heF9oZWlnaHQpLCBib3JkZXJWYWx1ZT0oMjU1LCAyNTUsIDI1NSkpCgoKZGVmIHJvdGF0ZV9ib3VuZChpbWFnZSwgYW5nbGUpOgogICAgaGVpZ2h0LCB3aWR0aCA9IGltYWdlLnNoYXBlWzoyXQogICAgY2VudGVyID0gKHdpZHRoIC8gMiwgaGVpZ2h0IC8gMikKICAgIG1hdHJpeCA9IGN2Mi5nZXRSb3RhdGlvbk1hdHJpeDJEKGNlbnRlciwgYW5nbGUsIDEuMCkKICAgIGNvcyA9IGFicyhtYXRyaXhbMCwgMF0pCiAgICBzaW4gPSBhYnMobWF0cml4WzAsIDFdKQoKICAgIG5ld193aWR0aCA9IGludCgoaGVpZ2h0ICogc2luKSArICh3aWR0aCAqIGNvcykpCiAgICBuZXdfaGVpZ2h0ID0gaW50KChoZWlnaHQgKiBjb3MpICsgKHdpZHRoICogc2luKSkKCiAgICBtYXRyaXhbMCwgMl0gKz0gKG5ld193aWR0aCAvIDIpIC0gY2VudGVyWzBdCiAgICBtYXRyaXhbMSwgMl0gKz0gKG5ld19oZWlnaHQgLyAyKSAtIGNlbnRlclsxXQoKICAgIHJldHVybiBjdjIud2FycEFmZmluZShpbWFnZSwgbWF0cml4LCAobmV3X3dpZHRoLCBuZXdfaGVpZ2h0KSwgYm9yZGVyVmFsdWU9KDI1NSwgMjU1LCAyNTUpKQoKCmRlZiBkZXNrZXdfYnlfdGV4dF9hbmdsZShpbWFnZSk6CiAgICBncmF5ID0gY3YyLmN2dENvbG9yKGltYWdlLCBjdjIuQ09MT1JfQkdSMkdSQVkpCiAgICBpbnZlcnRlZCA9IGN2Mi5iaXR3aXNlX25vdChncmF5KQogICAgdGhyZXNob2xkID0gY3YyLnRocmVzaG9sZChpbnZlcnRlZCwgMCwgMjU1LCBjdjIuVEhSRVNIX0JJTkFSWSB8IGN2Mi5USFJFU0hfT1RTVSlbMV0KICAgIGNvb3JkaW5hdGVzID0gbnAuY29sdW1uX3N0YWNrKG5wLndoZXJlKHRocmVzaG9sZCA+IDApKQoKICAgIGlmIGxlbihjb29yZGluYXRlcykgPCA1MDA6CiAgICAgICAgcmV0dXJuIGltYWdlCgogICAgYW5nbGUgPSBjdjIubWluQXJlYVJlY3QoY29vcmRpbmF0ZXMpWy0xXQogICAgaWYgYW5nbGUgPCAtNDU6CiAgICAgICAgYW5nbGUgPSAtKDkwICsgYW5nbGUpCiAgICBlbHNlOgogICAgICAgIGFuZ2xlID0gLWFuZ2xlCgogICAgaWYgYWJzKGFuZ2xlKSA8IDAuMiBvciBhYnMoYW5nbGUpID4gODoKICAgICAgICByZXR1cm4gaW1hZ2UKCiAgICByZXR1cm4gcm90YXRlX2JvdW5kKGltYWdlLCBhbmdsZSkKCgpkZWYgZmluZF9kb2N1bWVudF9jb250b3VyKGltYWdlLCBwcm9maWxlKToKICAgIHJhdGlvID0gaW1hZ2Uuc2hhcGVbMF0gLyA5MDAuMAogICAgcmVzaXplZCA9IGN2Mi5yZXNpemUoaW1hZ2UsIChpbnQoaW1hZ2Uuc2hhcGVbMV0gLyByYXRpbyksIDkwMCkpCiAgICBncmF5ID0gY3YyLmN2dENvbG9yKHJlc2l6ZWQsIGN2Mi5DT0xPUl9CR1IyR1JBWSkKICAgIGdyYXkgPSBjdjIuR2F1c3NpYW5CbHVyKGdyYXksICg1LCA1KSwgMCkKCiAgICBlZGdlcyA9IGN2Mi5DYW5ueShncmF5LCA0NSwgMTQwKQogICAga2VybmVsID0gY3YyLmdldFN0cnVjdHVyaW5nRWxlbWVudChjdjIuTU9SUEhfUkVDVCwgKDcsIDcpKQogICAgZWRnZXMgPSBjdjIubW9ycGhvbG9neUV4KGVkZ2VzLCBjdjIuTU9SUEhfQ0xPU0UsIGtlcm5lbCkKCiAgICBjb250b3VycywgXyA9IGN2Mi5maW5kQ29udG91cnMoZWRnZXMsIGN2Mi5SRVRSX0VYVEVSTkFMLCBjdjIuQ0hBSU5fQVBQUk9YX1NJTVBMRSkKICAgIGNvbnRvdXJzID0gc29ydGVkKGNvbnRvdXJzLCBrZXk9Y3YyLmNvbnRvdXJBcmVhLCByZXZlcnNlPVRydWUpWzo4XQoKICAgIG1pbl9hcmVhID0gcmVzaXplZC5zaGFwZVswXSAqIHJlc2l6ZWQuc2hhcGVbMV0gKiAoMC4wMyBpZiBwcm9maWxlID09ICJyZWNlaXB0IiBlbHNlIDAuMTIpCgogICAgZm9yIGNvbnRvdXIgaW4gY29udG91cnM6CiAgICAgICAgaWYgY3YyLmNvbnRvdXJBcmVhKGNvbnRvdXIpIDwgbWluX2FyZWE6CiAgICAgICAgICAgIGNvbnRpbnVlCgogICAgICAgIHBlcmltZXRlciA9IGN2Mi5hcmNMZW5ndGgoY29udG91ciwgVHJ1ZSkKICAgICAgICBhcHByb3ggPSBjdjIuYXBwcm94UG9seURQKGNvbnRvdXIsIDAuMDI1ICogcGVyaW1ldGVyLCBUcnVlKQogICAgICAgIGlmIGxlbihhcHByb3gpID09IDQ6CiAgICAgICAgICAgIHJldHVybiBhcHByb3gucmVzaGFwZSg0LCAyKSAqIHJhdGlvCgogICAgcmV0dXJuIE5vbmUKCgpkZWYgdHJpbV9saWdodF9ib3JkZXIoaW1hZ2UpOgogICAgZ3JheSA9IGN2Mi5jdnRDb2xvcihpbWFnZSwgY3YyLkNPTE9SX0JHUjJHUkFZKQogICAgbWFzayA9IGN2Mi50aHJlc2hvbGQoZ3JheSwgMjQ1LCAyNTUsIGN2Mi5USFJFU0hfQklOQVJZX0lOVilbMV0KICAgIGtlcm5lbCA9IGN2Mi5nZXRTdHJ1Y3R1cmluZ0VsZW1lbnQoY3YyLk1PUlBIX1JFQ1QsICg5LCA5KSkKICAgIG1hc2sgPSBjdjIubW9ycGhvbG9neUV4KG1hc2ssIGN2Mi5NT1JQSF9DTE9TRSwga2VybmVsKQoKICAgIGNvbnRvdXJzLCBfID0gY3YyLmZpbmRDb250b3VycyhtYXNrLCBjdjIuUkVUUl9FWFRFUk5BTCwgY3YyLkNIQUlOX0FQUFJPWF9TSU1QTEUpCiAgICBpZiBub3QgY29udG91cnM6CiAgICAgICAgcmV0dXJuIGltYWdlCgogICAgY29udG91ciA9IG1heChjb250b3Vycywga2V5PWN2Mi5jb250b3VyQXJlYSkKICAgIGlmIGN2Mi5jb250b3VyQXJlYShjb250b3VyKSA8IGltYWdlLnNoYXBlWzBdICogaW1hZ2Uuc2hhcGVbMV0gKiAwLjAyOgogICAgICAgIHJldHVybiBpbWFnZQoKICAgIHgsIHksIHdpZHRoLCBoZWlnaHQgPSBjdjIuYm91bmRpbmdSZWN0KGNvbnRvdXIpCiAgICBwYWRkaW5nID0gbWF4KDEyLCBpbnQobWluKHdpZHRoLCBoZWlnaHQpICogMC4wMjUpKQogICAgeCA9IG1heCgwLCB4IC0gcGFkZGluZykKICAgIHkgPSBtYXgoMCwgeSAtIHBhZGRpbmcpCiAgICB3aWR0aCA9IG1pbihpbWFnZS5zaGFwZVsxXSAtIHgsIHdpZHRoICsgcGFkZGluZyAqIDIpCiAgICBoZWlnaHQgPSBtaW4oaW1hZ2Uuc2hhcGVbMF0gLSB5LCBoZWlnaHQgKyBwYWRkaW5nICogMikKICAgIHJldHVybiBpbWFnZVt5OnkgKyBoZWlnaHQsIHg6eCArIHdpZHRoXQoKCmRlZiBlbmhhbmNlX3JlY2VpcHQoaW1hZ2UpOgogICAgZ3JheSA9IGN2Mi5jdnRDb2xvcihpbWFnZSwgY3YyLkNPTE9SX0JHUjJHUkFZKQogICAgY2xhaGUgPSBjdjIuY3JlYXRlQ0xBSEUoY2xpcExpbWl0PTIuMCwgdGlsZUdyaWRTaXplPSg4LCA4KSkKICAgIGdyYXkgPSBjbGFoZS5hcHBseShncmF5KQogICAgZ3JheSA9IGN2Mi5mYXN0TmxNZWFuc0Rlbm9pc2luZyhncmF5LCBOb25lLCA4LCA3LCAyMSkKICAgIGdyYXkgPSBjdjIubm9ybWFsaXplKGdyYXksIE5vbmUsIDAsIDI1NSwgY3YyLk5PUk1fTUlOTUFYKQogICAgcmV0dXJuIGN2Mi5jdnRDb2xvcihncmF5LCBjdjIuQ09MT1JfR1JBWTJCR1IpCgoKZGVmIGVuaGFuY2VfZG9jdW1lbnQoaW1hZ2UpOgogICAgbGFiID0gY3YyLmN2dENvbG9yKGltYWdlLCBjdjIuQ09MT1JfQkdSMkxBQikKICAgIGxfY2hhbm5lbCwgYV9jaGFubmVsLCBiX2NoYW5uZWwgPSBjdjIuc3BsaXQobGFiKQogICAgY2xhaGUgPSBjdjIuY3JlYXRlQ0xBSEUoY2xpcExpbWl0PTEuNiwgdGlsZUdyaWRTaXplPSg4LCA4KSkKICAgIGxfY2hhbm5lbCA9IGNsYWhlLmFwcGx5KGxfY2hhbm5lbCkKICAgIHJldHVybiBjdjIuY3Z0Q29sb3IoY3YyLm1lcmdlKChsX2NoYW5uZWwsIGFfY2hhbm5lbCwgYl9jaGFubmVsKSksIGN2Mi5DT0xPUl9MQUIyQkdSKQoKCmRlZiBhdXRvX3JvdGF0ZV9wcm9maWxlKGltYWdlLCBwcm9maWxlKToKICAgIGhlaWdodCwgd2lkdGggPSBpbWFnZS5zaGFwZVs6Ml0KCiAgICBpZiBwcm9maWxlID09ICJyZWNlaXB0IiBhbmQgd2lkdGggPiBoZWlnaHQ6CiAgICAgICAgcmV0dXJuIGN2Mi5yb3RhdGUoaW1hZ2UsIGN2Mi5ST1RBVEVfOTBfQ0xPQ0tXSVNFKQoKICAgIHJldHVybiBpbWFnZQoKCmRlZiBwb3N0cHJvY2VzcyhpbnB1dF9wYXRoLCBvdXRwdXRfcGF0aCwgcHJvZmlsZSk6CiAgICBpbWFnZSA9IGN2Mi5pbXJlYWQoc3RyKGlucHV0X3BhdGgpLCBjdjIuSU1SRUFEX0NPTE9SKQogICAgaWYgaW1hZ2UgaXMgTm9uZToKICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoZiJPcGVuQ1Yga29ubnRlIHtpbnB1dF9wYXRofSBuaWNodCBsZXNlbiIpCgogICAgY29udG91ciA9IGZpbmRfZG9jdW1lbnRfY29udG91cihpbWFnZSwgcHJvZmlsZSkKICAgIGlmIGNvbnRvdXIgaXMgbm90IE5vbmU6CiAgICAgICAgcHJvY2Vzc2VkID0gZm91cl9wb2ludF90cmFuc2Zvcm0oaW1hZ2UsIGNvbnRvdXIuYXN0eXBlKCJmbG9hdDMyIikpCiAgICBlbHNlOgogICAgICAgIHByb2Nlc3NlZCA9IHRyaW1fbGlnaHRfYm9yZGVyKGltYWdlKQoKICAgIHByb2Nlc3NlZCA9IGRlc2tld19ieV90ZXh0X2FuZ2xlKHByb2Nlc3NlZCkKICAgIHByb2Nlc3NlZCA9IHRyaW1fbGlnaHRfYm9yZGVyKHByb2Nlc3NlZCkKICAgIHByb2Nlc3NlZCA9IGF1dG9fcm90YXRlX3Byb2ZpbGUocHJvY2Vzc2VkLCBwcm9maWxlKQoKICAgIGlmIHByb2ZpbGUgPT0gInJlY2VpcHQiOgogICAgICAgIHByb2Nlc3NlZCA9IGVuaGFuY2VfcmVjZWlwdChwcm9jZXNzZWQpCiAgICBlbGlmIHByb2ZpbGUgIT0gInJhdyI6CiAgICAgICAgcHJvY2Vzc2VkID0gZW5oYW5jZV9kb2N1bWVudChwcm9jZXNzZWQpCgogICAgc2F2ZV9vdXRwdXQocHJvY2Vzc2VkLCBvdXRwdXRfcGF0aCkKCgpkZWYgc2F2ZV9vdXRwdXQoaW1hZ2UsIG91dHB1dF9wYXRoKToKICAgIHN1ZmZpeCA9IG91dHB1dF9wYXRoLnN1ZmZpeC5sb3dlcigpCgogICAgaWYgc3VmZml4ID09ICIucGRmIjoKICAgICAgICByZ2IgPSBjdjIuY3Z0Q29sb3IoaW1hZ2UsIGN2Mi5DT0xPUl9CR1IyUkdCKQogICAgICAgIHBpbF9pbWFnZSA9IEltYWdlLmZyb21hcnJheShyZ2IpCiAgICAgICAgaWYgcGlsX2ltYWdlLm1vZGUgIT0gIlJHQiI6CiAgICAgICAgICAgIHBpbF9pbWFnZSA9IHBpbF9pbWFnZS5jb252ZXJ0KCJSR0IiKQogICAgICAgIHBpbF9pbWFnZS5zYXZlKG91dHB1dF9wYXRoLCAiUERGIiwgcmVzb2x1dGlvbj0zMDAuMCkKICAgICAgICByZXR1cm4KCiAgICBpZiBzdWZmaXggaW4geyIuanBnIiwgIi5qcGVnIn06CiAgICAgICAgY3YyLmltd3JpdGUoc3RyKG91dHB1dF9wYXRoKSwgaW1hZ2UsIFtjdjIuSU1XUklURV9KUEVHX1FVQUxJVFksIDkyXSkKICAgICAgICByZXR1cm4KCiAgICBpZiBzdWZmaXggPT0gIi5wbmciOgogICAgICAgIGN2Mi5pbXdyaXRlKHN0cihvdXRwdXRfcGF0aCksIGltYWdlLCBbY3YyLklNV1JJVEVfUE5HX0NPTVBSRVNTSU9OLCAzXSkKICAgICAgICByZXR1cm4KCiAgICBpZiBzdWZmaXggaW4geyIudGlmIiwgIi50aWZmIn06CiAgICAgICAgY3YyLmltd3JpdGUoc3RyKG91dHB1dF9wYXRoKSwgaW1hZ2UpCiAgICAgICAgcmV0dXJuCgogICAgcmFpc2UgUnVudGltZUVycm9yKGYiTmljaHQgdW50ZXJzdMO8dHp0ZXMgQXVzZ2FiZWZvcm1hdDoge3N1ZmZpeH0iKQoKCmRlZiBtYWluKCk6CiAgICBwYXJzZXIgPSBhcmdwYXJzZS5Bcmd1bWVudFBhcnNlcihkZXNjcmlwdGlvbj0iRkVERU8gU2Nhbi1OYWNoYmVhcmJlaXR1bmcgbWl0IE9wZW5DViIpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCItLWlucHV0IiwgcmVxdWlyZWQ9VHJ1ZSkKICAgIHBhcnNlci5hZGRfYXJndW1lbnQoIi0tb3V0cHV0IiwgcmVxdWlyZWQ9VHJ1ZSkKICAgIHBhcnNlci5hZGRfYXJndW1lbnQoIi0tcHJvZmlsZSIsIGRlZmF1bHQ9ImRvY3VtZW50IiwgY2hvaWNlcz1bImRvY3VtZW50IiwgInJlY2VpcHQiLCAicmF3Il0pCiAgICBhcmdzID0gcGFyc2VyLnBhcnNlX2FyZ3MoKQoKICAgIHBvc3Rwcm9jZXNzKFBhdGgoYXJncy5pbnB1dCksIFBhdGgoYXJncy5vdXRwdXQpLCBhcmdzLnByb2ZpbGUpCgoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIG1haW4oKQo=",