#!/usr/bin/python3
"""Install the exact reviewed recovery-help UI; never communicate with a phone."""
import base64
import datetime
import hashlib
import json
import os
from pathlib import Path
import stat
import sys
import tempfile
import types
import uuid

TARGET = Path('/usr/local/lib/garry-mobile-reset/phone_reset.py')
CORE = Path('/usr/local/bin/garry-usb-update-core')
BACKUP = Path('/var/backups/garry-mobile-reset')
OLD_SHA = 'ef86b2ce437dd80292650f88d2e0a6974d524adc02ee8b4d1f7ed84e47d1b8c1'
NEW_SHA = 'e0eeadcf5947e870c35a34867466590ea88f7d9384b83eff6149f4150076d2f5'
PAYLOAD = 'IyEvdXNyL2Jpbi9weXRob24zCiIiIkdhcnJ5J3MgZXhwbGljaXQsIHNpbmdsZS10YXJnZXQgZmFjdG9yeSByZXN0b3JlIGZyb250IGVuZCBmb3IgTGludXguCgpPcGVuaW5nIHRoZSBVSSBhbmQgY2hlY2tpbmcgZGVwZW5kZW5jaWVzIG5ldmVyIGNoYW5nZXMgYSBkZXZpY2UuIERpc2NvdmVyeSB1c2VzCm9ubHkgTGludXggc3lzZnMgYW5kIGlyZWNvdmVyeSAtcS4gVGhlIGNvbnNvbGUgaXMgdGhlIG9ubHkgcmVzdG9yZSBlbnRyeSBwb2ludDsKaXQgYXNrcyBmb3IgdGhlIGZ1bGwgdGFyZ2V0IEVDSUQgYW5kIHJlLWRpc2NvdmVycyBpbW1lZGlhdGVseSBiZWZvcmUgZXhlY3V0aW9uLgoiIiIKaW1wb3J0IGFyZ3BhcnNlCmZyb20gY29udGV4dGxpYiBpbXBvcnQgY29udGV4dG1hbmFnZXIKZnJvbSBkYXRhY2xhc3NlcyBpbXBvcnQgZGF0YWNsYXNzCmltcG9ydCBvcwpmcm9tIHBhdGhsaWIgaW1wb3J0IFBhdGgKaW1wb3J0IHJlCmltcG9ydCBzaHV0aWwKaW1wb3J0IHN0YXQKaW1wb3J0IHN1YnByb2Nlc3MKaW1wb3J0IHN5cwppbXBvcnQgdGVtcGZpbGUKaW1wb3J0IHRocmVhZGluZwoKVkVSU0lPTiA9ICJyZWNvdmVyeS1oZWxwLTIwMjYwOTIzIgpSRVNUT1JFID0gIi91c3IvYmluL2lkZXZpY2VyZXN0b3JlIgpSRUNPVkVSWSA9ICIvdXNyL2Jpbi9pcmVjb3ZlcnkiClRFUk1JTkFMID0gIi91c3IvYmluL3hmY2U0LXRlcm1pbmFsIgpQWVRIT04gPSAiL3Vzci9iaW4vcHl0aG9uMyIKSU5TVEFMTEVEX1NDUklQVCA9ICIvdXNyL2xvY2FsL2xpYi9nYXJyeS1tb2JpbGUtcmVzZXQvcGhvbmVfcmVzZXQucHkiCklOU1RBTExFUiA9ICIvdXNyL2xvY2FsL2Jpbi9nYXJyeS1tb2JpbGUtaW5zdGFsbC10b29scyIKUEtFWEVDID0gIi91c3IvYmluL3BrZXhlYyIKVVNCX1NZU0ZTID0gUGF0aCgiL3N5cy9idXMvdXNiL2RldmljZXMiKQpNQVhfUVVFUllfQllURVMgPSA2NCAqIDEwMjQKUkVDT1ZFUllfUElEUyA9IHsiMTI4MCIsICIxMjgxIiwgIjEyODIiLCAiMTI4MyJ9CiMgQWR2aXNvcnkgVVNCIG1vZGUgbGFiZWxzIG9ubHkuIFRoZXNlIG5ldmVyIGF1dGhvcml6ZSBhIHJlc3RvcmU6IGEgcmVjb2duaXplZAojIFJlY292ZXJ5IFBJRCBwbHVzIGEgZnJlc2hseSBxdWVyaWVkLCB2YWxpZCBFQ0lEL3Byb2R1Y3QgaXMgc3RpbGwgcmVxdWlyZWQuCiMgSURzOiBsaWJpcmVjb3ZlcnkgaW5jbHVkZS9saWJpcmVjb3ZlcnkuaCBhbmQgdXNibXV4ZCBzcmMvdXNiLmguCkRGVV9QSURTID0geyIxMjI3IiwgImYwMTQifQpOT1JNQUxfVVNCX1BJRFMgPSB7ZiJ7bnVtYmVyOjA0eH0iIGZvciBudW1iZXIgaW4gcmFuZ2UoMHgxMjkwLCAweDEyYjApfQpQUk9EVUNUX1JFID0gcmUuY29tcGlsZShyImkoPzpQaG9uZXxQYWQpXGR7MSwzfSxcZHsxLDN9XFoiKQpMT0NLRURfQUNDRVNTT1JZX0hFTFAgPSAoCiAgICAiU2VlaW5nICdVbmxvY2sgaVBhZCB0byB1c2UgYWNjZXNzb3JpZXMnPyBUaGUgaVBhZCBpcyBzdGlsbCBvbiBpdHMgbm9ybWFsIGxvY2sgc2NyZWVuLiAiCiAgICAiRm9yIGFuIGVyYXNlLCB1c2UgaXRzIHBoeXNpY2FsIGJ1dHRvbnMgdG8gcmVhY2ggdGhlIGNhYmxlLWFuZC1jb21wdXRlciBSZWNvdmVyeSBzY3JlZW4uICIKICAgICJZb3UgZG8gbm90IG5lZWQgdGhlIHNjcmVlbiBwYXNzY29kZSBmb3IgdGhhdCBzdGVwLiIKKQpJUEFEX1JFQ09WRVJZX1NUQVJUID0gKAogICAgIkZpcnN0IGRpc2Nvbm5lY3QgdGhlIGlQYWQuIFBvd2VyIGl0IG9mZiB3aXRoIHRoZSBzbGlkZXIgYW5kIHdhaXQgb25lIG1pbnV0ZS4gIgogICAgIldpdGhvdXQgYSBIb21lIGJ1dHRvbiwgaG9sZCB0aGUgdG9wIGJ1dHRvbiBhbmQgZWl0aGVyIHZvbHVtZSBidXR0b24gdG8gc2hvdyB0aGUgc2xpZGVyOyAiCiAgICAid2l0aCBhIEhvbWUgYnV0dG9uLCBob2xkIHRoZSB0b3AgYnV0dG9uLiBUaGVuIGNvbm5lY3QgdGhlIGlQYWQgdG8gdGhpcyBjb21wdXRlciB3aXRoIGEgZGF0YSBjYWJsZS4iCikKSVBBRF9SRUNPVkVSWV9OT19IT01FID0gKAogICAgImlQYWQgd2l0aG91dCBhIEhvbWUgYnV0dG9uOiBxdWlja2x5IHByZXNzIGFuZCByZWxlYXNlIHRoZSB2b2x1bWUgYnV0dG9uIG5lYXJlc3QgdGhlIHRvcCBidXR0b24sICIKICAgICJ0aGVuIHF1aWNrbHkgcHJlc3MgYW5kIHJlbGVhc2UgdGhlIHZvbHVtZSBidXR0b24gZmFydGhlc3QgZnJvbSBpdC4gSG9sZCB0aGUgdG9wIGJ1dHRvbi4gIgogICAgIktlZXAgaG9sZGluZyBwYXN0IHRoZSBBcHBsZSBsb2dvIHVudGlsIHRoZSBjYWJsZS1hbmQtY29tcHV0ZXIgc2NyZWVuIGFwcGVhcnMsIHRoZW4gcmVsZWFzZS4iCikKSVBBRF9SRUNPVkVSWV9IT01FID0gKAogICAgImlQYWQgd2l0aCBhIEhvbWUgYnV0dG9uOiBob2xkIEhvbWUgYW5kIHRoZSB0b3AgKG9yIHNpZGUpIGJ1dHRvbiB0b2dldGhlci4gIgogICAgIktlZXAgaG9sZGluZyBwYXN0IHRoZSBBcHBsZSBsb2dvIHVudGlsIHRoZSBjYWJsZS1hbmQtY29tcHV0ZXIgc2NyZWVuIGFwcGVhcnMsIHRoZW4gcmVsZWFzZS4iCikKSVBBRF9SRUNPVkVSWV9GSU5JU0ggPSAoCiAgICAiTGVhdmUgaXQgY29ubmVjdGVkIGFuZCBzZWxlY3QgRGV0ZWN0IGRldmljZSBhYm92ZS4gSWYgdGhlIHBhc3Njb2RlIHNjcmVlbiByZXR1cm5zLCAiCiAgICAicG93ZXIgb2ZmIGFuZCByZXBlYXQuIEZvciBhbiBpUGhvbmUsIHVzZSB0aGUgaVBob25lIHJlY292ZXJ5IGJ1dHRvbnMgZ3VpZGUuICIKICAgICJSZWNvdmVyeSBtb2RlIHByZXBhcmVzIGFuIGVyYXNlOyBpdCBkb2VzIG5vdCByZW1vdmUgQWN0aXZhdGlvbiBMb2NrLiIKKQpHVUlERVMgPSB7CiAgICAiaVBob25lIHJlY292ZXJ5IGJ1dHRvbnMiOiAiaHR0cHM6Ly9zdXBwb3J0LmFwcGxlLmNvbS9lbi11cy8xMTg0MzAiLAogICAgImlQYWQgcmVjb3ZlcnkgYnV0dG9ucyI6ICJodHRwczovL3N1cHBvcnQuYXBwbGUuY29tL2VuLXVzLzExOTg1OCIsCiAgICAiR29vZ2xlIFBpeGVsIGZhY3RvcnkgcmVzZXQiOiAiaHR0cHM6Ly9zdXBwb3J0Lmdvb2dsZS5jb20vcGl4ZWxwaG9uZS9hbnN3ZXIvNDU5NjgzNiIsCiAgICAiU2Ftc3VuZyBHYWxheHkgZmFjdG9yeSByZXNldCI6ICJodHRwczovL3d3dy5zYW1zdW5nLmNvbS91ay9zdXBwb3J0L21vYmlsZS1kZXZpY2VzL2hvdy1kby1pLXBlcmZvcm0tZmFjdG9yeS1yZXNldC1vbi1teS1tb2JpbGUtZGV2aWNlLyIsCiAgICAiT3RoZXIgQW5kcm9pZCBtYW51ZmFjdHVyZXJzIjogImh0dHBzOi8vc3VwcG9ydC5nb29nbGUuY29tL2FuZHJvaWQvYW5zd2VyLzMwOTQ3NDIiLAogICAgIkFwcGxlIGFjY291bnQgcmVjb3ZlcnkiOiAiaHR0cHM6Ly9zdXBwb3J0LmFwcGxlLmNvbS9lbi11cy8xMDg5MzQiLAogICAgIkdvb2dsZSBhY2NvdW50IGFmdGVyIHJlc2V0IjogImh0dHBzOi8vc3VwcG9ydC5nb29nbGUuY29tL2FuZHJvaWQvYW5zd2VyLzk0NTkzNDYiLAp9CgoKY2xhc3MgUmVzZXRFcnJvcihFeGNlcHRpb24pOgogICAgIiIiQW4gYWN0aW9uYWJsZSwgc2FmZS10by1zaG93IHByb2JsZW07IGNvbnRhaW5zIG5vIHJhdyBwcm9jZXNzIG91dHB1dC4iIiIKCgpAZGF0YWNsYXNzKGZyb3plbj1UcnVlKQpjbGFzcyBBcHBsZVVTQjoKICAgIG5vZGU6IHN0cgogICAgcHJvZHVjdF9pZDogc3RyCgoKQGRhdGFjbGFzcyhmcm96ZW49VHJ1ZSkKY2xhc3MgVGFyZ2V0OgogICAgZWNpZDogc3RyCiAgICBwcm9kdWN0OiBzdHIKICAgIHVzYjogQXBwbGVVU0IKICAgIG1vZGU6IHN0ciA9ICJSZWNvdmVyeSIKCgpkZWYgbm9ybWFsaXplX2VjaWQodmFsdWUpOgogICAgIyBpcmVjb3ZlcnkgLXEgcHJpbnRzIGhleGFkZWNpbWFsLiBBbHdheXMgZm9yd2FyZCBhbiBleHBsaWNpdCAweCBwcmVmaXg6CiAgICAjIHZlcnNpb25zIG9mIHRoZSB0d28gdXBzdHJlYW0gdXRpbGl0aWVzIGRpZmZlciBpbiB1bnByZWZpeGVkLW51bWJlciBwYXJzaW5nLgogICAgaWYgbm90IGlzaW5zdGFuY2UodmFsdWUsIHN0cikgb3Igbm90IHJlLmZ1bGxtYXRjaChyIig/OjBbeFhdKT9bMC05YS1mQS1GXXsxLDE2fSIsIHZhbHVlKToKICAgICAgICByYWlzZSBSZXNldEVycm9yKCJUaGUgZGV2aWNlIGlkZW50aWZpZXIgaXMgaW52YWxpZC4gUmVjb25uZWN0IGFuZCBkZXRlY3QgYWdhaW4uIikKICAgIG51bWJlciA9IGludCh2YWx1ZSwgMTYpCiAgICBpZiBudW1iZXIgPT0gMDoKICAgICAgICByYWlzZSBSZXNldEVycm9yKCJUaGUgZGV2aWNlIGRpZCBub3QgcmVwb3J0IGEgdXNhYmxlIGlkZW50aWZpZXIuIikKICAgIHJldHVybiBmIjB4e251bWJlcjowMTZ4fSIKCgpkZWYgdHJ1c3RlZF9maWxlKHBhdGgsIGV4ZWN1dGFibGU9VHJ1ZSk6CiAgICAiIiJPbmx5IE9TL2FkbWluLW93bmVkIGZpbGVzLCBuZXZlciB1c2VyIFBBVEggb3Igd3JpdGFibGUgcmVwbGFjZW1lbnRzLiIiIgogICAgdHJ5OgogICAgICAgIHJlc29sdmVkID0gUGF0aChwYXRoKS5yZXNvbHZlKHN0cmljdD1UcnVlKQogICAgICAgIG1ldGFkYXRhID0gcmVzb2x2ZWQuc3RhdCgpCiAgICAgICAgaWYgbm90IHN0YXQuU19JU1JFRyhtZXRhZGF0YS5zdF9tb2RlKToKICAgICAgICAgICAgcmV0dXJuIEZhbHNlCiAgICAgICAgZm9yIGl0ZW0gaW4gKHJlc29sdmVkLCAqcmVzb2x2ZWQucGFyZW50cyk6CiAgICAgICAgICAgIG1ldGFkYXRhID0gaXRlbS5zdGF0KCkKICAgICAgICAgICAgaWYgbWV0YWRhdGEuc3RfdWlkICE9IDAgb3IgbWV0YWRhdGEuc3RfbW9kZSAmIDBvMDIyOgogICAgICAgICAgICAgICAgcmV0dXJuIEZhbHNlCiAgICAgICAgcmV0dXJuIG5vdCBleGVjdXRhYmxlIG9yIG9zLmFjY2VzcyhyZXNvbHZlZCwgb3MuWF9PSykKICAgIGV4Y2VwdCAoT1NFcnJvciwgUnVudGltZUVycm9yKToKICAgICAgICByZXR1cm4gRmFsc2UKCgpkZWYgcmVxdWlyZV90cnVzdGVkKCpwYXRocyk6CiAgICBpZiBhbnkobm90IHRydXN0ZWRfZmlsZShwYXRoKSBmb3IgcGF0aCBpbiBwYXRocyk6CiAgICAgICAgcmFpc2UgUmVzZXRFcnJvcigiUmVxdWlyZWQgc3lzdGVtIHRvb2xzIGFyZSBtaXNzaW5nIG9yIGhhdmUgdW5zYWZlIHBlcm1pc3Npb25zLiBVc2UgU2V0dXAgdG9vbHMgZmlyc3QuIikKCgpkZWYgcHJvY2Vzc19lbnYoZ3JhcGhpY2FsPUZhbHNlKToKICAgIGVudiA9IHsiUEFUSCI6ICIvdXNyL2JpbjovYmluIiwgIkxBTkciOiAiQy5VVEYtOCIsICJMQ19BTEwiOiAiQy5VVEYtOCIsICJIT01FIjogc3RyKFBhdGguaG9tZSgpKX0KICAgIGlmIGdyYXBoaWNhbDoKICAgICAgICBmb3Iga2V5IGluICgiRElTUExBWSIsICJXQVlMQU5EX0RJU1BMQVkiLCAiWEFVVEhPUklUWSIsICJEQlVTX1NFU1NJT05fQlVTX0FERFJFU1MiLCAiWERHX1JVTlRJTUVfRElSIik6CiAgICAgICAgICAgIGlmIGtleSBpbiBvcy5lbnZpcm9uOgogICAgICAgICAgICAgICAgZW52W2tleV0gPSBvcy5lbnZpcm9uW2tleV0KICAgIHJldHVybiBlbnYKCgpkZWYgcXVlcnkoYXJndik6CiAgICAiIiJSZWFkLW9ubHkgc3VicHJvY2Vzcywgbm8gc2hlbGwsIGJvdW5kZWQgcmV0dXJuZWQgb3V0cHV0LCBubyBzdGRpbi4iIiIKICAgIHRyeToKICAgICAgICB3aXRoIHRlbXBmaWxlLlRlbXBvcmFyeUZpbGUoKSBhcyBvdXQsIHRlbXBmaWxlLlRlbXBvcmFyeUZpbGUoKSBhcyBlcnI6CiAgICAgICAgICAgIHJlc3VsdCA9IHN1YnByb2Nlc3MucnVuKGFyZ3YsIHN0ZGluPXN1YnByb2Nlc3MuREVWTlVMTCwgc3Rkb3V0PW91dCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RkZXJyPWVyciwgdGltZW91dD0xMiwgY2hlY2s9RmFsc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWxsPUZhbHNlLCBlbnY9cHJvY2Vzc19lbnYoKSwgY2xvc2VfZmRzPVRydWUpCiAgICAgICAgICAgIGlmIG91dC50ZWxsKCkgPiBNQVhfUVVFUllfQllURVMgb3IgZXJyLnRlbGwoKSA+IE1BWF9RVUVSWV9CWVRFUzoKICAgICAgICAgICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIlRoZSBkZXZpY2UgdG9vbCByZXR1cm5lZCB1bmV4cGVjdGVkIG91dHB1dC4gTm90aGluZyB3YXMgZXJhc2VkLiIpCiAgICAgICAgICAgIG91dC5zZWVrKDApCiAgICAgICAgICAgIGVyci5zZWVrKDApCiAgICAgICAgICAgIHJldHVybiByZXN1bHQucmV0dXJuY29kZSwgb3V0LnJlYWQoKS5kZWNvZGUoInV0Zi04IiwgInJlcGxhY2UiKSwgZXJyLnJlYWQoKS5kZWNvZGUoInV0Zi04IiwgInJlcGxhY2UiKQogICAgZXhjZXB0IHN1YnByb2Nlc3MuVGltZW91dEV4cGlyZWQ6CiAgICAgICAgcmFpc2UgUmVzZXRFcnJvcigiRGV2aWNlIGRldGVjdGlvbiB0aW1lZCBvdXQuIENoZWNrIHRoZSBjYWJsZSBhbmQgcmVjb3Zlcnkgc2NyZWVuLCB0aGVuIHRyeSBhZ2Fpbi4iKSBmcm9tIE5vbmUKICAgIGV4Y2VwdCBPU0Vycm9yOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIlRoZSBzeXN0ZW0gZGV2aWNlIHRvb2wgY291bGQgbm90IHN0YXJ0LiBPcGVuIFNldHVwIHRvb2xzLCB0aGVuIHRyeSBhZ2Fpbi4iKSBmcm9tIE5vbmUKCgpkZWYgY2hlY2tfcmVzdG9yZV90b29scygpOgogICAgcmVxdWlyZV90cnVzdGVkKFJFU1RPUkUsIFJFQ09WRVJZKQogICAgZm9yIGJpbmFyeSwgcmVxdWlyZWQgaW4gKChSRVNUT1JFLCAoIi0tZXJhc2UiLCAiLS1sYXRlc3QiLCAiLS1lY2lkIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIChSRUNPVkVSWSwgKCItLXF1ZXJ5IiwgIi0tZWNpZCIpKSk6CiAgICAgICAgY29kZSwgb3V0cHV0LCBlcnJvciA9IHF1ZXJ5KFtiaW5hcnksICItLWhlbHAiXSkKICAgICAgICBpZiBjb2RlICE9IDAgb3IgYW55KGZsYWcgbm90IGluIG91dHB1dCArIGVycm9yIGZvciBmbGFnIGluIHJlcXVpcmVkKToKICAgICAgICAgICAgcmFpc2UgUmVzZXRFcnJvcigiSW5zdGFsbGVkIEFwcGxlIHRvb2xzIGRvIG5vdCBzdXBwb3J0IHRoaXMgcmVzdG9yZSBmbG93LiBPcGVuIFNldHVwIHRvb2xzIGZpcnN0LiIpCgoKZGVmIGFwcGxlX3VzYl9kZXZpY2VzKHJvb3Q9VVNCX1NZU0ZTKToKICAgIGlmIG5vdCByb290LmlzX2RpcigpOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIkxpbnV4IFVTQiBkaXNjb3ZlcnkgaXMgdW5hdmFpbGFibGUuIEJvb3QgR2FycnkgVVNCIG9uIGEgY29tcGF0aWJsZSBjb21wdXRlci4iKQogICAgZGV2aWNlcyA9IFtdCiAgICB0cnk6CiAgICAgICAgZm9yIG5vZGUgaW4gc29ydGVkKHJvb3QuaXRlcmRpcigpKToKICAgICAgICAgICAgIyBVU0IgaW50ZXJmYWNlIG5vZGVzIGFyZSBub3QgZGV2aWNlcyBhbmQgZG8gbm90IGhhdmUgaWRWZW5kb3IuCiAgICAgICAgICAgIHZlbmRvcl9wYXRoID0gbm9kZSAvICJpZFZlbmRvciIKICAgICAgICAgICAgaWYgbm90IHZlbmRvcl9wYXRoLmV4aXN0cygpOgogICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgaWYgdmVuZG9yX3BhdGgucmVhZF90ZXh0KCkuc3RyaXAoKS5sb3dlcigpICE9ICIwNWFjIjoKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIHByb2R1Y3RfaWQgPSAobm9kZSAvICJpZFByb2R1Y3QiKS5yZWFkX3RleHQoKS5zdHJpcCgpLmxvd2VyKCkKICAgICAgICAgICAgaWYgbm90IHJlLmZ1bGxtYXRjaChyIlswLTlhLWZdezR9IiwgcHJvZHVjdF9pZCk6CiAgICAgICAgICAgICAgICByYWlzZSBSZXNldEVycm9yKCJBcHBsZSBVU0IgaWRlbnRpdHkgY291bGQgbm90IGJlIHJlYWQgcmVsaWFibHkuIFJlY29ubmVjdCBhbmQgZGV0ZWN0IGFnYWluLiIpCiAgICAgICAgICAgIGRldmljZXMuYXBwZW5kKEFwcGxlVVNCKG5vZGUubmFtZSwgcHJvZHVjdF9pZCkpCiAgICBleGNlcHQgT1NFcnJvcjoKICAgICAgICByYWlzZSBSZXNldEVycm9yKCJVU0IgZGV2aWNlcyBjaGFuZ2VkIGR1cmluZyBkZXRlY3Rpb24uIFJlY29ubmVjdCBhbmQgZGV0ZWN0IGFnYWluLiIpIGZyb20gTm9uZQogICAgcmV0dXJuIHR1cGxlKGRldmljZXMpCgoKZGVmIG9ubHlfcmVjb3ZlcnlfdXNiKGRldmljZXMpOgogICAgaWYgbm90IGRldmljZXM6CiAgICAgICAgcmFpc2UgUmVzZXRFcnJvcigiTm8gQXBwbGUgVVNCIGRldmljZSBpcyB2aXNpYmxlIHRvIHRoaXMgY29tcHV0ZXIuIElmIHRoZSBpUGFkIHNheXMgJ1VubG9jayBpUGFkIHRvIHVzZSBhY2Nlc3NvcmllcycsIHVzZSB0aGUgUmVjb3Zlcnkgc3RlcHMgYmVsb3cgZmlyc3QuIFdoZW4gaXRzIGNhYmxlLWFuZC1jb21wdXRlciBzY3JlZW4gaXMgc2hvd2luZywgY2hlY2sgdGhlIGRhdGEgY2FibGUvVVNCIHBvcnQgYW5kIHNlbGVjdCBEZXRlY3QgZGV2aWNlIGFnYWluLiIpCiAgICBpZiBsZW4oZGV2aWNlcykgPiAxOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoZiJ7bGVuKGRldmljZXMpfSBBcHBsZSBVU0IgZGV2aWNlcyBhcmUgdmlzaWJsZS4gTGVhdmUgb25seSB0aGUgcGhvbmUgb3IgdGFibGV0IHRvIGVyYXNlIGNvbm5lY3RlZDsgZGlzY29ubmVjdCBvdGhlciBBcHBsZSBVU0IgZGV2aWNlcywgdGhlbiBzZWxlY3QgRGV0ZWN0IGRldmljZSBhZ2Fpbi4iKQogICAgaWYgZGV2aWNlc1swXS5wcm9kdWN0X2lkIGluIERGVV9QSURTOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIkFuIEFwcGxlIGRldmljZSBpcyBpbiBERlUgbW9kZSwgbm90IHRoZSBSZWNvdmVyeSBtb2RlIHVzZWQgaGVyZS4gRm9sbG93IHRoZSBtb2RlbCdzIHJlY292ZXJ5IGJ1dHRvbnMgZ3VpZGUgdW50aWwgdGhlIGNhYmxlLWFuZC1jb21wdXRlciBzY3JlZW4gYXBwZWFycywgdGhlbiBzZWxlY3QgRGV0ZWN0IGRldmljZSBhZ2Fpbi4iKQogICAgaWYgZGV2aWNlc1swXS5wcm9kdWN0X2lkIGluIE5PUk1BTF9VU0JfUElEUzoKICAgICAgICByYWlzZSBSZXNldEVycm9yKCJBbiBBcHBsZSBkZXZpY2UgaXMgdmlzaWJsZSBpbiBub3JtYWwgVVNCIG1vZGUsIG5vdCBSZWNvdmVyeSBtb2RlLiBJZiBpdCBzaG93cyBhIGxvY2sgc2NyZWVuIG9yICdVbmxvY2sgdG8gdXNlIGFjY2Vzc29yaWVzJywgZm9sbG93IHRoZSBSZWNvdmVyeSBzdGVwcyBiZWxvdy4gRGV0ZWN0IGFnYWluIG9ubHkgYWZ0ZXIgaXRzIGNhYmxlLWFuZC1jb21wdXRlciBzY3JlZW4gYXBwZWFycy4iKQogICAgaWYgZGV2aWNlc1swXS5wcm9kdWN0X2lkIG5vdCBpbiBSRUNPVkVSWV9QSURTOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIkFuIEFwcGxlIFVTQiBkZXZpY2UgaXMgdmlzaWJsZSwgYnV0IGl0cyBtb2RlL3Byb2R1Y3QgaXMgbm90IHN1cHBvcnRlZCBoZXJlLiBGb3IgYW4gaVBob25lIG9yIGlQYWQsIHVzZSB0aGUgbW9kZWwncyByZWNvdmVyeSBidXR0b25zIGd1aWRlIHRvIHJlYWNoIHRoZSBjYWJsZS1hbmQtY29tcHV0ZXIgc2NyZWVuLCB0aGVuIHNlbGVjdCBEZXRlY3QgZGV2aWNlIGFnYWluLiIpCiAgICByZXR1cm4gZGV2aWNlc1swXQoKCmRlZiBwYXJzZV9yZWNvdmVyeV9pbmZvKG91dHB1dCwgdXNiKToKICAgIHZhbHVlcyA9IHt9CiAgICBmb3IgbGluZSBpbiBvdXRwdXQuc3BsaXRsaW5lcygpOgogICAgICAgIGlmICI6IiBub3QgaW4gbGluZToKICAgICAgICAgICAgY29udGludWUKICAgICAgICBrZXksIHZhbHVlID0gbGluZS5zcGxpdCgiOiIsIDEpCiAgICAgICAgaWYga2V5IGluIHsiRUNJRCIsICJQUk9EVUNUIiwgIk1PREUiLCAiUFdORCJ9OgogICAgICAgICAgICBpZiBrZXkgaW4gdmFsdWVzOgogICAgICAgICAgICAgICAgcmFpc2UgUmVzZXRFcnJvcigiRGV2aWNlIGRldGVjdGlvbiByZXR1cm5lZCBhbWJpZ3VvdXMgaWRlbnRpdGllcy4gTm90aGluZyB3YXMgZXJhc2VkLiIpCiAgICAgICAgICAgIHZhbHVlc1trZXldID0gdmFsdWUuc3RyaXAoKQogICAgaWYgIlBXTkQiIGluIHZhbHVlczoKICAgICAgICByYWlzZSBSZXNldEVycm9yKCJUaGlzIHRvb2wgcmVxdWlyZXMgc3RvY2sgcmVjb3ZlcnkgbW9kZS4gVXNlIEFwcGxlJ3Mgb2ZmaWNpYWwgcmVjb3Zlcnkgc3VwcG9ydCBmb3IgdGhpcyBkZXZpY2UuIikKICAgIGlmIHZhbHVlcy5nZXQoIk1PREUiKSAhPSAiUmVjb3ZlcnkiOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIlRoZSBkZXZpY2UgaXMgbm90IGluIHN1cHBvcnRlZCBzdG9jayBSZWNvdmVyeSBtb2RlLiIpCiAgICBwcm9kdWN0ID0gdmFsdWVzLmdldCgiUFJPRFVDVCIsICIiKQogICAgaWYgbm90IFBST0RVQ1RfUkUuZnVsbG1hdGNoKHByb2R1Y3QpOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIlRoZSBjb25uZWN0ZWQgcHJvZHVjdCBpcyBub3QgYSByZWNvZ25pemVkIGlQaG9uZSBvciBpUGFkLiBVc2UgaXRzIG1hbnVmYWN0dXJlcidzIHJlY292ZXJ5IHByb2Nlc3MuIikKICAgIHJldHVybiBUYXJnZXQobm9ybWFsaXplX2VjaWQodmFsdWVzLmdldCgiRUNJRCIsICIiKSksIHByb2R1Y3QsIHVzYikKCgpkZWYgZGlzY292ZXJfdGFyZ2V0KCk6CiAgICByZXF1aXJlX3RydXN0ZWQoUkVDT1ZFUlkpCiAgICBiZWZvcmUgPSBhcHBsZV91c2JfZGV2aWNlcygpCiAgICB1c2IgPSBvbmx5X3JlY292ZXJ5X3VzYihiZWZvcmUpCiAgICBjb2RlLCBvdXRwdXQsIF8gPSBxdWVyeShbUkVDT1ZFUlksICItcSJdKQogICAgYWZ0ZXIgPSBhcHBsZV91c2JfZGV2aWNlcygpCiAgICBpZiBiZWZvcmUgIT0gYWZ0ZXI6CiAgICAgICAgcmFpc2UgUmVzZXRFcnJvcigiVVNCIGRldmljZXMgY2hhbmdlZCBkdXJpbmcgZGV0ZWN0aW9uLiBEZXRlY3QgdGhlIHRhcmdldCBhZ2Fpbi4iKQogICAgaWYgY29kZSAhPSAwOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIlRoZSBBcHBsZSByZWNvdmVyeSB0b29sIGNvdWxkIG5vdCByZWFkIHRoZSBkZXZpY2UuIENoZWNrIHJlY292ZXJ5IG1vZGUsIHRoZSBkYXRhIGNhYmxlIGFuZCBVU0IgcGVybWlzc2lvbnM7IHRoZW4gZGV0ZWN0IGFnYWluLiIpCiAgICByZXR1cm4gcGFyc2VfcmVjb3ZlcnlfaW5mbyhvdXRwdXQsIHVzYikKCgpkZWYgcmVzdG9yZV9hcmd2KGVjaWQpOgogICAgcmV0dXJuIFtSRVNUT1JFLCAiLS1lcmFzZSIsICItLWxhdGVzdCIsICItLWVjaWQiLCBub3JtYWxpemVfZWNpZChlY2lkKV0KCgpkZWYgcmV2YWxpZGF0ZV90YXJnZXQoZXhwZWN0ZWQpOgogICAgY3VycmVudCA9IGRpc2NvdmVyX3RhcmdldCgpCiAgICBpZiBjdXJyZW50ICE9IGV4cGVjdGVkOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIlRoZSBzZWxlY3RlZCBkZXZpY2Ugb3IgaXRzIFVTQiBjb25uZWN0aW9uIGNoYW5nZWQuIE5vdGhpbmcgd2FzIGVyYXNlZC4gQ2xvc2UgdGhpcyB3aW5kb3cgYW5kIGRldGVjdCBpdCBhZ2Fpbi4iKQogICAgcmV0dXJuIGN1cnJlbnQKCgpkZWYgdGVybWluYWxfYXJndihhcmd1bWVudHMsIHRpdGxlPSJQaG9uZSAmIFRhYmxldCBSZXNldCIpOgogICAgcmVxdWlyZV90cnVzdGVkKFRFUk1JTkFMLCBQWVRIT04pCiAgICBpZiBub3QgdHJ1c3RlZF9maWxlKElOU1RBTExFRF9TQ1JJUFQsIGV4ZWN1dGFibGU9RmFsc2UpOgogICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIkluc3RhbGwgdGhlIHNpZ25lZCBHYXJyeSBVU0IgdXBkYXRlIGJlZm9yZSB1c2luZyB0aGlzIGxhdW5jaGVyLiIpCiAgICByZXR1cm4gW1RFUk1JTkFMLCAiLS1kaXNhYmxlLXNlcnZlciIsICItLWhvbGQiLCAiLS10aXRsZT0iICsgdGl0bGUsCiAgICAgICAgICAgICItLWV4ZWN1dGUiLCBQWVRIT04sICItSSIsIElOU1RBTExFRF9TQ1JJUFQsICphcmd1bWVudHNdCgoKZGVmIGxhdW5jaF9yZXN0b3JlKHRhcmdldCk6CiAgICAjIE9wZW5pbmcgdGhlIHRlcm1pbmFsIG5ldmVyIHN0YXJ0cyBhIHJlc3RvcmU7IHRoZSBjb25zb2xlIGFza3MgZm9yIGFwcHJvdmFsLgogICAgYXJncyA9IFsiLS1yZXN0b3JlLWNvbnNvbGUiLCAiLS1lY2lkIiwgdGFyZ2V0LmVjaWQsICItLXByb2R1Y3QiLCB0YXJnZXQucHJvZHVjdCwKICAgICAgICAgICAgIi0tdXNiLW5vZGUiLCB0YXJnZXQudXNiLm5vZGUsICItLXVzYi1waWQiLCB0YXJnZXQudXNiLnByb2R1Y3RfaWRdCiAgICByZXR1cm4gc3VicHJvY2Vzcy5Qb3Blbih0ZXJtaW5hbF9hcmd2KGFyZ3MpLCBzaGVsbD1GYWxzZSwgZW52PXByb2Nlc3NfZW52KFRydWUpLCBjbG9zZV9mZHM9VHJ1ZSkKCgpkZWYgbGF1bmNoX2luc3RhbGxlcigpOgogICAgcmVxdWlyZV90cnVzdGVkKFRFUk1JTkFMLCBQS0VYRUMsIElOU1RBTExFUikKICAgIHJldHVybiBzdWJwcm9jZXNzLlBvcGVuKFtURVJNSU5BTCwgIi0tZGlzYWJsZS1zZXJ2ZXIiLCAiLS1ob2xkIiwgIi0tdGl0bGU9SW5zdGFsbCBBcHBsZSByZXN0b3JlIHRvb2xzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLS1leGVjdXRlIiwgUEtFWEVDLCBJTlNUQUxMRVIsICItLWluc3RhbGwiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWxsPUZhbHNlLCBlbnY9cHJvY2Vzc19lbnYoVHJ1ZSksIGNsb3NlX2Zkcz1UcnVlKQoKCkBjb250ZXh0bWFuYWdlcgpkZWYgcmVzdG9yZV93b3Jrc3BhY2UoKToKICAgICMgS2VlcCBkb3dubG9hZGVkIHN0b2NrIGZpcm13YXJlIGluIHRoZSB1c2VyJ3Mgd3JpdGFibGUgVVNCIHBlcnNpc3RlbmNlLgogICAgaW1wb3J0IGZjbnRsCiAgICBkaXJlY3RvcnkgPSBQYXRoLmhvbWUoKSAvICIubG9jYWwvc2hhcmUvZ2FycnktbW9iaWxlLXJlc2V0IgogICAgZGlyZWN0b3J5Lm1rZGlyKHBhcmVudHM9VHJ1ZSwgZXhpc3Rfb2s9VHJ1ZSwgbW9kZT0wbzcwMCkKICAgIGlmIGRpcmVjdG9yeS5pc19zeW1saW5rKCkgb3IgZGlyZWN0b3J5LnN0YXQoKS5zdF91aWQgIT0gb3MuZ2V0dWlkKCk6CiAgICAgICAgcmFpc2UgUmVzZXRFcnJvcigiVGhlIHJlc3RvcmUgd29ya2luZyBmb2xkZXIgaGFzIHVuc2FmZSBvd25lcnNoaXAuIikKICAgIG9zLmNobW9kKGRpcmVjdG9yeSwgMG83MDApCiAgICBmbGFncyA9IG9zLk9fQ1JFQVQgfCBvcy5PX1JEV1IgfCBvcy5PX05PRk9MTE9XCiAgICBkZXNjcmlwdG9yID0gb3Mub3BlbihkaXJlY3RvcnkgLyAicmVzdG9yZS5sb2NrIiwgZmxhZ3MsIDBvNjAwKQogICAgdHJ5OgogICAgICAgIHRyeToKICAgICAgICAgICAgZmNudGwuZmxvY2soZGVzY3JpcHRvciwgZmNudGwuTE9DS19FWCB8IGZjbnRsLkxPQ0tfTkIpCiAgICAgICAgZXhjZXB0IEJsb2NraW5nSU9FcnJvcjoKICAgICAgICAgICAgcmFpc2UgUmVzZXRFcnJvcigiQW5vdGhlciByZXN0b3JlIHdpbmRvdyBpcyBhbHJlYWR5IGFjdGl2ZS4gRmluaXNoIG9yIGNsb3NlIHRoYXQgd2luZG93IGZpcnN0LiIpIGZyb20gTm9uZQogICAgICAgIGZpcm13YXJlID0gZGlyZWN0b3J5IC8gImZpcm13YXJlIgogICAgICAgIGZpcm13YXJlLm1rZGlyKG1vZGU9MG83MDAsIGV4aXN0X29rPVRydWUpCiAgICAgICAgaWYgZmlybXdhcmUuaXNfc3ltbGluaygpIG9yIGZpcm13YXJlLnN0YXQoKS5zdF91aWQgIT0gb3MuZ2V0dWlkKCk6CiAgICAgICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIlRoZSBmaXJtd2FyZSBmb2xkZXIgaGFzIHVuc2FmZSBvd25lcnNoaXAuIikKICAgICAgICB5aWVsZCBmaXJtd2FyZQogICAgZmluYWxseToKICAgICAgICBvcy5jbG9zZShkZXNjcmlwdG9yKQoKCmRlZiBydW5fcmVzdG9yZV9jb25zb2xlKGV4cGVjdGVkLCBpbnB1dF9mbj1pbnB1dCk6CiAgICAiIiJGb3JlZ3JvdW5kIGV4ZWN1dGlvbiB3aXRoIG5hdGl2ZSBwcm9tcHRzIHJldGFpbmVkLiBUZXN0ZWQgd2l0aCBtb2NrcyBvbmx5LiIiIgogICAgY2hlY2tfcmVzdG9yZV90b29scygpCiAgICByZXZhbGlkYXRlX3RhcmdldChleHBlY3RlZCkKICAgIHdpdGggcmVzdG9yZV93b3Jrc3BhY2UoKSBhcyBmaXJtd2FyZToKICAgICAgICBmcmVlX2dpYiA9IHNodXRpbC5kaXNrX3VzYWdlKGZpcm13YXJlKS5mcmVlIC8gKDEwMjQgKiogMykKICAgICAgICBwcmludCgiR0FSUlkgfCBQSE9ORSAmIFRBQkxFVCBSRVNFVFxuIikKICAgICAgICBwcmludCgiRXhwZXJpbWVudGFsIExpbnV4IHJlc3RvcmU6IHBoeXNpY2FsLWRldmljZSB2YWxpZGF0aW9uIGlzIHBlbmRpbmcuIikKICAgICAgICBwcmludChmIlNlbGVjdGVkIGRldmljZToge2V4cGVjdGVkLnByb2R1Y3R9XG5FQ0lEOiB7ZXhwZWN0ZWQuZWNpZH1cblVTQiBjb25uZWN0aW9uOiB7ZXhwZWN0ZWQudXNiLm5vZGV9IikKICAgICAgICBwcmludCgiXG5UaGlzIGVyYXNlcyBhbGwgbG9jYWwgZGF0YSBhbmQgdGhlIHNjcmVlbiBwYXNzY29kZSBvbiB0aGF0IGRldmljZS4iKQogICAgICAgIHByaW50KCJBcHBsZSBBY3RpdmF0aW9uIExvY2sgbWF5IHN0aWxsIHJlcXVpcmUgdGhlIGxpbmtlZCBBcHBsZSBBY2NvdW50LiIpCiAgICAgICAgcHJpbnQoIkEgc2lnbmVkIHN0b2NrIGZpcm13YXJlIGRvd25sb2FkIGFuZCBhIHdvcmtpbmcgaW50ZXJuZXQgY29ubmVjdGlvbiBhcmUgcmVxdWlyZWQuIikKICAgICAgICBwcmludChmIldyaXRhYmxlIGZpcm13YXJlIHNwYWNlOiB7ZnJlZV9naWI6LjFmfSBHaUIuIFBsYW4gZm9yIGF0IGxlYXN0IDIwIEdpQjsgc29tZSBmaXJtd2FyZSBuZWVkcyBtb3JlLiIpCiAgICAgICAgcHJpbnQoIktlZXAgdGhlIGNvbXB1dGVyIHBvd2VyZWQgYW5kIHRoZSBkYXRhIGNhYmxlIGNvbm5lY3RlZCBkdXJpbmcgcmVzdG9yZS4iKQogICAgICAgIHBocmFzZSA9ICJFUkFTRSAiICsgZXhwZWN0ZWQuZWNpZAogICAgICAgIGlmIGlucHV0X2ZuKGYiXG5UbyBlcmFzZSB0aGlzIGV4YWN0IGRldmljZSwgdHlwZSB7cGhyYXNlfVxuPiAiKS5zdHJpcCgpICE9IHBocmFzZToKICAgICAgICAgICAgcHJpbnQoIkNhbmNlbGxlZC4gTm8gcmVzdG9yZSBjb21tYW5kIHdhcyBzdGFydGVkLiIpCiAgICAgICAgICAgIHJldHVybiAyCiAgICAgICAgIyBQZXJtaXNzaW9uL3Byb21wdCBkZWxheXMgbXVzdCBub3QgYWxsb3cgdGhlIG9yaWdpbmFsbHkgc2hvd24gdGFyZ2V0IHRvCiAgICAgICAgIyBiZWNvbWUgc3RhbGUuIE5vIG90aGVyIGRpYWxvZywgZG93bmxvYWQgb3Igd2FpdCBpbnRlcnZlbmVzIGFmdGVyIHRoaXMuCiAgICAgICAgcmVxdWlyZV90cnVzdGVkKFJFU1RPUkUsIFJFQ09WRVJZKQogICAgICAgIHJldmFsaWRhdGVfdGFyZ2V0KGV4cGVjdGVkKQogICAgICAgIHJlc3VsdCA9IHN1YnByb2Nlc3MucnVuKHJlc3RvcmVfYXJndihleHBlY3RlZC5lY2lkKSwgY3dkPXN0cihmaXJtd2FyZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW52PXByb2Nlc3NfZW52KCksIHNoZWxsPUZhbHNlLCBjaGVjaz1GYWxzZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbG9zZV9mZHM9VHJ1ZSkKICAgICAgICBpZiByZXN1bHQucmV0dXJuY29kZSA9PSAwOgogICAgICAgICAgICBwcmludCgiXG5UaGUgcmVzdG9yZSB0b29sIHJlcG9ydGVkIHN1Y2Nlc3MuIENvbmZpcm0gdGhlIHNldHVwIHNjcmVlbiBvbiB0aGUgZGV2aWNlLiIpCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcHJpbnQoIlxuVGhlIHJlc3RvcmUgdG9vbCByZXBvcnRlZCBmYWlsdXJlLiBLZWVwIHRoZSBlcnJvciB2aXNpYmxlIGFuZCB1c2UgQXBwbGUncyByZWNvdmVyeSBndWlkZSBiZWZvcmUgYW5vdGhlciBhdHRlbXB0LiIpCiAgICAgICAgcmV0dXJuIHJlc3VsdC5yZXR1cm5jb2RlCgoKZGVmIHJ1bl91aSgpOgogICAgaW1wb3J0IHRraW50ZXIgYXMgdGsKICAgIGZyb20gdGtpbnRlciBpbXBvcnQgbWVzc2FnZWJveCwgdHRrCiAgICBpbXBvcnQgd2ViYnJvd3NlcgoKICAgIHJvb3QgPSB0ay5UaygpCiAgICByb290LnRpdGxlKCJHYXJyeSB8IFBob25lICYgVGFibGV0IFJlc2V0IikKICAgIHJvb3QuZ2VvbWV0cnkoIjg2MHg2OTAiKQogICAgcm9vdC5taW5zaXplKDYyMCwgNTAwKQogICAgYmcsIHBhbmVsLCB0ZXh0LCBkaW0sIGFjY2VudCA9ICIjMDgxMTFmIiwgIiMxNDIyMzgiLCAiI2U3ZWVmYiIsICIjYWFiYmQzIiwgIiM2MWQ3Y2UiCiAgICByb290LmNvbmZpZ3VyZShiZz1iZykKICAgIHN0eWxlID0gdHRrLlN0eWxlKHJvb3QpCiAgICBzdHlsZS50aGVtZV91c2UoImNsYW0iKQogICAgc3R5bGUuY29uZmlndXJlKCJUTm90ZWJvb2siLCBiYWNrZ3JvdW5kPWJnLCBib3JkZXJ3aWR0aD0wKQogICAgc3R5bGUuY29uZmlndXJlKCJUTm90ZWJvb2suVGFiIiwgYmFja2dyb3VuZD1wYW5lbCwgZm9yZWdyb3VuZD10ZXh0LCBwYWRkaW5nPSgxOCwgOSkpCiAgICBzdHlsZS5tYXAoIlROb3RlYm9vay5UYWIiLCBiYWNrZ3JvdW5kPVsoInNlbGVjdGVkIiwgIiMyNDU2NmEiKV0pCiAgICBzdHlsZS5jb25maWd1cmUoIlRGcmFtZSIsIGJhY2tncm91bmQ9cGFuZWwpCiAgICBvdXRlciA9IHRrLkZyYW1lKHJvb3QsIGJnPWJnKQogICAgb3V0ZXIucGFjayhmaWxsPSJib3RoIiwgZXhwYW5kPVRydWUsIHBhZHg9MjAsIHBhZHk9MTYpCiAgICB0ay5MYWJlbChvdXRlciwgdGV4dD0iUEhPTkUgJiBUQUJMRVQgUkVTRVQiLCBiZz1iZywgZmc9YWNjZW50LCBmb250PSgiU2FucyIsIDExLCAiYm9sZCIpKS5wYWNrKGFuY2hvcj0idyIpCiAgICB0ay5MYWJlbChvdXRlciwgdGV4dD0iU3RhcnQgZnJlc2ggb24geW91ciBkZXZpY2UiLCBiZz1iZywgZmc9dGV4dCwgZm9udD0oIlNhbnMiLCAyMywgImJvbGQiKSkucGFjayhhbmNob3I9InciLCBwYWR5PSg0LCA4KSkKICAgIHRrLkxhYmVsKG91dGVyLCB0ZXh0PSJCb290IEdhcnJ5IFVTQiBvbiBhIGNvbXB1dGVyLCB0aGVuIGNvbm5lY3QgdGhlIHBob25lIHdpdGggYSBkYXRhIGNhYmxlLlxuVGhlIFVTQiBjYW5ub3QgcmVzZXQgYSBwaG9uZSBieSBpdHNlbGYuIiwgYmc9YmcsIGZnPWRpbSwganVzdGlmeT0ibGVmdCIsIGFuY2hvcj0idyIpLnBhY2soZmlsbD0ieCIpCiAgICB0YWJzID0gdHRrLk5vdGVib29rKG91dGVyKQogICAgdGFicy5wYWNrKGZpbGw9ImJvdGgiLCBleHBhbmQ9VHJ1ZSwgcGFkeT0oMTYsIDEyKSkKICAgIGRlZiBtYWtlX3RhYih0aXRsZSk6CiAgICAgICAgc2hlbGwgPSB0dGsuRnJhbWUodGFicykKICAgICAgICBjYW52YXMgPSB0ay5DYW52YXMoc2hlbGwsIGJnPXBhbmVsLCBoaWdobGlnaHR0aGlja25lc3M9MCkKICAgICAgICBzY3JvbGxiYXIgPSB0dGsuU2Nyb2xsYmFyKHNoZWxsLCBvcmllbnQ9InZlcnRpY2FsIiwgY29tbWFuZD1jYW52YXMueXZpZXcpCiAgICAgICAgY2FudmFzLmNvbmZpZ3VyZSh5c2Nyb2xsY29tbWFuZD1zY3JvbGxiYXIuc2V0KQogICAgICAgIHNjcm9sbGJhci5wYWNrKHNpZGU9InJpZ2h0IiwgZmlsbD0ieSIpCiAgICAgICAgY2FudmFzLnBhY2soc2lkZT0ibGVmdCIsIGZpbGw9ImJvdGgiLCBleHBhbmQ9VHJ1ZSkKICAgICAgICBib2R5ID0gdHRrLkZyYW1lKGNhbnZhcywgcGFkZGluZz0xOCkKICAgICAgICB3aW5kb3cgPSBjYW52YXMuY3JlYXRlX3dpbmRvdygoMCwgMCksIHdpbmRvdz1ib2R5LCBhbmNob3I9Im53IikKICAgICAgICBjYW52YXMuYmluZCgiPENvbmZpZ3VyZT4iLCBsYW1iZGEgZXZlbnQ6IGNhbnZhcy5pdGVtY29uZmlndXJlKHdpbmRvdywgd2lkdGg9ZXZlbnQud2lkdGgpKQogICAgICAgIGJvZHkuYmluZCgiPENvbmZpZ3VyZT4iLCBsYW1iZGEgZXZlbnQ6IGNhbnZhcy5jb25maWd1cmUoc2Nyb2xscmVnaW9uPWNhbnZhcy5iYm94KCJhbGwiKSkpCiAgICAgICAgdGFicy5hZGQoc2hlbGwsIHRleHQ9dGl0bGUpCiAgICAgICAgcmV0dXJuIGJvZHkKCiAgICBhcHBsZSwgYW5kcm9pZCwgc2V0dXAgPSAobWFrZV90YWIodGl0bGUpIGZvciB0aXRsZSBpbiAoImlQaG9uZSAvIGlQYWQiLCAiQW5kcm9pZCIsICJTZXR1cCAmIGhlbHAiKSkKCiAgICBkZWYgbGFiZWwoZnJhbWUsIHZhbHVlLCBjb2xvcj10ZXh0LCBib2xkPUZhbHNlKToKICAgICAgICB3aWRnZXQgPSB0ay5MYWJlbChmcmFtZSwgdGV4dD12YWx1ZSwgYmc9cGFuZWwsIGZnPWNvbG9yLCBqdXN0aWZ5PSJsZWZ0IiwgYW5jaG9yPSJ3IiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3cmFwbGVuZ3RoPTcyMCwgZm9udD0oIlNhbnMiLCAxMCwgImJvbGQiIGlmIGJvbGQgZWxzZSAibm9ybWFsIikpCiAgICAgICAgd2lkZ2V0LnBhY2soZmlsbD0ieCIsIHBhZHk9KDAsIDEwKSkKICAgICAgICAjIFJlc3BvbnNpdmUgd3JhcHBpbmcga2VlcHMgdGhlIGFjdGlvbnMgdXNhYmxlIG9uIHNtYWxsZXIgVVNCIGRpc3BsYXlzLgogICAgICAgIGZyYW1lLmJpbmQoIjxDb25maWd1cmU+IiwgbGFtYmRhIGV2ZW50LCB3PXdpZGdldDogdy5jb25maWd1cmUod3JhcGxlbmd0aD1tYXgoMjUwLCBldmVudC53aWR0aCAtIDQwKSksIGFkZD1UcnVlKQogICAgICAgIHJldHVybiB3aWRnZXQKCiAgICBkZWYgYnV0dG9uKGZyYW1lLCB0aXRsZSwgY2FsbGJhY2ssIHByaW1hcnk9RmFsc2UpOgogICAgICAgIHdpZGdldCA9IHRrLkJ1dHRvbihmcmFtZSwgdGV4dD10aXRsZSwgY29tbWFuZD1jYWxsYmFjaywgYmc9YWNjZW50IGlmIHByaW1hcnkgZWxzZSAiIzI2Mzk1MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZnPWJnIGlmIHByaW1hcnkgZWxzZSB0ZXh0LCBhY3RpdmViYWNrZ3JvdW5kPSIjODVlOGUwIiwgcmVsaWVmPSJmbGF0IiwgcGFkeD0xNCwgcGFkeT05KQogICAgICAgIHdpZGdldC5wYWNrKGFuY2hvcj0idyIsIHBhZHk9KDAsIDkpKQogICAgICAgIHJldHVybiB3aWRnZXQKCiAgICBkZWYgbGluayhmcmFtZSwgdGl0bGUpOgogICAgICAgIGJ1dHRvbihmcmFtZSwgdGl0bGUsIGxhbWJkYTogd2ViYnJvd3Nlci5vcGVuKEdVSURFU1t0aXRsZV0pKQoKICAgIGxhYmVsKGFwcGxlLCAiRXhwZXJpbWVudGFsIExpbnV4IHJlc3RvcmUg4oCUIHBoeXNpY2FsLWRldmljZSB2YWxpZGF0aW9uIHBlbmRpbmciLCAiI2ZmZDE4YiIsIFRydWUpCiAgICBsYWJlbChhcHBsZSwgTE9DS0VEX0FDQ0VTU09SWV9IRUxQKQogICAgbGFiZWwoYXBwbGUsICIxLiBVc2UgdGhlIFJlY292ZXJ5IHN0ZXBzIGJlbG93IChvciB5b3VyIG1vZGVsJ3MgZ3VpZGUpLlxuMi4gV2l0aCB0aGUgY2FibGUtYW5kLWNvbXB1dGVyIHNjcmVlbiBzaG93aW5nLCBzZWxlY3QgRGV0ZWN0IGRldmljZS5cbjMuIENoZWNrIHRoZSBzZWxlY3RlZCBkZXZpY2UsIHRoZW4gb3BlbiB0aGUgZXJhc2UgY29uZmlybWF0aW9uLiIpCiAgICBsaW5rcyA9IHRrLkZyYW1lKGFwcGxlLCBiZz1wYW5lbCkKICAgIGxpbmtzLnBhY2soZmlsbD0ieCIpCiAgICBmb3IgdGl0bGUgaW4gKCJpUGhvbmUgcmVjb3ZlcnkgYnV0dG9ucyIsICJpUGFkIHJlY292ZXJ5IGJ1dHRvbnMiKToKICAgICAgICB0ay5CdXR0b24obGlua3MsIHRleHQ9dGl0bGUsIGNvbW1hbmQ9bGFtYmRhIHQ9dGl0bGU6IHdlYmJyb3dzZXIub3BlbihHVUlERVNbdF0pLCBiZz0iIzI2Mzk1MiIsIGZnPXRleHQsCiAgICAgICAgICAgICAgICAgIHJlbGllZj0iZmxhdCIsIHBhZHg9MTAsIHBhZHk9NykucGFjayhzaWRlPSJsZWZ0IiwgcGFkeD0oMCwgMTApLCBwYWR5PSgwLCAxMikpCiAgICB0YXJnZXRfc3RhdHVzID0gbGFiZWwoYXBwbGUsICJObyBkZXZpY2Ugc2VsZWN0ZWQuIERldGVjdGlvbiBpcyByZWFkLW9ubHkuIiwgYWNjZW50KQogICAgc2VsZWN0ZWQgPSB7InRhcmdldCI6IE5vbmUsICJidXN5IjogRmFsc2V9CgogICAgZGVmIGZpbmlzaF9kZXRlY3QodGFyZ2V0LCBlcnJvcik6CiAgICAgICAgc2VsZWN0ZWQudXBkYXRlKHRhcmdldD10YXJnZXQsIGJ1c3k9RmFsc2UpCiAgICAgICAgZGV0ZWN0LmNvbmZpZ3VyZShzdGF0ZT0ibm9ybWFsIikKICAgICAgICBlcmFzZS5jb25maWd1cmUoc3RhdGU9Im5vcm1hbCIgaWYgdGFyZ2V0IGVsc2UgImRpc2FibGVkIikKICAgICAgICB0YXJnZXRfc3RhdHVzLmNvbmZpZ3VyZSh0ZXh0PWVycm9yIGlmIGVycm9yIGVsc2UgZiJ7dGFyZ2V0LnByb2R1Y3R9ICB8ICBSZWNvdmVyeSBtb2RlXG5FQ0lEOiB7dGFyZ2V0LmVjaWR9XG5VU0IgY29ubmVjdGlvbjoge3RhcmdldC51c2Iubm9kZX0iKQoKICAgIGRlZiBkZXRlY3RfZGV2aWNlKCk6CiAgICAgICAgaWYgc2VsZWN0ZWRbImJ1c3kiXToKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgc2VsZWN0ZWQudXBkYXRlKHRhcmdldD1Ob25lLCBidXN5PVRydWUpCiAgICAgICAgZGV0ZWN0LmNvbmZpZ3VyZShzdGF0ZT0iZGlzYWJsZWQiKQogICAgICAgIGVyYXNlLmNvbmZpZ3VyZShzdGF0ZT0iZGlzYWJsZWQiKQogICAgICAgIHRhcmdldF9zdGF0dXMuY29uZmlndXJlKHRleHQ9IkNoZWNraW5nIHRoZSBjb25uZWN0ZWQgcmVjb3ZlcnkgZGV2aWNl4oCmIikKCiAgICAgICAgZGVmIHdvcmtlcigpOgogICAgICAgICAgICB0cnk6CiAgICAgICAgICAgICAgICBjaGVja19yZXN0b3JlX3Rvb2xzKCkKICAgICAgICAgICAgICAgIGZvdW5kID0gZGlzY292ZXJfdGFyZ2V0KCkKICAgICAgICAgICAgICAgIHJvb3QuYWZ0ZXIoMCwgZmluaXNoX2RldGVjdCwgZm91bmQsIE5vbmUpCiAgICAgICAgICAgIGV4Y2VwdCBSZXNldEVycm9yIGFzIGV4YzoKICAgICAgICAgICAgICAgIHJvb3QuYWZ0ZXIoMCwgZmluaXNoX2RldGVjdCwgTm9uZSwgc3RyKGV4YykpCiAgICAgICAgdGhyZWFkaW5nLlRocmVhZCh0YXJnZXQ9d29ya2VyLCBkYWVtb249VHJ1ZSkuc3RhcnQoKQoKICAgIGRlZiBvcGVuX3Jlc3RvcmUoKToKICAgICAgICB0YXJnZXQgPSBzZWxlY3RlZFsidGFyZ2V0Il0KICAgICAgICBpZiB0YXJnZXQgaXMgTm9uZToKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgdHJ5OgogICAgICAgICAgICBsYXVuY2hfcmVzdG9yZSh0YXJnZXQpCiAgICAgICAgICAgIHNlbGVjdGVkWyJ0YXJnZXQiXSA9IE5vbmUKICAgICAgICAgICAgZXJhc2UuY29uZmlndXJlKHN0YXRlPSJkaXNhYmxlZCIpCiAgICAgICAgICAgIHRhcmdldF9zdGF0dXMuY29uZmlndXJlKHRleHQ9IkNvbmZpcm1hdGlvbiBvcGVuZWQgaW4gYSB0ZXJtaW5hbC4gTm90aGluZyBpcyBlcmFzZWQgdW50aWwgeW91IHR5cGUgdGhlIGZ1bGwgcmVxdWVzdGVkIHBocmFzZSB0aGVyZS4iKQogICAgICAgIGV4Y2VwdCAoUmVzZXRFcnJvciwgT1NFcnJvcikgYXMgZXhjOgogICAgICAgICAgICBtZXNzYWdlYm94LnNob3dlcnJvcigiQ2Fubm90IG9wZW4gcmVzdG9yZSIsIHN0cihleGMpLCBwYXJlbnQ9cm9vdCkKCiAgICBkZXRlY3QgPSBidXR0b24oYXBwbGUsICJEZXRlY3QgZGV2aWNlIiwgZGV0ZWN0X2RldmljZSkKICAgIGVyYXNlID0gYnV0dG9uKGFwcGxlLCAiT3BlbiBlcmFzZSBjb25maXJtYXRpb27igKYiLCBvcGVuX3Jlc3RvcmUsIHByaW1hcnk9VHJ1ZSkKICAgIGVyYXNlLmNvbmZpZ3VyZShzdGF0ZT0iZGlzYWJsZWQiKQogICAgbGFiZWwoYXBwbGUsICJFcmFzaW5nIHJlbW92ZXMgYWxsIGxvY2FsIGRhdGEgYW5kIHRoZSBzY3JlZW4gcGFzc2NvZGUuIEFjdGl2YXRpb24gTG9jayBjYW4gc3RpbGwgcmVxdWlyZSB0aGUgbGlua2VkIEFwcGxlIEFjY291bnQuIFRoZSByZXN0b3JlIHRvb2wgZG93bmxvYWRzIGN1cnJlbnRseSBzaWduZWQgc3RvY2sgZmlybXdhcmUgYW5kIGtlZXBzIGl0cyBvd24gcHJvbXB0cyB2aXNpYmxlLiIsIGRpbSkKICAgIGxhYmVsKGFwcGxlLCAiaVBhZCBSZWNvdmVyeSBzdGVwcyDigJQgdXNlIHRoZSBidXR0b25zIG9uIHRoZSBpUGFkIiwgYWNjZW50LCBUcnVlKQogICAgbGFiZWwoYXBwbGUsIElQQURfUkVDT1ZFUllfU1RBUlQpCiAgICBsYWJlbChhcHBsZSwgSVBBRF9SRUNPVkVSWV9OT19IT01FKQogICAgbGFiZWwoYXBwbGUsIElQQURfUkVDT1ZFUllfSE9NRSkKICAgIGxhYmVsKGFwcGxlLCBJUEFEX1JFQ09WRVJZX0ZJTklTSCwgZGltKQoKICAgIGxhYmVsKGFuZHJvaWQsICJGYWN0b3J5IHJlc2V0IHVzaW5nIHlvdXIgbW9kZWwncyBvZmZpY2lhbCByZWNvdmVyeSBidXR0b25zIiwgYWNjZW50LCBUcnVlKQogICAgbGFiZWwoYW5kcm9pZCwgIkNob29zZSB5b3VyIG1hbnVmYWN0dXJlciwgdGhlbiBmb2xsb3cgaXRzIFJlY292ZXJ5IC8gZmFjdG9yeSByZXNldCBpbnN0cnVjdGlvbnMuIEJ1dHRvbiBjb21iaW5hdGlvbnMgdmFyeSBieSBtb2RlbDsgbWFueSBkZXZpY2VzIGNhbiBiZSByZXNldCB3aXRob3V0IGEgY29tcHV0ZXIuIEEgcmVzZXQgZGVsZXRlcyBsb2NhbCBkYXRhLiIpCiAgICBmb3IgdGl0bGUgaW4gKCJHb29nbGUgUGl4ZWwgZmFjdG9yeSByZXNldCIsICJTYW1zdW5nIEdhbGF4eSBmYWN0b3J5IHJlc2V0IiwgIk90aGVyIEFuZHJvaWQgbWFudWZhY3R1cmVycyIpOgogICAgICAgIGxpbmsoYW5kcm9pZCwgdGl0bGUpCiAgICBsYWJlbChhbmRyb2lkLCAiVGhpcyBsYXVuY2hlciBwcm92aWRlcyBvZmZpY2lhbCBndWlkZXMgZm9yIEFuZHJvaWQuIEl0IGRvZXMgbm90IHNlbmQgYW4gZXJhc2UgY29tbWFuZCB0byBBbmRyb2lkIGRldmljZXMuIEFmdGVyIHJlc2V0LCBhIHByZXZpb3VzbHkgc3luY2VkIEdvb2dsZSBhY2NvdW50IG9yIHRoZSBwcmV2aW91cyBzY3JlZW4gbG9jayBtYXkgc3RpbGwgYmUgcmVxdWlyZWQuIiwgZGltKQogICAgbGluayhhbmRyb2lkLCAiR29vZ2xlIGFjY291bnQgYWZ0ZXIgcmVzZXQiKQoKICAgIGxhYmVsKHNldHVwLCAiSW5zdGFsbCBvbmNlLCB0aGVuIGNoZWNrIHRoZSBhY3R1YWwgZGV2aWNlIiwgYWNjZW50LCBUcnVlKQogICAgbGFiZWwoc2V0dXAsICJDb25uZWN0IEdhcnJ5IFVTQiB0byBXaS1GaSBhbmQgZGlzY29ubmVjdCBwaG9uZXMgYW5kIHRhYmxldHMgZHVyaW5nIHNldHVwLiBTZXR1cCB0b29scyBvcGVucyBhIHRlcm1pbmFsIGFuZCBpbnN0YWxscyBBcHBsZSByZXN0b3JlIHRvb2xzIGZyb20gb2ZmaWNpYWwgRGViaWFuIHJlcG9zaXRvcmllcy4gV3JpdGFibGUgVVNCIHBlcnNpc3RlbmNlIGlzIG5lZWRlZCB0byByZXRhaW4gdGhlIHRvb2xzIGFuZCBmaXJtd2FyZSBkb3dubG9hZHMuIikKCiAgICBkZWYgaW5zdGFsbCgpOgogICAgICAgIHRyeToKICAgICAgICAgICAgbGF1bmNoX2luc3RhbGxlcigpCiAgICAgICAgZXhjZXB0IChSZXNldEVycm9yLCBPU0Vycm9yKSBhcyBleGM6CiAgICAgICAgICAgIG1lc3NhZ2Vib3guc2hvd2Vycm9yKCJDYW5ub3Qgb3BlbiBpbnN0YWxsZXIiLCBzdHIoZXhjKSwgcGFyZW50PXJvb3QpCgogICAgYnV0dG9uKHNldHVwLCAiU2V0dXAgdG9vbHMiLCBpbnN0YWxsLCBwcmltYXJ5PVRydWUpCiAgICBsYWJlbChzZXR1cCwgIktlZXAgYSByZWxpYWJsZSBkYXRhIGNhYmxlIGFuZCBwb3dlciBjb25uZWN0ZWQuIEZpcm13YXJlIGRvd25sb2FkcyBjYW4gYmUgbGFyZ2U7IHBsYW4gZm9yIGF0IGxlYXN0IDIwIEdpQiBvZiB3cml0YWJsZSBmcmVlIHNwYWNlIGFuZCBtb3JlIGlmIHRoZSBjaG9zZW4gZmlybXdhcmUgcmVxdWlyZXMgaXQuIExpbnV4IHN1cHBvcnQgdmFyaWVzIGJ5IG1vZGVsIGFuZCBmaXJtd2FyZS4gSWYgaXQgZmFpbHMsIHVzZSBBcHBsZSBEZXZpY2VzIG9uIFdpbmRvd3Mgb3IgRmluZGVyIG9uIGEgTWFjLiIpCiAgICBsaW5rKHNldHVwLCAiQXBwbGUgYWNjb3VudCByZWNvdmVyeSIpCiAgICBsYWJlbChzZXR1cCwgIk5vIG1hbmFnZW1lbnQgc29mdHdhcmUgaXMgbmVlZGVkIGJlZm9yZSBhIGZhY3RvcnkgcmVzZXQuIFRoZSBkZXZpY2UncyBsaW5rZWQgYWNjb3VudCBtYXkgc3RpbGwgYmUgbmVlZGVkIGFmdGVyd2FyZC4iLCBkaW0pCiAgICB0ay5MYWJlbChvdXRlciwgdGV4dD1WRVJTSU9OICsgIiAg4oCiICBObyBwaHlzaWNhbCBwaG9uZS90YWJsZXQgcmVzdG9yZSBoYXMgYmVlbiB2YWxpZGF0ZWQgZm9yIHRoaXMgcmVsZWFzZS4iLAogICAgICAgICAgICAgYmc9YmcsIGZnPWRpbSwgd3JhcGxlbmd0aD04MDAsIGp1c3RpZnk9ImxlZnQiKS5wYWNrKGFuY2hvcj0idyIpCiAgICByb290Lm1haW5sb29wKCkKCgpkZWYgbWFpbihhcmd2PU5vbmUpOgogICAgcGFyc2VyID0gYXJncGFyc2UuQXJndW1lbnRQYXJzZXIoZGVzY3JpcHRpb249IkdhcnJ5IFBob25lICYgVGFibGV0IFJlc2V0IikKICAgIHBhcnNlci5hZGRfYXJndW1lbnQoIi0tcmVzdG9yZS1jb25zb2xlIiwgYWN0aW9uPSJzdG9yZV90cnVlIikKICAgIHBhcnNlci5hZGRfYXJndW1lbnQoIi0tZWNpZCIpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCItLXByb2R1Y3QiKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS11c2Itbm9kZSIpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCItLXVzYi1waWQiKQogICAgYXJncyA9IHBhcnNlci5wYXJzZV9hcmdzKGFyZ3YpCiAgICB0cnk6CiAgICAgICAgaWYgYXJncy5yZXN0b3JlX2NvbnNvbGU6CiAgICAgICAgICAgIGlmIG5vdCBQUk9EVUNUX1JFLmZ1bGxtYXRjaChhcmdzLnByb2R1Y3Qgb3IgIiIpIG9yIG5vdCByZS5mdWxsbWF0Y2gociJcZCstXGQrKD86XC5cZCspKiIsIGFyZ3MudXNiX25vZGUgb3IgIiIpIG9yIGFyZ3MudXNiX3BpZCBub3QgaW4gUkVDT1ZFUllfUElEUzoKICAgICAgICAgICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIlNlbGVjdCBhIGRldmljZSBpbiB0aGUgR2FycnkgbGF1bmNoZXIgZmlyc3QuIFRoZSByZXF1ZXN0ZWQgdGFyZ2V0IGlzIGludmFsaWQuIikKICAgICAgICAgICAgZXhwZWN0ZWQgPSBUYXJnZXQobm9ybWFsaXplX2VjaWQoYXJncy5lY2lkKSwgYXJncy5wcm9kdWN0LCBBcHBsZVVTQihhcmdzLnVzYl9ub2RlLCBhcmdzLnVzYl9waWQpKQogICAgICAgICAgICBpZiBub3Qgc3lzLnN0ZGluLmlzYXR0eSgpIG9yIG5vdCBzeXMuc3Rkb3V0LmlzYXR0eSgpOgogICAgICAgICAgICAgICAgcmFpc2UgUmVzZXRFcnJvcigiT3BlbiB0aGUgcmVzdG9yZSBjb25maXJtYXRpb24gaW4gdGhlIGZvcmVncm91bmQgdGVybWluYWwuIFBpcGVkIG9yIHVuYXR0ZW5kZWQgcmVzdG9yZSBpbnB1dCBpcyBub3QgYWNjZXB0ZWQuIikKICAgICAgICAgICAgcmV0dXJuIHJ1bl9yZXN0b3JlX2NvbnNvbGUoZXhwZWN0ZWQpCiAgICAgICAgaWYgYW55KChhcmdzLmVjaWQsIGFyZ3MucHJvZHVjdCwgYXJncy51c2Jfbm9kZSwgYXJncy51c2JfcGlkKSk6CiAgICAgICAgICAgIHJhaXNlIFJlc2V0RXJyb3IoIlRhcmdldCBvcHRpb25zIHJlcXVpcmUgdGhlIGV4cGxpY2l0IHJlc3RvcmUgY29uc29sZS4iKQogICAgICAgIHJ1bl91aSgpCiAgICAgICAgcmV0dXJuIDAKICAgIGV4Y2VwdCAoUmVzZXRFcnJvciwgS2V5Ym9hcmRJbnRlcnJ1cHQsIEVPRkVycm9yKSBhcyBleGM6CiAgICAgICAgcHJpbnQoc3RyKGV4YykgaWYgc3RyKGV4YykgZWxzZSAiQ2FuY2VsbGVkLiIsIGZpbGU9c3lzLnN0ZGVycikKICAgICAgICByZXR1cm4gMgoKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICBzeXMuZXhpdChtYWluKCkpCg=='
CORE_SHAS = {'a712b9ced4141cf787e188bd10110524c76ccb1543dba59724ab36e5750ffb5d',
             'dca18b74fc08653ceb056ac3d64bde98ec033a58de623e2ef1f1edb78326e3e1'}


def sha(data):
    return hashlib.sha256(data).hexdigest()


def protected(path, directory=False):
    for current in (path, *path.parents):
        info = current.lstat()
        if stat.S_ISLNK(info.st_mode) or info.st_uid != 0 or info.st_mode & 0o022:
            raise ValueError('A repair path has unexpected ownership or permissions.')
        expected = stat.S_ISDIR if current != path or directory else stat.S_ISREG
        if not expected(info.st_mode):
            raise ValueError('A repair path has an unexpected file type.')


def read_known(path, hashes):
    protected(path)
    fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
    with os.fdopen(fd, 'rb') as stream:
        info = os.fstat(stream.fileno())
        if not stat.S_ISREG(info.st_mode) or info.st_size > 128 * 1024:
            raise ValueError('The installed file is not a bounded regular file.')
        data = stream.read(128 * 1024 + 1)
    if sha(data) not in hashes:
        raise ValueError('The installed file is not the reviewed version: ' + path.name)
    return data


def replacement():
    fixed = base64.b64decode(PAYLOAD, validate=True)
    if sha(fixed) != NEW_SHA:
        raise ValueError('The embedded update does not match its reviewed checksum.')
    compile(fixed, str(TARGET), 'exec')
    return fixed


def media_core():
    data = read_known(CORE, CORE_SHAS)
    module = types.ModuleType('garry_reviewed_media_core')
    module.__file__ = str(CORE)
    exec(compile(data, str(CORE), 'exec'), module.__dict__)
    return module


def atomic(path, data, mode):
    protected(path.parent, directory=True)
    if path.exists() or path.is_symlink():
        protected(path)
    fd, temporary = tempfile.mkstemp(prefix='.garry-recovery-', dir=path.parent)
    temporary = Path(temporary)
    try:
        with os.fdopen(fd, 'wb') as stream:
            stream.write(data)
            stream.flush()
            os.fsync(stream.fileno())
        temporary.chmod(mode)
        temporary.replace(path)
        fd = os.open(path.parent, os.O_RDONLY | os.O_DIRECTORY)
        try:
            os.fsync(fd)
        finally:
            os.close(fd)
        if path.read_bytes() != data:
            raise OSError('Repair read-back did not match.')
    finally:
        if temporary.exists():
            temporary.unlink()


def repair():
    original = read_known(TARGET, {OLD_SHA, NEW_SHA})
    fixed = replacement()
    core = media_core()
    core.inspect_media()
    with core.update_lock():
        if read_known(TARGET, {OLD_SHA, NEW_SHA}) != original:
            raise ValueError('The app changed during inspection. Nothing was patched.')
        if original == fixed:
            return {'status': 'already_repaired', 'sha256': NEW_SHA}
        if not BACKUP.exists():
            protected(BACKUP.parent, directory=True)
            BACKUP.mkdir(mode=0o700)
        protected(BACKUP, directory=True)
        stamp = datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%SZ')
        folder = BACKUP / ('recovery-help-' + stamp + '-' + uuid.uuid4().hex[:8])
        folder.mkdir(mode=0o700)
        atomic(folder / 'phone_reset.py.before', original, 0o600)
        receipt = {'status': 'repair_verified', 'previous_sha256': OLD_SHA,
                   'sha256': NEW_SHA, 'backup_directory': str(folder),
                   'boot_files_changed': False, 'phone_connected_or_erased': False}
        try:
            atomic(TARGET, fixed, 0o644)
            if read_known(TARGET, {NEW_SHA}) != fixed:
                raise OSError('Final app verification failed.')
            atomic(folder / 'repair-receipt.json', (json.dumps(receipt, indent=2) + '\n').encode(), 0o600)
        except Exception:
            atomic(TARGET, original, 0o644)
            raise
        return receipt


def main():
    if sys.platform != 'linux' or not sys.flags.isolated or os.geteuid() != 0:
        print('Run: sudo python3 -I ~/Downloads/garry-recovery-help.py')
        return 2
    try:
        result = repair()
    except Exception as exc:
        print('REPAIR NOT CONFIRMED: ' + ''.join(c for c in str(exc) if c.isprintable())[:500])
        print('Show this message. This helper does not connect to or erase phones.')
        return 1
    print('Garry recovery help installed and verified.' if result['status'] == 'repair_verified' else 'Garry recovery help is already installed.')
    print('Close and reopen Phone & Tablet Reset. The iPad must show the computer-and-cable recovery screen before detection.')
    print('No reboot is needed. No phone was erased by this repair.')
    return 0


if __name__ == '__main__':
    raise SystemExit(main())
