#!/bin/sh
# Public SafeTun bootstrap installer. The release process replaces all marked
# trust values; an unpinned source-tree copy intentionally fails closed.
set -eu

umask 077
# Never inherit command resolution from the invoking account, especially when
# the verified phase later performs root-owned promotion.
PATH=/usr/sbin:/usr/bin:/sbin:/bin
export PATH
unset PYTHONPATH PYTHONHOME PYTHONSTARTUP PYTHONINSPECT CURL_HOME XDG_CONFIG_HOME \
    OPENSSL_MODULES PHPRC PHP_INI_SCAN_DIR SSL_CERT_FILE SSL_CERT_DIR
PYTHONNOUSERSITE=1
export PYTHONNOUSERSITE
OPENSSL_CONF=/dev/null
export OPENSSL_CONF
python3() {
    command python3 -I "$@"
}

PINNED_RELEASE_KEY_ID='release-root-2026-08'
PINNED_RELEASE_PUBLIC_KEY_B64URL='cdEFJIqprq7xGyeGRWGMpC-WsONn9bMaooJZtasY-Hg'
PINNED_RELEASE_PUBLIC_KEY_SHA256='4737d3309a332383d44a49a333ee089edd5071b971577ef5e0206e2d7d4b9241'
DEFAULT_RELEASE_BASE_URL='https://tun.parssafe.com/safetun-releases/0.1.0'
DEPLOY_PAYLOAD_B64='H4sIAAAAAAACA-w9a3PbRpL-zF8xgZWY8JEgKb_WTORdb6JcXOdYLtu5XE5hsSByKCICAS4ASubK_O_X3fPADDAgKVnO1dadq7ICZ3p6enp6-jWPnfJlnK57UZIXYRx3J2lSZGkc5PN7d_evD_-e9fv0t1_9O3j25PGzx_cGTw4fP3o8eDR48uxef3D47HH_Huvf-xP-rWDgGWP3_o_-u_9V7yxKevm8dZ-9D2f8wyrpplcJn7JLnuVRmrD8Kiom8yg577DpKgvPYs6KLEzycFJgdcYnKYCuOyxMpmwS8zBZLYNWzgvW5atWa7UI8wvWf_as9fblh5-Oeqs86-XQ5ZC-6EP8hP9p8Y_LNCsYQrZWCeJ4-9uHn07eYIH8_Onk52P5-f7Dy3cffnkrf7168_7t8fcfWuLXm5Nf3h-_e__qw_HRQKOt1LSW62KeJo_aPrtuMfg3SRcLHIUsZ91XzDv4m9fatFrTiGuwZRYlxYw9-Dr_PXnAvMraGbKDhx578c0hwfKPUcEGiOEyjKPpGABKRJMw59DDwGMwdib_zVdnn_j0nPvA2mKVJazPvv1W1z7UxQNVzGEqyg6ImmSyo5MHDz49PP3qZfe_w-4_-93n46A7evgpePip68Avuz0FJNf3BxuPdUEEnj5ioyoBGf_HKsr4mOTHHin-ODoY0Lei8OhAsGgRZhc8O_J6l2HWi6OzXg5yWKwSpZR41ju4RgSbgDB71OqUdWdAkWjsATHffANlX7Hua6v00ycGU8e8RZTnIMNKxhliyvJ5tJTds1masQPsRaH3Dto5LINuwh4Mlg9KpL7Hjpj3_uWPxx9-eTN-hVL4-vXxu_HJr2-Ofxj_58DsNUpoUmq9Ofo4rPchyDHQ1YhGAAZDW4SwRB1IHzmQKvZvRayADOQwwTgx4zhKLsagM895oacXRrnS8ysFjspQ6JQmyXsgRUm4AMBrqryvKzYgShXRFlJl4MOWhE7ILkitEF8S3Yc9-C8IXDJcIkpWC55FE-gecX39dffhRgrgH2mGpaL-668DWZHxRRglU25U3n8YbDSfdb3HvkLWShjJWUWD6CNKqA_dpOxlifw1q6w-qFbiN_qr9yDZJOGBTw-DJkagrIOuW6YJTwoERRkBHnj4gYR6GtG3bJpqLSC70E3t6Rg1dTcFYMlPodBQlsIiXUQTkiYtRkKqlBxhldIRBYcuszBbH4ESwopNkPCr4OBACT0sfCRNw1U1glWhxF4XUl8sjDMeTteos_MiF5jjhHVzbE-keRYmMbGXrPthZvfgHSA-WjLLjC9D0InncXoWxuM4nZTDlfqNdWGxLhi6SKybwppOwXSei7_NOlGIjjJUWwDVVyBICJAE9t13D97-9qAVLcgwprn6AshCf69zoD8s5qA24DsADlyeDkatWRye51CW5sHJ-N0Pv75jn8T39--OX35oRTM2D_OwKLJ2mneYdzJ-c_LjyevXJ796_lCIHyH4JDGo2taU55MsWhYgnFSVLnnSxv47okWH9dOn_b7fKrL1UDIQJBnUE_oh1GSG9LdLRL4Am7EkFWML3o9fvX93_O9to2mQF-NFOgWDm2asUr4C5Q1Lrz_UayALI1gE79c5zPcxGPe2J_jKNMMZcTjKqdOQ5lG6VBk_X8Xgbc4i0OuCNiR6MofuDar1QBVAvk4m1qhmUQJdSS4AxCROc25DwFimYIwn8GuNy7StYJGjAVShDiT2-h1nlRN0T1h3W2gsJcA51ZrcjhKtkzevf1PC9cOrd-Ddnbz7TbBFy0Ajj0jSTD418urtb6SQJsJ7ca1U6eSOc55dRhOeg7YeDLsDoaWvwqgYA7-pCdQcDrv9jdUMRjcF5wPqHulWsmy8TONosoaqx8NuxmernG9MdV7tmVRu_9PAlxbTcjOUL85QnD2XEbVo3YqLhBjBm5FVhrcVnYTp7ibRZgwhFXz5lF9Ey23IGYYkl0IdEPkKhdWL9PG7l6BVEOhFb8ove8kKFPHhi28GpXHIIDSERSugVkUUR8Ual_UqCS_DKMZIyJPxQE3HS9-fT9jz717cTDcrlXVan64u_weY1tG3rJjz0pcXBHav2OHjPnte8wt4nPMqbOKAm0Vmz7W5dfetwGAMYyMqzJ2SW5tbjYY67aIfci2bQQBRzub4nIN_Sp_DLgQgVSrkvC5jXvCxC0GNlVbTHV0euYDrI-5vGZ_kLfyhMAmC5NytaOT8rNhzQ4JefNM1w6somYOXCaLpxHCKjlBvmaWTXs7jWW827T03XB63sTL0MQi4jJWMeAL9InKRKogppLih6zFiv2u-3IQqudi9Vl2Ot-CQZnjO4yk7W4PYQIExbeSj3Wd_pLAOgMA_cpAVgCBrAmsfFUXG0YSBQgzzImAvreRHaWGvIvDEVuBMF4AOMHD4DTSEgC5RosnO-Dla4jMOcsihDv3OSy4zLOR-oHaKioJ8hTyarnjQMvobC39Pz7UoVf6yiLEPKzH2I_qdk78CAq40lzA40k7JJTq-CnOxBLD6ia5eJbB0sA44AU2nUPlUV8qMz7iIIPYxIJ5VreBaaQID6C8ayFh5VUzPNdAsgmlE29sHNVBxgL0DOaM6bjZDXe-gxgHPkEOorrEAG1VHjmXOAdvImkbsSSpdA8U6Gp9Xcc5RJuuOOnpUsObUz4xrr32OpqrRnxdM6pCwdLSYdLSAFPxj0RGzweUPSaD8pYdPv_RIjXZycFRAI7Lih-EIIwRKXODChPVw7c1XZx5ECpj18ja4DLAm48EMjDJlH9qZd2olq64HnaePNl45AulY1r1z5SOYyzaaQvAK1hx8cKBFoQgwE1zgYpy3216AFHU9_7aIWxS_HamJCt7C3_aWHJfntyxzciQDQHREymLPBAIYq0mPzTyRKOteq0FtvJZUbmMZypkIALup-rwWth6foSNWozxdFopqz4eWCNpC-QKTK4aqCJ6kySw6B4PfQBAixgEKJSbBvWG1Q15MrA4duIIiXcSeiEk8mU3qynTXUNGj2gUSQMHrpFdzC5FvlPDQ5zmfNgOLegO64N3JKgP7UXRl-mDIDIYhp0R1IKudTTV7GpoaHBANwR29jNJV3tSpqnf2qhs3dFs2NvoFNSnEuD6JmOQHQxzGlOVX89ktW8iI0kMeYnHRIAhCP8m_Uh4UNjEBfwukuvVKlPFZOLn4PLRdhaaGX6rCrireowfNAOkEdtWGicLhV3CTjfgszAID4N1oxXt0JJXtUCUg5_kplXR5cumN6ou_vhYJ2liJ2NDEZguxQuuWYXdbLYruxloSqXVLLm7UcgXPUDeCAUHPK4q5yH1kns43t_ufTgfd56NTkbb8PdhV4EkM7b8Ou-1TM_f8b77_V68F-n7KZ4wS5DI3TiluaT3IiAFJFSINAyegzXQVlRt5JxGr_RiqcA7GL6caEBNwcJ6lq2X7sW8mWxGVAQrGFVZdu4y8QHTIzUW4Nv4KonwanUeY3MfymCdU7LMXEP9hCQEZttLrg5UsQx301hEpWPay3yBfxmg0A5n2kvwiP3usvWiRJ9qSIhLZwD83O0SE8iRfQei1jMMocdNby0XGlIskCGcWEkhuzEJqoNdv_sMJtCUfOQN1jHJYBidDdo1kbDw5GIzmxtLutyWqhgEazoK_bZimj3HzpOvO4Toys3n0Tw4i-fTJk0dPt2VnJTNMr0cSK0VxGhYhDAX9HwhQw2luDSYgZqEz2-YQyFEaz1sVs-5flNDLgUa53nlFjB1g_6QQowNlgEU-ZpKvvXwy54sQvUsKUzpyAxnDFPjGKDvHD0p50wcosNzbbBujyxWVg2CyO00rUnKqiBghSQMkUhQTRVRIdkKXawqpTv3aRpKLFOUdl5uK2zh4KnkxcrBS10meSkOC7FJmgb5XZ3E0uTnvKNVB1kZSiEoNswCUSHf2ZqxIUuUgURahp9h8ZCa8BJjMT7xJE07KtV3hBEFBeFZkvgqM6kbG6Hz_QSqLQFtVFfFQRCsOjlSs1v6QITlkhfybslUgq3OXf1yCuoEIU-0sXZexdD1sB647gvUOeaF2sN4p0biDdlyDTaG60bgxZBcwm61CLNaxW4hlHQmxzYSbslZSb7EVKAqTtRAR5_yRWEsxTJhFUkDFedv374gSN29ItTXwRtQRb7CUXMMbU4NYsHllHXfYghchaf5y5KLDAJ2XvG30VKdeNa4Qrop9ze1rVBA56opNh5U_QO5o-wOFNiIxPIc_m1stYxqh6tnzTapVaYCaQnfu71jLN-xaoJ1wo2sMllbLeqpBcBi-cApchJ5qIkc2PQBjM5i0_g522iiahqWTs_swtRzduMERErV-lfqaK1TH0uwRbYHdZ4wOD0hg9JxkYnjgkPXTC74eYb6tEHGBVc5eHLE-rS74JYykY0Z8f78pqUuacT6pPik8BsrVjnMsDm-oedgl1qtE6d1m_shACntV_vMCbMa4lB2lLSQHq7SYTnQ1oLuZ810fp-V4b9OOtIeKm6RFClorn4QZbm-wMFvYY5eDFmnkIFsUGed1SqqBm5mHhCgDTY9MUR4xj7Y9vPLsx1gYF1g2p18k7TxqNH_XEKuCMA68jW37DKpubmKgrZKUNC3GNDF8KvOhgZynEiBYXADf2rg-jvrps36_w3D3OCnyI6GQqcU4vaCf_jYBQXSWhTUJKMdRnSyiQvSpwuVy9gz6zWJ7HFZNfTz7j8CWG2MkLpK2j6hxiTQtv9oitk-aubLrQT0DTcLdvYZOwcouo2nb33iNlCjc_r6hE-aUcdFS7l6eS6vQWeO_qBcqDBdZOSJtg02IhvYIOCYnDh3yTT2tUvpSOeigCa0jctLqHtQW3SjaOgxD2b8InZhp8YfCa9nUWuEZ7ChZcbtrt6mWXe801XeQpNmdrFmECe4e0LCH7FrQtqlbaHcWZPCUPWSD_uFj-Wevns0uMQ4t0pTFGFaiiZB2pZGUKc-B0YqnStgqrp1hSCbpco0dSa53TAQ2ZkzCqQNxCsI6Eaf-YfLRRCNShF52Bi5umLM5eCkxr3NCpwMFQIBUJWnbt5G7xK-GypBHUt11APKChlpUfj754dgpKo6m6DgNHecRHaDnLtDzKuimpX9SfF-ua3s5U3yOPpyZ6Sg3Bsu8ved3WNtMuFhAZWpkP02A3TqWDJGq5-CNOkp820VPvWxd8ne5mrE3WEJ0YLmygEQCR5Cmjtdsoc7I-Yg_t6ZH9txAls1uAaoBRAKHzmzXt4jKnb6zKHHupFnnvarTb-CuyktDZt1oYMFrj_4IKDC3rXuCjJ4U314TdTeRCjQE5gyaVJlpnRsEajJNBlxUJ9Odc1Tm5o5I-xjxUF5Re_UGYhtJA8kcuK3hVJJ4yAa2IhFp4qE4Q2LX6ETxsDxbYkOI1OJQ0FSpE8mnoUvT1vOAQ-vMCgUaA8-hHB3JwqEZaTS3rCUUh1ZQ0tzQnW0cWkFMc-vGlOTQjnuaMTQmLIfVUMmJY1OdFvIZh4ZNLAE2jT659AlK0VXbABWP1D6AYvgX9e0_CSp3AH99Z-4A0uUD9eP4v75_XfMZyF9A6z8Vx82N8_belYcBp72_02EJvwIx5Ufe70mzT0EbR9PVYin3fQQMesVZMb7gaxXW5XhIOITu8qO218EwdOhVnA7pkVzh6c42deqqnsWrfN6uOU07nJpaxK5jEXP7M-MQoU14Wdthtdh_d_wvtPCELwv2d_AGjukTD-9uMwCu4MiRiaiTTYq0RVkgI-kgcxwy7eCK9qotxOm7obkpaO-UqrBOHGqTKQUrbb59I_IiSa-SSp4Ru_TLW6VtD-9pzmyspwQ2IsXOcLfdIp3SGuCHwjxwsaNBn91sleDiN4umfMbB9OncaPMoFeQYPQH0FDH9Ws2hmzFAc_BnM7lKnTh7ILfW7F6Hra1OnhuvHmKJWE3UTZDr7YEje3egvo1XFWMzrtnLj2kMhP7XY1HJ09JhNEjduLcaGjP4It2E7DQCNlFoO29NBy3KbNXtthluPF0kF8JT3Gu6xEnpCSjgc_I927Va0mZmJKjOP-mZBEkuOUmx48iJha7al43xlprVFGPHvVqeV1ueb21pTh5pjbN1gbuEiENMh1Vcw1MvgSnRTBs6-3VGd2aWToqWyM-ZFOL8bwLpM7lSdLewRk3JdbFSmtN1TekQwbUOc9g1KxliGOSqhDhagJ1xtyDB6FTn25FXKdOLd5lVcXsYjUuqfjzM1gLOnZ_mFQ2Qq4SitL17rGsrv9Xaw_pscQT6EsOfk3DRaYYdp1Gc2Rh9MNAyL3YupcHC7G9dGnIkQJOkPcop7TPctWQbEkjlrNdTBa4pR6jAZW9qishUQkYrqYmoZC8VdAP106x61KmaLfoHOsnXC2KFYK1T7bjXqM27rTxr3VmqaEeaaId4mqD7HJx0519sJ2jnQSnHyrtdEsqycOVIbBkzK768qJnnt_azeJ8jcc78Xs0i1Dgjo8947xRjqR9u3WMtHJM3gjH2Ejf6VMTlCLXus59TEOI0Adbq29HgwmdhXmSrSQHusLj-WODpyZSOLLN0VeTRlOM1WHERR2BSVxUwXOuws1XBFqsc10cUx-yM6wec1A1ENgmX-Ups_9DA8jmfBso8XUH8PCZv2nJnXYs5OsOrqtVbTepJJM_Y39j_IoNCIplSvSJxO2Rl_qt7RWfmvwxWfelCryZ5ayGfg1xMK1eRHADLcI2Hkbvw8_DJ02Y484aSkCepWJTqdfoRTdrVbGssEVXcEMFarVrbMugORPv6D0o7q5DMPL6Kco1KSK41v0a4c7NlO9nGhouN5baEShp2kaqeXbNnziah1kjaqqMalm2bMKLRrkkVUM3TSofZapi2HGZrhr0lY-XgmxhL4Yw9mj1impsnVCus97ccVjFWpLqSZBxQJVOq82nqIG7tPGrNutknwNw5s12XVNRhy105p2E9YiRi7ipYdF0Msgy8ySjLVP2pfPpS-bnm6EmOtZsm8bp0F-SpEXXL5zbzckdz4nhzSL1NQDLfMW7xmd8SUWdHqGDbwc4epnqxiououwIzL--7Bldhgk7qTew9mfPcicBemHr4-rzccJ_0pv7akY2wwewchFR8Lse2fjtrxx5OCbTjHOjuvaByN3q_LRF9ClW9yqT3Kx2PX8ga-x0Mo8J8EsMorr6O4X72hV7IqL1OARGV9TiGUTUVngW33seovlBhkVx5EEK9W-Eg1X5gwklwpSUQWilR9FVfmJiHufmWxE0fnKg8MSE_cck0PzdRUg1rOFKHfBWBcmv6T3g1wuBqmn3uSxDGe0PGQxD2gw37PgfRs1598He87bDrWQcV5tXASpIl5P_fo_5XvEf9r3KNGhjC8-Kzrk3fkZfV7GEZq1hvfJqOlbreKbVmICJ0mczZ1-PC2T0TD1QlOM1ZOw4XZ9NwqA55YJTaNk70-h125nkVb4JICVbLKXhRbUJniayonvOPku1yEvDNqXGegEqYp4VyUG7w5ou9MepOLWyNKd0Te4s5M9SXpkhspuArfUi4Oiy_Jf63qdl2znKv_stNC4uCO8mHSyT7HojUV0pl4vY2qWjXLNXJuPFxSEnSnrytn4is8VelKY2rwwLcGyoRlTPjYK55UfhuHiPSxyRVOqCOcctLUM2PFokTjZT6uwXmXiX76NeRyrzjLZBWMpYmbn1979ZcMNOcJW_v9Lkg68mg8Zd5MkhfFXc9w6PF-NTjyWWUpcmCDtJ81ms80hToJxLG-lEotSHjoSGj8530LPrQMtLGLrXOtiCJ6pjXZmM8KSK9zPZ20y6hvsQrIb_bGY3G15ybnxMZPH30l8d77BGail-Mp_E1EVm_-yER49y6-QCCfi7kIkqmTc-GGFFgR_8_UuDzrZG1asoK8jsR9gyvDIo7ujo-7OCjc1EYCyjxUIJyGPZ49KDp7RM9QPmuiLiXrh4oEU-R1KawBKTx-2X8V86B-ZADhIJbcBDv_OoDJ6JO89M3HzmpY3OMWCAwJsGXT3Y4G1djVAiDwu5sdP30Mcam8lxOiWvkQFOsl2bP9oT7vnpWJAKHxH7ERQON2HcudjcOrio6W0dY7VA0GRkh0f4dKwG9BUsh4n_0tOSpwrQHQ_VSaOClrm9gYwWdvZpKnEBRfANW6DXoyyW2z13lRlVVu9cu-aP0txX9qainYonEc8DrvHcBYTiPexlEL-mip-fMqfXCfBJFHp7JgOCw7YOevIIAyDo23j55f5xleDT_lySCdpx-USjF8WvbwCdhIkQinNL-uCCNRmfkZdgsSxcCmXWDersgmcmI7Wx391oLz5T5FE8726EZKc5h5eEmJQL0EpMzlNvpTotHh-lqb5KyOE3OeSYyH-BCR0VuyAlRh5PM81zIbxuUh0tA7rMf6Vj84SHdJZ1z1YxRM8oHBuw9pi9YOIOIl2Aod8Ae-A_YGZ-EK-Ol8vtUj6cKVgWdWaCz3ItwjRTyeEabNiEYgnwZQjeM9oPQw4FBgH9iHMOJ4qrczqTgXsNYNj3kxA5JzWTaxQcRGPing5HMw_jVtBL2djp4PnLL8qtkyj-65LqWnqJ7jhbzQ5w1ZH6nDKKIs8ZvFLZSYKxilJbK-nZmw6opn4sojkWv_dpg63KBLq1NncmItwL-f9p71q42jmTzeX7FRCbXxouEBBgn-Co3xMYJZx3gAr7ZHC9HZ5AGoyBptDNSCIn9329VdXVPv2Y0EvJjN1JOjDTTz-ru6nrXqyS5mY4PrGNsD0TWiVMKR56M_BUqjYEASV41ikbVzpZuaSWJNZTjkKPAIzSzkk-FidUovrXMq9aLRW2aQdPcTksfwGFpSc5KJY5KBU5K5epFvwWYwSmUKasCy_wqSoc6SVjH32yAJVVh5XEMi5kTT_1iJqWscEVczTdDlsdqkVmDzCiGpi4QJ0wyZsfAh0FaVajFegMrM9K61wRaA3bFvh-EZ0T8b6rIgHR3ir6jKeZ4mPS7cE-JC4V03nJIk-sILhKtqTyzSISacdpNz-g6E_cd35KuLR2uMdw8vYaGW3Ru1qNQNXbmrN05k7qQlH9O8xdQuVJTptHRkuDWNWf56znpQ1g62nDA_kuxJfqHILweyb7Xn6nO-I3RNx9WuvLbHuwc5BYmqTLtJrpaNvrfolWiF_AfwBHG-2_d138LAWfOx7WTSEpvlyds3hIuH47O0MyK7-nqs5rvBAqHPcWZWuIr6UE9w2taZwX3DMWpxdHthXRPO2zXngC21qIkz_dykkB7qyCyp4CjvTVZGQ7EossH9myqlAUGhpcjoTKfIyPiTw7eCXC7jrs3JKSI0rQfp2RPK58phKOejBNAM1KuIQKMvi8NzOViJB7eKBnpAe18Phy2_6SJLoha0w6AoN68fPhGEbfssq1STAR4Rh5L4xx863CnHkTNENYM1WlFRdLOy7sOyzeVywjt9QsDxwv8Ll6b--HChmSeG0osgRw9xToVUEJ22TuEdfMA1TTTbm0-ap_otGEhO2UY6-jzwwSL-nFWrL4uicFS-W8LSWuIWk1MTle1ZoFrlsmjrgRJ47rAmjoOIDy2YSBIK7quthjJTQEM5fm6HwjdLSLgINXi-tpXgMaDcN80d2Nr8gFxq3fQeJagUTt7nCL-IHN44ZnQs9oieR9K9RvhOZViakFcBJLA4XB4mCUo_h0AJHZmw3RlZRTWM-1MCab3WHxu1tzs_nge3tbsMCDubWauXsFU7K3x-Z6tXNBoQyKH_RznSz9V1OC9T5V1Q90fhvnh-nwgqA7S8uGX3-d7pThH21reI6W9LztVVVZFIybmA9wM4OFUGbtTi7NA5yKMOwVEfV4KXMX7ZKEjMms5q1h96oyHafRJMRX17HqV8oi7Oc6aRdnNmv68Zs2SjGbN8lxmzfIsZnmHbaUrpjRl363lRoesKpY0m5apUkytOxk42Sopx3G9F3pU006aRBdALcPoX3XSz4RHUxzW63Am4gmnQquJBn0QbT2TSQ59rTEYCppz1mG-xkoT33AX_jVdrJ8CvzTuqXCH3K8zv4cZ91m47fI--Y-bTJCTEv6bJs0TeTFFRs558QUSioBwtYSh3LORp1flui0oXC0hL1f3ZL3VRt2uag-8SYtVz5cqz9wq86BrAZ3tTOjGKyefK2do1_YM4Zc5mlQZOT2Bx5H9Lh3tpmG4XNyPXc6ah2efy6DXnp1uXmFX4cMXoixJW1WA-DOYzPl0FH6VbX6VhZ4ovY1_jh6WNu-DrpQR81Frrz3yjF1EnPKd0ab2n3Na1wuze96jE6e19YIkoYv3Ybe1XpZpdPFuvA2uz8hZunh3RW2uz0iAuniPRW2uL0CNYB5ga68WJYWuRLhIJCHFTcBxMwHew_jDDCzi6N0Y9RZJg-0D0z-WdIWvs0lqxg6rTO2YnDcOmQ0MqEccn0x5ckWSLD3DDlPmnjzQQiiBkogiEQdCEEV_m3Tf02plAIoY-AJ0twc6PBbKC25LuoIIu76sEZ7KyBWkR0dhBqA3GKKShGywRe1GKKxesUtuTCS5zMLbawwODXgr6o8oeQBqXYaz4hU0imgNGTWiCEnOt8_yJexFMQwKKcAk6plZxX30iL85s0lR2LOjDA6yoDLcNQW1_fvRJAzfFBNMc4y8lCxecD5V26w6y2Kab4GJFtDl95zq7FarT7aQhKwDl98SlNObArqai3gAws0XJ5YuhmUlePpZDx9YvaCtBt6ZnfihbEFa-_ogfJGwzlWQ3gKVCWTYHUwzRPh5svgrmS0eM8XvhTHuysCSHot2riNAwyIMx8HvcfcMH56kmkSZhekhp1tBjJnpkQgfUGb6RnjALB-vtjSUGqGpAOqlhZUUGe_Itp9Bz3C1TqOBOTYR9AVxjZxuJrTlwJvkg0wyzJXCtldiquMY5VVwszTuc6Uy2Cvsc7ETBVFfjOc1vpBLek-Ed1srlCICJwD5lHvgmm6vWdyFiy3bEK6qQnrFzxqT5CYeda7j3x9tb61v-DTOra-bJK5SoQ0VRcPkAQvLtI3hzRSuGjh8edZ-GD4Udov1NJ-IJnVTz5RsUD2Jf4fmYYYHxy-DNQsIAT6U_QA7N9JRr-5AzCtjFsjdhuXrP_TX1HHNWDT8SGg4rHA5FDxEAwdTKuWsHDfxULdHKZBueEFQW1ur-Wdvzs-D_nCjPnJHIvGBZxDrtbAdkvalEH7dZMrBhnEiOS2nTpdMPy0ExzX7IMDxcxzilRtfYblcViK_lZfX3eY9YHUYbKZNe2woimSpyV6Teaow35EIPI2HQIVmHMTqLmTVcinXbdxGnr0lgiZUkgmcynkXjllaZtHYS4cFCFMTXEEdXXiV5dKrIkwKaO3PlhJRkcJC33fJoN-9gyJbe3VK-8WJcmijoVWk2AUo5LJe5Muexz6YJQDL7isB4w78s6DGxSTeZTf98Tsaa53OwLsogzFMBBXq7V2onzUdOrepd8-3VlH3fD5Fj85tQ90QPJEC0-FbczCgfK0PiEparSnPE63FHG1VadU-AzRFQurGEH3N2xNkQZ5y3fF2Z2BxJgaK0U8wG-sEVRCNsCcSSKDkmq8SwoKCnBgBLQIi8BaO1xAUWByluYW2z6iowCpVpDdbagLxEu-4Yr0diXNzmtmQdSTolhLARoC7jgLGJ6gRFbnm0MEdc4wBJXUT37WFqztFN9gTURDQsHo9IGeATt7Em4sARSr4gChZflPqXUiFZapyJbpt25aX_2w8up5evkO3yfX6I1-UkPV_cmo3LXwF2VxD-zxelZJL9mPoXfPHHE9ia70grohK7DxzZb0q_fuv9UzDSQ2U3uWvmXErlCHsBnltAIkt3LNhDWGhbqPBjVgnIL2TcS-5HbHV-RVwMsktxVRt-9LS6mm4RWKCv4VW0C8lgwRur2ef3zx-ki86vKpWGBIPX3pDmJtBDu02jIXwvvUvx72XJRzGw0vDlsgM56QdFicMmnEYG9EYEa2sgM4lfEph1EbJkqgjImLXx406AiPFwCvGECkCSzGSU1fdaIrAC5Mrecn4gYzY3kBTHnjMRlYyso2Fp2ZiKT9KUnFvcMfpMW0KcVCVuMhlUKDjVPP7TXzYi2rxMRuJV3QoteCiMqGmWH2HzY9hmwg-f8YuyYlNosSUYaxNcQk5lS0N4OKC1JQ_FKUoHxAv_izsJQYeMXtk6lRn9e32TE7faNxl9H3MfvlWcbn-anS4Ru0XSjNpGNGooGcRCFn51OQiOxEPmaRiw-kkMpVMlmTRkjcQt9f2Mf7C0tqBvAfe6yUw5X3GnjEYtFlC1-PZa4a1FIyVPVZkqZzeuM117wU0c2mQMytcktJEHgXwrb4pdObMA0VLjmiuRNtl2uZoIz8tbT-r9iEAIva3YGyl9EFnxTK1O_BOMua76Y7c28WzZ67lojgo79AvYt1XwGa8PVuU955VWbHhVle6QKTKCSqXUOTsLHobsZCU21DCUSGUERIhrzFRmfyohSPYInsklldWbSIXb2ptSLqu42OCNfkQahI6t1F_YgiElMhGva4qoyEtiCui4Xviz0Kmfq_-vubK7UsqyYWbu6JmuGpXlRiTHIZh88lo92p-hTKLvCfbKKJowt-tlU4rN5_QNP1qHNKH8SaOx5nQNYUJoIoUzvVV3L3rYmiSsRT6J1NNecXNCfGjlPx20wTuRuEkiaomUzHF8mfh9yCtBEQACm6tF-Ne64WYk22gyZg1zQNaI0jPilBEDALeKstYn3QdR4PJdUPuSlQOd94OkksghHFLGdLM5IbtTnNNkxQO1tbMlSBxl1av6dMzJTeGYunLGaYdVg-O-sjqjPEwBiIIv_nvb0skQPytIebdUPNWw9VOo193JZSQ9dtwa6cZfuNRAQA12CXahRYpp3GonlgJW-DqkYNzN6PldqGsBf0r4x7TXIyuDGii_kCa_1ALQgHgnGN5fm6jjG1T0BTU0P4taFZZdNzr5cddJ-57uvaoxGiyoIy1JQp0SqZribGrnXjCJkFTmzGTogJ6cCOkeJKbQpWVqq8WVkMkiUQW4fP9M15xQ9mSpB3blGGGDdzSpl7dds6jKF-SRQNjCz8g5rKLqddHye09rDkqGMks2MVMi5lSTV3xcteqnFKpDolLzinZ4cxxSnVz53z365FkvTbQPGNXwyhvW_Iqcgz4TK1jfrZI5egxqV8IVGbsdaYhKtnVGzqxAlWYTwPmaL9KlF5Fui6-u3TaA85yC_537x9Ns-698aQgQFx9yE4ZcTl0204GD_XXQQsipnDkc7aTU-CTmUCnWXvtf_RdPw7r4cE_Ds_DH1-fhIdH5-H5welPNm5weitDCx5qzHcSeTQt32lEAyG0wRGO41r4PxqwNUcafv72IVVuPTQnxHQnb_gwusSwYSPTyDfbYL1vGMF6XV3FHN7X0OhuaDar0P9vHCREc-ClCl0oJaQnZKNLsUTiOoUDEe52l0Cc3TZ0EsLRymPUbk3YUGrCuhj_AtTBn7pZpO_cohvoml9UwcaDM-44asCQUbx3zbeLec-wVeBOtAznlfn8TKxhixb-qAx4z1mRWxlQ73Qwac9rzFMixPPE1IEB9q8wug0lArfoIEn6mSPSrYU8LYutzKEFsRywwZe6UFDyMtoNWHjxVb7vqt5yRWyhizubduIP6Qf8F75-BOcl6WmN7VLAcS6f_M1yrx9Pj5_0AnLmWekK-tzQVwnOUROsgnWUXw1vFc2zvBLmyYUrjHAU1-1b3IX4tXv4LH1Y3ute_NcH4cHmsKhfKi_m0UAsZj3Jd02-oYD-0NDnRZGPlUS1JdtYKBQ-7OXm6X6hS86Hpe1rDlcmmU6Q8NSSXH0kfoY7t_gaOST7apHPl3uxOL190mvFmmPlS6WEf0A16UJMwuIUujCaRlWZPpZSc0mVVU_k5_vwlpDCAKOpRw0pNYRcuo1JBUMS_dQrMzLDgCSbDh-16Fh1yGbZMHwsMSABwKHBkX4YCVP3krc6iivCLO4RtZQkvvUXB6tZ4lG5rGtVKFW1rY30RiU6Xncp2P7klD2rVHVPEVjkx2--5BCej989fLhe2JZezdSrAgZ4kL99LxZmd0dj8Mqb-8hSL3Y14zsPlhKzWdq3g3y-3NvB6e2T3g7WHOeReu0bcZTISs-MdXt73YdnZq72uopfi6HvLlXCd1bJNqQs7c50D-8lccZqPbHYMk2VUOHuhVGYh-l-IGdFdqoplNDjrV-jdG0QX01ow-QSNRFIvteHzmFek0ZQorYSs_V7Y81QMHnkHcrx0ReXKig2JnF7b330W9mPzN0TJYjESTLsd1VMMkp0rE5VlkzTrsKiPdgQ_RGjzS0zvnkbJqa9p0jmjbW1Wo5-4WjUh2Fzt9kM64nwca2_FX_hJFBHCDjVoqg6_C2sXxmP4YfWUc03B06yJmdBjor3noTUpHyVCe8rarUWfuuOuXsNN7-YqecdhifDWe_x1BeZsEolhdttWZKrhS418yaTYe5EtFWjN5uB890reeSOaCRsVnjnbKjzuCEjq1AEwOlIbi3DBjQL2Y_X1AXI8N0iToQu-VdJxDg4RSP8vo8hRgF1Jmn_D2ZjkkAmj1AaALJ9U4CK3mLSiNwZ3Lzv2AG8MS-k1GJTrBIZLE4-lJjBeb7UC9Icg-Ns7YymiAicB3HOuEN91zA52M6SP5RfvjYAq9--mAqwbSZBXMvPFF-ObZS7Z_GmkdJynMa_9ROYKL-Uv2vSQA7lCrKGsp9-RaIkLqkRdfIaxqwl_FoCS8tvmIdd04fHqBN4OJlmUet53Rist6gaD4eHwpSX-IoL543JXHF2QC85eH3AtaK2rKE4jXmnb4K8I8LUSMjbTW4aIYzUelzpnXMuSEsg63ktR6eGxUkn0TCczQoJp1HqyUAGu-ck9qVCZBFjp0B-jHS2Cn_UV9lEOeN8_jMZDhRY5Mv8N7w1jP8ZCvkA0cJJdGKDoqhMgYWPpLw4cJCZXEG5w4V5U4G0vhUgk1SAs6UzjIE4Ch-2xg_NUZkQkXtXtuNu-MKGLPBxSxRkwj8qYd9tP3PPsg0LRXsLqtc6NTW3W-eotH3nx7NHZ_RsHzHRtWf7czvK1aBe5ycFAMR8p4F5A5E1PDoseSzZ7M0olxSTVRZvR6uUDfUD7EvLl2nsRQeF-geiZlQ-EruYsw7zjQXuSXEn2dFuq1IZLVFfrBHmQr9uG7lBbVSjLRilTyXnJisCXI1lL5ggJaQCPBpRulYYx01EyJH2flTRN2mDzdgx2Ayzn5Ith6cxn7PBAEjK3PPefFp93-LDDiyqBVvKuJqDViVcXcIkaXvV1mTHxgT1SdoFtEeGUoJZL-v6VwglJx48pW20p5EPgePRQL64C2tSN6m6MQiLW_SPvviS8DaFvZgqIDFuygMX12UHjPqKOlAnqXCkLuRKLqFFRsod-Ae6IJJeFFi8ZQvQ9qLNyxm6rRtnxcCmnNu6vfantVUe8Jts871fVsBJsVFaULKD18y83Hj2XInCIvX5VM9ZdZ4KPE7HwWn2faMY2JZpsIqRKntsh0r04CSBXyJxHYWrzLKk24_QiNWiUYrC42gLQX5QHAaxUIYyl8xECA7aVUAmEo7rvISobJMH-VPb-0ha6dpyC-GYlw8qlwIpmnWbaFZuen1ecY_T4cLyn3JumQ1eiCeTZ8sGj_OS_Hk4CrKPqfWyr5LNegsD1h-Z3WjMN_RSxiwbxdc9TVkseyk7bVZYPk-tuYw7rICtvlsq-83UA8N9jrMjauijZ3o7b8dDZRsvfV4wDken1SCNwdn-y4Pz10edw6Oz8_1Xrw5OO_D3h4MXnf9refRpogE-IzV_V1tFXeU2uMreSm9OxIs0dRHuHq6pGynvccfbY9kKG20668vDkqtr3AS6qYyzOrmxzIy18fSmw1Tey4j1cqURZRzAk1NT2GHzsS27wHGpKvJY2z7TjIWMcvrOshuwA1qpsB08jly7vxdqlVV_GOcCiAv15sGDx0xQsMAzogjr2tpSZIyyFZSVnMVzhkS9w7jMJnMHQ26mUF7hFvOLF9xy1i7zyYydpdEEwYwDFNQsmV3RmrnFch-zK46vis6Cw4TSjAG7SbdafZAkN_jSAaAWHnEY1tOrsF439ogn6h-2jTI5diTNnW_Uofoqs6iZfHlI4gV0DGEVQDr16boSu-cUwzQDxI-O_JmIoxVwBHXh1P0-YOMDfqriN7CQvg7Yd93AXw9y4b_aURms357kTOscZ1xvouakp-qPrmNMINZz9JRldk6BFUdAdnGpbHcWH-YlQUdPEIfuzvRYZj8IxyiaQEurzLRsqNPWEP4gIqtbuE-O00YO2UsKUpSWhU4XCu9LMpajDORI6Uq_aumOItrTFNPCt1pa9tSTS5SVoC-18JwOj9ANnPLIXqfJCE7k4E5TzYvmIjGAJO2Rl9g-2oRvnspoJqTygv1G5LUWGXW2bYihX1-iVq-qOdwSlO-29RJaalY0XyoJvWLEXjUiMauVrM2j9yo6G8rt_74HRDVUK90ALfjvYy2_39JBA4IRxXPB-ettLAuRoTG61qw9bBLbese7PXu8IunS6fGrg5Co1aPnB8Z9_qXJ2G4RafClywVuyxxaBmnrDbb0zNygVSDjk0xv1ajbgp28KDxkuo_PHSJ-vXgBTISkZVGQsHH95w4RrzipACAc6mZRiMhIOZ87SDwBgIphol1KcMl4QfOkAv4zWjEhFP5wcHRwun9-eHwUvjjYf_Hq8GiZUPMF1VkAaK6xoAjczmCDf3bwn5OTwxf490kZIGVKaC80d-aCpmyqEKSfHyQLbC_VTEyYzgrm4c1A7Qvd4S4DBcLs_xEvYRlkU__-y3DfNUBHpJIAKvOgYw2-7IS7KGZ2WypC0m5MiUrjU_5TSxhh7k45e4y66-XsUeJiLGOzQzMVNrrlVGHtqZJhssvIfeQG_ta8Y9Pc2hyikXmLhalGaYZUsJCGCW4JnSYYm0VhwdUtDORlu_wetLoa8gx44rGuPpImjsJi1WLPdH8NxXw1zDACZAzZ9HGpUrlm-2_o77C2YZ_qt1GtZKfqSW9WyZljXktSxyLV483qMTDNjUzVbHQo5EamFZwAlcRbpnEjuanYh8D4XU8vSf_uhOpV6pJSNYunVamxLASgrknV88vlTRQGvFVme5VEG-6uatoH7vG6pT2YKZx8p0sA3znSDiMTSPhOMK6y2DsfJwWFNBz2GH76kQm8cM43zII8uL74D_j04vEgudtU8pxGdr30Pprwedps0t-m83enubPz5IvWk62d7Z3WduvJ0y-ardZua-uLsPkxADDF6z0Mv_iLfh58uXnZH21m1wG6YKCugzPHoZFcFnbTmKw3MCAZafV64eUdicXl_aTwUiPI4glg8WkQTIdRdhM2nz4NTvbPf2xvTrN0M4Nu9ugbfRE_4Z8g_p38jrFkMB1hGye_nP94fIQP-OuPxz8d8Fc4lafngG3FLzilJwfPzwPx6-j49dnB6dnh-QHgftms9SZgv2d1p8lktcof-hDQ2XdofIJ4oB1IRNDuxVfRdDAJXpz-0jl9fQRYbf_s7PVPB51fDs7gx8nr0x8OOs-Pj14e_qB-QlUYTDMIAM2pHu0bnwGpjuBeuPYY7rX_2grURdVCHRJhyXzc0QQ9tw-OXz4MXgv8KeXduXC2Xid0L5MIhG_qdcX-HO3_dHAhcRq86KV39XQ6usDvd3FGf8dTuB3YwEx7QBqQiyD4Hr0NCSobHFQE9wcaE_cx6YdKNJttiIh2pD25G1KCD0plKzR3vQ1B3QSio2nKob1g8xH_FQ1kA6hEGUoNjGhARP9shCc4svBqEL3NOJ5twKHApAong6ek8s3D5uMeF3FxGXZwKXQT6IWoqcFtdJcHGG1QoGhYB5ON1BYk4yDOWnj1hw_fPX7zpZG44fG7xuN39cfr0g6mpYfEhsfCJ7iFrsAArl0kg7kAXTpqAKzb9HvQ8WDY_w0oDjEQGIIYC43j8Sb832jwgN49rhtjchJ0qcby0eI0KP9Bv9te-5MKfPVV_fH7ZygrYEpBvnjwuP7emqqqSgWMSsacHTMYacju-mCKoepFxOQbOFWabcEkmd4ZRr8mKQyZh_bVV43H77VACr1Ye_ngceO9FvOW33OINS5j2jyJxRn2R9SHqpL3Mkatkv7K6IPeyhhweX9uDxIMojw6qhfPG6nUZDgGGg-3_YgMzwAGyCrRQGuqIYNazXXSoqq5yy6Kuius2nxHiZYeywjl3tqKElU2ZHAcBGckeba3E-HSxkP1nkqBFtfzOnG4pfF5jDVVmohInC2YP10Ja1vPwuy6fzWBStp-zlFrScMK9XgaVzdNYQeMotdDeQe1ZEGj2B3muNEuJ38pHbevh8b1VVaBcK8sL-43b_Hrd_U6JphdD-neesZ8qIUB6B3edc-k4csNmnAAbn87RQ8KuAtbNQMX0BbgVcXlqDE_JbLk6OHteRnJuuKSLkHUXGKxPAiDIxJUQoRCL1qR6SYIhP1kFbM4HKY0KJ3Dmo6qSVu6STK8zCYw9wp11P2P-WUCNFXswO3ZkW493HmeZlLMBHBmhs6PTd3qz_sw9_Ayn0vTa-EXIAdstZEbBOoAtC2ArHezzQGNCgXWgMc_H9nGgK6tLDqwEaRKTQLd7uRuLGm7wChQ0NWdQjtgsy9jVFZVMY58C-tGj1JeBK1l-V62W9gga4c1V5Rm7pGWYz9oL2ZuPli-lIWrIF0s7fzS97YlVa_fIuVRblVqX1l6XSeNTon5qZMzxV_28OgHKuyes5bdgERyptmptnv1CsbtW9XA1d7OlQxceTupCRRs6SIwa3vaaqLK1uYROpvbaqpwj1tobIZRrpW1VZoaqnLKn8QPQFneh3As5NtatrWus2lKD5vC5E48S-3FbAydlzbQ8-sjPgOd8-Ofvj87Pz46MFG0ZmokW6iKpa0u3T3ta7tgZxvNb_ub921P7_DlDnW7wULCNcPZf1p3ZnGxnFr5J-Xl3Q2-W15BQ0R5nafldYha7AjyUqv1dZVaMqWarPRNYSXkXi6ThMS-xLvk8KvJX0xCyZ_5ZNQjfazWQxGBzZHT833AXXuzK_kWHsUTFpI2kbMhapdhEfVJFGtJbDSkL3WtdDsyOijDSE4M0jdOD-2wPmPbX0eIaZTlvdmt146SIWAQH05gE33J69CNAk_xSHKCQ4iS1Dl85undxMZG9396FkiMQFrR25cB8e4m4Dwh2DW_isLlskbuA59JtGmAKrpp9KkUXov66O1COqawTpsqarCa7gG0ygkW0zmSBtow-Qz3ujRuMC0KbPH9VXbzeC7Lkk1q7gPntRvgzPUbTNLQubHZy_BZqBwhSOjJfpOFPF9A3uc-vz66GgMRCYL8U6AASusHSTcaCB2B9MUQRUvCDmCBuroN2QU5l-b66miyXrs-Mc0wBa5lc79OaSuFG77-Lh-MSsyGxcjbWI5E-A_wX3O23-XVlE2B6GZm1bqsoLURCOE9ypMd6X84HsBdRj6iWH1TjTxAzUEyTJQEe0AWkRlJSUJz-wXyQGouV1pZczNS4WS8KQNJw7mRHUHhcA0nGoTSy4a1QCxezbCE8GalXZWXwy20ScJ_bJBGtxeuafvrmWiZluBZuGbAlZoh3woBUimW38t9qADACBGS-outqO8hGriOaFRZQ4ewJw_fmoZsgqMEznUa3yKErwbT7BpVGVMMdXgbx-MNHBMnrYsnbA1PzlIAFtyj6iSKbJwpxpuV6oOA7xQW4Pnuc0s99ELI_FR0wWfAvYik5xsy3AZ8m8LXjIeZ0ZjUDJLLX-G-zcLbGMM_XkcjWHo2EWHTEEBic_on8SxyGaN18xoTOb8bx-HpwU_H_3fAruKTRDmL7YUPFV2uE9BS_YV5kFUSZFpnDt6r8K7-kMhw7so6PkbsGK0KPOnlsXJqCIyADRDQegHWT-gvMajm73HXFrpJYwUBki9V9BGtvnnpOO80iMl3vT6G0H_-grSnDx-G3Z7wU8ME9ih9FL-ayHYAETK-hdcn60YLPPI1rUV7xI3sWqx8wZANhzzfhAiUSu1nG2-Iok4MGKlurf_GaQiL4slMUth10K4ohVnr-5M7pzkyMiEkPmdixjz8dW1NNVJzYmHLbxQIW36_y4KADnobvzei9O1vb1oXgdA9tmWG-59PZX7756cH--e4QYAAjiaT9BHG2K4dd46OXx6_enX8c40DUIsG3nEL8m2Q57MXjSfjePQI-98QNTbCZrLbbK4Hk_SuIHr2FUXPzhvyx9A-PfhhmSnYBbjtFJIyPQ1hEvbJS-O300GUElpj5g4HTRE1tFGricoC6C1nzIrMhAcMBSjRHSRZbJQ4-SXIrj072jEpCmTGT31_BJ7UmcvymPIOy3BA0oJkwrWunBQpdBzduZocFW5PuPWjRrhvxMdEuoLyzQYPjGsKZyByoPfgQKNfoh0nE8Z-OSgMl1lCcMbZdEjxx5UGY82h2QMFHcMYMX9qmCGa5oelZod8UXman5GDdQorXMW0UOySb_-rbiaLNYwL3wc0RnM2wpywLF6lxv4bwPLF7TTlOibHlgeaK-BBMPimXl_MRceQGqfku6wd5sftS09LaLK_qqwpmNGJt_w3EWjFaJpzFPgwtZG-QEPbgDZlFF8u1cDwNR28Zx-J-GF44_4tvKphwJ36n4BW3saTcb_3aP09ICs8ZUh1_HNUa_ya9EeP3tTKRZu1jfCx6n9r7-JiHRrH6n5Er0a3Ia6Fn0-Pj179Ylwt8sfBP56_UjiSYvAgkuxRMzoWrd3CGGKANqY_b9eirNvvwxOYHdDlwA7BWNaR1gNasTfghAzie-MW_R0e4ZzX9cdEJT-yELN8BxhklDxaXw_gTRoDe9ON9VkhjAGMKsSBecc10JNqNNmQt6o--ReHpwfPz49Pf9GuvvxakA0W3gp5AU7N4BMlIDk4UwqlETW5D7KFPbTDCu2Vp6j2Jaa2UjNwIU3eRugZKGt6TRhb2jspvtMU788_Bk4sZTbLljGm629BL5zLqfJUJUtaPFtZYu4JVxtK-Yy5DdVPpc3CfIDGCZtMgBYbxAo0pNXIg5ZqxYn7caU6MtKRJcDRiHiOcUv9cFQSJtOs6AkcQWooGBB9QIFK9FQ687hs5vpYCGtLWnHkRHFgK8JaDvK6DGNFcggria_2WOtPJuvWKxkZuq3W8jiXMvLHJI0dkWApGOykb1oQkrw3N2O7ZC6NORYG3fKW8EiYZVoukzxz_V6kYkDOlmWPpr9AOgSEagJtZpBvV6lgLsh8Mywcr746mqxamhr6mtu0BfdWnApNCZvbIrpa2EI7RW22bjMeYwazE12JK7difoF6ZmyGvdUadHFCcefF-MMaSmnIbHPP5NvfmqibQM5DJUpdi4xw79vLjljKQO2yrV5YBk5nw-vOoPa-17bkrAOwwJnhnqtcNtqcke0ThfCSE5pSJXyt6ckB-BLU1J22jY-4iV0LH37u3-hXTnXX2ktrWKpfJuoeENtnL9TLOnupbrZlA42Uq_Adi4pdN9OUTuNSTDsm29BCrYXJt7hLkYNTj0Zsiwi1F_4w2lZlS1hntZsLPd9aADXjYdV9MZJ1exDJ_C0SKllpYMxQyQocKnSxAQvtafHO0qvqkLCaJDA4MbqLAKIDxQyrbJ7D2ZpivwEam0aYoBLvbJ1W3bqNtKC-3itJWjJ4biT1qhiaTiOeK8HoQb8DZuwyHahmUyXq_9I9p0HU3XkMTnMDOtA0FtYLUGdbGs8LPC5NcPpDy5uN64Cca596wOpMSoOrZ_MKjGSqaC2s5Lx0MVPP34iBnbx9CAylXpViKRW1z2pJn5OtRIvFJW9wicoKy3A7IkcjTZP4TMRVE8rDvkymRmJYYjyno0GcZeFdMhUZ0iIKhDwdN2r6DW1IrywDErnRWMXtbLT8uWkoktOPWk03dYENZWE34gOwRY7JuvMD1NCxLgeAEgegFb--8Uj2Tu7LbTzlgeIptBdQB5uqwJ9-OdP3Om9WOVwvUFUaC-kzUVRJmUkBk6d11ixIkwJNvDpPbTv-XVldqd_jpZuz58IQfEtqhmYisdmc4rgq6bT9kJtFrFdN0m3DdFntLpavVcSa_HscCzHi5DYJJ_3RXZhdRykF0GQNGat4Odw7FAVehpNWchuihjgoki3a7PXfxtlEJXE7R-QAyAQ9oa7gUF6HtkqZFxajc5LwGLsaEpoW1VA6NInTdDpGJJTr2ZT_JnCFwsFzcNdgRDDnFtEAHsXDhPZDEvUIQRXoSXQ5nG9P84737fbhdDDp19Gkg9NDNG6jEczUV5ZWNDPLccuFqEgWMMy7Qp1wCotss0IPeVXQ3zxKmpk6GsqPFd12NLZ8FOpalD2WIPLrjq9FowFDBW7Wa3CKai0vtBHb2KunMZuYpa8Qisu7vAOvOlscSE15UajWhodwj_ZHN49YnVJkM7C4PmVeNbvPASzItatBrjn1KX-bgaQ48oDLaDrEEVSoOGeBFT7kmAFXOGpLczBB6JDZE6WthR0j8AdTHPHv40G_259gsAMkTnocxdnRbwb_wfEfOP6Hwip8gwDJpOwVlxL_Y7cw_kdzu9XcseJ_7Oxu7a7if3yMz5vXo_7kInjBZxfV__LAHaZwtf4I9Lai67_qBy-SLjnmiuS815PJONvb3Owl3QywZoTC1AY7D6hb4l_TfvdGhLL-Ge-n9igGmiK9qSeIsWK-uwIZx7o9gzoKKOy1v5FZlFVwhsN41R_2J4dIM8BAz-Jue7vZ1N58P02zSXs3CN6ciVoXAZowtrM-Ti94DW21tXMS_EBp1PQnr3-Kspt2EwOgHACWo6ZP0rj9tyqWhL5gesj1APCNxgxFHxRw1HxYqTCjn3GPQ8n6V32SKuV9VOuAopjPbhZKCAKaMj4VWn6LGptRtwsIukE1tEknsCxzgzCP4MdAPI3pZ5sD7U3TWD7CrdBqZsG5iFh3Jp9t68-SsXx0lBzFtydp_zeYEpC07bs4C_AnwPl8ONZ_vojJTJcfJRMgFIShXDubpP3uRD78MRnGeqG_x-koHpwLbXfmvvkp6U29L14lb42nzwVcaKeaL_DG1R_8COCiFBfaM_jTbcOp7md9pO3x59n0Mosn7XG_R8DDSZy9Pnxx9sPhC6opH55ipMo-N_cK-joBajXBWJ6TO3r2E9ze6d2LeHT3M5qW4GJPJzG3gRf74clz-vU8GkeXZAT6fTIdoeXKGaYB2h9e9mH3qLd9AIfqfb_XA4SSvYyG8Ape7L9Em5x_hPD38OjgXP7dDcRqPIcttJ92r_s46SmiohFlwNBev-wPEPl8J-7LukIrqsBBmibp0XR4CaUOTtCOC0DQOx4N7pAEzdqFB2TGmaBmCETcjk3di2LhZjod6QeUqgpxzAtJobZnvIdtFbcxYhegwENxsi4Idce97-_aDncSfLH6_KfRfyhLWxoBOIv-293Zsum_p7vbK_rvE9N_f0fpza9CEbEiAQtJQBI7mzQgPVo6EUjqL4D_AyEz03VDRFVhVTJLG08vgbENhaNtJHJZoLCLSom4fhgajXPOQHuCLTbCrY0F5RLexHf4K-qn4eUU7TmFd9EkuYkpjkjYnzSCg3woL8kXw9H-wi0H4y0hYLGUQ2DSjKuRsLKXMhq2uI8yKlZvGYsoKM2gZbneJsKuoam26nUScN7VAbTh2p_SWPhk__C08_eDXzqHL963PY9fHr46eI9BprJsCpshL3F4dvb64BRfRdMe0EJdFcyOeJGlkc9y-63o5xX9_JnQz8bRLEI6M0_oTNKay5m0tapcRFwXFfi8qOti-Z_ruPyB6L_WTnPbov92d1pPVvTfJ6L_MKuzyOYsKUFLCIh29-jXrRR1dhLZAPBlr4-N4Yk6IG1KmYMm7DahJHQILk5nJygu9BhkSou--iisSs66eaxvR7CGl6SIdqBUfqhbrV-S4mKCztixmV0OReWAaSQq-8-_1WbcDgU3zfP9k87zH49_PnLQrSVmLFNcmjpKS3-Z_8zy3-ZG8KlQ_9riixL-f2kXwEz832ra-P_JTmuF_z8b_G-LAJZ-AeB2-0Q3gGRr7nMFkLRsdQcs6Q6gFVldAp8U_xcIzz4Q_t-y6f-nzZX899Phf87FGo3uMAcjoHcr14cRweJShI2QmbHTyXQ8J_YPvqcm2j7bk9CrkPhol4SWdMiRaj0Z9kcrTH8fTP_RkfxKnTkv_i-y114q_t9-Yun_tpq7uzsr_P_J8X8YXUYj9JrMrwAtFal2C8xL7-tp1lmZN0tt95FQvj-x5Qr5__sj_5WtxzLwP_kbLJf-b25vNW38v729sv_9VPifjjK5_qCrDznyJVdh5L8C-tEAUDOix_QiOB7tUwwgqeE9HmHr5rP9bneaRt07UhZnARZoV6U6vASc4QGzOuXLOf8FfoYfhv_fcvJ_Pm1ureS_n47-o2CS_RHHBJPnXoZ85qCQIkAzRndhkxqyMZKS4HllAB-JvOP9vCLdVqTb6jMH_l-E7KtO_7V2HfuPp09X-P8T4f-f4_hmcBdeIlpAb0qxBZAGLLwSdBLweTSIR70obd9SO8EpihCG_T_i3ot4EBHdt3UdoB0b3AnoForYyiADC4iPFfX3AT5ssU1uJmRH9wH6mHH-n7TgsFv537d2VvK_j_J5EOrunpto6SWN-MMTNAu_TgY9DPKAyCANLQN_ysHdi_EOT4FWGmBY8RFaDadA3ZB4jwM8kKm0NOHOQiBNpmgiil7k4eV0gvHMKRQ92WGjweQgPH91thE8kChmMzLimAuzdCQ4ozDrv0UJpYjbhwOC3tHWluSWUaZM2SlpRiPIutfxMFKJstphCxDLKOkB5UlKrHZY6wMoagHFfYZfaAvJac5lKhoM29f2RHsximqmpqpCmZOXqoiD6cAMKTpf1WqbWKsBtWoBWpx3YHGgZg3mZkDuIojGfYo12JmmA5oeO3BgMceBAwpv_taqBcq0HCpoerpaQFCfb6C6dyemp_3XFEjVDktbsZVWM6sFwrakS4NWwMD0Cn-GONK6ZDoq96pVaoxh6OF7gA0JojEMxUWAqQ6wtaskvY3SHoAxTeS8siFwGJ0shvoYqR__AuHcuRokFGChBqBJ7zD8SA127M8YDmWUhM9fHYb1uuohRHF22u_FGziBBFO2ZOH_vj58TtsYc0vJOFSwbVWD6O3x_CS8ioS5SiPcH6nABapF4wiGY_QBofaE40gDQykMRXzzGnZdC2Rz8ORNbQL7c9Id1zAweJbVLmB-GR6NzjhJcIdsBcPo9w4c2Tga4gK0mls79OgqhRPSubybxOLxztdPnu4GsJzT_Onu01bz6693dwKOldzpapbmtJrcPXzHIDQbIfoKqR8wIP5Oy5WvVwNojHHSH02yiwvjpArnF9ixgu_Bx80G_bf39c7ONq4e4Ji0I-vAngGmy974teA27r-9ntC8mvpGacB4L4JunE7E9pxz80PtRjed4O4irDT_OccW6Jh3o_kqdiPuOYbpY7fXUXYtkMSwP9IQYq3V2K4Zc0ZlDICpC8cEWH4KuYbbJ7m6ouJwXHE_6I-GteDX_mQCPY3jtCsO6laTikUTjP4-yfBNB3rGzErtcBuhzGcPmNH8PMrdXgtgl3RSzF-Eq_rmIpj2zN9jwQbDJsOSOHB6sbW1EcLKb4S4_noprK9KUYknra-3moAiB4PkFpshqrLT7fdS7uJqOhhQHdFFmvyOp2r7m2azpb2jhrV3WwEc431FUQ-I8MVczCMSs-KlyzOn3EiAVcZ0OgltfN38uilLImbn2IANOA05uBrDaKyfBN7O9dsYcDT7ydFuh3MeiP5pmbae0tlo7bWwGwCxmPF1kk2M9-oNDalNgwpoijjRSdIlTEHXzTW6rFzjRhHedfj8SYY4h5yFOpNrjPIEVAUCJ2A1353x-ElwjfwoPOjTAd4e0hbtD6fDDhehHQZdX8adFMGaUTXcXuKhjZXgihdQgNUFFNih0V1FdKMBNsxi8Vjk-TIeDSdTRkEBfO0onNsOYTtnWac7AFDnqJVa6HWy6eUonvCuCd4kwFohD5Re6NfKZTRAi0rANpeXad7Ev3r9rJv_FOHwOsLQphONx4M7OSAsgEl5up00RiMVNXIOlQXHHEVK6jEM5BLxH0t-LoJB8rYziH-jIjXM8QPHNiMkQO1jHrgYNt406_g2zTffNGFnZNMx7XrhH1iFNtrkKrUVw_bZ8H9kgvthGMAZ_N_OdsuO_9Pa3t1a8X8fl_8T7t6bIu6sYgHhwkERvxUUldgsxGJ15CR6yOTFcMWxxzjH6ELhTj-hSGGU-hdIYjMZ1f7JYfj69JVIYCXYN0AVwJ6llbi0G-ot59PIZ6Eio2aWnYdTM2tWZ9X0ehqvhjm9hPs1umSHEdrC0FWPWB9oXFSzTNMRZejSVqBOtITwyz580bBZvg_B1nBASLiRu9eYGqxPQ-lGmB1XkjEme1LEAIncY8UMC-02jmyZ5azPX52N8XMqn4yrMTb0YmyN00Rlvsao-W_P2CDxLijFj8biPAgPYKh34TCORiIcRM529OJs0h9x4AiWzwDXcXmn8yDItOAtwLxS40MwTSte4i_FS2xV5iWM479iJpZF_0uQYtiEj0f_N3ee2PT_1u7Wiv7_SPT_iYgWpMvbzdBBWqygcDzF1L1acKANjShFdY0WKWhDRAmieEHjKMsAY2JMb0FDssGBE8WoEZhxbdpl6onAEzynjSOQgv7AG0anXY2s0BtCjcEKv6w-q8_qs_qsPqvP6rP6rD6rz-qz-qw-q8_qs_qsPqvP6rP6rD6rz-qz-qw-q8_qs_qsPp_t5_8BWQNNwQC4AQA'
EMBEDDED_DEPLOY_VERSION='0.1.0'
EMBEDDED_DEPLOY_SHA256='fd22f6d7886bb43a49cc167a78fa0eab27c113cf79c34e33562855bdf9fb695d'
EMBEDDED_DEPLOY_SIZE='20009'

ROLE=
ARCH=
INSTANCE=default
BASE_URL=$DEFAULT_RELEASE_BASE_URL
ACCEPT_BOOTSTRAP=0
ACTIVATE=0
STAGE_ONLY=0
ALLOW_BETA=0
DRY_RUN=0
CONFIG_SOURCE=

die() {
    printf '%s\n' "SafeTun install: $*" >&2
    exit 1
}

usage() {
    cat <<'EOF'
Usage:
  sh install.sh --role hub|edge [--arch amd64|arm64] [--instance NAME]
      [--base-url https://downloads.example/releases/VERSION]
      [--config /absolute/local/config.toml] [--activate]
      [--stage-only] [--allow-beta] [--dry-run]
      --accept-bootstrap-trust

--stage-only is Edge-only and guarantees that no service is enabled or started.
The default is also non-activating; --activate is always an explicit operation.
No credential, private key, pair bundle, or token is accepted on argv or through
environment variables. Provision those as mode-0600 files after installation.
EOF
}

valid_instance() {
    case "$1" in
        ''|*[!A-Za-z0-9_.-]*|.*|-*) return 1 ;;
        *) [ "${#1}" -le 63 ] ;;
    esac
}

while [ "$#" -gt 0 ]; do
    case "$1" in
        --role)
            [ "$#" -ge 2 ] || die "--role requires a value"
            ROLE=$2
            shift 2
            ;;
        --arch)
            [ "$#" -ge 2 ] || die "--arch requires a value"
            ARCH=$2
            shift 2
            ;;
        --instance)
            [ "$#" -ge 2 ] || die "--instance requires a value"
            INSTANCE=$2
            shift 2
            ;;
        --base-url)
            [ "$#" -ge 2 ] || die "--base-url requires a value"
            BASE_URL=$2
            shift 2
            ;;
        --config)
            [ "$#" -ge 2 ] || die "--config requires a value"
            CONFIG_SOURCE=$2
            shift 2
            ;;
        --accept-bootstrap-trust)
            ACCEPT_BOOTSTRAP=1
            shift
            ;;
        --activate)
            ACTIVATE=1
            shift
            ;;
        --stage-only)
            STAGE_ONLY=1
            shift
            ;;
        --allow-beta)
            ALLOW_BETA=1
            shift
            ;;
        --dry-run)
            DRY_RUN=1
            shift
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            usage >&2
            die "unknown argument: $1"
            ;;
    esac
done

cat <<EOF
SafeTun bootstrap trust statement
---------------------------------
This installer is itself a bootstrap trust anchor. Before running it as root,
obtain it through an authenticated channel and compare its published digest or
detached signature as documented. Accepting this script means trusting its
pinned Ed25519 release key and the installation paths it owns.

Pinned key ID:      $PINNED_RELEASE_KEY_ID
Pinned fingerprint: $PINNED_RELEASE_PUBLIC_KEY_SHA256
EOF

[ "$ACCEPT_BOOTSTRAP" -eq 1 ] || die "read the trust statement, verify this installer, then pass --accept-bootstrap-trust"
case "$ROLE" in hub|edge) ;; *) die "--role must be hub or edge" ;; esac
ROLE_USER="safetun-$ROLE"
ROLE_GROUP=$ROLE_USER
valid_instance "$INSTANCE" || die "--instance must be 1..63 safe characters"
if [ "$STAGE_ONLY" -eq 1 ] && [ "$ROLE" != edge ]; then
    die "--stage-only is supported only for the Edge role"
fi
if [ "$STAGE_ONLY" -eq 1 ] && [ "$ACTIVATE" -eq 1 ]; then
    die "--stage-only and --activate are mutually exclusive"
fi
placeholder_prefix='@@''SAFETUN_'
case "$PINNED_RELEASE_KEY_ID$PINNED_RELEASE_PUBLIC_KEY_B64URL$PINNED_RELEASE_PUBLIC_KEY_SHA256$DEPLOY_PAYLOAD_B64$EMBEDDED_DEPLOY_VERSION$EMBEDDED_DEPLOY_SHA256$EMBEDDED_DEPLOY_SIZE" in
    *"$placeholder_prefix"*) die "this source template has no pinned release key; use a finalized release installer" ;;
esac
case "$PINNED_RELEASE_PUBLIC_KEY_B64URL" in
    ''|*[!A-Za-z0-9_-]*) die "pinned public key encoding is invalid" ;;
esac
case "$PINNED_RELEASE_PUBLIC_KEY_SHA256" in
    *[!0-9a-f]*|'') die "pinned public key fingerprint is invalid" ;;
esac
[ "${#PINNED_RELEASE_PUBLIC_KEY_SHA256}" -eq 64 ] || die "pinned public key fingerprint length is invalid"
case "$BASE_URL" in
    https://*) ;;
    *) die "release base URL must use HTTPS" ;;
esac
BASE_URL=${BASE_URL%/}

if [ -z "$ARCH" ]; then
    case "$(uname -m)" in
        x86_64|amd64) ARCH=amd64 ;;
        aarch64|arm64) ARCH=arm64 ;;
        *) die "unsupported architecture; pass --arch amd64 or --arch arm64" ;;
    esac
fi
case "$ARCH" in amd64|arm64) ;; *) die "--arch must be amd64 or arm64" ;; esac

for dependency in python3 openssl curl mktemp install tar cmp flock; do
    command -v "$dependency" >/dev/null 2>&1 || die "required command is unavailable: $dependency"
done
python3 - "$BASE_URL" <<'PY'
import sys
import urllib.parse
parsed = urllib.parse.urlsplit(sys.argv[1])
if parsed.scheme != "https" or not parsed.hostname or parsed.username or parsed.password or parsed.query or parsed.fragment:
    raise SystemExit("release base URL must be a plain HTTPS directory URL without userinfo, query, or fragment")
if any(ord(character) < 33 or ord(character) == 127 for character in sys.argv[1]):
    raise SystemExit("release base URL contains a control or whitespace character")
PY

if [ "$(id -u)" -eq 0 ]; then
    work_parent=/var/tmp/safetun-installer
    if [ ! -e "$work_parent" ] && [ ! -L "$work_parent" ]; then
        mkdir -- "$work_parent" || die "cannot create root work parent"
        chmod 0700 "$work_parent"
        chown root:root "$work_parent"
    fi
    python3 - "$work_parent" <<'PY'
import os
import pathlib
import stat
import sys

path = pathlib.Path(sys.argv[1])
if os.path.realpath(path) != str(path):
    raise SystemExit("root work parent must not contain symlinks")
information = os.lstat(path)
if not stat.S_ISDIR(information.st_mode) or stat.S_ISLNK(information.st_mode):
    raise SystemExit("root work parent is unsafe")
if information.st_uid != 0 or stat.S_IMODE(information.st_mode) != 0o700:
    raise SystemExit("root work parent must be root-owned mode 0700")
PY
else
    work_parent=${TMPDIR:-/tmp}
fi
work_dir=$(mktemp -d "$work_parent/safetun-install.XXXXXXXX") || die "cannot create private temporary directory"
case "$work_dir" in "$work_parent"/safetun-install.*) ;; *) die "unexpected temporary directory" ;; esac
python3 - "$work_dir" "$(id -u)" <<'PY'
import os
import pathlib
import stat
import sys

path = pathlib.Path(sys.argv[1])
information = os.lstat(path)
if os.path.realpath(path) != str(path) or not stat.S_ISDIR(information.st_mode) or stat.S_ISLNK(information.st_mode):
    raise SystemExit("private work directory is unsafe")
if information.st_uid != int(sys.argv[2]) or stat.S_IMODE(information.st_mode) != 0o700:
    raise SystemExit("private work directory ownership or mode is unsafe")
PY
transaction_armed=0
transaction_complete=0
activation_capsule_armed=0
activation_generation=
config_path=
config_had_original=0
edge_env=
edge_env_had_original=0
role_base=
old_target=
old_previous_target=
unit=
systemd_available=0
install_lock=
role_was_owned=0
shared_was_owned=0
existing_staged_version=
existing_stage_incomplete=0
version_dir=
stage_dir=
version_created=0
retain_version=0
staged_config=
staged_config_created=0
staged_env=
staged_env_created=0
stage_intent_created=0
cleanup() {
    status=$?
    trap - EXIT HUP INT TERM
    if [ "$transaction_armed" -eq 1 ] && [ "$transaction_complete" -eq 0 ]; then
        # Never ask a child to recover through the parent's inherited flock:
        # prior-service health must cross the barrier after the lock is
        # released. The durable capsule keeps every competing lifecycle out.
        if [ -n "$install_lock" ]; then
            flock -u 9 >/dev/null 2>&1 || true
            exec 9>&-
            install_lock=
        fi
        recovery_ok=0
        if [ "$activation_capsule_armed" -eq 1 ] && [ -n "$activation_generation" ]; then
            if sh "$work_dir/deploy/deploy/install-control.sh" activation-fail \
                "$ROLE" "$INSTANCE" "$activation_generation"; then
                recovery_ok=1
            fi
        elif sh "$work_dir/deploy/deploy/install-control.sh" recover-lifecycle; then
            recovery_ok=1
        fi
        if [ "$recovery_ok" -ne 1 ]; then
            status=1
            retain_version=1
            printf '%s\n' "SafeTun recovery did not complete; the durable journal was retained for the next verified installer invocation." >&2
        else
            printf '%s\n' "SafeTun install transaction failed; the durable journal restored the exact prior managed state." >&2
        fi
    fi
    if [ -n "$stage_dir" ]; then
        case "$stage_dir" in "/opt/safetun/$ROLE/versions/.stage-"*) ;; *) stage_dir= ;; esac
        if [ -n "$stage_dir" ] && [ -d "$stage_dir" ] && [ ! -L "$stage_dir" ]; then
            rm -rf -- "$stage_dir"
        fi
    fi
    if [ "$version_created" -eq 1 ] && [ "$retain_version" -eq 0 ] && [ -n "$version_dir" ]; then
        case "$version_dir" in "/opt/safetun/$ROLE/versions/"*) ;; *) version_dir= ;; esac
        if [ -n "$version_dir" ] && [ -d "$version_dir" ] && [ ! -L "$version_dir" ]; then
            rm -rf -- "$version_dir"
        fi
    fi
    if [ "$staged_config_created" -eq 1 ] && [ -n "$staged_config" ]; then
        rm -f -- "$staged_config"
    fi
    if [ "$staged_env_created" -eq 1 ] && [ -n "$staged_env" ]; then
        rm -f -- "$staged_env"
    fi
    if [ "$stage_intent_created" -eq 1 ]; then
        rm -f -- "/var/lib/safetun/installer/$ROLE.staged"
    fi
    if [ -n "$install_lock" ]; then
        rm -f -- "/var/lib/safetun/installer/shared.version.new" \
            "/var/lib/safetun/installer/shared.payload-sha256.new" \
            /var/lib/safetun/installer/shared.owned.new
    fi
    if [ -n "$install_lock" ]; then
        flock -u 9 >/dev/null 2>&1 || true
        exec 9>&-
    fi
    rm -rf -- "$work_dir"
    exit "$status"
}
trap cleanup EXIT
trap 'exit 1' HUP INT TERM
chmod 0700 "$work_dir"

fetch_https() {
    source_url=$1
    destination=$2
    maximum=$3
    case "$source_url" in https://*) ;; *) die "refusing non-HTTPS download URL" ;; esac
    curl -q --fail --silent --show-error --location --max-redirs 3 \
        --proto '=https' --proto-redir '=https' --tlsv1.2 \
        --connect-timeout 15 --max-time 300 --max-filesize "$maximum" \
        --output "$destination" "$source_url"
    [ -f "$destination" ] && [ ! -L "$destination" ] || die "download did not produce a regular file"
    actual_size=$(wc -c < "$destination" | tr -d ' ')
    [ "$actual_size" -le "$maximum" ] || die "download exceeds its size bound"
}

durable_sync_paths() {
    python3 - "$@" <<'PY'
import os
import pathlib
import stat
import sys

parents = set()
for raw_path in sys.argv[1:]:
    path = pathlib.Path(raw_path)
    information = os.lstat(path)
    if stat.S_ISLNK(information.st_mode):
        raise SystemExit(f"refusing to sync symlink: {path}")
    if stat.S_ISREG(information.st_mode):
        with path.open("rb") as handle:
            os.fsync(handle.fileno())
    elif stat.S_ISDIR(information.st_mode):
        descriptor = os.open(path, os.O_RDONLY | os.O_DIRECTORY)
        try:
            os.fsync(descriptor)
        finally:
            os.close(descriptor)
    else:
        raise SystemExit(f"refusing to sync special path: {path}")
    parents.add(path.parent)
for parent in sorted(parents, key=lambda item: len(str(item)), reverse=True):
    descriptor = os.open(parent, os.O_RDONLY | os.O_DIRECTORY)
    try:
        os.fsync(descriptor)
    finally:
        os.close(descriptor)
PY
}

manifest="$work_dir/manifest.json"
signature_source="$work_dir/manifest.json.sig.input"
fetch_https "$BASE_URL/manifest.json" "$manifest" 1048576
fetch_https "$BASE_URL/manifest.json.sig" "$signature_source" 4096

python3 - "$PINNED_RELEASE_PUBLIC_KEY_B64URL" "$work_dir/release-key.raw" "$signature_source" "$work_dir/manifest.sig" <<'PY'
import base64
import pathlib
import re
import sys

def decode_url(value: bytes) -> bytes:
    if not re.fullmatch(rb"[A-Za-z0-9_-]+", value):
        raise SystemExit("invalid base64url data")
    return base64.urlsafe_b64decode(value + b"=" * (-len(value) % 4))

public = decode_url(sys.argv[1].encode("ascii"))
if len(public) != 32:
    raise SystemExit("pinned Ed25519 public key is not 32 bytes")
pathlib.Path(sys.argv[2]).write_bytes(public)

encoded = pathlib.Path(sys.argv[3]).read_bytes()
signature = encoded if len(encoded) == 64 else decode_url(encoded.strip())
if len(signature) != 64:
    raise SystemExit("detached Ed25519 signature is not 64 bytes")
pathlib.Path(sys.argv[4]).write_bytes(signature)
PY

computed_fingerprint=$(python3 - "$work_dir/release-key.raw" <<'PY'
import hashlib, pathlib, sys
print(hashlib.sha256(pathlib.Path(sys.argv[1]).read_bytes()).hexdigest())
PY
)
[ "$computed_fingerprint" = "$PINNED_RELEASE_PUBLIC_KEY_SHA256" ] || die "pinned release-key fingerprint mismatch"

python3 - "$work_dir/release-key.raw" "$work_dir/release-key.der" <<'PY'
import pathlib, sys
raw = pathlib.Path(sys.argv[1]).read_bytes()
# RFC 8410 SubjectPublicKeyInfo prefix for a 32-byte Ed25519 public key.
pathlib.Path(sys.argv[2]).write_bytes(bytes.fromhex("302a300506032b6570032100") + raw)
PY
printf 'SAFETUN-RELEASE-MANIFEST-v1\000' > "$work_dir/manifest.signing-input"
cat "$manifest" >> "$work_dir/manifest.signing-input"

verified=0
# The single quotes deliberately protect fixed PHP source from shell expansion.
# shellcheck disable=SC2016
if openssl pkeyutl -verify -pubin -keyform DER -inkey "$work_dir/release-key.der" \
    -rawin -in "$work_dir/manifest.signing-input" -sigfile "$work_dir/manifest.sig" >/dev/null 2>&1; then
    verified=1
elif command -v php >/dev/null 2>&1 && php -n -r '
    if (!extension_loaded("sodium")) { exit(2); }
    $s = file_get_contents($argv[1]); $m = file_get_contents($argv[2]); $k = file_get_contents($argv[3]);
    exit(is_string($s) && is_string($m) && is_string($k) && sodium_crypto_sign_verify_detached($s, $m, $k) ? 0 : 1);
' "$work_dir/manifest.sig" "$work_dir/manifest.signing-input" "$work_dir/release-key.raw" >/dev/null 2>&1; then
    verified=1
fi
[ "$verified" -eq 1 ] || die "manifest Ed25519 signature verification failed; there is no unverified fallback"

current_version=
if [ -f "/var/lib/safetun/installer/${ROLE}.version" ] && [ ! -L "/var/lib/safetun/installer/${ROLE}.version" ]; then
    current_version=$(sed -n '1p' "/var/lib/safetun/installer/${ROLE}.version")
elif [ -e "/var/lib/safetun/installer/${ROLE}.version" ] || [ -L "/var/lib/safetun/installer/${ROLE}.version" ]; then
    die "existing version marker is unsafe"
fi

python3 - "$manifest" "$ROLE" "$ARCH" "$ALLOW_BETA" "$current_version" "$PINNED_RELEASE_KEY_ID" "$work_dir" <<'PY'
import datetime
import json
import pathlib
import re
import sys
import urllib.parse

path, role, arch, allow_beta, current, key_id, output = sys.argv[1:]
raw = pathlib.Path(path).read_bytes()
try:
    data = json.loads(raw)
except Exception as exc:
    raise SystemExit(f"invalid manifest JSON: {exc}")
if not isinstance(data, dict) or set(data) != {
    "schema_version", "version", "channel", "generated_at",
    "minimum_config_schema", "minimum_api_version", "release_key_id", "artifacts",
}:
    raise SystemExit("manifest fields are not the exact schema")
if type(data["schema_version"]) is not int or data["schema_version"] != 1:
    raise SystemExit("unsupported manifest schema")
if data["release_key_id"] != key_id:
    raise SystemExit("manifest release key ID does not match the pinned key")
version_re = re.compile(r"^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-([0-9A-Za-z.-]+))?$")

def parse_version(value):
    if not isinstance(value, str):
        raise SystemExit("release version must be text")
    match = version_re.fullmatch(value)
    if not match:
        raise SystemExit("invalid release version")
    pre = match.group(4)
    if pre is not None:
        for item in pre.split("."):
            if not item or (item.isdigit() and len(item) > 1 and item[0] == "0"):
                raise SystemExit("invalid release prerelease identifier")
    return tuple(map(int, match.group(1, 2, 3))), pre

def compare(left, right):
    lnum, lpre = parse_version(left); rnum, rpre = parse_version(right)
    if lnum != rnum:
        return (lnum > rnum) - (lnum < rnum)
    if lpre == rpre: return 0
    if lpre is None: return 1
    if rpre is None: return -1
    lp, rp = lpre.split("."), rpre.split(".")
    for a, b in zip(lp, rp):
        if a == b: continue
        ai, bi = a.isdigit(), b.isdigit()
        if ai and bi: return (int(a) > int(b)) - (int(a) < int(b))
        if ai != bi: return -1 if ai else 1
        return (a > b) - (a < b)
    return (len(lp) > len(rp)) - (len(lp) < len(rp))

version = data["version"]
parse_version(version)
if current and compare(version, current) < 0:
    raise SystemExit("release downgrade is not allowed")
if data["channel"] not in ("stable", "beta") or (data["channel"] == "beta" and allow_beta != "1"):
    raise SystemExit("manifest channel is not allowed")
if type(data["minimum_config_schema"]) is not int or data["minimum_config_schema"] > 1:
    raise SystemExit("release requires a newer config schema")
if data["minimum_api_version"] != "v1":
    raise SystemExit("release API version is incompatible")
try:
    generated = datetime.datetime.fromisoformat(data["generated_at"].replace("Z", "+00:00"))
    now = datetime.datetime.now(datetime.timezone.utc)
    if generated.tzinfo is None or generated > now + datetime.timedelta(hours=24):
        raise ValueError()
except Exception:
    raise SystemExit("manifest generated_at is invalid")

artifacts = data["artifacts"]
if not isinstance(artifacts, list) or not (1 <= len(artifacts) <= 100):
    raise SystemExit("manifest artifact count is invalid")
seen = set(); selected = []
for artifact in artifacts:
    required = {"name", "role", "os", "arch", "sha256", "size", "url"}
    if not isinstance(artifact, dict) or not required.issubset(artifact) or set(artifact) - (required | {"watermark"}):
        raise SystemExit("artifact fields are invalid")
    if "watermark" in artifact and not isinstance(artifact["watermark"], str):
        raise SystemExit("artifact watermark is invalid")
    target = (artifact["role"], artifact["os"], artifact["arch"])
    if target in seen: raise SystemExit("duplicate role/platform artifact")
    seen.add(target)
    if artifact["role"] not in ("hub", "edge", "backend"):
        raise SystemExit("artifact role is invalid")
    if artifact["os"] != "linux" and not (artifact["role"] == "backend" and artifact["os"] == "any"):
        raise SystemExit("artifact OS is invalid")
    if artifact["arch"] not in ("amd64", "arm64") and not (artifact["role"] == "backend" and artifact["arch"] == "any"):
        raise SystemExit("artifact architecture is invalid")
    if not isinstance(artifact["name"], str) or not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_.-]{0,254}", artifact["name"]):
        raise SystemExit("artifact name is unsafe")
    if not isinstance(artifact["sha256"], str) or not re.fullmatch(r"[0-9a-f]{64}", artifact["sha256"]):
        raise SystemExit("artifact SHA-256 is invalid")
    if type(artifact["size"]) is not int or not (1 <= artifact["size"] <= 1 << 30):
        raise SystemExit("artifact size is invalid")
    parsed = urllib.parse.urlsplit(artifact["url"])
    if parsed.scheme != "https" or not parsed.hostname or parsed.username or parsed.password or parsed.fragment:
        raise SystemExit("artifact URL is unsafe")
    if target == (role, "linux", arch): selected.append(artifact)
if len(selected) != 1:
    raise SystemExit("signed manifest has no unique artifact for this role and architecture")

chosen = selected[0]
out = pathlib.Path(output)
for name, value in {
    "selected.name": chosen["name"], "selected.sha256": chosen["sha256"],
    "selected.size": str(chosen["size"]), "selected.url": chosen["url"],
    "selected.version": version,
}.items():
    if "\n" in value or "\r" in value or "\0" in value:
        raise SystemExit("unsafe control character in manifest")
    (out / name).write_text(value, encoding="utf-8")
PY

artifact_name=$(sed -n '1p' "$work_dir/selected.name")
artifact_sha=$(sed -n '1p' "$work_dir/selected.sha256")
artifact_size=$(sed -n '1p' "$work_dir/selected.size")
artifact_url=$(sed -n '1p' "$work_dir/selected.url")
release_version=$(sed -n '1p' "$work_dir/selected.version")
[ "$release_version" = "$EMBEDDED_DEPLOY_VERSION" ] \
    || die "this installer deploy payload is bound to release $EMBEDDED_DEPLOY_VERSION, not signed release $release_version"
artifact_file="$work_dir/$artifact_name"
fetch_https "$artifact_url" "$artifact_file" "$artifact_size"
actual_size=$(wc -c < "$artifact_file" | tr -d ' ')
[ "$actual_size" = "$artifact_size" ] || die "artifact size does not match the signed manifest"
actual_sha=$(python3 - "$artifact_file" <<'PY'
import hashlib, pathlib, sys
print(hashlib.sha256(pathlib.Path(sys.argv[1]).read_bytes()).hexdigest())
PY
)
[ "$actual_sha" = "$artifact_sha" ] || die "artifact SHA-256 does not match the signed manifest"

python3 - "$DEPLOY_PAYLOAD_B64" "$work_dir/deploy" "$EMBEDDED_DEPLOY_SHA256" "$EMBEDDED_DEPLOY_SIZE" <<'PY'
import base64
import hashlib
import io
import pathlib
import re
import sys
import tarfile

encoded, destination, expected_sha256, expected_size = sys.argv[1:]
try:
    payload = base64.urlsafe_b64decode(encoded.encode("ascii") + b"=" * (-len(encoded) % 4))
except Exception as exc:
    raise SystemExit(f"invalid embedded deploy payload: {exc}")
if not re.fullmatch(r"[0-9a-f]{64}", expected_sha256) or not expected_size.isdigit():
    raise SystemExit("embedded deploy payload metadata is invalid")
if len(payload) != int(expected_size) or hashlib.sha256(payload).hexdigest() != expected_sha256:
    raise SystemExit("embedded deploy payload size or SHA-256 mismatch")
allowed = {
    "deploy/install-control.sh", "deploy/uninstall.sh",
    "deploy/systemd/safetun-hub@.service", "deploy/systemd/safetun-edge@.service",
    "deploy/systemd/safetun-hub-rollback@.service", "deploy/systemd/safetun-edge-rollback@.service",
    "deploy/systemd/safetun-release-cleanup.service", "deploy/systemd/safetun-release-cleanup.timer",
    "deploy/systemd/safetun-install-recover.service",
    "deploy/systemd/safetun-install-activation-watch.service",
    "deploy/systemd/safetun-install-activation-watch.timer",
    "examples/hub.toml", "examples/edge.toml", "examples/edge-default.env",
}
root = pathlib.Path(destination)
root.mkdir(mode=0o700)
with tarfile.open(fileobj=io.BytesIO(payload), mode="r:gz") as archive:
    members = archive.getmembers()
    names = {member.name for member in members}
    if names != allowed:
        raise SystemExit("embedded deploy payload has unexpected or missing members")
    for member in members:
        if not member.isfile() or member.issym() or member.islnk() or member.name.startswith("/") or ".." in pathlib.PurePosixPath(member.name).parts:
            raise SystemExit("embedded deploy payload contains an unsafe member")
        target = root.joinpath(*pathlib.PurePosixPath(member.name).parts)
        target.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
        source = archive.extractfile(member)
        if source is None: raise SystemExit("cannot extract deploy payload member")
        target.write_bytes(source.read())
        target.chmod(0o600)
PY

printf 'Verified release %s (%s/linux/%s), artifact %s.\n' "$release_version" "$ROLE" "$ARCH" "$artifact_name"
if [ "$DRY_RUN" -eq 1 ]; then
    printf '%s\n' "Dry-run complete: manifest signature, schema, target, size, hash, and embedded deploy payload verified; no persistent changes were made."
    exit 0
fi
[ "$(id -u)" -eq 0 ] || die "persistent installation must run as root"
python3 - "$PATH" <<'PY'
import os
import pathlib
import shutil
import stat
import sys

trusted_path = sys.argv[1]
required = {
    "python3", "openssl", "curl", "mktemp", "install", "tar", "cmp", "id", "chmod", "mkdir",
    "mv", "cp", "rm", "rmdir", "ln", "readlink", "sed", "getent", "groupadd", "useradd", "tr",
    "grep", "chown", "uname", "flock",
}
for name in sorted(required):
    located = shutil.which(name, path=trusted_path)
    if not located:
        raise SystemExit(f"required trusted tool is unavailable: {name}")
    resolved = pathlib.Path(located).resolve(strict=True)
    information = os.stat(resolved)
    if not stat.S_ISREG(information.st_mode) or information.st_uid != 0 or stat.S_IMODE(information.st_mode) & 0o022:
        raise SystemExit(f"trusted tool is not a root-owned non-writable regular file: {resolved}")
PY
install -d -m 0700 -o root -g root /var/lib/safetun/installer
lock_file=/var/lib/safetun/installer/install.global.lock
python3 - "$lock_file" <<'PY'
import os
import stat
import sys

path = sys.argv[1]
flags = os.O_RDWR | os.O_CREAT
if hasattr(os, "O_NOFOLLOW"):
    flags |= os.O_NOFOLLOW
try:
    descriptor = os.open(path, flags, 0o600)
except OSError as error:
    raise SystemExit(f"cannot safely open global installer lock: {error}") from error
try:
    information = os.fstat(descriptor)
    if not stat.S_ISREG(information.st_mode) or information.st_uid != 0:
        raise SystemExit("global installer lock is not a root-owned regular file")
    os.fchmod(descriptor, 0o600)
    os.fsync(descriptor)
finally:
    os.close(descriptor)
for directory in (
    os.path.dirname(path),
    os.path.dirname(os.path.dirname(path)),
    os.path.dirname(os.path.dirname(os.path.dirname(path))),
):
    descriptor = os.open(directory, os.O_RDONLY | os.O_DIRECTORY)
    try:
        os.fsync(descriptor)
    finally:
        os.close(descriptor)
PY
exec 9<>"$lock_file"
flock -n 9 || die "another install, rollback, cleanup, or uninstall transaction is active"
install_lock=$lock_file
flock -u 9
exec 9>&-
install_lock=
sh "$work_dir/deploy/deploy/install-control.sh" recover-lifecycle
exec 9<>"$lock_file"
flock -n 9 || die "another install, rollback, cleanup, or uninstall transaction is active"
install_lock=$lock_file
sh "$work_dir/deploy/deploy/install-control.sh" assert-clean
for uninstall_tombstone in /var/lib/safetun/installer/hub.uninstalling /var/lib/safetun/installer/edge.uninstalling; do
    if [ -e "$uninstall_tombstone" ] || [ -L "$uninstall_tombstone" ]; then
        [ -f "$uninstall_tombstone" ] && [ ! -L "$uninstall_tombstone" ] \
            || die "unsafe interrupted-uninstall tombstone"
        die "an interrupted uninstall must be resumed with safetun-uninstall before installation"
    fi
done

existing_marker="/var/lib/safetun/installer/$ROLE.owned"
if [ -f "$existing_marker" ] && [ ! -L "$existing_marker" ]; then
    [ "$(sed -n '1p' "$existing_marker")" = SAFETUN_INSTALLER_OWNED_V1 ] || die "existing ownership marker is invalid"
    [ "$(sed -n '2p' "$existing_marker")" = "$ROLE" ] || die "existing ownership marker role mismatch"
    existing_instance=$(sed -n '3p' "$existing_marker")
    [ "$existing_instance" = "$INSTANCE" ] || die "this installer manages one instance per role; existing instance is $existing_instance"
    role_was_owned=1
elif [ -e "$existing_marker" ] || [ -L "$existing_marker" ]; then
    die "existing ownership marker is unsafe"
fi
staged_marker="/var/lib/safetun/installer/$ROLE.staged"
if [ -f "$staged_marker" ] && [ ! -L "$staged_marker" ]; then
    staged_magic=$(sed -n '1p' "$staged_marker")
    case "$staged_magic" in
        SAFETUN_INSTALLER_STAGED_V1) ;;
        SAFETUN_INSTALLER_STAGING_V1) existing_stage_incomplete=1 ;;
        *) die "existing staged marker is invalid" ;;
    esac
    [ "$(sed -n '2p' "$staged_marker")" = "$ROLE" ] || die "existing staged marker role mismatch"
    existing_instance=$(sed -n '3p' "$staged_marker")
    [ "$existing_instance" = "$INSTANCE" ] || die "this installer manages one instance per role; staged instance is $existing_instance"
    existing_staged_version=$(sed -n '4p' "$staged_marker")
    python3 - "$existing_staged_version" <<'PY'
import re, sys
match = re.fullmatch(r"(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-([0-9A-Za-z.-]+))?", sys.argv[1])
if not match or (match.group(4) and any(not item or (item.isdigit() and len(item) > 1 and item[0] == "0") for item in match.group(4).split("."))):
    raise SystemExit("existing staged marker version is invalid")
PY
    [ "$existing_staged_version" = "$release_version" ] \
        || die "an existing staged candidate belongs to release $existing_staged_version"
elif [ -e "$staged_marker" ] || [ -L "$staged_marker" ]; then
    die "existing staged marker is unsafe"
fi
if [ "$existing_stage_incomplete" -eq 1 ] && [ "$STAGE_ONLY" -ne 1 ]; then
    die "an interrupted stage-only transaction exists; rerun --stage-only or uninstall the staged candidate first"
fi
shared_was_owned=$role_was_owned
if [ "$shared_was_owned" -eq 0 ]; then
    if [ "$ROLE" = hub ]; then
        other_role=edge
    else
        other_role=hub
    fi
    other_marker="/var/lib/safetun/installer/$other_role.owned"
    if [ -f "$other_marker" ] && [ ! -L "$other_marker" ]; then
        [ "$(sed -n '1p' "$other_marker")" = SAFETUN_INSTALLER_OWNED_V1 ] || die "other role ownership marker is invalid"
        [ "$(sed -n '2p' "$other_marker")" = "$other_role" ] || die "other role ownership marker mismatch"
        shared_was_owned=1
    elif [ -e "$other_marker" ] || [ -L "$other_marker" ]; then
        die "other role ownership marker is unsafe"
    fi
fi
shared_marker=/var/lib/safetun/installer/shared.owned
if [ -f "$shared_marker" ] && [ ! -L "$shared_marker" ]; then
    [ "$(sed -n '1p' "$shared_marker")" = SAFETUN_SHARED_ASSETS_OWNED_V1 ] \
        || die "shared asset ownership marker is invalid"
    shared_was_owned=1
elif [ -e "$shared_marker" ] || [ -L "$shared_marker" ]; then
    die "shared asset ownership marker is unsafe"
fi

# Publish a recoverable authorization record before any stage-only artifact.
# SIGKILL can then leave only paths that a rerun or uninstall is authorized to
# validate and remove; the completed marker is published after all writes.
if [ "$STAGE_ONLY" -eq 1 ] && [ "$existing_stage_incomplete" -eq 0 ]; then
    printf '%s\n%s\n%s\n%s\n' SAFETUN_INSTALLER_STAGING_V1 "$ROLE" "$INSTANCE" "$release_version" \
        > "/var/lib/safetun/installer/$ROLE.staged.new"
    chmod 0600 "/var/lib/safetun/installer/$ROLE.staged.new"
    mv -f "/var/lib/safetun/installer/$ROLE.staged.new" "/var/lib/safetun/installer/$ROLE.staged"
    durable_sync_paths "/var/lib/safetun/installer/$ROLE.staged" /var/lib/safetun/installer
    stage_intent_created=1
fi

if ! getent group "$ROLE_GROUP" >/dev/null 2>&1; then
    groupadd --system "$ROLE_GROUP"
fi
if ! getent passwd "$ROLE_USER" >/dev/null 2>&1; then
    nologin_shell=/usr/sbin/nologin
    [ -x "$nologin_shell" ] || nologin_shell=/sbin/nologin
    useradd --system --gid "$ROLE_GROUP" --home-dir "/var/lib/safetun/$ROLE" \
        --shell "$nologin_shell" "$ROLE_USER"
    install -d -m 0700 -o root -g root /var/lib/safetun/installer
    printf '%s\n%s\n' SAFETUN_INSTALLER_CREATED_USER_V1 "$ROLE_USER" \
        > "/var/lib/safetun/installer/$ROLE.user.owned"
    chmod 0600 "/var/lib/safetun/installer/$ROLE.user.owned"
fi
python3 - "$ROLE_USER" "$ROLE_GROUP" "/var/lib/safetun/$ROLE" <<'PY'
import grp
import os
import pathlib
import pwd
import sys

user_name, group_name, expected_home = sys.argv[1:]
user = pwd.getpwnam(user_name)
group = grp.getgrnam(group_name)
if user.pw_uid == 0 or user.pw_gid != group.gr_gid or user.pw_dir != expected_home:
    raise SystemExit("role account has unsafe UID, primary group, or home")
if user.pw_shell not in {"/usr/sbin/nologin", "/sbin/nologin"}:
    raise SystemExit("role account must use the system nologin shell")
if sum(1 for candidate in pwd.getpwall() if candidate.pw_uid == user.pw_uid) != 1:
    raise SystemExit("role account UID is not unique")
if sum(1 for candidate in grp.getgrall() if candidate.gr_gid == group.gr_gid) != 1:
    raise SystemExit("role account primary GID is not unique")
if group.gr_mem:
    raise SystemExit("role service group must not have supplementary members")
groups = set(os.getgrouplist(user_name, group.gr_gid))
if groups != {group.gr_gid}:
    raise SystemExit("role account must not have supplementary groups")
password = None
try:
    for raw_line in pathlib.Path("/etc/shadow").read_text(encoding="utf-8").splitlines():
        fields = raw_line.split(":", 2)
        if len(fields) >= 2 and fields[0] == user_name:
            password = fields[1]
            break
except OSError as error:
    raise SystemExit("cannot verify the role account password lock") from error
if password is None:
    raise SystemExit("role account has no shadow entry")
if not password.startswith(("!", "*")):
    raise SystemExit("role account password must be locked")
uid_min = 1000
try:
    for raw_line in pathlib.Path("/etc/login.defs").read_text(encoding="utf-8").splitlines():
        fields = raw_line.split()
        if len(fields) >= 2 and fields[0] == "UID_MIN" and fields[1].isdigit():
            uid_min = int(fields[1])
            break
except OSError:
    pass
if user.pw_uid >= uid_min:
    raise SystemExit("role account is not a system account")
PY

install -d -m 0755 -o root -g root /opt/safetun "/opt/safetun/$ROLE" "/opt/safetun/$ROLE/versions"
install -d -m 0700 -o root -g root /var/lib/safetun/installer
install -d -m 0751 -o root -g root /etc/safetun
install -d -m 0711 -o root -g root /etc/safetun/credentials
install -d -m 0755 -o root -g root /usr/libexec/safetun /usr/local/bin /usr/local/sbin

python3 - "$ROLE_USER" "$ROLE_GROUP" "/var/lib/safetun/$ROLE-$INSTANCE" \
    "/etc/safetun/credentials/$ROLE-$INSTANCE" <<'PY'
import grp
import os
import pathlib
import pwd
import stat
import sys

uid = pwd.getpwnam(sys.argv[1]).pw_uid
gid = grp.getgrnam(sys.argv[2]).gr_gid
for raw_path in sys.argv[3:]:
    path = pathlib.Path(raw_path)
    parent = path.parent
    if os.path.lexists(path):
        flags = os.O_RDONLY | os.O_DIRECTORY
        if hasattr(os, "O_NOFOLLOW"):
            flags |= os.O_NOFOLLOW
        try:
            descriptor = os.open(path, flags)
        except OSError as error:
            raise SystemExit(f"unsafe role directory; migrate offline without changing it: {path}") from error
        try:
            information = os.fstat(descriptor)
            if not stat.S_ISDIR(information.st_mode) or information.st_uid != uid \
                    or information.st_gid != gid or stat.S_IMODE(information.st_mode) != 0o700:
                raise SystemExit(f"legacy role directory must be migrated offline before install: {path}")
        finally:
            os.close(descriptor)
        continue
    os.mkdir(path, 0o700)
    flags = os.O_RDONLY | os.O_DIRECTORY
    if hasattr(os, "O_NOFOLLOW"):
        flags |= os.O_NOFOLLOW
    descriptor = os.open(path, flags)
    try:
        os.fchown(descriptor, uid, gid)
        os.fchmod(descriptor, 0o700)
        os.fsync(descriptor)
    finally:
        os.close(descriptor)
    parent_descriptor = os.open(parent, os.O_RDONLY | os.O_DIRECTORY)
    try:
        os.fsync(parent_descriptor)
    finally:
        os.close(parent_descriptor)
PY

# Verify role ownership through held directory descriptors. Automatic legacy
# chown is deliberately refused: a compromised service user could otherwise
# race path-based root ownership changes. Operators must stop the old service,
# migrate offline, and rerun.
python3 - "$ROLE_USER" "/var/lib/safetun/$ROLE-$INSTANCE" \
    "/etc/safetun/credentials/$ROLE-$INSTANCE" <<'PY'
import os
import pwd
import stat
import sys

identity = sys.argv[1]
uid = pwd.getpwnam(identity).pw_uid
for raw_root in sys.argv[2:]:
    flags = os.O_RDONLY | os.O_DIRECTORY
    if hasattr(os, "O_NOFOLLOW"):
        flags |= os.O_NOFOLLOW
    root_fd = os.open(raw_root, flags)
    def verify_directory(directory_fd, display):
        information = os.fstat(directory_fd)
        if not stat.S_ISDIR(information.st_mode) or information.st_uid != uid:
            raise SystemExit(f"role directory ownership needs an offline migration: {display}")
        with os.scandir(directory_fd) as entries:
            names = sorted(entry.name for entry in entries)
        for name in names:
            # O_PATH never opens a FIFO/socket/device for I/O and therefore
            # cannot block the root installer while the role controls this
            # tree. The held descriptor is fstat'ed before any traversal.
            child_flags = getattr(os, "O_PATH", os.O_RDONLY | os.O_NONBLOCK)
            if hasattr(os, "O_NOFOLLOW"):
                child_flags |= os.O_NOFOLLOW
            try:
                child_fd = os.open(name, child_flags, dir_fd=directory_fd)
            except OSError as error:
                raise SystemExit(f"unsafe role-scoped member: {display}/{name}") from error
            try:
                child = os.fstat(child_fd)
                child_display = f"{display}/{name}"
                if child.st_uid != uid:
                    raise SystemExit(f"role file ownership needs an offline migration: {child_display}")
                if stat.S_ISDIR(child.st_mode):
                    directory_flags = os.O_RDONLY | os.O_DIRECTORY
                    if hasattr(os, "O_NOFOLLOW"):
                        directory_flags |= os.O_NOFOLLOW
                    traversal_fd = os.open(".", directory_flags, dir_fd=child_fd)
                    try:
                        verify_directory(traversal_fd, child_display)
                    finally:
                        os.close(traversal_fd)
                elif not stat.S_ISREG(child.st_mode) or child.st_nlink != 1:
                    raise SystemExit(f"unsafe role-scoped member: {child_display}")
            finally:
                os.close(child_fd)
    try:
        verify_directory(root_fd, raw_root)
    finally:
        os.close(root_fd)
PY

durable_sync_paths /var/lib /var/lib/safetun /var/lib/safetun/installer \
    /opt /opt/safetun "/opt/safetun/$ROLE" "/opt/safetun/$ROLE/versions" \
    /etc /etc/safetun /etc/safetun/credentials "/etc/safetun/credentials/$ROLE-$INSTANCE" \
    "/var/lib/safetun/$ROLE-$INSTANCE" /usr/local /usr/local/bin /usr/local/sbin \
    /usr/libexec /usr/libexec/safetun

version_dir="/opt/safetun/$ROLE/versions/$release_version"
stage_dir="/opt/safetun/$ROLE/versions/.stage-$release_version-$$"
if [ -e "$version_dir" ] || [ -L "$version_dir" ]; then
    [ -d "$version_dir" ] && [ ! -L "$version_dir" ] || die "existing version path is unsafe"
    [ -f "$version_dir/safetun-$ROLE" ] && [ ! -L "$version_dir/safetun-$ROLE" ] || die "existing version binary is unsafe"
    installed_sha=$(python3 - "$version_dir/safetun-$ROLE" <<'PY'
import hashlib, pathlib, sys
print(hashlib.sha256(pathlib.Path(sys.argv[1]).read_bytes()).hexdigest())
PY
)
    [ "$installed_sha" = "$artifact_sha" ] || die "same version is already present with different bytes"
else
    [ ! -e "$stage_dir" ] && [ ! -L "$stage_dir" ] || die "staging path already exists"
    install -d -m 0755 -o root -g root "$stage_dir"
    install -m 0755 -o root -g root "$artifact_file" "$stage_dir/safetun-$ROLE"
    "$stage_dir/safetun-$ROLE" version >/dev/null || die "downloaded binary failed its version smoke test"
    mv "$stage_dir" "$version_dir"
    durable_sync_paths "$version_dir/safetun-$ROLE" "$version_dir" "/opt/safetun/$ROLE/versions"
    version_created=1
fi

config_path="/etc/safetun/$ROLE-$INSTANCE.toml"
candidate_config="$work_dir/candidate-config.toml"
if [ -n "$CONFIG_SOURCE" ]; then
    [ -f "$CONFIG_SOURCE" ] && [ ! -L "$CONFIG_SOURCE" ] || die "--config source must be a regular, non-symlink file"
    cp -- "$CONFIG_SOURCE" "$candidate_config"
elif [ -e "$config_path" ] || [ -L "$config_path" ]; then
    [ -f "$config_path" ] && [ ! -L "$config_path" ] || die "configuration path is not a regular file"
    cp -- "$config_path" "$candidate_config"
else
    python3 - "$work_dir/deploy/examples/$ROLE.toml" "$candidate_config" "$ROLE" "$INSTANCE" <<'PY'
import pathlib, sys
source, destination, role, instance = sys.argv[1:]
text = pathlib.Path(source).read_text(encoding="utf-8")
text = text.replace(f"{role}-default", f"{role}-{instance}")
pathlib.Path(destination).write_text(text, encoding="utf-8", newline="\n")
PY
fi
chmod 0600 "$candidate_config"
"$version_dir/safetun-$ROLE" config validate --config "$candidate_config"

if [ "$ROLE" = edge ]; then
    edge_env="/etc/safetun/edge-$INSTANCE.env"
    candidate_edge_env="$work_dir/candidate-edge.env"
    if [ -e "$edge_env" ] || [ -L "$edge_env" ]; then
        [ -f "$edge_env" ] && [ ! -L "$edge_env" ] || die "Edge environment path is unsafe"
        cp -- "$edge_env" "$candidate_edge_env"
    else
        python3 - "$work_dir/deploy/examples/edge-default.env" "$candidate_edge_env" "$INSTANCE" <<'PY'
import pathlib, sys
source, destination, instance = sys.argv[1:]
text = pathlib.Path(source).read_text(encoding="utf-8").replace("edge-default", f"edge-{instance}")
pathlib.Path(destination).write_text(text, encoding="utf-8", newline="\n")
PY
    fi
    chmod 0600 "$candidate_edge_env"
fi

if [ "$STAGE_ONLY" -eq 1 ]; then
    staged_config_dir=/etc/safetun/staged
    install -d -m 0711 -o root -g root "$staged_config_dir"
    staged_config="$staged_config_dir/$ROLE-$INSTANCE-$release_version.toml"
    if [ -e "$staged_config" ] || [ -L "$staged_config" ]; then
        if [ ! -f "$staged_config" ] || [ -L "$staged_config" ] || ! cmp -s "$candidate_config" "$staged_config"; then
            die "a different staged config already exists for this version"
        fi
    else
        install -m 0640 -o root -g "$ROLE_GROUP" "$candidate_config" "$staged_config"
        staged_config_created=1
    fi
    if [ "$ROLE" = edge ]; then
        staged_env="$staged_config_dir/edge-$INSTANCE-$release_version.env"
        if [ -e "$staged_env" ] || [ -L "$staged_env" ]; then
            if [ ! -f "$staged_env" ] || [ -L "$staged_env" ] || ! cmp -s "$candidate_edge_env" "$staged_env"; then
                die "a different staged Edge environment already exists for this version"
            fi
        else
            install -m 0640 -o root -g "$ROLE_GROUP" "$candidate_edge_env" "$staged_env"
            staged_env_created=1
        fi
    fi
    if [ -n "$staged_env" ]; then
        durable_sync_paths "$version_dir/safetun-$ROLE" "$version_dir" "$staged_config" "$staged_env" \
            "$staged_config_dir" /etc/safetun
    else
        durable_sync_paths "$version_dir/safetun-$ROLE" "$version_dir" "$staged_config" \
            "$staged_config_dir" /etc/safetun
    fi
    printf '%s\n%s\n%s\n%s\n' SAFETUN_INSTALLER_STAGED_V1 "$ROLE" "$INSTANCE" "$release_version" \
        > "/var/lib/safetun/installer/$ROLE.staged.new"
    chmod 0600 "/var/lib/safetun/installer/$ROLE.staged.new"
    mv -f "/var/lib/safetun/installer/$ROLE.staged.new" "/var/lib/safetun/installer/$ROLE.staged"
    durable_sync_paths "/var/lib/safetun/installer/$ROLE.staged" /var/lib/safetun/installer
    printf 'Staged SafeTun %s %s without changing current, /usr/local/bin, or the live config.\n' "$ROLE" "$release_version"
    printf 'Candidate config: %s\n' "$staged_config"
    printf '%s\n' "No SafeTun service was enabled or started. Promote only after review by rerunning without --stage-only and passing --config that candidate path."
    retain_version=1
    staged_config_created=0
    staged_env_created=0
    stage_intent_created=0
    exit 0
fi

# Stage-only exits above. Helper programs and units are service-visible, so they
# are considered only when the operator has explicitly selected promotion.
python3 - "$release_version" "$EMBEDDED_DEPLOY_SHA256" \
    /var/lib/safetun/installer/hub.version \
    /var/lib/safetun/installer/edge.version \
    /var/lib/safetun/installer/shared.version \
    /var/lib/safetun/installer/shared.payload-sha256 <<'PY'
import os
import pathlib
import re
import stat
import sys

pattern = re.compile(r"(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-([0-9A-Za-z.-]+))?")

def parse(value):
    match = pattern.fullmatch(value)
    if not match:
        raise SystemExit(f"invalid installed version marker: {value!r}")
    prerelease = match.group(4)
    identifiers = () if prerelease is None else tuple(prerelease.split("."))
    if any(not item or (item.isdigit() and len(item) > 1 and item.startswith("0")) for item in identifiers):
        raise SystemExit(f"invalid installed version marker: {value!r}")
    return tuple(map(int, match.group(1, 2, 3))), identifiers

def less(left, right):
    left_core, left_pre = parse(left)
    right_core, right_pre = parse(right)
    if left_core != right_core:
        return left_core < right_core
    if not left_pre:
        return False
    if not right_pre:
        return True
    for left_item, right_item in zip(left_pre, right_pre):
        if left_item == right_item:
            continue
        if left_item.isdigit() and right_item.isdigit():
            return int(left_item) < int(right_item)
        if left_item.isdigit() != right_item.isdigit():
            return left_item.isdigit()
        return left_item < right_item
    return len(left_pre) < len(right_pre)

incoming = sys.argv[1]
incoming_payload = sys.argv[2]
parse(incoming)
if not re.fullmatch(r"[0-9a-f]{64}", incoming_payload):
    raise SystemExit("embedded deploy payload digest is invalid")
equal_installed_version = False
for raw_path in sys.argv[3:6]:
    path = pathlib.Path(raw_path)
    if not os.path.lexists(path):
        continue
    information = os.lstat(path)
    if not stat.S_ISREG(information.st_mode) or stat.S_ISLNK(information.st_mode) or information.st_size > 128:
        raise SystemExit(f"unsafe installed version marker: {path}")
    installed = path.read_text(encoding="ascii").strip()
    if less(incoming, installed):
        raise SystemExit(f"release {incoming} cannot replace shared installer assets at newer version {installed}")
    if not less(incoming, installed) and not less(installed, incoming):
        equal_installed_version = True
payload_path = pathlib.Path(sys.argv[6])
if os.path.lexists(payload_path):
    information = os.lstat(payload_path)
    if not stat.S_ISREG(information.st_mode) or stat.S_ISLNK(information.st_mode) or information.st_size > 128:
        raise SystemExit("unsafe shared deploy payload marker")
    installed_payload = payload_path.read_text(encoding="ascii").strip()
    if not re.fullmatch(r"[0-9a-f]{64}", installed_payload):
        raise SystemExit("invalid shared deploy payload marker")
else:
    installed_payload = None
if equal_installed_version and installed_payload != incoming_payload:
    raise SystemExit("same-version shared deploy payload differs or has no durable digest marker")
PY
if command -v systemctl >/dev/null 2>&1 && [ -d /etc/systemd/system ]; then
    systemd_available=1
fi

role_base="/opt/safetun/$ROLE"
old_target=
if [ -L "$role_base/current" ]; then
    old_target=$(readlink "$role_base/current")
    python3 - "$old_target" <<'PY'
import re, sys
match = re.fullmatch(r"versions/(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-([0-9A-Za-z.-]+))?", sys.argv[1])
if not match or (match.group(4) and any(not item or (item.isdigit() and len(item) > 1 and item[0] == "0") for item in match.group(4).split("."))):
    raise SystemExit("existing current link is unsafe")
PY
elif [ -e "$role_base/current" ]; then
    die "existing current path is not a SafeTun release link"
fi
if [ -L "$role_base/previous" ]; then
    old_previous_target=$(readlink "$role_base/previous")
    python3 - "$old_previous_target" <<'PY'
import re, sys
match = re.fullmatch(r"versions/(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-([0-9A-Za-z.-]+))?", sys.argv[1])
if not match or (match.group(4) and any(not item or (item.isdigit() and len(item) > 1 and item[0] == "0") for item in match.group(4).split("."))):
    raise SystemExit("existing previous link is unsafe")
PY
elif [ -e "$role_base/previous" ]; then
    die "existing previous path is not a SafeTun release link"
fi
if [ -L "/usr/local/bin/safetun-$ROLE" ]; then
    [ "$(readlink "/usr/local/bin/safetun-$ROLE")" = "/opt/safetun/$ROLE/current/safetun-$ROLE" ] \
        || die "existing binary link is not installer-owned"
elif [ -e "/usr/local/bin/safetun-$ROLE" ]; then
    die "existing binary path is not an installer-owned symlink"
fi

if [ -e "$config_path" ] || [ -L "$config_path" ]; then
    [ -f "$config_path" ] && [ ! -L "$config_path" ] || die "live config path is unsafe"
    config_had_original=1
    cp -- "$config_path" "$work_dir/original-config"
    backup_dir="/var/lib/safetun/installer/backups/$ROLE-$INSTANCE"
    install -d -m 0700 -o root -g root "$backup_dir"
    backup_path="$backup_dir/$release_version-$$.toml"
    [ ! -e "$backup_path" ] && [ ! -L "$backup_path" ] || die "config backup path already exists"
    install -m 0600 -o root -g root "$config_path" "$backup_path"
fi
if [ -n "$edge_env" ] && { [ -e "$edge_env" ] || [ -L "$edge_env" ]; }; then
    [ -f "$edge_env" ] && [ ! -L "$edge_env" ] || die "live Edge environment path is unsafe"
    edge_env_had_original=1
    cp -- "$edge_env" "$work_dir/original-edge-env"
fi
if [ -e "/var/lib/safetun/installer/$ROLE.version" ] || [ -L "/var/lib/safetun/installer/$ROLE.version" ]; then
    [ -f "/var/lib/safetun/installer/$ROLE.version" ] && [ ! -L "/var/lib/safetun/installer/$ROLE.version" ] || \
    die "version marker path is unsafe"
fi

unit="safetun-$ROLE@$INSTANCE.service"

if [ "$ACTIVATE" -eq 1 ]; then
    [ "$systemd_available" -eq 1 ] || die "--activate requires systemd; the verified binary remains staged"
    if ! "$version_dir/safetun-$ROLE" doctor --config "$candidate_config"; then
        die "candidate doctor failed; live config and current release were not changed"
    fi
    if [ "$ROLE" = hub ]; then
        hub_lease="/etc/safetun/credentials/hub-$INSTANCE/access.lease"
        [ -f "$hub_lease" ] && [ ! -L "$hub_lease" ] || die "Hub lease file is missing or unsafe"
        "$version_dir/safetun-hub" credential verify \
            --config "$candidate_config" --lease-file "$hub_lease" \
            || die "Hub authorization preflight failed; service state was not changed"
    else
        edge_credential="/etc/safetun/credentials/edge-$INSTANCE/pair.credential"
        [ -f "$edge_credential" ] && [ ! -L "$edge_credential" ] || die "Edge pair credential is missing or unsafe"
        python3 - "$candidate_edge_env" "$INSTANCE" "$work_dir/edge-pair-key-path" <<'PY'
import pathlib, re, sys, urllib.parse
source, instance, output = sys.argv[1:]
values = {}
for raw_line in pathlib.Path(source).read_text(encoding="utf-8").splitlines():
    line = raw_line.strip()
    if not line or line.startswith("#"): continue
    if "=" not in line: raise SystemExit("invalid Edge environment line")
    key, value = line.split("=", 1)
    if key in values or key not in {"SAFETUN_ISSUER", "SAFETUN_PAIR_KEY_ID", "SAFETUN_PAIR_KEY_FILE"}:
        raise SystemExit("unknown or duplicate Edge environment key")
    values[key] = value
if set(values) != {"SAFETUN_ISSUER", "SAFETUN_PAIR_KEY_ID", "SAFETUN_PAIR_KEY_FILE"}:
    raise SystemExit("Edge environment is incomplete")
issuer = urllib.parse.urlsplit(values["SAFETUN_ISSUER"])
if issuer.scheme != "https" or not issuer.hostname or issuer.username or issuer.password or issuer.query or issuer.fragment or issuer.hostname.endswith("example.invalid"):
    raise SystemExit("Edge issuer is invalid or still a placeholder")
if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]{0,63}", values["SAFETUN_PAIR_KEY_ID"]):
    raise SystemExit("Edge pair key ID is invalid")
expected_root = pathlib.PurePosixPath(f"/etc/safetun/credentials/edge-{instance}")
key_file = pathlib.PurePosixPath(values["SAFETUN_PAIR_KEY_FILE"])
if key_file.parent != expected_root or key_file.name != values["SAFETUN_PAIR_KEY_ID"] + ".pub":
    raise SystemExit("Edge pair public-key path must be inside the selected credential directory")
pathlib.Path(output).write_text(str(key_file), encoding="utf-8")
PY
        edge_pair_key_path=$(sed -n '1p' "$work_dir/edge-pair-key-path")
        [ -f "$edge_pair_key_path" ] && [ ! -L "$edge_pair_key_path" ] || die "Edge pair verification key is missing or unsafe"
        edge_issuer=$(sed -n 's/^SAFETUN_ISSUER=//p' "$candidate_edge_env")
        edge_pair_key_id=$(sed -n 's/^SAFETUN_PAIR_KEY_ID=//p' "$candidate_edge_env")
        "$version_dir/safetun-edge" credential verify \
            --config "$candidate_config" --credential-file "$edge_credential" \
            --verify-key "$edge_pair_key_id=$edge_pair_key_path" \
            --issuer "$edge_issuer" --audience safetun-hub \
            || die "Edge credential preflight failed; service state was not changed"
    fi
fi

install -d -m 0700 "$work_dir/original-deploy"
for managed_path in /usr/libexec/safetun/install-control /usr/local/sbin/safetun-uninstall; do
    if [ -e "$managed_path" ] || [ -L "$managed_path" ]; then
        [ -f "$managed_path" ] && [ ! -L "$managed_path" ] || die "managed helper path is unsafe: $managed_path"
        [ "$shared_was_owned" -eq 1 ] || die "refusing to overwrite an unmarked helper path: $managed_path"
        cp -- "$managed_path" "$work_dir/original-deploy/${managed_path##*/}"
    fi
done
if [ "$systemd_available" -eq 1 ]; then
    for managed_name in \
        "safetun-$ROLE@.service" \
        "safetun-$ROLE-rollback@.service" \
        safetun-install-recover.service \
        safetun-install-activation-watch.service \
        safetun-install-activation-watch.timer \
        safetun-release-cleanup.service \
        safetun-release-cleanup.timer; do
        managed_path="/etc/systemd/system/$managed_name"
        if [ -e "$managed_path" ] || [ -L "$managed_path" ]; then
            [ -f "$managed_path" ] && [ ! -L "$managed_path" ] || die "managed unit path is unsafe: $managed_path"
            case "$managed_name" in
                safetun-release-cleanup.*|safetun-install-recover.service|safetun-install-activation-watch.*)
                    [ "$shared_was_owned" -eq 1 ] || die "refusing to overwrite an unmarked shared unit: $managed_path"
                    ;;
                *)
                    [ "$role_was_owned" -eq 1 ] || die "refusing to overwrite an unmarked role unit: $managed_path"
                    ;;
            esac
            cp -- "$managed_path" "$work_dir/original-deploy/$managed_name"
        fi
    done
fi

# The controller is forward-only infrastructure and understands the journal
# schema below. Publish it atomically and durably before arming any journal that
# an older installed controller might not be able to recover.
controller_path=/usr/libexec/safetun/install-control
controller_temporary="$controller_path.new.$$"
install -m 0755 -o root -g root "$work_dir/deploy/deploy/install-control.sh" "$controller_temporary"
durable_sync_paths "$controller_temporary"
mv -f "$controller_temporary" "$controller_path"
durable_sync_paths "$controller_path" /usr/libexec/safetun

transaction_armed=1
sh "$work_dir/deploy/deploy/install-control.sh" begin "$ROLE" "$INSTANCE"
install -m 0755 -o root -g root "$work_dir/deploy/deploy/uninstall.sh" /usr/local/sbin/safetun-uninstall
if [ "$systemd_available" -eq 1 ]; then
    for managed_name in \
        "safetun-$ROLE@.service" \
        "safetun-$ROLE-rollback@.service" \
        safetun-install-recover.service \
        safetun-install-activation-watch.service \
        safetun-install-activation-watch.timer \
        safetun-release-cleanup.service \
        safetun-release-cleanup.timer; do
        install -m 0644 -o root -g root "$work_dir/deploy/deploy/systemd/$managed_name" "/etc/systemd/system/$managed_name.new"
        mv -f "/etc/systemd/system/$managed_name.new" "/etc/systemd/system/$managed_name"
    done
    systemctl daemon-reload
    # Enable the boot recovery barrier before any live config or release link
    # changes. Its prior enabled state is part of the durable journal.
    systemctl enable safetun-install-recover.service >/dev/null
fi
install -m 0640 -o root -g "$ROLE_GROUP" "$candidate_config" "$config_path.new.$$"
mv -f "$config_path.new.$$" "$config_path"
if [ -n "$edge_env" ]; then
    install -m 0640 -o root -g "$ROLE_GROUP" "$candidate_edge_env" "$edge_env.new.$$"
    mv -f "$edge_env.new.$$" "$edge_env"
fi
new_target="versions/$release_version"
if [ -n "$old_target" ] && [ "$old_target" != "$new_target" ]; then
    ln -s "$old_target" "$role_base/previous.new.$$"
    mv -Tf "$role_base/previous.new.$$" "$role_base/previous"
fi
ln -s "$new_target" "$role_base/current.new.$$"
mv -Tf "$role_base/current.new.$$" "$role_base/current"
ln -s "/opt/safetun/$ROLE/current/safetun-$ROLE" "/usr/local/bin/safetun-$ROLE.new.$$"
mv -Tf "/usr/local/bin/safetun-$ROLE.new.$$" "/usr/local/bin/safetun-$ROLE"

# Keep the config/environment paired with each switch position. Manual rollback
# validates and restores the previous snapshot before changing release links.
state_dir="/var/lib/safetun/installer/configs/$ROLE-$INSTANCE"
install -d -m 0700 -o root -g root "$state_dir"
if [ -n "$old_target" ] && [ "$old_target" != "$new_target" ]; then
    if [ "$config_had_original" -eq 1 ]; then
        printf '%s\n' "$old_target" > "$state_dir/previous.target.new.$$"
        chmod 0600 "$state_dir/previous.target.new.$$"
        mv -f "$state_dir/previous.target.new.$$" "$state_dir/previous.target"
        install -m 0600 -o root -g root "$work_dir/original-config" "$state_dir/previous.toml.new.$$"
        mv -f "$state_dir/previous.toml.new.$$" "$state_dir/previous.toml"
        if [ "$ROLE" = edge ]; then
            if [ "$edge_env_had_original" -eq 1 ]; then
                install -m 0600 -o root -g root "$work_dir/original-edge-env" "$state_dir/previous.env.new.$$"
                mv -f "$state_dir/previous.env.new.$$" "$state_dir/previous.env"
            else
                rm -f -- "$state_dir/previous.env"
            fi
        fi
    else
        rm -f -- "$state_dir/previous.target" "$state_dir/previous.toml" "$state_dir/previous.env"
    fi
fi
printf '%s\n' "$new_target" > "$state_dir/current.target.new.$$"
chmod 0600 "$state_dir/current.target.new.$$"
mv -f "$state_dir/current.target.new.$$" "$state_dir/current.target"
install -m 0600 -o root -g root "$candidate_config" "$state_dir/current.toml.new.$$"
mv -f "$state_dir/current.toml.new.$$" "$state_dir/current.toml"
if [ "$ROLE" = edge ]; then
    install -m 0600 -o root -g root "$candidate_edge_env" "$state_dir/current.env.new.$$"
    mv -f "$state_dir/current.env.new.$$" "$state_dir/current.env"
fi

printf '%s\n%s\n%s\n' SAFETUN_INSTALLER_OWNED_V1 "$ROLE" "$INSTANCE" > "/var/lib/safetun/installer/$ROLE.owned.new"
chmod 0600 "/var/lib/safetun/installer/$ROLE.owned.new"
mv -f "/var/lib/safetun/installer/$ROLE.owned.new" "/var/lib/safetun/installer/$ROLE.owned"
printf '%s\n' "$release_version" > "/var/lib/safetun/installer/$ROLE.version.new"
chmod 0600 "/var/lib/safetun/installer/$ROLE.version.new"
mv -f "/var/lib/safetun/installer/$ROLE.version.new" "/var/lib/safetun/installer/$ROLE.version"
printf '%s\n' "$release_version" > "/var/lib/safetun/installer/shared.version.new"
chmod 0600 "/var/lib/safetun/installer/shared.version.new"
mv -f "/var/lib/safetun/installer/shared.version.new" "/var/lib/safetun/installer/shared.version"
printf '%s\n' "$EMBEDDED_DEPLOY_SHA256" > "/var/lib/safetun/installer/shared.payload-sha256.new"
chmod 0600 "/var/lib/safetun/installer/shared.payload-sha256.new"
mv -f "/var/lib/safetun/installer/shared.payload-sha256.new" "/var/lib/safetun/installer/shared.payload-sha256"
printf '%s\n%s\n' SAFETUN_SHARED_ASSETS_OWNED_V1 "$release_version" \
    > /var/lib/safetun/installer/shared.owned.new
chmod 0600 /var/lib/safetun/installer/shared.owned.new
mv -f /var/lib/safetun/installer/shared.owned.new /var/lib/safetun/installer/shared.owned
if [ -n "$existing_staged_version" ] && [ "$existing_staged_version" = "$release_version" ]; then
    rm -f -- "/var/lib/safetun/installer/$ROLE.staged"
fi

if [ "$systemd_available" -eq 1 ]; then
    systemctl enable safetun-release-cleanup.timer >/dev/null 2>&1 || true
fi

retain_version=1
if [ "$ACTIVATE" -eq 1 ]; then
    # Make the candidate binary, helpers, units, config, markers, symlinks, and
    # every containing directory durable before publishing its activation
    # capsule or dropping the mutation lock. This is commit's durability
    # barrier without journal deletion.
    sh "$work_dir/deploy/deploy/install-control.sh" prepare "$ROLE" "$INSTANCE"
    activation_values=$(python3 - <<'PY'
import secrets, time
print(secrets.token_hex(32), int(time.time()) + 180)
PY
    ) || die "cannot generate activation transaction identity"
    IFS=' ' read -r activation_generation activation_deadline activation_extra <<EOF
$activation_values
EOF
    [ -n "$activation_generation" ] && [ -n "$activation_deadline" ] && [ -z "$activation_extra" ] \
        || die "invalid activation transaction identity"
    sh "$work_dir/deploy/deploy/install-control.sh" activation-arm \
        "$ROLE" "$INSTANCE" "$activation_generation" "$activation_deadline" >/dev/null
    activation_capsule_armed=1
    systemctl start safetun-install-activation-watch.timer \
        || die "could not arm the activation recovery watchdog"
else
    sh "$work_dir/deploy/deploy/install-control.sh" commit "$ROLE" "$INSTANCE"
    transaction_complete=1
fi

# Role ExecStartPre takes the same stable installer flock. Release it only
# after the durable capsule is armed, then perform the requested trial.
flock -u 9
exec 9>&-
install_lock=
if [ "$ACTIVATE" -eq 1 ]; then
    # Exact generation/hash CAS immediately before enable. Other installers,
    # cleanup, rollback, and uninstall refuse the still-live capsule.
    exec 9<>"$lock_file"
    flock -w 240 9 || die "could not reacquire the installer lock before activation"
    install_lock=$lock_file
    sh "$work_dir/deploy/deploy/install-control.sh" activation-precheck \
        "$ROLE" "$INSTANCE" "$activation_generation"
    flock -u 9
    exec 9>&-
    install_lock=
    if ! systemctl enable "$unit"; then
        die "candidate could not be enabled; the prior state will be restored"
    fi
    if ! systemctl restart "$unit" || ! systemctl is-active --quiet "$unit"; then
        systemctl disable --now "$unit" >/dev/null 2>&1 || true
        die "candidate failed its activation health check; the prior state will be restored"
    fi
    # systemctl restart includes the root ExecStartPre trial barrier. Finalize
    # only while the exact generation and all candidate hashes still match.
    exec 9<>"$lock_file"
    flock -w 240 9 || die "could not reacquire the installer lock after activation"
    install_lock=$lock_file
    sh "$work_dir/deploy/deploy/install-control.sh" activation-finalize \
        "$ROLE" "$INSTANCE" "$activation_generation"
    transaction_complete=1
    activation_capsule_armed=0
    flock -u 9
    exec 9>&-
    install_lock=
    systemctl stop safetun-install-activation-watch.timer >/dev/null 2>&1 || true
fi

printf '%s\n' "Installed SafeTun $ROLE $release_version for $ARCH as instance $INSTANCE."
if [ "$ACTIVATE" -eq 0 ]; then
    printf '%s\n' "The service was not enabled or started. Provision mode-0600 credentials and TLS material, run doctor, then activate explicitly."
fi
