#!/usr/bin/env python3
"""
Deploy runner. Built by deploy/build_ship.py, always arrives as ship.py.

  python3 ship.py             show what would change, write nothing
  python3 ship.py --apply     back up, write, restart, verify, roll back on failure
  python3 ship.py --rollback  put the last deploy back

What it refuses to do:
  run against the wrong site, write a Python file that does not compile,
  write a template whose tags do not balance, or leave a broken site up.
"""

import base64
import datetime
import difflib
import glob
import hashlib
import json
import os
import re
import shutil
import subprocess
import sys

SITE = {
    "user": "hpglobal",
    "base": "/home/hpglobal/public_html/backend",
    "service": "hpglobal",
    "health": "https://hpglobal.uk/",
    "panel": "https://panel.hpglobal.uk/auth/login/",
    "marker": "hpglobal"
}
FILES = {
    "templates/cms/base.html": {
        "b64": "PCFkb2N0eXBlIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCI+CiAgICA8dGl0bGU+eyUgYmxvY2sgdGl0bGUgJX1QYW5lbHslIGVuZGJsb2NrICV9IOKAlCB7JSBmaXJzdG9mIHRlbmFudC5uYW1lIGNvbXBhbnkgJX08L3RpdGxlPgogICAgeyUgbG9hZCBzdGF0aWMgJX0KICAgIHslIGlmIHNpdGUuYXBwbGVfdG91Y2hfaWNvbiAlfQogICAgPGxpbmsgcmVsPSJpY29uIiBocmVmPSJ7eyBzaXRlLmFwcGxlX3RvdWNoX2ljb24udXJsIH19Ij4KICAgIDxsaW5rIHJlbD0iYXBwbGUtdG91Y2gtaWNvbiIgc2l6ZXM9IjE4MHgxODAiIGhyZWY9Int7IHNpdGUuYXBwbGVfdG91Y2hfaWNvbi51cmwgfX0iPgogICAgeyUgZWxpZiB0ZW5hbnQuZmF2aWNvbiAlfQogICAgPGxpbmsgcmVsPSJpY29uIiBocmVmPSJ7eyB0ZW5hbnQuZmF2aWNvbi51cmwgfX0iPgogICAgPGxpbmsgcmVsPSJhcHBsZS10b3VjaC1pY29uIiBzaXplcz0iMTgweDE4MCIgaHJlZj0ie3sgdGVuYW50LmZhdmljb24udXJsIH19Ij4KICAgIHslIGVsaWYgc2l0ZS5mYXZpY29uICV9CiAgICA8bGluayByZWw9Imljb24iIGhyZWY9Int7IHNpdGUuZmF2aWNvbi51cmwgfX0iPgogICAgPGxpbmsgcmVsPSJhcHBsZS10b3VjaC1pY29uIiBzaXplcz0iMTgweDE4MCIgaHJlZj0ie3sgc2l0ZS5mYXZpY29uLnVybCB9fSI+CiAgICB7JSBlbmRpZiAlfQogICAgPG1ldGEgbmFtZT0iYXBwbGUtbW9iaWxlLXdlYi1hcHAtY2FwYWJsZSIgY29udGVudD0ieWVzIj4KICAgIDxtZXRhIG5hbWU9ImFwcGxlLW1vYmlsZS13ZWItYXBwLXN0YXR1cy1iYXItc3R5bGUiIGNvbnRlbnQ9ImJsYWNrLXRyYW5zbHVjZW50Ij4KICAgIDxtZXRhIG5hbWU9ImFwcGxlLW1vYmlsZS13ZWItYXBwLXRpdGxlIiBjb250ZW50PSJ7JSBmaXJzdG9mIHRlbmFudC5uYW1lIGNvbXBhbnkgJX0iPgogICAgPG1ldGEgbmFtZT0ibW9iaWxlLXdlYi1hcHAtY2FwYWJsZSIgY29udGVudD0ieWVzIj4KICAgIDxtZXRhIG5hbWU9InRoZW1lLWNvbG9yIiBjb250ZW50PSJ7eyB0ZW5hbnQuY21zX2RhcmtfY29sb3VyfGRlZmF1bHQ6JyMwMzMxNTInIH19Ij4KICAgIDxtZXRhIG5hbWU9ImZvcm1hdC1kZXRlY3Rpb24iIGNvbnRlbnQ9InRlbGVwaG9uZT1ubyI+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9InslIHN0YXRpYyAnY3NzL2Jvb3RzdHJhcC5taW4uY3NzJyAlfSI+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9InslIHN0YXRpYyAnY3NzL3ZlbmRvci9mb250YXdlc29tZS5jc3MnICV9Ij4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0ieyUgc3RhdGljICdjc3MvdmVuZG9yL3NvbGlkLmNzcycgJX0iPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJ7JSBzdGF0aWMgJ2Nzcy92ZW5kb3IvYnJhbmRzLmNzcycgJX0iPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJ7JSBzdGF0aWMgJ2Nzcy92ZW5kb3IvcmVndWxhci5jc3MnICV9Ij4KICAgIDxzdHlsZT4KICAgICAgICA6cm9vdCB7CiAgICAgICAgICAgIC0tY21zLWFjY2VudDogICB7eyB0ZW5hbnQuYWNjZW50X2NvbG91cnxkZWZhdWx0OiIjZmY0MDRiIiB9fTsKICAgICAgICAgICAgLyogU2lkZWJhciAqLwogICAgICAgICAgICAtLXNiLWJnOiAgICAgICAge3sgdGVuYW50LmNtc19kYXJrX2NvbG91cnxkZWZhdWx0OiIjMDMzMTUyIiB9fTsKICAgICAgICAgICAgLyogVGhlIHRlbmFudCdzIG93biBjb2xvdXIuIFRoaXMgd2FzIHBpbm5lZCB0byBvbmUgYnJhbmQncwogICAgICAgICAgICAgICBvcmFuZ2UtcmVkLCBzbyBldmVyeSBjbGllbnQncyBtZW51IGhpZ2hsaWdodGVkIGFuZCBob3ZlcmVkCiAgICAgICAgICAgICAgIGluIHNvbWVib2R5IGVsc2UncyBjb2xvdXIgd2hpbGUgdGhlaXIgbG9nbyBzYXQgYWJvdmUgaXQuICovCiAgICAgICAgICAgIC0tc2ItYWNjZW50OiAgICB7eyB0ZW5hbnQuYWNjZW50X2NvbG91cnxkZWZhdWx0OiIjZmY0MDRiIiB9fTsKICAgICAgICAgICAgLS1zYi1ob3ZlcjogICAgIHJnYmEoMjU1LDI1NSwyNTUsLjA3KTsKICAgICAgICAgICAgLyogQSB0aW50IG9mIHdoYXRldmVyIHRoZSBhY2NlbnQgaXMuIFdhcyBhIGZpeGVkIHJnYmEgb2Ygb25lCiAgICAgICAgICAgICAgIGJyYW5kJ3MgcmVkLCBzbyBhIGdvbGQgYWNjZW50IHNhdCBvbiBhIHBpbmsgcm93LiAqLwogICAgICAgICAgICAtLXNiLWFjdGl2ZTogICAgcmdiYSgyNTUsMjU1LDI1NSwuMDYpOwogICAgICAgICAgICAtLXNiLWFjdGl2ZTogICAgY29sb3ItbWl4KGluIHNyZ2IsIHZhcigtLXNiLWFjY2VudCkgMTQlLCB0cmFuc3BhcmVudCk7CiAgICAgICAgICAgIC0tc2ItdGV4dDogICAgICB7eyB0ZW5hbnQuY21zX3RleHRfY29sb3VyfGRlZmF1bHQ6IiNiOGQ0ZWEiIH19OwogICAgICAgICAgICAtLXNiLW11dGVkOiAgICAgIzRkN2E5ZTsKICAgICAgICAgICAgLS1zYi1ib3JkZXI6ICAgIHJnYmEoMjU1LDI1NSwyNTUsLjA4KTsKICAgICAgICAgICAgLS1zYi13aWR0aDogICAgIDI1MHB4OwogICAgICAgICAgICAtLXNiLXdpZHRoLW1pbjogNjRweDsKICAgICAgICAgICAgLyogUmlnaHQgc2lkZSAod2hpdGUpICovCiAgICAgICAgICAgIC0tY21zLWJnOiAgICAgICAjZjBmNGY4OwogICAgICAgICAgICAtLWNtcy1jYXJkOiAgICAgI2ZmZmZmZjsKICAgICAgICAgICAgLS1jbXMtYm9yZGVyOiAgICNkY2U2ZWY7CiAgICAgICAgICAgIC0tY21zLXRleHQ6ICAgICAjMWUyZDNkOwogICAgICAgICAgICAtLWNtcy1tdXRlZDogICAgIzVmN2E5NDsKICAgICAgICAgICAgLS1jbXMtZGFuZ2VyOiAgICNkYzI2MjY7CiAgICAgICAgICAgIC0tY21zLXN1Y2Nlc3M6ICAjMTZhMzRhOwogICAgICAgIH0KICAgICAgICAqIHsgYm94LXNpemluZzogYm9yZGVyLWJveDsgfQogICAgICAgIGJvZHkgewogICAgICAgICAgICBiYWNrZ3JvdW5kOiB2YXIoLS1jbXMtYmcpOwogICAgICAgICAgICBjb2xvcjogdmFyKC0tY21zLXRleHQpOwogICAgICAgICAgICBmb250LWZhbWlseTogJ1NlZ29lIFVJJywgc3lzdGVtLXVpLCBzYW5zLXNlcmlmOwogICAgICAgICAgICBtYXJnaW46IDA7CiAgICAgICAgfQogICAgICAgIGEgeyBjb2xvcjogdmFyKC0tY21zLWFjY2VudCk7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgfQogICAgICAgIGE6aG92ZXIgeyBvcGFjaXR5OiAuODsgfQoKICAgICAgICAvKiDilIDilIAgU2lkZWJhciBzaGVsbCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8KICAgICAgICAuY21zLXNpZGViYXIgewogICAgICAgICAgICBwb3NpdGlvbjogZml4ZWQ7IHRvcDogMDsgbGVmdDogMDsKICAgICAgICAgICAgd2lkdGg6IHZhcigtLXNiLXdpZHRoKTsgaGVpZ2h0OiAxMDB2aDsgaGVpZ2h0OiAxMDBkdmg7CiAgICAgICAgICAgIGJhY2tncm91bmQ6IHZhcigtLXNiLWJnKTsKICAgICAgICAgICAgZGlzcGxheTogZmxleDsgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICAgICAgICAgICAgei1pbmRleDogMTAwMDsKICAgICAgICAgICAgdHJhbnNpdGlvbjogd2lkdGggLjI1cyBlYXNlOwogICAgICAgICAgICBvdmVyZmxvdzogaGlkZGVuOwogICAgICAgIH0KICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIHsgd2lkdGg6IHZhcigtLXNiLXdpZHRoLW1pbik7IH0KCiAgICAgICAgLyog4pSA4pSAIEJyYW5kIHJvdyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8KICAgICAgICAuc2lkZWJhci1icmFuZCB7CiAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGdhcDogLjc1cmVtOwogICAgICAgICAgICBwYWRkaW5nOiAxLjJyZW0gMS4xcmVtOwogICAgICAgICAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgdmFyKC0tc2ItYm9yZGVyKTsKICAgICAgICAgICAgZmxleC1zaHJpbms6IDA7CiAgICAgICAgICAgIG1pbi1oZWlnaHQ6IDY0cHg7CiAgICAgICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTsKICAgICAgICB9CiAgICAgICAgLyogVGhlIHRlbmFudCdzIG93biBmYXZpY29uLCBwYWludGVkIHdoaXRlIHNvIGl0IHJlYWRzIG9uIHRoZSBkYXJrCiAgICAgICAgICAgc2lkZWJhciB3aGF0ZXZlciBjb2xvdXJzIHRoZSBicmFuZCB1c2VzLiBBIG1hc2sga2VlcHMgb25seSB0aGUKICAgICAgICAgICBpbWFnZSdzIHNoYXBlIGFuZCBkaXNjYXJkcyBpdHMgY29sb3Vycy4KICAgICAgICAgICBUaGlzIGxvb2tlZCBicm9rZW4gZm9yIGEgd2hpbGUgYW5kIGl0IHdhcyBub3QgdGhlIG1hc2s6IHVwbG9hZHMKICAgICAgICAgICB3ZXJlIGJlaW5nIGZsYXR0ZW5lZCBvbnRvIGEgd2hpdGUgc3F1YXJlIGJlZm9yZSBzYXZpbmcsIHNvIHRoZXJlCiAgICAgICAgICAgd2FzIG5vIHRyYW5zcGFyZW5jeSBsZWZ0IHRvIG1hc2sgYWdhaW5zdCBhbmQgdGhlIHJlc3VsdCB3YXMgYSBzb2xpZAogICAgICAgICAgIGJsb2NrLiBGaXhlZCBpbiBfY29udmVydF90b193ZWJwLiBBIGZhdmljb24gdXBsb2FkZWQgYmVmb3JlIHRoYXQKICAgICAgICAgICBmaXggc3RpbGwgaGFzIG5vIGFscGhhIGFuZCBtdXN0IGJlIHVwbG9hZGVkIGFnYWluLiAqLwogICAgICAgIC5icmFuZC1tYXJrIHsKICAgICAgICAgICAgd2lkdGg6IDM0cHg7IGhlaWdodDogMzRweDsgZmxleC1zaHJpbms6IDA7CiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6ICNmZmY7CiAgICAgICAgICAgIC13ZWJraXQtbWFzay1yZXBlYXQ6IG5vLXJlcGVhdDsgbWFzay1yZXBlYXQ6IG5vLXJlcGVhdDsKICAgICAgICAgICAgLXdlYmtpdC1tYXNrLXBvc2l0aW9uOiBjZW50ZXI7ICBtYXNrLXBvc2l0aW9uOiBjZW50ZXI7CiAgICAgICAgICAgIC13ZWJraXQtbWFzay1zaXplOiBjb250YWluOyAgICAgbWFzay1zaXplOiBjb250YWluOwogICAgICAgIH0KICAgICAgICAuYnJhbmQtaW5pdGlhbHMgewogICAgICAgICAgICB3aWR0aDogMzRweDsgaGVpZ2h0OiAzNHB4OyBib3JkZXItcmFkaXVzOiA4cHg7CiAgICAgICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWNtcy1hY2NlbnQpOyBjb2xvcjogIzAwMDsKICAgICAgICAgICAgZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IGNlbnRlcjsganVzdGlmeS1jb250ZW50OiBjZW50ZXI7CiAgICAgICAgICAgIGZvbnQtd2VpZ2h0OiA4MDA7IGZvbnQtc2l6ZTogLjhyZW07IGZsZXgtc2hyaW5rOiAwOwogICAgICAgIH0KICAgICAgICAuYnJhbmQtaG9tZSB7CiAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGdhcDogLjc1cmVtOwogICAgICAgICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7IGNvbG9yOiBpbmhlcml0OyBtaW4td2lkdGg6IDA7IGZsZXg6IDE7CiAgICAgICAgfQogICAgICAgIC5icmFuZC1ob21lOmhvdmVyIHsgb3BhY2l0eTogLjg1OyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IH0KICAgICAgICAuYnJhbmQtbG9nbyB7IGhlaWdodDogMzJweDsgd2lkdGg6IGF1dG87IGJvcmRlci1yYWRpdXM6IDA7IGZsZXgtc2hyaW5rOiAwOyBvYmplY3QtZml0OiBjb250YWluOyB9CiAgICAgICAgLmJyYW5kLXRleHQgeyBvdmVyZmxvdzogaGlkZGVuOyB3aGl0ZS1zcGFjZTogbm93cmFwOyB0cmFuc2l0aW9uOiBvcGFjaXR5IC4yczsgfQogICAgICAgIC5icmFuZC1uYW1lIHsgZm9udC13ZWlnaHQ6IDcwMDsgZm9udC1zaXplOiAuOXJlbTsgY29sb3I6ICNmZmY7IGxpbmUtaGVpZ2h0OiAxLjI7IH0KICAgICAgICAuYnJhbmQtc3ViICB7IGZvbnQtc2l6ZTogLjZyZW07IGNvbG9yOiB2YXIoLS1zYi1tdXRlZCk7IGxldHRlci1zcGFjaW5nOiAuMDhlbTsgfQoKICAgICAgICAvKiBUb2dnbGUgYnV0dG9uIOKAlCBzaXRzIGF0IHRoZSByaWdodCBvZiB0aGUgYnJhbmQgcm93ICovCiAgICAgICAgLnNpZGViYXItdG9nZ2xlIHsKICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlOyByaWdodDogLjc1cmVtOyB0b3A6IDUwJTsgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKC01MCUpOwogICAgICAgICAgICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwyNTUsMjU1LC4wOCk7IGJvcmRlcjogbm9uZTsKICAgICAgICAgICAgY29sb3I6IHZhcigtLXNiLW11dGVkKTsgd2lkdGg6IDI2cHg7IGhlaWdodDogMjZweDsgYm9yZGVyLXJhZGl1czogNnB4OwogICAgICAgICAgICBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGp1c3RpZnktY29udGVudDogY2VudGVyOwogICAgICAgICAgICBmb250LXNpemU6IC43cmVtOyB0cmFuc2l0aW9uOiBjb2xvciAuMTVzLCBiYWNrZ3JvdW5kIC4xNXMsIG9wYWNpdHkgLjJzOwogICAgICAgICAgICBmbGV4LXNocmluazogMDsKICAgICAgICB9CiAgICAgICAgLyogU2FtZSBwYWlyIGFzIHRoZSBzaWduIG91dCBjb250cm9sIGF0IHRoZSBib3R0b20gb2YgdGhlIHNpZGViYXIsIHNvCiAgICAgICAgICAgdGhlIHR3byBjaHJvbWUgYnV0dG9ucyBiZWhhdmUgaWRlbnRpY2FsbHkuICovCiAgICAgICAgLnNpZGViYXItdG9nZ2xlOmhvdmVyIHsgY29sb3I6IHZhcigtLXNiLWFjY2VudCk7IGJhY2tncm91bmQ6IHZhcigtLXNiLWhvdmVyKTsgfQoKICAgICAgICAvKiBXaGVuIG1pbmltaXplZDogaGlkZSB0ZXh0ICsgbG9nbywgc2hvdyBvbmx5IHRvZ2dsZSBhcnJvdyAqLwogICAgICAgIC5jbXMtc2lkZWJhci5taW5pbWl6ZWQgLmJyYW5kLXRleHQgICAgIHsgb3BhY2l0eTogMDsgd2lkdGg6IDA7IG92ZXJmbG93OiBoaWRkZW47IH0KICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5icmFuZC1pbml0aWFscyB7IGRpc3BsYXk6IG5vbmU7IH0KICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5icmFuZC1sb2dvICAgICB7IGRpc3BsYXk6IG5vbmU7IH0KICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5icmFuZC1tYXJrICAgICB7IGRpc3BsYXk6IG5vbmU7IH0KICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5zaWRlYmFyLXRvZ2dsZSB7IHJpZ2h0OiA1MCU7IHRyYW5zZm9ybTogdHJhbnNsYXRlKDUwJSwgLTUwJSk7IH0KICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5zaWRlYmFyLWJyYW5kICB7IGp1c3RpZnktY29udGVudDogY2VudGVyOyBwYWRkaW5nOiAxLjJyZW0gMDsgfQoKICAgICAgICAvKiDilIDilIAgTmF2IHNjcm9sbCBhcmVhIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCAqLwogICAgICAgIC5zaWRlYmFyLW5hdi13cmFwIHsKICAgICAgICAgICAgZmxleDogMTsgb3ZlcmZsb3cteTogYXV0bzsgb3ZlcmZsb3cteDogaGlkZGVuOwogICAgICAgICAgICBwYWRkaW5nOiAuNXJlbSAwOwogICAgICAgIH0KICAgICAgICAuc2lkZWJhci1uYXYtd3JhcDo6LXdlYmtpdC1zY3JvbGxiYXIgeyB3aWR0aDogNHB4OyB9CiAgICAgICAgLnNpZGViYXItbmF2LXdyYXA6Oi13ZWJraXQtc2Nyb2xsYmFyLXRodW1iIHsgYmFja2dyb3VuZDogdmFyKC0tc2ItYm9yZGVyKTsgYm9yZGVyLXJhZGl1czogNHB4OyB9CgogICAgICAgIC5uYXYtc2VjdGlvbiB7CiAgICAgICAgICAgIHBhZGRpbmc6IC42cmVtIDEuMXJlbSAuMnJlbTsKICAgICAgICAgICAgZm9udC1zaXplOiAuNnJlbTsgZm9udC13ZWlnaHQ6IDcwMDsKICAgICAgICAgICAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTsgbGV0dGVyLXNwYWNpbmc6IC4xNGVtOwogICAgICAgICAgICBjb2xvcjogdmFyKC0tc2ItbXV0ZWQpOwogICAgICAgICAgICB3aGl0ZS1zcGFjZTogbm93cmFwOwogICAgICAgICAgICBvdmVyZmxvdzogaGlkZGVuOwogICAgICAgICAgICB0cmFuc2l0aW9uOiBvcGFjaXR5IC4yczsKICAgICAgICB9CiAgICAgICAgLmNtcy1zaWRlYmFyLm1pbmltaXplZCAubmF2LXNlY3Rpb24geyBvcGFjaXR5OiAwOyBoZWlnaHQ6IDA7IHBhZGRpbmc6IDA7IH0KCiAgICAgICAgLnNpZGViYXItbmF2LXdyYXAgYSB7CiAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGdhcDogLjdyZW07CiAgICAgICAgICAgIHBhZGRpbmc6IC41MnJlbSAxLjFyZW07CiAgICAgICAgICAgIGNvbG9yOiB2YXIoLS1zYi10ZXh0KTsgZm9udC1zaXplOiAuODQ1cmVtOwogICAgICAgICAgICBib3JkZXItbGVmdDogM3B4IHNvbGlkIHRyYW5zcGFyZW50OwogICAgICAgICAgICB0cmFuc2l0aW9uOiBhbGwgLjJzOyB3aGl0ZS1zcGFjZTogbm93cmFwOyBvdmVyZmxvdzogaGlkZGVuOwogICAgICAgIH0KICAgICAgICAuc2lkZWJhci1uYXYtd3JhcCBhIGkubmF2LWljb24gewogICAgICAgICAgICB3aWR0aDogMThweDsgdGV4dC1hbGlnbjogY2VudGVyOyBmbGV4LXNocmluazogMDsgZm9udC1zaXplOiAuOTVyZW07CiAgICAgICAgICAgIHRyYW5zaXRpb246IGNvbG9yIC4ycywgZmlsdGVyIC4yczsKICAgICAgICB9CiAgICAgICAgLyogSG92ZXIgZ29lcyB0byB0aGUgYWNjZW50LCBub3QgdG8gd2hpdGUuIFdpdGggdGhlIHNpZGViYXIgdGV4dCBzZXQgdG8KICAgICAgICAgICB3aGl0ZSwgYSB3aGl0ZSBob3ZlciB3YXMgaW52aXNpYmxlOiB0aGUgb25seSB0aGluZyB0aGF0IG1vdmVkIHdhcwogICAgICAgICAgIHRoZSBpY29uLiAqLwogICAgICAgIC5zaWRlYmFyLW5hdi13cmFwIGE6aG92ZXIgewogICAgICAgICAgICBiYWNrZ3JvdW5kOiB2YXIoLS1zYi1ob3Zlcik7IGNvbG9yOiB2YXIoLS1zYi1hY2NlbnQpOyBvcGFjaXR5OiAxOwogICAgICAgICAgICBib3JkZXItbGVmdC1jb2xvcjogdmFyKC0tc2ItYWNjZW50KTsKICAgICAgICB9CiAgICAgICAgLnNpZGViYXItbmF2LXdyYXAgYTpob3ZlciBpLm5hdi1pY29uIHsKICAgICAgICAgICAgY29sb3I6IHZhcigtLXNiLWFjY2VudCk7CiAgICAgICAgfQogICAgICAgIC8qIEFjdGl2ZTogb3JhbmdlLXJlZCBib3JkZXIgKyBnbG93aW5nIGljb24gKyBib2xkIHdoaXRlIHRleHQgKi8KICAgICAgICAuc2lkZWJhci1uYXYtd3JhcCBhLmFjdGl2ZSB7CiAgICAgICAgICAgIGJhY2tncm91bmQ6IHZhcigtLXNiLWFjdGl2ZSk7CiAgICAgICAgICAgIGJvcmRlci1sZWZ0LWNvbG9yOiB2YXIoLS1zYi1hY2NlbnQpOwogICAgICAgICAgICBjb2xvcjogI2ZmZjsKICAgICAgICAgICAgZm9udC13ZWlnaHQ6IDcwMDsKICAgICAgICB9CiAgICAgICAgLnNpZGViYXItbmF2LXdyYXAgYS5hY3RpdmUgaS5uYXYtaWNvbiB7CiAgICAgICAgICAgIGNvbG9yOiB2YXIoLS1zYi1hY2NlbnQpOwogICAgICAgICAgICAvKiBjdXJyZW50Q29sb3IgcmF0aGVyIHRoYW4gYSBmaXhlZCByZ2JhLCBzbyB0aGUgZ2xvdyBmb2xsb3dzIHRoZQogICAgICAgICAgICAgICBhY2NlbnQgaW5zdGVhZCBvZiBzdGF5aW5nIG9yYW5nZS1yZWQgdW5kZXIgYSBnb2xkIGljb24uICovCiAgICAgICAgICAgIGZpbHRlcjogZHJvcC1zaGFkb3coMCAwIDVweCBjdXJyZW50Q29sb3IpOwogICAgICAgIH0KICAgICAgICAubmF2LXRleHQgeyB0cmFuc2l0aW9uOiBvcGFjaXR5IC4yczsgfQogICAgICAgIC5jbXMtc2lkZWJhci5taW5pbWl6ZWQgLm5hdi10ZXh0IHsgb3BhY2l0eTogMDsgd2lkdGg6IDA7IG92ZXJmbG93OiBoaWRkZW47IH0KICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5zaWRlYmFyLW5hdi13cmFwIGEgewogICAgICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjsKICAgICAgICAgICAgcGFkZGluZzogLjZyZW0gMDsKICAgICAgICB9CgogICAgICAgIC8qIFRvb2x0aXAgb24gbWluaW1pemVkIGljb25zICovCiAgICAgICAgLnNpZGViYXItbmF2LXdyYXAgYSB7IHBvc2l0aW9uOiByZWxhdGl2ZTsgfQogICAgICAgIC5jbXMtc2lkZWJhci5taW5pbWl6ZWQgLnNpZGViYXItbmF2LXdyYXAgYTo6YWZ0ZXIgewogICAgICAgICAgICBjb250ZW50OiBhdHRyKGRhdGEtbGFiZWwpOwogICAgICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7IGxlZnQ6IGNhbGModmFyKC0tc2Itd2lkdGgtbWluKSAtIDRweCk7CiAgICAgICAgICAgIGJhY2tncm91bmQ6ICMxZTJkM2Q7IGNvbG9yOiAjZmZmOwogICAgICAgICAgICBwYWRkaW5nOiAuM3JlbSAuNjVyZW07IGJvcmRlci1yYWRpdXM6IDZweDsKICAgICAgICAgICAgZm9udC1zaXplOiAuNzhyZW07IHdoaXRlLXNwYWNlOiBub3dyYXA7CiAgICAgICAgICAgIHBvaW50ZXItZXZlbnRzOiBub25lOyBvcGFjaXR5OiAwOwogICAgICAgICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTRweCk7CiAgICAgICAgICAgIHRyYW5zaXRpb246IG9wYWNpdHkgLjE1cywgdHJhbnNmb3JtIC4xNXM7CiAgICAgICAgICAgIHotaW5kZXg6IDIwMDA7CiAgICAgICAgfQogICAgICAgIC5jbXMtc2lkZWJhci5taW5pbWl6ZWQgLnNpZGViYXItbmF2LXdyYXAgYTpob3Zlcjo6YWZ0ZXIgewogICAgICAgICAgICBvcGFjaXR5OiAxOyB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoMCk7CiAgICAgICAgfQoKICAgICAgICAvKiBCYWRnZSBpbnNpZGUgbmF2IChlLmcuIHRpY2tldCBjb3VudCkgKi8KICAgICAgICAubmF2LWJhZGdlIHsKICAgICAgICAgICAgbWFyZ2luLWxlZnQ6IGF1dG87IGJhY2tncm91bmQ6IHZhcigtLWNtcy1hY2NlbnQpOyBjb2xvcjogIzAwMDsKICAgICAgICAgICAgZm9udC1zaXplOiAuNnJlbTsgZm9udC13ZWlnaHQ6IDcwMDsKICAgICAgICAgICAgcGFkZGluZzogLjFyZW0gLjQ1cmVtOyBib3JkZXItcmFkaXVzOiAyMHB4OwogICAgICAgICAgICBmbGV4LXNocmluazogMDsKICAgICAgICB9CiAgICAgICAgLmNtcy1zaWRlYmFyLm1pbmltaXplZCAubmF2LWJhZGdlIHsgZGlzcGxheTogbm9uZTsgfQogICAgICAgIC8qIFN0YXR1cyBkb3RzIGFyZSBtZWFuaW5nbGVzcyB3aXRob3V0IHRoZWlyIGxhYmVsLCBhbmQgdGhleQogICAgICAgICAgIHB1c2ggdGhlIGljb24gb2ZmIGNlbnRyZSBpbiB0aGUgY29sbGFwc2VkIHJhaWwuICovCiAgICAgICAgLmNtcy1zaWRlYmFyLm1pbmltaXplZCAubmF2LWRvdCB7IGRpc3BsYXk6IG5vbmU7IH0KCiAgICAgICAgLyog4pSA4pSAIFNpZGViYXIgZm9vdGVyIChjb3B5cmlnaHQpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCAqLwogICAgICAgIC5zaWRlYmFyLWZvb3RlciB7CiAgICAgICAgICAgIGZsZXgtc2hyaW5rOiAwOwogICAgICAgICAgICBib3JkZXItdG9wOiAxcHggc29saWQgdmFyKC0tc2ItYm9yZGVyKTsKICAgICAgICAgICAgcGFkZGluZzogLjg1cmVtIDEuMXJlbTsKICAgICAgICB9CiAgICAgICAgLnNpZGViYXItY29weXJpZ2h0IHsKICAgICAgICAgICAgZm9udC1zaXplOiAuNjVyZW07IGNvbG9yOiB2YXIoLS1zYi1tdXRlZCk7CiAgICAgICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjsgd2hpdGUtc3BhY2U6IG5vd3JhcDsgb3ZlcmZsb3c6IGhpZGRlbjsKICAgICAgICB9CiAgICAgICAgLmNtcy1zaWRlYmFyLm1pbmltaXplZCAuc2lkZWJhci1jb3B5cmlnaHQgeyBmb250LXNpemU6IC41NXJlbTsgfQoKICAgICAgICAvKiBVc2VyIGluZm8gcm93IGFib3ZlIGNvcHlyaWdodCAqLwogICAgICAgIC5zaWRlYmFyLXVzZXIgewogICAgICAgICAgICBkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyBnYXA6IC42cmVtOwogICAgICAgICAgICBtYXJnaW4tYm90dG9tOiAuNjVyZW07IG92ZXJmbG93OiBoaWRkZW47CiAgICAgICAgfQogICAgICAgIC5zaWRlYmFyLXVzZXItYXZhdGFyIHsKICAgICAgICAgICAgd2lkdGg6IDI4cHg7IGhlaWdodDogMjhweDsgYm9yZGVyLXJhZGl1czogNTAlOwogICAgICAgICAgICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwyNTUsMjU1LC4xNSk7IGNvbG9yOiAjZmZmOwogICAgICAgICAgICBkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjsKICAgICAgICAgICAgZm9udC1zaXplOiAuN3JlbTsgZm9udC13ZWlnaHQ6IDcwMDsgZmxleC1zaHJpbms6IDA7CiAgICAgICAgfQogICAgICAgIC5zaWRlYmFyLXVzZXItaW5mbyB7IG92ZXJmbG93OiBoaWRkZW47IGZsZXg6IDE7IH0KICAgICAgICAuc2lkZWJhci11c2VyLW5hbWUgeyBmb250LXNpemU6IC43OHJlbTsgY29sb3I6ICNmZmY7IHdoaXRlLXNwYWNlOiBub3dyYXA7IG92ZXJmbG93OiBoaWRkZW47IHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzOyB9CiAgICAgICAgLnNpZGViYXItdXNlci1yb2xlIHsgZm9udC1zaXplOiAuNnJlbTsgY29sb3I6IHZhcigtLXNiLW11dGVkKTsgfQogICAgICAgIC5jbXMtc2lkZWJhci5taW5pbWl6ZWQgLnNpZGViYXItdXNlci1pbmZvIHsgZGlzcGxheTogbm9uZTsgfQogICAgICAgIC5zaWRlYmFyLWxvZ291dC1idG4gewogICAgICAgICAgICAvKiBTYW1lIGJveCBhcyAuc2lkZWJhci10b2dnbGUgYWJvdmU6IDI2cHggc3F1YXJlLCA2cHggY29ybmVycy4KICAgICAgICAgICAgICAgSXQgd2FzIGEgY2lyY2xlLCB3aGljaCBtYWRlIHRoZSB0d28gY2hyb21lIGJ1dHRvbnMgb24gdGhlCiAgICAgICAgICAgICAgIHNpZGViYXIgZGlmZmVyZW50IHNoYXBlcyBmb3Igbm8gcmVhc29uLiAqLwogICAgICAgICAgICB3aWR0aDogMjZweDsgaGVpZ2h0OiAyNnB4OyBib3JkZXItcmFkaXVzOiA2cHg7CiAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGp1c3RpZnktY29udGVudDogY2VudGVyOwogICAgICAgICAgICBjb2xvcjogdmFyKC0tc2ItbXV0ZWQpOyBmb250LXNpemU6IC44cmVtOyBmbGV4LXNocmluazogMDsKICAgICAgICAgICAgdHJhbnNpdGlvbjogY29sb3IgLjE1cywgYmFja2dyb3VuZCAuMTVzOwogICAgICAgICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7CiAgICAgICAgfQogICAgICAgIC8qIEhvdmVycyB0byB0aGUgdGVuYW50IGFjY2VudCwgbWF0Y2hpbmcgdGhlIG5hdiBpdGVtcyBhYm92ZSBpdCwgc28gdGhlCiAgICAgICAgICAgc2lkZWJhciBoYXMgb25lIGhvdmVyIGNvbG91ciByYXRoZXIgdGhhbiBhIHJlZCBleGNlcHRpb24gYXQgdGhlCiAgICAgICAgICAgYm90dG9tLiBUaGUgYmFja2dyb3VuZCBpcyB0aGUgc2FtZSB0cmFuc2x1Y2VudCB3YXNoIHRoZSBuYXYgdXNlcy4gKi8KICAgICAgICAuc2lkZWJhci1sb2dvdXQtYnRuOmhvdmVyIHsgY29sb3I6IHZhcigtLXNiLWFjY2VudCk7IGJhY2tncm91bmQ6IHZhcigtLXNiLWhvdmVyKTsgfQoKICAgICAgICAvKiDilIDilIAgTWFpbiBjb250ZW50IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCAqLwogICAgICAgIC5jbXMtbWFpbiB7CiAgICAgICAgICAgIG1hcmdpbi1sZWZ0OiB2YXIoLS1zYi13aWR0aCk7CiAgICAgICAgICAgIG1pbi1oZWlnaHQ6IDEwMHZoOwogICAgICAgICAgICBtaW4taGVpZ2h0OiAxMDBkdmg7CiAgICAgICAgICAgIHRyYW5zaXRpb246IG1hcmdpbi1sZWZ0IC4yNXMgZWFzZTsKICAgICAgICB9CiAgICAgICAgLmNtcy1tYWluLnNpZGViYXItbWluaW1pemVkIHsgbWFyZ2luLWxlZnQ6IHZhcigtLXNiLXdpZHRoLW1pbik7IH0KICAgICAgICAuY21zLWNvbnRlbnQgeyBwYWRkaW5nOiAxLjc1cmVtIDJyZW07IH0KCiAgICAgICAgLyog4pSA4pSAIFZpZXcgTGl2ZSBTaXRlIGJ1dHRvbiAoZGFzaGJvYXJkIGhlYWRlcikg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAICovCiAgICAgICAgLmJ0bi1jbXMtc2l0ZSB7CiAgICAgICAgICAgIGJhY2tncm91bmQ6ICMwMzMxNTI7IGNvbG9yOiAjZmZmOwogICAgICAgICAgICBib3JkZXI6IG5vbmU7IHBhZGRpbmc6IC40NXJlbSAxcmVtOyBib3JkZXItcmFkaXVzOiA3cHg7CiAgICAgICAgICAgIGZvbnQtc2l6ZTogLjgycmVtOyBmb250LXdlaWdodDogNjAwOwogICAgICAgICAgICBkaXNwbGF5OiBpbmxpbmUtZmxleDsgYWxpZ24taXRlbXM6IGNlbnRlcjsgZ2FwOiAuNHJlbTsKICAgICAgICAgICAgdHJhbnNpdGlvbjogb3BhY2l0eSAuMTVzOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7CiAgICAgICAgfQogICAgICAgIC5idG4tY21zLXNpdGU6aG92ZXIgeyBvcGFjaXR5OiAuODI7IGNvbG9yOiAjZmZmOyB9CgogICAgICAgIC8qIOKUgOKUgCBDYXJkcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8KICAgICAgICAuY21zLWNhcmQgewogICAgICAgICAgICBiYWNrZ3JvdW5kOiB2YXIoLS1jbXMtY2FyZCk7CiAgICAgICAgICAgIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWNtcy1ib3JkZXIpOwogICAgICAgICAgICBib3JkZXItcmFkaXVzOiAxMHB4OyBwYWRkaW5nOiAxLjI1cmVtOwogICAgICAgICAgICBib3gtc2hhZG93OiAwIDFweCAzcHggcmdiYSgwLDAsMCwuMDQpOwogICAgICAgIH0KICAgICAgICAuY21zLWNhcmQgaDUgewogICAgICAgICAgICBjb2xvcjogdmFyKC0tY21zLW11dGVkKTsgZm9udC1zaXplOiAuNzJyZW07CiAgICAgICAgICAgIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7IGxldHRlci1zcGFjaW5nOiAuMWVtOyBtYXJnaW4tYm90dG9tOiAuNXJlbTsKICAgICAgICB9CiAgICAgICAgLmNtcy1jYXJkIC5iaWctbnVtYmVyIHsgZm9udC1zaXplOiAyLjJyZW07IGZvbnQtd2VpZ2h0OiA3MDA7IGNvbG9yOiB2YXIoLS1jbXMtYWNjZW50KTsgbGluZS1oZWlnaHQ6IDE7IH0KCiAgICAgICAgLyog4pSA4pSAIFRhYmxlcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8KICAgICAgICAuY21zLXRhYmxlIHsgd2lkdGg6IDEwMCU7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7IH0KICAgICAgICAuY21zLXRhYmxlIHRoIHsKICAgICAgICAgICAgcGFkZGluZzogLjZyZW0gMXJlbTsKICAgICAgICAgICAgYmFja2dyb3VuZDogI2Y3ZmFmYzsKICAgICAgICAgICAgY29sb3I6IHZhcigtLWNtcy1tdXRlZCk7IGZvbnQtc2l6ZTogLjcycmVtOwogICAgICAgICAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlOyBsZXR0ZXItc3BhY2luZzogLjA4ZW07CiAgICAgICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjsgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIHZhcigtLWNtcy1ib3JkZXIpOwogICAgICAgIH0KICAgICAgICAuY21zLXRhYmxlIHRkIHsKICAgICAgICAgICAgcGFkZGluZzogLjc1cmVtIDFyZW07CiAgICAgICAgICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCB2YXIoLS1jbXMtYm9yZGVyKTsKICAgICAgICAgICAgZm9udC1zaXplOiAuODc1cmVtOyB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlOwogICAgICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgICAgICAgfQogICAgICAgIC8qIE1haW4gbmFtZS90aXRsZSBjb2x1bW4gKDJuZCBjb2wsIGFmdGVyIHRoZSByb3cgIyBjb3VudGVyKSBzdGF5cyBsZWZ0ICovCiAgICAgICAgLmNtcy10YWJsZSB0aDpudGgtY2hpbGQoMiksCiAgICAgICAgLmNtcy10YWJsZSB0ZDpudGgtY2hpbGQoMikgeyB0ZXh0LWFsaWduOiBsZWZ0OyB9CiAgICAgICAgLmNtcy10YWJsZSB0cjpsYXN0LWNoaWxkIHRkIHsgYm9yZGVyLWJvdHRvbTogbm9uZTsgfQogICAgICAgIC5jbXMtdGFibGUgdHI6aG92ZXIgdGQgeyBiYWNrZ3JvdW5kOiAjZmFmY2ZmOyB9CgogICAgICAgIC8qIOKUgOKUgCBCYWRnZXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAICovCiAgICAgICAgLmJhZGdlLW5ldyAgICAgIHsgYmFja2dyb3VuZDogI2VmZjZmZjsgY29sb3I6ICMyNTYzZWI7IGJvcmRlcjogMXB4IHNvbGlkICNiZmRiZmU7IHBhZGRpbmc6IC4ycmVtIC42cmVtOyBib3JkZXItcmFkaXVzOiAyMHB4OyBmb250LXNpemU6IC43cmVtOyBmb250LXdlaWdodDogNjAwOyB9CiAgICAgICAgLmJhZGdlLW9wZW4gICAgIHsgYmFja2dyb3VuZDogI2ZmZjdlZDsgY29sb3I6ICNjMjQxMGM7IGJvcmRlcjogMXB4IHNvbGlkICNmZWQ3YWE7IHBhZGRpbmc6IC4ycmVtIC42cmVtOyBib3JkZXItcmFkaXVzOiAyMHB4OyBmb250LXNpemU6IC43cmVtOyBmb250LXdlaWdodDogNjAwOyB9CiAgICAgICAgLmJhZGdlLXJlc29sdmVkIHsgYmFja2dyb3VuZDogI2YwZmRmNDsgY29sb3I6ICMxNTgwM2Q7IGJvcmRlcjogMXB4IHNvbGlkICNiYmY3ZDA7IHBhZGRpbmc6IC4ycmVtIC42cmVtOyBib3JkZXItcmFkaXVzOiAyMHB4OyBmb250LXNpemU6IC43cmVtOyBmb250LXdlaWdodDogNjAwOyB9CiAgICAgICAgLmJhZGdlLWluX3Byb2dyZXNzIHsgYmFja2dyb3VuZDogI2ZhZjVmZjsgY29sb3I6ICM3YzNhZWQ7IGJvcmRlcjogMXB4IHNvbGlkICNkZGQ2ZmU7IHBhZGRpbmc6IC4ycmVtIC42cmVtOyBib3JkZXItcmFkaXVzOiAyMHB4OyBmb250LXNpemU6IC43cmVtOyBmb250LXdlaWdodDogNjAwOyB9CiAgICAgICAgLmJhZGdlLWNsb3NlZCAgIHsgYmFja2dyb3VuZDogI2Y4ZmFmYzsgY29sb3I6IHZhcigtLWNtcy1tdXRlZCk7IGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWNtcy1ib3JkZXIpOyBwYWRkaW5nOiAuMnJlbSAuNnJlbTsgYm9yZGVyLXJhZGl1czogMjBweDsgZm9udC1zaXplOiAuN3JlbTsgfQogICAgICAgIC5iYWRnZS1zb3VyY2UgICB7IGJhY2tncm91bmQ6ICNmMWY1Zjk7IGNvbG9yOiB2YXIoLS1jbXMtbXV0ZWQpOyBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1jbXMtYm9yZGVyKTsgcGFkZGluZzogLjJyZW0gLjZyZW07IGJvcmRlci1yYWRpdXM6IDIwcHg7IGZvbnQtc2l6ZTogLjdyZW07IH0KICAgICAgICAuYmFkZ2UtcHJlbWl1bSAgeyBiYWNrZ3JvdW5kOiB2YXIoLS1jbXMtYWNjZW50KTsgY29sb3I6ICMwMDA7IHBhZGRpbmc6IC4ycmVtIC42cmVtOyBib3JkZXItcmFkaXVzOiAyMHB4OyBmb250LXNpemU6IC43cmVtOyBmb250LXdlaWdodDogNzAwOyB9CiAgICAgICAgLmJhZGdlLWRyYWZ0ICAgIHsgYmFja2dyb3VuZDogI2Y4ZmFmYzsgY29sb3I6IHZhcigtLWNtcy1tdXRlZCk7IGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWNtcy1ib3JkZXIpOyBwYWRkaW5nOiAuMnJlbSAuNnJlbTsgYm9yZGVyLXJhZGl1czogMjBweDsgZm9udC1zaXplOiAuN3JlbTsgfQogICAgICAgIC5iYWRnZS1yZXZpZXdlZCB7IGJhY2tncm91bmQ6ICNmYWY1ZmY7IGNvbG9yOiAjN2MzYWVkOyBib3JkZXI6IDFweCBzb2xpZCAjZGRkNmZlOyBwYWRkaW5nOiAuMnJlbSAuNnJlbTsgYm9yZGVyLXJhZGl1czogMjBweDsgZm9udC1zaXplOiAuN3JlbTsgZm9udC13ZWlnaHQ6IDYwMDsgfQogICAgICAgIC5iYWRnZS1xdW90ZWQgICB7IGJhY2tncm91bmQ6ICNmZmY3ZWQ7IGNvbG9yOiAjYzI0MTBjOyBib3JkZXI6IDFweCBzb2xpZCAjZmVkN2FhOyBwYWRkaW5nOiAuMnJlbSAuNnJlbTsgYm9yZGVyLXJhZGl1czogMjBweDsgZm9udC1zaXplOiAuN3JlbTsgZm9udC13ZWlnaHQ6IDYwMDsgfQogICAgICAgIC5iYWRnZS13b24gICAgICB7IGJhY2tncm91bmQ6ICNmMGZkZjQ7IGNvbG9yOiAjMTU4MDNkOyBib3JkZXI6IDFweCBzb2xpZCAjYmJmN2QwOyBwYWRkaW5nOiAuMnJlbSAuNnJlbTsgYm9yZGVyLXJhZGl1czogMjBweDsgZm9udC1zaXplOiAuN3JlbTsgZm9udC13ZWlnaHQ6IDYwMDsgfQogICAgICAgIC5iYWRnZS1sb3N0ICAgICB7IGJhY2tncm91bmQ6ICNmZWYyZjI7IGNvbG9yOiAjYjkxYzFjOyBib3JkZXI6IDFweCBzb2xpZCAjZmVjYWNhOyBwYWRkaW5nOiAuMnJlbSAuNnJlbTsgYm9yZGVyLXJhZGl1czogMjBweDsgZm9udC1zaXplOiAuN3JlbTsgZm9udC13ZWlnaHQ6IDYwMDsgfQoKICAgICAgICAvKiDilIDilIAgRm9ybXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAICovCiAgICAgICAgLmNtcy1mb3JtIGxhYmVsIHsKICAgICAgICAgICAgZm9udC1zaXplOiAuNzVyZW07IGNvbG9yOiB2YXIoLS1jbXMtbXV0ZWQpOwogICAgICAgICAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlOyBsZXR0ZXItc3BhY2luZzogLjA4ZW07CiAgICAgICAgICAgIG1hcmdpbi1ib3R0b206IC4zcmVtOyBkaXNwbGF5OiBibG9jazsgZm9udC13ZWlnaHQ6IDYwMDsKICAgICAgICB9CiAgICAgICAgLmNtcy1mb3JtIGlucHV0LAogICAgICAgIC5jbXMtZm9ybSB0ZXh0YXJlYSwKICAgICAgICAuY21zLWZvcm0gc2VsZWN0IHsKICAgICAgICAgICAgd2lkdGg6IDEwMCU7CiAgICAgICAgICAgIGJhY2tncm91bmQ6ICNmZmY7CiAgICAgICAgICAgIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWNtcy1ib3JkZXIpOwogICAgICAgICAgICBjb2xvcjogdmFyKC0tY21zLXRleHQpOwogICAgICAgICAgICBwYWRkaW5nOiAuNnJlbSAuOXJlbTsKICAgICAgICAgICAgYm9yZGVyLXJhZGl1czogN3B4OwogICAgICAgICAgICBmb250LXNpemU6IC45cmVtOyBvdXRsaW5lOiBub25lOwogICAgICAgICAgICB0cmFuc2l0aW9uOiBib3JkZXItY29sb3IgLjE1cywgYm94LXNoYWRvdyAuMTVzOwogICAgICAgIH0KICAgICAgICAuY21zLWZvcm0gaW5wdXQ6Zm9jdXMsCiAgICAgICAgLmNtcy1mb3JtIHRleHRhcmVhOmZvY3VzLAogICAgICAgIC5jbXMtZm9ybSBzZWxlY3Q6Zm9jdXMgewogICAgICAgICAgICBib3JkZXItY29sb3I6ICMxNjUxN2I7CiAgICAgICAgICAgIGJveC1zaGFkb3c6IDAgMCAwIDNweCByZ2JhKDIyLDgxLDEyMywuMTIpOwogICAgICAgIH0KICAgICAgICAuY21zLWZvcm0gLmZvcm0tZ3JvdXAgeyBtYXJnaW4tYm90dG9tOiAxcmVtOyB9CiAgICAgICAgLmNtcy1mb3JtIC5mb3JtLWNoZWNrIHsgZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IGNlbnRlcjsgZ2FwOiAuNXJlbTsgfQogICAgICAgIC5jbXMtZm9ybSAuZm9ybS1jaGVjayBsYWJlbCB7IHRleHQtdHJhbnNmb3JtOiBub25lOyBsZXR0ZXItc3BhY2luZzogMDsgZm9udC1zaXplOiAuODc1cmVtOyBjb2xvcjogdmFyKC0tY21zLXRleHQpOyBtYXJnaW46IDA7IH0KICAgICAgICAuY21zLWZvcm0gLmZvcm0tY2hlY2sgaW5wdXRbdHlwZT1jaGVja2JveF0geyB3aWR0aDogYXV0bzsgYWNjZW50LWNvbG9yOiAjMTY1MTdiOyB9CgogICAgICAgIC8qIOKUgOKUgCBCdXR0b25zIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCAqLwogICAgICAgIC5idG4tY21zIHsKICAgICAgICAgICAgYmFja2dyb3VuZDogIzAzMzE1MjsgY29sb3I6ICNmZmY7IGZvbnQtd2VpZ2h0OiA2MDA7CiAgICAgICAgICAgIGJvcmRlcjogMXB4IHNvbGlkIHRyYW5zcGFyZW50OyBwYWRkaW5nOiAuNTVyZW0gMS4yNXJlbTsgYm9yZGVyLXJhZGl1czogN3B4OwogICAgICAgICAgICBjdXJzb3I6IHBvaW50ZXI7IGZvbnQtc2l6ZTogLjg3NXJlbTsgbGluZS1oZWlnaHQ6IDEuMjsgdHJhbnNpdGlvbjogb3BhY2l0eSAuMTVzOwogICAgICAgICAgICBkaXNwbGF5OiBpbmxpbmUtZmxleDsgYWxpZ24taXRlbXM6IGNlbnRlcjsgZ2FwOiAuNHJlbTsKICAgICAgICAgICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOyBib3gtc2l6aW5nOiBib3JkZXItYm94OwogICAgICAgICAgICAtd2Via2l0LWFwcGVhcmFuY2U6IG5vbmU7IGFwcGVhcmFuY2U6IG5vbmU7CiAgICAgICAgfQogICAgICAgIC5idG4tY21zOmhvdmVyIHsgb3BhY2l0eTogLjg1OyBjb2xvcjogI2ZmZjsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyB9CiAgICAgICAgLmJ0bi1jbXMtZ2hvc3QgewogICAgICAgICAgICBiYWNrZ3JvdW5kOiAjZmZmOyBjb2xvcjogdmFyKC0tY21zLXRleHQpOyBmb250LXdlaWdodDogNjAwOwogICAgICAgICAgICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1jbXMtYm9yZGVyKTsgcGFkZGluZzogLjU1cmVtIDEuMjVyZW07IGJvcmRlci1yYWRpdXM6IDdweDsKICAgICAgICAgICAgY3Vyc29yOiBwb2ludGVyOyBmb250LXNpemU6IC44NzVyZW07IGxpbmUtaGVpZ2h0OiAxLjI7IHRyYW5zaXRpb246IGFsbCAuMTVzOwogICAgICAgICAgICBkaXNwbGF5OiBpbmxpbmUtZmxleDsgYWxpZ24taXRlbXM6IGNlbnRlcjsgZ2FwOiAuNHJlbTsKICAgICAgICAgICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOyBib3gtc2l6aW5nOiBib3JkZXItYm94OwogICAgICAgICAgICAtd2Via2l0LWFwcGVhcmFuY2U6IG5vbmU7IGFwcGVhcmFuY2U6IG5vbmU7CiAgICAgICAgfQogICAgICAgIC5idG4tY21zLWdob3N0OmhvdmVyIHsgYm9yZGVyLWNvbG9yOiAjMDMzMTUyOyBjb2xvcjogIzAzMzE1MjsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyB9CiAgICAgICAgLyogT25lIGxvb2sgZm9yIGV2ZXJ5IGRlbGV0ZSBjb250cm9sIGluIHRoZSBwYW5lbDogb3V0bGluZWQgYXQgcmVzdCBzbyBhCiAgICAgICAgICAgZGVzdHJ1Y3RpdmUgYWN0aW9uIG5ldmVyIHNpdHMgb24gdGhlIHBhZ2Ugc2hvdXRpbmcsIGZpbGxlZCBvbiBob3ZlciBzbwogICAgICAgICAgIHlvdSBhcmUgaW4gbm8gZG91YnQgd2hhdCB5b3UgYXJlIGFib3V0IHRvIHByZXNzLiAqLwogICAgICAgIC5idG4tY21zLWRhbmdlciB7CiAgICAgICAgICAgIGJhY2tncm91bmQ6ICNmZmY7IGNvbG9yOiAjZTAyMDFiOyBmb250LXdlaWdodDogNjAwOwogICAgICAgICAgICBib3JkZXI6IDFweCBzb2xpZCAjZTAyMDFiOyBwYWRkaW5nOiAuNTVyZW0gMS4yNXJlbTsgYm9yZGVyLXJhZGl1czogN3B4OwogICAgICAgICAgICBjdXJzb3I6IHBvaW50ZXI7IGZvbnQtc2l6ZTogLjg3NXJlbTsgbGluZS1oZWlnaHQ6IDEuMjsgdHJhbnNpdGlvbjogYWxsIC4xNXM7CiAgICAgICAgICAgIGRpc3BsYXk6IGlubGluZS1mbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyBnYXA6IC40cmVtOwogICAgICAgICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7IGJveC1zaXppbmc6IGJvcmRlci1ib3g7CiAgICAgICAgICAgIC13ZWJraXQtYXBwZWFyYW5jZTogbm9uZTsgYXBwZWFyYW5jZTogbm9uZTsKICAgICAgICB9CiAgICAgICAgYS5idG4tY21zLWRhbmdlcjpob3ZlciwKICAgICAgICBidXR0b24uYnRuLWNtcy1kYW5nZXI6aG92ZXIsCiAgICAgICAgLmJ0bi1jbXMtZGFuZ2VyOmhvdmVyIHsKICAgICAgICAgICAgYmFja2dyb3VuZDogI2UwMjAxYjsgY29sb3I6ICNmZmY7IGJvcmRlci1jb2xvcjogI2UwMjAxYjsKICAgICAgICAgICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOyBvcGFjaXR5OiAxOwogICAgICAgIH0KICAgICAgICAuYnRuLWNtcy1kYW5nZXI6aG92ZXIgaSB7IGNvbG9yOiAjZmZmOyB9CiAgICAgICAgLmJ0bi1jbXMtZGFuZ2VyOmRpc2FibGVkLAogICAgICAgIC5idG4tY21zLWRhbmdlcltkaXNhYmxlZF0gewogICAgICAgICAgICBjb2xvcjogI2NiZDVlMTsgYm9yZGVyLWNvbG9yOiAjZTJlOGYwOyBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDsgY3Vyc29yOiBkZWZhdWx0OwogICAgICAgIH0KCiAgICAgICAgLyog4pSA4pSAIEFsZXJ0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8KICAgICAgICAuY21zLWFsZXJ0IHsgcGFkZGluZzogLjg1cmVtIDEuMXJlbTsgYm9yZGVyLXJhZGl1czogOHB4OyBtYXJnaW4tYm90dG9tOiAxcmVtOyBmb250LXNpemU6IC44NzVyZW07IH0KICAgICAgICAuY21zLWFsZXJ0LXN1Y2Nlc3MgeyBiYWNrZ3JvdW5kOiAjZjBmZGY0OyBib3JkZXI6IDFweCBzb2xpZCAjYmJmN2QwOyBjb2xvcjogIzE1ODAzZDsgfQogICAgICAgIC5jbXMtYWxlcnQtZXJyb3IgICB7IGJhY2tncm91bmQ6ICNmZWYyZjI7IGJvcmRlcjogMXB4IHNvbGlkICNmZWNhY2E7IGNvbG9yOiAjZGMyNjI2OyB9CiAgICAgICAgLmNtcy1hbGVydC13YXJuaW5nIHsgYmFja2dyb3VuZDogI2ZmZjdlZDsgYm9yZGVyOiAxcHggc29saWQgI2ZlZDdhYTsgY29sb3I6ICNjMjQxMGM7IH0KICAgICAgICAuY21zLWFsZXJ0LWluZm8gICAgeyBiYWNrZ3JvdW5kOiAjZWZmNmZmOyBib3JkZXI6IDFweCBzb2xpZCAjYmZkYmZlOyBjb2xvcjogIzI1NjNlYjsgfQoKICAgICAgICAvKiDilIDilIAgU2VjdGlvbiBoZWFkZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAICovCiAgICAgICAgLmNtcy1zZWN0aW9uLWhlYWRlciB7CiAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjsKICAgICAgICAgICAgZ2FwOiAuNzVyZW07IGZsZXgtd3JhcDogd3JhcDsKICAgICAgICAgICAgLyogRml4ZWQgaGVpZ2h0IHNvIHRoZSByb3cgaXMgaWRlbnRpY2FsIG9uIGV2ZXJ5IHBhZ2UuIFdpdGhvdXQgaXQgdGhlCiAgICAgICAgICAgICAgIGhlYWRlciBncm93cyB0byBmaXQgaXRzIHRhbGxlc3QgY29udHJvbCwgd2hpY2ggZGlmZmVycyBwZXIgcGFnZQogICAgICAgICAgICAgICAoc2VhcmNoIGJveCwgdGFsbCBidXR0b25zKSwgYW5kIGV2ZXJ5dGhpbmcgYmVsb3cgc2hpZnRzLiAqLwogICAgICAgICAgICBtaW4taGVpZ2h0OiAyLjc1cmVtOwogICAgICAgICAgICBtYXJnaW4tYm90dG9tOiAxLjI1cmVtOwogICAgICAgIH0KICAgICAgICAuY21zLXNlY3Rpb24taGVhZGVyID4gKiB7IG1hcmdpbjogMDsgfQogICAgICAgIC5jbXMtc2VjdGlvbi1oZWFkZXIgaDIgeyBmb250LXNpemU6IDEuMXJlbTsgZm9udC13ZWlnaHQ6IDcwMDsgbWFyZ2luOiAwOyBjb2xvcjogdmFyKC0tY21zLXRleHQpOyB9CgogICAgICAgIC8qIOKUgOKUgCBOYXYgZGlzYWJsZWQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAICovCiAgICAgICAgLm5hdi1kaXNhYmxlZCB7IG9wYWNpdHk6IC4zNTsgY3Vyc29yOiBub3QtYWxsb3dlZDsgcG9pbnRlci1ldmVudHM6IG5vbmU7IH0KCiAgICAgICAgLyog4pSA4pSAIE1vYmlsZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8KICAgICAgICAvKiDilIDilIAgVGFibGV0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICAgICAgICAgIGlQYWQgaW4gcG9ydHJhaXQgaXMgd2lkZSBlbm91Z2ggZm9yIHRoZSBjb250ZW50IGJ1dCBub3QgZm9yIHRoZQogICAgICAgICAgIHNpZGViYXIgYXMgd2VsbCwgc28gdGhlIHNpZGViYXIgY29sbGFwc2VzIHRvIGljb25zIGFuZCB0aGUgcGFkZGluZwogICAgICAgICAgIHRpZ2h0ZW5zLiBFdmVyeXRoaW5nIGVsc2Ugc3RheXMgYXMgaXQgaXMgb24gZGVza3RvcC4gKi8KICAgICAgICBAbWVkaWEgKG1pbi13aWR0aDogNzY5cHgpIGFuZCAobWF4LXdpZHRoOiAxMDI0cHgpIGFuZCAobWluLWhlaWdodDogNjAwcHgpIHsKICAgICAgICAgICAgLmNtcy1jb250ZW50IHsgcGFkZGluZzogMS4yNXJlbSAxLjI1cmVtOyB9CiAgICAgICAgICAgIC5jbXMtY2FyZCB7IHBhZGRpbmc6IDFyZW07IH0KICAgICAgICAgICAgLmNtcy10YWJsZSB0aCwgLmNtcy10YWJsZSB0ZCB7IHBhZGRpbmc6IC42cmVtIC43cmVtOyB9CiAgICAgICAgICAgIC5jbXMtdGFibGUgdGQgeyBmb250LXNpemU6IC44NHJlbTsgfQogICAgICAgIH0KCiAgICAgICAgLyog4pSA4pSAIFBob25lIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICAgICAgICAgIFByZXNlbnRhdGlvbiBvbmx5LiBFdmVyeSBydWxlIGhlcmUgaXMgc2NvcGVkIHRvIHNtYWxsIHNjcmVlbnMsIHNvCiAgICAgICAgICAgcmVtb3ZpbmcgdGhpcyBibG9jayByZXN0b3JlcyB0aGUgZGVza3RvcCBsYXlvdXQgZXhhY3RseS4gKi8KICAgICAgICBAbWVkaWEgKG1heC13aWR0aDogNzY4cHgpLAogICAgICAgICAgICAgICAobWF4LWhlaWdodDogNTk5cHgpIGFuZCAob3JpZW50YXRpb246IGxhbmRzY2FwZSkgewogICAgICAgICAgICBodG1sLCBib2R5IHsgb3ZlcmZsb3cteDogaGlkZGVuOyBtYXgtd2lkdGg6IDEwMCU7IH0KICAgICAgICAgICAgLyogaU9TIHpvb21zIHRoZSBwYWdlIHdoZW4gYSBmaWVsZCB3aXRoIHRleHQgdW5kZXIgMTZweCBpcyBmb2N1c2VkLAogICAgICAgICAgICAgICBhbmQgbmV2ZXIgem9vbXMgYmFjayBvdXQuIDE2cHggaW5wdXRzIHN0b3AgdGhhdC4gKi8KICAgICAgICAgICAgaW5wdXQsIHNlbGVjdCwgdGV4dGFyZWEgeyBmb250LXNpemU6IDE2cHggIWltcG9ydGFudDsgfQoKICAgICAgICAgICAgLyogU2lkZWJhciBiZWNvbWVzIGEgZHJhd2VyIHdpdGggYSBkaW1tZWQgcGFnZSBiZWhpbmQgaXQgKi8KICAgICAgICAgICAgLmNtcy1zaWRlYmFyIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWCgtMTAwJSk7CiAgICAgICAgICAgICAgICB3aWR0aDogbWluKDgydncsIHZhcigtLXNiLXdpZHRoKSkgIWltcG9ydGFudDsKICAgICAgICAgICAgICAgIGJveC1zaGFkb3c6IG5vbmU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLyogU2hhZG93IG9ubHkgd2hpbGUgb3Blbi4gT2ZmIHNjcmVlbiBpdCBzcGlsbHMgb250byB0aGUgcGFnZSBhbmQKICAgICAgICAgICAgICAgc2hvd3MgYXMgYSBwYWxlIHNtZWFyIGRvd24gdGhlIGxlZnQgZWRnZS4gKi8KICAgICAgICAgICAgLmNtcy1zaWRlYmFyLm1vYmlsZS1vcGVuIHsgYm94LXNoYWRvdzogMCAwIDQwcHggcmdiYSgwLDAsMCwuMzUpOyB9CiAgICAgICAgICAgIC5jbXMtc2lkZWJhci5tb2JpbGUtb3BlbiB7IHRyYW5zZm9ybTogdHJhbnNsYXRlWCgwKTsgfQogICAgICAgICAgICAvKiBUaGUgZGVza3RvcCBjb2xsYXBzZSBjb250cm9sIG1ha2VzIG5vIHNlbnNlIGluIGEgZHJhd2VyOiBpdAogICAgICAgICAgICAgICBsZWF2ZXMgYSB3aWRlIHBhbmVsIG9mIHVubGFiZWxsZWQgaWNvbnMgYW5kIG5vIHdheSBiYWNrLiBIaWRlCiAgICAgICAgICAgICAgIGl0LCBhbmQgbmV1dHJhbGlzZSBldmVyeSBydWxlIHRoZSBtaW5pbWl6ZWQgc3RhdGUgYXBwbGllcy4gKi8KICAgICAgICAgICAgLnNpZGViYXItdG9nZ2xlIHsgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50OyB9CiAgICAgICAgICAgIC5jbXMtc2lkZWJhci5taW5pbWl6ZWQgeyB3aWR0aDogbWluKDgydncsIHZhcigtLXNiLXdpZHRoKSkgIWltcG9ydGFudDsgfQogICAgICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5uYXYtdGV4dCwKICAgICAgICAgICAgLmNtcy1zaWRlYmFyIC5uYXYtdGV4dCB7CiAgICAgICAgICAgICAgICBvcGFjaXR5OiAxICFpbXBvcnRhbnQ7IHdpZHRoOiBhdXRvICFpbXBvcnRhbnQ7IG92ZXJmbG93OiB2aXNpYmxlICFpbXBvcnRhbnQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLmNtcy1zaWRlYmFyLm1pbmltaXplZCAubmF2LXNlY3Rpb24sCiAgICAgICAgICAgIC5jbXMtc2lkZWJhciAubmF2LXNlY3Rpb24gewogICAgICAgICAgICAgICAgb3BhY2l0eTogMSAhaW1wb3J0YW50OyBoZWlnaHQ6IGF1dG8gIWltcG9ydGFudDsKICAgICAgICAgICAgICAgIHBhZGRpbmc6IC45cmVtIDEuMjVyZW0gLjM1cmVtICFpbXBvcnRhbnQ7IHRleHQtYWxpZ246IGxlZnQgIWltcG9ydGFudDsKICAgICAgICAgICAgfQogICAgICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5icmFuZC10ZXh0IHsgb3BhY2l0eTogMSAhaW1wb3J0YW50OyB3aWR0aDogYXV0byAhaW1wb3J0YW50OyB9CiAgICAgICAgICAgIC5jbXMtc2lkZWJhci5taW5pbWl6ZWQgLmJyYW5kLWxvZ28geyBkaXNwbGF5OiBibG9jayAhaW1wb3J0YW50OyB9CiAgICAgICAgICAgIC5jbXMtc2lkZWJhci5taW5pbWl6ZWQgLmJyYW5kLWluaXRpYWxzIHsgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDsgfQogICAgICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5icmFuZC1tYXJrIHsgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDsgfQogICAgICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5zaWRlYmFyLWJyYW5kIHsganVzdGlmeS1jb250ZW50OiBmbGV4LXN0YXJ0ICFpbXBvcnRhbnQ7IHBhZGRpbmc6IDEuMnJlbSAxLjI1cmVtICFpbXBvcnRhbnQ7IH0KICAgICAgICAgICAgLyogTGVmdCBhbGlnbiBldmVyeSByb3csIGljb25zIGluIG9uZSBjb2x1bW4sIHRleHQgYmVzaWRlIHRoZW0gKi8KICAgICAgICAgICAgLmNtcy1zaWRlYmFyLm1pbmltaXplZCAuc2lkZWJhci1uYXYtd3JhcCBhLAogICAgICAgICAgICAuY21zLXNpZGViYXIgLnNpZGViYXItbmF2LXdyYXAgYSB7CiAgICAgICAgICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGZsZXgtc3RhcnQgIWltcG9ydGFudDsKICAgICAgICAgICAgICAgIHBhZGRpbmc6IC43NXJlbSAxLjI1cmVtICFpbXBvcnRhbnQ7CiAgICAgICAgICAgICAgICBnYXA6IC44NXJlbTsKICAgICAgICAgICAgfQogICAgICAgICAgICAuY21zLXNpZGViYXIgLnNpZGViYXItbmF2LXdyYXAgYSBpLm5hdi1pY29uIHsgd2lkdGg6IDIycHggIWltcG9ydGFudDsgdGV4dC1hbGlnbjogY2VudGVyOyB9CiAgICAgICAgICAgIC8qIFRvb2x0aXBzIGJlbG9uZyB0byB0aGUgY29sbGFwc2VkIGRlc2t0b3Agc3RhdGUgKi8KICAgICAgICAgICAgLmNtcy1zaWRlYmFyLm1pbmltaXplZCAuc2lkZWJhci1uYXYtd3JhcCBhOjphZnRlciB7IGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDsgfQogICAgICAgICAgICAvKiBGb290ZXIgc2hvd3MgdGhlIHBlcnNvbiwgbm90IGp1c3QgYW4gaW5pdGlhbCAqLwogICAgICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIC5zaWRlYmFyLXVzZXItaW5mbywKICAgICAgICAgICAgLmNtcy1zaWRlYmFyIC5zaWRlYmFyLXVzZXItaW5mbyB7IGRpc3BsYXk6IGJsb2NrICFpbXBvcnRhbnQ7IG9wYWNpdHk6IDEgIWltcG9ydGFudDsgd2lkdGg6IGF1dG8gIWltcG9ydGFudDsgfQoKICAgICAgICAgICAgLyogVGhlIG1lbnUgYnV0dG9uIGRvdWJsZXMgYXMgdGhlIGNsb3NlIGNvbnRyb2wsIHNvIGl0IHNpdHMgYWJvdmUKICAgICAgICAgICAgICAgdGhlIGRyYXdlciBhbmQgbW92ZXMgdG8gdGhlIHJpZ2h0IHdoZXJlIHRoZSBkcmF3ZXIgY2Fubm90IGNvdmVyCiAgICAgICAgICAgICAgIGl0LiBUYXBwaW5nIGl0IGFnYWluIGNsb3NlcyB0aGUgbWVudS4gKi8KICAgICAgICAgICAgLyogTGVmdCwgYW5kIGxldmVsIHdpdGggdGhlIGhlYWRlciByb3cgcmF0aGVyIHRoYW4gYWJvdmUgaXQuIFNpdHMKICAgICAgICAgICAgICAgYWJvdmUgdGhlIGRyYXdlciBzbyB0aGUgc2FtZSBidXR0b24gY2xvc2VzIHRoZSBtZW51LiAqLwogICAgICAgICAgICAvKiBGaXhlZCBtZWFudCBpdCBob3ZlcmVkIG92ZXIgd2hhdGV2ZXIgc2Nyb2xsZWQgYmVuZWF0aCBpdCwgYWxsCiAgICAgICAgICAgICAgIHRoZSB3YXkgZG93biB0aGUgcGFnZS4gQWJzb2x1dGUga2VlcHMgaXQgYXQgdGhlIHRvcCBvZiB0aGUgcGFnZQogICAgICAgICAgICAgICBpbnN0ZWFkLCBzbyBpdCBzY3JvbGxzIGF3YXkgd2l0aCB0aGUgaGVhZGVyIGFuZCBuZXZlciBjb3ZlcnMgYQogICAgICAgICAgICAgICB0YWJsZSwgYSBsYWJlbCBvciBhIHZhbHVlLiAqLwogICAgICAgICAgICAubW9iaWxlLW1lbnUtYnRuIHsKICAgICAgICAgICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZSAhaW1wb3J0YW50OwogICAgICAgICAgICAgICAgei1pbmRleDogMTIwMCAhaW1wb3J0YW50OwogICAgICAgICAgICAgICAgbGVmdDogMXJlbTsgcmlnaHQ6IGF1dG87CiAgICAgICAgICAgICAgICB0b3A6IDFyZW07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLmNtcy1tYWluIHsgcG9zaXRpb246IHJlbGF0aXZlOyB9CiAgICAgICAgICAgIC5jbXMtbWFpbiwgLmNtcy1tYWluLnNpZGViYXItbWluaW1pemVkIHsgbWFyZ2luLWxlZnQ6IDA7IH0KCiAgICAgICAgICAgIC5tb2JpbGUtbWVudS1idG4gewogICAgICAgICAgICAgICAgZGlzcGxheTogZmxleCAhaW1wb3J0YW50OwogICAgICAgICAgICAgICAgd2lkdGg6IDQ0cHg7IGhlaWdodDogNDRweDsKICAgICAgICAgICAgICAgIGJveC1zaGFkb3c6IDAgMnB4IDEwcHggcmdiYSgwLDAsMCwuMTgpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvKiBSb29tIGZvciB0aGUgZmxvYXRpbmcgbWVudSBidXR0b24gKi8KICAgICAgICAgICAgLyogUm9vbSBmb3IgdGhlIGJ1dHRvbiBvbiB0aGUgZmlyc3Qgc2NyZWVuIG9ubHkgKi8KICAgICAgICAgICAgLmNtcy1jb250ZW50IHsgcGFkZGluZzogNC4yNXJlbSAxcmVtIDJyZW07IH0KCiAgICAgICAgICAgIC8qIFBhZ2UgaGVhZGVyOiB0aXRsZSBvbiBpdHMgb3duIGxpbmUsIGNvbnRyb2xzIGZ1bGwgd2lkdGggYmVsb3cgKi8KICAgICAgICAgICAgLmNtcy1zZWN0aW9uLWhlYWRlciB7CiAgICAgICAgICAgICAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uOyBhbGlnbi1pdGVtczogc3RyZXRjaDsKICAgICAgICAgICAgICAgIGdhcDogLjZyZW07IG1pbi1oZWlnaHQ6IDA7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLmNtcy1zZWN0aW9uLWhlYWRlciBoMiB7IGZvbnQtc2l6ZTogMS4wNXJlbTsgdGV4dC1hbGlnbjogbGVmdDsgfQogICAgICAgICAgICAvKiBDb250cm9scyBydW4gbGVmdCB0byByaWdodCBhbmQgd3JhcCBvbmx5IHdoZW4gdGhleSBtdXN0LCBzbyBhCiAgICAgICAgICAgICAgIHNlYXJjaCBib3ggYW5kIG9uZSBvciB0d28gYnV0dG9ucyBzaGFyZSBhIGxpbmUgd2hlcmUgdGhlcmUgaXMKICAgICAgICAgICAgICAgcm9vbSBmb3IgdGhlbSAqLwogICAgICAgICAgICAuY21zLXNlY3Rpb24taGVhZGVyID4gZGl2IHsKICAgICAgICAgICAgICAgIHdpZHRoOiAxMDAlOyBkaXNwbGF5OiBmbGV4OyBmbGV4LXdyYXA6IHdyYXA7CiAgICAgICAgICAgICAgICBnYXA6IC41cmVtICFpbXBvcnRhbnQ7IGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLnNlYXJjaC1pbmxpbmUgeyBmbGV4OiAxIDEgMTAwJTsgbWluLXdpZHRoOiAwOyBwYWRkaW5nOiAuNXJlbSAuOXJlbSAhaW1wb3J0YW50OyB9CiAgICAgICAgICAgIC5zZWFyY2gtaW5saW5lIGlucHV0IHsgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsgbWluLXdpZHRoOiAwOyB9CiAgICAgICAgICAgIC8qIEJ1dHRvbnMgc2l0IHNpZGUgYnkgc2lkZSBhbmQgc2hhcmUgdGhlIHJvdyBldmVubHkgcmF0aGVyIHRoYW4KICAgICAgICAgICAgICAgb25lIHN0cmV0Y2hpbmcgZnVsbCB3aWR0aCBhbmQgcHVzaGluZyB0aGUgbmV4dCBvbmUgZG93biAqLwogICAgICAgICAgICAuY21zLXNlY3Rpb24taGVhZGVyID4gZGl2ID4gYSwKICAgICAgICAgICAgLmNtcy1zZWN0aW9uLWhlYWRlciA+IGRpdiA+IGJ1dHRvbiwKICAgICAgICAgICAgLmNtcy1zZWN0aW9uLWhlYWRlciA+IGRpdiA+IGZvcm06bm90KC5zZWFyY2gtaW5saW5lKSB7CiAgICAgICAgICAgICAgICBmbGV4OiAxIDEgYXV0bzsgbWluLXdpZHRoOiAxMjBweDsganVzdGlmeS1jb250ZW50OiBjZW50ZXI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8qIEJ1dHRvbnMgcmVhY2ggdGhlIDQ0cHggQXBwbGUgYW5kIEdvb2dsZSBib3RoIGFzayBmb3IgKi8KICAgICAgICAgICAgLmJ0bi1jbXMsIC5idG4tY21zLWdob3N0LCAuYnRuLWNtcy1zaXRlLCAuY21zLXNlY3Rpb24taGVhZGVyIGEuYnRuLWNtcywKICAgICAgICAgICAgLmNtcy1zZWN0aW9uLWhlYWRlciBhLmJ0bi1jbXMtZ2hvc3QgewogICAgICAgICAgICAgICAgbWluLWhlaWdodDogNDRweDsKICAgICAgICAgICAgICAgIHBhZGRpbmc6IC42NXJlbSAxcmVtOwogICAgICAgICAgICAgICAgZm9udC1zaXplOiAuODVyZW07CiAgICAgICAgICAgICAgICBkaXNwbGF5OiBpbmxpbmUtZmxleDsgYWxpZ24taXRlbXM6IGNlbnRlcjsganVzdGlmeS1jb250ZW50OiBjZW50ZXI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8qIENhcmRzOiBmdWxsIGJsZWVkLCB0aWdodGVyIHBhZGRpbmcsIGFuZCBhbnkgdGFibGUgaW5zaWRlIHNjcm9sbHMKICAgICAgICAgICAgICAgd2l0aGluIHRoZSBjYXJkIHJhdGhlciB0aGFuIHB1c2hpbmcgdGhlIHBhZ2Ugc2lkZXdheXMgKi8KICAgICAgICAgICAgLyogNjIgY2FyZHMgY2FycnkgYW4gaW5saW5lIG92ZXJmbG93OmhpZGRlbiwgd2hpY2ggYmVhdHMgYSBwbGFpbgogICAgICAgICAgICAgICBzdHlsZXNoZWV0IHJ1bGUuICFpbXBvcnRhbnQgaXMgbmVlZGVkIG9yIHRoZSB0YWJsZSBpbnNpZGUgaXMKICAgICAgICAgICAgICAgc2ltcGx5IGNsaXBwZWQgYW5kIGNhbm5vdCBiZSBzY3JvbGxlZCB0by4gKi8KICAgICAgICAgICAgLmNtcy1jYXJkIHsKICAgICAgICAgICAgICAgIHBhZGRpbmc6IDFyZW07CiAgICAgICAgICAgICAgICBib3JkZXItcmFkaXVzOiAxMHB4OwogICAgICAgICAgICAgICAgbWF4LXdpZHRoOiAxMDAlOwogICAgICAgICAgICAgICAgb3ZlcmZsb3cteDogYXV0byAhaW1wb3J0YW50OwogICAgICAgICAgICAgICAgLXdlYmtpdC1vdmVyZmxvdy1zY3JvbGxpbmc6IHRvdWNoOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8qIFNxdWVlemluZyBhIG5pbmUgY29sdW1uIHRhYmxlIGludG8gMzkwcHggdHVybnMgZXZlcnkgY2VsbCBpbnRvCiAgICAgICAgICAgICAgIG9uZSBsZXR0ZXIgcGVyIGxpbmUuIFRhYmxlcyBrZWVwIHRoZWlyIG5hdHVyYWwgd2lkdGggYW5kIHRoZQogICAgICAgICAgICAgICBjYXJkIHNjcm9sbHMgc2lkZXdheXMgaW5zdGVhZCwgbGlrZSBhIHNwcmVhZHNoZWV0LiAqLwogICAgICAgICAgICAuY21zLXRhYmxlIHsgd2lkdGg6IGF1dG87IG1pbi13aWR0aDogMTAwJTsgdGFibGUtbGF5b3V0OiBhdXRvOyB9CiAgICAgICAgICAgIC5jbXMtdGFibGUgdGgsIC5jbXMtdGFibGUgdGQgewogICAgICAgICAgICAgICAgcGFkZGluZzogLjZyZW0gLjc1cmVtOwogICAgICAgICAgICAgICAgd2hpdGUtc3BhY2U6IG5vd3JhcDsKICAgICAgICAgICAgICAgIHdvcmQtYnJlYWs6IG5vcm1hbDsKICAgICAgICAgICAgfQogICAgICAgICAgICAuY21zLXRhYmxlIHRkIHsgZm9udC1zaXplOiAuODJyZW07IH0KICAgICAgICAgICAgLmNtcy10YWJsZSB0aCB7IGZvbnQtc2l6ZTogLjYycmVtOyBsZXR0ZXItc3BhY2luZzogLjA0ZW07IH0KICAgICAgICAgICAgLyogQSBsb25nIG5hbWUgb3IgZW1haWwgd291bGQgb3RoZXJ3aXNlIHN0cmV0Y2ggaXRzIGNvbHVtbiBhY3Jvc3MKICAgICAgICAgICAgICAgc2V2ZXJhbCBzY3JlZW5zLiBDdXQgaXQgd2l0aCBhbiBlbGxpcHNpcyBpbnN0ZWFkLiBUaGUgZnVsbCB2YWx1ZQogICAgICAgICAgICAgICBpcyBzdGlsbCB0aGVyZSwgaXQganVzdCBkb2VzIG5vdCBkcmFnIHRoZSB0YWJsZSB3aWRlLiAqLwogICAgICAgICAgICAuY21zLXRhYmxlIHRkID4gZGl2LCAuY21zLXRhYmxlIHRkID4gc3BhbiB7CiAgICAgICAgICAgICAgICBtYXgtd2lkdGg6IDIwMHB4OwogICAgICAgICAgICAgICAgb3ZlcmZsb3c6IGhpZGRlbjsKICAgICAgICAgICAgICAgIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzOwogICAgICAgICAgICAgICAgd2hpdGUtc3BhY2U6IG5vd3JhcDsKICAgICAgICAgICAgICAgIGRpc3BsYXk6IGJsb2NrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8qIFRoZSBuYW1lIGNvbHVtbiBnZXRzIHRoZSBtb3N0IHJvb20sIHNpbmNlIGl0IGlzIHdoYXQgeW91IHJlYWQKICAgICAgICAgICAgICAgdG8gZmluZCB0aGUgcm93IHlvdSB3YW50ICovCiAgICAgICAgICAgIC5jbXMtdGFibGUgdGQ6bnRoLWNoaWxkKDIpIHsgbWF4LXdpZHRoOiAyMjBweDsgfQogICAgICAgICAgICAuY21zLXRhYmxlIHRkIGEsIC5jbXMtdGFibGUgdGQgYnV0dG9uIHsgbWluLWhlaWdodDogMzZweDsgfQogICAgICAgICAgICAvKiBBIGhpbnQgdGhhdCB0aGVyZSBpcyBtb3JlIHRvIHRoZSByaWdodCAqLwogICAgICAgICAgICAuY21zLWNhcmQ6aGFzKC5jbXMtdGFibGUpIHsgcG9zaXRpb246IHJlbGF0aXZlOyB9CgogICAgICAgICAgICAvKiBFZGl0IHBhZ2VzOiB0aGUgc2lkZWJhciBjb2x1bW4gY2FycmllcyBTYXZlLCBzbyBpdCBnb2VzIG9uIHRvcCAqLwogICAgICAgICAgICAucm93ID4gW2NsYXNzKj0iY29sLWxnLTQiXSB7IG9yZGVyOiAtMTsgfQogICAgICAgICAgICAucm93ID4gW2NsYXNzKj0iY29sLWxnLTgiXSB7IG9yZGVyOiAwOyB9CiAgICAgICAgICAgIC5yb3cgeyBkaXNwbGF5OiBmbGV4OyBmbGV4LWRpcmVjdGlvbjogY29sdW1uOyB9CiAgICAgICAgICAgIC5yb3cgPiBbY2xhc3MqPSJjb2wtIl0geyB3aWR0aDogMTAwJTsgbWF4LXdpZHRoOiAxMDAlOyBmbGV4OiAwIDAgYXV0bzsgfQogICAgICAgICAgICAvKiBCb290c3RyYXAgcm93cyBjYXJyeSBhIG5lZ2F0aXZlIG1hcmdpbiBlaXRoZXIgc2lkZSBhbmQgdGhlCiAgICAgICAgICAgICAgIGNvbHVtbnMgcGFkIGl0IGJhY2suIENvbWJpbmVkIHdpdGggdGhlIG1heC13aWR0aDogMTAwJSBiZWxvdywKICAgICAgICAgICAgICAgdGhlIGxlZnQgbmVnYXRpdmUgbWFyZ2luIHN1cnZpdmVzIGFuZCB0aGUgcmlnaHQgb25lIGNhbm5vdAogICAgICAgICAgICAgICBleHBhbmQsIHNvIGV2ZXJ5IHJvdyBmaW5pc2hlZCBzaG9ydCBvbiB0aGUgcmlnaHQgd2hpbGUgc3RhcnRpbmcKICAgICAgICAgICAgICAgZmx1c2ggb24gdGhlIGxlZnQuIENhcmRzIHRoZW4gc2F0IGluc2V0IGZyb20gdGhlIHJpZ2h0IGVkZ2UKICAgICAgICAgICAgICAgd2hpbGUgdGhlIGhlYWRlciBidXR0b24gcmVhY2hlZCBpdCwgd2hpY2ggaXMgd2hhdCB5b3Ugc2VlIG9uIGEKICAgICAgICAgICAgICAgcGhvbmUuIEd1dHRlcnMgb2ZmIGhvcml6b250YWxseTsgdGhlIHZlcnRpY2FsIGdhcCBjb21lcyBmcm9tCiAgICAgICAgICAgICAgIG1hcmdpbi10b3Agb24gdGhlIGNvbHVtbnMgYW5kIGlzIHVudG91Y2hlZC4gKi8KICAgICAgICAgICAgLnJvdyB7IG1hcmdpbi1sZWZ0OiAwICFpbXBvcnRhbnQ7IG1hcmdpbi1yaWdodDogMCAhaW1wb3J0YW50OyB9CiAgICAgICAgICAgIC5yb3cgPiBbY2xhc3MqPSJjb2wtIl0geyBwYWRkaW5nLWxlZnQ6IDAgIWltcG9ydGFudDsgcGFkZGluZy1yaWdodDogMCAhaW1wb3J0YW50OyB9CgogICAgICAgICAgICAvKiBTdGlja3kgY2FyZHMgd291bGQgY292ZXIgbW9zdCBvZiBhIHBob25lIHNjcmVlbiAqLwogICAgICAgICAgICBbc3R5bGUqPSJwb3NpdGlvbjpzdGlja3kiXSwgW3N0eWxlKj0icG9zaXRpb246IHN0aWNreSJdIHsKICAgICAgICAgICAgICAgIHBvc2l0aW9uOiBzdGF0aWMgIWltcG9ydGFudDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLyogRm9ybSB0YWJsZXM6IGxhYmVsIGFib3ZlIHRoZSBmaWVsZCwgbm90IGJlc2lkZSBpdCAqLwogICAgICAgICAgICAuZm9ybS10YWJsZSwgLmZvcm0tdGFibGUgdGJvZHksIC5mb3JtLXRhYmxlIHRyLCAuZm9ybS10YWJsZSB0ZCB7IGRpc3BsYXk6IGJsb2NrOyB3aWR0aDogMTAwJTsgfQogICAgICAgICAgICAvKiBIb3Jpem9udGFsIHBhZGRpbmcgb24gdGhlIGNlbGwsIG5vdCB0aGUgcm93LiBNb3N0IG9mIHRoZXNlIGNhcmRzCiAgICAgICAgICAgICAgIGNhcnJ5IGFuIGlubGluZSBwYWRkaW5nOjAsIHNvIHdpdGhvdXQgaXQgdGhlIGxhYmVsIGFuZCB0aGUgdmFsdWUKICAgICAgICAgICAgICAgc2l0IGhhcmQgYWdhaW5zdCB0aGUgY2FyZCBib3JkZXIuICovCiAgICAgICAgICAgIC5mb3JtLXRhYmxlIHRkIHsgYm9yZGVyOiBub25lOyBwYWRkaW5nOiAuM3JlbSAxcmVtOyB9CiAgICAgICAgICAgIC5mb3JtLXRhYmxlIHRyIHsgcGFkZGluZzogLjU1cmVtIDA7IGJvcmRlci1ib3R0b206IDFweCBzb2xpZCB2YXIoLS1jbXMtYm9yZGVyKTsgfQogICAgICAgICAgICAuZm9ybS10YWJsZSB0cjpsYXN0LWNoaWxkIHsgYm9yZGVyLWJvdHRvbTogbm9uZTsgfQogICAgICAgICAgICAuZm9ybS10YWJsZSB7IHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IG1pbi13aWR0aDogMCAhaW1wb3J0YW50OyB0YWJsZS1sYXlvdXQ6IGZpeGVkICFpbXBvcnRhbnQ7IH0KICAgICAgICAgICAgLyogVGhlIG5vd3JhcCBhYm92ZSBiZWxvbmdzIHRvIGRhdGEgZ3JpZHMsIHdoaWNoIHNjcm9sbCBzaWRld2F5cyBvbgogICAgICAgICAgICAgICBwdXJwb3NlLiBBIGZvcm0gdGFibGUgY2FycmllcyB0aGUgc2FtZSBjbGFzcyBhbmQgaXMgbm90IGEgZ3JpZDoKICAgICAgICAgICAgICAgZm9yY2luZyBpdHMgaGVscCB0ZXh0IG9udG8gb25lIGxpbmUgcHVzaGVkIHRoZSB0YWJsZSB3aWRlciB0aGFuCiAgICAgICAgICAgICAgIGl0cyBjYXJkLCBzbyB0aGUgaW5wdXRzIHdlcmUgc2l6ZWQgYWdhaW5zdCB0aGUgd3JvbmcgYm94IGFuZCB0aGUKICAgICAgICAgICAgICAgcGhvdG8gYnV0dG9ucyB3ZXJlIGN1dCBvZmYuIFRleHQgd3JhcHMgaGVyZSwgYW5kIGFueSBmbGV4IHJvdwogICAgICAgICAgICAgICBpbnNpZGUgYSBmaWVsZCB3cmFwcyB3aXRoIGl0LiAqLwogICAgICAgICAgICAuZm9ybS10YWJsZSwgLmZvcm0tdGFibGUgdGQsIC5mb3JtLXRhYmxlIHRoIHsgd2hpdGUtc3BhY2U6IG5vcm1hbCAhaW1wb3J0YW50OyB9CiAgICAgICAgICAgIC5mb3JtLXRhYmxlIC5maWVsZC10ZCA+IGRpdiB7IGZsZXgtd3JhcDogd3JhcDsgfQogICAgICAgICAgICAvKiBUaGUgcmVxdWlyZWQgbWFya2VyIHNpdHMgYXQgdGhlIHRvcCByaWdodCBvZiBpdHMgbGFiZWwsIG5ldmVyIG9uCiAgICAgICAgICAgICAgIGEgbGluZSBvZiBpdHMgb3duIHVuZGVybmVhdGggaXQuIExhYmVscyBhcmUgc2hvcnQgYW5kIG5ldmVyIG5lZWQKICAgICAgICAgICAgICAgdG8gd3JhcCwgc28gbm93cmFwIGhlcmUga2VlcHMgdGhlIGFzdGVyaXNrIGJlc2lkZSBpdHMgdGl0bGUsIGFuZAogICAgICAgICAgICAgICBzdXBlciBsaWZ0cyBpdCBjbGVhciBvZiB0aGUgdGV4dCByYXRoZXIgdGhhbiBzaXR0aW5nIG9uIHRoZQogICAgICAgICAgICAgICBiYXNlbGluZS4gKi8KICAgICAgICAgICAgLmZvcm0tdGFibGUgLmZpZWxkLWxhYmVsIHsgd2hpdGUtc3BhY2U6IG5vd3JhcCAhaW1wb3J0YW50OyB9CiAgICAgICAgICAgIC8qIExpdmUgQ2hhdCBpcyBhIHR3byBwYW5lIGRlc2t0b3AgbGF5b3V0OiBhIDMwMHB4IHNlc3Npb24gbGlzdAogICAgICAgICAgICAgICBiZXNpZGUgdGhlIGNvbnZlcnNhdGlvbi4gT24gYSBwaG9uZSB0aGF0IGxlYXZlcyB0aGUgY29udmVyc2F0aW9uCiAgICAgICAgICAgICAgIGFzIGEgc3RyaXAgYSBmZXcgY2hhcmFjdGVycyB3aWRlLiBTdGFjayB0aGVtIGluc3RlYWQsIGxpc3Qgb24KICAgICAgICAgICAgICAgdG9wIHdpdGggaXRzIG93biBzY3JvbGwgc28gaXQgY2Fubm90IHB1c2ggdGhlIGNvbnZlcnNhdGlvbiBvZmYKICAgICAgICAgICAgICAgdGhlIHNjcmVlbi4gQSBmdWxsIHNjcmVlbiBjb252ZXJzYXRpb24gd2l0aCBhIGJhY2sgYnV0dG9uIHdvdWxkCiAgICAgICAgICAgICAgIGJlIGJldHRlciwgYnV0IHRoZXJlIGlzIG5vIGJhY2sgY29udHJvbCB5ZXQsIGFuZCBoaWRpbmcgdGhlIGxpc3QKICAgICAgICAgICAgICAgd2l0aG91dCBvbmUgd291bGQgdHJhcCB5b3UuICovCiAgICAgICAgICAgIC5saXZlY2hhdC13cmFwIHsgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsgaGVpZ2h0OiBhdXRvOyBtaW4taGVpZ2h0OiAwOyB9CiAgICAgICAgICAgIC5sYy1sZWZ0IHsKICAgICAgICAgICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IGJvcmRlci1yaWdodDogbm9uZTsKICAgICAgICAgICAgICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCB2YXIoLS1jbXMtYm9yZGVyKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAubGMtc2Vzc2lvbnMgeyBtYXgtaGVpZ2h0OiA0MHZoOyBvdmVyZmxvdy15OiBhdXRvOyB9CiAgICAgICAgICAgIC5sYy1yaWdodCB7IHdpZHRoOiAxMDAlOyBtaW4taGVpZ2h0OiA1NXZoOyB9CiAgICAgICAgICAgIC8qICJQaWNrIGEgc2Vzc2lvbiBmcm9tIHRoZSBsZWZ0IiBpcyB3cm9uZyBvbmNlIHRoZXkgYXJlIHN0YWNrZWQuICovCiAgICAgICAgICAgIC5sYy1uby1zZXNzaW9uIHNtYWxsIHsgZGlzcGxheTogbm9uZTsgfQogICAgICAgICAgICAucmVxIHsKICAgICAgICAgICAgICAgIGRpc3BsYXk6IGlubGluZSAhaW1wb3J0YW50OwogICAgICAgICAgICAgICAgdmVydGljYWwtYWxpZ246IHN1cGVyOwogICAgICAgICAgICAgICAgZm9udC1zaXplOiAuN2VtOwogICAgICAgICAgICAgICAgbGluZS1oZWlnaHQ6IDA7CiAgICAgICAgICAgICAgICBtYXJnaW4tbGVmdDogMnB4OwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8qIEFueSBjb250cm9sIGluc2lkZSBvbmUgZmlsbHMgdGhlIHJvdy4gVGhlc2UgYXJlIGlubGluZS1zdHlsZWQgaW4KICAgICAgICAgICAgICAgc2V2ZXJhbCB0ZW1wbGF0ZXMsIHNvIHRoZSB3aWR0aCBoYXMgdG8gYmUgZm9yY2VkIGhlcmUuICovCiAgICAgICAgICAgIC5mb3JtLXRhYmxlIHNlbGVjdCwKICAgICAgICAgICAgLmZvcm0tdGFibGUgdGV4dGFyZWEsCiAgICAgICAgICAgIC5mb3JtLXRhYmxlIGlucHV0Om5vdChbdHlwZT1jaGVja2JveF0pOm5vdChbdHlwZT1yYWRpb10pIHsKICAgICAgICAgICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IG1heC13aWR0aDogMTAwJSAhaW1wb3J0YW50OyBib3gtc2l6aW5nOiBib3JkZXItYm94OwogICAgICAgICAgICB9CiAgICAgICAgICAgIC5maWVsZC1sYWJlbCB7CiAgICAgICAgICAgICAgICBmb250LXNpemU6IC43OHJlbTsgZm9udC13ZWlnaHQ6IDYwMDsgY29sb3I6IHZhcigtLWNtcy1tdXRlZCk7CiAgICAgICAgICAgICAgICB0ZXh0LWFsaWduOiBsZWZ0ICFpbXBvcnRhbnQ7IHdpZHRoOiBhdXRvICFpbXBvcnRhbnQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLmZpZWxkLWlucHV0IHsgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsgbWF4LXdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IH0KCiAgICAgICAgICAgIC8qIENvbG91ciBwaWNrZXJzLCB1cGxvYWQgcm93cyBhbmQgYnV0dG9uIHJvd3Mgd3JhcCBpbnN0ZWFkIG9mCiAgICAgICAgICAgICAgIG92ZXJmbG93aW5nICovCiAgICAgICAgICAgIC5jb2xvci1yb3csIC51cGxvYWQtYnRuLXdyYXAsIC5zZWNyZXQtcm93IHsgZmxleC13cmFwOiB3cmFwOyB9CiAgICAgICAgICAgIC5pbWctdXBsb2FkLXpvbmUgeyBmbGV4LXdyYXA6IHdyYXA7IH0KCiAgICAgICAgICAgIC8qIElubGluZSBncmlkcyBsaWtlIHJlcGVhdCgzLDFmcikgYXJlIHdpZGVyIHRoYW4gYSBwaG9uZS4gUmVmbG93CiAgICAgICAgICAgICAgIHRoZW0gdG8gd2hhdGV2ZXIgZml0cywgYW5kIGRyb3AgYW55IGZpeGVkIHJvdyBoZWlnaHRzIHdpdGggdGhlbS4gKi8KICAgICAgICAgICAgW3N0eWxlKj0iZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zIl0gewogICAgICAgICAgICAgICAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiByZXBlYXQoYXV0by1maXQsIG1pbm1heCgxMzVweCwgMWZyKSkgIWltcG9ydGFudDsKICAgICAgICAgICAgICAgIGdyaWQtdGVtcGxhdGUtcm93czogYXV0byAhaW1wb3J0YW50OwogICAgICAgICAgICAgICAgaGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8qIE5vdGhpbmcgbWF5IGV4Y2VlZCB0aGUgdmlld3BvcnQgKi8KICAgICAgICAgICAgLmNtcy1tYWluLCAuY21zLWNvbnRlbnQsIC5jbXMtY2FyZCwgLnJvdywgW2NsYXNzKj0iY29sLSJdIHsgbWF4LXdpZHRoOiAxMDAlOyB9CiAgICAgICAgICAgIC5jbXMtbWFpbiB7IG92ZXJmbG93LXg6IGhpZGRlbjsgfQoKICAgICAgICAgICAgLyogQ2hhcnRzIGtlZXAgdGhlaXIgYXNwZWN0IHJhdGlvIGluc3RlYWQgb2Ygc3F1YXNoaW5nICovCiAgICAgICAgICAgIGNhbnZhcyB7IG1heC13aWR0aDogMTAwJSAhaW1wb3J0YW50OyBoZWlnaHQ6IGF1dG8gIWltcG9ydGFudDsgfQogICAgICAgIH0KCiAgICAgICAgLyogUGhvbmUgaGVsZCBzaWRld2F5czogcGxlbnR5IG9mIHdpZHRoLCBhbG1vc3Qgbm8gaGVpZ2h0LiBOYXJyb3cgdGhlCiAgICAgICAgICAgZHJhd2VyIHNvIGl0IGRvZXMgbm90IHN3YWxsb3cgdGhlIHNjcmVlbiwgYW5kIGNsYXcgYmFjayB2ZXJ0aWNhbAogICAgICAgICAgIHNwYWNlIGZyb20gdGhlIGhlYWRlciBhbmQgdGhlIG5hdiByb3dzLiAqLwogICAgICAgIEBtZWRpYSAobWF4LWhlaWdodDogNTk5cHgpIGFuZCAob3JpZW50YXRpb246IGxhbmRzY2FwZSkgewogICAgICAgICAgICAuY21zLXNpZGViYXIgeyB3aWR0aDogbWluKDQ1dncsIHZhcigtLXNiLXdpZHRoKSkgIWltcG9ydGFudDsgfQogICAgICAgICAgICAuY21zLXNpZGViYXIubWluaW1pemVkIHsgd2lkdGg6IG1pbig0NXZ3LCB2YXIoLS1zYi13aWR0aCkpICFpbXBvcnRhbnQ7IH0KICAgICAgICAgICAgLmNtcy1zaWRlYmFyIGEgeyBwYWRkaW5nLXRvcDogLjVyZW0gIWltcG9ydGFudDsgcGFkZGluZy1ib3R0b206IC41cmVtICFpbXBvcnRhbnQ7IH0KICAgICAgICAgICAgLmNtcy1zaWRlYmFyIC5uYXYtc2VjdGlvbiB7IHBhZGRpbmc6IC41cmVtIDEuMjVyZW0gLjJyZW0gIWltcG9ydGFudDsgfQogICAgICAgICAgICAuc2lkZWJhci1icmFuZCB7IHBhZGRpbmc6IC43NXJlbSAxLjI1cmVtICFpbXBvcnRhbnQ7IH0KICAgICAgICAgICAgLmNtcy1jb250ZW50IHsgcGFkZGluZzogLjc1cmVtIDFyZW0gMS41cmVtOyB9CiAgICAgICAgICAgIC5jbXMtc2VjdGlvbi1oZWFkZXIgeyBmbGV4LWRpcmVjdGlvbjogcm93OyBhbGlnbi1pdGVtczogY2VudGVyOyBmbGV4LXdyYXA6IHdyYXA7IH0KICAgICAgICAgICAgLmNtcy1zZWN0aW9uLWhlYWRlciA+IGRpdiB7IHdpZHRoOiBhdXRvOyBmbGV4OiAxIDEgYXV0bzsganVzdGlmeS1jb250ZW50OiBmbGV4LWVuZDsgfQogICAgICAgIH0KICAgICAgICAubW9iaWxlLW1lbnUtYnRuIHsKICAgICAgICAgICAgZGlzcGxheTogbm9uZTsgcG9zaXRpb246IGZpeGVkOyB0b3A6IDFyZW07IGxlZnQ6IDFyZW07CiAgICAgICAgICAgIHotaW5kZXg6IDk5OTsgYmFja2dyb3VuZDogdmFyKC0tc2ItYmcpOwogICAgICAgICAgICBjb2xvcjogI2ZmZjsgYm9yZGVyOiBub25lOyB3aWR0aDogMzhweDsgaGVpZ2h0OiAzOHB4OwogICAgICAgICAgICBib3JkZXItcmFkaXVzOiA4cHg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGp1c3RpZnktY29udGVudDogY2VudGVyOwogICAgICAgICAgICBjdXJzb3I6IHBvaW50ZXI7IGZvbnQtc2l6ZTogMXJlbTsKICAgICAgICB9CiAgICA8L3N0eWxlPgogICAgPHN0eWxlPgogICAgICAgIC8qIOKUgOKUgCBTaGFyZWQgU0VPIC8gR0VPIFNjb3JlIHN5c3RlbSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8KICAgICAgICAuc2VvLXNjb3JlLXJpbmcgewogICAgICAgICAgICBkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDoxNHB4O21hcmdpbi1ib3R0b206MTJweDsKICAgICAgICB9CiAgICAgICAgLnNlby1zY29yZS1jaXJjbGUgewogICAgICAgICAgICB3aWR0aDo2NHB4O2hlaWdodDo2NHB4O2JvcmRlci1yYWRpdXM6NTAlOwogICAgICAgICAgICBkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2p1c3RpZnktY29udGVudDpjZW50ZXI7CiAgICAgICAgICAgIGZvbnQtc2l6ZToxLjI1cmVtO2ZvbnQtd2VpZ2h0OjcwMDtjb2xvcjojZmZmOwogICAgICAgICAgICBmbGV4LXNocmluazowO3RyYW5zaXRpb246YmFja2dyb3VuZCAuM3M7CiAgICAgICAgfQogICAgICAgIC5zZW8tY2hlY2sgewogICAgICAgICAgICBkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6ZmxleC1zdGFydDtnYXA6OHB4OwogICAgICAgICAgICBmb250LXNpemU6MTIuNXB4O21hcmdpbi1ib3R0b206NXB4O2xpbmUtaGVpZ2h0OjEuNDsKICAgICAgICB9CiAgICAgICAgLnNlby1jaGVjayAuaWMgeyBmbGV4LXNocmluazowO2ZvbnQtc2l6ZToxM3B4O21hcmdpbi10b3A6MXB4OyB9CiAgICAgICAgLnNlby1jaGVjay5vayAuaWM6OmJlZm9yZSB7IGNvbnRlbnQ6IuKclCI7Y29sb3I6IzJlOWU1YjsgfQogICAgICAgIC5zZW8tY2hlY2suYmFkIC5pYzo6YmVmb3JlIHsgY29udGVudDoi4pyWIjtjb2xvcjojZDk1MzRmOyB9CiAgICAgICAgLmNoYXItY291bnRlciB7IGZvbnQtc2l6ZToxMXB4O2NvbG9yOiM4ODg7bWFyZ2luLXRvcDozcHg7IH0KICAgICAgICAuY2hhci1jb3VudGVyLmdvb2QgeyBjb2xvcjojMmU5ZTViOyB9CiAgICAgICAgLmNoYXItY291bnRlci53YXJuIHsgY29sb3I6I2UwYTcyZTsgfQogICAgICAgIC5jaGFyLWNvdW50ZXIuYmFkICB7IGNvbG9yOiNkOTUzNGY7IH0KICAgICAgICAvKiDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8KICAgIDwvc3R5bGU+CiAgICB7JSBibG9jayBleHRyYV9oZWFkICV9eyUgZW5kYmxvY2sgJX0KPC9oZWFkPgo8Ym9keT4KCjxidXR0b24gY2xhc3M9Im1vYmlsZS1tZW51LWJ0biIgb25jbGljaz0iZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2Ntc1NpZGViYXInKS5jbGFzc0xpc3QudG9nZ2xlKCdtb2JpbGUtb3BlbicpIj4KICAgIDxpIGNsYXNzPSJmYS1zb2xpZCBmYS1iYXJzIj48L2k+CjwvYnV0dG9uPgoKPGRpdiBjbGFzcz0iY21zLXNpZGViYXIiIGlkPSJjbXNTaWRlYmFyIj48c2NyaXB0PmlmKGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdjbXNTaWRlYmFyTWluaW1pemVkJyk9PT0nMScpe2RvY3VtZW50LmN1cnJlbnRTY3JpcHQucGFyZW50RWxlbWVudC5jbGFzc0xpc3QuYWRkKCdtaW5pbWl6ZWQnKTt9PC9zY3JpcHQ+CiAgICB7JSBsb2FkIHN0YXRpYyB0ZW5hbnRfdGFncyAlfQoKICAgIDxkaXYgY2xhc3M9InNpZGViYXItYnJhbmQiPgogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX2Rhc2hib2FyZCcgJX0iIGNsYXNzPSJicmFuZC1ob21lIiB0aXRsZT0iR28gdG8gdGhlIGRhc2hib2FyZCI+CiAgICAgICAgICAgIHslIGlmIHRlbmFudCBhbmQgdGVuYW50LmZhdmljb24gYW5kIHRlbmFudC5wayAhPSAwICV9CiAgICAgICAgICAgIDxkaXYgY2xhc3M9ImJyYW5kLW1hcmsiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0ie3sgdGVuYW50Lm5hbWUgfX0iCiAgICAgICAgICAgICAgICAgc3R5bGU9Ii13ZWJraXQtbWFzay1pbWFnZTp1cmwoJ3t7IHRlbmFudC5mYXZpY29uLnVybCB9fScpO21hc2staW1hZ2U6dXJsKCd7eyB0ZW5hbnQuZmF2aWNvbi51cmwgfX0nKSI+PC9kaXY+CiAgICAgICAgICAgIHslIGVsaWYgc2l0ZS5mYXZpY29uICV9CiAgICAgICAgICAgIDxkaXYgY2xhc3M9ImJyYW5kLW1hcmsiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0ie3sgc2l0ZS5zaXRlX25hbWUgfX0iCiAgICAgICAgICAgICAgICAgc3R5bGU9Ii13ZWJraXQtbWFzay1pbWFnZTp1cmwoJ3t7IHNpdGUuZmF2aWNvbi51cmwgfX0nKTttYXNrLWltYWdlOnVybCgne3sgc2l0ZS5mYXZpY29uLnVybCB9fScpIj48L2Rpdj4KICAgICAgICAgICAgeyUgZWxzZSAlfQogICAgICAgICAgICA8ZGl2IGNsYXNzPSJicmFuZC1pbml0aWFscyI+eyUgaWYgdGVuYW50IGFuZCB0ZW5hbnQucGsgIT0gMCAlfXt7IHRlbmFudC5wcmVmaXh8c2xpY2U6IjoyIiB9fXslIGVsc2UgJX17eyBjb21wYW55fHNsaWNlOiI6MiJ8dXBwZXIgfX17JSBlbmRpZiAlfTwvZGl2PgogICAgICAgICAgICB7JSBlbmRpZiAlfQogICAgICAgICAgICA8ZGl2IGNsYXNzPSJicmFuZC10ZXh0Ij4KICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9ImJyYW5kLW5hbWUiPnslIGlmIHRlbmFudCBhbmQgdGVuYW50Lm5hbWUgYW5kIHRlbmFudC5wayAhPSAwICV9e3sgdGVuYW50Lm5hbWUgfX17JSBlbHNlICV9e3sgY29tcGFueSB9fXslIGVuZGlmICV9PC9kaXY+CiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJicmFuZC1zdWIiPlBhbmVseyUgaWYgY21zX3ZlcnNpb24gJX0gJm5ic3A7dnt7IGNtc192ZXJzaW9uIH19eyUgZW5kaWYgJX08L2Rpdj4KICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgPC9hPgogICAgICAgIDxidXR0b24gY2xhc3M9InNpZGViYXItdG9nZ2xlIiBvbmNsaWNrPSJ0b2dnbGVTaWRlYmFyKCkiIHRpdGxlPSJDb2xsYXBzZSBzaWRlYmFyIj4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLWFuZ2xlcy1sZWZ0IiBpZD0ic2lkZWJhclRvZ2dsZUljb24iPjwvaT4KICAgICAgICA8L2J1dHRvbj4KICAgIDwvZGl2PgoKICAgIDxkaXYgY2xhc3M9InNpZGViYXItbmF2LXdyYXAiPgogICAgICAgIDxkaXYgY2xhc3M9Im5hdi1zZWN0aW9uIj5PdmVydmlldzwvZGl2PgogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX2Rhc2hib2FyZCcgJX0iCiAgICAgICAgICAgZGF0YS1sYWJlbD0iRGFzaGJvYXJkIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lID09ICdjbXNfZGFzaGJvYXJkJyAlfWFjdGl2ZXslIGVuZGlmICV9Ij4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLWdhdWdlIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5EYXNoYm9hcmQ8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIHslIGlmICdjcm0nfG1vZHVsZV9lbmFibGVkOnRlbmFudCBhbmQgY2FuX3NlY3Rpb24uZmluYW5jZSAlfQogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX2NybScgJX0iCiAgICAgICAgICAgZGF0YS1sYWJlbD0iQ1JNIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lID09ICdjbXNfY3JtJyAlfWFjdGl2ZXslIGVuZGlmICV9Ij4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLXN0b3JlIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5DUk08L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIHslIGVuZGlmICV9CiAgICAgICAgeyUgaWYgJ2FuYWx5dGljcyd8bW9kdWxlX2VuYWJsZWQ6dGVuYW50IGFuZCBjYW5fc2VjdGlvbi5hbmFseXRpY3MgJX0KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19hbmFseXRpY3MnICV9IgogICAgICAgICAgIGRhdGEtbGFiZWw9IkFuYWx5dGljcyIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSA9PSAnY21zX2FuYWx5dGljcycgJX1hY3RpdmV7JSBlbmRpZiAlfSI+CiAgICAgICAgICAgIDxpIGNsYXNzPSJmYS1zb2xpZCBmYS1jaGFydC1saW5lIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5BbmFseXRpY3M8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIHslIGVuZGlmICV9CgogICAgICAgIHslIGlmIGNhbl9zZWN0aW9uLmNvbnRlbnQgb3IgY2FuX3NlY3Rpb24uY29tbWVyY2UgJX0KICAgICAgICA8ZGl2IGNsYXNzPSJuYXYtc2VjdGlvbiI+Q29udGVudDwvZGl2PgogICAgICAgIHslIGlmICdob21lcGFnZSd8bW9kdWxlX2VuYWJsZWQ6dGVuYW50IGFuZCBjYW5fc2VjdGlvbi5jb250ZW50ICV9CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfaG9tZXBhZ2UnICV9IiBkYXRhLWxhYmVsPSJIb21lcGFnZSIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgJ2hvbWVwYWdlJyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtaG91c2UgbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPkhvbWVwYWdlPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICB7JSBlbmRpZiAlfQogICAgICAgIHslIGlmICdlY29tbWVyY2UnfG1vZHVsZV9lbmFibGVkOnRlbmFudCBhbmQgY2FuX3NlY3Rpb24uY29tbWVyY2UgJX0KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19wcm9kdWN0cycgJX0iCiAgICAgICAgICAgZGF0YS1sYWJlbD0iUHJvZHVjdHMiCiAgICAgICAgICAgY2xhc3M9InslIGlmICdwcm9kdWN0JyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtYm94IG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5Qcm9kdWN0czwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfc3Vic2NyaXB0aW9ucycgJX0iCiAgICAgICAgICAgZGF0YS1sYWJlbD0iU3Vic2NyaXB0aW9ucyIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgJ3N1YnNjcmlwdGlvbicgaW4gcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSAlfWFjdGl2ZXslIGVuZGlmICV9Ij4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLXJvdGF0ZSBuYXYtaWNvbiI+PC9pPjxzcGFuIGNsYXNzPSJuYXYtdGV4dCI+U3Vic2NyaXB0aW9uczwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgeyUgZW5kaWYgJX0KICAgICAgICB7JSBpZiAnaG9tZXBhZ2UnfG1vZHVsZV9lbmFibGVkOnRlbmFudCBhbmQgY2FuX3NlY3Rpb24uY29udGVudCAlfQogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX3NlcnZpY2VzJyAlfSIgZGF0YS1sYWJlbD0iU2VydmljZXMiCiAgICAgICAgICAgY2xhc3M9InslIGlmICdzZXJ2aWNlJyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtbGF5ZXItZ3JvdXAgbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPlNlcnZpY2VzPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICB7JSBlbmRpZiAlfQogICAgICAgIHslIGlmICdwb3J0Zm9saW8nfG1vZHVsZV9lbmFibGVkOnRlbmFudCBhbmQgY2FuX3NlY3Rpb24uY29udGVudCAlfQogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX3BvcnRmb2xpbycgJX0iIGRhdGEtbGFiZWw9IlBvcnRmb2xpbyIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgJ3BvcnRmb2xpbycgaW4gcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSAlfWFjdGl2ZXslIGVuZGlmICV9Ij4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLWJyaWVmY2FzZSBuYXYtaWNvbiI+PC9pPjxzcGFuIGNsYXNzPSJuYXYtdGV4dCI+UG9ydGZvbGlvPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICB7JSBlbmRpZiAlfQogICAgICAgIHslIGlmICdob21lcGFnZSd8bW9kdWxlX2VuYWJsZWQ6dGVuYW50IGFuZCBjYW5fc2VjdGlvbi5jb250ZW50ICV9CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfd2h5X2JveGVzJyAlfSIgZGF0YS1sYWJlbD0iV2h5IFVzIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAnd2h5JyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtc3F1YXJlLWNoZWNrIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5XaHkgVXM8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIHslIGVuZGlmICV9CiAgICAgICAgeyUgaWYgJ2JyYW5kcyd8bW9kdWxlX2VuYWJsZWQ6dGVuYW50IGFuZCBjYW5fc2VjdGlvbi5jb250ZW50ICV9CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfYnJhbmRzJyAlfSIgZGF0YS1sYWJlbD0iQnJhbmRzIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAnYnJhbmQnIGluIHJlcXVlc3QucmVzb2x2ZXJfbWF0Y2gudXJsX25hbWUgJX1hY3RpdmV7JSBlbmRpZiAlfSI+CiAgICAgICAgICAgIDxpIGNsYXNzPSJmYS1zb2xpZCBmYS1zaGFwZXMgbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPkJyYW5kczwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgeyUgZW5kaWYgJX0KICAgICAgICB7JSBpZiAnaW5zaWdodHMnfG1vZHVsZV9lbmFibGVkOnRlbmFudCBhbmQgY2FuX3NlY3Rpb24uY29udGVudCAlfQogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX2luc2lnaHRzJyAlfSIgZGF0YS1sYWJlbD0iSW5zaWdodHMiCiAgICAgICAgICAgY2xhc3M9InslIGlmICdpbnNpZ2h0JyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtbmV3c3BhcGVyIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5JbnNpZ2h0czwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgeyUgZW5kaWYgJX0KICAgICAgICB7JSBpZiAnZmFxJ3xtb2R1bGVfZW5hYmxlZDp0ZW5hbnQgYW5kIGNhbl9zZWN0aW9uLmNvbnRlbnQgJX0KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19mYXEnICV9IiBkYXRhLWxhYmVsPSJGQVEiCiAgICAgICAgICAgY2xhc3M9InslIGlmICdmYXEnIGluIHJlcXVlc3QucmVzb2x2ZXJfbWF0Y2gudXJsX25hbWUgJX1hY3RpdmV7JSBlbmRpZiAlfSI+CiAgICAgICAgICAgIDxpIGNsYXNzPSJmYS1zb2xpZCBmYS1jaXJjbGUtcXVlc3Rpb24gbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPkZBUTwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgeyUgZW5kaWYgJX0KICAgICAgICB7JSBlbmRpZiAlfQoKICAgICAgICB7JSBpZiAnbWVkaWEnfG1vZHVsZV9lbmFibGVkOnRlbmFudCBhbmQgY2FuX3NlY3Rpb24uY29udGVudCAlfQogICAgICAgIDxkaXYgY2xhc3M9Im5hdi1zZWN0aW9uIj5NZWRpYSBIdWI8L2Rpdj4KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19tZWRpYV9saWJyYXJ5JyAlfSIKICAgICAgICAgICBkYXRhLWxhYmVsPSJMaWJyYXJ5IgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAnbWVkaWEnIGluIHJlcXVlc3QucmVzb2x2ZXJfbWF0Y2gudXJsX25hbWUgYW5kICdjb2xsZWN0aW9uJyBub3QgaW4gcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSBhbmQgJ2NhdGVnb3InIG5vdCBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtcGhvdG8tZmlsbSBuYXYtaWNvbiI+PC9pPjxzcGFuIGNsYXNzPSJuYXYtdGV4dCI+TGlicmFyeTwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfbWVkaWFfY29sbGVjdGlvbnMnICV9IgogICAgICAgICAgIGRhdGEtbGFiZWw9IkNvbGxlY3Rpb25zIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAnY29sbGVjdGlvbicgaW4gcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSAlfWFjdGl2ZXslIGVuZGlmICV9Ij4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLWxheWVyLWdyb3VwIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5Db2xsZWN0aW9uczwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgeyUgZW5kaWYgJX0KCiAgICAgICAgeyUgaWYgJ2Vjb21tZXJjZSd8bW9kdWxlX2VuYWJsZWQ6dGVuYW50IGFuZCBjYW5fc2VjdGlvbi5jb21tZXJjZSBvciAnZWNvbW1lcmNlJ3xtb2R1bGVfZW5hYmxlZDp0ZW5hbnQgYW5kIGNhbl9zZWN0aW9uLmZpbmFuY2Ugb3IgJ2Vjb21tZXJjZSd8bW9kdWxlX2VuYWJsZWQ6dGVuYW50IGFuZCBjYW5fc2VjdGlvbi5zYWxlcyAlfQogICAgICAgIDxkaXYgY2xhc3M9Im5hdi1zZWN0aW9uIj5Db21tZXJjZTwvZGl2PgogICAgICAgIHslIGlmIGNhbl9zZWN0aW9uLnNhbGVzICV9CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfYXNzZXNzbWVudHMnICV9IgogICAgICAgICAgIGRhdGEtbGFiZWw9IkFzc2Vzc21lbnRzIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAnYXNzZXNzbWVudCcgaW4gcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSAlfWFjdGl2ZXslIGVuZGlmICV9Ij4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLWNsaXBib2FyZC1saXN0IG5hdi1pY29uIj48L2k+CiAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJuYXYtdGV4dCI+QXNzZXNzbWVudHM8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIHslIGVuZGlmICV9CiAgICAgICAgeyUgaWYgY2FuX3NlY3Rpb24uY29tbWVyY2UgJX0KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19vcmRlcnMnICV9IgogICAgICAgICAgIGRhdGEtbGFiZWw9Ik9yZGVycyIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgJ29yZGVyJyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtcmVjZWlwdCBuYXYtaWNvbiI+PC9pPjxzcGFuIGNsYXNzPSJuYXYtdGV4dCI+T3JkZXJzPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICB7JSBlbmRpZiAlfQogICAgICAgIHslIGlmIGNhbl9zZWN0aW9uLmZpbmFuY2UgJX0KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19leHBlbnNlcycgJX0iCiAgICAgICAgICAgZGF0YS1sYWJlbD0iRXhwZW5zZXMiCiAgICAgICAgICAgY2xhc3M9InslIGlmICdleHBlbnNlJyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtYXJyb3ctdHJlbmQtZG93biBuYXYtaWNvbiI+PC9pPjxzcGFuIGNsYXNzPSJuYXYtdGV4dCI+RXhwZW5zZXM8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX2VtYWlsX2xvZycgJX0iCiAgICAgICAgICAgZGF0YS1sYWJlbD0iQ29ycmVzcG9uZGVuY2VzIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAnZW1haWxfbG9nJyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtZW52ZWxvcGUgbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPkNvcnJlc3BvbmRlbmNlczwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgeyUgZW5kaWYgJX0KICAgICAgICB7JSBlbmRpZiAlfQoKICAgICAgICB7JSBpZiBjYW5fc2VjdGlvbi5zdXBwb3J0ICV9CiAgICAgICAgPGRpdiBjbGFzcz0ibmF2LXNlY3Rpb24iPlN1cHBvcnQ8L2Rpdj4KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc190aWNrZXRzJyAlfSIKICAgICAgICAgICBkYXRhLWxhYmVsPSJUaWNrZXRzIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAndGlja2V0JyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtdGlja2V0IG5hdi1pY29uIj48L2k+CiAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJuYXYtdGV4dCI+VGlja2V0czwvc3Bhbj4KICAgICAgICAgICAgeyUgaWYgbmV3X3RpY2tldF9jb3VudCAlfTxzcGFuIGNsYXNzPSJuYXYtYmFkZ2UiPnt7IG5ld190aWNrZXRfY291bnQgfX08L3NwYW4+eyUgZW5kaWYgJX0KICAgICAgICA8L2E+CiAgICAgICAgeyUgaWYgJ2NoYXQnfG1vZHVsZV9lbmFibGVkOnRlbmFudCBhbmQgY2FuX3NlY3Rpb24uc3VwcG9ydCAlfQogICAgICAgIHslIGlmIHRlbmFudCBhbmQgdGVuYW50LmNoYXRfZW5hYmxlZCAlfQogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX2NoYXRfbGl2ZScgJX0iIGRhdGEtbGFiZWw9IkxpdmUgQ2hhdCIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSA9PSAnY21zX2NoYXRfbGl2ZScgJX1hY3RpdmV7JSBlbmRpZiAlfSI+CiAgICAgICAgICAgIDxpIGNsYXNzPSJmYS1zb2xpZCBmYS1oZWFkc2V0IG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5MaXZlIENoYXQ8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIHslIGVuZGlmICV9CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfY2hhdCcgJX0/dGFiPXNlc3Npb25zIiBkYXRhLWxhYmVsPSJBSSBDaGF0IgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAnY2hhdCcgaW4gcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSBhbmQgcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSAhPSAnY21zX2NoYXRfbGl2ZScgYW5kIHJlcXVlc3QuR0VULnRhYiAhPSAnd2hhdHNhcHAnICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtcm9ib3QgbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPkFJIENoYXQ8L3NwYW4+CiAgICAgICAgICAgIHslIGlmIHRlbmFudCBhbmQgdGVuYW50LmNoYXRfZW5hYmxlZCAlfTxzcGFuIGNsYXNzPSJuYXYtZG90IG1zLWF1dG8iIHN0eWxlPSJ3aWR0aDo3cHg7aGVpZ2h0OjdweDtib3JkZXItcmFkaXVzOjUwJTtiYWNrZ3JvdW5kOiMxNmEzNGE7ZmxleC1zaHJpbms6MCI+PC9zcGFuPnslIGVuZGlmICV9CiAgICAgICAgPC9hPgogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX2NoYXQnICV9P3RhYj13aGF0c2FwcCIgZGF0YS1sYWJlbD0iV0EgQ2hhdCIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgJ2NoYXQnIGluIHJlcXVlc3QucmVzb2x2ZXJfbWF0Y2gudXJsX25hbWUgYW5kIHJlcXVlc3QuR0VULnRhYiA9PSAnd2hhdHNhcHAnICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtYnJhbmRzIGZhLXdoYXRzYXBwIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5XQSBDaGF0PC9zcGFuPgogICAgICAgICAgICB7JSBpZiB0ZW5hbnQgYW5kIHRlbmFudC5jaGF0X3doYXRzYXBwICV9PHNwYW4gY2xhc3M9Im5hdi1kb3QgbXMtYXV0byIgc3R5bGU9IndpZHRoOjdweDtoZWlnaHQ6N3B4O2JvcmRlci1yYWRpdXM6NTAlO2JhY2tncm91bmQ6IzE2YTM0YTtmbGV4LXNocmluazowIj48L3NwYW4+eyUgZW5kaWYgJX0KICAgICAgICA8L2E+CiAgICAgICAgeyUgZW5kaWYgJX0KICAgICAgICB7JSBlbmRpZiAlfQoKICAgICAgICB7JSBpZiBpc19mbGVldF9tYXN0ZXIgYW5kIGNhbl9zZWN0aW9uLnBsYXRmb3JtICV9CiAgICAgICAgPGRpdiBjbGFzcz0ibmF2LXNlY3Rpb24iPk1hcmtldHBsYWNlPC9kaXY+CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfcGx1Z2luX3VwZ3JhZGVzJyAlfSIgZGF0YS1sYWJlbD0iVXBncmFkZSIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgJ3BsdWdpbl91cGdyYWRlJyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtc2VydmVyIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5VcGdyYWRlPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19wbHVnaW5zJyAlfSIgZGF0YS1sYWJlbD0iUGx1Z2lucyIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSA9PSAnY21zX3BsdWdpbnMnIG9yIHJlcXVlc3QucmVzb2x2ZXJfbWF0Y2gudXJsX25hbWUgPT0gJ2Ntc19wbHVnaW5fYWRkJyBvciByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lID09ICdjbXNfcGx1Z2luX2VkaXQnICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtcHV6emxlLXBpZWNlIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5QbHVnaW5zPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICB7JSBlbmRpZiAlfQoKICAgICAgICB7JSBpZiBub3QgaXNfZmxlZXRfbWFzdGVyIGFuZCBjYW5fc2VjdGlvbi5wbGF0Zm9ybSAlfQogICAgICAgIDxkaXYgY2xhc3M9Im5hdi1zZWN0aW9uIj5NYXJrZXRwbGFjZTwvZGl2PgogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX3RlbmFudF9wbHVnaW5zJyAlfSN1cGdyYWRlIiBkYXRhLWxhYmVsPSJVcGdyYWRlIgogICAgICAgICAgIGNsYXNzPSIiPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtc2VydmVyIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5VcGdyYWRlPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc190ZW5hbnRfcGx1Z2lucycgJX0iIGRhdGEtbGFiZWw9IlBsdWdpbnMiCiAgICAgICAgICAgY2xhc3M9InslIGlmICdwbHVnaW4nIGluIHJlcXVlc3QucmVzb2x2ZXJfbWF0Y2gudXJsX25hbWUgJX1hY3RpdmV7JSBlbmRpZiAlfSI+CiAgICAgICAgICAgIDxpIGNsYXNzPSJmYS1zb2xpZCBmYS1wdXp6bGUtcGllY2UgbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPlBsdWdpbnM8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIHslIGVuZGlmICV9CgogICAgICAgIHslIGlmIGNhbl9zZWN0aW9uLnBsYXRmb3JtIG9yIGNhbl9zZWN0aW9uLnVzZXJzIG9yIGNhbl9zZWN0aW9uLnNldHRpbmdzICV9CiAgICAgICAgPGRpdiBjbGFzcz0ibmF2LXNlY3Rpb24iPkFkbWluPC9kaXY+CiAgICAgICAgeyUgaWYgaXNfZmxlZXRfbWFzdGVyIGFuZCBjYW5fc2VjdGlvbi5wbGF0Zm9ybSAlfQogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX3RlbmFudHMnICV9IiBkYXRhLWxhYmVsPSJUZW5hbnRzIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAndGVuYW50JyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtYnVpbGRpbmcgbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPlRlbmFudHM8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX2ZsZWV0JyAlfSIgZGF0YS1sYWJlbD0iRmxlZXQiCiAgICAgICAgICAgY2xhc3M9InslIGlmICdmbGVldCcgaW4gcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSAlfWFjdGl2ZXslIGVuZGlmICV9Ij4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLXNhdGVsbGl0ZS1kaXNoIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5GbGVldDwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfaGVhbHRoJyAlfSIgZGF0YS1sYWJlbD0iSGVhbHRoIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiAnaGVhbHRoJyBpbiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtaGVhcnQtcHVsc2UgbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPlNlcnZpY2UgSGVhbHRoPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICB7JSBlbmRpZiAlfQogICAgICAgIHslIGlmIGNhbl9zZWN0aW9uLnVzZXJzICV9CiAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfdXNlcnMnICV9IiBkYXRhLWxhYmVsPSJVc2VycyIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgJ3VzZXInIGluIHJlcXVlc3QucmVzb2x2ZXJfbWF0Y2gudXJsX25hbWUgJX1hY3RpdmV7JSBlbmRpZiAlfSI+CiAgICAgICAgICAgIDxpIGNsYXNzPSJmYS1zb2xpZCBmYS11c2VycyBuYXYtaWNvbiI+PC9pPjxzcGFuIGNsYXNzPSJuYXYtdGV4dCI+VXNlcnM8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIHslIGVuZGlmICV9CiAgICAgICAgeyUgaWYgY2FuX3NlY3Rpb24uc2V0dGluZ3MgJX0KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19zZXR0aW5ncycgJX0iIGRhdGEtbGFiZWw9IlNldHRpbmdzIgogICAgICAgICAgIGNsYXNzPSJ7JSBpZiByZXF1ZXN0LnJlc29sdmVyX21hdGNoLnVybF9uYW1lID09ICdjbXNfc2V0dGluZ3MnICV9YWN0aXZleyUgZW5kaWYgJX0iPgogICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtZ2VhciBuYXYtaWNvbiI+PC9pPjxzcGFuIGNsYXNzPSJuYXYtdGV4dCI+U2V0dGluZ3M8L3NwYW4+CiAgICAgICAgPC9hPgogICAgICAgIHslIGVuZGlmICV9CiAgICAgICAgeyUgaWYgY2FuX3NlY3Rpb24uc2V0dGluZ3MgYW5kICdjb25zZW50J3xtb2R1bGVfZW5hYmxlZDp0ZW5hbnQgJX0KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19jb25zZW50JyAlfSIgZGF0YS1sYWJlbD0iQ29va2llIENvbnNlbnQiCiAgICAgICAgICAgY2xhc3M9InslIGlmIHJlcXVlc3QucmVzb2x2ZXJfbWF0Y2gudXJsX25hbWUgPT0gJ2Ntc19jb25zZW50JyAlfWFjdGl2ZXslIGVuZGlmICV9Ij4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLWNvb2tpZS1iaXRlIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5Db29raWUgQ29uc2VudDwvc3Bhbj4KICAgICAgICA8L2E+CiAgICAgICAgeyUgZW5kaWYgJX0KICAgICAgICB7JSBpZiBjYW5fc2VjdGlvbi5wbGF0Zm9ybSAlfQogICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX2JhY2t1cCcgJX0iCiAgICAgICAgICAgZGF0YS1sYWJlbD0iQmFja3VwcyIKICAgICAgICAgICBjbGFzcz0ieyUgaWYgJ2JhY2t1cCcgaW4gcmVxdWVzdC5yZXNvbHZlcl9tYXRjaC51cmxfbmFtZSAlfWFjdGl2ZXslIGVuZGlmICV9Ij4KICAgICAgICAgICAgPGkgY2xhc3M9ImZhLXNvbGlkIGZhLWJveC1hcmNoaXZlIG5hdi1pY29uIj48L2k+PHNwYW4gY2xhc3M9Im5hdi10ZXh0Ij5CYWNrdXBzPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICA8YSBocmVmPSJ7JSB1cmwgJ2Ntc19zeXN0ZW1faW5mbycgJX0iCiAgICAgICAgICAgZGF0YS1sYWJlbD0iU3lzdGVtIEluZm8iCiAgICAgICAgICAgY2xhc3M9InslIGlmIHJlcXVlc3QucmVzb2x2ZXJfbWF0Y2gudXJsX25hbWUgPT0gJ2Ntc19zeXN0ZW1faW5mbycgJX1hY3RpdmV7JSBlbmRpZiAlfSI+CiAgICAgICAgICAgIDxpIGNsYXNzPSJmYS1zb2xpZCBmYS1taWNyb2NoaXAgbmF2LWljb24iPjwvaT48c3BhbiBjbGFzcz0ibmF2LXRleHQiPlN5c3RlbSBJbmZvPC9zcGFuPgogICAgICAgIDwvYT4KICAgICAgICB7JSBlbmRpZiAlfQogICAgICAgIHslIGVuZGlmICV9CgogICAgPC9kaXY+CgogICAgPGRpdiBjbGFzcz0ic2lkZWJhci1mb290ZXIiPgogICAgICAgIDxkaXYgY2xhc3M9InNpZGViYXItdXNlciI+CiAgICAgICAgICAgIDxhIGhyZWY9InslIHVybCAnY21zX3VzZXJfZWRpdCcgcmVxdWVzdC51c2VyLnBrICV9IiBzdHlsZT0iZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6LjZyZW07ZmxleDoxO292ZXJmbG93OmhpZGRlbjt0ZXh0LWRlY29yYXRpb246bm9uZTtvcGFjaXR5OjEiIHRpdGxlPSJNeSBQcm9maWxlIj4KICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InNpZGViYXItdXNlci1hdmF0YXIiPgogICAgICAgICAgICAgICAgICAgIHslIHdpdGggbmFtZT1yZXF1ZXN0LnVzZXIuZ2V0X2Z1bGxfbmFtZXxkZWZhdWx0OnJlcXVlc3QudXNlci51c2VybmFtZSAlfXt7IG5hbWV8c2xpY2U6IjoxInx1cHBlciB9fXslIGVuZHdpdGggJX0KICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0ic2lkZWJhci11c2VyLWluZm8iPgogICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InNpZGViYXItdXNlci1uYW1lIj57JSBmaXJzdG9mIHJlcXVlc3QudXNlci5nZXRfZnVsbF9uYW1lIHJlcXVlc3QudXNlci51c2VybmFtZSAlfTwvZGl2PgogICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9InNpZGViYXItdXNlci1yb2xlIj57eyByZXF1ZXN0LnVzZXIuZ2V0X3JvbGVfZGlzcGxheSB9fTwvZGl2PgogICAgICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgIDwvYT4KICAgICAgICAgICAgPGEgaHJlZj0ieyUgdXJsICdjbXNfbG9nb3V0JyAlfSIgY2xhc3M9InNpZGViYXItbG9nb3V0LWJ0biIgdGl0bGU9IkxvZ291dCI+CiAgICAgICAgICAgICAgICA8aSBjbGFzcz0iZmEtc29saWQgZmEtcmlnaHQtZnJvbS1icmFja2V0Ij48L2k+CiAgICAgICAgICAgIDwvYT4KICAgICAgICA8L2Rpdj4KICAgICAgICA8ZGl2IGNsYXNzPSJzaWRlYmFyLWNvcHlyaWdodCI+CiAgICAgICAgICAgICZjb3B5OzxzcGFuIGlkPSJjb3B5cmlnaHRZZWFyIj48L3NwYW4+IHslIGZpcnN0b2YgcGFuZWxfY3JlZGl0IHRlbmFudC5wcmltYXJ5X2RvbWFpbiB0ZW5hbnQubmFtZSAlfQogICAgICAgIDwvZGl2PgogICAgPC9kaXY+CjwvZGl2PgoKPGRpdiBjbGFzcz0iY21zLW1haW4iIGlkPSJjbXNNYWluIj48c2NyaXB0PmlmKGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdjbXNTaWRlYmFyTWluaW1pemVkJyk9PT0nMScpe2RvY3VtZW50LmN1cnJlbnRTY3JpcHQucGFyZW50RWxlbWVudC5jbGFzc0xpc3QuYWRkKCdzaWRlYmFyLW1pbmltaXplZCcpO308L3NjcmlwdD4KICAgIDxkaXYgY2xhc3M9ImNtcy1jb250ZW50Ij4KCgogICAgICAgIHslIGlmIG1lc3NhZ2VzICV9CiAgICAgICAgeyUgZm9yIG1lc3NhZ2UgaW4gbWVzc2FnZXMgJX0KICAgICAgICA8ZGl2IGNsYXNzPSJjbXMtYWxlcnQgY21zLWFsZXJ0LXslIGlmIG1lc3NhZ2UudGFncyA9PSAnZXJyb3InICV9ZXJyb3J7JSBlbGlmIG1lc3NhZ2UudGFncyA9PSAnd2FybmluZycgJX13YXJuaW5neyUgZWxpZiBtZXNzYWdlLnRhZ3MgPT0gJ3N1Y2Nlc3MnICV9c3VjY2Vzc3slIGVsc2UgJX1pbmZveyUgZW5kaWYgJX0iPgogICAgICAgICAgICB7JSBpZiBtZXNzYWdlLnRhZ3MgPT0gJ3N1Y2Nlc3MnICV9PGkgY2xhc3M9ImZhLXNvbGlkIGZhLWNpcmNsZS1jaGVjayBtZS0yIj48L2k+eyUgZWxpZiBtZXNzYWdlLnRhZ3MgPT0gJ2Vycm9yJyBvciBtZXNzYWdlLnRhZ3MgPT0gJ3dhcm5pbmcnICV9PGkgY2xhc3M9ImZhLXNvbGlkIGZhLXRyaWFuZ2xlLWV4Y2xhbWF0aW9uIG1lLTIiPjwvaT57JSBlbmRpZiAlfQogICAgICAgICAgICB7eyBtZXNzYWdlIH19CiAgICAgICAgPC9kaXY+CiAgICAgICAgeyUgZW5kZm9yICV9CiAgICAgICAgeyUgZW5kaWYgJX0KCiAgICAgICAgeyUgYmxvY2sgY21zX2NvbnRlbnQgJX17JSBlbmRibG9jayAlfQogICAgPC9kaXY+CjwvZGl2PgoKPHNjcmlwdCBzcmM9InslIHN0YXRpYyAnanMvYm9vdHN0cmFwLmJ1bmRsZS5taW4uanMnICV9Ij48L3NjcmlwdD4KPHNjcmlwdCBzcmM9Imh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vc29ydGFibGVqc0AxLjE1LjAvU29ydGFibGUubWluLmpzIj48L3NjcmlwdD4KPHNjcmlwdD4KICAgIC8vIENvcHlyaWdodCB5ZWFyCiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY29weXJpZ2h0WWVhcicpLnRleHRDb250ZW50ID0gbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpOwoKICAgIC8vIFNpZGViYXIgdG9nZ2xlCiAgICB2YXIgTUlOSU1JWkVEX0tFWSA9ICdjbXNTaWRlYmFyTWluaW1pemVkJzsKICAgIHZhciBzaWRlYmFyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2Ntc1NpZGViYXInKTsKICAgIHZhciBtYWluICAgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2Ntc01haW4nKTsKICAgIHZhciBpY29uICAgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3NpZGViYXJUb2dnbGVJY29uJyk7CgogICAgZnVuY3Rpb24gc2V0U2lkZWJhcihtaW5pbWl6ZWQpIHsKICAgICAgICBpZiAobWluaW1pemVkKSB7CiAgICAgICAgICAgIHNpZGViYXIuY2xhc3NMaXN0LmFkZCgnbWluaW1pemVkJyk7CiAgICAgICAgICAgIG1haW4uY2xhc3NMaXN0LmFkZCgnc2lkZWJhci1taW5pbWl6ZWQnKTsKICAgICAgICAgICAgaWNvbi5jbGFzc0xpc3QucmVwbGFjZSgnZmEtYW5nbGVzLWxlZnQnLCAnZmEtYW5nbGVzLXJpZ2h0Jyk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgc2lkZWJhci5jbGFzc0xpc3QucmVtb3ZlKCdtaW5pbWl6ZWQnKTsKICAgICAgICAgICAgbWFpbi5jbGFzc0xpc3QucmVtb3ZlKCdzaWRlYmFyLW1pbmltaXplZCcpOwogICAgICAgICAgICBpY29uLmNsYXNzTGlzdC5yZXBsYWNlKCdmYS1hbmdsZXMtcmlnaHQnLCAnZmEtYW5nbGVzLWxlZnQnKTsKICAgICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gdG9nZ2xlU2lkZWJhcigpIHsKICAgICAgICB2YXIgbWluaW1pemVkID0gIXNpZGViYXIuY2xhc3NMaXN0LmNvbnRhaW5zKCdtaW5pbWl6ZWQnKTsKICAgICAgICBzZXRTaWRlYmFyKG1pbmltaXplZCk7CiAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oTUlOSU1JWkVEX0tFWSwgbWluaW1pemVkID8gJzEnIDogJzAnKTsKICAgIH0KCiAgICAvLyBSZXN0b3JlIHN0YXRlIG9uIGxvYWQKICAgIGlmIChsb2NhbFN0b3JhZ2UuZ2V0SXRlbShNSU5JTUlaRURfS0VZKSA9PT0gJzEnKSB7CiAgICAgICAgc2V0U2lkZWJhcih0cnVlKTsKICAgIH0KCiAgICAvLyDilIDilIAgU2lkZWJhciBzY3JvbGwgcGVyc2lzdGVuY2Ug4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACiAgICB2YXIgU0NST0xMX0tFWSA9ICdjbXNTaWRlYmFyU2Nyb2xsJzsKICAgIHZhciBuYXZXcmFwID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNpZGViYXItbmF2LXdyYXAnKTsKICAgIGlmIChuYXZXcmFwKSB7CiAgICAgICAgdmFyIHNhdmVkID0gbG9jYWxTdG9yYWdlLmdldEl0ZW0oU0NST0xMX0tFWSk7CiAgICAgICAgaWYgKHNhdmVkKSB7CiAgICAgICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZShmdW5jdGlvbigpIHsKICAgICAgICAgICAgICAgIG5hdldyYXAuc2Nyb2xsVG9wID0gcGFyc2VJbnQoc2F2ZWQsIDEwKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIG5hdldyYXAuYWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgZnVuY3Rpb24gKCkgewogICAgICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbShTQ1JPTExfS0VZLCBuYXZXcmFwLnNjcm9sbFRvcCk7CiAgICAgICAgfSwgeyBwYXNzaXZlOiB0cnVlIH0pOwogICAgfQoKICAgIC8vIOKUgOKUgCBEcmFnLXRvLXJlb3JkZXIgaGVscGVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICAgLy8gVXNhZ2U6IGluaXREcmFnU29ydCgnI3Rib2R5LWlkJywgJ01vZGVsTmFtZScsICcvY21zL3NvcnQvJykKICAgIGZ1bmN0aW9uIGluaXREcmFnU29ydCh0Ym9keVNlbGVjdG9yLCBtb2RlbE5hbWUsIHNvcnRVcmwsIGNzcmZUb2tlbikgewogICAgICAgIHZhciB0Ym9keSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGJvZHlTZWxlY3Rvcik7CiAgICAgICAgaWYgKCF0Ym9keSkgcmV0dXJuOwogICAgICAgIFNvcnRhYmxlLmNyZWF0ZSh0Ym9keSwgewogICAgICAgICAgICBoYW5kbGU6ICcuZHJhZy1oYW5kbGUnLAogICAgICAgICAgICBhbmltYXRpb246IDE1MCwKICAgICAgICAgICAgZ2hvc3RDbGFzczogJ2RyYWctZ2hvc3QnLAogICAgICAgICAgICBvbkVuZDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICB2YXIgb3JkZXIgPSBBcnJheS5mcm9tKHRib2R5LnF1ZXJ5U2VsZWN0b3JBbGwoJ3RyW2RhdGEtaWRdJykpLm1hcChmdW5jdGlvbihyKXsgcmV0dXJuIHIuZGF0YXNldC5pZDsgfSk7CiAgICAgICAgICAgICAgICBmZXRjaChzb3J0VXJsLCB7CiAgICAgICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsCiAgICAgICAgICAgICAgICAgICAgaGVhZGVyczogeydDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsICdYLUNTUkZUb2tlbic6IGNzcmZUb2tlbn0sCiAgICAgICAgICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe21vZGVsOiBtb2RlbE5hbWUsIG9yZGVyOiBvcmRlcn0pCiAgICAgICAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uKHIpeyByZXR1cm4gci5qc29uKCk7IH0pLnRoZW4oZnVuY3Rpb24oZCl7CiAgICAgICAgICAgICAgICAgICAgaWYgKCFkLm9rKSBjb25zb2xlLndhcm4oJ1NvcnQgZmFpbGVkOicsIGQuZXJyb3IpOwogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKICAgIH0KPC9zY3JpcHQ+CjxzdHlsZT4KLmRyYWctaGFuZGxlIHsgY3Vyc29yOiBncmFiOyB0ZXh0LWFsaWduOiBjZW50ZXI7IGNvbG9yOiAjOTRhM2I4OyB3aWR0aDogMzJweDsgfQouZHJhZy1oYW5kbGU6YWN0aXZlIHsgY3Vyc29yOiBncmFiYmluZzsgfQouZHJhZy1naG9zdCB7IGJhY2tncm91bmQ6ICNmMGY0ZjggIWltcG9ydGFudDsgb3BhY2l0eTogLjc7IH0KPC9zdHlsZT4KeyUgYmxvY2sgZXh0cmFfanMgJX17JSBlbmRibG9jayAlfQoKPHN0eWxlPgogIC8qIEFMVCB0ZXh0IGlzIGNhcHBlZCBhdCAxMjUgY2hhcmFjdGVycy4gVGhlIGNvdW50ZXIgYW5kIHRoZSByZWQgc3RhdGUgbGl2ZQogICAgIGhlcmUgaW4gdGhlIGJhc2UgcmF0aGVyIHRoYW4gb24gZWFjaCBwYWdlLCBzbyBldmVyeSBBTFQgYm94IGluIHRoZSBwYW5lbCwKICAgICBpbmNsdWRpbmcgb25lcyBhZGRlZCBsYXRlciwgYmVoYXZlcyB0aGUgc2FtZSB3aXRob3V0IGJlaW5nIHdpcmVkIHVwLiAqLwogIC5hbHQtY291bnQgeyBmb250LXNpemU6LjcycmVtOyBjb2xvcjp2YXIoLS1jbXMtbXV0ZWQpOyBtYXJnaW4tdG9wOi4ycmVtOyB9CiAgLmFsdC1jb3VudC5vdmVyIHsgY29sb3I6I2ZmNDA0YjsgZm9udC13ZWlnaHQ6NzAwOyB9CiAgaW5wdXQuYWx0LW92ZXIgeyBib3JkZXItY29sb3I6I2ZmNDA0YiAhaW1wb3J0YW50OyBiYWNrZ3JvdW5kOiNmZmY1ZjU7IH0KPC9zdHlsZT4KPHNjcmlwdD4KKGZ1bmN0aW9uIGFsdExpbWl0KCkgewogIGNvbnN0IE1BWCA9IDEyNTsKICAvLyBtYXhsZW5ndGggaXMgZGVsaWJlcmF0ZWx5IG5vdCB1c2VkOiBpdCBzdG9wcyB0eXBpbmcgd2l0aCBubyBleHBsYW5hdGlvbi4KICAvLyBUeXBpbmcgcGFzdCB0aGUgbGltaXQgaXMgYWxsb3dlZCwgc2hvd24gaW4gcmVkLCBhbmQgcmVmdXNlZCBvbiBzYXZlLgogIGNvbnN0IGJveGVzID0gWy4uLmRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ2lucHV0W25hbWUkPSJhbHQiXSwgaW5wdXRbbmFtZSQ9Il9hbHQiXSwgaW5wdXRbbmFtZT0iaW1hZ2VfYWx0Il0nKV07CiAgaWYgKCFib3hlcy5sZW5ndGgpIHJldHVybjsKCiAgYm94ZXMuZm9yRWFjaChmdW5jdGlvbiAoYm94KSB7CiAgICBib3gucmVtb3ZlQXR0cmlidXRlKCdtYXhsZW5ndGgnKTsKCiAgICBjb25zdCBjb3VudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpOwogICAgY291bnQuY2xhc3NOYW1lID0gJ2FsdC1jb3VudCc7CiAgICBib3guaW5zZXJ0QWRqYWNlbnRFbGVtZW50KCdhZnRlcmVuZCcsIGNvdW50KTsKCiAgICBmdW5jdGlvbiByZW5kZXIoKSB7CiAgICAgIGNvbnN0IG4gPSBib3gudmFsdWUubGVuZ3RoOwogICAgICBjb25zdCBvdmVyID0gbiA+IE1BWDsKICAgICAgY291bnQudGV4dENvbnRlbnQgPSBuICsgJyAvICcgKyBNQVggKyAob3ZlciA/ICcgIHRvbyBsb25nIGJ5ICcgKyAobiAtIE1BWCkgOiAnJyk7CiAgICAgIGNvdW50LmNsYXNzTGlzdC50b2dnbGUoJ292ZXInLCBvdmVyKTsKICAgICAgYm94LmNsYXNzTGlzdC50b2dnbGUoJ2FsdC1vdmVyJywgb3Zlcik7CiAgICB9CgogICAgYm94LmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgcmVuZGVyKTsKICAgIHJlbmRlcigpOwogIH0pOwoKICAvLyBSZWZ1c2UgdGhlIHNhdmUgcmF0aGVyIHRoYW4gc2lsZW50bHkgdHJpbW1pbmcsIHNvIG5vdGhpbmcgaXMgbG9zdCB3aXRob3V0CiAgLy8gdGhlIHBlcnNvbiBzZWVpbmcgaXQuCiAgYm94ZXMuZm9yRWFjaChmdW5jdGlvbiAoYm94KSB7CiAgICBjb25zdCBmb3JtID0gYm94LmNsb3Nlc3QoJ2Zvcm0nKTsKICAgIGlmICghZm9ybSB8fCBmb3JtLmRhdGFzZXQuYWx0R3VhcmQpIHJldHVybjsKICAgIGZvcm0uZGF0YXNldC5hbHRHdWFyZCA9ICcxJzsKICAgIGZvcm0uYWRkRXZlbnRMaXN0ZW5lcignc3VibWl0JywgZnVuY3Rpb24gKGUpIHsKICAgICAgY29uc3QgYmFkID0gYm94ZXMuZmlsdGVyKGZ1bmN0aW9uIChiKSB7IHJldHVybiBiLmNsb3Nlc3QoJ2Zvcm0nKSA9PT0gZm9ybSAmJiBiLnZhbHVlLmxlbmd0aCA+IE1BWDsgfSk7CiAgICAgIGlmICghYmFkLmxlbmd0aCkgcmV0dXJuOwogICAgICBlLnByZXZlbnREZWZhdWx0KCk7CiAgICAgIGJhZFswXS5mb2N1cygpOwogICAgICBiYWRbMF0uc2Nyb2xsSW50b1ZpZXcoeyBibG9jazogJ2NlbnRlcicsIGJlaGF2aW9yOiAnc21vb3RoJyB9KTsKICAgICAgYWxlcnQoJ0FMVCB0ZXh0IG11c3QgYmUgMTI1IGNoYXJhY3RlcnMgb3IgZmV3ZXIuIE9uZSBvZiB0aGUgYm94ZXMgaXMgJyArCiAgICAgICAgICAgIGJhZFswXS52YWx1ZS5sZW5ndGggKyAnIGNoYXJhY3RlcnMuJyk7CiAgICB9KTsKICB9KTsKfSkoKTsKPC9zY3JpcHQ+CjwvYm9keT4KPC9odG1sPgo=",
        "sha": "27258f4b889fdee851782f92f65b4ad9816de886cfc606d5c40e3b604fbdc1f5",
        "size": 64046
    }
}
SOURCE = "The Panel"

BASE = SITE['base']
STAMP = datetime.datetime.now().strftime('%Y%m%d-%H%M%S')
BACKUPS = os.path.join(BASE, 'deploy_backups')
MODE = sys.argv[1] if len(sys.argv) > 1 else '--check'


def say(msg=''):
    print(msg, flush=True)


def run(cmd):
    """Run a shell command and hand back the result.

    Written the long way on purpose. The server's system python is 3.6 and
    subprocess.run only grew capture_output in 3.7, so the short form dies
    with a TypeError after the files are already written, which leaves the
    service unrestarted and the deploy half done.
    """
    proc = subprocess.Popen(cmd, shell=True,
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, err = proc.communicate()

    class Result(object):
        pass

    r = Result()
    r.returncode = proc.returncode
    r.stdout = out.decode('utf-8', 'replace')
    r.stderr = err.decode('utf-8', 'replace')
    return r


def newest_backup():
    dirs = sorted(glob.glob(os.path.join(BACKUPS, '*')))
    return dirs[-1] if dirs else None


def restore(folder):
    n = 0
    for root, _dirs, names in os.walk(folder):
        for name in names:
            src = os.path.join(root, name)
            rel = os.path.relpath(src, folder)
            shutil.copyfile(src, os.path.join(BASE, rel))
            n += 1
    return n


def migrate():
    """Apply migrations before the restart, not after.

    A bundle that carries both a model and its migration has to migrate while
    the old code is still serving, otherwise the new model asks the database
    for a column that the migration has not added yet and every page 500s.
    Splitting that across two uploads is not a workflow, it is a trap.
    """
    cmd = ('cd %s && sudo -u %s venv/bin/python manage.py migrate --noinput'
           % (BASE, SITE['user']))
    say('  applying migrations')
    r = run(cmd)
    out = (r.stdout or '') + (r.stderr or '')
    for line in out.splitlines():
        line = line.strip()
        if line.startswith('Applying') or line.startswith('  Applying'):
            say('    ' + line)
    if r.returncode != 0:
        tail = [l for l in out.splitlines() if l.strip() and 'profiling:' not in l][-6:]
        return False, ' / '.join(t.strip() for t in tail)
    if 'No migrations to apply' in out:
        say('    nothing new to apply')
    return True, ''


def restart_and_check():
    say('  restarting %s' % SITE['service'])
    r = run('systemctl restart %s' % SITE['service'])
    if r.returncode != 0:
        return False, (r.stderr or '').strip()[:200]
    run('sleep 4')
    r = run('systemctl is-active %s' % SITE['service'])
    if r.stdout.strip() != 'active':
        return False, 'service is %s' % r.stdout.strip()
    # Both halves, because they fail independently. A missing module imported
    # only by the panel leaves the public site answering 200 while every page
    # of the CMS is a 500, and a check that looks at one of them calls that a
    # successful deploy.
    for label, url in (('public', SITE.get('health')), ('panel', SITE.get('panel'))):
        if not url:
            continue
        r = run('curl -s -o /dev/null -w "%%{http_code}" -m 20 %s' % url)
        code = r.stdout.strip()
        if code not in ('200', '301', '302'):
            return False, '%s returned %s' % (label, code)
        say('    %s %s' % (label, code))
    return True, 'both answered'


# ---- identity ------------------------------------------------------------
if not os.path.isdir(BASE):
    sys.exit('  REFUSING: %s does not exist on this machine' % BASE)

env_path = os.path.join(BASE, '.env')
if os.path.isfile(env_path):
    env = open(env_path, errors='ignore').read()
    if SITE['marker'] not in env:
        sys.exit('  REFUSING: %s is not mentioned in %s, wrong site'
                 % (SITE['marker'], env_path))
else:
    say('  note: no .env found, skipping the site identity check')

say('  site    : %s' % SITE['service'])
say('  target  : %s' % BASE)
say('  built   : from %s' % SOURCE)
say()

# ---- rollback ------------------------------------------------------------
if MODE == '--rollback':
    folder = newest_backup()
    if not folder:
        sys.exit('  nothing to roll back')
    n = restore(folder)
    say('  restored %d files from %s' % (n, os.path.basename(folder)))
    ok, detail = restart_and_check()
    say('  %s after rollback (%s)' % ('healthy' if ok else 'STILL BROKEN', detail))
    sys.exit(0 if ok else 1)

# ---- compare -------------------------------------------------------------
changed, identical, missing = [], [], []
for rel, meta in sorted(FILES.items()):
    live = os.path.join(BASE, rel)
    new = base64.b64decode(meta['b64'])
    if not os.path.exists(live):
        missing.append(rel)
        say('  NEW      %s  (%d bytes)' % (rel, meta['size']))
        continue
    cur = open(live, 'rb').read()
    if hashlib.sha256(cur).hexdigest() == meta['sha']:
        identical.append(rel)
        say('  same     %s' % rel)
        continue
    changed.append(rel)
    diff = list(difflib.unified_diff(
        cur.decode(errors='replace').splitlines(),
        new.decode(errors='replace').splitlines(),
        fromfile='live/' + rel, tofile='new/' + rel, lineterm='', n=2))
    adds = sum(1 for d in diff if d.startswith('+') and not d.startswith('+++'))
    dels = sum(1 for d in diff if d.startswith('-') and not d.startswith('---'))
    say('  CHANGED  %s  (+%d -%d)' % (rel, adds, dels))
    for line in diff[:400]:
        say('      ' + line)
    if len(diff) > 400:
        say('      ... %d more diff lines' % (len(diff) - 400))
    say()

say('  %d to write, %d already current, %d new'
    % (len(changed), len(identical), len(missing)))

if not changed and not missing:
    say('  nothing to do')
    sys.exit(0)

if MODE != '--apply':
    say()
    say('  Read the diff above. Nothing was written.')
    say('  Re-run with --apply when it is what you expect.')
    sys.exit(0)

# ---- validate ------------------------------------------------------------
for rel in changed + missing:
    new = base64.b64decode(FILES[rel]['b64']).decode(errors='replace')
    if rel.endswith('.py'):
        try:
            compile(new, rel, 'exec')
        except SyntaxError as exc:
            sys.exit('  REFUSING: %s does not compile, %s' % (rel, exc))
    if rel.endswith('.html'):
        for a, b in ((r'{%\s*if\b', r'{%\s*endif\s*%}'),
                     (r'{%\s*for\b', r'{%\s*endfor'),
                     (r'{%\s*block\b', r'{%\s*endblock')):
            if len(re.findall(a, new)) != len(re.findall(b, new)):
                sys.exit('  REFUSING: %s has unbalanced template tags' % rel)
        if '{#' in new:
            sys.exit('  REFUSING: %s contains a template comment' % rel)
say('  all files validate')

# ---- write ---------------------------------------------------------------
folder = os.path.join(BACKUPS, STAMP)
for rel in changed:
    dest = os.path.join(folder, rel)
    os.makedirs(os.path.dirname(dest), exist_ok=True)
    shutil.copyfile(os.path.join(BASE, rel), dest)
say('  backed up %d files to deploy_backups/%s' % (len(changed), STAMP))

for rel in changed + missing:
    live = os.path.join(BASE, rel)
    os.makedirs(os.path.dirname(live), exist_ok=True)
    open(live, 'wb').write(base64.b64decode(FILES[rel]['b64']))
    shutil.chown(live, SITE['user'], SITE['user'])
    say('  wrote %s' % rel)

if any('migrations/' in rel for rel in changed + missing):
    ok, detail = migrate()
    if not ok:
        say()
        say('  MIGRATION FAILED: %s' % detail)
        say('  rolling the files back, the database was not left half done')
        restore(folder)
        for rel in missing:
            p = os.path.join(BASE, rel)
            if os.path.exists(p):
                os.remove(p)
        restart_and_check()
        sys.exit(1)

ok, detail = restart_and_check()
if ok:
    say()
    say('  done, site healthy (%s)' % detail)
    sys.exit(0)

say()
say('  FAILED: %s' % detail)
say('  rolling back')
restore(folder)
for rel in missing:
    p = os.path.join(BASE, rel)
    if os.path.exists(p):
        os.remove(p)
ok2, detail2 = restart_and_check()
say('  %s after rollback (%s)' % ('recovered' if ok2 else 'STILL BROKEN', detail2))
sys.exit(1)
