#!/bin/bash
# ============================================================
#  REBOOTLY ARCHIVES — 02-deploy-client.sh  VERSION: 2.5.0
#  2026-03-17 — update.sh intégré (LATEST regex fix), cron auto-update
#  Déploie une instance client : LXC Debian 12 + Docker +
#  Mailpiler + Manticore + MariaDB + Bridge API + React UI
#
#  Version : 3.0.0 — LXC+Docker (tous bugs validés)
#
#  Usage interactif :
#    bash 02-deploy-client.sh
#
#  Usage CLI :
#    bash 02-deploy-client.sh --lxcid 200 --domain client.fr \
#      --admin admin@client.fr --retention 3650
# ============================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

GREEN='\033[0;32m'; CYAN='\033[0;36m'; YELLOW='\033[1;33m'
RED='\033[0;31m'; BOLD='\033[1m'; NC='\033[0m'
ok()      { echo -e "${GREEN}[✓]${NC} $1"; }
section() { echo -e "\n${CYAN}${BOLD}┌─ $1${NC}"; }
warn()    { echo -e "${YELLOW}[!]${NC} $1"; }
err()     { echo -e "${RED}[✗]${NC} $1"; exit 1; }
info()    { echo -e "    ${CYAN}→${NC} $1"; }

# ── Bridge embarqué en base64 (rebootly-bridge-v2.js) ────────────────────────
# Généré par : base64 -w0 rebootly-bridge-v2.js
BRIDGE_B64="J3VzZSBzdHJpY3QnOw0KY29uc3QgaHR0cCAgICA9IHJlcXVpcmUoJ2h0dHAnKTsNCmNvbnN0IHVybCAgICAgPSByZXF1aXJlKCd1cmwnKTsNCmNvbnN0IGNyeXB0byAgPSByZXF1aXJlKCdjcnlwdG8nKTsNCmNvbnN0IGZzICAgICAgPSByZXF1aXJlKCdmcycpOw0KY29uc3QgeyBzcGF3blN5bmMsIHNwYXduIH0gPSByZXF1aXJlKCdjaGlsZF9wcm9jZXNzJyk7DQoNCmNvbnN0IFBPUlQgICAgICAgPSAzMDAxOw0KY29uc3QgQVBJX1NFQ1JFVCA9ICdfX0FQSV9TRUNSRVRfXyc7DQpjb25zdCBTUUxfUEFTUyAgID0gJ19fU1FMX1BBU1NfXyc7DQpjb25zdCBBQ0NPVU5UX0lEID0gJ19fQUNDT1VOVF9JRF9fJzsNCmNvbnN0IERPTUFJTiAgICAgPSAnX19ET01BSU5fXyc7DQpjb25zdCBMWENfSVAgICAgID0gJ19fTFhDX0lQX18nOw0KY29uc3QgREJfTkFNRSAgICA9ICdyYi1tYXJpYWRiLScgKyBBQ0NPVU5UX0lEOw0KY29uc3QgUElMRVJfTkFNRSA9ICdyYi1waWxlci0nICAgKyBBQ0NPVU5UX0lEOw0KY29uc3QgVkVSU0lPTiAgICA9ICc1LjMuMyc7DQoNCi8vIOKUgOKUgCBKV1Qg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQpjb25zdCBqd3RTaWduID0gKHApID0+IHsNCiAgY29uc3QgaCA9IEJ1ZmZlci5mcm9tKEpTT04uc3RyaW5naWZ5KHthbGc6J0hTMjU2Jyx0eXA6J0pXVCd9KSkudG9TdHJpbmcoJ2Jhc2U2NHVybCcpOw0KICBjb25zdCBiID0gQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkoey4uLnAsaWF0Ok1hdGguZmxvb3IoRGF0ZS5ub3coKS8xMDAwKX0pKS50b1N0cmluZygnYmFzZTY0dXJsJyk7DQogIGNvbnN0IHMgPSBjcnlwdG8uY3JlYXRlSG1hYygnc2hhMjU2JyxBUElfU0VDUkVUKS51cGRhdGUoaCsnLicrYikuZGlnZXN0KCdiYXNlNjR1cmwnKTsNCiAgcmV0dXJuIGgrJy4nK2IrJy4nK3M7DQp9Ow0KY29uc3Qgand0VmVyaWZ5ID0gKHRva2VuKSA9PiB7DQogIHRyeSB7DQogICAgY29uc3QgW2gsYixzXSA9IHRva2VuLnNwbGl0KCcuJyk7DQogICAgY29uc3QgZSA9IGNyeXB0by5jcmVhdGVIbWFjKCdzaGEyNTYnLEFQSV9TRUNSRVQpLnVwZGF0ZShoKycuJytiKS5kaWdlc3QoJ2Jhc2U2NHVybCcpOw0KICAgIGlmICghY3J5cHRvLnRpbWluZ1NhZmVFcXVhbChCdWZmZXIuZnJvbShzKSxCdWZmZXIuZnJvbShlKSkpIHJldHVybiBudWxsOw0KICAgIGNvbnN0IHAgPSBKU09OLnBhcnNlKEJ1ZmZlci5mcm9tKGIsJ2Jhc2U2NHVybCcpLnRvU3RyaW5nKCkpOw0KICAgIGlmIChwLmV4cCAmJiBwLmV4cCA8IE1hdGguZmxvb3IoRGF0ZS5ub3coKS8xMDAwKSkgcmV0dXJuIG51bGw7DQogICAgcmV0dXJuIHA7DQogIH0gY2F0Y2ggeyByZXR1cm4gbnVsbDsgfQ0KfTsNCg0KLy8g4pSA4pSAIERCIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgA0KY29uc3QgZGJRdWVyeSA9IChzcWwsIHRpbWVvdXQ9MTAwMDApID0+IHsNCiAgY29uc3QgdG1wID0gJy90bXAvcmJxXycrRGF0ZS5ub3coKSsnXycrTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMikrJy5zcWwnOw0KICBmcy53cml0ZUZpbGVTeW5jKHRtcCwgc3FsKydcbicpOw0KICBjb25zdCBjcCA9IHNwYXduU3luYygnZG9ja2VyJyxbJ2NwJyx0bXAsREJfTkFNRSsnOi90bXAvcS5zcWwnXSx7dGltZW91dDo0MDAwLGVuY29kaW5nOid1dGY4J30pOw0KICB0cnkgeyBmcy51bmxpbmtTeW5jKHRtcCk7IH0gY2F0Y2gge30NCiAgaWYgKGNwLnN0YXR1cyE9PTApIHRocm93IG5ldyBFcnJvcignZG9ja2VyIGNwOiAnKyhjcC5zdGRlcnJ8fCcnKS5zbGljZSgwLDEwMCkpOw0KICBjb25zdCByID0gc3Bhd25TeW5jKCdkb2NrZXInLFsnZXhlYycsREJfTkFNRSwnbWFyaWFkYicsJy1oJywnMTI3LjAuMC4xJywnLXVwaWxlcicsJy1wJytTUUxfUEFTUywncGlsZXInLCctc04nLCctZScsJ3NvdXJjZSAvdG1wL3Euc3FsJ10se3RpbWVvdXQsZW5jb2Rpbmc6J3V0ZjgnfSk7DQogIGNvbnN0IGVyciA9IChyLnN0ZGVycnx8JycpLnNwbGl0KCdcbicpLmZpbHRlcihsPT4hL3dhcm5pbmd8bWFyaWFkYiBmcm9tL2kudGVzdChsKSkuam9pbignXG4nKS50cmltKCk7DQogIGlmIChyLnN0YXR1cyE9PTAgJiYgZXJyKSB0aHJvdyBuZXcgRXJyb3IoJ0RCOiAnK2Vyci5zbGljZSgwLDIwMCkpOw0KICByZXR1cm4gKHIuc3Rkb3V0fHwnJykudHJpbSgpOw0KfTsNCmNvbnN0IGRiUm93cyA9IChzcWwpID0+IHsgY29uc3Qgbz1kYlF1ZXJ5KHNxbCk7IGlmKCFvKSByZXR1cm4gW107IHJldHVybiBvLnNwbGl0KCdcbicpLm1hcChyPT5yLnNwbGl0KCdcdCcpKTsgfTsNCg0KLy8g4pSA4pSAIEV4ZWMgYXN5bmMgKG5vbi1ibG9xdWFudCDigJQgbmUgZmlnZSBwYXMgbCdldmVudCBsb29wKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIANCmNvbnN0IHJ1bkFzeW5jID0gKGNtZCwgYXJncywgaW5wdXQ9bnVsbCkgPT4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHsNCiAgY29uc3QgY2hpbGQgPSBzcGF3bihjbWQsIGFyZ3MsIHtlbnY6cHJvY2Vzcy5lbnZ9KTsNCiAgbGV0IHN0ZG91dD0nJywgc3RkZXJyPScnOw0KICBpZihpbnB1dCl7IGNoaWxkLnN0ZGluLndyaXRlKGlucHV0KTsgY2hpbGQuc3RkaW4uZW5kKCk7IH0NCiAgY2hpbGQuc3Rkb3V0Lm9uKCdkYXRhJywgZD0+eyBzdGRvdXQrPWQ7IH0pOw0KICBjaGlsZC5zdGRlcnIub24oJ2RhdGEnLCBkPT57IHN0ZGVycis9ZDsgfSk7DQogIGNoaWxkLm9uKCdjbG9zZScsIGNvZGU9PnJlc29sdmUoe2NvZGUsIHN0ZG91dCwgc3RkZXJyfSkpOw0KICBjaGlsZC5vbignZXJyb3InLCBlPT5yZXNvbHZlKHtjb2RlOi0xLCBzdGRvdXQ6JycsIHN0ZGVycjplLm1lc3NhZ2V9KSk7DQogIC8vIFRpbWVvdXQgMTAgbWluDQogIHNldFRpbWVvdXQoKCk9PnsgdHJ5e2NoaWxkLmtpbGwoJ1NJR1RFUk0nKTt9Y2F0Y2h7fSB9LCA2MDAwMDApOw0KfSk7DQoNCi8vIOKUgOKUgCBQYXNzd29yZHMg4oCUIFNIQS01MTIgY3J5cHQgdmlhIG9wZW5zc2wgKGNvbXBhdGlibGUgTWFpbHBpbGVyLCBzYW5zIGTDqXBlbmRhbmNlIFB5dGhvbikg4pSA4pSADQpjb25zdCB2ZXJpZnlQdyA9IChwdywgaGFzaCkgPT4gew0KICBpZiAoIWhhc2gpIHJldHVybiBmYWxzZTsNCiAgLy8gU0hBLTUxMiAoJDYkKSDigJQgZm9ybWF0IGNyw6nDqSBwYXIgbGUgYnJpZGdlDQogIGNvbnN0IG02ID0gKGhhc2gpLm1hdGNoKC9eXCQ2XCQoW14kXSspXCQvKTsNCiAgaWYgKG02KSB7DQogICAgY29uc3QgciA9IHNwYXduU3luYygnb3BlbnNzbCcsIFsncGFzc3dkJywgJy02JywgJy1zYWx0JywgbTZbMV0sIHB3XSwgeyB0aW1lb3V0OiA0MDAwLCBlbmNvZGluZzogJ3V0ZjgnIH0pOw0KICAgIHJldHVybiAoci5zdGRvdXQgfHwgJycpLnRyaW0oKSA9PT0gaGFzaDsNCiAgfQ0KICAvLyBNRDUgKCQxJCkg4oCUIGZvcm1hdCBjcsOpw6kgcGFyIGwnaW50ZXJmYWNlIG5hdGl2ZSBNYWlscGlsZXINCiAgY29uc3QgbTEgPSAoaGFzaCkubWF0Y2goL15cJDFcJChbXiRdKylcJC8pOw0KICBpZiAobTEpIHsNCiAgICBjb25zdCByID0gc3Bhd25TeW5jKCdvcGVuc3NsJywgWydwYXNzd2QnLCAnLTEnLCAnLXNhbHQnLCBtMVsxXSwgcHddLCB7IHRpbWVvdXQ6IDQwMDAsIGVuY29kaW5nOiAndXRmOCcgfSk7DQogICAgcmV0dXJuIChyLnN0ZG91dCB8fCAnJykudHJpbSgpID09PSBoYXNoOw0KICB9DQogIHJldHVybiBmYWxzZTsNCn07DQpjb25zdCBoYXNoUHcgPSAocHcpID0+IHsNCiAgY29uc3QgciA9IHNwYXduU3luYygnb3BlbnNzbCcsIFsncGFzc3dkJywgJy02JywgcHddLCB7IHRpbWVvdXQ6IDQwMDAsIGVuY29kaW5nOiAndXRmOCcgfSk7DQogIHJldHVybiAoci5zdGRvdXQgfHwgJycpLnRyaW0oKTsNCn07DQoNCi8vIOKUgOKUgCBIVFRQIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgA0KY29uc3QganNvbj0ocmVzLGRhdGEsY29kZT0yMDApPT57Y29uc3QgYj1KU09OLnN0cmluZ2lmeShkYXRhKTtyZXMud3JpdGVIZWFkKGNvZGUseydDb250ZW50LVR5cGUnOidhcHBsaWNhdGlvbi9qc29uJywnQ29udGVudC1MZW5ndGgnOkJ1ZmZlci5ieXRlTGVuZ3RoKGIpLCdBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nOicqJywnQWNjZXNzLUNvbnRyb2wtQWxsb3ctSGVhZGVycyc6J0F1dGhvcml6YXRpb24sQ29udGVudC1UeXBlJywnWC1SZWJvb3RseS1WZXJzaW9uJzpWRVJTSU9OfSk7cmVzLmVuZChiKTt9Ow0KY29uc3QgcmVhZEJvZHk9KHJlcSk9Pm5ldyBQcm9taXNlKChyZXNvbHZlLHJlamVjdCk9PntsZXQgZD0nJztyZXEub24oJ2RhdGEnLGM9PntkKz1jO2lmKGQubGVuZ3RoPjEwZTYpcmVqZWN0KG5ldyBFcnJvcignQm9keSB0cm9wIGdyYW5kJykpO30pO3JlcS5vbignZW5kJywoKT0+e3RyeXtyZXNvbHZlKEpTT04ucGFyc2UoZHx8J3t9JykpO31jYXRjaHtyZXNvbHZlKHt9KTt9fSk7cmVxLm9uKCdlcnJvcicscmVqZWN0KTt9KTsNCmNvbnN0IHJlcXVpcmVBdXRoPShyZXEscmVzKT0+e2NvbnN0IGF1dGg9cmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbnx8Jyc7aWYoIWF1dGguc3RhcnRzV2l0aCgnQmVhcmVyICcpKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidOb24gYXV0b3Jpc8OpJ30sNDAxKTtyZXR1cm4gbnVsbDt9Y29uc3QgdT1qd3RWZXJpZnkoYXV0aC5zbGljZSg3KSk7aWYoIXUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J1Nlc3Npb24gZXhwaXLDqWUnfSw0MDEpO3JldHVybiBudWxsO31yZXR1cm4gdTt9Ow0KY29uc3QgcmVxdWlyZUFkbWluPShyZXEscmVzKT0+e2NvbnN0IHU9cmVxdWlyZUF1dGgocmVxLHJlcyk7aWYoIXUpcmV0dXJuIG51bGw7aWYoIXUuaXNhZG1pbil7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonQWRtaW4gcmVxdWlzJ30sNDAzKTtyZXR1cm4gbnVsbDt9cmV0dXJuIHU7fTsNCmNvbnN0IGVzYz0ocyk9PlN0cmluZyhzPT1udWxsPycnOnMpLnJlcGxhY2UoL1xcL2csJ1xcXFwnKS5yZXBsYWNlKC8nL2csIlxcJyIpOw0KY29uc3Qgbm93PSgpPT5NYXRoLmZsb29yKERhdGUubm93KCkvMTAwMCk7DQoNCmNvbnN0IHJvdXRlcyA9IHt9Ow0KDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCi8vIEFVVEgNCi8vIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkA0Kcm91dGVzWydQT1NUIC92MS9hdXRoL2xvZ2luJ10gPSBhc3luYyAocmVxLHJlcykgPT4gew0KICBjb25zdCB7dXNlcm5hbWUscGFzc3dvcmR9PWF3YWl0IHJlYWRCb2R5KHJlcSk7DQogIGlmICghdXNlcm5hbWV8fCFwYXNzd29yZCkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J0lkZW50aWZpYW50cyByZXF1aXMnfSw0MDApOw0KICBsZXQgcm93Ow0KICB0cnkgeyByb3c9KGRiUm93cyhgU0VMRUNUIHVpZCx1c2VybmFtZSxwYXNzd29yZCxpc2FkbWluIEZST00gdXNlciBXSEVSRSB1c2VybmFtZT0nJHtlc2ModXNlcm5hbWUpfScgTElNSVQgMWApKVswXTsgfQ0KICBjYXRjaChlKSB7IHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTsgfQ0KICBpZiAoIXJvd3x8cm93Lmxlbmd0aDw0fHwhcm93WzJdKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonVXRpbGlzYXRldXIgaW50cm91dmFibGUnfSw0MDEpOw0KICBpZiAoIXZlcmlmeVB3KHBhc3N3b3JkLHJvd1syXSkpIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidNb3QgZGUgcGFzc2UgaW5jb3JyZWN0J30sNDAxKTsNCiAgY29uc3QgZXhwPW5vdygpKzg2NDAwKjc7DQogIGNvbnN0IHRva2VuPWp3dFNpZ24oe3VpZDpwYXJzZUludChyb3dbMF0pLHVzZXJuYW1lOnJvd1sxXSxpc2FkbWluOnJvd1szXT09PScxJyxleHB9KTsNCiAganNvbihyZXMse29rOnRydWUsdG9rZW4sZXhwLHVzZXI6e3VpZDpwYXJzZUludChyb3dbMF0pLHVzZXJuYW1lOnJvd1sxXSxpc2FkbWluOnJvd1szXT09PScxJ319KTsNCn07DQpyb3V0ZXNbJ0dFVCAvdjEvYXV0aC9tZSddPShyZXEscmVzKT0+e2NvbnN0IHU9cmVxdWlyZUF1dGgocmVxLHJlcyk7aWYoIXUpcmV0dXJuO2pzb24ocmVzLHtvazp0cnVlLHVzZXI6dX0pO307DQoNCi8vIOKUgOKUgOKUgCBCcmFuZGluZyBwdWJsaWMgKHNhbnMgYXV0aCDigJQgdXRpbGlzw6kgcGFyIGxhIHBhZ2UgZGUgY29ubmV4aW9uKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIANCnJvdXRlc1snR0VUIC92MS9wdWJsaWMvYnJhbmRpbmcnXT0ocmVxLHJlcyk9PnsNCiAgdHJ5ew0KICAgIGNvbnN0IHJvd3M9ZGJSb3dzKCJTRUxFQ1QgdmFsdWUgRlJPTSBgb3B0aW9uYCBXSEVSRSBga2V5YD0nY29tcGFueV9uYW1lJyIpOw0KICAgIGNvbnN0IGNvbXBhbnlfbmFtZT0ocm93cy5sZW5ndGgmJnJvd3NbMF1bMF0mJnJvd3NbMF1bMF0hPT0nTlVMTCcpP3Jvd3NbMF1bMF06Jyc7DQogICAganNvbihyZXMse2NvbXBhbnlfbmFtZX0pOw0KICB9Y2F0Y2goZSl7anNvbihyZXMse2NvbXBhbnlfbmFtZTonJ30pO30NCn07DQoNCi8vIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkA0KLy8gU1RBVFMgLyBTVEFUVVMgLyBIRUFMVEgNCi8vIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkA0Kcm91dGVzWydHRVQgL3YxL3N0YXR1cyddPShyZXEscmVzKT0+anNvbihyZXMse29rOnRydWUsdmVyc2lvbjpWRVJTSU9OLGNsaWVudF9pZDpBQ0NPVU5UX0lELGRvbWFpbjpET01BSU4sbHhjX2lwOkxYQ19JUCx0aW1lc3RhbXA6bmV3IERhdGUoKS50b0lTT1N0cmluZygpfSk7DQoNCnJvdXRlc1snR0VUIC92MS9zdGF0cyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQXV0aChyZXEscmVzKSlyZXR1cm47DQogIHRyeSB7DQogICAgY29uc3QgbT0oZGJSb3dzKCdTRUxFQ1QgQ09VTlQoKiksQ09BTEVTQ0UoU1VNKHNpemUpLDApLE1BWChhcnJpdmVkKSBGUk9NIG1ldGFkYXRhIFdIRVJFIGRlbGV0ZWQ9MCcpWzBdKXx8W107DQogICAgY29uc3QgdGQ9KGRiUm93cyhgU0VMRUNUIENPVU5UKCopIEZST00gbWV0YWRhdGEgV0hFUkUgZGVsZXRlZD0wIEFORCBhcnJpdmVkPj0ke25vdygpLTg2NDAwfWApWzBdKXx8W107DQogICAgY29uc3QgdT0oZGJSb3dzKCdTRUxFQ1QgQ09VTlQoKikgRlJPTSB1c2VyJylbMF0pfHxbXTsNCiAgICBjb25zdCBkPShkYlJvd3MoJ1NFTEVDVCBDT1VOVCgqKSBGUk9NIGRvbWFpbicpWzBdKXx8W107DQogICAgY29uc3QgYz0oZGJSb3dzKCdTRUxFQ1QgcmN2ZCx2aXJ1cyxkdXBsaWNhdGUsc3RvcmVkX3NpemUgRlJPTSBjb3VudGVyIExJTUlUIDEnKVswXSl8fFtdOw0KICAgIGNvbnN0IGltcD0oZGJSb3dzKCdTRUxFQ1QgQ09VTlQoKiksQ09BTEVTQ0UoU1VNKGltcG9ydGVkKSwwKSBGUk9NIGltcG9ydCcpWzBdKXx8W107DQogICAganNvbihyZXMse3RvdGFsX2VtYWlsczpwYXJzZUludChtWzBdKXx8MCx0b3RhbF9ieXRlczpwYXJzZUludChtWzFdKXx8MCxsYXN0X2VtYWlsOm1bMl0mJm1bMl0hPT0nTlVMTCc/bmV3IERhdGUocGFyc2VJbnQobVsyXSkqMTAwMCkudG9JU09TdHJpbmcoKTpudWxsLHRvZGF5X2VtYWlsczpwYXJzZUludCh0ZFswXSl8fDAsdG90YWxfdXNlcnM6cGFyc2VJbnQodVswXSl8fDAsdG90YWxfZG9tYWluczpwYXJzZUludChkWzBdKXx8MCxyY3ZkOnBhcnNlSW50KGNbMF0pfHwwLHZpcnVzOnBhcnNlSW50KGNbMV0pfHwwLGR1cGxpY2F0ZV90b3RhbDpwYXJzZUludChjWzJdKXx8MCxzdG9yZWRfYnl0ZXM6cGFyc2VJbnQoY1szXSl8fDAsaW1wb3J0X2pvYnM6cGFyc2VJbnQoaW1wWzBdKXx8MCxpbXBvcnRfdG90YWw6cGFyc2VJbnQoaW1wWzFdKXx8MH0pOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQoNCmxldCBfaGVhbHRoQ2FjaGU9bnVsbCxfaGVhbHRoQ2FjaGVUcz0wOw0Kcm91dGVzWydHRVQgL3YxL2hlYWx0aCddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQXV0aChyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IG5vdz1EYXRlLm5vdygpOw0KICBpZihfaGVhbHRoQ2FjaGUmJihub3ctX2hlYWx0aENhY2hlVHMpPDMwMDAwKXJldHVybiBqc29uKHJlcyxfaGVhbHRoQ2FjaGUpOw0KICBjb25zdCByPXNwYXduU3luYygnZG9ja2VyJyxbJ3BzJywnLWEnLCctLWZvcm1hdCcsJ3t7Lk5hbWVzfX18e3suU3RhdHVzfX18e3suU3RhdGV9fScsJy0tZmlsdGVyJywnbmFtZT1yYi0nXSx7ZW5jb2Rpbmc6J3V0ZjgnfSk7DQogIGNvbnN0IGNvbnRhaW5lcnM9KHIuc3Rkb3V0fHwnJykudHJpbSgpLnNwbGl0KCdcbicpLmZpbHRlcihCb29sZWFuKS5tYXAobD0+e2NvbnN0W25hbWUsc3RhdHVzLHN0YXRlXT1sLnNwbGl0KCd8Jyk7cmV0dXJue25hbWUsc3RhdHVzLHJ1bm5pbmc6c3RhdGU9PT0ncnVubmluZyd9O30pOw0KICBfaGVhbHRoQ2FjaGU9e29rOmNvbnRhaW5lcnMuZXZlcnkoYz0+Yy5ydW5uaW5nKSxjb250YWluZXJzfTsNCiAgX2hlYWx0aENhY2hlVHM9bm93Ow0KICBqc29uKHJlcyxfaGVhbHRoQ2FjaGUpOw0KfTsNCg0KLy8g4pSA4pSAIENvbnRhaW5lciBhY3Rpb25zIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgA0KY29uc3QgYWxsb3dlZENvbnRhaW5lcnM9WydyYi1waWxlci0nLCdyYi1tYXJpYWRiLScsJ3JiLW1hbnRpY29yZS0nLCdyYi1tZW1jYWNoZWQtJywncmItcG9ydGFpbmVyLSddOw0Kcm91dGVzWydQT1NUIC92MS9jb250YWluZXJzLzpuYW1lL3Jlc3RhcnQnXT1hc3luYyhyZXEscmVzLHtuYW1lfSk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIGlmKCFhbGxvd2VkQ29udGFpbmVycy5zb21lKHA9Pm5hbWUuc3RhcnRzV2l0aChwKSkpcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J05vbiBhdXRvcmlzw6knfSw0MDMpOw0KICBjb25zdCByPXNwYXduU3luYygnZG9ja2VyJyxbJ3Jlc3RhcnQnLG5hbWVdLHt0aW1lb3V0OjYwMDAwLGVuY29kaW5nOid1dGY4J30pOw0KICByLnN0YXR1cyE9PTA/anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTooci5zdGRlcnJ8fCcnKS5zbGljZSgwLDIwMCl9LDUwMCk6anNvbihyZXMse29rOnRydWUsbWVzc2FnZTpgJHtuYW1lfSByZWTDqW1hcnLDqWB9KTsNCn07DQpyb3V0ZXNbJ1BPU1QgL3YxL2NvbnRhaW5lcnMvOm5hbWUvc3RvcCddPWFzeW5jKHJlcSxyZXMse25hbWV9KT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgaWYoIWFsbG93ZWRDb250YWluZXJzLnNvbWUocD0+bmFtZS5zdGFydHNXaXRoKHApKSlyZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonTm9uIGF1dG9yaXPDqSd9LDQwMyk7DQogIHNwYXduU3luYygnZG9ja2VyJyxbJ3N0b3AnLG5hbWVdLHt0aW1lb3V0OjMwMDAwLGVuY29kaW5nOid1dGY4J30pOw0KICBqc29uKHJlcyx7b2s6dHJ1ZSxtZXNzYWdlOmAke25hbWV9IGFycsOqdMOpYH0pOw0KfTsNCnJvdXRlc1snUE9TVCAvdjEvY29udGFpbmVycy86bmFtZS9zdGFydCddPWFzeW5jKHJlcSxyZXMse25hbWV9KT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgaWYoIWFsbG93ZWRDb250YWluZXJzLnNvbWUocD0+bmFtZS5zdGFydHNXaXRoKHApKSlyZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonTm9uIGF1dG9yaXPDqSd9LDQwMyk7DQogIHNwYXduU3luYygnZG9ja2VyJyxbJ3N0YXJ0JyxuYW1lXSx7dGltZW91dDozMDAwMCxlbmNvZGluZzondXRmOCd9KTsNCiAganNvbihyZXMse29rOnRydWUsbWVzc2FnZTpgJHtuYW1lfSBkw6ltYXJyw6lgfSk7DQp9Ow0Kcm91dGVzWydHRVQgL3YxL2NvbnRhaW5lcnMvOm5hbWUvbG9ncyddPWFzeW5jKHJlcSxyZXMse25hbWV9KT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgaWYoIWFsbG93ZWRDb250YWluZXJzLnNvbWUocD0+bmFtZS5zdGFydHNXaXRoKHApKSlyZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonTm9uIGF1dG9yaXPDqSd9LDQwMyk7DQogIGNvbnN0IGxpbmVzPU1hdGgubWluKDUwMCxwYXJzZUludChyZXEucXVlcnkubGluZXN8fCcxMDAnKSk7DQogIGNvbnN0IHI9c3Bhd25TeW5jKCdkb2NrZXInLFsnbG9ncycsJy0tdGFpbCcsU3RyaW5nKGxpbmVzKSwnLS10aW1lc3RhbXBzJyxuYW1lXSx7dGltZW91dDoxMDAwMCxlbmNvZGluZzondXRmOCcsbWF4QnVmZmVyOjIqMTAyNCoxMDI0fSk7DQogIGNvbnN0IG91dD0oKHIuc3Rkb3V0fHwnJykrKHIuc3RkZXJyfHwnJykpLnRyaW0oKTsNCiAganNvbihyZXMse29rOnRydWUsbG9nczpvdXQ/b3V0LnNwbGl0KCdcbicpOltdfSk7DQp9Ow0KDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCi8vIEVNQUlMUyAodl9tZXNzYWdlcyB2aWV3ID0gbWV0YWRhdGEgSk9JTiByY3B0KQ0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQpyb3V0ZXNbJ0RFTEVURSAvdjEvZW1haWxzJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IHtpZHN9PWF3YWl0IHJlYWRCb2R5KHJlcSk7DQogIGlmKCFBcnJheS5pc0FycmF5KGlkcyl8fCFpZHMubGVuZ3RoKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonaWRzW10gcmVxdWlzJ30sNDAwKTsNCiAgY29uc3Qgc2FmZUlkcz1pZHMubWFwKGlkPT5wYXJzZUludChpZCkpLmZpbHRlcihpZD0+IWlzTmFOKGlkKSYmaWQ+MCk7DQogIGlmKCFzYWZlSWRzLmxlbmd0aCkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J0F1Y3VuIGlkIHZhbGlkZSd9LDQwMCk7DQogIHRyeXsNCiAgICAvLyBFeGNsdXJlIGxlcyBlbWFpbHMgcHJvdMOpZ8OpcyAoaW1tdWFibGVzKQ0KICAgIGxldCBwcm90ZWN0ZWRSb3dzPVtdOw0KICAgIHRyeXtwcm90ZWN0ZWRSb3dzPWRiUm93cyhgU0VMRUNUIG1ldGFkYXRhX2lkIEZST00gcmJfcHJvdGVjdGVkIFdIRVJFIG1ldGFkYXRhX2lkIElOICgke3NhZmVJZHMuam9pbignLCcpfSlgKTt9Y2F0Y2h7fQ0KICAgIGNvbnN0IHByb3RlY3RlZElkcz1uZXcgU2V0KHByb3RlY3RlZFJvd3MubWFwKHI9PnBhcnNlSW50KHJbMF0pKSk7DQogICAgY29uc3QgZGVsZXRhYmxlPXNhZmVJZHMuZmlsdGVyKGlkPT4hcHJvdGVjdGVkSWRzLmhhcyhpZCkpOw0KICAgIGlmKGRlbGV0YWJsZS5sZW5ndGgpIGRiUXVlcnkoYFVQREFURSBtZXRhZGF0YSBTRVQgZGVsZXRlZD0xIFdIRVJFIGlkIElOICgke2RlbGV0YWJsZS5qb2luKCcsJyl9KSBBTkQgZGVsZXRlZD0wYCk7DQogICAganNvbihyZXMse29rOnRydWUsZGVsZXRlZDpkZWxldGFibGUubGVuZ3RoLHNraXBwZWQ6cHJvdGVjdGVkSWRzLnNpemV9KTsNCiAgfWNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQoNCnJvdXRlc1snUE9TVCAvdjEvZW1haWxzLzppZC9wcm90ZWN0J109YXN5bmMocmVxLHJlcyx7aWR9KT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgY29uc3QgbWlkPXBhcnNlSW50KGlkKTsNCiAgaWYoIW1pZCkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J2lkIGludmFsaWRlJ30sNDAwKTsNCiAgdHJ5ew0KICAgIGRiUXVlcnkoYElOU0VSVCBJR05PUkUgSU5UTyByYl9wcm90ZWN0ZWQgKG1ldGFkYXRhX2lkLHByb3RlY3RlZF9hdCkgVkFMVUVTICgke21pZH0sJHtub3coKX0pYCk7DQogICAganNvbihyZXMse29rOnRydWUscHJvdGVjdGVkOnRydWV9KTsNCiAgfWNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQoNCnJvdXRlc1snREVMRVRFIC92MS9lbWFpbHMvOmlkL3Byb3RlY3QnXT1hc3luYyhyZXEscmVzLHtpZH0pPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICBjb25zdCBtaWQ9cGFyc2VJbnQoaWQpOw0KICBpZighbWlkKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonaWQgaW52YWxpZGUnfSw0MDApOw0KICB0cnl7DQogICAgZGJRdWVyeShgREVMRVRFIEZST00gcmJfcHJvdGVjdGVkIFdIRVJFIG1ldGFkYXRhX2lkPSR7bWlkfWApOw0KICAgIGpzb24ocmVzLHtvazp0cnVlLHByb3RlY3RlZDpmYWxzZX0pOw0KICB9Y2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0Kcm91dGVzWydHRVQgL3YxL2VtYWlscyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQXV0aChyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IHE9cmVxLnF1ZXJ5LHBhZ2U9TWF0aC5tYXgoMCxwYXJzZUludChxLnBhZ2V8fCcwJykpLGxpbWl0PU1hdGgubWluKDEwMCxwYXJzZUludChxLmxpbWl0fHwnMjUnKSk7DQogIC8vIGQgPSBkYXRlIHLDqWVsbGUgZW1haWwgKHNlbnQgc2kgZGlzcG8sIHNpbm9uIGFycml2ZWQpDQogIGNvbnN0IGRhdGVDb2w9J0NPQUxFU0NFKG0uc2VudCwgbS5hcnJpdmVkKSc7DQogIC8vIFBhciBkw6lmYXV0LCBleGNsdXJlIGxlcyBlbWFpbHMgaW1wb3J0w6lzIGRlcHVpcyBQU1QgKGlscyBzb250IGRhbnMgbCdvbmdsZXQgSW1wb3J0cykNCiAgbGV0IHdoZXJlPSdXSEVSRSBtLmRlbGV0ZWQ9MCBBTkQgTk9UIEVYSVNUUyAoU0VMRUNUIDEgRlJPTSByYl9wc3RfaW1wb3J0ZWQgcGkgV0hFUkUgcGkubWV0YWRhdGFfaWQ9bS5pZCknOw0KICBpZihxLnEpICAgICB3aGVyZSs9YCBBTkQgKG0uc3ViamVjdCBMSUtFICclJHtlc2MocS5xKX0lJyBPUiBtLlxgZnJvbVxgIExJS0UgJyUke2VzYyhxLnEpfSUnIE9SIHIudG8gTElLRSAnJSR7ZXNjKHEucSl9JScpYDsNCiAgaWYocS5vd25lcikgd2hlcmUrPWAgQU5EIChtLlxgZnJvbVxgIExJS0UgJyUke2VzYyhxLm93bmVyKX0lJyBPUiByLnRvIExJS0UgJyUke2VzYyhxLm93bmVyKX0lJylgOw0KICBlbHNlIHsNCiAgICBpZihxLmZyb20pICB3aGVyZSs9YCBBTkQgbS5cYGZyb21cYCBMSUtFICclJHtlc2MocS5mcm9tKX0lJ2A7DQogICAgaWYocS50bykgICAgd2hlcmUrPWAgQU5EIHIudG8gTElLRSAnJSR7ZXNjKHEudG8pfSUnYDsNCiAgfQ0KICBpZihxLnN0YXJ0KSB3aGVyZSs9YCBBTkQgJHtkYXRlQ29sfT49JHtwYXJzZUludChxLnN0YXJ0KX1gOw0KICBpZihxLmVuZCkgICB3aGVyZSs9YCBBTkQgJHtkYXRlQ29sfTw9JHtwYXJzZUludChxLmVuZCl9YDsNCiAgaWYocS5kaXIpICAgd2hlcmUrPWAgQU5EIG0uZGlyZWN0aW9uPSR7cGFyc2VJbnQocS5kaXIpfWA7DQogIGlmKHEuc3BhbT09PScxJykgd2hlcmUrPWAgQU5EIG0uc3BhbT0xYDsNCiAgZWxzZSBpZihxLnNwYW09PT0nMCcpIHdoZXJlKz1gIEFORCBtLnNwYW09MGA7DQogIHRyeSB7DQogICAgY29uc3QgdG90YWw9cGFyc2VJbnQoKGRiUm93cyhgU0VMRUNUIENPVU5UKERJU1RJTkNUIG0uaWQpIEZST00gbWV0YWRhdGEgbSBMRUZUIEpPSU4gcmNwdCByIE9OIG0uaWQ9ci5pZCAke3doZXJlfWApWzBdfHxbXSlbMF0pfHwwOw0KICAgIGNvbnN0IHJvd3M9ZGJSb3dzKGBTRUxFQ1QgbS5pZCxtLnN1YmplY3QsbS5cYGZyb21cYCxHUk9VUF9DT05DQVQoci50byBTRVBBUkFUT1IgJywgJyksJHtkYXRlQ29sfSxtLnNpemUsbS5kaXJlY3Rpb24sbS5hdHRhY2htZW50cyxtLnNwYW0sSUYocC5tZXRhZGF0YV9pZCBJUyBOT1QgTlVMTCwxLDApIEZST00gbWV0YWRhdGEgbSBMRUZUIEpPSU4gcmNwdCByIE9OIG0uaWQ9ci5pZCBMRUZUIEpPSU4gcmJfcHJvdGVjdGVkIHAgT04gcC5tZXRhZGF0YV9pZD1tLmlkICR7d2hlcmV9IEdST1VQIEJZIG0uaWQgT1JERVIgQlkgJHtkYXRlQ29sfSBERVNDIExJTUlUICR7bGltaXR9IE9GRlNFVCAke3BhZ2UqbGltaXR9YCk7DQogICAganNvbihyZXMse3RvdGFsLHBhZ2UsbGltaXQsZW1haWxzOnJvd3MuZmlsdGVyKHI9PnIubGVuZ3RoPj01KS5tYXAocj0+KHtpZDpyWzBdLHN1YmplY3Q6clsxXXx8JyhzYW5zIG9iamV0KScsZnJvbTpyWzJdfHwnJyx0bzpyWzNdfHwnJyxkYXRlOnJbNF0mJnJbNF0hPT0nTlVMTCc/bmV3IERhdGUocGFyc2VJbnQocls0XSkqMTAwMCkudG9JU09TdHJpbmcoKTpudWxsLHNpemU6cGFyc2VJbnQocls1XSl8fDAsZGlyZWN0aW9uOnBhcnNlSW50KHJbNl0pfHwwLGF0dGFjaG1lbnRzOnBhcnNlSW50KHJbN10pfHwwLHNwYW06cls4XT09PScxJyxwcm90ZWN0ZWQ6cls5XT09PScxJ30pKX0pOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQoNCi8vIOKUgOKUgCBFeHRyYWN0aW9uIHBpw6hjZSBqb2ludGUgZGVwdWlzIEVNTCAocGFyIGluZGV4IGRhbnMgbCdvcmRyZSBNSU1FKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIANCmZ1bmN0aW9uIGV4dHJhY3RNaW1lQXR0YWNobWVudChyYXcsdGFyZ2V0RmlsZW5hbWUsdGFyZ2V0SWR4KXsNCiAgY29uc3QgY29sbGVjdGVkPVtdOw0KICBmdW5jdGlvbiBjb2xsZWN0UGFydHModGV4dCl7DQogICAgY29uc3QgYmRNPXRleHQubWF0Y2goL2JvdW5kYXJ5PSI/KFteIlxyXG47XSspIj8vaSk7DQogICAgaWYoIWJkTSlyZXR1cm47DQogICAgY29uc3QgYmQ9YmRNWzFdLnRyaW0oKTsNCiAgICBjb25zdCBwYXJ0cz10ZXh0LnNwbGl0KCctLScrYmQpOw0KICAgIGZvcihsZXQgaT0xO2k8cGFydHMubGVuZ3RoO2krKyl7DQogICAgICBjb25zdCBwPXBhcnRzW2ldO2lmKHAuc3RhcnRzV2l0aCgnLS0nKXx8IXAudHJpbSgpKWNvbnRpbnVlOw0KICAgICAgY29uc3Qgc2VwPXAuaW5kZXhPZignXHJcblxyXG4nKSE9PS0xP3AuaW5kZXhPZignXHJcblxyXG4nKTpwLmluZGV4T2YoJ1xuXG4nKTtpZihzZXA9PT0tMSljb250aW51ZTsNCiAgICAgIGNvbnN0IHBoPXAuc2xpY2UoMCxzZXApLHBiPXAuc2xpY2Uoc2VwKyhwLmluZGV4T2YoJ1xyXG5cclxuJykhPT0tMT80OjIpKTsNCiAgICAgIGNvbnN0IHBjdD0oKHBoLm1hdGNoKC9Db250ZW50LVR5cGU6XHMqKFteO1xyXG5dKykvaSl8fFtdKVsxXXx8JycpLnRyaW0oKS50b0xvd2VyQ2FzZSgpOw0KICAgICAgY29uc3QgZGlzcD0oKHBoLm1hdGNoKC9Db250ZW50LURpc3Bvc2l0aW9uOlxzKihbXjtcclxuXSspL2kpfHxbXSlbMV18fCcnKS50cmltKCkudG9Mb3dlckNhc2UoKTsNCiAgICAgIGNvbnN0IGZuPSgocGgubWF0Y2goL2ZpbGVuYW1lXCo/PSI/KFteIlxyXG47XSspIj8vaSl8fFtdKVsxXXx8JycpLnJlcGxhY2UoL151dGYtOCdbXiddKicvaSwnJykudHJpbSgpOw0KICAgICAgaWYocGN0LnN0YXJ0c1dpdGgoJ211bHRpcGFydC8nKSl7Y29sbGVjdFBhcnRzKHBoKydcclxuXHJcbicrcGIpO30NCiAgICAgIGVsc2UgaWYoZGlzcC5pbmNsdWRlcygnYXR0YWNobWVudCcpfHwoZm4mJiFwY3Quc3RhcnRzV2l0aCgndGV4dC8nKSkpew0KICAgICAgICBjb25zdCBlbmM9KChwaC5tYXRjaCgvQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzpccyooW15cclxuXSspL2kpfHxbXSlbMV18fCcnKS50cmltKCkudG9Mb3dlckNhc2UoKTsNCiAgICAgICAgY29sbGVjdGVkLnB1c2goe2ZuLGVuYyxib2R5OnBifSk7DQogICAgICB9DQogICAgfQ0KICB9DQogIGNvbGxlY3RQYXJ0cyhyYXcpOw0KICAvLyBDaGVyY2hlciBkJ2Fib3JkIHBhciBpbmRleCwgcHVpcyBwYXIgbm9tDQogIGNvbnN0IGJ5SWR4PWNvbGxlY3RlZFt0YXJnZXRJZHhdOw0KICBjb25zdCBieU5hbWU9dGFyZ2V0RmlsZW5hbWU/Y29sbGVjdGVkLmZpbmQoYT0+YS5mbiYmYS5mbi50b0xvd2VyQ2FzZSgpPT09dGFyZ2V0RmlsZW5hbWUudG9Mb3dlckNhc2UoKSk6bnVsbDsNCiAgY29uc3QgYXR0PWJ5SWR4fHxieU5hbWV8fGNvbGxlY3RlZFswXTsNCiAgaWYoIWF0dClyZXR1cm4gbnVsbDsNCiAgaWYoYXR0LmVuYz09PSdiYXNlNjQnKXJldHVybiBCdWZmZXIuZnJvbShhdHQuYm9keS5yZXBsYWNlKC9bXHJcblxzXS9nLCcnKSwnYmFzZTY0Jyk7DQogIHJldHVybiBCdWZmZXIuZnJvbShhdHQuYm9keSwnbGF0aW4xJyk7DQp9DQoNCi8vIOKUgOKUgCBIZWxwZXJzIE1JTUUgOiBkw6ljb2RhZ2Ugcm9idXN0ZSAoYmFzZTY0LCBRUCwgY2hhcnNldCkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQpmdW5jdGlvbiBkZWNvZGVNaW1lUGFydChkYXRhLGVuYyxjaGFyc2V0KXsNCiAgbGV0IG91dD1kYXRhO2NvbnN0IGU9KGVuY3x8JycpLnRvTG93ZXJDYXNlKCkudHJpbSgpOw0KICBjb25zdCBjcz0oY2hhcnNldHx8J3V0Zi04JykudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bXmEtejAtOV0vZywnJyk7DQogIGNvbnN0IGlzTGF0aW49L2xhdGlufGlzbzg4NTl8d2luZG93czEyNXxjcDEyNS8udGVzdChjcyk7DQogIGlmKGU9PT0nYmFzZTY0Jyl7DQogICAgdHJ5e2NvbnN0IGJ1Zj1CdWZmZXIuZnJvbShkYXRhLnJlcGxhY2UoL1tcclxuXHNdL2csJycpLCdiYXNlNjQnKTtvdXQ9YnVmLnRvU3RyaW5nKGlzTGF0aW4/J2xhdGluMSc6J3V0ZjgnKTt9Y2F0Y2h7b3V0PWRhdGE7fQ0KICB9IGVsc2UgaWYoZT09PSdxdW90ZWQtcHJpbnRhYmxlJyl7DQogICAgLy8gPVhYIOKGkiBjb2RlcG9pbnQgdW5pY29kZSBkaXJlY3QgKGxhdGluMSBJUyB1bmljb2RlIDAtMjU1LCBwYXMgZGUgZG91YmxlIGNvbnZlcnNpb24pDQogICAgb3V0PWRhdGEucmVwbGFjZSgvPVxyP1xuL2csJycpLnJlcGxhY2UoLz0oWzAtOUEtRmEtZl17Mn0pL2csKF8saCk9PlN0cmluZy5mcm9tQ2hhckNvZGUocGFyc2VJbnQoaCwxNikpKTsNCiAgfQ0KICByZXR1cm4gb3V0Ow0KfQ0KLy8gRMOpY29kZSBsZXMgZW5jb2RlZC13b3JkcyBNSU1FID0/Y2hhcnNldD9CL1E/dGV4dD89IGRhbnMgbGVzIGhlYWRlcnMNCmZ1bmN0aW9uIGRlY29kZU1pbWVXb3JkcyhzdHIpew0KICBpZighc3RyfHwhc3RyLmluY2x1ZGVzKCc9PycpKXJldHVybiBzdHI7DQogIC8vIFJGQyAyMDQ3IDogc3VwcHJpbWVyIGxlIGJsYW5jIGVudHJlIGRldXggZW5jb2RlZC13b3JkcyBhZGphY2VudHMNCiAgY29uc3QgTT0nXHgwMSc7DQogIGxldCBzPXN0ci5yZXBsYWNlKC8oPVw/W14/XStcP1tCUWJxXVw/W14/XSpcPz0pXHMrKD1cPykvZywnJDEnK00rJyQyJyk7DQogIHM9cy5yZXBsYWNlKC89XD8oW14/XSspXD8oW0JRYnFdKVw/KFteP10qKVw/PS9nLChfLGNzLGVuYyx0ZXh0KT0+ew0KICAgIGNvbnN0IGlzTGF0aW49L2xhdGlufGlzby4/ODg1OXx3aW5kb3dzLj8xMjV8Y3AuPzEyNS9pLnRlc3QoY3MpOw0KICAgIHRyeXsNCiAgICAgIGlmKGVuYy50b1VwcGVyQ2FzZSgpPT09J0InKXsNCiAgICAgICAgY29uc3QgYnVmPUJ1ZmZlci5mcm9tKHRleHQucmVwbGFjZSgvXHMvZywnJyksJ2Jhc2U2NCcpOw0KICAgICAgICByZXR1cm4gYnVmLnRvU3RyaW5nKGlzTGF0aW4/J2xhdGluMSc6J3V0ZjgnKTsNCiAgICAgIH0gZWxzZSB7DQogICAgICAgIHJldHVybiB0ZXh0LnJlcGxhY2UoL18vZywnICcpLnJlcGxhY2UoLz0oWzAtOUEtRmEtZl17Mn0pL2csKF8saCk9PlN0cmluZy5mcm9tQ2hhckNvZGUocGFyc2VJbnQoaCwxNikpKTsNCiAgICAgIH0NCiAgICB9Y2F0Y2h7cmV0dXJuIHRleHQ7fQ0KICB9KTsNCiAgcmV0dXJuIHMucmVwbGFjZSgvXHgwMS9nLCcnKTsNCn0NCmZ1bmN0aW9uIHBhcnNlRW1haWxNaW1lKHJhdyl7DQogIGNvbnN0IGJkTT1yYXcubWF0Y2goL2JvdW5kYXJ5PSI/KFteIlxyXG47XSspIj8vaSk7DQogIC8vIFNpIHVuIGJvdW5kYXJ5IGVzdCBwcsOpc2VudCwgdG91am91cnMgZXNzYXllciBsZSBwYXJzaW5nIG11bHRpcGFydCAobcOqbWUgc2FucyBDb250ZW50LVR5cGU6IG11bHRpcGFydC8pDQogIGlmKGJkTSl7DQogICAgY29uc3QgYmQ9YmRNWzFdLnRyaW0oKTsNCiAgICBjb25zdCBwYXJ0cz1yYXcuc3BsaXQoJy0tJytiZCk7DQogICAgbGV0IGh0bWw9bnVsbCx0ZXh0PScnOw0KICAgIGZvcihsZXQgaT0xO2k8cGFydHMubGVuZ3RoO2krKyl7DQogICAgICBjb25zdCBwPXBhcnRzW2ldO2lmKHAuc3RhcnRzV2l0aCgnLS0nKXx8IXAudHJpbSgpKWNvbnRpbnVlOw0KICAgICAgY29uc3Qgc2VwPXAuaW5kZXhPZignXHJcblxyXG4nKSE9PS0xP3AuaW5kZXhPZignXHJcblxyXG4nKTpwLmluZGV4T2YoJ1xuXG4nKTtpZihzZXA9PT0tMSljb250aW51ZTsNCiAgICAgIGNvbnN0IHBoPXAuc2xpY2UoMCxzZXApLHBiPXAuc2xpY2Uoc2VwKyhwLmluZGV4T2YoJ1xyXG5cclxuJykhPT0tMT80OjIpKTsNCiAgICAgIGNvbnN0IHBjdD0oKHBoLm1hdGNoKC9Db250ZW50LVR5cGU6XHMqKFteO1xyXG5dKykvaSl8fFtdKVsxXXx8JycpLnRyaW0oKS50b0xvd2VyQ2FzZSgpOw0KICAgICAgY29uc3QgcGVuYz0oKHBoLm1hdGNoKC9Db250ZW50LVRyYW5zZmVyLUVuY29kaW5nOlxzKihbXlxyXG5dKykvaSl8fFtdKVsxXXx8JycpLnRyaW0oKTsNCiAgICAgIGNvbnN0IHBjcz0oKHBoLm1hdGNoKC9jaGFyc2V0PSI/KFteIlxzO10rKSI/L2kpfHxbXSlbMV18fCd1dGYtOCcpOw0KICAgICAgaWYocGN0LnN0YXJ0c1dpdGgoJ211bHRpcGFydC8nKXx8KCFwY3QmJnBoLm1hdGNoKC9ib3VuZGFyeT0vaSkpKXtjb25zdCBuPXBhcnNlRW1haWxNaW1lKHBoKydcclxuXHJcbicrcGIpO2lmKG4uaHRtbCYmIWh0bWwpaHRtbD1uLmh0bWw7aWYobi50ZXh0JiYhdGV4dCl0ZXh0PW4udGV4dDt9DQogICAgICBlbHNlIGlmKHBjdD09PSd0ZXh0L2h0bWwnJiYhaHRtbCl7aHRtbD1kZWNvZGVNaW1lUGFydChwYixwZW5jLHBjcyk7fQ0KICAgICAgZWxzZSBpZihwY3Q9PT0ndGV4dC9wbGFpbicmJiF0ZXh0KXt0ZXh0PWRlY29kZU1pbWVQYXJ0KHBiLHBlbmMscGNzKTt9DQogICAgfQ0KICAgIGlmKGh0bWx8fHRleHQpcmV0dXJue2h0bWwsdGV4dH07DQogICAgLy8gRmFsbGJhY2sgc2kgYXVjdW5lIHBhcnRpZSB0cm91dsOpZSAoYm91bmRhcnkgbWFpcyBwYXMgZGUgcGFydHMgdmFsaWRlcykNCiAgfQ0KICBjb25zdCBoRW5kPXJhdy5pbmRleE9mKCdcclxuXHJcbicpIT09LTE/cmF3LmluZGV4T2YoJ1xyXG5cclxuJyk6cmF3LmluZGV4T2YoJ1xuXG4nKTsNCiAgY29uc3QgaGRyPWhFbmQ+MD9yYXcuc2xpY2UoMCxoRW5kKTonJztjb25zdCBib2R5PWhFbmQ+MD9yYXcuc2xpY2UoaEVuZCs0KTpyYXc7DQogIGNvbnN0IGVuYz0oKGhkci5tYXRjaCgvQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzpccyooW15cclxuXSspL2kpfHxbXSlbMV18fCcnKS50cmltKCk7DQogIGNvbnN0IGNzPSgoaGRyLm1hdGNoKC9jaGFyc2V0PSI/KFteIlxzO10rKSI/L2kpfHxbXSlbMV18fCd1dGYtOCcpOw0KICBjb25zdCBpc0h0bWw9L0NvbnRlbnQtVHlwZTpccyp0ZXh0XC9odG1sL2kudGVzdChoZHIpOw0KICBjb25zdCBkZWM9ZGVjb2RlTWltZVBhcnQoYm9keSxlbmMsY3MpOw0KICByZXR1cm57aHRtbDppc0h0bWw/ZGVjOm51bGwsdGV4dDppc0h0bWw/bnVsbDpkZWN9Ow0KfQ0KDQovLyDilIDilIAgRW1haWwgOiBsaXN0ZSBkZXMgYm/DrnRlcyBtYWlsIChhcmJvcmVzY2VuY2UgcGFyIGNvbXB0ZSBpbXBvcnTDqSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQpyb3V0ZXNbJ0dFVCAvdjEvZW1haWxzL21haWxib3hlcyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQXV0aChyZXEscmVzKSlyZXR1cm47DQogIHRyeXsNCiAgICAvLyBVdGlsaXNlciBsYSB0YWJsZSBpbXBvcnQgcG91ciBvYnRlbmlyIGxlcyB2cmFpcyBjb21wdGVzIGNvbmZpZ3Vyw6lzDQogICAgY29uc3Qgc291cmNlcz1kYlJvd3MoJ1NFTEVDVCBpZCx1c2VybmFtZSBGUk9NIGltcG9ydCBPUkRFUiBCWSBpZCcpOw0KICAgIGNvbnN0IG1haWxib3hlcz1bXTsNCiAgICBmb3IoY29uc3QgW3NyY0lkLHVzZXJuYW1lXSBvZiBzb3VyY2VzKXsNCiAgICAgIGlmKCF1c2VybmFtZXx8dXNlcm5hbWU9PT0nTlVMTCcpY29udGludWU7DQogICAgICBjb25zdCB1PWVzYyh1c2VybmFtZSk7DQogICAgICBjb25zdCByZWN2PXBhcnNlSW50KChkYlJvd3MoYFNFTEVDVCBDT1VOVChESVNUSU5DVCBtLmlkKSBGUk9NIG1ldGFkYXRhIG0gSk9JTiByY3B0IHIgT04gci5pZD1tLmlkIFdIRVJFIG0uZGVsZXRlZD0wIEFORCBtLmRpcmVjdGlvbj0wIEFORCBtLnNwYW09MCBBTkQgci50byBMSUtFICclJHt1fSUnYClbMF18fFtdKVswXSl8fDA7DQogICAgICBjb25zdCBzZW50PXBhcnNlSW50KChkYlJvd3MoYFNFTEVDVCBDT1VOVChESVNUSU5DVCBtLmlkKSBGUk9NIG1ldGFkYXRhIG0gV0hFUkUgbS5kZWxldGVkPTAgQU5EIG0uZGlyZWN0aW9uPTEgQU5EIG0uXGBmcm9tXGAgTElLRSAnJSR7dX0lJ2ApWzBdfHxbXSlbMF0pfHwwOw0KICAgICAgY29uc3Qgc3BhbT1wYXJzZUludCgoZGJSb3dzKGBTRUxFQ1QgQ09VTlQoRElTVElOQ1QgbS5pZCkgRlJPTSBtZXRhZGF0YSBtIEpPSU4gcmNwdCByIE9OIHIuaWQ9bS5pZCBXSEVSRSBtLmRlbGV0ZWQ9MCBBTkQgbS5zcGFtPTEgQU5EIHIudG8gTElLRSAnJSR7dX0lJ2ApWzBdfHxbXSlbMF0pfHwwOw0KICAgICAgbGV0IGZvbGRlcnM9W107DQogICAgICB0cnl7Y29uc3QgZnI9ZGJSb3dzKGBTRUxFQ1QgZm9sZGVyX25hbWUsZW1haWxfY291bnQgRlJPTSByYl9pbWFwX2ZvbGRlcnMgV0hFUkUgc291cmNlX2lkPSR7cGFyc2VJbnQoc3JjSWQpfSBPUkRFUiBCWSBlbWFpbF9jb3VudCBERVNDYCk7Zm9sZGVycz1mci5tYXAoKFtuLGNdKT0+KHtuYW1lOm4sY291bnQ6cGFyc2VJbnQoYyl8fDB9KSk7fWNhdGNoe30NCiAgICAgIGNvbnN0IHRvdGFsPXJlY3Yrc2VudCtzcGFtOw0KICAgICAgaWYodG90YWw+MCkgbWFpbGJveGVzLnB1c2goe2FkZHJlc3M6dXNlcm5hbWUsdG90YWwscmVjZWl2ZWQ6cmVjdixzZW50LHNwYW0sZm9sZGVyc30pOw0KICAgIH0NCiAgICBqc29uKHJlcyx7bWFpbGJveGVzfSk7DQogIH1jYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0KDQovLyDilIDilIAgRW1haWwgOiBjb3JwcyArIHBpw6hjZXMgam9pbnRlcyArIHJhdyBFTUwgKyByZW52b2kg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQpyb3V0ZXNbJ0dFVCAvdjEvZW1haWxzLzppZC9ib2R5J109YXN5bmMocmVxLHJlcyx7aWR9KT0+ew0KICBpZighcmVxdWlyZUF1dGgocmVxLHJlcykpcmV0dXJuOw0KICBjb25zdCB6bGliPXJlcXVpcmUoJ3psaWInKTsNCiAgdHJ5IHsNCiAgICBjb25zdCByb3dzPWRiUm93cyhgU0VMRUNUIG0uaWQsbS5waWxlcl9pZCxtLlxgZnJvbVxgLG0uc3ViamVjdCxJRihwLm1ldGFkYXRhX2lkIElTIE5PVCBOVUxMLDEsMCkgRlJPTSBtZXRhZGF0YSBtIExFRlQgSk9JTiByYl9wcm90ZWN0ZWQgcCBPTiBwLm1ldGFkYXRhX2lkPW0uaWQgV0hFUkUgbS5pZD0nJHtlc2MoaWQpfScgQU5EIG0uZGVsZXRlZD0wIExJTUlUIDFgKTsNCiAgICBpZighcm93cy5sZW5ndGh8fCFyb3dzWzBdWzBdKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRW1haWwgaW50cm91dmFibGUnfSw0MDQpOw0KICAgIGNvbnN0IHBpbGVySWQ9cm93c1swXVsxXXx8cm93c1swXVswXTsNCiAgICBjb25zdCBpc1Byb3RlY3RlZD1yb3dzWzBdWzRdPT09JzEnOw0KDQogICAgY29uc3Qgcmc9c3Bhd25TeW5jKCdkb2NrZXInLFsnZXhlYycsUElMRVJfTkFNRSwncGlsZXJnZXQnLFN0cmluZyhwaWxlcklkKV0sDQogICAgICB7ZW5jb2Rpbmc6J2J1ZmZlcicsdGltZW91dDoxNTAwMCxtYXhCdWZmZXI6MjAqMTAyNCoxMDI0fSk7DQogICAgbGV0IHJhdz0nJzsNCiAgICBpZihyZy5zdGF0dXM9PT0wJiZyZy5zdGRvdXQmJnJnLnN0ZG91dC5sZW5ndGg+MCl7DQogICAgICBpZihyZy5zdGRvdXRbMF09PT0weDFmJiZyZy5zdGRvdXRbMV09PT0weDhiKXsNCiAgICAgICAgdHJ5e3Jhdz16bGliLmd1bnppcFN5bmMocmcuc3Rkb3V0KS50b1N0cmluZygndXRmOCcpO31jYXRjaHtyYXc9cmcuc3Rkb3V0LnRvU3RyaW5nKCdsYXRpbjEnKTt9DQogICAgICB9IGVsc2Ugew0KICAgICAgICAvLyBFc3NheWVyIHV0ZjgsIGZhbGxiYWNrIGxhdGluMSBzaSBjYXJhY3TDqHJlcyBpbnZhbGlkZXMNCiAgICAgICAgdHJ5e3Jhdz1yZy5zdGRvdXQudG9TdHJpbmcoJ3V0ZjgnKTtpZihyYXcuaW5jbHVkZXMoJ1x1RkZGRCcpKXJhdz1yZy5zdGRvdXQudG9TdHJpbmcoJ2xhdGluMScpO30NCiAgICAgICAgY2F0Y2h7cmF3PXJnLnN0ZG91dC50b1N0cmluZygnbGF0aW4xJyk7fQ0KICAgICAgfQ0KICAgIH0NCiAgICBpZighcmF3KXsNCiAgICAgIGNvbnN0IHJmPXNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLFBJTEVSX05BTUUsJ2ZpbmQnLCcvdmFyL3BpbGVyJywnLW5hbWUnLGAqJHtTdHJpbmcocGlsZXJJZCkuc2xpY2UoLTgpfSpgLCctdHlwZScsJ2YnXSx7ZW5jb2Rpbmc6J3V0ZjgnLHRpbWVvdXQ6NTAwMH0pOw0KICAgICAgY29uc3QgZmlsZXM9KHJmLnN0ZG91dHx8JycpLnRyaW0oKS5zcGxpdCgnXG4nKS5maWx0ZXIoQm9vbGVhbik7DQogICAgICBpZihmaWxlcy5sZW5ndGgpew0KICAgICAgICBjb25zdCBjYXRSPXNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLFBJTEVSX05BTUUsJ2NhdCcsZmlsZXNbMF1dLHtlbmNvZGluZzonYnVmZmVyJyx0aW1lb3V0OjgwMDAsbWF4QnVmZmVyOjEwKjEwMjQqMTAyNH0pOw0KICAgICAgICBpZihjYXRSLnN0ZG91dCl7DQogICAgICAgICAgaWYoY2F0Ui5zdGRvdXRbMF09PT0weDFmJiZjYXRSLnN0ZG91dFsxXT09PTB4OGIpe3RyeXtyYXc9emxpYi5ndW56aXBTeW5jKGNhdFIuc3Rkb3V0KS50b1N0cmluZygndXRmOCcpO31jYXRjaHtyYXc9Y2F0Ui5zdGRvdXQudG9TdHJpbmcoJ2xhdGluMScpO319DQogICAgICAgICAgZWxzZXtyYXc9Y2F0Ui5zdGRvdXQudG9TdHJpbmcoJ3V0ZjgnKTt9DQogICAgICAgIH0NCiAgICAgIH0NCiAgICB9DQogICAgaWYoIXJhdykgcmV0dXJuIGpzb24ocmVzLHt0ZXh0OicoQ29ycHMgaW5kaXNwb25pYmxlKScsaHRtbDpudWxsLGhlYWRlcnM6e319KTsNCg0KICAgIC8vIEhlYWRlcnMgZ2xvYmF1eCAoYXZlYyBnZXN0aW9uIGR1IGZvbGRpbmcgbXVsdGktbGlnbmVzKQ0KICAgIGNvbnN0IGhFbmQ9cmF3LmluZGV4T2YoJ1xyXG5cclxuJykhPT0tMT9yYXcuaW5kZXhPZignXHJcblxyXG4nKTpyYXcuaW5kZXhPZignXG5cbicpOw0KICAgIGNvbnN0IGhlYWRlclN0cj1oRW5kPjA/cmF3LnNsaWNlKDAsaEVuZCk6Jyc7DQogICAgY29uc3QgaGRycz17fTsNCiAgICBoZWFkZXJTdHIucmVwbGFjZSgvXHI/XG5bIFx0XSsvZywnICcpLnNwbGl0KC9ccj9cbi8pLmZvckVhY2gobD0+ew0KICAgICAgY29uc3QgbT1sLm1hdGNoKC9eKFtcdy1dKyk6XHMqKC4rKS9pKTtpZighbSlyZXR1cm47DQogICAgICBsZXQgdmFsPW1bMl0udHJpbSgpOw0KICAgICAgLy8gU2kgcGFzIGQnZW5jb2RlZC13b3JkLCB0ZW50ZXIgcmUtZMOpY29kYWdlIGxhdGluMeKGknV0ZjggcGFyIGhlYWRlcg0KICAgICAgaWYoIXZhbC5pbmNsdWRlcygnPT8nKSl7DQogICAgICAgIHRyeXtjb25zdCB1PUJ1ZmZlci5mcm9tKHZhbCwnbGF0aW4xJykudG9TdHJpbmcoJ3V0ZjgnKTtpZighdS5pbmNsdWRlcygnXHVGRkZEJykpdmFsPXU7fWNhdGNoe30NCiAgICAgIH0NCiAgICAgIGhkcnNbbVsxXS50b0xvd2VyQ2FzZSgpXT12YWw7DQogICAgfSk7DQoNCiAgICAvLyBQYXJzaW5nIE1JTUUgcm9idXN0ZSAobXVsdGlwYXJ0LCBiYXNlNjQsIFFQLCBjaGFyc2V0KQ0KICAgIGNvbnN0e2h0bWw6aHRtbEJvZHksdGV4dDpyYXdUZXh0fT1wYXJzZUVtYWlsTWltZShyYXcpOw0KICAgIGNvbnN0IHRleHRCb2R5PShyYXdUZXh0fHwnJykucmVwbGFjZSgvPFtePl0rPi9nLCcgJykucmVwbGFjZSgvXHN7Myx9L2csJ1xuXG4nKS5zbGljZSgwLDMwMDAwKTsNCiAgICAvLyBGaXggY2hhcnNldCBtZXRhIHBvdXIgcmVuZHUgY29ycmVjdCBkYW5zIGlmcmFtZSBzcmNEb2MgKGxlIGNvbnRlbnUgZXN0IGTDqWrDoCB1dGYtMTYgSlMpDQogICAgbGV0IGh0bWxPdXQ9aHRtbEJvZHl8fG51bGw7DQogICAgaWYoaHRtbE91dCkgaHRtbE91dD1odG1sT3V0LnJlcGxhY2UoLzxtZXRhW14+XSpjaGFyc2V0W14+XSo+L2dpLCc8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+Jyk7DQoNCiAgICAvLyBEw6ljb2RlciBsZXMgZW5jb2RlZC13b3JkcyBNSU1FIGRhbnMgbGVzIGhlYWRlcnMgKD0/VVRGLTg/Qj8uLi4/PSBldGMuKQ0KICAgIGNvbnN0IHN1YmplY3Q9ZGVjb2RlTWltZVdvcmRzKGhkcnMuc3ViamVjdHx8JycpOw0KICAgIGNvbnN0IGZyb209ZGVjb2RlTWltZVdvcmRzKGhkcnMuZnJvbXx8JycpOw0KICAgIGNvbnN0IHRvPWRlY29kZU1pbWVXb3JkcyhoZHJzLnRvfHwnJyk7DQogICAganNvbihyZXMse2h0bWw6aHRtbE91dCx0ZXh0OnRleHRCb2R5fHwnJyxoZWFkZXJzOmhkcnMsZnJvbSx0byxzdWJqZWN0LGRhdGU6aGRycy5kYXRlfHwnJyxwcm90ZWN0ZWQ6aXNQcm90ZWN0ZWR9KTsNCiAgfSBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0KDQovLyDilIDilIAgRW1haWwgOiBzeW5jaHJvbmlzYXRpb24gdmVycyBJTUFQIChyZXN0YXVyYXRpb24pIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgA0Kcm91dGVzWydQT1NUIC92MS9lbWFpbHMvc3luYyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQXV0aChyZXEscmVzKSlyZXR1cm47DQogIHRyeXsNCiAgICBjb25zdCBib2R5PUpTT04ucGFyc2UoYXdhaXQgbmV3IFByb21pc2Uocj0+e2NvbnN0IGM9W107cmVxLm9uKCdkYXRhJyxkPT5jLnB1c2goZCkpO3JlcS5vbignZW5kJywoKT0+cihCdWZmZXIuY29uY2F0KGMpLnRvU3RyaW5nKCkpKTt9KSk7DQogICAgbGV0e2VtYWlsX2lkcyxpbWFwX2hvc3QsaW1hcF91c2VyLGltYXBfcGFzcyxpbWFwX2ZvbGRlcj0nSU5CT1gnLGltYXBfc3NsPXRydWUsZGVzdGluYXRpb25faWQsc2F2ZV9kZXN0aW5hdGlvbj1mYWxzZSxkZXN0aW5hdGlvbl9sYWJlbD0nJ309Ym9keTsNCiAgICBpZighZW1haWxfaWRzPy5sZW5ndGgpcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J2VtYWlsX2lkcyByZXF1aXMnfSw0MDApOw0KICAgIC8vIENoYXJnZXIgZGVwdWlzIGRlc3RpbmF0aW9uIHNhdXZlZ2FyZMOpZSBzaSBkZXN0aW5hdGlvbl9pZCBmb3VybmkNCiAgICBpZihkZXN0aW5hdGlvbl9pZCl7DQogICAgICBjb25zdCBkcm93PWRiUm93cyhgU0VMRUNUIGltYXBfaG9zdCxpbWFwX3VzZXIsaW1hcF9wYXNzLGltYXBfZm9sZGVyLGltYXBfc3NsIEZST00gc3luY19kZXN0aW5hdGlvbnMgV0hFUkUgaWQ9JyR7ZXNjKFN0cmluZyhkZXN0aW5hdGlvbl9pZCkpfScgTElNSVQgMWApOw0KICAgICAgaWYoIWRyb3cubGVuZ3RofHwhZHJvd1swXVswXSlyZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRGVzdGluYXRpb24gaW50cm91dmFibGUnfSw0MDQpOw0KICAgICAgW2ltYXBfaG9zdCxpbWFwX3VzZXIsaW1hcF9wYXNzLGltYXBfZm9sZGVyLGltYXBfc3NsXT1bZHJvd1swXVswXSxkcm93WzBdWzFdLGRyb3dbMF1bMl0sZHJvd1swXVszXXx8J0lOQk9YJyxkcm93WzBdWzRdPT09JzEnXTsNCiAgICAgIC8vIE1ldHRyZSDDoCBqb3VyIGxhc3RfdXNlZF9hdA0KICAgICAgdHJ5e2RiUXVlcnkoYFVQREFURSBzeW5jX2Rlc3RpbmF0aW9ucyBTRVQgbGFzdF91c2VkX2F0PU5PVygpIFdIRVJFIGlkPScke2VzYyhTdHJpbmcoZGVzdGluYXRpb25faWQpKX0nYCk7fWNhdGNoe30NCiAgICB9DQogICAgaWYoIWltYXBfaG9zdHx8IWltYXBfdXNlcnx8IWltYXBfcGFzcylyZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonUGFyYW3DqHRyZXMgSU1BUCByZXF1aXMnfSw0MDApOw0KICAgIGNvbnN0IGlkcz1lbWFpbF9pZHMuc2xpY2UoMCw1MDApLm1hcCh4PT5wYXJzZUludCh4KSkuZmlsdGVyKG49Pm4+MCk7DQogICAgLy8gUsOpc291ZHJlIGxlcyBwaWxlcl9pZCAoaGFzaCkgZGVwdWlzIGxlcyBJRHMgZW50aWVycyDigJQgcGlsZXJnZXQgZXhpZ2UgbGUgaGFzaA0KICAgIGNvbnN0IHBpbGVySWRzPWlkcy5mbGF0TWFwKGlkPT57DQogICAgICBjb25zdCByb3dzPWRiUm93cyhgU0VMRUNUIHBpbGVyX2lkIEZST00gbWV0YWRhdGEgV0hFUkUgaWQ9JyR7ZXNjKFN0cmluZyhpZCkpfScgQU5EIGRlbGV0ZWQ9MCBMSU1JVCAxYCk7DQogICAgICByZXR1cm4gKHJvd3MubGVuZ3RoJiZyb3dzWzBdWzBdKT9bU3RyaW5nKHJvd3NbMF1bMF0pXTpbXTsNCiAgICB9KTsNCiAgICBpZighcGlsZXJJZHMubGVuZ3RoKXJldHVybiBqc29uKHJlcyx7b2s6MCxlcnJvcnM6aWRzLmxlbmd0aCx0b3RhbDppZHMubGVuZ3RoLGVycl9kZXRhaWw6J0VtYWlsKHMpIGludHJvdXZhYmxlKHMpIGRhbnMgbFwnaW5kZXggTWFpbHBpbGVyIChwaWxlcl9pZCBtYW5xdWFudCDigJQgZW1haWwgc3VwcHJpbcOpIG91IG5vbiBpbmRleMOpKSd9KTsNCiAgICBjb25zdCBob3N0UGFydD1pbWFwX2hvc3QuaW5jbHVkZXMoJzonKT9pbWFwX2hvc3Quc3BsaXQoJzonKVswXTppbWFwX2hvc3Q7DQogICAgY29uc3QgcG9ydFBhcnQ9aW1hcF9ob3N0LmluY2x1ZGVzKCc6Jyk/cGFyc2VJbnQoaW1hcF9ob3N0LnNwbGl0KCc6JylbMV0pOmltYXBfc3NsPzk5MzoxNDM7DQogICAgY29uc3QgU0NSSVBUPWBpbXBvcnQgaW1hcGxpYixzdWJwcm9jZXNzLHNzbCxzeXMsb3MNCmhvc3QscG9ydCx1c2VyLHB3LGZvbGRlcj1zeXMuYXJndlsxXSxpbnQoc3lzLmFyZ3ZbMl0pLHN5cy5hcmd2WzNdLHN5cy5hcmd2WzRdLHN5cy5hcmd2WzVdDQpwaWxlcl9pZHM9JHtKU09OLnN0cmluZ2lmeShwaWxlcklkcyl9DQpvaz1lcnI9MA0KZXJycz1bXQ0KZGVmIHBpbGVyZ2V0KHBpZCk6DQogZm9yIGNtZCBpbiBbJy91c3IvYmluL3BpbGVyZ2V0JywncGlsZXJnZXQnXToNCiAgdHJ5Og0KICAgcj1zdWJwcm9jZXNzLnJ1bihbY21kLHBpZF0sc3Rkb3V0PXN1YnByb2Nlc3MuUElQRSxzdGRlcnI9c3VicHJvY2Vzcy5QSVBFLHRpbWVvdXQ9MTUpDQogICBpZiByLnJldHVybmNvZGU9PTAgYW5kIHIuc3Rkb3V0OiByZXR1cm4gci5zdGRvdXQNCiAgZXhjZXB0IEZpbGVOb3RGb3VuZEVycm9yOiBjb250aW51ZQ0KICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6IGVycnMuYXBwZW5kKHN0cihlKSk7IGJyZWFrDQogcmV0dXJuIE5vbmUNCnRyeToNCiBjdHg9c3NsLmNyZWF0ZV9kZWZhdWx0X2NvbnRleHQoKQ0KIGN0eC5jaGVja19ob3N0bmFtZT1GYWxzZQ0KIGN0eC52ZXJpZnlfbW9kZT1zc2wuQ0VSVF9OT05FDQogdXNlX3NzbD0ke2ltYXBfc3NsPydUcnVlJzonRmFsc2UnfQ0KIGlmIHVzZV9zc2w6DQogIE09aW1hcGxpYi5JTUFQNF9TU0woaG9zdCxwb3J0LHNzbF9jb250ZXh0PWN0eCkNCiBlbHNlOg0KICBNPWltYXBsaWIuSU1BUDQoaG9zdCxwb3J0KQ0KICB0cnk6DQogICBNLnN0YXJ0dGxzKHNzbF9jb250ZXh0PWN0eCkNCiAgZXhjZXB0IEV4Y2VwdGlvbjoNCiAgIHBhc3MNCiBNLmxvZ2luKHVzZXIscHcpDQogZm9yIHBpZCBpbiBwaWxlcl9pZHM6DQogIHRyeToNCiAgIGVtbD1waWxlcmdldChwaWQpDQogICBpZiBub3QgZW1sOiBlcnIrPTE7IGVycnMuYXBwZW5kKGYncGlsZXJnZXQgZmFpbGVkIGZvciB7cGlkfScpOyBjb250aW51ZQ0KICAgaWYgbGVuKGVtbCk+MiBhbmQgZW1sWzBdPT0weDFmIGFuZCBlbWxbMV09PTB4OGI6DQogICAgaW1wb3J0IGd6aXAgYXMgZ3o7IGVtbD1nei5kZWNvbXByZXNzKGVtbCkNCiAgIE0uYXBwZW5kKGZvbGRlcixOb25lLE5vbmUsZW1sKTsgb2srPTENCiAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOiBlcnIrPTE7IGVycnMuYXBwZW5kKHN0cihlKSkNCiBNLmxvZ291dCgpDQpleGNlcHQgRXhjZXB0aW9uIGFzIGU6DQogcmVtYWluaW5nPWxlbihwaWxlcl9pZHMpLW9rDQogaWYgcmVtYWluaW5nPjA6IGVycis9cmVtYWluaW5nDQogZXJycy5hcHBlbmQoc3RyKGUpKQ0Kc3lzLnN0ZGVyci53cml0ZSgnfCcuam9pbihlcnJzKSkNCnByaW50KGYne29rfTp7ZXJyfScpDQpgOw0KICAgIGNvbnN0IHRtcD1gL3RtcC9zeW5jXyR7RGF0ZS5ub3coKX0ucHlgOw0KICAgIHNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLCctaScsUElMRVJfTkFNRSwnc2gnLCctYycsYGNhdCA+ICR7dG1wfWBdLHtpbnB1dDpTQ1JJUFQsZW5jb2Rpbmc6J3V0ZjgnLHRpbWVvdXQ6NTAwMH0pOw0KICAgIGNvbnN0IHI9c3Bhd25TeW5jKCdkb2NrZXInLFsnZXhlYycsUElMRVJfTkFNRSwncHl0aG9uMycsdG1wLGhvc3RQYXJ0LFN0cmluZyhwb3J0UGFydCksaW1hcF91c2VyLGltYXBfcGFzcyxpbWFwX2ZvbGRlcl0se2VuY29kaW5nOid1dGY4Jyx0aW1lb3V0OjMwMDAwMH0pOw0KICAgIHNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLFBJTEVSX05BTUUsJ3JtJywnLWYnLHRtcF0pOw0KICAgIGNvbnN0W29rLGVycm9yc109KHIuc3Rkb3V0fHwnMDowJykudHJpbSgpLnNwbGl0KCc6Jyk7DQogICAgY29uc3QgZXJyRGV0YWlsPShyLnN0ZGVycnx8JycpLnRyaW0oKTsNCiAgICAvLyBTYXV2ZWdhcmRlciBsYSBkZXN0aW5hdGlvbiBzaSBkZW1hbmTDqSBldCBzeW5jIHLDqXVzc2llDQogICAgbGV0IHNhdmVkX2lkPW51bGw7DQogICAgaWYoc2F2ZV9kZXN0aW5hdGlvbiYmIWRlc3RpbmF0aW9uX2lkJiZpbWFwX2hvc3QmJmltYXBfdXNlciYmaW1hcF9wYXNzJiZwYXJzZUludChvayk+MCl7DQogICAgICB0cnl7DQogICAgICAgIGRiUXVlcnkoYElOU0VSVCBJTlRPIHN5bmNfZGVzdGluYXRpb25zIChsYWJlbCxpbWFwX2hvc3QsaW1hcF91c2VyLGltYXBfcGFzcyxpbWFwX2ZvbGRlcixpbWFwX3NzbCxsYXN0X3VzZWRfYXQpIFZBTFVFUyAoJyR7ZXNjKGRlc3RpbmF0aW9uX2xhYmVsfHxpbWFwX2hvc3QpfScsJyR7ZXNjKGltYXBfaG9zdCl9JywnJHtlc2MoaW1hcF91c2VyKX0nLCcke2VzYyhpbWFwX3Bhc3MpfScsJyR7ZXNjKGltYXBfZm9sZGVyKX0nLCR7aW1hcF9zc2w/MTowfSxOT1coKSlgKTsNCiAgICAgICAgY29uc3QgaWRSb3c9ZGJSb3dzKCdTRUxFQ1QgTEFTVF9JTlNFUlRfSUQoKScpOw0KICAgICAgICBzYXZlZF9pZD1wYXJzZUludCgoaWRSb3dbMF18fFtdKVswXSl8fG51bGw7DQogICAgICB9Y2F0Y2h7fQ0KICAgIH0NCiAgICBqc29uKHJlcyx7b2s6cGFyc2VJbnQob2spfHwwLGVycm9yczpwYXJzZUludChlcnJvcnMpfHwwLHRvdGFsOmlkcy5sZW5ndGgsc2F2ZWRfaWQsZXJyX2RldGFpbDplcnJEZXRhaWx8fHVuZGVmaW5lZH0pOw0KICB9Y2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0KLy8g4pSA4pSAIFN5bmMgOiBsaXN0ZXIgbGVzIGRvc3NpZXJzIElNQVAgZGUgZGVzdGluYXRpb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQpyb3V0ZXNbJ1BPU1QgL3YxL2VtYWlscy9zeW5jL2xpc3QtZm9sZGVycyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQXV0aChyZXEscmVzKSlyZXR1cm47DQogIHRyeXsNCiAgICBjb25zdCB7aW1hcF9ob3N0LGltYXBfdXNlcixpbWFwX3Bhc3MsaW1hcF9zc2w9dHJ1ZX09YXdhaXQgcmVhZEJvZHkocmVxKTsNCiAgICBpZighaW1hcF9ob3N0fHwhaW1hcF91c2VyfHwhaW1hcF9wYXNzKXJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidQYXJhbcOodHJlcyByZXF1aXMnfSw0MDApOw0KICAgIGNvbnN0IGhvc3RQYXJ0PWltYXBfaG9zdC5pbmNsdWRlcygnOicpP2ltYXBfaG9zdC5zcGxpdCgnOicpWzBdOmltYXBfaG9zdDsNCiAgICBjb25zdCBwb3J0UGFydD1pbWFwX2hvc3QuaW5jbHVkZXMoJzonKT9wYXJzZUludChpbWFwX2hvc3Quc3BsaXQoJzonKVsxXSk6aW1hcF9zc2w/OTkzOjE0MzsNCiAgICBjb25zdCBTQ1JJUFQ9YGltcG9ydCBpbWFwbGliLHNzbCxzeXMsanNvbixyZQ0KaG9zdCxwb3J0LHVzZXIscHc9c3lzLmFyZ3ZbMV0saW50KHN5cy5hcmd2WzJdKSxzeXMuYXJndlszXSxzeXMuYXJndls0XQ0KdXNlX3NzbD1zeXMuYXJndls1XT09JzEnDQp0cnk6DQogY3R4PXNzbC5jcmVhdGVfZGVmYXVsdF9jb250ZXh0KCkNCiBjdHguY2hlY2tfaG9zdG5hbWU9RmFsc2UNCiBjdHgudmVyaWZ5X21vZGU9c3NsLkNFUlRfTk9ORQ0KIE09aW1hcGxpYi5JTUFQNF9TU0woaG9zdCxwb3J0LHNzbF9jb250ZXh0PWN0eCkgaWYgdXNlX3NzbCBlbHNlIGltYXBsaWIuSU1BUDQoaG9zdCxwb3J0KQ0KIGlmIG5vdCB1c2Vfc3NsOg0KICB0cnk6IE0uc3RhcnR0bHMoc3NsX2NvbnRleHQ9Y3R4KQ0KICBleGNlcHQ6IHBhc3MNCiBNLmxvZ2luKHVzZXIscHcpDQogdHlwLGRhdGE9TS5saXN0KCkNCiBmb2xkZXJzPVtdDQogZm9yIGl0ZW0gaW4gKGRhdGEgb3IgW10pOg0KICBpZiBpdGVtIGlzIE5vbmU6IGNvbnRpbnVlDQogIHM9aXRlbS5kZWNvZGUoJ3V0Zi04JywncmVwbGFjZScpIGlmIGlzaW5zdGFuY2UoaXRlbSxieXRlcykgZWxzZSBzdHIoaXRlbSkNCiAgbT1yZS5zZWFyY2gociciWy4vXFxcXF0iICg/OiIoLispInwoW14gXSspKSQnLHMpDQogIGlmIG06IGZvbGRlcnMuYXBwZW5kKChtLmdyb3VwKDEpIG9yIG0uZ3JvdXAoMikpLnN0cmlwKCciJykpDQogTS5sb2dvdXQoKQ0KIHByaW50KGpzb24uZHVtcHMoeydvayc6VHJ1ZSwnZm9sZGVycyc6c29ydGVkKGZvbGRlcnMpfSkpDQpleGNlcHQgRXhjZXB0aW9uIGFzIGU6DQogcHJpbnQoanNvbi5kdW1wcyh7J29rJzpGYWxzZSwnZXJyb3InOnN0cihlKX0pKQ0KYDsNCiAgICBjb25zdCB0bXA9YC90bXAvbGZfJHtEYXRlLm5vdygpfS5weWA7DQogICAgc3Bhd25TeW5jKCdkb2NrZXInLFsnZXhlYycsJy1pJyxQSUxFUl9OQU1FLCdzaCcsJy1jJyxgY2F0ID4gJHt0bXB9YF0se2lucHV0OlNDUklQVCxlbmNvZGluZzondXRmOCcsdGltZW91dDo1MDAwfSk7DQogICAgY29uc3Qgcj1zcGF3blN5bmMoJ2RvY2tlcicsWydleGVjJyxQSUxFUl9OQU1FLCdweXRob24zJyx0bXAsaG9zdFBhcnQsU3RyaW5nKHBvcnRQYXJ0KSxpbWFwX3VzZXIsaW1hcF9wYXNzLGltYXBfc3NsPycxJzonMCddLHtlbmNvZGluZzondXRmOCcsdGltZW91dDoyMDAwMH0pOw0KICAgIHNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLFBJTEVSX05BTUUsJ3JtJywnLWYnLHRtcF0pOw0KICAgIHRyeXsgY29uc3QgZD1KU09OLnBhcnNlKHIuc3Rkb3V0fHwne30nKTsganNvbihyZXMsZCk7IH0NCiAgICBjYXRjaHsganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTpyLnN0ZGVycnx8ci5zdGRvdXR8fCdFcnJldXIgaW5jb25udWUnfSw1MDApOyB9DQogIH1jYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0KDQovLyDilIDilIAgU3luYyBkZXN0aW5hdGlvbnMgKHNhdXZlZ2FyZGUgSU1BUCBwb3VyIHJlc3RhdXJhdGlvbiByYXBpZGUpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgA0Kcm91dGVzWydHRVQgL3YxL3N5bmMtZGVzdGluYXRpb25zJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBdXRoKHJlcSxyZXMpKXJldHVybjsNCiAgdHJ5ew0KICAgIGNvbnN0IHJvd3M9ZGJSb3dzKCdTRUxFQ1QgaWQsbGFiZWwsaW1hcF9ob3N0LGltYXBfdXNlcixpbWFwX2ZvbGRlcixpbWFwX3NzbCxsYXN0X3VzZWRfYXQsY3JlYXRlZF9hdCBGUk9NIHN5bmNfZGVzdGluYXRpb25zIE9SREVSIEJZIGxhc3RfdXNlZF9hdCBERVNDLCBpZCBERVNDJyk7DQogICAgY29uc3QgZGVzdHM9cm93cy5maWx0ZXIocj0+clswXSYmclswXSE9PScnKS5tYXAocj0+KHtpZDpwYXJzZUludChyWzBdKSxsYWJlbDpyWzFdfHwnJyxpbWFwX2hvc3Q6clsyXXx8JycsaW1hcF91c2VyOnJbM118fCcnLGltYXBfZm9sZGVyOnJbNF18fCdJTkJPWCcsaW1hcF9zc2w6cls1XT09PScxJ3x8cls1XT09PScxJyxsYXN0X3VzZWRfYXQ6cls2XSYmcls2XSE9PSdOVUxMJz9yWzZdOm51bGx9KSk7DQogICAganNvbihyZXMse2Rlc3RpbmF0aW9uczpkZXN0c30pOw0KICB9Y2F0Y2goZSl7anNvbihyZXMse2Rlc3RpbmF0aW9uczpbXSxlcnJvcjplLm1lc3NhZ2V9KTt9DQp9Ow0KDQpyb3V0ZXNbJ1BPU1QgL3YxL3N5bmMtZGVzdGluYXRpb25zJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBdXRoKHJlcSxyZXMpKXJldHVybjsNCiAgdHJ5ew0KICAgIGNvbnN0IGJvZHk9SlNPTi5wYXJzZShhd2FpdCBuZXcgUHJvbWlzZShyPT57Y29uc3QgYz1bXTtyZXEub24oJ2RhdGEnLGQ9PmMucHVzaChkKSk7cmVxLm9uKCdlbmQnLCgpPT5yKEJ1ZmZlci5jb25jYXQoYykudG9TdHJpbmcoKSkpO30pKTsNCiAgICBjb25zdHtsYWJlbD0nJyxpbWFwX2hvc3QsaW1hcF91c2VyLGltYXBfcGFzcyxpbWFwX2ZvbGRlcj0nSU5CT1gnLGltYXBfc3NsPXRydWV9PWJvZHk7DQogICAgaWYoIWltYXBfaG9zdHx8IWltYXBfdXNlcnx8IWltYXBfcGFzcylyZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonUGFyYW3DqHRyZXMgSU1BUCByZXF1aXMnfSw0MDApOw0KICAgIGRiUXVlcnkoYElOU0VSVCBJTlRPIHN5bmNfZGVzdGluYXRpb25zIChsYWJlbCxpbWFwX2hvc3QsaW1hcF91c2VyLGltYXBfcGFzcyxpbWFwX2ZvbGRlcixpbWFwX3NzbCkgVkFMVUVTICgnJHtlc2MobGFiZWwpfScsJyR7ZXNjKGltYXBfaG9zdCl9JywnJHtlc2MoaW1hcF91c2VyKX0nLCcke2VzYyhpbWFwX3Bhc3MpfScsJyR7ZXNjKGltYXBfZm9sZGVyKX0nLCR7aW1hcF9zc2w/MTowfSlgKTsNCiAgICBjb25zdCBpZFJvdz1kYlJvd3MoJ1NFTEVDVCBMQVNUX0lOU0VSVF9JRCgpJyk7DQogICAganNvbihyZXMse29rOnRydWUsaWQ6cGFyc2VJbnQoKGlkUm93WzBdfHxbXSlbMF0pfHwwfSk7DQogIH1jYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0KDQpyb3V0ZXNbJ0RFTEVURSAvdjEvc3luYy1kZXN0aW5hdGlvbnMvOmlkJ109YXN5bmMocmVxLHJlcyx7aWR9KT0+ew0KICBpZighcmVxdWlyZUF1dGgocmVxLHJlcykpcmV0dXJuOw0KICB0cnl7DQogICAgZGJRdWVyeShgREVMRVRFIEZST00gc3luY19kZXN0aW5hdGlvbnMgV0hFUkUgaWQ9JyR7ZXNjKGlkKX0nIExJTUlUIDFgKTsNCiAgICBqc29uKHJlcyx7b2s6dHJ1ZX0pOw0KICB9Y2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0Kcm91dGVzWydHRVQgL3YxL2VtYWlscy86aWQvYXR0YWNobWVudHMnXT1hc3luYyhyZXEscmVzLHtpZH0pPT57DQogIGlmKCFyZXF1aXJlQXV0aChyZXEscmVzKSlyZXR1cm47DQogIHRyeSB7DQogICAgLy8gSm9pbnR1cmUgcGFyIHBpbGVyX2lkIChwYXMgbWV0YWRhdGFfaWQpLCBjb2xvbm5lIG5hbWUgKHRpbnlibG9iLCBwYXMgZmlsZW5hbWUpDQogICAgY29uc3Qgcm93cz1kYlJvd3MoYFNFTEVDVCBhLmlkLGEubmFtZSxhLnR5cGUsYS5zaXplLGEuYXR0YWNobWVudF9pZCBGUk9NIGF0dGFjaG1lbnQgYSBKT0lOIG1ldGFkYXRhIG0gT04gbS5waWxlcl9pZD1hLnBpbGVyX2lkIFdIRVJFIG0uaWQ9JyR7ZXNjKGlkKX0nIEFORCBtLmRlbGV0ZWQ9MCBPUkRFUiBCWSBhLmF0dGFjaG1lbnRfaWRgKTsNCiAgICBjb25zdCBhdHRhY2htZW50cz1yb3dzLmZpbHRlcihyPT5yLmxlbmd0aD49MiYmclswXSkubWFwKHI9Pih7aWQ6clswXSxmaWxlbmFtZTpyWzFdfHwnYXR0YWNobWVudCcsdHlwZTpyWzJdfHwnYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtJyxzaXplOnBhcnNlSW50KHJbM10pfHwwfSkpOw0KICAgIGpzb24ocmVzLHthdHRhY2htZW50c30pOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHthdHRhY2htZW50czpbXSxlcnJvcjplLm1lc3NhZ2V9KTt9DQp9Ow0KDQpyb3V0ZXNbJ0dFVCAvdjEvZW1haWxzLzppZC9yYXcnXT1hc3luYyhyZXEscmVzLHtpZH0pPT57DQogIGNvbnN0IHU9cmVxdWlyZUF1dGgocmVxLHJlcyk7aWYoIXUpcmV0dXJuOw0KICB0cnkgew0KICAgIGNvbnN0IHJvd3M9ZGJSb3dzKGBTRUxFQ1QgaWQscGlsZXJfaWQsc3ViamVjdCBGUk9NIG1ldGFkYXRhIFdIRVJFIGlkPScke2VzYyhpZCl9JyBBTkQgZGVsZXRlZD0wIExJTUlUIDFgKTsNCiAgICBpZighcm93cy5sZW5ndGh8fCFyb3dzWzBdWzBdKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRW1haWwgaW50cm91dmFibGUnfSw0MDQpOw0KICAgIGNvbnN0IHBpbGVySWQ9cm93c1swXVsxXXx8cm93c1swXVswXTsNCiAgICBjb25zdCBzdWJqZWN0PXJvd3NbMF1bMl18fCdlbWFpbCc7DQogICAgLy8gRXNzYWkgcGlsZXJnZXQgZCdhYm9yZA0KICAgIGNvbnN0IHJnPXNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLFBJTEVSX05BTUUsJ3BpbGVyZ2V0JyxTdHJpbmcocGlsZXJJZCldLHtlbmNvZGluZzondXRmOCcsdGltZW91dDoxMDAwMCxtYXhCdWZmZXI6MjAqMTAyNCoxMDI0fSk7DQogICAgY29uc3QgZW1sRGF0YT1yZy5zdGF0dXM9PT0wJiZyZy5zdGRvdXQ/cmcuc3Rkb3V0OicnOw0KICAgIGlmKCFlbWxEYXRhKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRmljaGllciBFTUwgbm9uIGRpc3BvbmlibGUnfSw0MDQpOw0KICAgIGNvbnN0IGJ1Zj1CdWZmZXIuZnJvbShlbWxEYXRhLCd1dGY4Jyk7DQogICAgY29uc3Qgc2FmZU5hbWU9c3ViamVjdC5yZXBsYWNlKC9bXmEtejAtOVxzXS9naSwnXycpLnNsaWNlKDAsNDApKycuZW1sJzsNCiAgICByZXMud3JpdGVIZWFkKDIwMCx7J0NvbnRlbnQtVHlwZSc6J21lc3NhZ2UvcmZjODIyJywnQ29udGVudC1EaXNwb3NpdGlvbic6YGF0dGFjaG1lbnQ7IGZpbGVuYW1lPSIke3NhZmVOYW1lfSJgLCdDb250ZW50LUxlbmd0aCc6YnVmLmxlbmd0aCwnQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJzonKicsJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnOidBdXRob3JpemF0aW9uLENvbnRlbnQtVHlwZSd9KTsNCiAgICByZXMuZW5kKGJ1Zik7DQogIH0gY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0KLy8g4pSA4pSAIEVtYWlsIDogRU1MIGJydXQgZW4gYmFzZTY0IEpTT04gKHBvdXIgcG9zdGFsLW1pbWUgY8O0dMOpIGNsaWVudCkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQpyb3V0ZXNbJ0dFVCAvdjEvZW1haWxzLzppZC9lbWwnXT1hc3luYyhyZXEscmVzLHtpZH0pPT57DQogIGNvbnN0IHU9cmVxdWlyZUF1dGgocmVxLHJlcyk7aWYoIXUpcmV0dXJuOw0KICB0cnl7DQogICAgY29uc3Qgcm93cz1kYlJvd3MoYFNFTEVDVCBpZCxwaWxlcl9pZCBGUk9NIG1ldGFkYXRhIFdIRVJFIGlkPScke2VzYyhpZCl9JyBBTkQgZGVsZXRlZD0wIExJTUlUIDFgKTsNCiAgICBpZighcm93cy5sZW5ndGh8fCFyb3dzWzBdWzBdKXJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidFbWFpbCBpbnRyb3V2YWJsZSd9LDQwNCk7DQogICAgY29uc3QgcGlsZXJJZD1yb3dzWzBdWzFdfHxyb3dzWzBdWzBdOw0KICAgIGNvbnN0IHpsaWI9cmVxdWlyZSgnemxpYicpOw0KICAgIGNvbnN0IHJnPXNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLFBJTEVSX05BTUUsJ3BpbGVyZ2V0JyxTdHJpbmcocGlsZXJJZCldLHtlbmNvZGluZzonYnVmZmVyJyx0aW1lb3V0OjE1MDAwLG1heEJ1ZmZlcjozMCoxMDI0KjEwMjR9KTsNCiAgICBpZihyZy5zdGF0dXMhPT0wfHwhcmcuc3Rkb3V0fHwhcmcuc3Rkb3V0Lmxlbmd0aClyZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRU1MIG5vbiBkaXNwb25pYmxlJ30sNDA0KTsNCiAgICBsZXQgYnVmPXJnLnN0ZG91dDsNCiAgICBpZihidWZbMF09PT0weDFmJiZidWZbMV09PT0weDhiKXt0cnl7YnVmPXpsaWIuZ3VuemlwU3luYyhidWYpO31jYXRjaHt9fQ0KICAgIGpzb24ocmVzLHtpZDpwYXJzZUludChpZCksZW1sOmJ1Zi50b1N0cmluZygnYmFzZTY0Jyksc2l6ZTpidWYubGVuZ3RofSk7DQogIH1jYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0KDQpyb3V0ZXNbJ0dFVCAvdjEvZW1haWxzLzplbWFpbElkL2F0dGFjaG1lbnRzLzphdHRJZC9kb3dubG9hZCddPWFzeW5jKHJlcSxyZXMse2VtYWlsSWQsYXR0SWR9KT0+ew0KICBpZighcmVxdWlyZUF1dGgocmVxLHJlcykpcmV0dXJuOw0KICB0cnkgew0KICAgIC8vIFLDqWN1cMOpcmVyIGZpbGVuYW1lICsgbWltZSArIGluZGV4IGRlIGwnYXR0YWNobWVudCAoT1JERVIgQlkgaWQgPSBvcmRyZSBkYW5zIGwnRU1MKQ0KICAgIGNvbnN0IGFsbEF0dHM9ZGJSb3dzKGBTRUxFQ1QgaWQsZmlsZW5hbWUsdHlwZSBGUk9NIGF0dGFjaG1lbnQgV0hFUkUgbWV0YWRhdGFfaWQ9JyR7ZXNjKGVtYWlsSWQpfScgT1JERVIgQlkgaWRgKTsNCiAgICBjb25zdCBhdHRJZHg9YWxsQXR0cy5maW5kSW5kZXgocj0+U3RyaW5nKHJbMF0pPT09U3RyaW5nKGF0dElkKSk7DQogICAgaWYoYXR0SWR4PT09LTEpIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidQacOoY2Ugam9pbnRlIGludHJvdXZhYmxlJ30sNDA0KTsNCiAgICBjb25zdCBbLGZpbGVuYW1lLG1pbWVdPWFsbEF0dHNbYXR0SWR4XTsNCiAgICAvLyBSw6ljdXDDqXJlciBsZSBwaWxlcl9pZCBkZSBsJ2VtYWlsDQogICAgY29uc3QgbWV0YVJvd3M9ZGJSb3dzKGBTRUxFQ1QgcGlsZXJfaWQgRlJPTSBtZXRhZGF0YSBXSEVSRSBpZD0nJHtlc2MoZW1haWxJZCl9JyBBTkQgZGVsZXRlZD0wIExJTUlUIDFgKTsNCiAgICBpZighbWV0YVJvd3MubGVuZ3RoKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRW1haWwgaW50cm91dmFibGUnfSw0MDQpOw0KICAgIGNvbnN0IHBpbGVySWQ9bWV0YVJvd3NbMF1bMF07DQogICAgLy8gUsOpY3Vww6lyZXIgRU1MIGNvbXBsZXQNCiAgICBjb25zdCB6bGliPXJlcXVpcmUoJ3psaWInKTsNCiAgICBjb25zdCByZz1zcGF3blN5bmMoJ2RvY2tlcicsWydleGVjJyxQSUxFUl9OQU1FLCdwaWxlcmdldCcsU3RyaW5nKHBpbGVySWQpXSx7ZW5jb2Rpbmc6J2J1ZmZlcicsdGltZW91dDoxNTAwMCxtYXhCdWZmZXI6MzAqMTAyNCoxMDI0fSk7DQogICAgaWYocmcuc3RhdHVzIT09MHx8IXJnLnN0ZG91dHx8IXJnLnN0ZG91dC5sZW5ndGgpIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidFTUwgbm9uIGRpc3BvbmlibGUnfSw1MDApOw0KICAgIGxldCByYXc9Jyc7DQogICAgaWYocmcuc3Rkb3V0WzBdPT09MHgxZiYmcmcuc3Rkb3V0WzFdPT09MHg4Yil7dHJ5e3Jhdz16bGliLmd1bnppcFN5bmMocmcuc3Rkb3V0KS50b1N0cmluZygnbGF0aW4xJyk7fWNhdGNoe3Jhdz1yZy5zdGRvdXQudG9TdHJpbmcoJ2xhdGluMScpO319DQogICAgZWxzZXtyYXc9cmcuc3Rkb3V0LnRvU3RyaW5nKCdsYXRpbjEnKTt9DQogICAgLy8gRXh0cmFpcmUgbGEgcGnDqGNlIGpvaW50ZSBwYXIgaW5kZXggZGVwdWlzIGwnRU1MDQogICAgY29uc3QgYXR0RGF0YT1leHRyYWN0TWltZUF0dGFjaG1lbnQocmF3LGZpbGVuYW1lfHwnJyxhdHRJZHgpOw0KICAgIGlmKCFhdHREYXRhKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRXh0cmFjdGlvbiBwacOoY2Ugam9pbnRlIMOpY2hvdcOpZSd9LDUwMCk7DQogICAgY29uc3Qgc2FmZUZuPShmaWxlbmFtZXx8J2F0dGFjaG1lbnQnKS5yZXBsYWNlKC9bXmEtejAtOS5fXC0gXS9naSwnXycpOw0KICAgIHJlcy53cml0ZUhlYWQoMjAwLHsnQ29udGVudC1UeXBlJzptaW1lfHwnYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtJywnQ29udGVudC1EaXNwb3NpdGlvbic6YGF0dGFjaG1lbnQ7IGZpbGVuYW1lPSIke3NhZmVGbn0iYCwnQ29udGVudC1MZW5ndGgnOmF0dERhdGEubGVuZ3RoLCdBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nOicqJywnQWNjZXNzLUNvbnRyb2wtQWxsb3ctSGVhZGVycyc6J0F1dGhvcml6YXRpb24sQ29udGVudC1UeXBlJ30pOw0KICAgIHJlcy5lbmQoYXR0RGF0YSk7DQogIH0gY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0Kcm91dGVzWydQT1NUIC92MS9lbWFpbHMvOmlkL3Jlc2VuZCddPWFzeW5jKHJlcSxyZXMse2lkfSk9PnsNCiAgaWYoIXJlcXVpcmVBdXRoKHJlcSxyZXMpKXJldHVybjsNCiAgdHJ5IHsNCiAgICAvLyBMaXJlIGJvZHkgSlNPTiBwb3VyIGxlICJ0byIgb3ZlcnJpZGUNCiAgICBjb25zdCBib2R5QnVmPWF3YWl0IG5ldyBQcm9taXNlKHI9Pntjb25zdCBjPVtdO3JlcS5vbignZGF0YScsZD0+Yy5wdXNoKGQpKTtyZXEub24oJ2VuZCcsKCk9PnIoQnVmZmVyLmNvbmNhdChjKSkpO30pOw0KICAgIGxldCBib2R5VG89Jyc7DQogICAgdHJ5IHsgY29uc3QgYj1KU09OLnBhcnNlKGJvZHlCdWYudG9TdHJpbmcoKSk7IGJvZHlUbz1iLnRvfHwnJzsgfSBjYXRjaCB7fQ0KDQogICAgLy8gUsOpY3Vww6lyZXIgbWV0YWRhdGEgKHNhbnMgSk9JTiBmcmFnaWxlKQ0KICAgIGNvbnN0IHJvd3M9ZGJSb3dzKGBTRUxFQ1QgaWQscGlsZXJfaWQsXGBmcm9tXGAgRlJPTSBtZXRhZGF0YSBXSEVSRSBpZD0nJHtlc2MoaWQpfScgQU5EIGRlbGV0ZWQ9MCBMSU1JVCAxYCk7DQogICAgaWYoIXJvd3MubGVuZ3RofHwhcm93c1swXVswXSkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J0VtYWlsIGludHJvdXZhYmxlJ30sNDA0KTsNCiAgICBjb25zdCBbLHBpbGVySWRdPXJvd3NbMF07DQoNCiAgICAvLyBSw6ljdXDDqXJlciBkZXN0aW5hdGFpcmUgZGVwdWlzIHJjcHQgc2kgcGFzIGRhbnMgYm9keQ0KICAgIGxldCB0bz1ib2R5VG87DQogICAgaWYoIXRvKXsNCiAgICAgIGNvbnN0IHJjcHRSb3dzPWRiUm93cyhgU0VMRUNUIFxgdG9cYCBGUk9NIHJjcHQgV0hFUkUgaWQ9JyR7ZXNjKGlkKX0nIExJTUlUIDFgKTsNCiAgICAgIGlmKHJjcHRSb3dzLmxlbmd0aCYmcmNwdFJvd3NbMF1bMF0mJnJjcHRSb3dzWzBdWzBdIT09J05VTEwnKSB0bz1yY3B0Um93c1swXVswXTsNCiAgICB9DQogICAgaWYoIXRvKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRGVzdGluYXRhaXJlIGludHJvdXZhYmxlJ30sNDAwKTsNCg0KICAgIC8vIFLDqWN1cMOpcmVyIEVNTCB2aWEgcGlsZXJnZXQNCiAgICBjb25zdCByZz1zcGF3blN5bmMoJ2RvY2tlcicsWydleGVjJyxQSUxFUl9OQU1FLCdwaWxlcmdldCcsU3RyaW5nKHBpbGVySWR8fGlkKV0se2VuY29kaW5nOididWZmZXInLHRpbWVvdXQ6MTUwMDAsbWF4QnVmZmVyOjIwKjEwMjQqMTAyNH0pOw0KICAgIGlmKHJnLnN0YXR1cyE9PTB8fCFyZy5zdGRvdXR8fHJnLnN0ZG91dC5sZW5ndGg9PT0wKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRmljaGllciBFTUwgbm9uIGRpc3BvbmlibGUnfSw1MDApOw0KDQogICAgLy8gRMOpY29tcHJlc3NlciBzaSBnemlwDQogICAgY29uc3QgemxpYj1yZXF1aXJlKCd6bGliJyk7DQogICAgbGV0IGVtbERhdGE7DQogICAgaWYocmcuc3Rkb3V0WzBdPT09MHgxZiYmcmcuc3Rkb3V0WzFdPT09MHg4Yil7DQogICAgICB0cnkgeyBlbWxEYXRhPXpsaWIuZ3VuemlwU3luYyhyZy5zdGRvdXQpLnRvU3RyaW5nKCd1dGY4Jyk7IH0NCiAgICAgIGNhdGNoIHsgZW1sRGF0YT1yZy5zdGRvdXQudG9TdHJpbmcoJ2xhdGluMScpOyB9DQogICAgfSBlbHNlIHsgZW1sRGF0YT1yZy5zdGRvdXQudG9TdHJpbmcoJ3V0ZjgnKTsgfQ0KDQogICAgLy8gRW52b3llciB2aWEgc2VuZG1haWwNCiAgICBjb25zdCBzZW5kPXNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLCctaScsUElMRVJfTkFNRSwnc2VuZG1haWwnLCctZicsJ25vcmVwbHlAcmVib290bHknLHRvXSwNCiAgICAgIHtpbnB1dDplbWxEYXRhLGVuY29kaW5nOid1dGY4Jyx0aW1lb3V0OjE1MDAwfSk7DQogICAgaWYoc2VuZC5zdGF0dXMhPT0wKXsNCiAgICAgIC8vIEZhbGxiYWNrOiDDqWNyaXJlIGRhbnMgY29udGFpbmVyIGV0IHJlbGFuY2VyDQogICAgICBjb25zdCB0bXBFbWw9YC90bXAvcmVzZW5kXyR7aWR9XyR7RGF0ZS5ub3coKX0uZW1sYDsNCiAgICAgIGZzLndyaXRlRmlsZVN5bmModG1wRW1sLGVtbERhdGEpOw0KICAgICAgc3Bhd25TeW5jKCdkb2NrZXInLFsnY3AnLHRtcEVtbCxgJHtQSUxFUl9OQU1FfTovdG1wL3JzXyR7aWR9LmVtbGBdLHt0aW1lb3V0OjUwMDB9KTsNCiAgICAgIGNvbnN0IHNlbmQyPXNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLFBJTEVSX05BTUUsJ3NlbmRtYWlsJywnLWYnLCdub3JlcGx5QHJlYm9vdGx5Jyx0bywnL3RtcC9yc18nK2lkKycuZW1sJ10se2VuY29kaW5nOid1dGY4Jyx0aW1lb3V0OjE1MDAwfSk7DQogICAgICBmcy51bmxpbmsodG1wRW1sLCgpPT57fSk7DQogICAgICAvLyBzZW5kbWFpbCBhdmVjIC10IChsaXQgVG86IGRlcHVpcyBoZWFkZXJzKQ0KICAgICAgaWYoc2VuZDIuc3RhdHVzIT09MCl7DQogICAgICAgIHNwYXduU3luYygnZG9ja2VyJyxbJ2V4ZWMnLFBJTEVSX05BTUUsJ3NoJywnLWMnLGBzZW5kbWFpbCAtdCA8IC90bXAvcnNfJHtpZH0uZW1sYF0se2VuY29kaW5nOid1dGY4Jyx0aW1lb3V0OjE1MDAwfSk7DQogICAgICB9DQogICAgfQ0KICAgIGpzb24ocmVzLHtvazp0cnVlLG1lc3NhZ2U6YEVtYWlsIHJlbnZvecOpIMOgICR7dG99YH0pOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQoNCi8vIOKUgOKUgCBVcGxvYWQgUFNUIC8gTUJPWCAvIEVNTCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIANCmNvbnN0IGh0dHAyPXJlcXVpcmUoJ2h0dHAnKTsNCnJvdXRlc1snUE9TVCAvdjEvaW1wb3J0L3VwbG9hZCddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICAvLyBMaXJlIGxlIGJvZHkgbXVsdGlwYXJ0IG1hbnVlbGxlbWVudA0KICBjb25zdCBjdD1yZXEuaGVhZGVyc1snY29udGVudC10eXBlJ118fCcnOw0KICBjb25zdCBib3VuZGFyeU1hdGNoPWN0Lm1hdGNoKC9ib3VuZGFyeT0oLispLyk7DQogIGlmKCFjdC5pbmNsdWRlcygnbXVsdGlwYXJ0L2Zvcm0tZGF0YScpfHwhYm91bmRhcnlNYXRjaCkNCiAgICByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonTXVsdGlwYXJ0IHJlcXVpcyd9LDQwMCk7DQogIGNvbnN0IGJvdW5kYXJ5PSctLScrYm91bmRhcnlNYXRjaFsxXS50cmltKCk7DQogIGNvbnN0IGNodW5rcz1bXTsNCiAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpPT57cmVxLm9uKCdkYXRhJyxjPT5jaHVua3MucHVzaChjKSk7cmVxLm9uKCdlbmQnLHJlc29sdmUpO3JlcS5vbignZXJyb3InLHJlc29sdmUpO30pOw0KICBjb25zdCBib2R5PUJ1ZmZlci5jb25jYXQoY2h1bmtzKTsNCiAgY29uc3QgYm9keVN0cj1ib2R5LnRvU3RyaW5nKCdiaW5hcnknKTsNCiAgLy8gUGFyc2VyIGxlIGNoYW1wIHR5cGUNCiAgY29uc3QgdHlwZU1hdGNoPWJvZHlTdHIubWF0Y2goL25hbWU9InR5cGUiXHJcblxyXG4oW15cclxuXSspLyk7DQogIGNvbnN0IGZpbGVUeXBlPSh0eXBlTWF0Y2g/dHlwZU1hdGNoWzFdOidlbWwnKS50b0xvd2VyQ2FzZSgpOw0KICAvLyBQYXJzZXIgbGUgZmljaGllcg0KICBjb25zdCBmaWxlUGFydE1hdGNoPWJvZHlTdHIubWF0Y2goL25hbWU9ImZpbGUiW15cclxuXSpcclxuQ29udGVudC1UeXBlOlteXHJcbl0rXHJcblxyXG4vKTsNCiAgaWYoIWZpbGVQYXJ0TWF0Y2gpIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidGaWNoaWVyIG1hbnF1YW50J30sNDAwKTsNCiAgY29uc3QgZmlsZVN0YXJ0PWJvZHkuaW5kZXhPZihCdWZmZXIuZnJvbShmaWxlUGFydE1hdGNoWzBdLCdiaW5hcnknKSkrZmlsZVBhcnRNYXRjaFswXS5sZW5ndGg7DQogIGNvbnN0IGVuZEJvdW5kYXJ5PWJvZHkuaW5kZXhPZihCdWZmZXIuZnJvbSgnXHJcbicrYm91bmRhcnksJ2JpbmFyeScpLGZpbGVTdGFydCk7DQogIGNvbnN0IGZpbGVEYXRhPWVuZEJvdW5kYXJ5PjA/Ym9keS5zbGljZShmaWxlU3RhcnQsZW5kQm91bmRhcnkpOmJvZHkuc2xpY2UoZmlsZVN0YXJ0KTsNCiAgLy8gU2F1dmVnYXJkZXIgbGUgZmljaGllciB0ZW1wb3JhaXJlbWVudA0KICBjb25zdCBleHQ9ZmlsZVR5cGU9PT0ncHN0Jz8nLnBzdCc6ZmlsZVR5cGU9PT0nbWJveCc/Jy5tYm94JzonLmVtbCc7DQogIGNvbnN0IHRtcEZpbGU9YC90bXAvcmJfdXBsb2FkXyR7RGF0ZS5ub3coKX0ke2V4dH1gOw0KICBmcy53cml0ZUZpbGVTeW5jKHRtcEZpbGUsZmlsZURhdGEpOw0KICAvLyBSw6ljdXDDqXJlciBvd25lciBkZXB1aXMgbGUgZm9ybSAoY2hhbXAgJ293bmVyJykNCiAgY29uc3Qgb3duZXJNYXRjaD1ib2R5LnRvU3RyaW5nKCdiaW5hcnknKS5tYXRjaCgvbmFtZT0ib3duZXIiXHJcblxyXG4oW15cclxuXSspLyk7DQogIGNvbnN0IG93bmVyPShvd25lck1hdGNoP293bmVyTWF0Y2hbMV06J2luY29ubnUnKS50cmltKCk7DQogIC8vIEVucmVnaXN0cmVyIGRhbnMgbGUgdHJhY2tpbmcNCiAgY29uc3QgdXBsb2Fkcz1yZWFkVXBsb2FkcygpOw0KICBjb25zdCB1aWQ9J3VwXycrRGF0ZS5ub3coKTsNCiAgbGV0IGlkX3N0YXJ0PTA7DQogIHRyeSB7IGNvbnN0IHI9ZGJSb3dzKCdTRUxFQ1QgTUFYKGlkKSBGUk9NIG1ldGFkYXRhJyk7aWRfc3RhcnQ9cGFyc2VJbnQoKHJbMF18fFtdKVswXXx8MCkrMTsgfSBjYXRjaCB7fQ0KICB1cGxvYWRzLnVuc2hpZnQoe3VpZCxvd25lcixmaWxlbmFtZTp0bXBGaWxlLnNwbGl0KCcvJykucG9wKCksdHlwZTpmaWxlVHlwZSxzaXplOmZpbGVEYXRhLmxlbmd0aCxkYXRlOm5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxzdGF0dXM6J2VuIGNvdXJzJyxpZF9zdGFydCxpZF9lbmQ6aWRfc3RhcnQrNTAwMDAsY291bnQ6MH0pOw0KICBzYXZlVXBsb2Fkcyh1cGxvYWRzLnNsaWNlKDAsMjAwKSk7DQogIGpzb24ocmVzLHtvazp0cnVlLG1lc3NhZ2U6J1VwbG9hZCByZcOndSwgaW1wb3J0IGVuIGFycmnDqHJlLXBsYW7igKYnLHVpZH0pOw0KICAvLyBUcmFpdGVtZW50IGFzeW5jaHJvbmUgc2Vsb24gbGUgdHlwZQ0KICAoYXN5bmMoKT0+ew0KICAgIHRyeSB7DQogICAgICBpZihmaWxlVHlwZT09PSdwc3QnKXsNCiAgICAgICAgLy8gcmVhZHBzdCBzJ2V4w6ljdXRlIHN1ciBsZSBMWEMgKHBhcyBkYW5zIGxlIGNvbnRhaW5lcikNCiAgICAgICAgY29uc3QgcHN0T3V0RGlyPScvdG1wL3JiX3BzdF9vdXRfJytEYXRlLm5vdygpOw0KICAgICAgICBjb25zdCB7c3Bhd25TeW5jOnNzfT1yZXF1aXJlKCdjaGlsZF9wcm9jZXNzJyk7DQogICAgICAgIHNzKCdta2RpcicsWyctcCcscHN0T3V0RGlyXSk7DQogICAgICAgIGNvbnN0IHJwPXNzKCdyZWFkcHN0JyxbJy1vJyxwc3RPdXREaXIsdG1wRmlsZV0se2VuY29kaW5nOid1dGY4Jyx0aW1lb3V0OjMwMDAwMH0pOw0KICAgICAgICBjb25zdCB1cGRTdGF0dXM9KHMpPT57IHRyeXsgY29uc3QgdXBzPXJlYWRVcGxvYWRzKCk7IGNvbnN0IHU9dXBzLmZpbmQoeD0+eC51aWQ9PT11aWQpOyBpZih1KXt1LnN0YXR1cz1zOyBzYXZlVXBsb2Fkcyh1cHMpO30gfWNhdGNoe30gfTsNCiAgICAgICAgaWYocnAuc3RhdHVzIT09MCl7DQogICAgICAgICAgY29uc29sZS5lcnJvcignW1BTVF0gcmVhZHBzdCBlcnJldXI6JyxycC5zdGRlcnJ8fHJwLnN0ZG91dCk7DQogICAgICAgICAgc3MoJ3JtJyxbJy1yZicscHN0T3V0RGlyXSk7DQogICAgICAgICAgdXBkU3RhdHVzKCdlcnJldXInKTsNCiAgICAgICAgfSBlbHNlIHsNCiAgICAgICAgICBhd2FpdCBydW5Bc3luYygnZG9ja2VyJyxbJ2V4ZWMnLFBJTEVSX05BTUUsJ21rZGlyJywnLXAnLCcvdG1wL3BzdF9lbWwnXSk7DQogICAgICAgICAgYXdhaXQgcnVuQXN5bmMoJ2RvY2tlcicsWydjcCcscHN0T3V0RGlyKycvLicsUElMRVJfTkFNRSsnOi90bXAvcHN0X2VtbC8nXSk7DQogICAgICAgICAgLy8gSW1wb3J0IHLDqWN1cnNpZiA6IGZpbmQgdG91cyBsZXMgLm1ib3ggZGFucyB0b3VzIGxlcyBzb3VzLWRvc3NpZXJzIFBTVA0KICAgICAgICAgIC8vIHBpbGVyaW1wb3J0IC1tIHN1ciBjaGFxdWUgZmljaGllciDihpIgUEogY29ycmVjdGVtZW50IGV4dHJhaXRlcw0KICAgICAgICAgIGF3YWl0IHJ1bkFzeW5jKCdkb2NrZXInLFsnZXhlYycsUElMRVJfTkFNRSwnYmFzaCcsJy1jJywNCiAgICAgICAgICAgICdmaW5kIC90bXAvcHN0X2VtbCAtdHlwZSBmIFxcKCAtbmFtZSAiKi5tYm94IiAtbyAtbmFtZSAiKi5tYngiIFxcKSB8IHdoaWxlIElGUz0gcmVhZCAtciBmOyBkbyBwaWxlcmltcG9ydCAtbSAiJGYiIDI+L2Rldi9udWxsOyBkb25lJw0KICAgICAgICAgIF0pOw0KICAgICAgICAgIGF3YWl0IHJ1bkFzeW5jKCdkb2NrZXInLFsnZXhlYycsUElMRVJfTkFNRSwncm0nLCctcmYnLCcvdG1wL3BzdF9lbWwnXSk7DQogICAgICAgICAgc3MoJ3JtJyxbJy1yZicscHN0T3V0RGlyXSk7DQogICAgICAgICAgLy8gTWFycXVlciB0b3VzIGxlcyBlbWFpbHMgaW1wb3J0w6lzIGRlcHVpcyBjZSBQU1QgZGFucyByYl9wc3RfaW1wb3J0ZWQgKGlkID4gaWRfc3RhcnQgcG91ciDDqXZpdGVyIGwnb2ZmLWJ5LW9uZSkNCiAgICAgICAgICB0cnkgeyBkYlF1ZXJ5KGBJTlNFUlQgSUdOT1JFIElOVE8gcmJfcHN0X2ltcG9ydGVkIChtZXRhZGF0YV9pZCx1cGxvYWRfdWlkKSBTRUxFQ1QgaWQsJyR7ZXNjKHVpZCl9JyBGUk9NIG1ldGFkYXRhIFdIRVJFIGlkPiR7aWRfc3RhcnR9IEFORCBkZWxldGVkPTBgKTsgfSBjYXRjaCB7fQ0KICAgICAgICAgIHVwZFN0YXR1cygndGVybWluw6knKTsNCiAgICAgICAgfQ0KICAgICAgfSBlbHNlIGlmKGZpbGVUeXBlPT09J21ib3gnKXsNCiAgICAgICAgYXdhaXQgcnVuQXN5bmMoJ2RvY2tlcicsWydjcCcsdG1wRmlsZSxgJHtQSUxFUl9OQU1FfTovdG1wL3VwbG9hZCR7ZXh0fWBdKTsNCiAgICAgICAgYXdhaXQgcnVuQXN5bmMoJ2RvY2tlcicsWydleGVjJyxQSUxFUl9OQU1FLCdwaWxlcmltcG9ydCcsJy1tJyxgL3RtcC91cGxvYWQke2V4dH1gXSk7DQogICAgICAgIGF3YWl0IHJ1bkFzeW5jKCdkb2NrZXInLFsnZXhlYycsUElMRVJfTkFNRSwncm0nLCctZicsYC90bXAvdXBsb2FkJHtleHR9YF0pOw0KICAgICAgICB0cnl7IGNvbnN0IHVwcz1yZWFkVXBsb2FkcygpOyBjb25zdCB1PXVwcy5maW5kKHg9PngudWlkPT09dWlkKTsgaWYodSl7dS5zdGF0dXM9J3Rlcm1pbsOpJzsgc2F2ZVVwbG9hZHModXBzKTt9IH1jYXRjaHt9DQogICAgICB9IGVsc2Ugew0KICAgICAgICAvLyBFTUwgc2ltcGxlDQogICAgICAgIGF3YWl0IHJ1bkFzeW5jKCdkb2NrZXInLFsnY3AnLHRtcEZpbGUsYCR7UElMRVJfTkFNRX06L3RtcC91cGxvYWQke2V4dH1gXSk7DQogICAgICAgIGF3YWl0IHJ1bkFzeW5jKCdkb2NrZXInLFsnZXhlYycsUElMRVJfTkFNRSwncGlsZXJpbXBvcnQnLGAvdG1wL3VwbG9hZCR7ZXh0fWBdKTsNCiAgICAgICAgYXdhaXQgcnVuQXN5bmMoJ2RvY2tlcicsWydleGVjJyxQSUxFUl9OQU1FLCdybScsJy1mJyxgL3RtcC91cGxvYWQke2V4dH1gXSk7DQogICAgICAgIHRyeXsgY29uc3QgdXBzPXJlYWRVcGxvYWRzKCk7IGNvbnN0IHU9dXBzLmZpbmQoeD0+eC51aWQ9PT11aWQpOyBpZih1KXt1LnN0YXR1cz0ndGVybWluw6knOyBzYXZlVXBsb2Fkcyh1cHMpO30gfWNhdGNoe30NCiAgICAgIH0NCiAgICAgIGZzLnVubGluayh0bXBGaWxlLCgpPT57fSk7DQogICAgfSBjYXRjaChlKXsNCiAgICAgIGZzLnVubGluayh0bXBGaWxlLCgpPT57fSk7IGNvbnNvbGUuZXJyb3IoJ1tVcGxvYWRdIGVycmV1cjonLGUubWVzc2FnZSk7DQogICAgICB0cnl7IGNvbnN0IHVwcz1yZWFkVXBsb2FkcygpOyBjb25zdCB1PXVwcy5maW5kKHg9PngudWlkPT09dWlkKTsgaWYodSl7dS5zdGF0dXM9J2VycmV1cic7IHUuZXJyb3I9ZS5tZXNzYWdlLnNsaWNlKDAsMjAwKTsgc2F2ZVVwbG9hZHModXBzKTt9IH1jYXRjaHt9DQogICAgfQ0KICB9KSgpOw0KfTsNCg0KDQovLyDilIDilIAgVXBsb2FkIHRyYWNraW5nIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgA0KY29uc3QgVVBMT0FEU19GSUxFPScvb3B0L3JlYm9vdGx5L3VwbG9hZHMuanNvbic7DQpjb25zdCByZWFkVXBsb2Fkcz0oKT0+eyB0cnl7cmV0dXJuIEpTT04ucGFyc2UocmVxdWlyZSgnZnMnKS5yZWFkRmlsZVN5bmMoVVBMT0FEU19GSUxFLCd1dGY4JykpO31jYXRjaHtyZXR1cm4gW107fSB9Ow0KY29uc3Qgc2F2ZVVwbG9hZHM9KGFycik9PnsgdHJ5e3JlcXVpcmUoJ2ZzJykud3JpdGVGaWxlU3luYyhVUExPQURTX0ZJTEUsSlNPTi5zdHJpbmdpZnkoYXJyLG51bGwsMikpO31jYXRjaHt9IH07DQoNCnJvdXRlc1snR0VUIC92MS9pbXBvcnQvdXBsb2FkcyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQXV0aChyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IHVwbG9hZHM9cmVhZFVwbG9hZHMoKTsNCiAgLy8gRW5yaWNoaXIgYXZlYyBsZSBjb21wdGFnZSByw6llbCBkZXB1aXMgbGEgREINCiAgY29uc3QgcmVzdWx0PXVwbG9hZHMubWFwKHU9PnsNCiAgICB0cnkgew0KICAgICAgY29uc3Qgcm93cz1kYlJvd3MoYFNFTEVDVCBDT1VOVCgqKSBGUk9NIG1ldGFkYXRhIFdIRVJFIGlkIEJFVFdFRU4gJHtwYXJzZUludCh1LmlkX3N0YXJ0KXx8MH0gQU5EICR7cGFyc2VJbnQodS5pZF9lbmQpfHw5OTk5OTk5OTl9IEFORCBkZWxldGVkPTBgKTsNCiAgICAgIHUuY291bnRfcmVhbD1wYXJzZUludCgocm93c1swXXx8W10pWzBdKXx8dS5jb3VudHx8MDsNCiAgICB9IGNhdGNoIHsgdS5jb3VudF9yZWFsPXUuY291bnR8fDA7IH0NCiAgICByZXR1cm4gdTsNCiAgfSk7DQogIGpzb24ocmVzLHt1cGxvYWRzOnJlc3VsdH0pOw0KfTsNCg0Kcm91dGVzWydERUxFVEUgL3YxL2ltcG9ydC91cGxvYWRzLzp1aWQnXT1hc3luYyhyZXEscmVzLHt1aWR9KT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgY29uc3QgdXBsb2Fkcz1yZWFkVXBsb2FkcygpOw0KICBjb25zdCBmaWx0ZXJlZD11cGxvYWRzLmZpbHRlcih1PT51LnVpZCE9PXVpZCk7DQogIHNhdmVVcGxvYWRzKGZpbHRlcmVkKTsNCiAganNvbihyZXMse29rOnRydWV9KTsNCn07DQoNCnJvdXRlc1snUE9TVCAvdjEvaW1wb3J0L3VwbG9hZHMvOnVpZC9wdXJnZSddPWFzeW5jKHJlcSxyZXMse3VpZH0pPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICBjb25zdCB1cGxvYWRzPXJlYWRVcGxvYWRzKCk7DQogIGNvbnN0IHU9dXBsb2Fkcy5maW5kKHg9PngudWlkPT09dWlkKTsNCiAgaWYoIXUpcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J0ltcG9ydCBpbnRyb3V2YWJsZSd9LDQwNCk7DQogIGxldCBkZWxldGVkPTA7DQogIHRyeXsNCiAgICBjb25zdCBzPXBhcnNlSW50KHUuaWRfc3RhcnQpfHwwOw0KICAgIGNvbnN0IGU9cGFyc2VJbnQodS5pZF9lbmQpfHw5OTk5OTk5OTk7DQogICAgY29uc3Qgcm93cz1kYlJvd3MoYFNFTEVDVCBDT1VOVCgqKSBGUk9NIG1ldGFkYXRhIFdIRVJFIGlkIEJFVFdFRU4gJHtzfSBBTkQgJHtlfSBBTkQgZGVsZXRlZD0wYCk7DQogICAgZGVsZXRlZD1wYXJzZUludCgocm93c1swXXx8W10pWzBdKXx8MDsNCiAgICBpZihkZWxldGVkPjApIGRiUXVlcnkoYFVQREFURSBtZXRhZGF0YSBTRVQgZGVsZXRlZD0xIFdIRVJFIGlkIEJFVFdFRU4gJHtzfSBBTkQgJHtlfSBBTkQgZGVsZXRlZD0wYCk7DQogIH1jYXRjaChlcnIpe3JldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidFcnJldXIgREI6ICcrZXJyLm1lc3NhZ2V9LDUwMCk7fQ0KICBzYXZlVXBsb2Fkcyh1cGxvYWRzLmZpbHRlcih4PT54LnVpZCE9PXVpZCkpOw0KICBqc29uKHJlcyx7b2s6dHJ1ZSxkZWxldGVkX2VtYWlsczpkZWxldGVkfSk7DQp9Ow0KDQovLyDilIDilIAgUkdQRCDigJQgRHJvaXQgw6AgbCdvdWJsaSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIANCnJvdXRlc1snREVMRVRFIC92MS9yZ3BkLzplbWFpbCddPWFzeW5jKHJlcSxyZXMse2VtYWlsfSk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IGFkZHI9ZGVjb2RlVVJJQ29tcG9uZW50KGVtYWlsKS50b0xvd2VyQ2FzZSgpLnRyaW0oKTsNCiAgaWYoIWFkZHIuaW5jbHVkZXMoJ0AnKSkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J0VtYWlsIGludmFsaWRlJ30sNDAwKTsNCiAgdHJ5IHsNCiAgICAvLyBDb21wdGVyIGQnYWJvcmQNCiAgICBjb25zdCBjb3VudFJvd3M9ZGJSb3dzKGBTRUxFQ1QgQ09VTlQoKikgRlJPTSBtZXRhZGF0YSBXSEVSRSAoTE9XRVIoXGBmcm9tXGApIExJS0UgJyUke2VzYyhhZGRyKX0lJykgQU5EIGRlbGV0ZWQ9MGApOw0KICAgIGNvbnN0IGNvdW50PXBhcnNlSW50KChjb3VudFJvd3NbMF18fFtdKVswXSl8fDA7DQogICAgLy8gTWFycXVlciBjb21tZSBzdXBwcmltw6lzIChzb2Z0IGRlbGV0ZSDigJQgTWFpbHBpbGVyIGNvbnZlbnRpb24pDQogICAgZGJRdWVyeShgVVBEQVRFIG1ldGFkYXRhIFNFVCBkZWxldGVkPTEgV0hFUkUgKExPV0VSKFxgZnJvbVxgKSBMSUtFICclJHtlc2MoYWRkcil9JScgT1IgRVhJU1RTIChTRUxFQ1QgMSBGUk9NIHJjcHQgciBXSEVSRSByLmlkPW1ldGFkYXRhLmlkIEFORCBMT1dFUihyLnRvKSBMSUtFICclJHtlc2MoYWRkcil9JScpKSBBTkQgZGVsZXRlZD0wYCk7DQogICAganNvbihyZXMse29rOnRydWUsZGVsZXRlZDpjb3VudCxlbWFpbDphZGRyLG1lc3NhZ2U6YCR7Y291bnR9IGVtYWlsKHMpIHN1cHByaW3DqShzKSBwb3VyICR7YWRkcn1gfSk7DQogIH0gY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQovLyBVU0VSUyArIEVNQUlMUyBBU1NPQ0nDiVMNCi8vIHVpZCA9IFBBUyBhdXRvX2luY3JlbWVudCDihpIgTUFYKHVpZCkrMQ0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQpyb3V0ZXNbJ0dFVCAvdjEvdXNlcnMnXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgdHJ5IHsNCiAgICBjb25zdCByb3dzPWRiUm93cygnU0VMRUNUIHVpZCx1c2VybmFtZSxyZWFsbmFtZSxpc2FkbWluLGRvbWFpbiBGUk9NIHVzZXIgT1JERVIgQlkgdWlkJyk7DQogICAganNvbihyZXMse3VzZXJzOnJvd3MuZmlsdGVyKHI9PnIubGVuZ3RoPj00KS5tYXAocj0+KHt1aWQ6cGFyc2VJbnQoclswXSksdXNlcm5hbWU6clsxXSxyZWFsbmFtZTpyWzJdfHwnJyxpc2FkbWluOnJbM109PT0nMScsZG9tYWluOnJbNF18fCcnfSkpfSk7DQogIH0gY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCnJvdXRlc1snUE9TVCAvdjEvdXNlcnMnXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgY29uc3Qge3VzZXJuYW1lLHBhc3N3b3JkLHJlYWxuYW1lPScnLGlzYWRtaW49MCxkb21haW49Jyd9PWF3YWl0IHJlYWRCb2R5KHJlcSk7DQogIGlmKCF1c2VybmFtZXx8IXBhc3N3b3JkKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTondXNlcm5hbWUgZXQgcGFzc3dvcmQgcmVxdWlzJ30sNDAwKTsNCiAgaWYocGFzc3dvcmQubGVuZ3RoPDYpIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidNb3QgZGUgcGFzc2UgdHJvcCBjb3VydCd9LDQwMCk7DQogIGNvbnN0IGhhc2g9aGFzaFB3KHBhc3N3b3JkKTsNCiAgaWYoIWhhc2h8fGhhc2gubGVuZ3RoPDIwKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRXJyZXVyIGfDqW7DqXJhdGlvbiBoYXNoJ30sNTAwKTsNCiAgdHJ5IHsNCiAgICBjb25zdCBuZXh0VWlkPXBhcnNlSW50KChkYlJvd3MoJ1NFTEVDVCBDT0FMRVNDRShNQVgodWlkKSwxKSsxIEZST00gdXNlcicpWzBdfHxbXSlbMF0pfHwyOw0KICAgIGRiUXVlcnkoYElOU0VSVCBJTlRPIHVzZXIgKHVpZCx1c2VybmFtZSxyZWFsbmFtZSxwYXNzd29yZCxkb21haW4sZG4saXNhZG1pbikgVkFMVUVTICgke25leHRVaWR9LCcke2VzYyh1c2VybmFtZSl9JywnJHtlc2MocmVhbG5hbWUpfScsJyR7ZXNjKGhhc2gpfScsJyR7ZXNjKGRvbWFpbil9JywnKicsJHtpc2FkbWluPzE6MH0pYCk7DQogICAganNvbihyZXMse29rOnRydWUsbWVzc2FnZTonVXRpbGlzYXRldXIgY3LDqcOpJyx1aWQ6bmV4dFVpZH0sMjAxKTsNCiAgfSBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0Kcm91dGVzWydQQVRDSCAvdjEvdXNlcnMvOnVpZCddPWFzeW5jKHJlcSxyZXMse3VpZH0pPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICBjb25zdCB7cmVhbG5hbWUsZG9tYWluLGlzYWRtaW59PWF3YWl0IHJlYWRCb2R5KHJlcSk7DQogIGNvbnN0IHNldHM9W107DQogIGlmKHJlYWxuYW1lIT09dW5kZWZpbmVkKSBzZXRzLnB1c2goYHJlYWxuYW1lPScke2VzYyhyZWFsbmFtZSl9J2ApOw0KICBpZihkb21haW4hPT11bmRlZmluZWQpICAgc2V0cy5wdXNoKGBkb21haW49JyR7ZXNjKGRvbWFpbil9J2ApOw0KICBpZihpc2FkbWluIT09dW5kZWZpbmVkKSAgc2V0cy5wdXNoKGBpc2FkbWluPSR7aXNhZG1pbj8xOjB9YCk7DQogIGlmKCFzZXRzLmxlbmd0aCkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J1JpZW4gw6AgbW9kaWZpZXInfSw0MDApOw0KICB0cnkgeyBkYlF1ZXJ5KGBVUERBVEUgdXNlciBTRVQgJHtzZXRzLmpvaW4oJywnKX0gV0hFUkUgdWlkPSR7cGFyc2VJbnQodWlkKX1gKTsganNvbihyZXMse29rOnRydWV9KTsgfQ0KICBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0Kcm91dGVzWydERUxFVEUgL3YxL3VzZXJzLzp1aWQnXT1hc3luYyhyZXEscmVzLHt1aWR9KT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgaWYodWlkPT09JzAnKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonQWRtaW4gcHJpbmNpcGFsIG5vbiBzdXBwcmltYWJsZSd9LDQwMCk7DQogIHRyeSB7IGRiUXVlcnkoYERFTEVURSBGUk9NIHVzZXIgV0hFUkUgdWlkPSR7cGFyc2VJbnQodWlkKX1gKTsgZGJRdWVyeShgREVMRVRFIEZST00gZW1haWwgV0hFUkUgdWlkPSR7cGFyc2VJbnQodWlkKX1gKTsganNvbihyZXMse29rOnRydWV9KTsgfQ0KICBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0Kcm91dGVzWydQQVRDSCAvdjEvdXNlcnMvOnVpZC9wYXNzd29yZCddPWFzeW5jKHJlcSxyZXMse3VpZH0pPT57DQogIGNvbnN0IHVzZXI9cmVxdWlyZUF1dGgocmVxLHJlcyk7aWYoIXVzZXIpcmV0dXJuOw0KICBpZih1c2VyLnVpZCE9PXBhcnNlSW50KHVpZCkmJiF1c2VyLmlzYWRtaW4pIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidOb24gYXV0b3Jpc8OpJ30sNDAzKTsNCiAgY29uc3Qge3Bhc3N3b3JkfT1hd2FpdCByZWFkQm9keShyZXEpOw0KICBpZighcGFzc3dvcmR8fHBhc3N3b3JkLmxlbmd0aDw2KSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonTW90IGRlIHBhc3NlIHRyb3AgY291cnQgKG1pbiA2KSd9LDQwMCk7DQogIGNvbnN0IGhhc2g9aGFzaFB3KHBhc3N3b3JkKTsNCiAgdHJ5IHsgZGJRdWVyeShgVVBEQVRFIHVzZXIgU0VUIHBhc3N3b3JkPScke2VzYyhoYXNoKX0nIFdIRVJFIHVpZD0ke3BhcnNlSW50KHVpZCl9YCk7IGpzb24ocmVzLHtvazp0cnVlfSk7IH0NCiAgY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCnJvdXRlc1snR0VUIC92MS91c2Vycy86dWlkL2VtYWlscyddPWFzeW5jKHJlcSxyZXMse3VpZH0pPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICB0cnkgeyBqc29uKHJlcyx7ZW1haWxzOihkYlJvd3MoYFNFTEVDVCBlbWFpbCBGUk9NIGVtYWlsIFdIRVJFIHVpZD0ke3BhcnNlSW50KHVpZCl9YCkpLmZpbHRlcihyPT5yWzBdKS5tYXAocj0+clswXSl9KTsgfQ0KICBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0Kcm91dGVzWydQT1NUIC92MS91c2Vycy86dWlkL2VtYWlscyddPWFzeW5jKHJlcSxyZXMse3VpZH0pPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICBjb25zdCB7ZW1haWx9PWF3YWl0IHJlYWRCb2R5KHJlcSk7DQogIGlmKCFlbWFpbCkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J2VtYWlsIHJlcXVpcyd9LDQwMCk7DQogIHRyeSB7IGRiUXVlcnkoYElOU0VSVCBJTlRPIGVtYWlsICh1aWQsZW1haWwpIFZBTFVFUyAoJHtwYXJzZUludCh1aWQpfSwnJHtlc2MoZW1haWwpfScpYCk7IGpzb24ocmVzLHtvazp0cnVlfSwyMDEpOyB9DQogIGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQpyb3V0ZXNbJ0RFTEVURSAvdjEvdXNlcnMvOnVpZC9lbWFpbHMvOmVtYWlsJ109YXN5bmMocmVxLHJlcyx7dWlkLGVtYWlsfSk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIHRyeSB7IGRiUXVlcnkoYERFTEVURSBGUk9NIGVtYWlsIFdIRVJFIHVpZD0ke3BhcnNlSW50KHVpZCl9IEFORCBlbWFpbD0nJHtlc2MoZGVjb2RlVVJJQ29tcG9uZW50KGVtYWlsKSl9J2ApOyBqc29uKHJlcyx7b2s6dHJ1ZX0pOyB9DQogIGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQoNCi8vIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkA0KLy8gRE9NQUlORVMgKyBkb21haW5fdXNlcg0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQpyb3V0ZXNbJ0dFVCAvdjEvZG9tYWlucyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICB0cnkgeyBqc29uKHJlcyx7ZG9tYWluczooZGJSb3dzKCdTRUxFQ1QgZG9tYWluLG1hcHBlZCxsZGFwX2lkIEZST00gZG9tYWluIE9SREVSIEJZIGRvbWFpbicpKS5maWx0ZXIocj0+ci5sZW5ndGg+PTIpLm1hcChyPT4oe2RvbWFpbjpyWzBdLG1hcHBlZDpyWzFdfHwnJyxsZGFwX2lkOnBhcnNlSW50KHJbMl0pfHwwfSkpfSk7IH0NCiAgY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCnJvdXRlc1snUE9TVCAvdjEvZG9tYWlucyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICBjb25zdCB7ZG9tYWluLG1hcHBlZD0nJ309YXdhaXQgcmVhZEJvZHkocmVxKTsNCiAgaWYoIWRvbWFpbikgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J2RvbWFpbiByZXF1aXMnfSw0MDApOw0KICB0cnkgeyBkYlF1ZXJ5KGBJTlNFUlQgSU5UTyBkb21haW4gKGRvbWFpbixtYXBwZWQpIFZBTFVFUyAoJyR7ZXNjKGRvbWFpbi50cmltKCkudG9Mb3dlckNhc2UoKSl9JywnJHtlc2MobWFwcGVkfHxkb21haW4udHJpbSgpLnRvTG93ZXJDYXNlKCkpfScpYCk7IGpzb24ocmVzLHtvazp0cnVlfSwyMDEpOyB9DQogIGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQpyb3V0ZXNbJ0RFTEVURSAvdjEvZG9tYWlucy86ZG9tYWluJ109YXN5bmMocmVxLHJlcyx7ZG9tYWlufSk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IGQ9ZGVjb2RlVVJJQ29tcG9uZW50KGRvbWFpbik7DQogIGlmKGQ9PT0nbG9jYWwnKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonRG9tYWluZSBsb2NhbCBub24gc3VwcHJpbWFibGUnfSw0MDApOw0KICB0cnkgeyBkYlF1ZXJ5KGBERUxFVEUgRlJPTSBkb21haW4gV0hFUkUgZG9tYWluPScke2VzYyhkKX0nYCk7IGpzb24ocmVzLHtvazp0cnVlfSk7IH0NCiAgY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQovLyBJTVBPUlQgSU1BUC9QT1AzICh0YWJsZSBpbXBvcnQpDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCnJvdXRlc1snR0VUIC92MS9zb3VyY2VzJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIHRyeSB7DQogICAgY29uc3Qgcm93cz1kYlJvd3MoJ1NFTEVDVCBpZCx0eXBlLHVzZXJuYW1lLHNlcnZlcixjcmVhdGVkLHN0YXJ0ZWQsZmluaXNoZWQsc3RhdHVzLHRvdGFsLGltcG9ydGVkLGR1cGxpY2F0ZSxlcnJvciBGUk9NIGltcG9ydCBPUkRFUiBCWSBpZCBERVNDJyk7DQogICAganNvbihyZXMse3NvdXJjZXM6cm93cy5maWx0ZXIocj0+ci5sZW5ndGg+PTEyKS5tYXAocj0+KHtpZDpwYXJzZUludChyWzBdKSx0eXBlOnJbMV0sdXNlcm5hbWU6clsyXSxzZXJ2ZXI6clszXSxjcmVhdGVkOnBhcnNlSW50KHJbNF0pfHwwLHN0YXJ0ZWQ6cGFyc2VJbnQocls1XSl8fDAsZmluaXNoZWQ6cGFyc2VJbnQocls2XSl8fDAsc3RhdHVzOnBhcnNlSW50KHJbN10pfHwwLHRvdGFsOnBhcnNlSW50KHJbOF0pfHwwLGltcG9ydGVkOnBhcnNlSW50KHJbOV0pfHwwLGR1cGxpY2F0ZTpwYXJzZUludChyWzEwXSl8fDAsZXJyb3I6cGFyc2VJbnQoclsxMV0pfHwwfSkpfSk7DQogIH0gY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCnJvdXRlc1snUE9TVCAvdjEvc291cmNlcyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICBjb25zdCB7dHlwZT0naW1hcCcsdXNlcm5hbWUscGFzc3dvcmQ9Jycsc2VydmVyfT1hd2FpdCByZWFkQm9keShyZXEpOw0KICBpZighdXNlcm5hbWV8fCFzZXJ2ZXIpIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOid1c2VybmFtZSBldCBzZXJ2ZXIgcmVxdWlzJ30sNDAwKTsNCiAgaWYoIVsnaW1hcCcsJ3BvcDMnXS5pbmNsdWRlcyh0eXBlKSkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J3R5cGUgZG9pdCDDqnRyZSBpbWFwIG91IHBvcDMnfSw0MDApOw0KICB0cnkgeyBkYlF1ZXJ5KGBJTlNFUlQgSU5UTyBpbXBvcnQgKHR5cGUsdXNlcm5hbWUscGFzc3dvcmQsc2VydmVyLGNyZWF0ZWQsc3RhdHVzKSBWQUxVRVMgKCcke2VzYyh0eXBlKX0nLCcke2VzYyh1c2VybmFtZSl9JywnJHtlc2MocGFzc3dvcmQpfScsJyR7ZXNjKHNlcnZlcil9Jywke25vdygpfSwwKWApOyBqc29uKHJlcyx7b2s6dHJ1ZX0sMjAxKTsgfQ0KICBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0Kcm91dGVzWydERUxFVEUgL3YxL3NvdXJjZXMvOmlkJ109YXN5bmMocmVxLHJlcyx7aWR9KT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgdHJ5IHsgZGJRdWVyeShgREVMRVRFIEZST00gaW1wb3J0IFdIRVJFIGlkPSR7cGFyc2VJbnQoaWQpfWApOyBqc29uKHJlcyx7b2s6dHJ1ZX0pOyB9DQogIGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQovLyDilIDilIAgR8OpbsOpcmF0ZXVyIHNjcmlwdCBQeXRob24gaW1wb3J0IChwYXJ0YWfDqSBlbnRyZSAvcnVuIGV0IC90cmlnZ2VyKSDilIDilIDilIDilIDilIDilIDilIDilIDilIANCmNvbnN0IGJ1aWxkSW1wb3J0U2NyaXB0ID0gKHR5cGUsIHVzZXJuYW1lLCBwYXNzd29yZCwgaG9zdCwgcG9ydCwgc2lkKSA9PiBgDQppbXBvcnQgaW1hcGxpYiwgcG9wbGliLCBvcywgc3NsLCBzdWJwcm9jZXNzLCBzeXMsIGpzb24NCg0KVFlQRSAgID0gJHtKU09OLnN0cmluZ2lmeSh0eXBlKX0NClVTRVIgICA9ICR7SlNPTi5zdHJpbmdpZnkodXNlcm5hbWUpfQ0KUEFTUyAgID0gJHtKU09OLnN0cmluZ2lmeShwYXNzd29yZCl9DQpIT1NUICAgPSAke0pTT04uc3RyaW5naWZ5KGhvc3QpfQ0KUE9SVCAgID0gaW50KCR7SlNPTi5zdHJpbmdpZnkocG9ydCl9KQ0KVE1QRElSID0gJy90bXAvcGlsZXJfaW1wb3J0XyR7cGFyc2VJbnQoc2lkKX1fJyArIHN0cihvcy5nZXRwaWQoKSkNCkNPTlRBSU5FUiA9ICR7SlNPTi5zdHJpbmdpZnkoUElMRVJfTkFNRSl9DQoNCm9zLm1ha2VkaXJzKFRNUERJUiwgZXhpc3Rfb2s9VHJ1ZSkNCnRvdGFsID0gMA0KZXJyb3JzID0gMA0KZm9sZGVyc19kb25lID0gW10NCg0KdHJ5Og0KICBpZiBUWVBFID09ICdpbWFwJzoNCiAgICBjdHggPSBzc2wuY3JlYXRlX2RlZmF1bHRfY29udGV4dCgpDQogICAgY3R4LmNoZWNrX2hvc3RuYW1lID0gRmFsc2UNCiAgICBjdHgudmVyaWZ5X21vZGUgPSBzc2wuQ0VSVF9OT05FDQogICAgaWYgUE9SVCA9PSA5OTM6DQogICAgICBNID0gaW1hcGxpYi5JTUFQNF9TU0woSE9TVCwgUE9SVCwgc3NsX2NvbnRleHQ9Y3R4KQ0KICAgIGVsc2U6DQogICAgICBNID0gaW1hcGxpYi5JTUFQNChIT1NULCBQT1JUKQ0KICAgICAgdHJ5OiBNLnN0YXJ0dGxzKHNzbF9jb250ZXh0PWN0eCkNCiAgICAgIGV4Y2VwdCBFeGNlcHRpb246IHBhc3MgICMgc2VydmV1ciBzYW5zIFNUQVJUVExTDQogICAgTS5sb2dpbihVU0VSLCBQQVNTKQ0KDQogICAgIyBMaXN0ZXIgdG91cyBsZXMgZG9zc2llcnMNCiAgICB0eXAsIGZvbGRlcl9saXN0ID0gTS5saXN0KCkNCiAgICBmb2xkZXJfbmFtZXMgPSBbXQ0KICAgIGZvciBmIGluIGZvbGRlcl9saXN0Og0KICAgICAgdHJ5Og0KICAgICAgICBkZWNvZGVkID0gZi5kZWNvZGUoKSBpZiBpc2luc3RhbmNlKGYsIGJ5dGVzKSBlbHNlIHN0cihmKQ0KICAgICAgZXhjZXB0OiBjb250aW51ZQ0KICAgICAgIyBGaWx0cmVyIGxlcyBub21zIGhhY2vDqXMgKHdlYm1haWwgZGVmYWPDqSDigJQgSFRNTCBkYW5zIGxlcyBub21zKQ0KICAgICAgaWYgJzwnIGluIGRlY29kZWQgb3IgJ3NjcmlwdCcgaW4gZGVjb2RlZC5sb3dlcigpOiBjb250aW51ZQ0KICAgICAgIyBTdXBwb3J0ZSBzw6lwYXJhdGV1ciAiLiIgKERvdmVjb3QpIGV0ICIvIiAoR21haWwsIEV4Y2hhbmdlKQ0KICAgICAgcGFydHMgPSBkZWNvZGVkLnNwbGl0KCciLiInKSBpZiAnIi4iJyBpbiBkZWNvZGVkIGVsc2UgZGVjb2RlZC5zcGxpdCgnIi8iJykNCiAgICAgIGlmIGxlbihwYXJ0cykgPj0gMjoNCiAgICAgICAgbmFtZSA9IHBhcnRzWy0xXS5zdHJpcCgpLnN0cmlwKCciJykuc3RyaXAoKQ0KICAgICAgICBpZiBuYW1lOiBmb2xkZXJfbmFtZXMuYXBwZW5kKG5hbWUpDQogICAgaWYgbm90IGZvbGRlcl9uYW1lczogZm9sZGVyX25hbWVzID0gWydJTkJPWCddDQoNCiAgICBmb3IgZm9sZGVyIGluIGZvbGRlcl9uYW1lczoNCiAgICAgIHRyeToNCiAgICAgICAgdHlwMiwgZGF0YSA9IE0uc2VsZWN0KCciJyArIGZvbGRlciArICciJywgcmVhZG9ubHk9VHJ1ZSkNCiAgICAgICAgY291bnQgPSBpbnQoZGF0YVswXSkgaWYgZGF0YSBhbmQgZGF0YVswXSBlbHNlIDANCiAgICAgICAgaWYgY291bnQgPT0gMDogY29udGludWUNCiAgICAgICAgdHlwMywgbXNncyA9IE0uc2VhcmNoKE5vbmUsICdBTEwnKQ0KICAgICAgICBpZiBub3QgbXNncyBvciBub3QgbXNnc1swXTogY29udGludWUNCiAgICAgICAgdWlkcyA9IG1zZ3NbMF0uc3BsaXQoKQ0KICAgICAgICBmb3IgdWlkIGluIHVpZHM6DQogICAgICAgICAgdHJ5Og0KICAgICAgICAgICAgdHlwNCwgbXNnX2RhdGEgPSBNLmZldGNoKHVpZCwgJyhSRkM4MjIpJykNCiAgICAgICAgICAgIGlmIG1zZ19kYXRhIGFuZCBtc2dfZGF0YVswXSBhbmQgbXNnX2RhdGFbMF1bMV06DQogICAgICAgICAgICAgIHVpZF9zID0gdWlkLmRlY29kZSgpIGlmIGlzaW5zdGFuY2UodWlkLCBieXRlcykgZWxzZSBzdHIodWlkKQ0KICAgICAgICAgICAgICBmbmFtZSA9IFRNUERJUiArICcvbXNnXycgKyBmb2xkZXIucmVwbGFjZSgnLicsJ18nKS5yZXBsYWNlKCcvJywnXycpICsgJ18nICsgdWlkX3MgKyAnLmVtbCcNCiAgICAgICAgICAgICAgd2l0aCBvcGVuKGZuYW1lLCAnd2InKSBhcyBmaDoNCiAgICAgICAgICAgICAgICBmaC53cml0ZShtc2dfZGF0YVswXVsxXSkNCiAgICAgICAgICAgICAgdG90YWwgKz0gMQ0KICAgICAgICAgIGV4Y2VwdDogZXJyb3JzICs9IDENCiAgICAgICAgZm9sZGVyc19kb25lLmFwcGVuZChmb2xkZXIgKyAnOicgKyBzdHIobGVuKHVpZHMpKSkNCiAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToNCiAgICAgICAgZXJyb3JzICs9IDENCiAgICBNLmxvZ291dCgpDQoNCiAgZWxzZTogICMgUE9QMw0KICAgIGlmIFBPUlQgPT0gOTk1Og0KICAgICAgY3R4ID0gc3NsLmNyZWF0ZV9kZWZhdWx0X2NvbnRleHQoKQ0KICAgICAgY3R4LmNoZWNrX2hvc3RuYW1lID0gRmFsc2UNCiAgICAgIGN0eC52ZXJpZnlfbW9kZSA9IHNzbC5DRVJUX05PTkUNCiAgICAgIE0gPSBwb3BsaWIuUE9QM19TU0woSE9TVCwgUE9SVCwgY29udGV4dD1jdHgpDQogICAgZWxzZToNCiAgICAgIE0gPSBwb3BsaWIuUE9QMyhIT1NULCBQT1JUKQ0KICAgIE0udXNlcihVU0VSKQ0KICAgIE0ucGFzc18oUEFTUykNCiAgICBudW0gPSBsZW4oTS5saXN0KClbMV0pDQogICAgZm9yIGkgaW4gcmFuZ2UoMSwgbnVtICsgMSk6DQogICAgICB0cnk6DQogICAgICAgIGxpbmVzID0gTS5yZXRyKGkpWzFdDQogICAgICAgIE5MID0gYnl0ZXMoWzEwXSkNCiAgICAgICAgcmF3ID0gTkwuam9pbihsaW5lcykNCiAgICAgICAgZm5hbWUgPSBUTVBESVIgKyAnL21zZ19wb3AzXycgKyBzdHIoaSkgKyAnLmVtbCcNCiAgICAgICAgd2l0aCBvcGVuKGZuYW1lLCAnd2InKSBhcyBmaDoNCiAgICAgICAgICBmaC53cml0ZShyYXcpDQogICAgICAgIHRvdGFsICs9IDENCiAgICAgIGV4Y2VwdDogZXJyb3JzICs9IDENCiAgICBNLnF1aXQoKQ0KICAgIGZvbGRlcnNfZG9uZSA9IFsnUE9QMzonICsgc3RyKG51bSldDQoNCiAgaWYgdG90YWwgPT0gMDoNCiAgICBpbXBvcnQgc2h1dGlsOyBzaHV0aWwucm10cmVlKFRNUERJUiwgaWdub3JlX2Vycm9ycz1UcnVlKQ0KICAgIHByaW50KGpzb24uZHVtcHMoeydvayc6IEZhbHNlLCAndG90YWwnOiAwLCAnZXJyb3JzJzogZXJyb3JzLCAnZm9sZGVycyc6IGZvbGRlcnNfZG9uZSwgJ21lc3NhZ2UnOiAnQXVjdW4gZW1haWwgdHJvdXbDqSd9KSkNCiAgICBzeXMuZXhpdCgwKQ0KDQogICMgQ29waWVyIGRhbnMgbGUgY29udGFpbmVyIGV0IGltcG9ydGVyDQogIHN1YnByb2Nlc3MucnVuKFsnZG9ja2VyJywgJ2V4ZWMnLCBDT05UQUlORVIsICdta2RpcicsICctcCcsICcvdG1wL2VtbF9yYiddLCBjYXB0dXJlX291dHB1dD1UcnVlKQ0KICBjcCA9IHN1YnByb2Nlc3MucnVuKFsnZG9ja2VyJywgJ2NwJywgVE1QRElSICsgJy8uJywgQ09OVEFJTkVSICsgJzovdG1wL2VtbF9yYi8nXSwgY2FwdHVyZV9vdXRwdXQ9VHJ1ZSkNCiAgciA9IHN1YnByb2Nlc3MucnVuKFsnZG9ja2VyJywgJ2V4ZWMnLCAnLXcnLCAnL3RtcCcsIENPTlRBSU5FUiwgJ3BpbGVyaW1wb3J0JywgJy1kJywgJy90bXAvZW1sX3JiJ10sIGNhcHR1cmVfb3V0cHV0PVRydWUsIHRleHQ9VHJ1ZSkNCiAgb3V0ID0gci5zdGRvdXQgKyByLnN0ZGVycg0KDQogICMgTmV0dG95ZXINCiAgaW1wb3J0IHNodXRpbA0KICBzaHV0aWwucm10cmVlKFRNUERJUiwgaWdub3JlX2Vycm9ycz1UcnVlKQ0KICBzdWJwcm9jZXNzLnJ1bihbJ2RvY2tlcicsICdleGVjJywgQ09OVEFJTkVSLCAncm0nLCAnLXJmJywgJy90bXAvZW1sX3JiJ10sIGNhcHR1cmVfb3V0cHV0PVRydWUpDQoNCiAgIyBQYXJzZXIgbGUgcsOpc3VsdGF0IHBpbGVyaW1wb3J0DQogIGltcG9ydGVkID0gMDsgZHVwID0gMDsgZXJyX2ltcCA9IDANCiAgaW1wb3J0IHJlDQogIG0gPSByZS5zZWFyY2gocidJbXBvcnRlZDpccyooXGQrKScsIG91dCkNCiAgaWYgbTogaW1wb3J0ZWQgPSBpbnQobS5ncm91cCgxKSkNCiAgbTIgPSByZS5zZWFyY2gocidbRGRddXBsaWNhdGU6XHMqKFxkKyknLCBvdXQpDQogIGlmIG0yOiBkdXAgPSBpbnQobTIuZ3JvdXAoMSkpDQogIG0zID0gcmUuc2VhcmNoKHInW0VlXXJyb3I6XHMqKFxkKyknLCBvdXQpDQogIGlmIG0zOiBlcnJfaW1wID0gaW50KG0zLmdyb3VwKDEpKQ0KICBpZiBpbXBvcnRlZCA9PSAwIGFuZCB0b3RhbCA+IDA6IGltcG9ydGVkID0gdG90YWwgICMgZmFsbGJhY2sgc2kgcGlsZXJpbXBvcnQgbmUgbG9nIHBhcw0KDQogIHByaW50KGpzb24uZHVtcHMoeydvayc6IFRydWUsICd0b3RhbCc6IHRvdGFsLCAnaW1wb3J0ZWQnOiBpbXBvcnRlZCwgJ2R1cGxpY2F0ZSc6IGR1cCwgJ2Vycm9ycyc6IGVycm9ycyArIGVycl9pbXAsICdmb2xkZXJzJzogZm9sZGVyc19kb25lfSkpDQoNCmV4Y2VwdCBFeGNlcHRpb24gYXMgZToNCiAgaW1wb3J0IHNodXRpbDsgc2h1dGlsLnJtdHJlZShUTVBESVIsIGlnbm9yZV9lcnJvcnM9VHJ1ZSkNCiAgcHJpbnQoanNvbi5kdW1wcyh7J29rJzogRmFsc2UsICdlcnJvcic6IHN0cihlKX0pKQ0KICBzeXMuZXhpdCgxKQ0KYDsNCg0KY29uc3QgcnVuSW1wb3J0QXN5bmMgPSAoc2lkLCB0eXBlLCB1c2VybmFtZSwgcGFzc3dvcmQsIGhvc3QsIHBvcnQpID0+IHsNCiAgY29uc3Qgc3RhcnRUaW1lPU1hdGguZmxvb3IoRGF0ZS5ub3coKS8xMDAwKTsNCiAgdHJ5IHsgZGJRdWVyeShgVVBEQVRFIGltcG9ydCBTRVQgc3RhdHVzPTEsc3RhcnRlZD0ke3N0YXJ0VGltZX0sZmluaXNoZWQ9MCxpbXBvcnRlZD0wLGR1cGxpY2F0ZT0wLGVycm9yPTAgV0hFUkUgaWQ9JHtwYXJzZUludChzaWQpfWApOyB9IGNhdGNoIHt9DQogIGNvbnN0IHB5U2NyaXB0PWJ1aWxkSW1wb3J0U2NyaXB0KHR5cGUsdXNlcm5hbWUscGFzc3dvcmQsaG9zdCxwb3J0LHBhcnNlSW50KHNpZCkpOw0KICBjb25zdCBweUZpbGU9YC90bXAvcmJfaW1wb3J0XyR7cGFyc2VJbnQoc2lkKX1fJHtEYXRlLm5vdygpfS5weWA7DQogIHRyeSB7IGZzLndyaXRlRmlsZVN5bmMocHlGaWxlLHB5U2NyaXB0KTsgfSBjYXRjaChlKXsgcmV0dXJuIGZhbHNlOyB9DQogIHJ1bkFzeW5jKCdweXRob24zJyxbcHlGaWxlXSkudGhlbihjaGlsZD0+ew0KICAgIGZzLnVubGluayhweUZpbGUsKCk9Pnt9KTsNCiAgICBjb25zdCBmaW5pc2hUaW1lPU1hdGguZmxvb3IoRGF0ZS5ub3coKS8xMDAwKTsNCiAgICBsZXQgaW1wb3J0ZWQ9MCxkdXA9MCxlcnI9MCxvaz1mYWxzZTsNCiAgICB0cnkgew0KICAgICAgY29uc3Qgcj1KU09OLnBhcnNlKChjaGlsZC5zdGRvdXR8fCcnKS50cmltKCkpOw0KICAgICAgaW1wb3J0ZWQ9ci5pbXBvcnRlZHx8ci50b3RhbHx8MDsNCiAgICAgIGR1cD1yLmR1cGxpY2F0ZXx8MDsNCiAgICAgIGVycj1yLmVycm9yc3x8MDsNCiAgICAgIC8vIG9rPXRydWUgc2kgcGFzIGQnZXJyZXVyIFB5dGhvbiAoZXhpdCAwKSDigJQgbGVzIGRvdWJsb25zIHNvbnQgdW4gc3VjY8Oocw0KICAgICAgb2s9Y2hpbGQuY29kZT09PTAmJiFyLmVycm9yOw0KICAgICAgLy8gU2F1dmVnYXJkZXIgbGVzIGRvc3NpZXJzIElNQVAgZGFucyByYl9pbWFwX2ZvbGRlcnMNCiAgICAgIGlmKEFycmF5LmlzQXJyYXkoci5mb2xkZXJzKSYmci5mb2xkZXJzLmxlbmd0aCl7DQogICAgICAgIGNvbnN0IHRzPU1hdGguZmxvb3IoRGF0ZS5ub3coKS8xMDAwKTsNCiAgICAgICAgZm9yKGNvbnN0IGYgb2Ygci5mb2xkZXJzKXsNCiAgICAgICAgICBjb25zdCBtPVN0cmluZyhmKS5tYXRjaCgvXiguKyk6KFxkKykkLyk7DQogICAgICAgICAgaWYobSl7DQogICAgICAgICAgICBjb25zdCBmbmFtZT1lc2MobVsxXSk7Y29uc3QgZmNvdW50PXBhcnNlSW50KG1bMl0pfHwwOw0KICAgICAgICAgICAgdHJ5e2RiUXVlcnkoYElOU0VSVCBJTlRPIHJiX2ltYXBfZm9sZGVycyAoc291cmNlX2lkLGZvbGRlcl9uYW1lLGVtYWlsX2NvdW50LHVwZGF0ZWRfYXQpIFZBTFVFUyAoJHtwYXJzZUludChzaWQpfSwnJHtmbmFtZX0nLCR7ZmNvdW50fSwke3RzfSkgT04gRFVQTElDQVRFIEtFWSBVUERBVEUgZW1haWxfY291bnQ9ZW1haWxfY291bnQrJHtmY291bnR9LHVwZGF0ZWRfYXQ9JHt0c31gKTt9Y2F0Y2h7fQ0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgICAgfQ0KICAgIH0gY2F0Y2ggeyBlcnI9MTsgfQ0KICAgIHRyeSB7IGRiUXVlcnkoYFVQREFURSBpbXBvcnQgU0VUIHN0YXR1cz0ke29rPzI6M30sZmluaXNoZWQ9JHtmaW5pc2hUaW1lfSxpbXBvcnRlZD0ke2ltcG9ydGVkfSxkdXBsaWNhdGU9JHtkdXB9LGVycm9yPSR7ZXJyfSBXSEVSRSBpZD0ke3BhcnNlSW50KHNpZCl9YCk7IH0gY2F0Y2gge30NCiAgfSk7DQogIHJldHVybiB0cnVlOw0KfTsNCg0Kcm91dGVzWydQT1NUIC92MS9zb3VyY2VzLzppZC9ydW4nXT1hc3luYyhyZXEscmVzLHtpZH0pPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICBsZXQgcm93Ow0KICB0cnkgew0KICAgIGNvbnN0IHJvd3M9ZGJSb3dzKGBTRUxFQ1QgaWQsdHlwZSx1c2VybmFtZSxwYXNzd29yZCxzZXJ2ZXIsc3RhdHVzLHN0YXJ0ZWQgRlJPTSBpbXBvcnQgV0hFUkUgaWQ9JHtwYXJzZUludChpZCl9YCk7DQogICAgaWYoIXJvd3MubGVuZ3RofHwhcm93c1swXVswXSkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J1NvdXJjZSBpbnRyb3V2YWJsZSd9LDQwNCk7DQogICAgcm93PXJvd3NbMF07DQogIH0gY2F0Y2goZSl7IHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTsgfQ0KICBjb25zdCBbc2lkLHR5cGUsdXNlcm5hbWUscGFzc3dvcmQsc2VydmVyLHJvd1N0YXR1cyxyb3dTdGFydGVkXT1yb3c7DQogIC8vIEltcG9ydCBvcnBoZWxpbiA6IHN0YXR1cz0xIG1haXMgZGVtYXJyw6kgaWwgeSBhID4gMTAgbWluIC0+IG9uIHJlbWV0IGEgMA0KICBjb25zdCBlbGFwc2VkPU1hdGguZmxvb3IoRGF0ZS5ub3coKS8xMDAwKS1wYXJzZUludChyb3dTdGFydGVkfHwwKTsNCiAgaWYocGFyc2VJbnQocm93U3RhdHVzKT09PTEgJiYgZWxhcHNlZD42MDApew0KICAgIHRyeSB7IGRiUXVlcnkoYFVQREFURSBpbXBvcnQgU0VUIHN0YXR1cz0wLHN0YXJ0ZWQ9MCxmaW5pc2hlZD0wIFdIRVJFIGlkPSR7cGFyc2VJbnQoaWQpfWApOyB9IGNhdGNoIHt9DQogIH0gZWxzZSBpZihwYXJzZUludChyb3dTdGF0dXMpPT09MSl7DQogICAgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6YEltcG9ydCBkZWphIGVuIGNvdXJzIChkZW1hcnJlIGlsIHkgYSAke2VsYXBzZWR9cykuIEF0dGVuZGV6IDEwIG1pbi5gfSw0MDkpOw0KICB9DQogIGlmKCFzZXJ2ZXJ8fCFzZXJ2ZXIuaW5jbHVkZXMoJzonKSkgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J0Zvcm1hdCBzZXJ2ZXVyIGludmFsaWRlIChob3N0OnBvcnQpJ30sNDAwKTsNCiAgY29uc3QgW2hvc3QscG9ydF09c2VydmVyLnNwbGl0KCc6Jyk7DQogIGNvbnN0IHN0YXJ0ZWQ9cnVuSW1wb3J0QXN5bmMoc2lkLHR5cGUsdXNlcm5hbWUscGFzc3dvcmQsaG9zdCxwb3J0KTsNCiAgaWYoIXN0YXJ0ZWQpIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidJbXBvc3NpYmxlIGRlIGNyZWVyIGxlIHNjcmlwdCBQeXRob24gdGVtcG9yYWlyZSd9LDUwMCk7DQogIGpzb24ocmVzLHtvazp0cnVlLG1lc3NhZ2U6J0ltcG9ydCBkZW1hcnJlIGVuIGFycmllcmUtcGxhbicsaWQ6cGFyc2VJbnQoaWQpfSk7DQp9Ow0KDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCi8vIExEQVAgKHRhYmxlIGxkYXApDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCnJvdXRlc1snR0VUIC92MS9sZGFwJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIHRyeSB7DQogICAgY29uc3Qgcm93cz1kYlJvd3MoJ1NFTEVDVCBpZCxkZXNjcmlwdGlvbixsZGFwX3R5cGUsbGRhcF9ob3N0LGxkYXBfYmFzZV9kbixsZGFwX2JpbmRfZG4sbGRhcF9tYWlsX2F0dHIsbGRhcF9hY2NvdW50X29iamVjdGNsYXNzIEZST00gbGRhcCBPUkRFUiBCWSBpZCcpOw0KICAgIGpzb24ocmVzLHtlbnRyaWVzOnJvd3MuZmlsdGVyKHI9PnIubGVuZ3RoPj02KS5tYXAocj0+KHtpZDpwYXJzZUludChyWzBdKSxkZXNjcmlwdGlvbjpyWzFdLHR5cGU6clsyXSxob3N0OnJbM10sYmFzZV9kbjpyWzRdLGJpbmRfZG46cls1XSxtYWlsX2F0dHI6cls2XXx8J21haWwnLG9iamVjdGNsYXNzOnJbN118fCdpbmV0T3JnUGVyc29uJ30pKX0pOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQpyb3V0ZXNbJ1BPU1QgL3YxL2xkYXAnXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgY29uc3Qge2Rlc2NyaXB0aW9uLGxkYXBfdHlwZT0nYWQnLGxkYXBfaG9zdCxsZGFwX2Jhc2VfZG4sbGRhcF9iaW5kX2RuLGxkYXBfYmluZF9wdz0nJyxsZGFwX21haWxfYXR0cj0nbWFpbCcsbGRhcF9hY2NvdW50X29iamVjdGNsYXNzPSdpbmV0T3JnUGVyc29uJ309YXdhaXQgcmVhZEJvZHkocmVxKTsNCiAgaWYoIWxkYXBfaG9zdHx8IWxkYXBfYmFzZV9kbnx8IWxkYXBfYmluZF9kbikgcmV0dXJuIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6J2hvc3QsIGJhc2VfZG4gZXQgYmluZF9kbiByZXF1aXMnfSw0MDApOw0KICB0cnkgew0KICAgIGRiUXVlcnkoYElOU0VSVCBJTlRPIGxkYXAgKGRlc2NyaXB0aW9uLGxkYXBfdHlwZSxsZGFwX2hvc3QsbGRhcF9iYXNlX2RuLGxkYXBfYmluZF9kbixsZGFwX2JpbmRfcHcsbGRhcF9tYWlsX2F0dHIsbGRhcF9hY2NvdW50X29iamVjdGNsYXNzKSBWQUxVRVMgKCcke2VzYyhkZXNjcmlwdGlvbnx8bGRhcF9ob3N0KX0nLCcke2VzYyhsZGFwX3R5cGUpfScsJyR7ZXNjKGxkYXBfaG9zdCl9JywnJHtlc2MobGRhcF9iYXNlX2RuKX0nLCcke2VzYyhsZGFwX2JpbmRfZG4pfScsJyR7ZXNjKGxkYXBfYmluZF9wdyl9JywnJHtlc2MobGRhcF9tYWlsX2F0dHIpfScsJyR7ZXNjKGxkYXBfYWNjb3VudF9vYmplY3RjbGFzcyl9JylgKTsNCiAgICBqc29uKHJlcyx7b2s6dHJ1ZX0sMjAxKTsNCiAgfSBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0Kcm91dGVzWydERUxFVEUgL3YxL2xkYXAvOmlkJ109YXN5bmMocmVxLHJlcyx7aWR9KT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgdHJ5IHsgZGJRdWVyeShgREVMRVRFIEZST00gbGRhcCBXSEVSRSBpZD0ke3BhcnNlSW50KGlkKX1gKTsganNvbihyZXMse29rOnRydWV9KTsgfQ0KICBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0KDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCi8vIFJFVEVOVElPTiBSVUxFUw0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQpyb3V0ZXNbJ0dFVCAvdjEvcmV0ZW50aW9uLXJ1bGVzJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIHRyeSB7DQogICAgY29uc3Qgcm93cz1kYlJvd3MoJ1NFTEVDVCBpZCxkb21haW4sZGF5cyxhY3Rpb24gRlJPTSByYl9yZXRlbnRpb25fcnVsZSBPUkRFUiBCWSBpZCcpOw0KICAgIGpzb24ocmVzLHtydWxlczpyb3dzLmZpbHRlcihyPT5yLmxlbmd0aD49NCkubWFwKHI9Pih7aWQ6cGFyc2VJbnQoclswXSksZG9tYWluOnJbMV18fCcnLGRheXM6cGFyc2VJbnQoclsyXSl8fDM2NSxhY3Rpb246clszXXx8J2RlbGV0ZSd9KSl9KTsNCiAgfSBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0Kcm91dGVzWydQT1NUIC92MS9yZXRlbnRpb24tcnVsZXMnXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgY29uc3Qge2RvbWFpbj0nJyxkYXlzPTM2NSxhY3Rpb249J2RlbGV0ZSd9PWF3YWl0IHJlYWRCb2R5KHJlcSk7DQogIHRyeSB7DQogICAgZGJRdWVyeShgSU5TRVJUIElOVE8gcmJfcmV0ZW50aW9uX3J1bGUgKGRvbWFpbixkYXlzLGFjdGlvbixjcmVhdGVkX2F0KSBWQUxVRVMgKCcke2VzYyhkb21haW4pfScsJHtwYXJzZUludChkYXlzKXx8MzY1fSwnJHtlc2MoYWN0aW9uKX0nLCR7bm93KCl9KWApOw0KICAgIGpzb24ocmVzLHtvazp0cnVlfSwyMDEpOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQpyb3V0ZXNbJ0RFTEVURSAvdjEvcmV0ZW50aW9uLXJ1bGVzLzppZCddPWFzeW5jKHJlcSxyZXMse2lkfSk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIHRyeSB7IGRiUXVlcnkoYERFTEVURSBGUk9NIHJiX3JldGVudGlvbl9ydWxlIFdIRVJFIGlkPSR7cGFyc2VJbnQoaWQpfWApOyBqc29uKHJlcyx7b2s6dHJ1ZX0pOyB9DQogIGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQoNCi8vIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkA0KLy8gQVJDSElWSU5HIFJVTEVTDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCnJvdXRlc1snR0VUIC92MS9hcmNoaXZpbmctcnVsZXMnXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgdHJ5IHsNCiAgICBjb25zdCByb3dzPWRiUm93cygnU0VMRUNUIGlkLHNyY19kb21haW4sc3ViamVjdF9maWx0ZXIsZHN0X2ZvbGRlcixhY3Rpb24gRlJPTSByYl9hcmNoaXZpbmdfcnVsZSBPUkRFUiBCWSBpZCcpOw0KICAgIGpzb24ocmVzLHtydWxlczpyb3dzLmZpbHRlcihyPT5yLmxlbmd0aD49NSkubWFwKHI9Pih7aWQ6cGFyc2VJbnQoclswXSksc3JjX2RvbWFpbjpyWzFdfHwnJyxzdWJqZWN0X2ZpbHRlcjpyWzJdfHwnJyxkc3RfZm9sZGVyOnJbM118fCcnLGFjdGlvbjpyWzRdfHwnYXJjaGl2ZSd9KSl9KTsNCiAgfSBjYXRjaChlKXtqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOmUubWVzc2FnZX0sNTAwKTt9DQp9Ow0Kcm91dGVzWydQT1NUIC92MS9hcmNoaXZpbmctcnVsZXMnXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgY29uc3Qge3NyY19kb21haW49Jycsc3ViamVjdF9maWx0ZXI9JycsZHN0X2ZvbGRlcj0nJyxhY3Rpb249J2FyY2hpdmUnfT1hd2FpdCByZWFkQm9keShyZXEpOw0KICB0cnkgew0KICAgIGRiUXVlcnkoYElOU0VSVCBJTlRPIHJiX2FyY2hpdmluZ19ydWxlIChzcmNfZG9tYWluLHN1YmplY3RfZmlsdGVyLGRzdF9mb2xkZXIsYWN0aW9uLGNyZWF0ZWRfYXQpIFZBTFVFUyAoJyR7ZXNjKHNyY19kb21haW4pfScsJyR7ZXNjKHN1YmplY3RfZmlsdGVyKX0nLCcke2VzYyhkc3RfZm9sZGVyKX0nLCcke2VzYyhhY3Rpb24pfScsJHtub3coKX0pYCk7DQogICAganNvbihyZXMse29rOnRydWV9LDIwMSk7DQogIH0gY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCnJvdXRlc1snREVMRVRFIC92MS9hcmNoaXZpbmctcnVsZXMvOmlkJ109YXN5bmMocmVxLHJlcyx7aWR9KT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgdHJ5IHsgZGJRdWVyeShgREVMRVRFIEZST00gcmJfYXJjaGl2aW5nX3J1bGUgV0hFUkUgaWQ9JHtwYXJzZUludChpZCl9YCk7IGpzb24ocmVzLHtvazp0cnVlfSk7IH0NCiAgY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQovLyBMRUdBTCBIT0xEDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCnJvdXRlc1snR0VUIC92MS9sZWdhbC1ob2xkJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIHRyeSB7DQogICAgY29uc3Qgcm93cz1kYlJvd3MoJ1NFTEVDVCBlbWFpbCxjcmVhdGVkX2F0IEZST00gbGVnYWxfaG9sZCBPUkRFUiBCWSBlbWFpbCcpOw0KICAgIGpzb24ocmVzLHtlbnRyaWVzOnJvd3MuZmlsdGVyKHI9PnJbMF0pLm1hcChyPT4oe2VtYWlsOnJbMF0sY3JlYXRlZDpwYXJzZUludChyWzFdKXx8bnVsbH0pKX0pOw0KICB9DQogIGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQpyb3V0ZXNbJ1BPU1QgL3YxL2xlZ2FsLWhvbGQnXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgY29uc3Qge2VtYWlsfT1hd2FpdCByZWFkQm9keShyZXEpOw0KICBpZighZW1haWwpIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidlbWFpbCByZXF1aXMnfSw0MDApOw0KICB0cnkgeyBkYlF1ZXJ5KGBJTlNFUlQgSUdOT1JFIElOVE8gbGVnYWxfaG9sZCAoZW1haWwsY3JlYXRlZF9hdCkgVkFMVUVTICgnJHtlc2MoZW1haWwpfScsJHtub3coKX0pYCk7IGpzb24ocmVzLHtvazp0cnVlfSwyMDEpOyB9DQogIGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQpyb3V0ZXNbJ0RFTEVURSAvdjEvbGVnYWwtaG9sZC86ZW1haWwnXT1hc3luYyhyZXEscmVzLHtlbWFpbH0pPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICB0cnkgeyBkYlF1ZXJ5KGBERUxFVEUgRlJPTSBsZWdhbF9ob2xkIFdIRVJFIGVtYWlsPScke2VzYyhkZWNvZGVVUklDb21wb25lbnQoZW1haWwpKX0nYCk7IGpzb24ocmVzLHtvazp0cnVlfSk7IH0NCiAgY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQovLyBBVURJVA0KLy8gYWN0aW9uOiAwPWxvZ2luLDE9c2VhcmNoLDI9dmlldywzPWV4cG9ydCw0PWRlbGV0ZSw1PXJlc3RvcmUsNj1kb3dubG9hZCw3PXByaW50LDg9Zm9yd2FyZA0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQpjb25zdCBBVURJVF9MQUJFTFM9ezA6J2xvZ2luJywxOidzZWFyY2gnLDI6J3ZpZXcnLDM6J2V4cG9ydCcsNDonZGVsZXRlJyw1OidyZXN0b3JlJyw2Oidkb3dubG9hZCcsNzoncHJpbnQnLDg6J2ZvcndhcmQnLDk6J2Fzc2lnbid9Ow0Kcm91dGVzWydHRVQgL3YxL2F1ZGl0J109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IHE9cmVxLnF1ZXJ5LGxpbWl0PU1hdGgubWluKDIwMCxwYXJzZUludChxLmxpbWl0fHwnNTAnKSksb2Zmc2V0PU1hdGgubWF4KDAscGFyc2VJbnQocS5wYWdlfHwnMCcpKSpsaW1pdDsNCiAgbGV0IHdoZXJlPSdXSEVSRSAxPTEnOw0KICBpZihxLmVtYWlsKSAgd2hlcmUrPWAgQU5EIChlbWFpbCBMSUtFICclJHtlc2MocS5lbWFpbCl9JScgT1IgZG9tYWluIExJS0UgJyUke2VzYyhxLmVtYWlsKX0lJylgOw0KICBpZihxLmFjdGlvbikgeyBjb25zdCBpZHg9T2JqZWN0LmVudHJpZXMoQVVESVRfTEFCRUxTKS5maW5kKChbLHZdKT0+dj09PXEuYWN0aW9uKT8uWzBdOyBpZihpZHghPT11bmRlZmluZWQpIHdoZXJlKz1gIEFORCBhY3Rpb249JHtwYXJzZUludChpZHgpfWA7IH0NCiAgaWYocS5zdGFydCkgIHdoZXJlKz1gIEFORCB0cz49JHtwYXJzZUludChxLnN0YXJ0KX1gOw0KICBpZihxLmVuZCkgICAgd2hlcmUrPWAgQU5EIHRzPD0ke3BhcnNlSW50KHEuZW5kKX1gOw0KICB0cnkgew0KICAgIGNvbnN0IHRvdGFsPXBhcnNlSW50KChkYlJvd3MoYFNFTEVDVCBDT1VOVCgqKSBGUk9NIGF1ZGl0ICR7d2hlcmV9YClbMF18fFtdKVswXSl8fDA7DQogICAgY29uc3Qgcm93cz1kYlJvd3MoYFNFTEVDVCBpZCx0cyxlbWFpbCxkb21haW4sYWN0aW9uLGlwYWRkcixkZXNjcmlwdGlvbiBGUk9NIGF1ZGl0ICR7d2hlcmV9IE9SREVSIEJZIHRzIERFU0MgTElNSVQgJHtsaW1pdH0gT0ZGU0VUICR7b2Zmc2V0fWApOw0KICAgIGpzb24ocmVzLHt0b3RhbCxlbnRyaWVzOnJvd3MuZmlsdGVyKHI9PnIubGVuZ3RoPj02KS5tYXAocj0+KHtpZDpwYXJzZUludChyWzBdKSx0czpyWzFdJiZyWzFdIT09J05VTEwnP25ldyBEYXRlKHBhcnNlSW50KHJbMV0pKjEwMDApLnRvSVNPU3RyaW5nKCk6bnVsbCxlbWFpbDpyWzJdfHwn4oCUJyxkb21haW46clszXXx8J+KAlCcsYWN0aW9uOkFVRElUX0xBQkVMU1twYXJzZUludChyWzRdKV18fGBhY3Rpb25fJHtyWzRdfWAsaXBhZGRyOnJbNV18fCfigJQnLGRlc2NyaXB0aW9uOnJbNl18fCcnfSkpfSk7DQogIH0gY2F0Y2goZSl7anNvbihyZXMse2VudHJpZXM6W10sZXJyb3I6ZS5tZXNzYWdlfSk7fQ0KfTsNCg0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQovLyBQQVJBTcOIVFJFUyAob3B0aW9uOiBrZXksIHZhbHVlKSArIGN1c3RvbWVyX3NldHRpbmdzDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCnJvdXRlc1snR0VUIC92MS9zZXR0aW5ncyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICB0cnkgew0KICAgIGNvbnN0IHJvd3M9ZGJSb3dzKCdTRUxFQ1QgYGtleWAsdmFsdWUgRlJPTSBgb3B0aW9uYCcpOw0KICAgIGNvbnN0IHM9e307cm93cy5maWx0ZXIocj0+ci5sZW5ndGg+PTIpLmZvckVhY2gocj0+e3NbclswXV09clsxXTt9KTsNCiAgICBzLl9kb21haW49RE9NQUlOO3MuX2x4Y19pcD1MWENfSVA7cy5fYWNjb3VudF9pZD1BQ0NPVU5UX0lEO3MuX3ZlcnNpb249VkVSU0lPTjsNCiAgICBqc29uKHJlcyx7c2V0dGluZ3M6c30pOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQpyb3V0ZXNbJ1BBVENIIC92MS9zZXR0aW5ncyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICBjb25zdCBib2R5PWF3YWl0IHJlYWRCb2R5KHJlcSk7DQogIGNvbnN0IGFsbG93ZWQ9WydyZXRlbnRpb25fZGF5cycsJ21heF9tc2dfc2l6ZScsJ2VuYWJsZV9hdWRpdCcsJ2RpZ2VzdF9kYXlzJywnaG9zdG5hbWUnLCdkcG9fZW1haWwnLCdzbXRwX3JlbGF5JywnY29tcGFueV9uYW1lJ107DQogIHRyeSB7DQogICAgZm9yKGNvbnN0IFtrLHZdIG9mIE9iamVjdC5lbnRyaWVzKGJvZHkpKXsNCiAgICAgIGlmKCFhbGxvd2VkLmluY2x1ZGVzKGspKWNvbnRpbnVlOw0KICAgICAgY29uc3QgdmFsPVN0cmluZyh2KS5zbGljZSgwLDMxKTsgLy8gb3B0aW9uLnZhbHVlIGVzdCBjaGFyKDMyKQ0KICAgICAgZGJRdWVyeShgREVMRVRFIEZST00gXGBvcHRpb25cYCBXSEVSRSBcYGtleVxgPScke2VzYyhrKX0nYCk7DQogICAgICBkYlF1ZXJ5KGBJTlNFUlQgSU5UTyBcYG9wdGlvblxgIChcYGtleVxgLHZhbHVlKSBWQUxVRVMgKCcke2VzYyhrKX0nLCcke2VzYyh2YWwpfScpYCk7DQogICAgfQ0KICAgIGpzb24ocmVzLHtvazp0cnVlfSk7DQogIH0gY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0KLy8g4pSA4pSA4pSAIEFkcmVzc2UgZCdhcmNoaXZhZ2UgKGFyY2hpdmVfYWRkcmVzcyBkYW5zIHBpbGVyLmNvbmYpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgA0Kcm91dGVzWydHRVQgL3YxL3BpbGVyL2FyY2hpdmUtYWRkcmVzcyddPWFzeW5jKHJlcSxyZXMpPT57DQogIGlmKCFyZXF1aXJlQWRtaW4ocmVxLHJlcykpcmV0dXJuOw0KICB0cnkgew0KICAgIGNvbnN0IHJvd3M9ZGJSb3dzKCJTRUxFQ1QgdmFsdWUgRlJPTSBgb3B0aW9uYCBXSEVSRSBga2V5YD0nYXJjaGl2ZV9hZGRyZXNzJyIpOw0KICAgIGNvbnN0IGFkZHI9KHJvd3MubGVuZ3RoJiZyb3dzWzBdWzBdJiZyb3dzWzBdWzBdIT09J05VTEwnKT9yb3dzWzBdWzBdOicnOw0KICAgIGpzb24ocmVzLHthcmNoaXZlX2FkZHJlc3M6YWRkcn0pOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHthcmNoaXZlX2FkZHJlc3M6JycsZXJyb3I6ZS5tZXNzYWdlfSk7fQ0KfTsNCnJvdXRlc1snUE9TVCAvdjEvcGlsZXIvYXJjaGl2ZS1hZGRyZXNzJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IHthcmNoaXZlX2FkZHJlc3M9Jyd9PWF3YWl0IHJlYWRCb2R5KHJlcSk7DQogIHRyeSB7DQogICAgZGJRdWVyeShgSU5TRVJUIElOVE8gXGBvcHRpb25cYCAoXGBrZXlcYCx2YWx1ZSkgVkFMVUVTICgnYXJjaGl2ZV9hZGRyZXNzJywnJHtlc2MoYXJjaGl2ZV9hZGRyZXNzLnRyaW0oKSl9JykgT04gRFVQTElDQVRFIEtFWSBVUERBVEUgdmFsdWU9JyR7ZXNjKGFyY2hpdmVfYWRkcmVzcy50cmltKCkpfSdgKTsNCiAgICBqc29uKHJlcyx7b2s6dHJ1ZSxhcmNoaXZlX2FkZHJlc3M6YXJjaGl2ZV9hZGRyZXNzLnRyaW0oKX0pOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn07DQoNCi8vIOKUgOKUgOKUgCBDb25maWcgY29tcGzDqHRlIGRlIGwnaW5zdGFuY2Ug4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQpyb3V0ZXNbJ0dFVCAvdjEvcGlsZXIvY29uZmlnJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIHRyeSB7DQogICAgY29uc3Qgcm93cz1kYlJvd3MoJ1NFTEVDVCBga2V5YCx2YWx1ZSBGUk9NIGBvcHRpb25gJyk7DQogICAgY29uc3Qgb3B0cz17fTtyb3dzLmZpbHRlcihyPT5yLmxlbmd0aD49MiYmclswXSkuZm9yRWFjaChyPT57b3B0c1tyWzBdXT1yWzFdO30pOw0KICAgIC8vIEluZm9zIExYQyBpbmplY3TDqWVzDQogICAgY29uc3Qgcj1zcGF3blN5bmMoJ2RmJyxbJy1oJywnLyddLHtlbmNvZGluZzondXRmOCcsdGltZW91dDozMDAwfSk7DQogICAgbGV0IGRpc2s9e3VzZWQ6Jz8nLHRvdGFsOic/JyxwZXJjZW50Oic/J307DQogICAgaWYoci5zdGRvdXQpew0KICAgICAgY29uc3QgbGluZXM9ci5zdGRvdXQudHJpbSgpLnNwbGl0KCdcbicpOw0KICAgICAgaWYobGluZXNbMV0pe2NvbnN0IHA9bGluZXNbMV0uc3BsaXQoL1xzKy8pO2Rpc2s9e3RvdGFsOnBbMV18fCc/Jyx1c2VkOnBbMl18fCc/JyxhdmFpbDpwWzNdfHwnPycscGVyY2VudDpwWzRdfHwnPyd9O30NCiAgICB9DQogICAganNvbihyZXMse2NvbmZpZzp7DQogICAgICAuLi5vcHRzLA0KICAgICAgX3ZlcnNpb246VkVSU0lPTiwgX2FjY291bnRfaWQ6QUNDT1VOVF9JRCwgX2RvbWFpbjpET01BSU4sIF9seGNfaXA6TFhDX0lQLA0KICAgICAgX3BpbGVyX2NvbnRhaW5lcjpQSUxFUl9OQU1FLCBfZGJfY29udGFpbmVyOkRCX05BTUUsDQogICAgICBfZGlzazpkaXNrLA0KICAgICAgX2JyaWRnZV91cHRpbWU6TWF0aC5mbG9vcihwcm9jZXNzLnVwdGltZSgpKSsncycsDQogICAgICBfbm9kZV92ZXJzaW9uOnByb2Nlc3MudmVyc2lvbiwNCiAgICB9fSk7DQogIH0gY2F0Y2goZSl7anNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTplLm1lc3NhZ2V9LDUwMCk7fQ0KfTsNCg0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQovLyBJTVBPUlQgR0xPQkFMDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCnJvdXRlc1snUE9TVCAvdjEvaW1wb3J0L3RyaWdnZXInXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgbGV0IHNvdXJjZXM9W107DQogIHRyeSB7IHNvdXJjZXM9ZGJSb3dzKCdTRUxFQ1QgaWQsdHlwZSx1c2VybmFtZSxwYXNzd29yZCxzZXJ2ZXIgRlJPTSBpbXBvcnQgV0hFUkUgc3RhdHVzPTAgT1JERVIgQlkgaWQnKTsgfSBjYXRjaCB7fQ0KICBjb25zdCByb3dzPXNvdXJjZXMuZmlsdGVyKHI9PnJbMF0mJnJbNF0mJnJbNF0uaW5jbHVkZXMoJzonKSk7DQogIGlmKCFyb3dzLmxlbmd0aCkgcmV0dXJuIGpzb24ocmVzLHtvazp0cnVlLG1lc3NhZ2U6J0F1Y3VuZSBzb3VyY2Ugw6AgZMOpY2xlbmNoZXInLHRyaWdnZXJlZDowfSk7DQoNCiAgLy8gTGFuY2VyIGNoYXF1ZSBzb3VyY2UgZW4gYXJyacOocmUtcGxhbiAobcOqbWUgbG9naXF1ZSBxdWUgL3J1bikNCiAganNvbihyZXMse29rOnRydWUsbWVzc2FnZTpgJHtyb3dzLmxlbmd0aH0gc291cmNlKHMpIGTDqWNsZW5jaMOpZShzKSBlbiBhcnJpw6hyZS1wbGFuYCx0cmlnZ2VyZWQ6cm93cy5sZW5ndGh9KTsNCg0KICBmb3IoY29uc3Qgcm93IG9mIHJvd3Mpew0KICAgIGNvbnN0IFtzaWQsdHlwZSx1c2VybmFtZSxwYXNzd29yZCxzZXJ2ZXJdPXJvdzsNCiAgICBjb25zdCBbaG9zdCxwb3J0XT1zZXJ2ZXIuc3BsaXQoJzonKTsNCiAgICBjb25zdCBzdGFydFRpbWU9TWF0aC5mbG9vcihEYXRlLm5vdygpLzEwMDApOw0KICAgIHRyeSB7IGRiUXVlcnkoYFVQREFURSBpbXBvcnQgU0VUIHN0YXR1cz0xLHN0YXJ0ZWQ9JHtzdGFydFRpbWV9LGZpbmlzaGVkPTAsaW1wb3J0ZWQ9MCxkdXBsaWNhdGU9MCxlcnJvcj0wIFdIRVJFIGlkPSR7cGFyc2VJbnQoc2lkKX1gKTsgfSBjYXRjaCB7fQ0KICAgIGNvbnN0IHB5U2NyaXB0PWJ1aWxkSW1wb3J0U2NyaXB0KHR5cGUsdXNlcm5hbWUscGFzc3dvcmQsaG9zdCxwb3J0LHBhcnNlSW50KHNpZCkpOw0KICAgIGNvbnN0IHB5RmlsZT1gL3RtcC9yYl9pbXBvcnRfJHtwYXJzZUludChzaWQpfV8ke0RhdGUubm93KCl9LnB5YDsNCiAgICB0cnkgeyBmcy53cml0ZUZpbGVTeW5jKHB5RmlsZSxweVNjcmlwdCk7IH0gY2F0Y2ggeyBjb250aW51ZTsgfQ0KICAgIHJ1bkFzeW5jKCdweXRob24zJyxbcHlGaWxlXSkudGhlbihjaGlsZD0+ew0KICAgICAgZnMudW5saW5rKHB5RmlsZSwoKT0+e30pOw0KICAgICAgY29uc3QgZmluaXNoVGltZT1NYXRoLmZsb29yKERhdGUubm93KCkvMTAwMCk7DQogICAgICBsZXQgaW1wb3J0ZWQ9MCxkdXA9MCxlcnI9MCxvaz1mYWxzZTsNCiAgICAgIHRyeSB7IGNvbnN0IHI9SlNPTi5wYXJzZSgoY2hpbGQuc3Rkb3V0fHwnJykudHJpbSgpKTtvaz1yLm9rfHxmYWxzZTtpbXBvcnRlZD1yLmltcG9ydGVkfHxyLnRvdGFsfHwwO2R1cD1yLmR1cGxpY2F0ZXx8MDtlcnI9ci5lcnJvcnN8fDA7IH0gY2F0Y2ggeyBlcnI9MTsgfQ0KICAgICAgdHJ5IHsgZGJRdWVyeShgVVBEQVRFIGltcG9ydCBTRVQgc3RhdHVzPSR7b2s/MjozfSxmaW5pc2hlZD0ke2ZpbmlzaFRpbWV9LGltcG9ydGVkPSR7aW1wb3J0ZWR9LGR1cGxpY2F0ZT0ke2R1cH0sZXJyb3I9JHtlcnJ9IFdIRVJFIGlkPSR7cGFyc2VJbnQoc2lkKX1gKTsgfSBjYXRjaCB7fQ0KICAgIH0pOw0KICB9DQp9Ow0KDQoNCi8vIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkA0KLy8gU01UUCBTw4lDVVJJVMOJIOKAlCBHZXN0aW9uIGlwdGFibGVzIHBvcnQgMjUNCi8vIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkA0KLy8gR0VUICAvdjEvc210cC9ydWxlcyAgICDihpIgbGlzdGUgZGVzIElQcyBhdXRvcmlzw6llcyBzdXIgcG9ydCAyNQ0KLy8gUE9TVCAvdjEvc210cC9ydWxlcyAgICDihpIgYWpvdXRlciB1bmUgSVAgYXV0b3Jpc8OpZQ0KLy8gREVMRVRFIC92MS9zbXRwL3J1bGVzLzppcCDihpIgc3VwcHJpbWVyIHVuZSBJUA0KLy8gUE9TVCAvdjEvc210cC9hcHBseSAgICDihpIgYXBwbGlxdWVyIGxlcyByw6hnbGVzIGlwdGFibGVzIChibG9xdWUgdG91dCBzYXVmIElQcyB3aGl0ZWxpc3TDqWVzKQ0KLy8gUE9TVCAvdjEvc210cC9vcGVuICAgICDihpIgb3V2cmlyIHRlbXBvcmFpcmVtZW50IChtb2RlIGRlYnVnIOKAlCA1IG1pbiBtYXgpDQoNCmNvbnN0IFNNVFBfV0hJVEVMSVNUX0ZJTEUgPSAnL29wdC9yZWJvb3RseS9zbXRwLXdoaXRlbGlzdC5qc29uJzsNCg0KY29uc3QgbG9hZFNtdHBXaGl0ZWxpc3QgPSAoKSA9PiB7DQogIHRyeSB7IHJldHVybiBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhTTVRQX1dISVRFTElTVF9GSUxFLCd1dGY4JykpOyB9DQogIGNhdGNoIHsgcmV0dXJuIFtdOyB9DQp9Ow0KY29uc3Qgc2F2ZVNtdHBXaGl0ZWxpc3QgPSAobGlzdCkgPT4gew0KICBmcy53cml0ZUZpbGVTeW5jKFNNVFBfV0hJVEVMSVNUX0ZJTEUsIEpTT04uc3RyaW5naWZ5KGxpc3QsbnVsbCwyKSk7DQp9Ow0KY29uc3QgYXBwbHlTbXRwUnVsZXMgPSAod2hpdGVsaXN0KSA9PiB7DQogIC8vIFN1cHByaW1lciBsZXMgcsOoZ2xlcyBleGlzdGFudGVzIHBvdXIgcG9ydCAyNQ0KICBzcGF3blN5bmMoJ2lwdGFibGVzJyxbJy1EJywnSU5QVVQnLCctcCcsJ3RjcCcsJy0tZHBvcnQnLCcyNScsJy1qJywnQUNDRVBUJ10se3RpbWVvdXQ6MzAwMH0pOw0KICBzcGF3blN5bmMoJ2lwdGFibGVzJyxbJy1EJywnSU5QVVQnLCctcCcsJ3RjcCcsJy0tZHBvcnQnLCcyNScsJy1qJywnRFJPUCddLHt0aW1lb3V0OjMwMDB9KTsNCiAgLy8gRmx1c2ggbGVzIHLDqGdsZXMgc3DDqWNpZmlxdWVzIHBvcnQgMjUNCiAgY29uc3QgZmx1c2g9c3Bhd25TeW5jKCdiYXNoJyxbJy1jJywiaXB0YWJsZXMgLUwgSU5QVVQgLS1saW5lLW51bWJlcnMgLW4gfCBncmVwICdkcHQ6MjUnIHwgYXdrICd7cHJpbnQgJDF9JyB8IHNvcnQgLXJuIHwgeGFyZ3MgLUl7fSBpcHRhYmxlcyAtRCBJTlBVVCB7fSJdLHt0aW1lb3V0OjUwMDAsZW5jb2Rpbmc6J3V0ZjgnfSk7DQoNCiAgaWYod2hpdGVsaXN0Lmxlbmd0aD09PTApIHsNCiAgICAvLyBBdWN1bmUgSVAgd2hpdGVsaXN0w6llIOKGkiBibG9xdWVyIHRvdXQgbGUgcG9ydCAyNQ0KICAgIHNwYXduU3luYygnaXB0YWJsZXMnLFsnLUEnLCdJTlBVVCcsJy1wJywndGNwJywnLS1kcG9ydCcsJzI1JywnLWonLCdEUk9QJ10se3RpbWVvdXQ6MzAwMH0pOw0KICAgIHJldHVybiB7YXBwbGllZDp0cnVlLG1vZGU6J2Jsb2NrZWQnLGlwczpbXX07DQogIH0NCg0KICAvLyBBdXRvcmlzZXIgdW5pcXVlbWVudCBsZXMgSVBzIHdoaXRlbGlzdMOpZXMNCiAgZm9yKGNvbnN0IGlwIG9mIHdoaXRlbGlzdCkgew0KICAgIHNwYXduU3luYygnaXB0YWJsZXMnLFsnLUEnLCdJTlBVVCcsJy1wJywndGNwJywnLS1kcG9ydCcsJzI1JywnLXMnLGlwLCctaicsJ0FDQ0VQVCddLHt0aW1lb3V0OjMwMDB9KTsNCiAgfQ0KICAvLyBCbG9xdWVyIGxlIHJlc3RlIHN1ciBwb3J0IDI1DQogIHNwYXduU3luYygnaXB0YWJsZXMnLFsnLUEnLCdJTlBVVCcsJy1wJywndGNwJywnLS1kcG9ydCcsJzI1JywnLWonLCdEUk9QJ10se3RpbWVvdXQ6MzAwMH0pOw0KICByZXR1cm4ge2FwcGxpZWQ6dHJ1ZSxtb2RlOid3aGl0ZWxpc3QnLGlwczp3aGl0ZWxpc3R9Ow0KfTsNCg0Kcm91dGVzWydHRVQgL3YxL3NtdHAvcnVsZXMnXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgY29uc3QgbGlzdD1sb2FkU210cFdoaXRlbGlzdCgpOw0KICAvLyBMaXJlIGxlcyByw6hnbGVzIGlwdGFibGVzIGFjdHVlbGxlcyBwb3VyIHBvcnQgMjUNCiAgY29uc3Qgcj1zcGF3blN5bmMoJ2Jhc2gnLFsnLWMnLCJpcHRhYmxlcyAtTCBJTlBVVCAtbiB8IGdyZXAgJ2RwdDoyNSciXSx7dGltZW91dDo1MDAwLGVuY29kaW5nOid1dGY4J30pOw0KICBjb25zdCBjdXJyZW50X3J1bGVzPShyLnN0ZG91dHx8JycpLnRyaW0oKS5zcGxpdCgnXG4nKS5maWx0ZXIoQm9vbGVhbik7DQogIGpzb24ocmVzLHt3aGl0ZWxpc3Q6bGlzdCxpcHRhYmxlc19ydWxlczpjdXJyZW50X3J1bGVzLG1vZGU6bGlzdC5sZW5ndGg9PT0wPydibG9ja2VkJzond2hpdGVsaXN0J30pOw0KfTsNCg0Kcm91dGVzWydQT1NUIC92MS9zbXRwL3J1bGVzJ109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IHtpcCxkZXNjcmlwdGlvbj0nJ309YXdhaXQgcmVhZEJvZHkocmVxKTsNCiAgaWYoIWlwfHwhL15cZHsxLDN9XC5cZHsxLDN9XC5cZHsxLDN9XC5cZHsxLDN9KFwvXGR7MSwyfSk/JC8udGVzdChpcC50cmltKCkpKQ0KICAgIHJldHVybiBqc29uKHJlcyx7ZXJyb3I6dHJ1ZSxtZXNzYWdlOidJUCBvdSBDSURSIGludmFsaWRlIChleDogOTEuMjM0LjU2Ljc4IG91IDkxLjIzNC41Ni4wLzI0KSd9LDQwMCk7DQogIGNvbnN0IGxpc3Q9bG9hZFNtdHBXaGl0ZWxpc3QoKTsNCiAgaWYobGlzdC5maW5kKGU9PmUuaXA9PT1pcC50cmltKCkpKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonSVAgZMOpasOgIHByw6lzZW50ZSd9LDQwOSk7DQogIGxpc3QucHVzaCh7aXA6aXAudHJpbSgpLGRlc2NyaXB0aW9uLGFkZGVkOk1hdGguZmxvb3IoRGF0ZS5ub3coKS8xMDAwKX0pOw0KICBzYXZlU210cFdoaXRlbGlzdChsaXN0KTsNCiAgY29uc3QgcmVzdWx0PWFwcGx5U210cFJ1bGVzKGxpc3QubWFwKGU9PmUuaXApKTsNCiAganNvbihyZXMse29rOnRydWUsLi4ucmVzdWx0LG1lc3NhZ2U6YElQICR7aXAudHJpbSgpfSBham91dMOpZSBldCByw6hnbGVzIGFwcGxpcXXDqWVzYH0sMjAxKTsNCn07DQoNCnJvdXRlc1snREVMRVRFIC92MS9zbXRwL3J1bGVzLzppcCddPWFzeW5jKHJlcSxyZXMse2lwfSk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IGRlY29kZWRJcD1kZWNvZGVVUklDb21wb25lbnQoaXApOw0KICBsZXQgbGlzdD1sb2FkU210cFdoaXRlbGlzdCgpOw0KICBjb25zdCBiZWZvcmU9bGlzdC5sZW5ndGg7DQogIGxpc3Q9bGlzdC5maWx0ZXIoZT0+ZS5pcCE9PWRlY29kZWRJcCk7DQogIGlmKGxpc3QubGVuZ3RoPT09YmVmb3JlKSByZXR1cm4ganNvbihyZXMse2Vycm9yOnRydWUsbWVzc2FnZTonSVAgbm9uIHRyb3V2w6llJ30sNDA0KTsNCiAgc2F2ZVNtdHBXaGl0ZWxpc3QobGlzdCk7DQogIGNvbnN0IHJlc3VsdD1hcHBseVNtdHBSdWxlcyhsaXN0Lm1hcChlPT5lLmlwKSk7DQogIGpzb24ocmVzLHtvazp0cnVlLC4uLnJlc3VsdCxtZXNzYWdlOmBJUCAke2RlY29kZWRJcH0gc3VwcHJpbcOpZSDigJQgcG9ydCAyNSAke2xpc3QubGVuZ3RoPT09MD8nYmxvcXXDqSc6J3Jlc3RyZWludCd9YH0pOw0KfTsNCg0Kcm91dGVzWydQT1NUIC92MS9zbXRwL2FwcGx5J109YXN5bmMocmVxLHJlcyk9PnsNCiAgaWYoIXJlcXVpcmVBZG1pbihyZXEscmVzKSlyZXR1cm47DQogIGNvbnN0IGxpc3Q9bG9hZFNtdHBXaGl0ZWxpc3QoKTsNCiAgY29uc3QgcmVzdWx0PWFwcGx5U210cFJ1bGVzKGxpc3QubWFwKGU9PmUuaXApKTsNCiAganNvbihyZXMse29rOnRydWUsLi4ucmVzdWx0fSk7DQp9Ow0KDQovLyBQZXJzaXN0YW5jZSBpcHRhYmxlcyBhdSByZWJvb3QgKHNhdXZlZ2FyZGUgZGFucyBpcHRhYmxlcy1wZXJzaXN0ZW50KQ0Kcm91dGVzWydQT1NUIC92MS9zbXRwL3NhdmUnXT1hc3luYyhyZXEscmVzKT0+ew0KICBpZighcmVxdWlyZUFkbWluKHJlcSxyZXMpKXJldHVybjsNCiAgY29uc3Qgcj1zcGF3blN5bmMoJ2Jhc2gnLFsnLWMnLCdpcHRhYmxlcy1zYXZlID4gL2V0Yy9pcHRhYmxlcy9ydWxlcy52NCAyPiYxJ10se3RpbWVvdXQ6NTAwMCxlbmNvZGluZzondXRmOCd9KTsNCiAganNvbihyZXMse29rOnIuc3RhdHVzPT09MCxtZXNzYWdlOnIuc3RhdHVzPT09MD8nUsOoZ2xlcyBzYXV2ZWdhcmTDqWVzIChwZXJzaXN0YW50ZXMgYXUgcmVib290KSc6KHIuc3Rkb3V0fHxyLnN0ZGVycnx8J0VycmV1cicpLnNsaWNlKDAsMjAwKX0pOw0KfTsNCg0KLy8g4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQDQovLyBST1VURVVSDQovLyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZANCmNvbnN0IG1hdGNoUm91dGU9KG1ldGhvZCxwYXRobmFtZSk9PnsNCiAgZm9yKGNvbnN0IFtrZXksaGFuZGxlcl0gb2YgT2JqZWN0LmVudHJpZXMocm91dGVzKSl7DQogICAgY29uc3QgW20scF09a2V5LnNwbGl0KCcgJyk7aWYobSE9PW1ldGhvZCljb250aW51ZTsNCiAgICBjb25zdCBuYW1lcz1bXTsNCiAgICBjb25zdCByeD1uZXcgUmVnRXhwKCdeJytwLnJlcGxhY2UoLzooXHcrKS9nLChfLG4pPT57bmFtZXMucHVzaChuKTtyZXR1cm4gbj09PSdpcCc/JyhbXlxcc10rKSc6JyhbXi9dKyknO30pKyckJyk7DQogICAgY29uc3QgbWF0Y2g9cGF0aG5hbWUubWF0Y2gocngpOw0KICAgIGlmKG1hdGNoKXtjb25zdCBwYXJhbXM9e307bmFtZXMuZm9yRWFjaCgobixpKT0+cGFyYW1zW25dPW1hdGNoW2krMV0pO3JldHVybntoYW5kbGVyLHBhcmFtc307fQ0KICB9DQogIHJldHVybiBudWxsOw0KfTsNCg0KLy8g4pSA4pSAIEluaXQgREIg4oCUIHRhYmxlcyBjdXN0b20g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSADQp0cnl7ZGJRdWVyeShgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgc3luY19kZXN0aW5hdGlvbnMgKGlkIElOVCBBVVRPX0lOQ1JFTUVOVCBQUklNQVJZIEtFWSwgbGFiZWwgVkFSQ0hBUigyNTUpIERFRkFVTFQgJycsIGltYXBfaG9zdCBWQVJDSEFSKDI1NSkgTk9UIE5VTEwsIGltYXBfdXNlciBWQVJDSEFSKDI1NSkgTk9UIE5VTEwsIGltYXBfcGFzcyBWQVJDSEFSKDI1NSkgTk9UIE5VTEwsIGltYXBfZm9sZGVyIFZBUkNIQVIoMTAwKSBOT1QgTlVMTCBERUZBVUxUICdJTkJPWCcsIGltYXBfc3NsIFRJTllJTlQoMSkgTk9UIE5VTEwgREVGQVVMVCAxLCBsYXN0X3VzZWRfYXQgREFURVRJTUUgREVGQVVMVCBOVUxMLCBjcmVhdGVkX2F0IERBVEVUSU1FIE5PVCBOVUxMIERFRkFVTFQgTk9XKCkpIEVOR0lORT1Jbm5vREIgREVGQVVMVCBDSEFSU0VUPXV0ZjhtYjRgKTt9Y2F0Y2goZSl7Y29uc29sZS5lcnJvcignW0JyaWRnZV0gREIgaW5pdDonLGUubWVzc2FnZSk7fQ0KdHJ5e2RiUXVlcnkoYENSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIHJiX3Byb3RlY3RlZCAobWV0YWRhdGFfaWQgSU5UIE5PVCBOVUxMLCBwcm90ZWN0ZWRfYXQgSU5UIE5PVCBOVUxMIERFRkFVTFQgMCwgUFJJTUFSWSBLRVkobWV0YWRhdGFfaWQpKSBFTkdJTkU9SW5ub0RCYCk7fWNhdGNoKGUpe2NvbnNvbGUuZXJyb3IoJ1tCcmlkZ2VdIERCIGluaXQgcHJvdGVjdGVkOicsZS5tZXNzYWdlKTt9DQp0cnl7ZGJRdWVyeShgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgcmJfaW1hcF9mb2xkZXJzIChzb3VyY2VfaWQgSU5UIE5PVCBOVUxMLCBmb2xkZXJfbmFtZSBWQVJDSEFSKDI1NSkgTk9UIE5VTEwsIGVtYWlsX2NvdW50IElOVCBOT1QgTlVMTCBERUZBVUxUIDAsIHVwZGF0ZWRfYXQgSU5UIE5PVCBOVUxMIERFRkFVTFQgMCwgUFJJTUFSWSBLRVkoc291cmNlX2lkLCBmb2xkZXJfbmFtZSkpIEVOR0lORT1Jbm5vREIgREVGQVVMVCBDSEFSU0VUPXV0ZjhtYjRgKTt9Y2F0Y2goZSl7Y29uc29sZS5lcnJvcignW0JyaWRnZV0gREIgaW5pdCBmb2xkZXJzOicsZS5tZXNzYWdlKTt9DQp0cnl7ZGJRdWVyeShgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgbGVnYWxfaG9sZCAoZW1haWwgVkFSQ0hBUigyNTUpIE5PVCBOVUxMLCBjcmVhdGVkX2F0IElOVCBOT1QgTlVMTCBERUZBVUxUIDAsIFBSSU1BUlkgS0VZKGVtYWlsKSkgRU5HSU5FPUlubm9EQiBERUZBVUxUIENIQVJTRVQ9dXRmOG1iNGApO31jYXRjaChlKXtjb25zb2xlLmVycm9yKCdbQnJpZGdlXSBEQiBpbml0IGxlZ2FsX2hvbGQ6JyxlLm1lc3NhZ2UpO30NCnRyeXtkYlF1ZXJ5KGBBTFRFUiBUQUJMRSBsZWdhbF9ob2xkIEFERCBDT0xVTU4gSUYgTk9UIEVYSVNUUyBjcmVhdGVkX2F0IElOVCBOT1QgTlVMTCBERUZBVUxUIDBgKTt9Y2F0Y2h7fQ0KdHJ5e2RiUXVlcnkoYENSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIHJiX3JldGVudGlvbl9ydWxlIChpZCBJTlQgQVVUT19JTkNSRU1FTlQgUFJJTUFSWSBLRVksIGRvbWFpbiBWQVJDSEFSKDI1NSkgTk9UIE5VTEwgREVGQVVMVCAnJywgZGF5cyBJTlQgTk9UIE5VTEwgREVGQVVMVCAzNjUsIGFjdGlvbiBWQVJDSEFSKDIwKSBOT1QgTlVMTCBERUZBVUxUICdkZWxldGUnLCBjcmVhdGVkX2F0IElOVCBOT1QgTlVMTCBERUZBVUxUIDApIEVOR0lORT1Jbm5vREIgREVGQVVMVCBDSEFSU0VUPXV0ZjhtYjRgKTt9Y2F0Y2goZSl7Y29uc29sZS5lcnJvcignW0JyaWRnZV0gREIgaW5pdCByYl9yZXRlbnRpb25fcnVsZTonLGUubWVzc2FnZSk7fQ0KdHJ5e2RiUXVlcnkoYENSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIHJiX2FyY2hpdmluZ19ydWxlIChpZCBJTlQgQVVUT19JTkNSRU1FTlQgUFJJTUFSWSBLRVksIHNyY19kb21haW4gVkFSQ0hBUigyNTUpIE5PVCBOVUxMIERFRkFVTFQgJycsIHN1YmplY3RfZmlsdGVyIFZBUkNIQVIoMjU1KSBOT1QgTlVMTCBERUZBVUxUICcnLCBkc3RfZm9sZGVyIFZBUkNIQVIoMjU1KSBOT1QgTlVMTCBERUZBVUxUICcnLCBhY3Rpb24gVkFSQ0hBUigyMCkgTk9UIE5VTEwgREVGQVVMVCAnYXJjaGl2ZScsIGNyZWF0ZWRfYXQgSU5UIE5PVCBOVUxMIERFRkFVTFQgMCkgRU5HSU5FPUlubm9EQiBERUZBVUxUIENIQVJTRVQ9dXRmOG1iNGApO31jYXRjaChlKXtjb25zb2xlLmVycm9yKCdbQnJpZGdlXSBEQiBpbml0IHJiX2FyY2hpdmluZ19ydWxlOicsZS5tZXNzYWdlKTt9DQp0cnl7ZGJRdWVyeShgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgcmJfcHN0X2ltcG9ydGVkIChtZXRhZGF0YV9pZCBJTlQgTk9UIE5VTEwsIHVwbG9hZF91aWQgVkFSQ0hBUig2MCkgTk9UIE5VTEwgREVGQVVMVCAnJywgUFJJTUFSWSBLRVkobWV0YWRhdGFfaWQpLCBJTkRFWCBpZHhfdWlkICh1cGxvYWRfdWlkKSkgRU5HSU5FPUlubm9EQmApO31jYXRjaChlKXtjb25zb2xlLmVycm9yKCdbQnJpZGdlXSBEQiBpbml0IHJiX3BzdF9pbXBvcnRlZDonLGUubWVzc2FnZSk7fQ0KLy8gTWlncmF0aW9uIHLDqXRyb2FjdGl2ZSA6IHRhZ3VlciBsZXMgYW5jaWVucyBpbXBvcnRzIFBTVCBub24gZW5jb3JlIGRhbnMgcmJfcHN0X2ltcG9ydGVkDQp0cnkgew0KICBjb25zdCB1cGxvYWRzPXJlYWRVcGxvYWRzKCk7DQogIGZvcihjb25zdCB1IG9mIHVwbG9hZHMpew0KICAgIGlmKHUudHlwZT09PSdwc3QnICYmIHUuc3RhdHVzPT09J3Rlcm1pbsOpJyAmJiB1LmlkX3N0YXJ0IT1udWxsKXsNCiAgICAgIGNvbnN0IGNudD1wYXJzZUludCgoZGJSb3dzKGBTRUxFQ1QgQ09VTlQoKikgRlJPTSByYl9wc3RfaW1wb3J0ZWQgV0hFUkUgdXBsb2FkX3VpZD0nJHtlc2ModS51aWQpfSdgKVswXXx8W10pWzBdKXx8MDsNCiAgICAgIGlmKGNudD09PTApew0KICAgICAgICBkYlF1ZXJ5KGBJTlNFUlQgSUdOT1JFIElOVE8gcmJfcHN0X2ltcG9ydGVkIChtZXRhZGF0YV9pZCx1cGxvYWRfdWlkKSBTRUxFQ1QgaWQsJyR7ZXNjKHUudWlkKX0nIEZST00gbWV0YWRhdGEgV0hFUkUgaWQ+JHtwYXJzZUludCh1LmlkX3N0YXJ0KXx8MH0gQU5EIGlkPD0ke3BhcnNlSW50KHUuaWRfZW5kKXx8cGFyc2VJbnQodS5pZF9zdGFydCkrNTAwMDB9IEFORCBkZWxldGVkPTBgKTsNCiAgICAgICAgY29uc29sZS5sb2coYFtCcmlkZ2VdIE1pZ3JhdGlvbiBQU1QgJHt1LnVpZH06IGVtYWlscyB0YWd1w6lzIGRhbnMgcmJfcHN0X2ltcG9ydGVkYCk7DQogICAgICB9DQogICAgfQ0KICB9DQp9Y2F0Y2goZSl7Y29uc29sZS5lcnJvcignW0JyaWRnZV0gTWlncmF0aW9uIFBTVDonLGUubWVzc2FnZSk7fQ0KDQpodHRwLmNyZWF0ZVNlcnZlcihhc3luYyhyZXEscmVzKT0+ew0KICBpZihyZXEubWV0aG9kPT09J09QVElPTlMnKXtyZXMud3JpdGVIZWFkKDIwNCx7J0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbic6JyonLCdBY2Nlc3MtQ29udHJvbC1BbGxvdy1NZXRob2RzJzonR0VULFBPU1QsUFVULFBBVENILERFTEVURSxPUFRJT05TJywnQWNjZXNzLUNvbnRyb2wtQWxsb3ctSGVhZGVycyc6J0F1dGhvcml6YXRpb24sQ29udGVudC1UeXBlJ30pO3JldHVybiByZXMuZW5kKCk7fQ0KICBjb25zdCBwYXJzZWQ9dXJsLnBhcnNlKHJlcS51cmwsdHJ1ZSk7cmVxLnF1ZXJ5PXBhcnNlZC5xdWVyeTsNCiAgY29uc3QgcGF0aD1wYXJzZWQucGF0aG5hbWUucmVwbGFjZSgvXlwvcmItYXBpLywnJyk7DQogIHRyeSB7DQogICAgY29uc3QgbWF0Y2g9bWF0Y2hSb3V0ZShyZXEubWV0aG9kLHBhdGgpOw0KICAgIGlmKG1hdGNoKSBhd2FpdCBtYXRjaC5oYW5kbGVyKHJlcSxyZXMsbWF0Y2gucGFyYW1zKTsNCiAgICBlbHNlIGpzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6YFJvdXRlIGluY29ubnVlOiAke3JlcS5tZXRob2R9ICR7cGF0aH1gfSw0MDQpOw0KICB9IGNhdGNoKGUpe2pzb24ocmVzLHtlcnJvcjp0cnVlLG1lc3NhZ2U6ZS5tZXNzYWdlfSw1MDApO30NCn0pLmxpc3RlbihQT1JULCcxMjcuMC4wLjEnLCgpPT5jb25zb2xlLmxvZyhgW1JlYm9vdGx5IEJyaWRnZSB2JHtWRVJTSU9OfV0gUG9ydCAke1BPUlR9IOKAlCAke0FDQ09VTlRfSUR9LyR7RE9NQUlOfWApKTsNCnByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJyxlPT5jb25zb2xlLmVycm9yKCdbQnJpZGdlXScsZS5tZXNzYWdlKSk7DQo="

# ── Valeurs par défaut ────────────────────────────────────────────────────────
# Registry Docker privé (optionnel)
# SaaS          : vide → Docker Hub utilisé directement
# On-premise    : export REBOOTLY_REGISTRY=10.38.100.1:5000 avant de lancer
# Futur VPS dédié : export REBOOTLY_REGISTRY=IP_VPS_DOCKER:5000
PRIVATE_REGISTRY="${REBOOTLY_REGISTRY:-registry.rebootly.cloud}"
REGISTRY_USER="${REBOOTLY_REGISTRY_USER:-rebootly}"
REGISTRY_PASS="${REBOOTLY_REGISTRY_PASS:-jupfvS2dFDvL2fOXYB0RwDiX}"
# Mode offline : si INSTALL_MODE=offline, docker load < BUNDLE_PATH remplace docker pull
INSTALL_MODE="${INSTALL_MODE:-connected}"
BUNDLE_PATH="${BUNDLE_PATH:-/tmp/rebootly-images.tar.gz}"

CT_STORAGE="local"
CT_BRIDGE="vmbr1"
CT_DNS="1.1.1.1 8.8.8.8"
TEMPLATE_ID="${REBOOTLY_TEMPLATE_ID:-9000}"
LXCID=""
DOMAIN=""
ADMIN_EMAIL=""
ACCOUNT_ID=""
LXC_IP=""
ADMIN_PASS=""
MAX_USERS="${MAX_USERS:-0}"
RETENTION="3650"
MEMORY="2048"
CORES="2"
DISK="20"
INTERACTIVE=true
MISTRAL_API_KEY=""
GROQ_API_KEY=""
ARIANA_URL="http://51.75.119.233:11435"

# ── Parsing arguments CLI ─────────────────────────────────────────────────────
while [[ $# -gt 0 ]]; do
  case $1 in
    --lxcid)      LXCID="$2";       INTERACTIVE=false; shift 2 ;;
    --domain)     DOMAIN="$2";      shift 2 ;;
    --admin)      ADMIN_EMAIL="$2"; shift 2 ;;
    --account-id) ACCOUNT_ID="$2";  shift 2 ;;
    --ip)         LXC_IP="$2";      shift 2 ;;
    --admin-pass) ADMIN_PASS="$2";  shift 2 ;;
    --retention)  RETENTION="$2";   shift 2 ;;
    --memory)     MEMORY="$2";      shift 2 ;;
    --cores)      CORES="$2";       shift 2 ;;
    --disk)       DISK="$2";        shift 2 ;;
    --storage)    CT_STORAGE="$2";  shift 2 ;;
    --bridge)     CT_BRIDGE="$2";   shift 2 ;;
    --template-id) TEMPLATE_ID="$2"; shift 2 ;;
    --registry-pass) REGISTRY_PASS="$2"; shift 2 ;;
    --registry-user) REGISTRY_USER="$2"; shift 2 ;;
    --registry)      PRIVATE_REGISTRY="$2"; shift 2 ;;
    --mistral-key) MISTRAL_API_KEY="$2"; shift 2 ;;
    --groq-key)   GROQ_API_KEY="$2"; shift 2 ;;
    --ariana-url) ARIANA_URL="$2";  shift 2 ;;
    *) err "Argument inconnu : $1" ;;
  esac
done

# ── Mode interactif ───────────────────────────────────────────────────────────
if [[ "$INTERACTIVE" == true ]]; then
  clear
  echo -e "${CYAN}${BOLD}"
  echo "  ┌─────────────────────────────────────────────────────┐"
  echo "  │   Rebootly Archives — Déploiement instance client   │"
  echo "  │   LXC + Docker + Bridge API + React UI              │"
  echo "  └─────────────────────────────────────────────────────┘"
  echo -e "${NC}"
  NEXT_ID=200
  while pct status "$NEXT_ID" >/dev/null 2>&1; do ((NEXT_ID++)); done
  read -p "  LXC ID        [défaut: $NEXT_ID] : " INPUT; LXCID="${INPUT:-$NEXT_ID}"
  read -p "  Domaine client (ex: monsite.fr) : " DOMAIN
  [[ -z "$DOMAIN" ]] && err "Le domaine est obligatoire"
  read -p "  Email admin    [admin@$DOMAIN]  : " INPUT; ADMIN_EMAIL="${INPUT:-admin@$DOMAIN}"
  read -p "  Rétention jours [3650]          : " INPUT; RETENTION="${INPUT:-3650}"
  echo ""
  read -p "  RAM Mo        [2048]            : " INPUT; MEMORY="${INPUT:-2048}"
  read -p "  CPU cores     [2]              : " INPUT; CORES="${INPUT:-2}"
  read -p "  Disque Go     [20]             : " INPUT; DISK="${INPUT:-20}"
  read -p "  Storage       [local]          : " INPUT; CT_STORAGE="${INPUT:-local}"
  echo ""
  read -p "  Mistral API Key [optionnel, laissez vide pour Ollama] : " INPUT; MISTRAL_API_KEY="${INPUT:-}"
  if [[ -z "$MISTRAL_API_KEY" ]]; then
    read -p "  Groq API Key   [optionnel, backup si Mistral absent]  : " INPUT; GROQ_API_KEY="${INPUT:-}"
  fi
fi

# ── Validation ────────────────────────────────────────────────────────────────
[[ -z "$LXCID" ]]       && err "--lxcid obligatoire en mode CLI"
[[ -z "$DOMAIN" ]]      && err "--domain obligatoire"
[[ -z "$ADMIN_EMAIL" ]] && ADMIN_EMAIL="admin@$DOMAIN"

# ── Génération des secrets (utilise valeurs CLI si fournies) ─────────────────
# Pas de pipe | head pour éviter SIGPIPE avec set -o pipefail
[[ -z "$ACCOUNT_ID" ]] && ACCOUNT_ID=$(openssl rand -hex 5)
SQL_PASS=$(openssl rand -hex 10)
API_SECRET=$(openssl rand -hex 16)
ROOT_PASS=$(openssl rand -hex 8)
[[ -z "$ADMIN_PASS" ]] && ADMIN_PASS=$(openssl rand -hex 8)

# IP : utilise valeur CLI ou calcule depuis lxcid
[[ -z "$LXC_IP" ]] && LXC_IP="10.10.0.$(( (LXCID % 100) + 100 ))"

# ── Récapitulatif ─────────────────────────────────────────────────────────────
echo ""
echo -e "${CYAN}${BOLD}  Récapitulatif${NC}"
echo -e "  LXC ID    : ${BOLD}$LXCID${NC}"
echo -e "  Domaine   : ${BOLD}$DOMAIN${NC}"
echo -e "  IP LXC    : ${BOLD}$LXC_IP${NC}"
echo -e "  Admin     : ${BOLD}$ADMIN_EMAIL${NC}"
echo -e "  Rétention : ${BOLD}${RETENTION} jours${NC}"
echo -e "  RAM/CPU   : ${BOLD}${MEMORY}Mo / ${CORES} cores / ${DISK}Go / ${CT_STORAGE}${NC}"
echo ""
# En mode CLI (non-interactif), pas de confirmation requise
if [[ "$INTERACTIVE" == true ]]; then
  read -p "  Confirmer ? [o/N] " -n 1 -r; echo
  [[ ! $REPLY =~ ^[oO]$ ]] && echo "Annulé." && exit 0
fi

# ═══════════════════════════════════════════════════════════════════════════════
section "0/5 — Prérequis"
[[ $EUID -ne 0 ]]             && err "Root requis"
command -v pct    >/dev/null 2>&1 || err "pct introuvable — Proxmox VE requis"
command -v openssl>/dev/null 2>&1 || err "openssl introuvable"
pct status "$LXCID" >/dev/null 2>&1 && err "LXC $LXCID existe déjà"

# Vérifier que le template LXC existe
if ! pct status "$TEMPLATE_ID" >/dev/null 2>&1; then
  err "Template LXC $TEMPLATE_ID introuvable. Lancer d'abord : bash /root/rebootly-archives/01-create-lxc-template.sh"
fi
ok "Prérequis OK — Template $TEMPLATE_ID disponible"

# ═══════════════════════════════════════════════════════════════════════════════
section "1/5 — Clone template LXC $TEMPLATE_ID → $LXCID"
pct clone "$TEMPLATE_ID" "$LXCID" --full 1
ok "Clone effectué"

pct set "$LXCID"   --hostname  "${DOMAIN}"   --memory    "$MEMORY"   --cores     "$CORES"   --net0      "name=eth0,bridge=${CT_BRIDGE},ip=${LXC_IP}/24,gw=10.10.0.1"   --nameserver  "$CT_DNS"   --searchdomain "local"   --description "Rebootly Archives — ${DOMAIN} | ID:${ACCOUNT_ID} | $(date '+%Y-%m-%d')"
ok "LXC $LXCID configuré"

pct start "$LXCID"
info "Attente 15s (réseau)..."
sleep 15
ok "LXC $LXCID démarré"

# Forcer DNS explicitement (peut être écrasé par clone)
pct exec "$LXCID" -- bash -c 'rm -f /etc/resolv.conf && echo -e "nameserver 1.1.1.1
nameserver 8.8.8.8" > /etc/resolv.conf'
ok "DNS forcé (1.1.1.1 / 8.8.8.8)"

# ═══════════════════════════════════════════════════════════════════════════════
section "2/5 — Désactivation exim4 + postfix (CRITIQUE — port 25 pour Mailpiler)"
pct exec "$LXCID" -- bash -c "
  systemctl stop    exim4   2>/dev/null || true
  systemctl disable exim4   2>/dev/null || true
  systemctl mask    exim4   2>/dev/null || true
  systemctl stop    postfix 2>/dev/null || true
  systemctl disable postfix 2>/dev/null || true
  systemctl mask    postfix 2>/dev/null || true
  echo 'exim4 + postfix masqués'
" || warn "exim4/postfix non présents (ignoré)"
ok "exim4 + postfix masqués — port 25 libéré"

# pst-utils (readpst) — normalement pré-installé dans le template
info "Vérification pst-utils (readpst)..."
pct exec "$LXCID" -- bash -c "
  which readpst >/dev/null 2>&1 && echo 'readpst OK (template)' || {
    echo 'readpst absent — installation fallback...'
    apt-get install -y -qq pst-utils 2>&1 | tail -2
    which readpst && echo 'readpst OK' || echo 'WARN: readpst non disponible'
  }
"
ok "pst-utils OK"

# ═══════════════════════════════════════════════════════════════════════════════
section "3/5 — Structure répertoires"
DATA_DIR="/srv/rebootly-${ACCOUNT_ID}"
pct exec "$LXCID" -- bash -c "
  mkdir -p ${DATA_DIR}/{mariadb,manticore,piler/store,portainer}
  # CRITIQUE : Manticore Search nécessite chmod 777
  chmod 777 ${DATA_DIR}/manticore
  chmod 755 ${DATA_DIR}/mariadb
  mkdir -p /opt/rebootly /var/www/rebootly
  echo 'Répertoires OK'
"
ok "Répertoires $DATA_DIR créés (manticore=777)"

# ═══════════════════════════════════════════════════════════════════════════════
section "4/5 — docker-compose.yml"
COMPOSE_FILE="/tmp/rb-compose-${LXCID}.yml"
cat > "$COMPOSE_FILE" << COMPOSE_EOF
version: '3.8'

services:

  rb-mariadb-${ACCOUNT_ID}:
    container_name: rb-mariadb-${ACCOUNT_ID}
    image: registry.rebootly.cloud/rb-mariadb:10.11
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: "${SQL_PASS}"
      MYSQL_DATABASE: piler
      MYSQL_USER: piler
      MYSQL_PASSWORD: "${SQL_PASS}"
    volumes:
      - ${DATA_DIR}/mariadb:/var/lib/mysql
    networks:
      - rb-net-${ACCOUNT_ID}
    healthcheck:
      # CRITIQUE : mariadb-admin (PAS mysqladmin) sur MariaDB 10.11
      test: ["CMD", "mariadb-admin", "ping", "-h", "127.0.0.1",
             "-u", "root", "-p${SQL_PASS}"]
      interval: 10s
      timeout: 5s
      retries: 12
      start_period: 40s

  rb-manticore-${ACCOUNT_ID}:
    container_name: rb-manticore-${ACCOUNT_ID}
    image: registry.rebootly.cloud/rb-manticore:6.3.4
    restart: unless-stopped
    volumes:
      - ${DATA_DIR}/manticore:/var/lib/manticore
    networks:
      - rb-net-${ACCOUNT_ID}
    ulimits:
      nofile:
        soft: 65536
        hard: 65536

  rb-memcached-${ACCOUNT_ID}:
    container_name: rb-memcached-${ACCOUNT_ID}
    image: registry.rebootly.cloud/rb-memcached:alpine
    restart: unless-stopped
    # CRITIQUE : -l 0.0.0.0 sinon Piler ne peut pas se connecter
    command: ["-l", "0.0.0.0"]
    networks:
      - rb-net-${ACCOUNT_ID}

  rb-piler-${ACCOUNT_ID}:
    container_name: rb-piler-${ACCOUNT_ID}
    image: registry.rebootly.cloud/rb-piler:1.4.8
    restart: unless-stopped
    ports:
      - "25:25"
      - "127.0.0.1:8080:80"
    volumes:
      - ${DATA_DIR}/piler/store:/var/piler/store
    environment:
      # CRITIQUE : noms exacts attendus par sutoj/piler:1.4.8
      MYSQL_HOSTNAME: rb-mariadb-${ACCOUNT_ID}
      MANTICORE_HOSTNAME: rb-manticore-${ACCOUNT_ID}
      MYSQL_DATABASE: piler
      MYSQL_USER: piler
      MYSQL_PASSWORD: "${SQL_PASS}"
      RT: "1"
      MEMCACHED_HOSTNAME: rb-memcached-${ACCOUNT_ID}
      PILER_HOSTNAME: "${LXC_IP}:80"
    networks:
      - rb-net-${ACCOUNT_ID}
    # CRITIQUE : attend que MariaDB soit healthy avant de démarrer
    depends_on:
      rb-mariadb-${ACCOUNT_ID}:
        condition: service_healthy

  rb-portainer-${ACCOUNT_ID}:
    container_name: rb-portainer-${ACCOUNT_ID}
    image: registry.rebootly.cloud/rb-portainer:latest
    restart: unless-stopped
    ports:
      - "9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${DATA_DIR}/portainer:/data
    networks:
      - rb-net-${ACCOUNT_ID}

networks:
  rb-net-${ACCOUNT_ID}:
    driver: bridge
COMPOSE_EOF

pct push "$LXCID" "$COMPOSE_FILE" /opt/rebootly/docker-compose.yml
rm -f "$COMPOSE_FILE"
ok "docker-compose.yml transféré"

# ═══════════════════════════════════════════════════════════════════════════════
section "5/5 — Fix MariaDB + démarrage Docker"
# CRITIQUE (LXC unprivileged) : chown 999:999 AVANT le premier démarrage MariaDB
info "Fix chown MariaDB (uid 999 = mysql dans le container)..."
pct exec "$LXCID" -- bash -c "
  chown -R 999:999 ${DATA_DIR}/mariadb
  echo 'chown OK'
"
ok "Permissions MariaDB corrigées"

# ── Chargement des images Docker : mode offline ou registry ──────────────────
if [[ "${INSTALL_MODE}" == "offline" ]]; then
  # Mode déconnecté : charger les images depuis le bundle tar.gz
  info "Mode offline : chargement des images Docker depuis ${BUNDLE_PATH}..."
  if pct exec "$LXCID" -- test -f "${BUNDLE_PATH}" 2>/dev/null; then
    pct exec "$LXCID" -- bash -c "
      echo 'Chargement bundle Docker (peut prendre 2-5 min)...'
      docker load < '${BUNDLE_PATH}'
      echo 'Bundle chargé avec succès'
      rm -f '${BUNDLE_PATH}'
    "
    ok "Images Docker chargées depuis le bundle (mode offline)"
  else
    # Copier le bundle depuis Proxmox vers le LXC si présent sur Proxmox
    if [[ -f "${BUNDLE_PATH}" ]]; then
      info "Copie bundle Proxmox → LXC ${LXCID}..."
      pct push "$LXCID" "${BUNDLE_PATH}" "${BUNDLE_PATH}"
      pct exec "$LXCID" -- bash -c "
        echo 'Chargement bundle Docker...'
        docker load < '${BUNDLE_PATH}'
        echo 'Bundle chargé avec succès'
        rm -f '${BUNDLE_PATH}'
      "
      ok "Images Docker chargées depuis le bundle (mode offline)"
    else
      warn "Bundle ${BUNDLE_PATH} introuvable — Docker Hub sera utilisé en fallback"
      warn "Assurez-vous que le bundle a bien été transféré sur le serveur Proxmox"
    fi
  fi
elif [[ -n "${PRIVATE_REGISTRY}" ]]; then
  # Mode connecté avec registry privé
  info "Registry privé : ${PRIVATE_REGISTRY} (HTTPS TLS) — docker login..."
  if [[ -z "$REGISTRY_PASS" ]]; then
    warn "REGISTRY_PASS vide — pull sans authentification (peut échouer)"
    warn "Utiliser : --registry-pass PASS ou REBOOTLY_REGISTRY_PASS=PASS"
  else
    pct exec "$LXCID" -- bash -c "
      echo '${REGISTRY_PASS}' | docker login '${PRIVATE_REGISTRY}' -u '${REGISTRY_USER}' --password-stdin
      echo 'Docker login OK'
    "
    ok "Docker login ${PRIVATE_REGISTRY} OK"
  fi

  info "Pré-pull images depuis registry privé ${PRIVATE_REGISTRY}..."
  pct exec "$LXCID" -- bash -c "
    REGISTRY='${PRIVATE_REGISTRY}'
    IMAGES=(
      'rb-piler:1.4.8|sutoj/piler:1.4.8'
      'rb-mariadb:10.11|mariadb:10.11'
      'rb-manticore:6.3.4|manticoresearch/manticore:6.3.4'
      'rb-memcached:alpine|memcached:alpine'
      'rb-portainer:latest|portainer/portainer-ce:latest'
    )
    for entry in \"\${IMAGES[@]}\"; do
      reg_tag=\"\${entry%%|*}\"
      hub_tag=\"\${entry##*|}\"
      reg_image=\"\${REGISTRY}/\${reg_tag}\"
    echo -n \"  Pull \${reg_tag}... \"
    if docker pull \"\${reg_image}\" >/dev/null 2>&1; then
      docker tag \"\${reg_image}\" \"\${hub_tag}\" 2>/dev/null || true
      echo \"[registry OK]\"
    else
      echo \"[registry indispo — Docker Hub sera utilisé]\"
    fi
  done
    echo 'Pré-pull terminé'
  "
else
  info "SaaS mode — Docker Hub utilisé directement (pas de registry privé)"
fi

info "Démarrage docker compose (attente MariaDB healthy)..."
pct exec "$LXCID" -- bash -c "
  cd /opt/rebootly
  docker compose up -d
  echo 'Attente MariaDB (max 90s)...'
  for i in \$(seq 1 18); do
    sleep 5
    STATUS=\$(docker inspect --format='{{.State.Health.Status}}' rb-mariadb-${ACCOUNT_ID} 2>/dev/null || echo unknown)
    printf '  [%2d/18] MariaDB: %s\n' \$i \"\$STATUS\"
    [ \"\$STATUS\" = 'healthy' ] && break
  done
"
ok "Conteneurs Docker démarrés"

# ═══════════════════════════════════════════════════════════════════════════════
section "6/5 — Bridge API + Service systemd"

# Bridge API — source unique : releases.rebootly.cloud (même credentials que update.sh)
RELEASES_URL="${RELEASES_URL:-https://releases.rebootly.cloud}"
RELEASES_KEY="${RELEASES_KEY:-rebootly:Rebootly2025!}"
RELEASES_BRIDGE_URL="${RELEASES_URL}/bridge/bridge-v5.js"
info "Téléchargement bridge v5 depuis releases.rebootly.cloud..."
if curl -sf -u "$RELEASES_KEY" --max-time 60 "$RELEASES_BRIDGE_URL" -o "/tmp/rb-bridge-${LXCID}.js" 2>/dev/null && [[ -s "/tmp/rb-bridge-${LXCID}.js" ]]; then
  info "Bridge v5 téléchargé depuis releases.rebootly.cloud"
elif [[ -f "/root/rebootly-bridge-v5.js" ]]; then
  warn "releases injoignable → bridge local (/root/rebootly-bridge-v5.js)"
  cp "/root/rebootly-bridge-v5.js" "/tmp/rb-bridge-${LXCID}.js"
else
  warn "releases + local injoignables → bridge embarqué (FALLBACK — version non garantie)"
  echo "$BRIDGE_B64" | base64 -d > "/tmp/rb-bridge-${LXCID}.js"
fi
sed -i \
  -e "s|__ACCOUNT_ID__|${ACCOUNT_ID}|g" \
  -e "s|__SQL_PASS__|${SQL_PASS}|g"     \
  -e "s|__API_SECRET__|${API_SECRET}|g" \
  -e "s|__DOMAIN__|${DOMAIN}|g"         \
  -e "s|__LXC_IP__|${LXC_IP}|g"        \
  -e "s|__MAX_USERS__|${MAX_USERS}|g"   \
  "/tmp/rb-bridge-${LXCID}.js"
pct push "$LXCID" "/tmp/rb-bridge-${LXCID}.js" /opt/rebootly/api-bridge.js --perms 644
rm -f "/tmp/rb-bridge-${LXCID}.js"
ok "Bridge API déployé (/opt/rebootly/api-bridge.js)"

# Mise à jour mot de passe admin Mailpiler (SHA-512 crypt unix)
# CRITIQUE : piler crée l'admin uid=0 automatiquement — on met juste à jour son mot de passe
info "Mise à jour mot de passe admin Mailpiler..."
pct exec "$LXCID" -- bash -c "
  for i in \$(seq 1 20); do
    docker exec rb-mariadb-${ACCOUNT_ID} mariadb -h 127.0.0.1 \
      -upiler -p'${SQL_PASS}' piler -e 'SELECT 1' >/dev/null 2>&1 && break
    sleep 3
  done
  HASH=\$(openssl passwd -6 '${ADMIN_PASS}' 2>/dev/null)
  docker exec rb-mariadb-${ACCOUNT_ID} mariadb -h 127.0.0.1 \
    -upiler -p'${SQL_PASS}' piler -e \"
    UPDATE user SET password='\$HASH', isadmin=1 WHERE uid=0;
  \"
  echo 'Admin password mis à jour (SHA-512 crypt)'
"
ok "Mot de passe admin Mailpiler mis à jour"

# Initialisation des répertoires store Piler (256 dirs 00-ff requis par pilerimport)
# Sans ces répertoires, pilerimport échoue sur une instance vide avec "No such file or directory"
info "Initialisation store Piler (256 sous-répertoires)..."
pct exec "$LXCID" -- bash -c "
  docker exec rb-piler-${ACCOUNT_ID} sh -c '
    cd /var/piler/store
    for a in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
      for b in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
        mkdir -p \"\${a}\${b}\"
      done
    done
    chown -R piler:piler /var/piler/store
    echo \"Store dirs: \$(ls | wc -l)\"
  '
"
ok "Store Piler initialisé"

# Fichiers de config complémentaires (identiques production)
pct exec "$LXCID" -- bash -c "
  cat > /opt/rebootly/rebootly.conf << EOF
ACCOUNT_ID=${ACCOUNT_ID}
SQL_PASS=${SQL_PASS}
LXC_IP=${LXC_IP}
DOMAIN=${DOMAIN}
API_SECRET=${API_SECRET}
VERSION=5.3.3
EOF
  echo '[{\"ip\":\"${LXC_IP}\",\"description\":\"\",\"added\":$(date +%s)}]' > /opt/rebootly/smtp-whitelist.json
  echo '[]' > /opt/rebootly/uploads.json
  echo 'Fichiers config OK'
"
ok "rebootly.conf + smtp-whitelist.json + uploads.json créés"

# Service systemd Bridge API (identique production)
pct exec "$LXCID" -- bash << 'SVCSCRIPT'
cat > /etc/systemd/system/rebootly-api.service << SVCEOF
[Unit]
Description=Rebootly Archives API Bridge v5
After=network.target docker.service

[Service]
Type=simple
User=root
WorkingDirectory=/opt/rebootly
ExecStart=/usr/bin/node /opt/rebootly/api-bridge.js
Restart=always
RestartSec=5
Environment=ARIANA_URL=${ARIANA_URL}
$([ -n "${MISTRAL_API_KEY}" ] && echo "Environment=MISTRAL_API_KEY=${MISTRAL_API_KEY}")
$([ -n "${GROQ_API_KEY}" ] && echo "Environment=GROQ_API_KEY=${GROQ_API_KEY}")
StandardOutput=append:/var/log/rebootly-bridge.log
StandardError=append:/var/log/rebootly-bridge.log

[Install]
WantedBy=multi-user.target
SVCEOF
systemctl daemon-reload
systemctl enable rebootly-api
systemctl start rebootly-api
sleep 3
systemctl is-active rebootly-api && echo 'Bridge actif' || echo 'WARN: bridge non actif - verif: tail /var/log/rebootly-bridge.log'
SVCSCRIPT
ok "Service rebootly-api créé et démarré"

# ═══════════════════════════════════════════════════════════════════════════════
section "7/5 — Nginx + React UI"

# ── Priorité 1 : dist pré-buildée (mise à jour par deploy-rebootly-v6.py) ────
DIST_DIR="${SCRIPT_DIR}/ui-dist"
UI_DEPLOYED=false

if [[ -f "${DIST_DIR}/index.html" ]]; then
  info "Dist UI pré-buildée trouvée → copie directe"
  tar -czf "/tmp/rb-ui-dist-${LXCID}.tar.gz" -C "$DIST_DIR" .
  pct push "$LXCID" "/tmp/rb-ui-dist-${LXCID}.tar.gz" /tmp/ui-dist.tar.gz
  rm -f "/tmp/rb-ui-dist-${LXCID}.tar.gz"
  pct exec "$LXCID" -- bash -c "
    cd /var/www/rebootly
    tar -xzf /tmp/ui-dist.tar.gz
    rm /tmp/ui-dist.tar.gz
    echo 'UI OK'
  "
  ok "React UI déployée depuis dist pré-buildée"
  UI_DEPLOYED=true
fi

# ── Priorité 2 : build depuis sources (fallback) ─────────────────────────────
if [[ "$UI_DEPLOYED" == false ]]; then
UI_SRC=""
for CANDIDATE in \
  "${SCRIPT_DIR}/../../rebootly-ui-src(1)/rebootly-ui" \
  "${SCRIPT_DIR}/../rebootly-ui" \
  "${SCRIPT_DIR}/ui-src/rebootly-ui" \
  "/root/rebootly-ui"
do
  [[ -f "${CANDIDATE}/package.json" ]] && UI_SRC="$CANDIDATE" && break
done

if [[ -n "$UI_SRC" ]]; then
  info "Sources React trouvées : $UI_SRC"
  info "Packaging + build dans le LXC..."
  tar -czf "/tmp/rb-ui-${LXCID}.tar.gz" -C "$(dirname "$UI_SRC")" "$(basename "$UI_SRC")"
  pct push "$LXCID" "/tmp/rb-ui-${LXCID}.tar.gz" /tmp/rebootly-ui.tar.gz
  rm -f "/tmp/rb-ui-${LXCID}.tar.gz"
  pct exec "$LXCID" -- bash -c "
    mkdir -p /opt/rebootly-ui
    cd /opt/rebootly-ui
    tar -xzf /tmp/rebootly-ui.tar.gz --strip-components=1
    rm /tmp/rebootly-ui.tar.gz
    echo 'VITE_API_BASE=/rb-api' > .env.local
    npm install --silent
    npm run build
    cp -r dist/* /var/www/rebootly/
    echo 'Build React OK'
  "
  ok "React UI buildée et déployée"
else
  warn "Sources React non trouvées → page placeholder"
  warn "Pour déployer l'UI complète :"
  warn "  cp -r rebootly-ui/ $SCRIPT_DIR/ui-src/ && bash $0 ..."
  pct exec "$LXCID" -- bash << 'HTMLSCRIPT'
cat > /var/www/rebootly/index.html << 'HTMLEOF'
<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <title>Rebootly Archives</title>
  <style>
    body{background:#0a0f1e;color:#fff;font-family:sans-serif;
         display:flex;align-items:center;justify-content:center;height:100vh;margin:0;}
    h1{background:linear-gradient(90deg,#0044CC,#40D4FF);
       -webkit-background-clip:text;-webkit-text-fill-color:transparent;font-size:2rem;}
    p{color:#8899aa;} a{color:#40D4FF;}
  </style>
</head>
<body><div style="text-align:center">
  <h1>Rebootly Archives</h1>
  <p>Interface en cours de déploiement...</p>
  <p><a href="/rb-api/v1/health">/rb-api/v1/health</a></p>
</div></body></html>
HTMLEOF
HTMLSCRIPT
fi
fi  # UI_DEPLOYED == false

# Configuration Nginx
pct exec "$LXCID" -- bash << 'NGINXSCRIPT'
cat > /etc/nginx/sites-available/rebootly << 'NGINXEOF'
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    root /var/www/rebootly;
    index index.html;

    # Proxy Bridge API Node.js :3001
    location /rb-api/ {
        proxy_pass http://127.0.0.1:3001/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_read_timeout 600s;
        client_max_body_size 500M;
    }

    # SPA React — fallback index.html
    location / {
        try_files $uri $uri/ /index.html;
    }
}
NGINXEOF
ln -sf /etc/nginx/sites-available/rebootly /etc/nginx/sites-enabled/rebootly
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx || systemctl restart nginx
echo 'Nginx OK'
NGINXSCRIPT
ok "Nginx configuré"

# Crons Mailpiler — scripts officiels piler
pct exec "$LXCID" -- bash -c "
# Installer et activer le daemon cron si absent
if ! command -v cron >/dev/null 2>&1 && ! systemctl is-active cron >/dev/null 2>&1; then
  apt-get install -y -qq cron
fi
systemctl enable cron --now 2>/dev/null || true

cat > /etc/cron.d/rebootly << EOF
# Rebootly Archives crons — scripts officiels Mailpiler
# Import IMAP/POP3 toutes les 5 min
*/2 * * * * root docker exec rb-piler-${ACCOUNT_ID} /usr/libexec/piler/import.sh >/dev/null 2>&1
# Indexation delta Manticore (toutes les 30 min)
5,35 * * * * root docker exec rb-piler-${ACCOUNT_ID} /usr/libexec/piler/indexer.delta.sh >/dev/null 2>&1
# Indexation complète (nuit 2h30)
30 2 * * * root docker exec rb-piler-${ACCOUNT_ID} /usr/libexec/piler/indexer.main.sh >/dev/null 2>&1
# Purge selon règles de rétention (nuit 3h40)
0 * * * * root docker exec rb-piler-${ACCOUNT_ID} /usr/libexec/piler/purge.sh >/dev/null 2>&1
# Stats journalières (6h30)
30 6 * * * root docker exec rb-piler-${ACCOUNT_ID} php /usr/libexec/piler/generate_stats.php --webui /var/piler/www >/dev/null 2>&1
EOF
chmod 644 /etc/cron.d/rebootly

systemctl is-active cron && echo 'cron daemon: actif' || echo 'WARN: cron daemon inactif'
"
ok "Crons Mailpiler configurés (cron daemon vérifié)"

# ── Script auto-update ──────────────────────────────────────────────────────
pct exec "$LXCID" -- bash -c "
echo '[6/?] Installation script auto-update...'
cat > /opt/rebootly/update.sh << 'UPDATE_SCRIPT'
#!/bin/bash
# /opt/rebootly/update.sh — VERSION: 2.0.0 — 2026-03-22
# Auto-update via portal proxy (token unique par instance — credential releases jamais exposé)
RELEASES_KEY_FILE=\"/opt/rebootly/.releases-key\"
PORTAL_URL_FILE=\"/opt/rebootly/.portal-url\"
BRIDGE_PATH=\"/opt/rebootly/api-bridge.js\"
WWW_PATH=\"/var/www/rebootly\"
BANNER_FILE=\"/opt/rebootly/update-banner.txt\"
LOG=\"/var/log/rebootly-update.log\"
FORCE=0
[ \"\$1\" = \"--force\" ] && FORCE=1
log() { echo \"[\$(date '+%Y-%m-%d %H:%M:%S')] \$*\" | tee -a \"\$LOG\"; }
TOKEN=\$(cat \"\$RELEASES_KEY_FILE\" 2>/dev/null | tr -d '[:space:]')
PORTAL_URL=\$(cat \"\$PORTAL_URL_FILE\" 2>/dev/null | tr -d '[:space:]')
if [ -z \"\$TOKEN\" ] || [ -z \"\$PORTAL_URL\" ]; then log \"ERROR: Token ou URL portal manquant\"; exit 1; fi
CURRENT=\$(grep \"const VERSION\" \"\$BRIDGE_PATH\" 2>/dev/null | grep -oP \"'[^']+'\" | head -1 | tr -d \"'\")
[ -z \"\$CURRENT\" ] && { log \"ERROR: Cannot read VERSION\"; exit 1; }
VER_JSON=\$(curl -sf --max-time 15 \"\${PORTAL_URL}/api/releases/version\" 2>/dev/null)
[ -z \"\$VER_JSON\" ] && { log \"Portal unreachable — skip\"; exit 0; }
LATEST=\$(echo \"\$VER_JSON\" | grep -m1 '\"bridge\"' | grep -oP '\"[0-9][^\"]*\"' | tr -d '\"')
[ -z \"\$LATEST\" ] && { log \"Cannot read latest version\"; exit 0; }
log \"Current: \$CURRENT | Available: \$LATEST\"
if [ \$FORCE -eq 0 ]; then
  HIGHER=\$(printf '%s\n%s' \"\$CURRENT\" \"\$LATEST\" | sort -V | tail -1)
  if [ \"\$CURRENT\" = \"\$LATEST\" ] || [ \"\$HIGHER\" != \"\$LATEST\" ]; then log \"Already up to date (\$CURRENT)\"; exit 0; fi
fi
log \"Updating: \$CURRENT -> \$LATEST\"
read_var() { grep \"const \$1\" \"\$BRIDGE_PATH\" | grep -oP \"'[^']+'\" | head -1 | tr -d \"'\"; }
ACCOUNT_ID=\$(read_var ACCOUNT_ID); SQL_PASS=\$(read_var SQL_PASS); API_SECRET=\$(read_var API_SECRET); DOMAIN=\$(read_var DOMAIN); LXC_IP=\$(read_var LXC_IP)
EXISTING_MAX_USERS=\$(grep \"const MAX_USERS\" \"\$BRIDGE_PATH\" | grep -oP \"parseInt\('\\K[^']+\" | head -1); EXISTING_MAX_USERS=\${EXISTING_MAX_USERS:-0}
cp \"\$BRIDGE_PATH\" \"\$BRIDGE_PATH.bak.\$(date +%Y%m%d-%H%M%S)\" 2>/dev/null || true
NEW_BRIDGE=\$(curl -sf -H \"Authorization: Bearer \$TOKEN\" --max-time 60 \"\${PORTAL_URL}/api/releases/bridge\" 2>/dev/null)
[ -z \"\$NEW_BRIDGE\" ] && { log \"ERROR: Bridge download failed (token invalide ou licence expirée)\"; exit 1; }
echo \"\$NEW_BRIDGE\" | sed \"s|__ACCOUNT_ID__|\$ACCOUNT_ID|g\" | sed \"s|__SQL_PASS__|\$SQL_PASS|g\" | sed \"s|__API_SECRET__|\$API_SECRET|g\" | sed \"s|__DOMAIN__|\$DOMAIN|g\" | sed \"s|__LXC_IP__|\$LXC_IP|g\" | sed \"s|__MAX_USERS__|\$EXISTING_MAX_USERS|g\" > /tmp/rb-bridge-update.js
if ! node --check /tmp/rb-bridge-update.js 2>/dev/null; then log \"ERROR: Syntax check failed — rollback\"; rm -f /tmp/rb-bridge-update.js; exit 1; fi
cp /tmp/rb-bridge-update.js \"\$BRIDGE_PATH\" && rm -f /tmp/rb-bridge-update.js && log \"Bridge applied\"
curl -sf -H \"Authorization: Bearer \$TOKEN\" --max-time 120 \"\${PORTAL_URL}/api/releases/ui\" -o /tmp/rb-ui-update.tar.gz 2>/dev/null
if [ -s /tmp/rb-ui-update.tar.gz ]; then cp -r \"\$WWW_PATH\" \"\$WWW_PATH.bak.\$(date +%Y%m%d-%H%M%S)\" 2>/dev/null || true; tar -xzf /tmp/rb-ui-update.tar.gz -C \"\$WWW_PATH\" 2>/dev/null; rm -f /tmp/rb-ui-update.tar.gz; log \"UI applied\"; fi
echo \"Mise à jour v\$LATEST effectuée avec succès\" > \"\$BANNER_FILE\"
DB_NAME=\"rb-mariadb-\$ACCOUNT_ID\"
for i in \$(seq 1 120); do COUNT=\$(docker exec \"\$DB_NAME\" mariadb -h 127.0.0.1 -upiler -p\"\$SQL_PASS\" piler -sN -e \"SELECT COUNT(*) FROM import WHERE status=1\" 2>/dev/null || echo 0); [ \"\${COUNT:-0}\" -eq 0 ] && break; [ \$i -eq 1 ] && log \"Import running — waiting...\"; sleep 15; done
systemctl restart rebootly-api && log \"Bridge restarted — update \$CURRENT -> \$LATEST done\"
UPDATE_SCRIPT
chmod +x /opt/rebootly/update.sh

# Cron auto-update (vérification nocturne à 4h30)
echo '30 4 * * * root bash /opt/rebootly/update.sh >> /var/log/rebootly-update.log 2>&1' >> /etc/cron.d/rebootly
echo 'Script auto-update installé'
"
ok "Script auto-update installé (/opt/rebootly/update.sh)"

# ── Sauvegarde credentials ────────────────────────────────────────────────────
DEPLOY_LOG="/root/rebootly-deployments.log"
{
  echo "# ──────────────────────────────────────────────────────────"
  echo "# $(date '+%Y-%m-%d %H:%M:%S')  Rebootly Archives"
  echo "  LXCID      : $LXCID"
  echo "  ACCOUNT_ID : $ACCOUNT_ID"
  echo "  DOMAIN     : $DOMAIN"
  echo "  LXC_IP     : $LXC_IP"
  echo "  ADMIN      : $ADMIN_EMAIL / $ADMIN_PASS"
  echo "  ROOT SSH   : $ROOT_PASS"
  echo "  SQL_PASS   : $SQL_PASS"
  echo "  API_SECRET : $API_SECRET"
  echo "# ──────────────────────────────────────────────────────────"
} >> "$DEPLOY_LOG"
chmod 600 "$DEPLOY_LOG"

# ── Résumé final ──────────────────────────────────────────────────────────────
echo ""
echo -e "${CYAN}${BOLD}╔══════════════════════════════════════════════════════════════╗"
echo -e "║         Rebootly Archives — Déploiement terminé !           ║"
echo -e "╠══════════════════════════════════════════════════════════════╣"
printf  "║  %-14s : %-45s║\n" "LXC ID"       "$LXCID"
printf  "║  %-14s : %-45s║\n" "Account ID"   "$ACCOUNT_ID"
printf  "║  %-14s : %-45s║\n" "IP LXC"       "$LXC_IP"
printf  "║  %-14s : %-45s║\n" "Domaine"      "$DOMAIN"
printf  "║  %-14s : %-45s║\n" "UI Web"       "http://$LXC_IP/"
printf  "║  %-14s : %-45s║\n" "Bridge API"   "http://$LXC_IP/rb-api/v1/health"
echo -e "╠══════════════════════════════════════════════════════════════╣"
printf  "║  %-14s : %-45s║\n" "Login admin"  "$ADMIN_EMAIL"
printf  "║  %-14s : %-45s║\n" "Mot de passe" "$ADMIN_PASS"
printf  "║  %-14s : %-45s║\n" "Root SSH pass" "$ROOT_PASS"
printf  "║  %-14s : %-45s║\n" "SQL pass"     "$SQL_PASS"
echo -e "╠══════════════════════════════════════════════════════════════╣"
echo -e "║  ssh root@$LXC_IP"
echo -e "║  Logs : cat $DEPLOY_LOG"
echo -e "╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
