#!/bin/bash
# ============================================================
#  REBOOTLY ARCHIVES — 08-update-client.sh  VERSION: 1.3.0
#  2026-03-17 — update.sh intégré (LATEST regex fix), cron auto-update
#  Met à jour le bridge API et/ou l'UI React d'une instance
#  LXC existante sans toucher aux données Mailpiler.
#
#  Usage :
#    bash 03-update-client.sh --lxcid 200
#    bash 03-update-client.sh --lxcid 200 --bridge-only
#    bash 03-update-client.sh --lxcid 200 --ui-only
#    bash 03-update-client.sh --all   (met à jour tous les LXC)
# ============================================================
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 ─────────────────────────────────────────────────
BRIDGE_B64="J3VzZSBzdHJpY3QnOwovKioKICogUmVib290bHkgQXJjaGl2ZXMg4oCUIEJyaWRnZSBBUEkgdjIKICogQXV0aCBKV1QgbG9jYWxlIChNYXJpYURCIFNIQS01MTIgY3J5cHQpICsgQVBJIGNvbXBsw6h0ZSBNYWlscGlsZXIKICogUG9ydCAzMDAxLCBsb29wYmFjayB1bmlxdWVtZW50IOKAlCBOZ2lueCBwcm94aWZpZSAvcmItYXBpLwogKi8KCmNvbnN0IGh0dHAgICA9IHJlcXVpcmUoJ2h0dHAnKTsKY29uc3QgdXJsICAgID0gcmVxdWlyZSgndXJsJyk7CmNvbnN0IGNyeXB0byA9IHJlcXVpcmUoJ2NyeXB0bycpOwpjb25zdCBmcyAgICAgPSByZXF1aXJlKCdmcycpOwpjb25zdCB7IGV4ZWNTeW5jLCBleGVjLCBzcGF3blN5bmMgfSA9IHJlcXVpcmUoJ2NoaWxkX3Byb2Nlc3MnKTsKCi8vIOKUgOKUgCBDb25maWcgKGluamVjdMOpZSBwYXIgZGVwbG95LWNsaWVudC5zaCkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmNvbnN0IFBPUlQgICAgICAgPSAzMDAxOwpjb25zdCBBUElfU0VDUkVUID0gJ19fQVBJX1NFQ1JFVF9fJzsKY29uc3QgU1FMX1BBU1MgICA9ICdfX1NRTF9QQVNTX18nOwpjb25zdCBBQ0NPVU5UX0lEID0gJ19fQUNDT1VOVF9JRF9fJzsKY29uc3QgRE9NQUlOICAgICA9ICdfX0RPTUFJTl9fJzsKY29uc3QgTFhDX0lQICAgICA9ICdfX0xYQ19JUF9fJzsKY29uc3QgREJfTkFNRSAgICA9ICdyYi1tYXJpYWRiLScgKyBBQ0NPVU5UX0lEOwpjb25zdCBQSUxFUl9OQU1FID0gJ3JiLXBpbGVyLScgICArIEFDQ09VTlRfSUQ7CmNvbnN0IFBJTEVSX1BPUlQgPSA4MDgwOwpjb25zdCBWRVJTSU9OICAgID0gJzMuMS4wJzsKCi8vIOKUgOKUgCBKV1QgbWFpc29uIChITUFDLVNIQTI1NiwgcGFzIGRlIGTDqXBlbmRhbmNlIGV4dGVybmUpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApjb25zdCBqd3RTaWduID0gKHBheWxvYWQpID0+IHsKICBjb25zdCBoZWFkZXIgID0gQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkoeyBhbGc6ICdIUzI1NicsIHR5cDogJ0pXVCcgfSkpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTsKICBjb25zdCBib2R5ICAgID0gQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkoeyAuLi5wYXlsb2FkLCBpYXQ6IE1hdGguZmxvb3IoRGF0ZS5ub3coKS8xMDAwKSB9KSkudG9TdHJpbmcoJ2Jhc2U2NHVybCcpOwogIGNvbnN0IHNpZyAgICAgPSBjcnlwdG8uY3JlYXRlSG1hYygnc2hhMjU2JywgQVBJX1NFQ1JFVCkudXBkYXRlKGhlYWRlciArICcuJyArIGJvZHkpLmRpZ2VzdCgnYmFzZTY0dXJsJyk7CiAgcmV0dXJuIGhlYWRlciArICcuJyArIGJvZHkgKyAnLicgKyBzaWc7Cn07Cgpjb25zdCBqd3RWZXJpZnkgPSAodG9rZW4pID0+IHsKICB0cnkgewogICAgY29uc3QgW2hlYWRlciwgYm9keSwgc2lnXSA9IHRva2VuLnNwbGl0KCcuJyk7CiAgICBjb25zdCBleHBlY3RlZCA9IGNyeXB0by5jcmVhdGVIbWFjKCdzaGEyNTYnLCBBUElfU0VDUkVUKS51cGRhdGUoaGVhZGVyICsgJy4nICsgYm9keSkuZGlnZXN0KCdiYXNlNjR1cmwnKTsKICAgIGlmICghY3J5cHRvLnRpbWluZ1NhZmVFcXVhbChCdWZmZXIuZnJvbShzaWcpLCBCdWZmZXIuZnJvbShleHBlY3RlZCkpKSByZXR1cm4gbnVsbDsKICAgIGNvbnN0IHBheWxvYWQgPSBKU09OLnBhcnNlKEJ1ZmZlci5mcm9tKGJvZHksICdiYXNlNjR1cmwnKS50b1N0cmluZygpKTsKICAgIGlmIChwYXlsb2FkLmV4cCAmJiBwYXlsb2FkLmV4cCA8IE1hdGguZmxvb3IoRGF0ZS5ub3coKS8xMDAwKSkgcmV0dXJuIG51bGw7CiAgICByZXR1cm4gcGF5bG9hZDsKICB9IGNhdGNoIHsgcmV0dXJuIG51bGw7IH0KfTsKCi8vIOKUgOKUgCBBdXRoIG1pZGRsZXdhcmUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmNvbnN0IGdldFVzZXIgPSAocmVxKSA9PiB7CiAgY29uc3QgYXV0aCA9IHJlcS5oZWFkZXJzLmF1dGhvcml6YXRpb24gfHwgJyc7CiAgaWYgKCFhdXRoLnN0YXJ0c1dpdGgoJ0JlYXJlciAnKSkgcmV0dXJuIG51bGw7CiAgcmV0dXJuIGp3dFZlcmlmeShhdXRoLnNsaWNlKDcpKTsKfTsKCmNvbnN0IHJlcXVpcmVBdXRoID0gKHJlcSwgcmVzKSA9PiB7CiAgY29uc3QgdXNlciA9IGdldFVzZXIocmVxKTsKICBpZiAoIXVzZXIpIHsganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6ICdOb24gYXV0b3Jpc8OpJyB9LCA0MDEpOyByZXR1cm4gbnVsbDsgfQogIHJldHVybiB1c2VyOwp9OwoKY29uc3QgcmVxdWlyZUFkbWluID0gKHJlcSwgcmVzKSA9PiB7CiAgY29uc3QgdXNlciA9IHJlcXVpcmVBdXRoKHJlcSwgcmVzKTsKICBpZiAoIXVzZXIpIHJldHVybiBudWxsOwogIGlmICghdXNlci5pc2FkbWluKSB7IGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiAnRHJvaXRzIGFkbWluIHJlcXVpcycgfSwgNDAzKTsgcmV0dXJuIG51bGw7IH0KICByZXR1cm4gdXNlcjsKfTsKCi8vIOKUgOKUgCBIZWxwZXJzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApjb25zdCBqc29uID0gKHJlcywgZGF0YSwgY29kZSA9IDIwMCkgPT4gewogIGNvbnN0IGJvZHkgPSBKU09OLnN0cmluZ2lmeShkYXRhKTsKICByZXMud3JpdGVIZWFkKGNvZGUsIHsKICAgICdDb250ZW50LVR5cGUnOiAgICAgICAgICAgICAgICAnYXBwbGljYXRpb24vanNvbicsCiAgICAnQ29udGVudC1MZW5ndGgnOiAgICAgICAgICAgICAgQnVmZmVyLmJ5dGVMZW5ndGgoYm9keSksCiAgICAnQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJzogJyonLAogICAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnOidBdXRob3JpemF0aW9uLCBDb250ZW50LVR5cGUnLAogICAgJ1gtUmVib290bHktVmVyc2lvbic6ICAgICAgICAgIFZFUlNJT04sCiAgfSk7CiAgcmVzLmVuZChib2R5KTsKfTsKCmNvbnN0IHJlYWRCb2R5ID0gKHJlcSkgPT4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4gewogIGxldCBkID0gJyc7CiAgcmVxLm9uKCdkYXRhJywgYyA9PiB7IGQgKz0gYzsgaWYgKGQubGVuZ3RoID4gMTBlNikgcmVqZWN0KG5ldyBFcnJvcignQm9keSB0cm9wIGdyYW5kJykpOyB9KTsKICByZXEub24oJ2VuZCcsICgpID0+IHsgdHJ5IHsgcmVzb2x2ZShKU09OLnBhcnNlKGQgfHwgJ3t9JykpOyB9IGNhdGNoIHsgcmVzb2x2ZSh7fSk7IH0gfSk7CiAgcmVxLm9uKCdlcnJvcicsIHJlamVjdCk7Cn0pOwoKLy8g4pSA4pSAIE1hcmlhREIgaGVscGVycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKY29uc3QgZGJRdWVyeSA9IChzcWwsIHRpbWVvdXQgPSA4MDAwKSA9PiB7CiAgdHJ5IHsKICAgIGNvbnN0IG91dCA9IGV4ZWNTeW5jKAogICAgICBgZG9ja2VyIGV4ZWMgJHtEQl9OQU1FfSBtYXJpYWRiIC1oIDEyNy4wLjAuMSAtdXBpbGVyIC1wJyR7U1FMX1BBU1N9JyBwaWxlciAtc04gLWUgIiR7c3FsLnJlcGxhY2UoLyIvZywgJ1xcIicpfSJgLAogICAgICB7IHRpbWVvdXQgfQogICAgKS50b1N0cmluZygpLnRyaW0oKTsKICAgIHJldHVybiBvdXQ7CiAgfSBjYXRjaCAoZSkgeyB0aHJvdyBuZXcgRXJyb3IoJ0RCIGVycm9yOiAnICsgZS5tZXNzYWdlLnNsaWNlKDAsIDIwMCkpOyB9Cn07Cgpjb25zdCBkYlJvd3MgPSAoc3FsKSA9PiB7CiAgY29uc3Qgb3V0ID0gZGJRdWVyeShzcWwpOwogIGlmICghb3V0KSByZXR1cm4gW107CiAgcmV0dXJuIG91dC5zcGxpdCgnXG4nKS5tYXAocm93ID0+IHJvdy5zcGxpdCgnXHQnKSk7Cn07CgovLyDilIDilIAgVsOpcmlmaWNhdGlvbiBtb3QgZGUgcGFzc2UgU0hBLTUxMiBjcnlwdCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLy8gUHl0aG9uJ3MgY3J5cHQgbW9kdWxlIGfDqHJlIFNIQS01MTIgKCQ2JCkgbmF0aXZlbWVudApjb25zdCB2ZXJpZnlQYXNzd29yZCA9IChwYXNzd29yZCwgaGFzaCkgPT4gewogIHRyeSB7CiAgICBjb25zdCByZXN1bHQgPSBzcGF3blN5bmMoJ3B5dGhvbjMnLCBbJy1jJywKICAgICAgYGltcG9ydCBjcnlwdDsgcHJpbnQoJ09LJyBpZiBjcnlwdC5jcnlwdCgke0pTT04uc3RyaW5naWZ5KHBhc3N3b3JkKX0sICR7SlNPTi5zdHJpbmdpZnkoaGFzaCl9KSA9PSAke0pTT04uc3RyaW5naWZ5KGhhc2gpfSBlbHNlICdGQUlMJylgCiAgICBdLCB7IHRpbWVvdXQ6IDMwMDAgfSk7CiAgICByZXR1cm4gcmVzdWx0LnN0ZG91dC50b1N0cmluZygpLnRyaW0oKSA9PT0gJ09LJzsKICB9IGNhdGNoIHsgcmV0dXJuIGZhbHNlOyB9Cn07CgovLyDilIDilIAgUHJveHkgdmVycyBNYWlscGlsZXIgUEhQIGludGVybmUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmNvbnN0IHBpbGVyRmV0Y2ggPSAobWV0aG9kLCBwYXRoLCBib2R5ID0gbnVsbCwgY29va2llID0gJycpID0+IHsKICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4gewogICAgY29uc3Qgb3B0cyA9IHsKICAgICAgaG9zdG5hbWU6ICcxMjcuMC4wLjEnLCBwb3J0OiBQSUxFUl9QT1JULCBwYXRoLCBtZXRob2QsCiAgICAgIGhlYWRlcnM6IHsKICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcsCiAgICAgICAgJ1VzZXItQWdlbnQnOiAgICdSZWJvb3RseS1CcmlkZ2UvMi4wJywKICAgICAgICAnQ29va2llJzogICAgICAgY29va2llLAogICAgICB9LAogICAgfTsKICAgIGlmIChib2R5KSBvcHRzLmhlYWRlcnNbJ0NvbnRlbnQtTGVuZ3RoJ10gPSBCdWZmZXIuYnl0ZUxlbmd0aChib2R5KTsKICAgIGNvbnN0IHJlcSA9IGh0dHAucmVxdWVzdChvcHRzLCByZXMgPT4gewogICAgICBsZXQgZCA9ICcnOwogICAgICByZXMub24oJ2RhdGEnLCBjID0+IGQgKz0gYyk7CiAgICAgIHJlcy5vbignZW5kJywgKCkgPT4gcmVzb2x2ZSh7IHN0YXR1czogcmVzLnN0YXR1c0NvZGUsIGhlYWRlcnM6IHJlcy5oZWFkZXJzLCBib2R5OiBkIH0pKTsKICAgIH0pOwogICAgcmVxLm9uKCdlcnJvcicsIHJlamVjdCk7CiAgICByZXEuc2V0VGltZW91dCgxMDAwMCwgKCkgPT4geyByZXEuZGVzdHJveSgpOyByZWplY3QobmV3IEVycm9yKCdUaW1lb3V0IE1haWxwaWxlcicpKTsgfSk7CiAgICBpZiAoYm9keSkgcmVxLndyaXRlKGJvZHkpOwogICAgcmVxLmVuZCgpOwogIH0pOwp9OwoKLy8gU2Vzc2lvbiBQaWxlciBkZSBzZXJ2aWNlIChhZG1pbikgcG91ciBsZXMgcmVxdcOqdGVzIGludGVybmVzCmxldCBzZXJ2aWNlU2Vzc2lvbiA9IHsgY29va2llOiAnJywgZXhwaXJlczogMCB9OwoKY29uc3QgZ2V0U2VydmljZVNlc3Npb24gPSBhc3luYyAoKSA9PiB7CiAgaWYgKHNlcnZpY2VTZXNzaW9uLmV4cGlyZXMgPiBEYXRlLm5vdygpKSByZXR1cm4gc2VydmljZVNlc3Npb24uY29va2llOwogIC8vIExvZ2luIGF2ZWMgbGUgY29tcHRlIGFkbWluIHZpYSBNYWlscGlsZXIgUEhQCiAgY29uc3QgYWRtaW5Sb3cgPSBkYlJvd3MoJ1NFTEVDVCB1c2VybmFtZSwgcGFzc3dvcmQgRlJPTSB1c2VyIFdIRVJFIHVpZD0wJylbMF07CiAgaWYgKCFhZG1pblJvdykgdGhyb3cgbmV3IEVycm9yKCdDb21wdGUgYWRtaW4gaW50cm91dmFibGUnKTsKICAvLyBPbiBuZSBwZXV0IHBhcyBpbnZlcnNlciBsZSBoYXNoIOKAlCBvbiB1dGlsaXNlIHVuIHRva2VuIGRpcmVjdCB2aWEgdW4gZW5kcG9pbnQgaW50ZXJuZQogIC8vIE1haWxwaWxlciBhY2NlcHRlIHVuZSBjb25uZXhpb24gcGFyIGNvb2tpZSBzaSBvbiBjb25uYcOudCBsZSBoYXNoCiAgLy8gQWx0ZXJuYXRpdmUgOiBhcHBlbCBkaXJlY3Qgc2FucyBzZXNzaW9uIHBvdXIgbGVzIGVuZHBvaW50cyBBUEkgaW50ZXJuZXMKICByZXR1cm4gJyc7Cn07CgovLyDilIDilIAgUm91dGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApjb25zdCByb3V0ZXMgPSB7fTsKCi8vIOKUgOKUgCBBdXRoIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKcm91dGVzWydQT1NUIC92MS9hdXRoL2xvZ2luJ10gPSBhc3luYyAocmVxLCByZXMpID0+IHsKICBjb25zdCB7IHVzZXJuYW1lLCBwYXNzd29yZCB9ID0gYXdhaXQgcmVhZEJvZHkocmVxKTsKICBpZiAoIXVzZXJuYW1lIHx8ICFwYXNzd29yZCkgcmV0dXJuIGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiAnSWRlbnRpZmlhbnRzIHJlcXVpcycgfSwgNDAwKTsKCiAgbGV0IHJvdzsKICB0cnkgewogICAgLy8gQ2hlcmNoZXIgcGFyIHVzZXJuYW1lIG91IGVtYWlsICh1aWQsIHVzZXJuYW1lLCBwYXNzd29yZCwgaXNhZG1pbikKICAgIGNvbnN0IHJvd3MgPSBkYlJvd3MoCiAgICAgIGBTRUxFQ1QgdWlkLCB1c2VybmFtZSwgcGFzc3dvcmQsIGlzYWRtaW4gRlJPTSB1c2VyIFdIRVJFIHVzZXJuYW1lPScke3VzZXJuYW1lLnJlcGxhY2UoLycvZywgIlxcJyIpfScgTElNSVQgMWAKICAgICk7CiAgICByb3cgPSByb3dzWzBdOwogIH0gY2F0Y2ggKGUpIHsgcmV0dXJuIGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiAnRXJyZXVyIERCOiAnICsgZS5tZXNzYWdlIH0sIDUwMCk7IH0KCiAgaWYgKCFyb3cgfHwgcm93Lmxlbmd0aCA8IDQpIHJldHVybiBqc29uKHJlcywgeyBlcnJvcjogdHJ1ZSwgbWVzc2FnZTogJ1V0aWxpc2F0ZXVyIGludHJvdXZhYmxlJyB9LCA0MDEpOwoKICBjb25zdCBbdWlkLCB1bmFtZSwgaGFzaCwgaXNhZG1pbl0gPSByb3c7CiAgY29uc3QgdmFsaWQgPSB2ZXJpZnlQYXNzd29yZChwYXNzd29yZCwgaGFzaCk7CiAgaWYgKCF2YWxpZCkgcmV0dXJuIGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiAnTW90IGRlIHBhc3NlIGluY29ycmVjdCcgfSwgNDAxKTsKCiAgY29uc3QgZXhwID0gTWF0aC5mbG9vcihEYXRlLm5vdygpLzEwMDApICsgODY0MDAgKiA3OyAvLyA3IGpvdXJzCiAgY29uc3QgdG9rZW4gPSBqd3RTaWduKHsgdWlkLCB1c2VybmFtZTogdW5hbWUsIGlzYWRtaW46IGlzYWRtaW4gPT09ICcxJywgZXhwIH0pOwoKICBqc29uKHJlcywgewogICAgb2s6ICAgICAgIHRydWUsCiAgICB0b2tlbiwKICAgIGV4cCwKICAgIHVzZXI6IHsgdWlkLCB1c2VybmFtZTogdW5hbWUsIGlzYWRtaW46IGlzYWRtaW4gPT09ICcxJyB9LAogIH0pOwp9OwoKcm91dGVzWydHRVQgL3YxL2F1dGgvbWUnXSA9IGFzeW5jIChyZXEsIHJlcykgPT4gewogIGNvbnN0IHVzZXIgPSByZXF1aXJlQXV0aChyZXEsIHJlcyk7CiAgaWYgKCF1c2VyKSByZXR1cm47CiAganNvbihyZXMsIHsgb2s6IHRydWUsIHVzZXIgfSk7Cn07CgovLyDilIDilIAgU3RhdHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpyb3V0ZXNbJ0dFVCAvdjEvc3RhdHMnXSA9IGFzeW5jIChyZXEsIHJlcykgPT4gewogIGlmICghcmVxdWlyZUF1dGgocmVxLCByZXMpKSByZXR1cm47CiAgdHJ5IHsKICAgIGNvbnN0IFt0b3RhbCwgYnl0ZXMsIGxhc3RdID0gZGJRdWVyeSgKICAgICAgJ1NFTEVDVCBDT1VOVCgqKSwgQ09BTEVTQ0UoU1VNKHNpemUpLDApLCBNQVgoYXJyaXZlZCkgRlJPTSBtZXRhZGF0YSBXSEVSRSBkZWxldGVkPTAnCiAgICApLnNwbGl0KCdcdCcpOwoKICAgIGNvbnN0IFt0b2RheV0gPSBkYlF1ZXJ5KAogICAgICBgU0VMRUNUIENPVU5UKCopIEZST00gbWV0YWRhdGEgV0hFUkUgZGVsZXRlZD0wIEFORCBhcnJpdmVkID49IFVOSVhfVElNRVNUQU1QKENVUkRBVEUoKSlgCiAgICApLnNwbGl0KCdcdCcpOwoKICAgIGNvbnN0IFt1c2Vyc10gPSBkYlF1ZXJ5KCdTRUxFQ1QgQ09VTlQoKikgRlJPTSB1c2VyJykuc3BsaXQoJ1x0Jyk7CiAgICBjb25zdCBbZG9tYWluc10gPSBkYlF1ZXJ5KCdTRUxFQ1QgQ09VTlQoKikgRlJPTSBkb21haW4nKS5zcGxpdCgnXHQnKTsKCiAgICBqc29uKHJlcywgewogICAgICB0b3RhbF9lbWFpbHM6ICBwYXJzZUludCh0b3RhbCkgIHx8IDAsCiAgICAgIHRvdGFsX2J5dGVzOiAgIHBhcnNlSW50KGJ5dGVzKSAgfHwgMCwKICAgICAgdG9kYXlfZW1haWxzOiAgcGFyc2VJbnQodG9kYXkpICB8fCAwLAogICAgICB0b3RhbF91c2VyczogICBwYXJzZUludCh1c2VycykgIHx8IDAsCiAgICAgIHRvdGFsX2RvbWFpbnM6IHBhcnNlSW50KGRvbWFpbnMpfHwgMCwKICAgICAgbGFzdF9lbWFpbDogICAgbGFzdCAmJiBsYXN0ICE9PSAnTlVMTCcgPyBuZXcgRGF0ZShwYXJzZUludChsYXN0KSoxMDAwKS50b0lTT1N0cmluZygpIDogbnVsbCwKICAgIH0pOwogIH0gY2F0Y2ggKGUpIHsganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6IGUubWVzc2FnZSB9LCA1MDApOyB9Cn07CgovLyDilIDilIAgU2FudMOpIGNvbnRhaW5lcnMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpyb3V0ZXNbJ0dFVCAvdjEvaGVhbHRoJ10gPSBhc3luYyAocmVxLCByZXMpID0+IHsKICBpZiAoIXJlcXVpcmVBdXRoKHJlcSwgcmVzKSkgcmV0dXJuOwogIHRyeSB7CiAgICBjb25zdCBvdXQgPSBleGVjU3luYygKICAgICAgYGRvY2tlciBwcyAtLWZvcm1hdCAne3suTmFtZXN9fXx7ey5TdGF0dXN9fXx7ey5TdGF0ZX19JyAtLWZpbHRlciAnbmFtZT1yYi0nYCwgeyB0aW1lb3V0OiA1MDAwIH0KICAgICkudG9TdHJpbmcoKS50cmltKCk7CiAgICBjb25zdCBjb250YWluZXJzID0gb3V0LnNwbGl0KCdcbicpLmZpbHRlcihCb29sZWFuKS5tYXAobGluZSA9PiB7CiAgICAgIGNvbnN0IFtuYW1lLCBzdGF0dXMsIHN0YXRlXSA9IGxpbmUuc3BsaXQoJ3wnKTsKICAgICAgcmV0dXJuIHsgbmFtZSwgc3RhdHVzLCBydW5uaW5nOiBzdGF0ZSA9PT0gJ3J1bm5pbmcnIH07CiAgICB9KTsKICAgIGpzb24ocmVzLCB7IG9rOiBjb250YWluZXJzLmV2ZXJ5KGMgPT4gYy5ydW5uaW5nKSwgY29udGFpbmVycyB9KTsKICB9IGNhdGNoIChlKSB7IGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiBlLm1lc3NhZ2UgfSwgNTAwKTsgfQp9OwoKLy8g4pSA4pSAIEVtYWlscyDigJQgcmVjaGVyY2hlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKcm91dGVzWydHRVQgL3YxL2VtYWlscyddID0gYXN5bmMgKHJlcSwgcmVzKSA9PiB7CiAgaWYgKCFyZXF1aXJlQXV0aChyZXEsIHJlcykpIHJldHVybjsKICBjb25zdCBxICAgICA9IHJlcS5xdWVyeTsKICBjb25zdCBwYWdlICA9IE1hdGgubWF4KDAsIHBhcnNlSW50KHEucGFnZSAgfHwgJzAnKSk7CiAgY29uc3QgbGltaXQgPSBNYXRoLm1pbigxMDAsIHBhcnNlSW50KHEubGltaXQgfHwgJzI1JykpOwogIGNvbnN0IG9mZnNldCA9IHBhZ2UgKiBsaW1pdDsKCiAgbGV0IHdoZXJlID0gJ1dIRVJFIG0uZGVsZXRlZD0wJzsKICBpZiAocS5xKSAgICAgd2hlcmUgKz0gYCBBTkQgKG0uc3ViamVjdCBMSUtFICclJHtxLnEucmVwbGFjZSgvJy9nLCJcXCciKX0lJyBPUiBlLmVtYWlsIExJS0UgJyUke3EucS5yZXBsYWNlKC8nL2csIlxcJyIpfSUnKWA7CiAgaWYgKHEuZnJvbSkgIHdoZXJlICs9IGAgQU5EIGUuZW1haWwgTElLRSAnJSR7cS5mcm9tLnJlcGxhY2UoLycvZywiXFwnIil9JSdgOwogIGlmIChxLnN0YXJ0KSB3aGVyZSArPSBgIEFORCBtLmFycml2ZWQgPj0gJHtwYXJzZUludChxLnN0YXJ0KX1gOwogIGlmIChxLmVuZCkgICB3aGVyZSArPSBgIEFORCBtLmFycml2ZWQgPD0gJHtwYXJzZUludChxLmVuZCl9YDsKCiAgdHJ5IHsKICAgIGNvbnN0IFt0b3RhbF0gPSBkYlF1ZXJ5KAogICAgICBgU0VMRUNUIENPVU5UKCopIEZST00gbWV0YWRhdGEgbSBMRUZUIEpPSU4gZW1haWwgZSBPTiBtLmlkPWUuaWQgJHt3aGVyZX1gCiAgICApLnNwbGl0KCdcdCcpOwoKICAgIGNvbnN0IHJvd3MgPSBkYlJvd3MoCiAgICAgIGBTRUxFQ1QgbS5pZCwgbS5zdWJqZWN0LCBlLmVtYWlsIGFzIHNlbmRlciwgbS5hcnJpdmVkLCBtLnNpemUsIG0uZGVsZXRlZAogICAgICAgRlJPTSBtZXRhZGF0YSBtIExFRlQgSk9JTiBlbWFpbCBlIE9OIG0uaWQ9ZS5pZAogICAgICAgJHt3aGVyZX0gT1JERVIgQlkgbS5hcnJpdmVkIERFU0MgTElNSVQgJHtsaW1pdH0gT0ZGU0VUICR7b2Zmc2V0fWAKICAgICk7CgogICAgY29uc3QgZW1haWxzID0gcm93cy5maWx0ZXIociA9PiByLmxlbmd0aCA+PSA1KS5tYXAociA9PiAoewogICAgICBpZDogICAgICByWzBdLAogICAgICBzdWJqZWN0OiByWzFdIHx8ICcoc2FucyBvYmpldCknLAogICAgICBmcm9tOiAgICByWzJdIHx8ICcnLAogICAgICBkYXRlOiAgICByWzNdID8gbmV3IERhdGUocGFyc2VJbnQoclszXSkqMTAwMCkudG9JU09TdHJpbmcoKSA6IG51bGwsCiAgICAgIHNpemU6ICAgIHBhcnNlSW50KHJbNF0pIHx8IDAsCiAgICB9KSk7CgogICAganNvbihyZXMsIHsgdG90YWw6IHBhcnNlSW50KHRvdGFsKXx8MCwgcGFnZSwgbGltaXQsIGVtYWlscyB9KTsKICB9IGNhdGNoIChlKSB7IGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiBlLm1lc3NhZ2UgfSwgNTAwKTsgfQp9OwoKLy8g4pSA4pSAIFV0aWxpc2F0ZXVycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCnJvdXRlc1snR0VUIC92MS91c2VycyddID0gYXN5bmMgKHJlcSwgcmVzKSA9PiB7CiAgaWYgKCFyZXF1aXJlQWRtaW4ocmVxLCByZXMpKSByZXR1cm47CiAgdHJ5IHsKICAgIGNvbnN0IHJvd3MgPSBkYlJvd3MoJ1NFTEVDVCB1aWQsIHVzZXJuYW1lLCByZWFsbmFtZSwgaXNhZG1pbiBGUk9NIHVzZXIgT1JERVIgQlkgdWlkJyk7CiAgICBjb25zdCB1c2VycyA9IHJvd3MuZmlsdGVyKHIgPT4gci5sZW5ndGggPj0gNCkubWFwKHIgPT4gKHsKICAgICAgdWlkOiBwYXJzZUludChyWzBdKSwgdXNlcm5hbWU6IHJbMV0sIHJlYWxuYW1lOiByWzJdIHx8ICcnLCBpc2FkbWluOiByWzNdID09PSAnMScsCiAgICB9KSk7CiAgICBqc29uKHJlcywgeyB1c2VycyB9KTsKICB9IGNhdGNoIChlKSB7IGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiBlLm1lc3NhZ2UgfSwgNTAwKTsgfQp9OwoKcm91dGVzWydQT1NUIC92MS91c2VycyddID0gYXN5bmMgKHJlcSwgcmVzKSA9PiB7CiAgaWYgKCFyZXF1aXJlQWRtaW4ocmVxLCByZXMpKSByZXR1cm47CiAgY29uc3QgeyB1c2VybmFtZSwgcGFzc3dvcmQsIHJlYWxuYW1lID0gJycsIGlzYWRtaW4gPSAwIH0gPSBhd2FpdCByZWFkQm9keShyZXEpOwogIGlmICghdXNlcm5hbWUgfHwgIXBhc3N3b3JkKSByZXR1cm4ganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6ICd1c2VybmFtZSBldCBwYXNzd29yZCByZXF1aXMnIH0sIDQwMCk7CgogIC8vIEfDqW7DqXJlciBoYXNoIFNIQS01MTIKICBsZXQgaGFzaDsKICB0cnkgewogICAgaGFzaCA9IHNwYXduU3luYygncHl0aG9uMycsIFsnLWMnLAogICAgICBgaW1wb3J0IGNyeXB0OyBwcmludChjcnlwdC5jcnlwdCgke0pTT04uc3RyaW5naWZ5KHBhc3N3b3JkKX0sIGNyeXB0Lm1rc2FsdChjcnlwdC5NRVRIT0RfU0hBNTEyKSkpYAogICAgXSwgeyB0aW1lb3V0OiAzMDAwIH0pLnN0ZG91dC50b1N0cmluZygpLnRyaW0oKTsKICB9IGNhdGNoIHsgcmV0dXJuIGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiAnRXJyZXVyIGfDqW7DqXJhdGlvbiBoYXNoJyB9LCA1MDApOyB9CgogIHRyeSB7CiAgICBkYlF1ZXJ5KGBJTlNFUlQgSU5UTyB1c2VyICh1c2VybmFtZSwgcmVhbG5hbWUsIHBhc3N3b3JkLCBpc2FkbWluKSBWQUxVRVMgKCcke3VzZXJuYW1lLnJlcGxhY2UoLycvZywiXFwnIil9JywnJHtyZWFsbmFtZS5yZXBsYWNlKC8nL2csIlxcJyIpfScsJyR7aGFzaH0nLCR7aXNhZG1pbj8xOjB9KWApOwogICAganNvbihyZXMsIHsgb2s6IHRydWUsIG1lc3NhZ2U6ICdVdGlsaXNhdGV1ciBjcsOpw6knIH0sIDIwMSk7CiAgfSBjYXRjaCAoZSkgeyBqc29uKHJlcywgeyBlcnJvcjogdHJ1ZSwgbWVzc2FnZTogZS5tZXNzYWdlIH0sIDUwMCk7IH0KfTsKCnJvdXRlc1snREVMRVRFIC92MS91c2Vycy86dWlkJ10gPSBhc3luYyAocmVxLCByZXMsIHsgdWlkIH0pID0+IHsKICBpZiAoIXJlcXVpcmVBZG1pbihyZXEsIHJlcykpIHJldHVybjsKICBpZiAodWlkID09PSAnMCcpIHJldHVybiBqc29uKHJlcywgeyBlcnJvcjogdHJ1ZSwgbWVzc2FnZTogJ0ltcG9zc2libGUgZGUgc3VwcHJpbWVyIGxcJ2FkbWluIHByaW5jaXBhbCcgfSwgNDAwKTsKICB0cnkgewogICAgZGJRdWVyeShgREVMRVRFIEZST00gdXNlciBXSEVSRSB1aWQ9JHtwYXJzZUludCh1aWQpfWApOwogICAganNvbihyZXMsIHsgb2s6IHRydWUgfSk7CiAgfSBjYXRjaCAoZSkgeyBqc29uKHJlcywgeyBlcnJvcjogdHJ1ZSwgbWVzc2FnZTogZS5tZXNzYWdlIH0sIDUwMCk7IH0KfTsKCnJvdXRlc1snUEFUQ0ggL3YxL3VzZXJzLzp1aWQvcGFzc3dvcmQnXSA9IGFzeW5jIChyZXEsIHJlcywgeyB1aWQgfSkgPT4gewogIGNvbnN0IHVzZXIgPSByZXF1aXJlQXV0aChyZXEsIHJlcyk7CiAgaWYgKCF1c2VyKSByZXR1cm47CiAgLy8gVW4gdXNlciBwZXV0IGNoYW5nZXIgc29uIHByb3ByZSBtZHAsIHVuIGFkbWluIHBldXQgY2hhbmdlciBuJ2ltcG9ydGUgbGVxdWVsCiAgaWYgKFN0cmluZyh1c2VyLnVpZCkgIT09IHVpZCAmJiAhdXNlci5pc2FkbWluKQogICAgcmV0dXJuIGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiAnTm9uIGF1dG9yaXPDqScgfSwgNDAzKTsKCiAgY29uc3QgeyBwYXNzd29yZCB9ID0gYXdhaXQgcmVhZEJvZHkocmVxKTsKICBpZiAoIXBhc3N3b3JkKSByZXR1cm4ganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6ICdwYXNzd29yZCByZXF1aXMnIH0sIDQwMCk7CgogIGxldCBoYXNoOwogIHRyeSB7CiAgICBoYXNoID0gc3Bhd25TeW5jKCdweXRob24zJywgWyctYycsCiAgICAgIGBpbXBvcnQgY3J5cHQ7IHByaW50KGNyeXB0LmNyeXB0KCR7SlNPTi5zdHJpbmdpZnkocGFzc3dvcmQpfSwgY3J5cHQubWtzYWx0KGNyeXB0Lk1FVEhPRF9TSEE1MTIpKSlgCiAgICBdLCB7IHRpbWVvdXQ6IDMwMDAgfSkuc3Rkb3V0LnRvU3RyaW5nKCkudHJpbSgpOwogIH0gY2F0Y2ggeyByZXR1cm4ganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6ICdFcnJldXIgZ8OpbsOpcmF0aW9uIGhhc2gnIH0sIDUwMCk7IH0KCiAgdHJ5IHsKICAgIGRiUXVlcnkoYFVQREFURSB1c2VyIFNFVCBwYXNzd29yZD0nJHtoYXNofScgV0hFUkUgdWlkPSR7cGFyc2VJbnQodWlkKX1gKTsKICAgIGpzb24ocmVzLCB7IG9rOiB0cnVlIH0pOwogIH0gY2F0Y2ggKGUpIHsganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6IGUubWVzc2FnZSB9LCA1MDApOyB9Cn07CgovLyDilIDilIAgRG9tYWluZXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpyb3V0ZXNbJ0dFVCAvdjEvZG9tYWlucyddID0gYXN5bmMgKHJlcSwgcmVzKSA9PiB7CiAgaWYgKCFyZXF1aXJlQWRtaW4ocmVxLCByZXMpKSByZXR1cm47CiAgdHJ5IHsKICAgIGNvbnN0IHJvd3MgPSBkYlJvd3MoJ1NFTEVDVCBpZCwgZG9tYWluLCBhY2NlcHRfb3V0Z29pbmcgRlJPTSBkb21haW4gT1JERVIgQlkgZG9tYWluJyk7CiAgICBjb25zdCBkb21haW5zID0gcm93cy5maWx0ZXIociA9PiByLmxlbmd0aCA+PSAzKS5tYXAociA9PiAoewogICAgICBpZDogcGFyc2VJbnQoclswXSksIGRvbWFpbjogclsxXSwgYWNjZXB0X291dGdvaW5nOiByWzJdID09PSAnMScsCiAgICB9KSk7CiAgICBqc29uKHJlcywgeyBkb21haW5zIH0pOwogIH0gY2F0Y2ggKGUpIHsganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6IGUubWVzc2FnZSB9LCA1MDApOyB9Cn07Cgpyb3V0ZXNbJ1BPU1QgL3YxL2RvbWFpbnMnXSA9IGFzeW5jIChyZXEsIHJlcykgPT4gewogIGlmICghcmVxdWlyZUFkbWluKHJlcSwgcmVzKSkgcmV0dXJuOwogIGNvbnN0IHsgZG9tYWluLCBhY2NlcHRfb3V0Z29pbmcgPSAwIH0gPSBhd2FpdCByZWFkQm9keShyZXEpOwogIGlmICghZG9tYWluKSByZXR1cm4ganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6ICdkb21haW4gcmVxdWlzJyB9LCA0MDApOwogIHRyeSB7CiAgICBkYlF1ZXJ5KGBJTlNFUlQgSU5UTyBkb21haW4gKGRvbWFpbiwgYWNjZXB0X291dGdvaW5nKSBWQUxVRVMgKCcke2RvbWFpbi5yZXBsYWNlKC8nL2csIlxcJyIpfScsJHthY2NlcHRfb3V0Z29pbmc/MTowfSlgKTsKICAgIGpzb24ocmVzLCB7IG9rOiB0cnVlLCBtZXNzYWdlOiAnRG9tYWluZSBham91dMOpJyB9LCAyMDEpOwogIH0gY2F0Y2ggKGUpIHsganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6IGUubWVzc2FnZSB9LCA1MDApOyB9Cn07Cgpyb3V0ZXNbJ0RFTEVURSAvdjEvZG9tYWlucy86aWQnXSA9IGFzeW5jIChyZXEsIHJlcywgeyBpZCB9KSA9PiB7CiAgaWYgKCFyZXF1aXJlQWRtaW4ocmVxLCByZXMpKSByZXR1cm47CiAgdHJ5IHsKICAgIGRiUXVlcnkoYERFTEVURSBGUk9NIGRvbWFpbiBXSEVSRSBpZD0ke3BhcnNlSW50KGlkKX1gKTsKICAgIGpzb24ocmVzLCB7IG9rOiB0cnVlIH0pOwogIH0gY2F0Y2ggKGUpIHsganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6IGUubWVzc2FnZSB9LCA1MDApOyB9Cn07CgovLyDilIDilIAgQXVkaXQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpyb3V0ZXNbJ0dFVCAvdjEvYXVkaXQnXSA9IGFzeW5jIChyZXEsIHJlcykgPT4gewogIGlmICghcmVxdWlyZUFkbWluKHJlcSwgcmVzKSkgcmV0dXJuOwogIGNvbnN0IHEgICAgICA9IHJlcS5xdWVyeTsKICBjb25zdCBsaW1pdCAgPSBNYXRoLm1pbigyMDAsIHBhcnNlSW50KHEubGltaXQgfHwgJzUwJykpOwogIGNvbnN0IG9mZnNldCA9IE1hdGgubWF4KDAsIHBhcnNlSW50KHEucGFnZSB8fCAnMCcpKSAqIGxpbWl0OwogIHRyeSB7CiAgICBjb25zdCByb3dzID0gZGJSb3dzKAogICAgICBgU0VMRUNUIGlkLCB1c2VybmFtZSwgZXZlbnQsIGlwLCB0cyBGUk9NIGF1ZGl0IE9SREVSIEJZIHRzIERFU0MgTElNSVQgJHtsaW1pdH0gT0ZGU0VUICR7b2Zmc2V0fWAKICAgICk7CiAgICBjb25zdCBlbnRyaWVzID0gcm93cy5maWx0ZXIociA9PiByLmxlbmd0aCA+PSA1KS5tYXAociA9PiAoewogICAgICBpZDogcGFyc2VJbnQoclswXSksIHVzZXJuYW1lOiByWzFdLCBldmVudDogclsyXSwgaXA6IHJbM10sCiAgICAgIHRzOiByWzRdID8gbmV3IERhdGUocGFyc2VJbnQocls0XSkqMTAwMCkudG9JU09TdHJpbmcoKSA6IG51bGwsCiAgICB9KSk7CiAgICBqc29uKHJlcywgeyBlbnRyaWVzIH0pOwogIH0gY2F0Y2ggKGUpIHsganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6IGUubWVzc2FnZSB9LCA1MDApOyB9Cn07CgovLyDilIDilIAgUGFyYW3DqHRyZXMgaW5zdGFuY2Ug4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpyb3V0ZXNbJ0dFVCAvdjEvc2V0dGluZ3MnXSA9IGFzeW5jIChyZXEsIHJlcykgPT4gewogIGlmICghcmVxdWlyZUFkbWluKHJlcSwgcmVzKSkgcmV0dXJuOwogIHRyeSB7CiAgICBjb25zdCByb3dzID0gZGJSb3dzKCdTRUxFQ1QgcGFyYW0sIHZhbHVlIEZST00gb3B0aW9uJyk7CiAgICBjb25zdCBzZXR0aW5ncyA9IHt9OwogICAgcm93cy5maWx0ZXIociA9PiByLmxlbmd0aCA+PSAyKS5mb3JFYWNoKHIgPT4geyBzZXR0aW5nc1tyWzBdXSA9IHJbMV07IH0pOwogICAgLy8gQWpvdXRlciBpbmZvcyBzdGF0aXF1ZXMKICAgIHNldHRpbmdzLl9kb21haW4gICAgID0gRE9NQUlOOwogICAgc2V0dGluZ3MuX2x4Y19pcCAgICAgPSBMWENfSVA7CiAgICBzZXR0aW5ncy5fYWNjb3VudF9pZCA9IEFDQ09VTlRfSUQ7CiAgICBzZXR0aW5ncy5fdmVyc2lvbiAgICA9IFZFUlNJT047CiAgICBqc29uKHJlcywgeyBzZXR0aW5ncyB9KTsKICB9IGNhdGNoIChlKSB7IGpzb24ocmVzLCB7IGVycm9yOiB0cnVlLCBtZXNzYWdlOiBlLm1lc3NhZ2UgfSwgNTAwKTsgfQp9OwoKcm91dGVzWydQQVRDSCAvdjEvc2V0dGluZ3MnXSA9IGFzeW5jIChyZXEsIHJlcykgPT4gewogIGlmICghcmVxdWlyZUFkbWluKHJlcSwgcmVzKSkgcmV0dXJuOwogIGNvbnN0IGJvZHkgPSBhd2FpdCByZWFkQm9keShyZXEpOwogIC8vIENoYW1wcyBhdXRvcmlzw6lzIMOgIG1vZGlmaWVyCiAgY29uc3QgYWxsb3dlZCA9IFsncmV0ZW50aW9uX2RheXMnLCAnbWF4X21zZ19zaXplJywgJ2VuYWJsZV9hdWRpdCcsICdkaWdlc3RfZGF5cyddOwogIHRyeSB7CiAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyhib2R5KSkgewogICAgICBpZiAoIWFsbG93ZWQuaW5jbHVkZXMoaykpIGNvbnRpbnVlOwogICAgICBkYlF1ZXJ5KGBJTlNFUlQgSU5UTyBvcHRpb24gKHBhcmFtLCB2YWx1ZSkgVkFMVUVTICgnJHtrfScsJyR7U3RyaW5nKHYpLnJlcGxhY2UoLycvZywiXFwnIil9JykgT04gRFVQTElDQVRFIEtFWSBVUERBVEUgdmFsdWU9JyR7U3RyaW5nKHYpLnJlcGxhY2UoLycvZywiXFwnIil9J2ApOwogICAgfQogICAganNvbihyZXMsIHsgb2s6IHRydWUgfSk7CiAgfSBjYXRjaCAoZSkgeyBqc29uKHJlcywgeyBlcnJvcjogdHJ1ZSwgbWVzc2FnZTogZS5tZXNzYWdlIH0sIDUwMCk7IH0KfTsKCi8vIOKUgOKUgCBTdGF0dXMgaW5zdGFuY2Ug4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpyb3V0ZXNbJ0dFVCAvdjEvc3RhdHVzJ10gPSBhc3luYyAocmVxLCByZXMpID0+IHsKICB0cnkgewogICAgY29uc3QgciA9IGF3YWl0IHBpbGVyRmV0Y2goJ0dFVCcsICcvJyk7CiAgICBqc29uKHJlcywgewogICAgICBvazogICAgICAgICByLnN0YXR1cyA9PT0gMjAwIHx8IHIuc3RhdHVzID09PSAzMDIsCiAgICAgIHZlcnNpb246ICAgIFZFUlNJT04sCiAgICAgIGNsaWVudF9pZDogIEFDQ09VTlRfSUQsCiAgICAgIGRvbWFpbjogICAgIERPTUFJTiwKICAgICAgbHhjX2lwOiAgICAgTFhDX0lQLAogICAgICB0aW1lc3RhbXA6ICBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksCiAgICB9KTsKICB9IGNhdGNoIChlKSB7IGpzb24ocmVzLCB7IG9rOiBmYWxzZSwgZXJyb3I6IGUubWVzc2FnZSB9LCA1MDMpOyB9Cn07CgovLyDilIDilIAgSW1wb3J0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKcm91dGVzWydQT1NUIC92MS9pbXBvcnQvdHJpZ2dlciddID0gYXN5bmMgKHJlcSwgcmVzKSA9PiB7CiAgaWYgKCFyZXF1aXJlQWRtaW4ocmVxLCByZXMpKSByZXR1cm47CiAgZXhlYyhgZG9ja2VyIGV4ZWMgJHtQSUxFUl9OQU1FfSBwaWxlcmltcG9ydCAtciAyPi9kZXYvbnVsbCB8fCB0cnVlYCk7CiAganNvbihyZXMsIHsgb2s6IHRydWUsIG1lc3NhZ2U6ICdJbXBvcnQgZMOpY2xlbmNow6knIH0pOwp9OwoKLy8g4pSA4pSAIFNlcnZldXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACmNvbnN0IG1hdGNoUm91dGUgPSAobWV0aG9kLCBwYXRobmFtZSkgPT4gewogIGZvciAoY29uc3QgW2tleSwgaGFuZGxlcl0gb2YgT2JqZWN0LmVudHJpZXMocm91dGVzKSkgewogICAgY29uc3QgW20sIHBdID0ga2V5LnNwbGl0KCcgJyk7CiAgICBpZiAobSAhPT0gbWV0aG9kKSBjb250aW51ZTsKICAgIGNvbnN0IHBhcmFtTmFtZXMgPSBbXTsKICAgIGNvbnN0IHJlZ2V4ID0gbmV3IFJlZ0V4cCgnXicgKyBwLnJlcGxhY2UoLzooXHcrKS9nLCAoXywgbikgPT4geyBwYXJhbU5hbWVzLnB1c2gobik7IHJldHVybiAnKFteL10rKSc7IH0pICsgJyQnKTsKICAgIGNvbnN0IG1hdGNoID0gcGF0aG5hbWUubWF0Y2gocmVnZXgpOwogICAgaWYgKG1hdGNoKSB7CiAgICAgIGNvbnN0IHBhcmFtcyA9IHt9OwogICAgICBwYXJhbU5hbWVzLmZvckVhY2goKG4sIGkpID0+IHBhcmFtc1tuXSA9IG1hdGNoW2krMV0pOwogICAgICByZXR1cm4geyBoYW5kbGVyLCBwYXJhbXMgfTsKICAgIH0KICB9CiAgcmV0dXJuIG51bGw7Cn07CgpodHRwLmNyZWF0ZVNlcnZlcihhc3luYyAocmVxLCByZXMpID0+IHsKICBpZiAocmVxLm1ldGhvZCA9PT0gJ09QVElPTlMnKSB7CiAgICByZXMud3JpdGVIZWFkKDIwNCwgeyAnQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJzogJyonLCAnQWNjZXNzLUNvbnRyb2wtQWxsb3ctTWV0aG9kcyc6ICdHRVQsUE9TVCxQVVQsUEFUQ0gsREVMRVRFLE9QVElPTlMnLCAnQWNjZXNzLUNvbnRyb2wtQWxsb3ctSGVhZGVycyc6ICdBdXRob3JpemF0aW9uLENvbnRlbnQtVHlwZScgfSk7CiAgICByZXR1cm4gcmVzLmVuZCgpOwogIH0KCiAgY29uc3QgcGFyc2VkID0gdXJsLnBhcnNlKHJlcS51cmwsIHRydWUpOwogIHJlcS5xdWVyeSAgICA9IHBhcnNlZC5xdWVyeTsKICBjb25zdCBwYXRoICAgPSBwYXJzZWQucGF0aG5hbWUucmVwbGFjZSgvXlwvcmItYXBpLywgJycpOwoKICB0cnkgewogICAgY29uc3QgbWF0Y2ggPSBtYXRjaFJvdXRlKHJlcS5tZXRob2QsIHBhdGgpOwogICAgaWYgKG1hdGNoKSBhd2FpdCBtYXRjaC5oYW5kbGVyKHJlcSwgcmVzLCBtYXRjaC5wYXJhbXMpOwogICAgZWxzZSBqc29uKHJlcywgeyBlcnJvcjogdHJ1ZSwgbWVzc2FnZTogYFJvdXRlIGluY29ubnVlOiAke3JlcS5tZXRob2R9ICR7cGF0aH1gIH0sIDQwNCk7CiAgfSBjYXRjaCAoZSkgewogICAganNvbihyZXMsIHsgZXJyb3I6IHRydWUsIG1lc3NhZ2U6IGUubWVzc2FnZSB9LCA1MDApOwogIH0KfSkubGlzdGVuKFBPUlQsICcxMjcuMC4wLjEnLCAoKSA9PiB7CiAgY29uc29sZS5sb2coYFtSZWJvb3RseSBCcmlkZ2UgdiR7VkVSU0lPTn1dIFBvcnQgJHtQT1JUfSDigJQgQ2xpZW50ICR7QUNDT1VOVF9JRH0gLyAke0RPTUFJTn1gKTsKfSk7Cgpwcm9jZXNzLm9uKCd1bmNhdWdodEV4Y2VwdGlvbicsIGUgPT4gY29uc29sZS5lcnJvcignW0JyaWRnZV0gRXJyZXVyOicsIGUubWVzc2FnZSkpOwo="

# ── Args ─────────────────────────────────────────────────────────────────────
LXCID=""
UPDATE_BRIDGE=true
UPDATE_UI=true
UPDATE_ALL=false
MISTRAL_API_KEY=""
GROQ_API_KEY=""
ARIANA_URL=""

while [[ $# -gt 0 ]]; do
  case $1 in
    --lxcid)       LXCID="$2"; shift 2 ;;
    --bridge-only) UPDATE_UI=false; shift ;;
    --ui-only)     UPDATE_BRIDGE=false; shift ;;
    --all)         UPDATE_ALL=true; shift ;;
    --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

[[ $EUID -ne 0 ]] && err "Root requis"
command -v pct >/dev/null 2>&1 || err "Proxmox VE requis"

# ── Lister tous les LXC Rebootly si --all ────────────────────────────────────
if [[ "$UPDATE_ALL" == true ]]; then
  LXCS=$(pct list | grep -v VMID | awk '{print $1}')
  if [[ -z "$LXCS" ]]; then
    err "Aucun LXC trouvé"
  fi
  for ID in $LXCS; do
    DESC=$(pct config "$ID" 2>/dev/null | grep "^description:" | head -1 || echo "")
    if echo "$DESC" | grep -qi "rebootly"; then
      echo -e "  ${GREEN}LXC $ID${NC} : $(echo "$DESC" | head -c 60)"
    fi
  done
  echo ""
  read -p "  Mettre à jour tous ces LXC ? [o/N] " -n 1 -r; echo
  [[ ! $REPLY =~ ^[oO]$ ]] && exit 0
  for ID in $LXCS; do
    DESC=$(pct config "$ID" 2>/dev/null | grep "^description:" | head -1 || echo "")
    if echo "$DESC" | grep -qi "rebootly"; then
      echo ""
      echo -e "${CYAN}=== Mise à jour LXC $ID ===${NC}"
      bash "$0" --lxcid "$ID" ${UPDATE_BRIDGE:+} ${UPDATE_UI:+}
    fi
  done
  exit 0
fi

[[ -z "$LXCID" ]] && {
  # Mode interactif
  echo -e "${CYAN}${BOLD}  Rebootly Archives — Mise à jour instance${NC}"
  echo ""
  pct list | grep -v VMID | while read -r ID STATUS NAME; do
    echo -e "  LXC ${BOLD}$ID${NC} — $STATUS — $NAME"
  done
  echo ""
  read -p "  LXC ID à mettre à jour : " LXCID
}

[[ -z "$LXCID" ]] && err "LXC ID obligatoire"

# Vérifier que le LXC existe et est démarré
pct status "$LXCID" >/dev/null 2>&1 || err "LXC $LXCID introuvable"
STATUS=$(pct status "$LXCID" | awk '{print $2}')
if [[ "$STATUS" != "running" ]]; then
  warn "LXC $LXCID non démarré ($STATUS) — démarrage..."
  pct start "$LXCID"
  sleep 5
fi

# Récupérer ACCOUNT_ID depuis le bridge existant
ACCOUNT_ID=$(pct exec "$LXCID" -- bash -c "
  grep \"^const ACCOUNT_ID\" /opt/rebootly/api-bridge.js 2>/dev/null \
    | grep -oP \"'[0-9]+'\" | tr -d \"'\" || echo ''
" 2>/dev/null || echo "")

if [[ -z "$ACCOUNT_ID" ]]; then
  warn "ACCOUNT_ID non trouvé dans le bridge — lecture dans docker ps"
  ACCOUNT_ID=$(pct exec "$LXCID" -- bash -c "
    docker ps --format '{{.Names}}' 2>/dev/null \
      | grep rb-mariadb \
      | sed 's/rb-mariadb-//' | head -1 || echo ''
  " 2>/dev/null || echo "")
fi

[[ -z "$ACCOUNT_ID" ]] && err "Impossible de déterminer ACCOUNT_ID — vérifier l'instance"
ok "ACCOUNT_ID : $ACCOUNT_ID"

# Récupérer les autres variables depuis le bridge
SQL_PASS=$(pct exec "$LXCID" -- bash -c "
  grep \"^const SQL_PASS\" /opt/rebootly/api-bridge.js 2>/dev/null \
    | grep -oP \"'[^']*'\" | tr -d \"'\" || echo ''
" 2>/dev/null || echo "")
API_SECRET=$(pct exec "$LXCID" -- bash -c "
  grep \"^const API_SECRET\" /opt/rebootly/api-bridge.js 2>/dev/null \
    | grep -oP \"'[^']*'\" | tr -d \"'\" || echo ''
" 2>/dev/null || echo "")
DOMAIN=$(pct exec "$LXCID" -- bash -c "
  grep \"^const DOMAIN\" /opt/rebootly/api-bridge.js 2>/dev/null \
    | grep -oP \"'[^']*'\" | tr -d \"'\" || echo ''
" 2>/dev/null || echo "")
LXC_IP=$(pct exec "$LXCID" -- hostname -I 2>/dev/null | awk '{print $1}' || echo "")
MAX_USERS=$(pct exec "$LXCID" -- bash -c "
  grep \"^const MAX_USERS\" /opt/rebootly/api-bridge.js 2>/dev/null \
    | grep -oP \"parseInt\('[^']*'\" | grep -oP \"'[^']*'\" | tr -d \"'\" || echo '0'
" 2>/dev/null || echo "0")
[[ -z "$MAX_USERS" ]] && MAX_USERS=0

info "SQL_PASS   : ${SQL_PASS:0:4}..."
info "API_SECRET : ${API_SECRET:0:4}..."
info "DOMAIN     : $DOMAIN"
info "LXC_IP     : $LXC_IP"
info "MAX_USERS  : $MAX_USERS"

# ── §1 Mise à jour Bridge ──────────────────────────────────────────────────────
if [[ "$UPDATE_BRIDGE" == true ]]; then
  section "Bridge API — mise à jour LXC $LXCID"

  # Backup
  pct exec "$LXCID" -- bash -c "
    cp /opt/rebootly/api-bridge.js /opt/rebootly/api-bridge.js.bak.\$(date +%Y%m%d-%H%M%S) 2>/dev/null || true
  "

  # Déployer le nouveau bridge
  echo "$BRIDGE_B64" | base64 -d > "/tmp/rb-bridge-update-${LXCID}.js"
  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-update-${LXCID}.js"

  pct push "$LXCID" "/tmp/rb-bridge-update-${LXCID}.js" /opt/rebootly/api-bridge.js --perms 644
  rm -f "/tmp/rb-bridge-update-${LXCID}.js"

  # Mettre à jour env vars Ariana si fournis
  if [[ -n "$MISTRAL_API_KEY" ]] || [[ -n "$GROQ_API_KEY" ]] || [[ -n "$ARIANA_URL" ]]; then
    info "Mise à jour variables Ariana AI dans le service systemd..."
    pct exec "$LXCID" -- bash -c "
      SVC=/etc/systemd/system/rebootly-api.service
      # Supprimer anciennes lignes Ariana
      sed -i '/^Environment=MISTRAL_API_KEY=/d' "\$SVC"
      sed -i '/^Environment=GROQ_API_KEY=/d' "\$SVC"
      sed -i '/^Environment=ARIANA_URL=/d' "\$SVC"
      # Ajouter les nouvelles avant StandardOutput
      ANCHOR='StandardOutput='
      $([ -n "${MISTRAL_API_KEY}" ] && echo "sed -i "/\$ANCHOR/i Environment=MISTRAL_API_KEY=${MISTRAL_API_KEY}" "\$SVC"")
      $([ -n "${GROQ_API_KEY}" ] && echo "sed -i "/\$ANCHOR/i Environment=GROQ_API_KEY=${GROQ_API_KEY}" "\$SVC"")
      $([ -n "${ARIANA_URL}" ] && echo "sed -i "/\$ANCHOR/i Environment=ARIANA_URL=${ARIANA_URL}" "\$SVC"")
      systemctl daemon-reload
      echo 'Env vars Ariana mis à jour'
    "
    ok "Variables Ariana AI mises à jour"
  fi

  # Redémarrer le service
  pct exec "$LXCID" -- bash -c "
    systemctl restart rebootly-api
    sleep 2
    systemctl is-active rebootly-api && echo 'Bridge actif' || echo 'WARN: bridge non actif'
  "
  ok "Bridge API mis à jour et redémarré"
fi

# ── §2 Mise à jour React UI ───────────────────────────────────────────────────
if [[ "$UPDATE_UI" == true ]]; then
  section "React UI — mise à jour LXC $LXCID"

  # Chercher les sources
  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 : $UI_SRC — rebuild en cours..."
    tar -czf "/tmp/rb-ui-update-${LXCID}.tar.gz" -C "$(dirname "$UI_SRC")" "$(basename "$UI_SRC")"
    pct push "$LXCID" "/tmp/rb-ui-update-${LXCID}.tar.gz" /tmp/rebootly-ui.tar.gz
    rm -f "/tmp/rb-ui-update-${LXCID}.tar.gz"

    pct exec "$LXCID" -- bash -c "
      # Backup ancien build
      [[ -d /var/www/rebootly ]] && \
        cp -r /var/www/rebootly /var/www/rebootly.bak.\$(date +%Y%m%d-%H%M%S) 2>/dev/null || true
      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/
      # Nginx reload pour prendre en compte les nouveaux assets
      nginx -s reload 2>/dev/null || true
      echo 'React build OK'
    "
    ok "React UI mise à jour"
  else
    warn "Sources React non trouvées — UI non mise à jour"
    warn "Copier le répertoire rebootly-ui dans $SCRIPT_DIR/ui-src/"
  fi
fi

# ── Script auto-update ──────────────────────────────────────────────────────
pct exec "$LXCID" -- bash -c "
cat > /opt/rebootly/update.sh << 'UPDATE_SCRIPT'
#!/bin/bash
# /opt/rebootly/update.sh — VERSION: 2.0.0 — 2026-03-28
# 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\('[^']*'\" | grep -oP \"'[^']*'\" | tr -d \"'\" || echo 0); 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
# Ajouter cron si absent
grep -q 'update.sh' /etc/cron.d/rebootly 2>/dev/null || 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é/mis à jour'
"
ok "Script auto-update installé (/opt/rebootly/update.sh)"

# ── Résumé ────────────────────────────────────────────────────────────────────
echo ""
echo -e "${CYAN}${BOLD}╔══════════════════════════════════════════════════════════════╗"
echo -e "║  Mise à jour terminée — LXC $LXCID"
printf  "║  %-14s : %-45s║\n" "ACCOUNT_ID" "$ACCOUNT_ID"
printf  "║  %-14s : %-45s║\n" "IP LXC"     "$LXC_IP"
printf  "║  %-14s : %-45s║\n" "Bridge"     "$([ "$UPDATE_BRIDGE" = true ] && echo 'mis à jour' || echo 'ignoré')"
printf  "║  %-14s : %-45s║\n" "React UI"   "$([ "$UPDATE_UI" = true ] && echo 'mis à jour' || echo 'ignoré')"
echo -e "╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
