diff --git a/build/csv/ceph/rook-ceph-drbd-setup-script_v1_configmap.yaml b/build/csv/ceph/rook-ceph-drbd-setup-script_v1_configmap.yaml index 0e44fc345ab2..2838f583a052 100644 --- a/build/csv/ceph/rook-ceph-drbd-setup-script_v1_configmap.yaml +++ b/build/csv/ceph/rook-ceph-drbd-setup-script_v1_configmap.yaml @@ -1,6 +1,6 @@ apiVersion: v1 data: - script: "IyEvYmluL2Jhc2gKIwojIENvcHlyaWdodCAyMDI2IFRoZSBSb29rIEF1dGhvcnMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKIyBEUkJEIFNldHVwIFNjcmlwdCBmb3IgVHdvLU5vZGUgT3BlblNoaWZ0IENsdXN0ZXIsIFNhZmUgdG8gcmUtcnVuKCBpZGVtcG90ZW50ICkuCiMgVGhlIHNjcmlwdCBjYW4gc2tpcCBzdWNjZXNzZnVsIHN0ZXBzICYgcnVuIG9ubHkgdGhlIHJlcXVpcmVkIHN0ZXBzLgojCiMgQ0xJIG92ZXJyaWRlcyBlbnYgZm9yOiAtLWRyYmQtY29uZi1wYXRoLCAtLWRyYmQtZGlyLXBhdGgsIC0tZHJiZC1yZXNvdXJjZSwgLS1kcmJkLWRldmljZSwgLS1kcmJkLXBvcnQKIwojIFByZXJlcXVpc2l0ZXM6CiMgICAtIE5vZGVzIGNhbiBwdWxsICR7RFJCRF9JTUFHRX07ICR7RFJCRF9QT1JUfS90Y3Agb3BlbiBiZXR3ZWVuIG5vZGVzLgojICAgLSBJbWFnZSByZWdpc3RyeTogdGhlIGluLWNsdXN0ZXIgT3BlblNoaWZ0IHJlZ2lzdHJ5IHdpdGggZW1wdHlEaXIgc3RvcmFnZQojCnNldCAtZXVvIHBpcGVmYWlsCgpkaWUoKSB7CiAgICBlY2hvICJFcnJvcjogJCoiID4mMgogICAgZWNobyAiUGxlYXNlIHRyeSByZS1ydW5uaW5nIHRoZSBzY3JpcHQuIiA+JjIKICAgIGV4aXQgMQp9Cm1zZygpIHsgZWNobyAiRFJCRDogJCoiOyB9CgojIFdhbGwtY2xvY2sgd2FpdCBoZWxwZXJzOiBjYWxsIF93YWl0X2JlZ2luIGltbWVkaWF0ZWx5IGJlZm9yZSBhIHBvbGxpbmcgbG9vcDsgb24gc3VjY2VzcyBjYWxsIF93YWl0X3N1Y2NlZWRlZCAibWVzc2FnZSIuCl93YWl0X2JlZ2luKCkgeyBfV0FJVF9UMD0kKGRhdGUgKyVzKTsgfQoKX3dhaXRfc3VjY2VlZGVkKCkgewogICAgbG9jYWwgZD0kKCggJChkYXRlICslcykgLSBfV0FJVF9UMCApKQogICAgaWYgKCggZCA8IDYwICkpOyB0aGVuCiAgICAgICAgbXNnICIkMSAoaW4gJHtkfXMpIgogICAgZWxpZiAoKCBkIDwgMzYwMCApKTsgdGhlbgogICAgICAgIG1zZyAiJDEgKGluICQoKGQgLyA2MCkpIG1pbiAkKChkICUgNjApKXMpIgogICAgZWxzZQogICAgICAgIG1zZyAiJDEgKGluICQoKGQgLyA2MCkpIG1pbikiCiAgICBmaQp9CgojIFRPRE86IGJ1bXAgZGVmYXVsdCBpbWFnZSB0YWcgd2hlbiBhIG5ldyBvbmUgaXMgcHVibGlzaGVkLgpEUkJEX0lNQUdFPSIke0RSQkRfSU1BR0U6LXF1YXkuaW8vcmhjZXBoLWRldi9vZGY0LW9kZi1kcmJkLXJoZWw5OnY0LjIyfSIgIyBPREYgRFJCRCBpbWFnZSAoZHJiZGFkbSArIHNvdXJjZXMpCiMgVE9ETzogYnVtcCB3aGVuIHRhcmJhbGwgaW5zaWRlIHRoZSBpbWFnZSBjaGFuZ2VzLgpEUkJEX1ZFUlNJT049IiR7RFJCRF9WRVJTSU9OOi05LjIuMTd9IiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBNdXN0IG1hdGNoIERSQkQgc291cmNlIHZlcnNpb24gaW4gRFJCRF9JTUFHRQoKRFJCRF9DT05GX1BBVEg9IiR7RFJCRF9DT05GX1BBVEg6LS9ldGMvZHJiZC5jb25mfSIgICAgICAgICAgICAgICAjIE1haW4gZmlsZTogaW5jbHVkZSBvZiAke0RSQkRfRElSX1BBVEh9LyoucmVzIG9ubHkKRFJCRF9ESVJfUEFUSD0iJHtEUkJEX0RJUl9QQVRIOi0vZXRjL2RyYmQuZH0iICAgICAgICAgICAgICAgICAgICAjIFBlci1yZXNvdXJjZSAucmVzIGZpbGVzIChhY3R1YWwgRFJCRCBkZWZpbml0aW9uKQpEUkJEX1JFU09VUkNFPSIke0RSQkRfUkVTT1VSQ0U6LXIwfSIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgRFJCRCByZXNvdXJjZSBuYW1lIChlLmcuIHIwKQpEUkJEX0RFVklDRT0iJHtEUkJEX0RFVklDRTotL2Rldi9kcmJkMH0iICAgICAgICAgICAgICAgICAgICAgICAgICMgRFJCRCBibG9jayBkZXZpY2UgcGF0aCBvbiBub2RlcyAoZS5nLiAvZGV2L2RyYmQwKQpEUkJEX1BPUlQ9IiR7RFJCRF9QT1JUOi03Nzk0fSIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgRFJCRCByZXBsaWNhdGlvbiBUQ1AgcG9ydCAoZS5nLiA3Nzk0KQoKQVVUT1NUQVJUX0RBRU1PTlNFVF9OQU1FPSIke0FVVE9TVEFSVF9EQUVNT05TRVRfTkFNRTotZHJiZC1hdXRvc3RhcnR9IiAjIERSQkQgYXV0by1zdGFydCBEYWVtb25TZXQgbmFtZQpBVVRPU1RBUlRfREFFTU9OU0VUX05TPSIke0FVVE9TVEFSVF9EQUVNT05TRVRfTlM6LW9wZW5zaGlmdC1rbW19IiAgICAgICMgRFJCRCBhdXRvLXN0YXJ0IERhZW1vblNldCBuYW1lc3BhY2UKCk9VVFBVVF9DTV9OUz0iJHtPVVRQVVRfQ01fTlM6LW9wZW5zaGlmdC1zdG9yYWdlfSIgICAgICAgICAgICAgICAgIyBOYW1lc3BhY2UgZm9yIHNldHVwIHN1bW1hcnkgQ29uZmlnTWFwCk9VVFBVVF9DTV9OQU1FPSIke09VVFBVVF9DTV9OQU1FOi1kcmJkLWNvbmZpZ3VyZX0iICAgICAgICAgICAgICAgIyBOYW1lIGZvciB0aGUgc2V0dXAgc3VtbWFyeSBDb25maWdNYXAKCiMgQXBwcm94aW1hdGUgd2FpdCBjZWlsaW5ncyBpbiB0aGlzIHNjcmlwdDogS01NIG9wZXJhdG9yIH41bSAoNjDDlzVzKTsgRFJCRCBtb2R1bGVzIH4xMG0gKDYww5cxMHMpOwojIGluaXRpYWwgc3luYyB+MzBtICg2MMOXMzBzKTsgYXV0b3N0YXJ0IERhZW1vblNldCB+NW0gKDYww5c1cykuCgojIFVzZXIgaW5wdXQ6IGJhY2tpbmcgcGF0aHMgKGUuZy4gL2Rldi9zZGIpLiAtZCA9IHNhbWUgb24gYm90aCBub2RlczsgZWxzZSAtZDAgLyAtZDEgcGVyIG5vZGUuCkJBQ0tJTkdfUEFUSD0iIgpCQUNLSU5HX1BBVEhfTk9ERTA9IiIKQkFDS0lOR19QQVRIX05PREUxPSIiCkRJU0tfUkVTT0xWRURfTk9ERTA9IiIKRElTS19SRVNPTFZFRF9OT0RFMT0iIgoKTElTVF9ERVZJQ0VTX09OTFk9MAoKIyBOb2RlIGluZm8gKHBvcHVsYXRlZCBieSBkZXRlY3Rfbm9kZXMpCk5PREVfMD0iIgpOT0RFXzE9IiIKTk9ERV8wX0lQPSIiCk5PREVfMV9JUD0iIgoKIy0tLSBGdW5jdGlvbnMgLS0tIwoKdXNhZ2UoKSB7CiAgICBjYXQgPDxVU0FHRQpVc2FnZToKICAkMCAtZCA8cGF0aD4KICAkMCAtZDAgPHBhdGgwPiAtZDEgPHBhdGgxPgogICQwIC1sCgpCYWNraW5nIHBhdGhzIGFyZSByYXcgYmxvY2sgZGV2aWNlIHBhdGhzIChlLmcuIC9kZXYvc2RiKS4gVXNlIHRoZSBQQVRIIGNvbHVtbiBmcm9tIC1sLgpEaXNrcyBtdXN0IGJlIFNTRC1jbGFzcyAoUk9UQSAwKSBhbmQgc2FtZSBzaXplIG9uIGJvdGggbm9kZXMuCgogIC1kIFBBVEgKICAgICAgT25lIHBhdGggdXNlZCBvbiBib3RoIG5vZGVzLiBDaG9vc2UgdGhpcyB3aGVuIGVhY2ggbWFjaGluZSBoYXMgdGhlIHJlcGxpY2EgZGlzayBhdCB0aGUKICAgICAgc2FtZSBkZXZpY2UgbmFtZSAoYm90aCBub2RlcyB1c2UgZS5nLiAvZGV2L3NkYiBmb3IgdGhlIERSQkQgbG93ZXIgbGF5ZXIpLgoKVXNlIC1kMC8tZDEgd2hlbiB0aGUgdHdvIG5vZGVzIHVzZSBkaWZmZXJlbnQgcGF0aHM7IGRvIG5vdCBjb21iaW5lIC1kIHdpdGggLWQwLy1kMS4KCiAgLWQwIFBBVEggICBQYXRoIG9uIG5vZGUgMCBvbmx5IChmaXJzdCBub2RlIG5hbWUgYWZ0ZXIgc29ydGluZyBhbGwgY2x1c3RlciBub2RlcykuCiAgLWQxIFBBVEggICBQYXRoIG9uIG5vZGUgMSBvbmx5IChzZWNvbmQgbm9kZSkuCgpEaXNjb3Zlcnk6CiAgLWwgICAgTGlzdCBibG9jayBkZXZpY2VzIG9uIGVhY2ggbm9kZSAoTkFNRSwgUEFUSCwgU0laRSwgUk9UQSwgVFlQRSwgRlNUWVBFKS4KCkRSQkQgb3B0aW9uczoKICAtLWRyYmQtY29uZi1wYXRoIFBBVEggIEhvc3QgcGF0aCB0byBkcmJkLmNvbmYgKGRlZmF1bHQgJHtEUkJEX0NPTkZfUEFUSH0pCiAgLS1kcmJkLWRpci1wYXRoIFBBVEggICBIb3N0IGRpciBmb3IgcmVzb3VyY2Ugc25pcHBldHMgKGRlZmF1bHQgJHtEUkJEX0RJUl9QQVRIfSkKICAtLWRyYmQtcmVzb3VyY2UgTkFNRSAgIExvZ2ljYWwgRFJCRCByZXNvdXJjZSBuYW1lIGluIGNvbmZpZyAoZGVmYXVsdCAke0RSQkRfUkVTT1VSQ0V9KQogIC0tZHJiZC1kZXZpY2UgUEFUSCAgICAgRFJCRCB1cHBlciBkZXZpY2Ugbm9kZSBwYXRoLCBzYW1lIG9uIGJvdGggbm9kZXMgKGRlZmF1bHQgJHtEUkJEX0RFVklDRX0pCiAgLS1kcmJkLXBvcnQgTiAgICAgICAgICBUQ1AgcG9ydCBmb3IgRFJCRCByZXBsaWNhdGlvbiAoZGVmYXVsdCAke0RSQkRfUE9SVH0pCgpHZW5lcmFsOgogIC1oICAgIFNob3cgdGhpcyBoZWxwIGFuZCBleGl0CgpFbnZpcm9ubWVudDoKICBEZWZhdWx0cyBhcmUgZG9jdW1lbnRlZCBvbiBlYWNoIGFzc2lnbm1lbnQgbmVhciB0aGUgdG9wIG9mIHRoaXMgc2NyaXB0LgogIE9VVFBVVF9DTV9OUyAvIE9VVFBVVF9DTV9OQU1FIOKAlCBuYW1lc3BhY2UgYW5kIG5hbWUgb2YgdGhlIHN1bW1hcnkgQ29uZmlnTWFwIChmbG9hdGluZyBtb24pLgoKVVNBR0UKfQoKcGFyc2VfYXJncygpIHsKICAgIHdoaWxlIFtbICQjIC1ndCAwIF1dOyBkbwogICAgICAgIGNhc2UgIiQxIiBpbgogICAgICAgICAgICAtZDApCiAgICAgICAgICAgICAgICBpZiBbWyAteiAiJHsyOi19IiBdXTsgdGhlbgogICAgICAgICAgICAgICAgICAgIGRpZSAiLWQwIHJlcXVpcmVzIGEgcGF0aCAoZS5nLiAvZGV2L3NkYikiCiAgICAgICAgICAgICAgICBmaQogICAgICAgICAgICAgICAgQkFDS0lOR19QQVRIX05PREUwPSIkMiIKICAgICAgICAgICAgICAgIHNoaWZ0IDIKICAgICAgICAgICAgICAgIDs7CiAgICAgICAgICAgIC1kMSkKICAgICAgICAgICAgICAgIGlmIFtbIC16ICIkezI6LX0iIF1dOyB0aGVuCiAgICAgICAgICAgICAgICAgICAgZGllICItZDEgcmVxdWlyZXMgYSBwYXRoIChlLmcuIC9kZXYvc2RiKSIKICAgICAgICAgICAgICAgIGZpCiAgICAgICAgICAgICAgICBCQUNLSU5HX1BBVEhfTk9ERTE9IiQyIgogICAgICAgICAgICAgICAgc2hpZnQgMgogICAgICAgICAgICAgICAgOzsKICAgICAgICAgICAgLWQpCiAgICAgICAgICAgICAgICBpZiBbWyAteiAiJHsyOi19IiBdXTsgdGhlbgogICAgICAgICAgICAgICAgICAgIGRpZSAiLWQgcmVxdWlyZXMgYSBwYXRoIChlLmcuIC9kZXYvc2RiKSIKICAgICAgICAgICAgICAgIGZpCiAgICAgICAgICAgICAgICBCQUNLSU5HX1BBVEg9IiQyIgogICAgICAgICAgICAgICAgc2hpZnQgMgogICAgICAgICAgICAgICAgOzsKICAgICAgICAgICAgLWwpCiAgICAgICAgICAgICAgICBMSVNUX0RFVklDRVNfT05MWT0xCiAgICAgICAgICAgICAgICBzaGlmdAogICAgICAgICAgICAgICAgOzsKICAgICAgICAgICAgLS1kcmJkLWNvbmYtcGF0aCkKICAgICAgICAgICAgICAgIGlmIFtbIC16ICIkezI6LX0iIF1dOyB0aGVuCiAgICAgICAgICAgICAgICAgICAgZGllICItLWRyYmQtY29uZi1wYXRoIHJlcXVpcmVzIGFuIGFic29sdXRlIHBhdGggdG8gZHJiZC5jb25mIgogICAgICAgICAgICAgICAgZmkKICAgICAgICAgICAgICAgIERSQkRfQ09ORl9QQVRIPSIkMiIKICAgICAgICAgICAgICAgIHNoaWZ0IDIKICAgICAgICAgICAgICAgIDs7CiAgICAgICAgICAgIC0tZHJiZC1kaXItcGF0aCkKICAgICAgICAgICAgICAgIGlmIFtbIC16ICIkezI6LX0iIF1dOyB0aGVuCiAgICAgICAgICAgICAgICAgICAgZGllICItLWRyYmQtZGlyLXBhdGggcmVxdWlyZXMgYW4gYWJzb2x1dGUgZGlyZWN0b3J5IHBhdGggKGUuZy4gL2V0Yy9kcmJkLmQpIgogICAgICAgICAgICAgICAgZmkKICAgICAgICAgICAgICAgIERSQkRfRElSX1BBVEg9IiQyIgogICAgICAgICAgICAgICAgc2hpZnQgMgogICAgICAgICAgICAgICAgOzsKICAgICAgICAgICAgLS1kcmJkLXJlc291cmNlKQogICAgICAgICAgICAgICAgaWYgW1sgLXogIiR7MjotfSIgXV07IHRoZW4KICAgICAgICAgICAgICAgICAgICBkaWUgIi0tZHJiZC1yZXNvdXJjZSByZXF1aXJlcyBhIG5hbWUiCiAgICAgICAgICAgICAgICBmaQogICAgICAgICAgICAgICAgRFJCRF9SRVNPVVJDRT0iJDIiCiAgICAgICAgICAgICAgICBzaGlmdCAyCiAgICAgICAgICAgICAgICA7OwogICAgICAgICAgICAtLWRyYmQtZGV2aWNlKQogICAgICAgICAgICAgICAgaWYgW1sgLXogIiR7MjotfSIgXV07IHRoZW4KICAgICAgICAgICAgICAgICAgICBkaWUgIi0tZHJiZC1kZXZpY2UgcmVxdWlyZXMgYSBwYXRoIChlLmcuIC9kZXYvZHJiZDApIgogICAgICAgICAgICAgICAgZmkKICAgICAgICAgICAgICAgIERSQkRfREVWSUNFPSIkMiIKICAgICAgICAgICAgICAgIHNoaWZ0IDIKICAgICAgICAgICAgICAgIDs7CiAgICAgICAgICAgIC0tZHJiZC1wb3J0KQogICAgICAgICAgICAgICAgaWYgW1sgLXogIiR7MjotfSIgXV07IHRoZW4KICAgICAgICAgICAgICAgICAgICBkaWUgIi0tZHJiZC1wb3J0IHJlcXVpcmVzIGEgVENQIHBvcnQgbnVtYmVyIgogICAgICAgICAgICAgICAgZmkKICAgICAgICAgICAgICAgIERSQkRfUE9SVD0iJDIiCiAgICAgICAgICAgICAgICBzaGlmdCAyCiAgICAgICAgICAgICAgICA7OwogICAgICAgICAgICAtaCkKICAgICAgICAgICAgICAgIHVzYWdlCiAgICAgICAgICAgICAgICBleGl0IDAKICAgICAgICAgICAgICAgIDs7CiAgICAgICAgICAgICopCiAgICAgICAgICAgICAgICBkaWUgIlVua25vd24gb3B0aW9uOiAkMSAodXNlIC1oKSIKICAgICAgICAgICAgICAgIDs7CiAgICAgICAgZXNhYwogICAgZG9uZQoKICAgIGlmIFtbICIkTElTVF9ERVZJQ0VTX09OTFkiIC1lcSAxIF1dOyB0aGVuCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgaWYgW1sgLW4gIiRCQUNLSU5HX1BBVEgiICYmICggLW4gIiRCQUNLSU5HX1BBVEhfTk9ERTAiIHx8IC1uICIkQkFDS0lOR19QQVRIX05PREUxIiApIF1dOyB0aGVuCiAgICAgICAgZGllICJVc2UgZWl0aGVyIC1kIG9yIGJvdGggLWQwIGFuZCAtZDEgKG5vZGUwL25vZGUxIHBhdGhzKSwgbm90IGJvdGgiCiAgICBmaQogICAgaWYgW1sgLW4gIiRCQUNLSU5HX1BBVEhfTk9ERTAiIHx8IC1uICIkQkFDS0lOR19QQVRIX05PREUxIiBdXTsgdGhlbgogICAgICAgIGlmIFtbIC16ICIkQkFDS0lOR19QQVRIX05PREUwIiB8fCAteiAiJEJBQ0tJTkdfUEFUSF9OT0RFMSIgXV07IHRoZW4KICAgICAgICAgICAgZGllICJCb3RoIC1kMCBhbmQgLWQxIGFyZSByZXF1aXJlZCB3aGVuIHVzaW5nIHBlci1ub2RlIHBhdGhzIgogICAgICAgIGZpCiAgICBmaQogICAgaWYgW1sgLXogIiRCQUNLSU5HX1BBVEgiICYmIC16ICIkQkFDS0lOR19QQVRIX05PREUwIiBdXTsgdGhlbgogICAgICAgIGRpZSAiU3BlY2lmeSBiYWNraW5nIHBhdGgocyk6IC1kLCBvciAtZDAgYW5kIC1kMSwgb3IgLWwgdG8gbGlzdCBkZXZpY2VzIChzZWUgLWgpIgogICAgZmkKfQoKIyBPcGVuU2hpZnQgbG9naW4sIHR3by1ub2RlIGNsdXN0ZXIsIGFuZCBUTkYgY29udHJvbC1wbGFuZSB0b3BvbG9neSAoRHVhbFJlcGxpY2EpLgpjaGVja19wcmVyZXF1aXNpdGVzKCkgewogICAgaWYgISBvYyB3aG9hbWkgJj4vZGV2L251bGw7IHRoZW4KICAgICAgICBkaWUgIm5vdCBsb2dnZWQgaW50byBPcGVuU2hpZnQgKG9jIHdob2FtaSkiCiAgICBmaQoKICAgIGxvY2FsIG5vZGVfY291bnQgdG9wb2xvZ3kKICAgIG5vZGVfY291bnQ9JChvYyBnZXQgbm9kZXMgLS1uby1oZWFkZXJzIDI+L2Rldi9udWxsIHwgd2MgLWwgfCB0ciAtZCAnICcpCiAgICBpZiBbWyAiJG5vZGVfY291bnQiIC1uZSAyIF1dOyB0aGVuCiAgICAgICAgZGllICJleHBlY3RlZCAyIG5vZGVzIGZvciBUTkYsIGZvdW5kICRub2RlX2NvdW50IgogICAgZmkKCiAgICBpZiAhIHRvcG9sb2d5PSQob2MgZ2V0IGluZnJhc3RydWN0dXJlIGNsdXN0ZXIgLW8ganNvbnBhdGg9J3suc3RhdHVzLmNvbnRyb2xQbGFuZVRvcG9sb2d5fScgMj4vZGV2L251bGwpOyB0aGVuCiAgICAgICAgdG9wb2xvZ3k9IiIKICAgIGZpCiAgICBpZiBbWyAteiAiJHRvcG9sb2d5IiBdXTsgdGhlbgogICAgICAgIGRpZSAiY291bGQgbm90IHJlYWQgaW5mcmFzdHJ1Y3R1cmUgQ1IiCiAgICBmaQogICAgaWYgW1sgIiR0b3BvbG9neSIgIT0gIkR1YWxSZXBsaWNhIiBdXTsgdGhlbgogICAgICAgIGRpZSAiZXhwZWN0ZWQgc3RhdHVzLmNvbnRyb2xQbGFuZVRvcG9sb2d5IER1YWxSZXBsaWNhICh0d28tbm9kZSBjb250cm9sIHBsYW5lKSwgZ290ICcke3RvcG9sb2d5fSciCiAgICBmaQp9CgojIFJlc29sdmUgdGhlIHR3byBjbHVzdGVyIG5vZGUgbmFtZXMgKHNvcnRlZCBhc2NlbmRpbmcpIGFuZCBlYWNoIG5vZGUncyBJbnRlcm5hbElQIGZvciBEUkJEIGVuZHBvaW50cy4KZGV0ZWN0X25vZGVzKCkgewogICAgbG9jYWwgbm9kZXNfc29ydGVkCgogICAgbm9kZXNfc29ydGVkPSQob2MgZ2V0IG5vZGVzIC1vIGpzb25wYXRoPSd7cmFuZ2UgLml0ZW1zWypdfXsubWV0YWRhdGEubmFtZX17IlxuIn17ZW5kfScgfCBzb3J0KQogICAgTk9ERV8wPSQocHJpbnRmICclc1xuJyAiJG5vZGVzX3NvcnRlZCIgfCBoZWFkIC1uIDEpCiAgICBOT0RFXzE9JChwcmludGYgJyVzXG4nICIkbm9kZXNfc29ydGVkIiB8IGhlYWQgLW4gMiB8IHRhaWwgLW4gMSkKICAgIGlmIFtbIC16ICIkTk9ERV8wIiB8fCAteiAiJE5PREVfMSIgXV07IHRoZW4KICAgICAgICBkaWUgImNvdWxkIG5vdCByZXNvbHZlIHR3byBub2RlIG5hbWVzIgogICAgZmkKCiAgICBOT0RFXzBfSVA9JChvYyBnZXQgbm9kZSAiJE5PREVfMCIgLW8ganNvbnBhdGg9J3suc3RhdHVzLmFkZHJlc3Nlc1s/KEAudHlwZT09IkludGVybmFsSVAiKV0uYWRkcmVzc30nKQogICAgTk9ERV8xX0lQPSQob2MgZ2V0IG5vZGUgIiROT0RFXzEiIC1vIGpzb25wYXRoPSd7LnN0YXR1cy5hZGRyZXNzZXNbPyhALnR5cGU9PSJJbnRlcm5hbElQIildLmFkZHJlc3N9JykKICAgIGlmIFtbIC16ICIkTk9ERV8wX0lQIiB8fCAteiAiJE5PREVfMV9JUCIgXV07IHRoZW4KICAgICAgICBkaWUgImNvdWxkIG5vdCByZWFkIEludGVybmFsSVAgKE5PREVfMD0kTk9ERV8wIE5PREVfMT0kTk9ERV8xKSIKICAgIGZpCn0KCiMgbGlzdCBibG9jayBkZXZpY2VzIG9uIGJvdGggbm9kZXMgd2l0aCBsc2JsawpsaXN0X2RldmljZXMoKSB7CiAgICBlY2hvICI9PT0gQmxvY2sgZGV2aWNlcyAobm9kZTA9JE5PREVfMCwgbm9kZTE9JE5PREVfMSkgPT09IgogICAgZWNobyAiVXNlIHRoZSBQQVRIIGNvbHVtbiAoZS5nLiAtZCAvZGV2L3NkYiBvciAtZDAgLyAtZDEgcGVyLW5vZGUgcGF0aHMpLiIKICAgIGVjaG8gIiIKICAgIGZvciBuIGluICIkTk9ERV8wIiAiJE5PREVfMSI7IGRvCiAgICAgICAgZWNobyAiLS0tICRuIC0tLSIKICAgICAgICBpZiAhIG9jIC0tcmVxdWVzdC10aW1lb3V0PTEyMHMgZGVidWcgLXEgIm5vZGUvJG4iIC0tIGNocm9vdCAvaG9zdCBsc2JsayAtbyBOQU1FLFBBVEgsU0laRSxST1RBLFRZUEUsRlNUWVBFOyB0aGVuCiAgICAgICAgICAgIGVjaG8gIiAgQ291bGQgbm90IGxpc3QgYmxvY2sgZGV2aWNlcyBvbiAkbiAob2MgZGVidWcgZmFpbGVkKS4gQ2hlY2sgY2x1c3RlciBhY2Nlc3MsIHRoZW4gcmUtcnVuOiAkMCAtbCIgPiYyCiAgICAgICAgZmkKICAgICAgICBlY2hvICIiCiAgICBkb25lCiAgICBlY2hvICJTYW1lIHBhdGggb24gYm90aCBub2RlczogLWQgPHBhdGg+IgogICAgZWNobyAiRGlmZmVyZW50IHBhdGhzIChzYW1lIHNpemUpOiAtZDAgPHBhdGgwPiAtZDEgPHBhdGgxPiIKfQoKIyBNYXAgdXNlciBkZXZpY2UgcGF0aCAtPiBzdGFibGUgZGlzayBieS1pZCBzeW1saW5rIGZvciBEUkJEIGNvbmZpZyBvbiB0aGF0IG5vZGUuCiMgTXVsdGlwbGUgYnktaWQgbmFtZXMgY2FuIHJlc29sdmUgdG8gdGhlIHNhbWUgY2Fub25pY2FsIGRldmljZTsgc29ydHxoZWFkIC0xIHBpY2tzIG9uZSBkZXRlcm1pbmlzdGljYWxseS4KcmVzb2x2ZV9kaXNrX3BhdGhfb25fbm9kZSgpIHsKICAgIGxvY2FsIG5vZGU9IiQxIiBkZXZpY2VfcGF0aD0iJDIiCiAgICBvYyBkZWJ1ZyAtcSAibm9kZS8kbm9kZSIgLS0gY2hyb290IC9ob3N0IGVudiAiRFJCRF9CTE9DS19ERVY9JHtkZXZpY2VfcGF0aH0iIGJhc2ggLWMgJwppZiAhIENBTk9OPSQocmVhZGxpbmsgLWYgIiREUkJEX0JMT0NLX0RFViIgMj4vZGV2L251bGwpOyB0aGVuCiAgQ0FOT049IiREUkJEX0JMT0NLX0RFViIKZmkKZm9yIGlkIGluIC9kZXYvZGlzay9ieS1pZC8qOyBkbwogIGlmIFtbICEgLWUgIiRpZCIgXV07IHRoZW4KICAgIGNvbnRpbnVlCiAgZmkKICBpZiBbWyAiJChyZWFkbGluayAtZiAiJGlkIiAyPi9kZXYvbnVsbCkiID09ICIkQ0FOT04iIF1dOyB0aGVuIGVjaG8gIiRpZCI7IGZpCmRvbmUgfCBzb3J0IC11IHwgaGVhZCAtbiAxCicgMj4vZGV2L251bGwgfCB0YWlsIC1uIDEKfQoKcHJpbnRfY29uZmlnKCkgewogICAgZWNobyAiIgogICAgbXNnICJDb25maWd1cmF0aW9uIgogICAgbG9jYWwgX2x3PTE4CiAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIk5vZGVzOiIgIiROT0RFXzAgKCROT0RFXzBfSVApLCAkTk9ERV8xICgkTk9ERV8xX0lQKSIKICAgIGlmIFtbIC1uICIkQkFDS0lOR19QQVRIIiBdXTsgdGhlbgogICAgICAgIHByaW50ZiAnICAlLSpzICVzIChzYW1lIHBhdGggb24gYm90aCBub2RlcylcbicgIiRfbHciICJCYWNraW5nIGRldmljZToiICIkQkFDS0lOR19QQVRIIgogICAgZWxzZQogICAgICAgIHByaW50ZiAnICAlLSpzICVzXG4nICIkX2x3IiAiQmFja2luZyBkZXZpY2VzOiIgInBlci1ub2RlIHBhdGhzIgogICAgICAgIHByaW50ZiAnICAlLSpzICVzOiAlc1xuJyAiJF9sdyIgIiIgIiROT0RFXzAiICIkQkFDS0lOR19QQVRIX05PREUwIgogICAgICAgIHByaW50ZiAnICAlLSpzICVzOiAlc1xuJyAiJF9sdyIgIiIgIiROT0RFXzEiICIkQkFDS0lOR19QQVRIX05PREUxIgogICAgZmkKICAgIHByaW50ZiAnICAlLSpzICVzXG4nICIkX2x3IiAiRFJCRCBDb25maWcgcGF0aDoiICIkRFJCRF9DT05GX1BBVEgiCiAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIkRSQkQgRGlyIHBhdGg6IiAiJERSQkRfRElSX1BBVEgiCiAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIkRSQkQgUmVzb3VyY2U6IiAiJERSQkRfUkVTT1VSQ0UiCiAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIkRSQkQgRGV2aWNlOiIgIiREUkJEX0RFVklDRSIKICAgIHByaW50ZiAnICAlLSpzICVzXG4nICIkX2x3IiAiRFJCRCBQb3J0OiIgIiREUkJEX1BPUlQiCiAgICBlY2hvICIiCn0KCgpfbHNibGtfb25lX2xpbmUoKSB7CiAgICBsb2NhbCBub2RlPSIkMSIgZGV2aWNlX3BhdGg9IiQyIgogICAgb2MgZGVidWcgLXEgIm5vZGUvJG5vZGUiIC0tIGNocm9vdCAvaG9zdCBsc2JsayAtbmRvIFNJWkUsUk8sUk9UQSAiJGRldmljZV9wYXRoIiAyPi9kZXYvbnVsbCB8IHRyIC1zICcgJyB8IGhlYWQgLTEKfQoKIyB2YWxpZGF0ZSB0aGUgYmFja2luZyBkZXZpY2UgcGF0aHMgYW5kIHJlc29sdmUgdGhlIGRpc2sgYnktaWQgc3ltbGluayBmb3IgRFJCRCBjb25maWcgb24gdGhhdCBub2RlLgp2YWxpZGF0ZV9hbmRfcmVzb2x2ZV9kaXNrcygpIHsKICAgIGxvY2FsIHAwIHAxIHJvdzAgcm93MSBzaXplMCBybzAgcm90YTAgc2l6ZTEgcm8xIHJvdGExCiAgICBpZiBbWyAtbiAiJEJBQ0tJTkdfUEFUSCIgXV07IHRoZW4KICAgICAgICBwMD0iJEJBQ0tJTkdfUEFUSCIKICAgICAgICBwMT0iJEJBQ0tJTkdfUEFUSCIKICAgIGVsc2UKICAgICAgICBwMD0iJEJBQ0tJTkdfUEFUSF9OT0RFMCIKICAgICAgICBwMT0iJEJBQ0tJTkdfUEFUSF9OT0RFMSIKICAgIGZpCgogICAgbXNnICJDaGVja2luZyBiYWNraW5nIGRldmljZSBwYXRocy4uLiIKICAgIHJvdzA9JChfbHNibGtfb25lX2xpbmUgIiROT0RFXzAiICIkcDAiKQogICAgcm93MT0kKF9sc2Jsa19vbmVfbGluZSAiJE5PREVfMSIgIiRwMSIpCiAgICBpZiBbWyAteiAiJHJvdzAiIF1dOyB0aGVuCiAgICAgICAgZGllICJkZXZpY2UgcGF0aCAkcDAgbm90IGZvdW5kIG9uICROT0RFXzAiCiAgICBmaQogICAgaWYgW1sgLXogIiRyb3cxIiBdXTsgdGhlbgogICAgICAgIGRpZSAiZGV2aWNlIHBhdGggJHAxIG5vdCBmb3VuZCBvbiAkTk9ERV8xIgogICAgZmkKCiAgICByZWFkIC1yIHNpemUwIHJvMCByb3RhMCA8PDwiJHJvdzAiCiAgICByZWFkIC1yIHNpemUxIHJvMSByb3RhMSA8PDwiJHJvdzEiCiAgICBpZiBbWyAiJHJvMCIgIT0gIjAiIF1dOyB0aGVuCiAgICAgICAgZGllICJkZXZpY2UgcGF0aCAkcDAgb24gJE5PREVfMCBpcyByZWFkLW9ubHkiCiAgICBmaQogICAgaWYgW1sgIiRybzEiICE9ICIwIiBdXTsgdGhlbgogICAgICAgIGRpZSAiZGV2aWNlIHBhdGggJHAxIG9uICROT0RFXzEgaXMgcmVhZC1vbmx5IgogICAgZmkKICAgIGlmIFtbICIkcm90YTAiICE9ICIwIiBdXTsgdGhlbgogICAgICAgIGRpZSAiZGV2aWNlIHBhdGggJHAwIG9uICROT0RFXzAgbXVzdCBiZSBub24tcm90YXRpb25hbCAoU1NEL05WTWU7IGxzYmxrIFJPVEEgMCksIG5vdCByb3RhdGlvbmFsIEhERCAoUk9UQT0ke3JvdGEwOi0/fSkiCiAgICBmaQogICAgaWYgW1sgIiRyb3RhMSIgIT0gIjAiIF1dOyB0aGVuCiAgICAgICAgZGllICJkZXZpY2UgcGF0aCAkcDEgb24gJE5PREVfMSBtdXN0IGJlIG5vbi1yb3RhdGlvbmFsIChTU0QvTlZNZTsgbHNibGsgUk9UQSAwKSwgbm90IHJvdGF0aW9uYWwgSEREIChST1RBPSR7cm90YTE6LT99KSIKICAgIGZpCiAgICBpZiBbWyAiJHNpemUwIiAhPSAiJHNpemUxIiBdXTsgdGhlbgogICAgICAgIGRpZSAiYmFja2luZyBkZXZpY2UgcGF0aCBzaXplIG1pc21hdGNoOiAkTk9ERV8wICRzaXplMCB2cyAkTk9ERV8xICRzaXplMSIKICAgIGZpCgogICAgZWNobyAiICAkTk9ERV8wOiAkcDAgICRzaXplMCIKICAgIGVjaG8gIiAgJE5PREVfMTogJHAxICAkc2l6ZTEiCiAgICBtc2cgIkJhY2tpbmcgZGV2aWNlIHBhdGhzIE9LLiIKCiAgICBtc2cgIlJlc29sdmluZyBkZXZpY2UgcGF0aHMgdG8gL2Rldi9kaXNrL2J5LWlkIGZvciBEUkJEIGNvbmZpZyIKICAgIERJU0tfUkVTT0xWRURfTk9ERTA9JChyZXNvbHZlX2Rpc2tfcGF0aF9vbl9ub2RlICIkTk9ERV8wIiAiJHAwIikKICAgIERJU0tfUkVTT0xWRURfTk9ERTE9JChyZXNvbHZlX2Rpc2tfcGF0aF9vbl9ub2RlICIkTk9ERV8xIiAiJHAxIikKICAgIGlmIFtbIC16ICIkRElTS19SRVNPTFZFRF9OT0RFMCIgXV07IHRoZW4KICAgICAgICBkaWUgIm5vIC9kZXYvZGlzay9ieS1pZCBzeW1saW5rIGZvciBkZXZpY2UgcGF0aCAkcDAgb24gJE5PREVfMCIKICAgIGZpCiAgICBpZiBbWyAteiAiJERJU0tfUkVTT0xWRURfTk9ERTEiIF1dOyB0aGVuCiAgICAgICAgZGllICJubyAvZGV2L2Rpc2svYnktaWQgc3ltbGluayBmb3IgZGV2aWNlIHBhdGggJHAxIG9uICROT0RFXzEiCiAgICBmaQogICAgZWNobyAiICAkTk9ERV8wOiAkcDAgIC0+ICAkRElTS19SRVNPTFZFRF9OT0RFMCIKICAgIGVjaG8gIiAgJE5PREVfMTogJHAxICAtPiAgJERJU0tfUkVTT0xWRURfTk9ERTEiCn0KCiMgaW5zdGFsbCB0aGUgS01NIChLZXJuZWwgTW9kdWxlIE1hbmFnZW1lbnQpIG9wZXJhdG9yCnNldHVwX2ttbV9vcGVyYXRvcigpIHsKICAgIGlmIG9jIGdldCBjc3YgLW4gb3BlbnNoaWZ0LWttbSAyPi9kZXYvbnVsbCB8IGdyZXAgLXEgU3VjY2VlZGVkOyB0aGVuCiAgICAgICAgbXNnICJLTU0gKEtlcm5lbCBNb2R1bGUgTWFuYWdlbWVudCkgb3BlcmF0b3IgaXMgYWxyZWFkeSBpbnN0YWxsZWQuIgogICAgICAgIHJldHVybiAwCiAgICBmaQoKICAgIG1zZyAiSW5zdGFsbGluZyBLTU0gKEtlcm5lbCBNb2R1bGUgTWFuYWdlbWVudCkgb3BlcmF0b3IuLi4iCiAgICBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgPDxFT0YKYXBpVmVyc2lvbjogdjEKa2luZDogTmFtZXNwYWNlCm1ldGFkYXRhOgogIG5hbWU6IG9wZW5zaGlmdC1rbW0KLS0tCmFwaVZlcnNpb246IG9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxCmtpbmQ6IE9wZXJhdG9yR3JvdXAKbWV0YWRhdGE6CiAgbmFtZToga2VybmVsLW1vZHVsZS1tYW5hZ2VtZW50CiAgbmFtZXNwYWNlOiBvcGVuc2hpZnQta21tCi0tLQphcGlWZXJzaW9uOiBvcGVyYXRvcnMuY29yZW9zLmNvbS92MWFscGhhMQpraW5kOiBTdWJzY3JpcHRpb24KbWV0YWRhdGE6CiAgbmFtZToga2VybmVsLW1vZHVsZS1tYW5hZ2VtZW50CiAgbmFtZXNwYWNlOiBvcGVuc2hpZnQta21tCnNwZWM6CiAgY2hhbm5lbDogc3RhYmxlCiAgaW5zdGFsbFBsYW5BcHByb3ZhbDogQXV0b21hdGljCiAgbmFtZToga2VybmVsLW1vZHVsZS1tYW5hZ2VtZW50CiAgc291cmNlOiByZWRoYXQtb3BlcmF0b3JzCiAgc291cmNlTmFtZXNwYWNlOiBvcGVuc2hpZnQtbWFya2V0cGxhY2UKRU9GCgogICAgIyBQb2xsIHVudGlsIGEgQ2x1c3RlclNlcnZpY2VWZXJzaW9uIGluIG9wZW5zaGlmdC1rbW0gcmVhY2hlcyBQaGFzZSBTdWNjZWVkZWQsIGUuZy4gYSBsaW5lIGxpa2U6CiAgICAjICAga2VybmVsLW1vZHVsZS1tYW5hZ2VtZW50LnZYLlkuWiAgIGt1YmUtYXBpc2VydmVyICAgU3VjY2VlZGVkCiAgICBtc2cgIldhaXRpbmcgZm9yIEtNTSBvcGVyYXRvciB0byBiZWNvbWUgcmVhZHkgKHVwIHRvIDUgbWluKS4uLiIKICAgIF93YWl0X2JlZ2luCiAgICBsb2NhbCBpCiAgICBmb3IgaSBpbiAkKHNlcSAxIDYwKTsgZG8KICAgICAgICBpZiBvYyBnZXQgY3N2IC1uIG9wZW5zaGlmdC1rbW0gMj4vZGV2L251bGwgfCBncmVwIC1xIFN1Y2NlZWRlZDsgdGhlbgogICAgICAgICAgICBfd2FpdF9zdWNjZWVkZWQgIktNTSBvcGVyYXRvciBpcyByZWFkeSIKICAgICAgICAgICAgcmV0dXJuIDAKICAgICAgICBmaQogICAgICAgIGlmIFtbICIkaSIgLWVxIDYwIF1dOyB0aGVuCiAgICAgICAgICAgIGRpZSAiS01NIG9wZXJhdG9yIG5vdCByZWFkeSBhZnRlciA1IG1pbnV0ZXMiCiAgICAgICAgZmkKICAgICAgICBzbGVlcCA1CiAgICBkb25lCn0KCiMgY2hlY2sgaWYgdGhlIGltYWdlIHJlZ2lzdHJ5IG9wZXJhdG9yIGlzIHJlYWR5CiMgWWVzIHdoZW46CiMgLSBtYW5hZ2VtZW50U3RhdGUgaXMgTWFuYWdlZAojIC0gQXZhaWxhYmxlIGlzIFRydWUKIyAtIHJlYWR5UmVwbGljYXMgPiAwCmltYWdlX3JlZ2lzdHJ5X29wZXJhdG9yX2F2YWlsYWJsZSgpIHsKICAgIGxvY2FsIHN0YXR1c19saW5lIG1hbmFnZW1lbnRfc3RhdGUgYXZhaWxhYmxlX3N0YXR1cyByZWFkeV9yZXBsaWNhcwogICAgaWYgISBzdGF0dXNfbGluZT0kKG9jIGdldCBjb25maWdzLmltYWdlcmVnaXN0cnkub3BlcmF0b3Iub3BlbnNoaWZ0LmlvIGNsdXN0ZXIgLW8ganNvbnBhdGg9J3suc3BlYy5tYW5hZ2VtZW50U3RhdGV9eyJcdCJ9ey5zdGF0dXMuY29uZGl0aW9uc1s/KEAudHlwZT09IkF2YWlsYWJsZSIpXS5zdGF0dXN9eyJcdCJ9ey5zdGF0dXMucmVhZHlSZXBsaWNhc30nIDI+L2Rldi9udWxsKTsgdGhlbgogICAgICAgIHN0YXR1c19saW5lPSIiCiAgICBmaQogICAgSUZTPSQnXHQnIHJlYWQgLXIgbWFuYWdlbWVudF9zdGF0ZSBhdmFpbGFibGVfc3RhdHVzIHJlYWR5X3JlcGxpY2FzIDw8PCIkc3RhdHVzX2xpbmUiCiAgICBpZiBbWyAiJG1hbmFnZW1lbnRfc3RhdGUiICE9ICJNYW5hZ2VkIiBdXTsgdGhlbgogICAgICAgIHJldHVybiAxCiAgICBmaQogICAgaWYgW1sgIiRhdmFpbGFibGVfc3RhdHVzIiAhPSAiVHJ1ZSIgXV07IHRoZW4KICAgICAgICByZXR1cm4gMQogICAgZmkKICAgIGlmIFtbIC16ICIkcmVhZHlfcmVwbGljYXMiIHx8ICEgIiRyZWFkeV9yZXBsaWNhcyIgPX4gXlswLTldKyQgfHwgIiRyZWFkeV9yZXBsaWNhcyIgLWxlIDAgXV07IHRoZW4KICAgICAgICByZXR1cm4gMQogICAgZmkKICAgIHJldHVybiAwCn0KCnBhdGNoX2ltYWdlX3JlZ2lzdHJ5X3RvX2VtcHR5ZGlyKCkgewogICAgbG9jYWwgcGF0Y2hfeWFtbAogICAgcGF0Y2hfeWFtbD0kKGNhdCA8PCdQQVRDSCcKc3BlYzoKICBtYW5hZ2VtZW50U3RhdGU6IE1hbmFnZWQKICBzdG9yYWdlOgogICAgZW1wdHlEaXI6IHt9ClBBVENICikKICAgIGlmICEgb2MgcGF0Y2ggY29uZmlncy5pbWFnZXJlZ2lzdHJ5Lm9wZXJhdG9yLm9wZW5zaGlmdC5pbyBjbHVzdGVyIC0tdHlwZSBtZXJnZSAtLXBhdGNoICIkcGF0Y2hfeWFtbCIgPi9kZXYvbnVsbDsgdGhlbgogICAgICAgIGRpZSAiZmFpbGVkIHRvIHBhdGNoIGltYWdlIHJlZ2lzdHJ5IGNvbmZpZyIKICAgIGZpCn0KCiMgSWYgdGhlIGltYWdlIHJlZ2lzdHJ5IG9wZXJhdG9yIGlzIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSwgY29uZmlndXJlIGl0IHdpdGggZW1wdHlEaXIgc3RvcmFnZS4Kc2V0dXBfaW1hZ2VfcmVnaXN0cnlfb3BlcmF0b3IoKSB7CiAgICBpZiBpbWFnZV9yZWdpc3RyeV9vcGVyYXRvcl9hdmFpbGFibGU7IHRoZW4KICAgICAgICBtc2cgIkltYWdlIHJlZ2lzdHJ5IG9wZXJhdG9yIGlzIGFscmVhZHkgcmVhZHkuIgogICAgICAgIHJldHVybiAwCiAgICBmaQogICAgbXNnICJDb25maWd1cmluZyBpbi1jbHVzdGVyIGltYWdlIHJlZ2lzdHJ5IHdpdGggZW1wdHlEaXIgc3RvcmFnZS4iCiAgICBwYXRjaF9pbWFnZV9yZWdpc3RyeV90b19lbXB0eWRpcgogICAgd2FpdF91bnRpbF9pbWFnZV9yZWdpc3RyeV9vcGVyYXRvcl9hdmFpbGFibGUKfQoKIyBXYWl0IHVudGlsIGltYWdlX3JlZ2lzdHJ5X29wZXJhdG9yX2F2YWlsYWJsZTogYWZ0ZXIgcGF0Y2hpbmcgZW1wdHlEaXIgdGhlIG9wZXJhdG9yIHJlY29uY2lsZXMgYW5kCiMgcmVnaXN0cnkgcG9kcyByb2xsIG91dDsgd2UgbmVlZCBNYW5hZ2VkICsgQXZhaWxhYmxlPVRydWUgKyByZWFkeVJlcGxpY2FzPjAgYmVmb3JlIEtNTSBjYW4gcHVzaAojIHRoZSBtb2R1bGUgaW1hZ2UgdG8gdGhlIGludGVybmFsIHJlZ2lzdHJ5Lgp3YWl0X3VudGlsX2ltYWdlX3JlZ2lzdHJ5X29wZXJhdG9yX2F2YWlsYWJsZSgpIHsKICAgIGxvY2FsIGkKICAgIG1zZyAiV2FpdGluZyBmb3IgaW1hZ2UgcmVnaXN0cnkgb3BlcmF0b3IgdG8gYmVjb21lIHJlYWR5ICh1cCB0byAxNSBtaW4pLi4uIgogICAgX3dhaXRfYmVnaW4KICAgIGZvciBpIGluICQoc2VxIDEgMTgwKTsgZG8KICAgICAgICBpZiBpbWFnZV9yZWdpc3RyeV9vcGVyYXRvcl9hdmFpbGFibGU7IHRoZW4KICAgICAgICAgICAgX3dhaXRfc3VjY2VlZGVkICJJbWFnZSByZWdpc3RyeSBvcGVyYXRvciBpcyByZWFkeSIKICAgICAgICAgICAgcmV0dXJuIDAKICAgICAgICBmaQogICAgICAgIGlmIFtbICIkaSIgLWVxIDE4MCBdXTsgdGhlbgogICAgICAgICAgICBkaWUgInRpbWVvdXQ6IGltYWdlIHJlZ2lzdHJ5IG9wZXJhdG9yIG5vdCByZWFkeSBhZnRlciAxNSBtaW51dGVzIChleHBlY3QgTWFuYWdlZCwgQXZhaWxhYmxlPVRydWUsIHN0YXR1cy5yZWFkeVJlcGxpY2FzPjA7IGNoZWNrOiBvYyBnZXQgY29uZmlncy5pbWFnZXJlZ2lzdHJ5Lm9wZXJhdG9yLm9wZW5zaGlmdC5pbyBjbHVzdGVyIC1vIHlhbWw7IG9jIGdldCBwb2RzIC1uIG9wZW5zaGlmdC1pbWFnZS1yZWdpc3RyeSkiCiAgICAgICAgZmkKICAgICAgICBpZiBbWyAkKChpICUgMTIpKSAtZXEgMCBdXTsgdGhlbgogICAgICAgICAgICBtc2cgIlN0aWxsIHdhaXRpbmcgZm9yIGltYWdlIHJlZ2lzdHJ5IG9wZXJhdG9yICgkKChpICogNSkpcyBlbGFwc2VkKS4uLiIKICAgICAgICBmaQogICAgICAgIHNsZWVwIDUKICAgIGRvbmUKfQoKIyBUcnVlIHdoZW4gb3BlbnNoaWZ0LWttbSBoYXMgYSBidWlsZGVyLWRvY2tlcmNmZy0qIFNlY3JldCB3aXRoIHVzYWJsZSBwdWxsL3B1c2ggY3JlZGVudGlhbHMuCmttbV9idWlsZGVyX2RvY2tlcmNmZ19yZWFkeSgpIHsKICAgIGxvY2FsIHNlYyBiNjQKICAgIHNlYz0kKG9jIGdldCBzZWNyZXRzIC1uIG9wZW5zaGlmdC1rbW0gLS1uby1oZWFkZXJzIDI+L2Rldi9udWxsIHwgYXdrICcvXmJ1aWxkZXItZG9ja2VyY2ZnLS8ge3ByaW50ICQxOyBleGl0fScpCiAgICBpZiBbWyAteiAiJHNlYyIgXV07IHRoZW4KICAgICAgICByZXR1cm4gMQogICAgZmkKICAgIGlmICEgYjY0PSQob2MgZ2V0IHNlY3JldCAiJHNlYyIgLW4gb3BlbnNoaWZ0LWttbSAtbyBqc29ucGF0aD0ney5kYXRhLlwuZG9ja2VyY2ZnfScgMj4vZGV2L251bGwpOyB0aGVuCiAgICAgICAgYjY0PSIiCiAgICBmaQogICAgaWYgW1sgLXogIiRiNjQiIF1dOyB0aGVuCiAgICAgICAgaWYgISBiNjQ9JChvYyBnZXQgc2VjcmV0ICIkc2VjIiAtbiBvcGVuc2hpZnQta21tIC1vIGpzb25wYXRoPSd7LmRhdGEuXC5kb2NrZXJjb25maWdqc29ufScgMj4vZGV2L251bGwpOyB0aGVuCiAgICAgICAgICAgIGI2ND0iIgogICAgICAgIGZpCiAgICBmaQogICAgIyBTZWNyZXQgY2FuIGV4aXN0IGJlZm9yZSBkYXRhIGlzIHBvcHVsYXRlZDsgcmVhbCBkb2NrZXJjZmcvZG9ja2VyY29uZmlnanNvbiBiYXNlNjQgaXMgdXN1YWxseSA+PjgwIGNoYXJzLgogICAgaWYgW1sgJHsjYjY0fSAtbHQgODAgXV07IHRoZW4KICAgICAgICByZXR1cm4gMQogICAgZmkKICAgIHJldHVybiAwCn0KCiMgV2FpdCBmb3IgU2VydmljZUFjY291bnQgYnVpbGRlciBhbmQgZG9ja2VyY2ZnIFNlY3JldCBvbmx5IHdoZW4gbWlzc2luZyAoS01NIGltYWdlIGJ1aWxkIG5lZWRzIHRoZW0pLgprbW1faW1hZ2VfYnVpbGRfd2FpdHMoKSB7CiAgICBsb2NhbCBpCiAgICBpZiBvYyBnZXQgc2EgYnVpbGRlciAtbiBvcGVuc2hpZnQta21tICY+L2Rldi9udWxsOyB0aGVuCiAgICAgICAgbXNnICJTZXJ2aWNlQWNjb3VudCBidWlsZGVyIGFscmVhZHkgcHJlc2VudCBpbiBvcGVuc2hpZnQta21tLiIKICAgIGVsc2UKICAgICAgICBtc2cgIldhaXRpbmcgZm9yIFNlcnZpY2VBY2NvdW50IGJ1aWxkZXIgaW4gb3BlbnNoaWZ0LWttbSAodXAgdG8gMyBtaW4pLi4uIgogICAgICAgIF93YWl0X2JlZ2luCiAgICAgICAgZm9yIGkgaW4gJChzZXEgMSAzNik7IGRvCiAgICAgICAgICAgIGlmIG9jIGdldCBzYSBidWlsZGVyIC1uIG9wZW5zaGlmdC1rbW0gJj4vZGV2L251bGw7IHRoZW4KICAgICAgICAgICAgICAgIF93YWl0X3N1Y2NlZWRlZCAiU2VydmljZUFjY291bnQgYnVpbGRlciBpcyBwcmVzZW50IGluIG9wZW5zaGlmdC1rbW0iCiAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICBmaQogICAgICAgICAgICBpZiBbWyAiJGkiIC1lcSAzNiBdXTsgdGhlbgogICAgICAgICAgICAgICAgZGllICJ0aW1lb3V0OiBidWlsZGVyIFNlcnZpY2VBY2NvdW50IG1pc3NpbmcgaW4gb3BlbnNoaWZ0LWttbSIKICAgICAgICAgICAgZmkKICAgICAgICAgICAgc2xlZXAgNQogICAgICAgIGRvbmUKICAgIGZpCgogICAgaWYga21tX2J1aWxkZXJfZG9ja2VyY2ZnX3JlYWR5OyB0aGVuCiAgICAgICAgbXNnICJCdWlsZGVyIGRvY2tlcmNmZyBTZWNyZXQgYWxyZWFkeSBwb3B1bGF0ZWQuIgogICAgZWxzZQogICAgICAgIG1zZyAiV2FpdGluZyBmb3IgYnVpbGRlciBkb2NrZXJjZmcgU2VjcmV0IHdpdGggcG9wdWxhdGVkIHJlZ2lzdHJ5IGNyZWRlbnRpYWxzICh1cCB0byA1IG1pbikuLi4iCiAgICAgICAgX3dhaXRfYmVnaW4KICAgICAgICBmb3IgaSBpbiAkKHNlcSAxIDYwKTsgZG8KICAgICAgICAgICAgaWYga21tX2J1aWxkZXJfZG9ja2VyY2ZnX3JlYWR5OyB0aGVuCiAgICAgICAgICAgICAgICBfd2FpdF9zdWNjZWVkZWQgIkJ1aWxkZXIgZG9ja2VyY2ZnIFNlY3JldCBpcyBwb3B1bGF0ZWQiCiAgICAgICAgICAgICAgICByZXR1cm4gMAogICAgICAgICAgICBmaQogICAgICAgICAgICBpZiBbWyAiJGkiIC1lcSA2MCBdXTsgdGhlbgogICAgICAgICAgICAgICAgZGllICJ0aW1lb3V0OiBidWlsZGVyIGRvY2tlcmNmZyBub3QgcG9wdWxhdGVkIGluIG9wZW5zaGlmdC1rbW0iCiAgICAgICAgICAgIGZpCiAgICAgICAgICAgIHNsZWVwIDUKICAgICAgICBkb25lCiAgICBmaQp9CgojIGNyZWF0ZSB0aGUgS01NIE1vZHVsZSBDUiBhbmQgZG9ja2VyZmlsZSBDb25maWdNYXAgdG8gYnVpbGQgYW5kIGxvYWQgRFJCRCBrZXJuZWwgbW9kdWxlcyBvbiB0aGUgbm9kZXMuCmNyZWF0ZV9kcmJkX21vZHVsZSgpIHsKICAgIGlmIG9jIGdldCBtb2R1bGUgZHJiZC1rbW9kIC1uIG9wZW5zaGlmdC1rbW0gJj4vZGV2L251bGw7IHRoZW4KICAgICAgICBtc2cgIktNTSBNb2R1bGUgZHJiZC1rbW9kIGFscmVhZHkgZXhpc3RzLiIKICAgICAgICByZXR1cm4gMAogICAgZmkKCiAgICBtc2cgIkNyZWF0aW5nIEtNTSBNb2R1bGUgZHJiZC1rbW9kIgoKICAgIGxvY2FsIGttbV9kb2NrZXJmaWxlCiAgICBrbW1fZG9ja2VyZmlsZT0kKGNhdCA8PCdET0NLRVJGSUxFX1RFTVBMQVRFJwogICAgQVJHIERUS19BVVRPCiAgICBBUkcgS0VSTkVMX0ZVTExfVkVSU0lPTgogICAgQVJHIERSQkRfVkVSU0lPTj1fX0RSQkRfVkVSU0lPTl9fCgogICAgRlJPTSBfX0RSQkRfSU1BR0VfXyBBUyBkcmJkLXNyYwoKICAgIEZST00gJHtEVEtfQVVUT30gQVMgYnVpbGRlcgogICAgQVJHIEtFUk5FTF9GVUxMX1ZFUlNJT04KICAgIEFSRyBEUkJEX1ZFUlNJT04KCiAgICBXT1JLRElSIC90bXAvZHJiZF9idWlsZAoKICAgIENPUFkgLS1mcm9tPWRyYmQtc3JjIC9kcmJkLSR7RFJCRF9WRVJTSU9OfS50YXIuZ3ogLgogICAgUlVOIHRhciAteHZ6ZiBkcmJkLSR7RFJCRF9WRVJTSU9OfS50YXIuZ3oKCiAgICBXT1JLRElSIC90bXAvZHJiZF9idWlsZC9kcmJkLSR7RFJCRF9WRVJTSU9OfQogICAgUlVOIG1ha2UgS1ZFUj0ke0tFUk5FTF9GVUxMX1ZFUlNJT059IC1qJChucHJvYykKICAgIFJVTiBta2RpciAtcCAvaW5zdGFsbC9saWIvbW9kdWxlcy8ke0tFUk5FTF9GVUxMX1ZFUlNJT059L2V4dHJhCiAgICBSVU4gY3AgZHJiZC9idWlsZC1jdXJyZW50L2RyYmQua28gZHJiZC9idWlsZC1jdXJyZW50L2RyYmRfdHJhbnNwb3J0X3RjcC5rbyAvaW5zdGFsbC9saWIvbW9kdWxlcy8ke0tFUk5FTF9GVUxMX1ZFUlNJT059L2V4dHJhLwogICAgUlVOIGRlcG1vZCAtYiAvaW5zdGFsbCAke0tFUk5FTF9GVUxMX1ZFUlNJT059CiAgICBGUk9NIHJlZ2lzdHJ5LnJlZGhhdC5pby91Ymk5L3ViaS1taW5pbWFsCiAgICBBUkcgS0VSTkVMX0ZVTExfVkVSU0lPTgogICAgQ09QWSAtLWZyb209YnVpbGRlciAvaW5zdGFsbC9saWIvbW9kdWxlcy8gL29wdC9saWIvbW9kdWxlcy8KRE9DS0VSRklMRV9URU1QTEFURQopCiAgICBrbW1fZG9ja2VyZmlsZT0iJHtrbW1fZG9ja2VyZmlsZS8vX19EUkJEX1ZFUlNJT05fXy8ke0RSQkRfVkVSU0lPTn19IgogICAga21tX2RvY2tlcmZpbGU9IiR7a21tX2RvY2tlcmZpbGUvL19fRFJCRF9JTUFHRV9fLyR7RFJCRF9JTUFHRX19IgoKICAgIG9jIGFwcGx5IC1mIC0gPi9kZXYvbnVsbCA8PEVPRgphcGlWZXJzaW9uOiB2MQpraW5kOiBDb25maWdNYXAKbWV0YWRhdGE6CiAgbmFtZTogZHJiZC1rbW9kLWRvY2tlcmZpbGUKICBuYW1lc3BhY2U6IG9wZW5zaGlmdC1rbW0KZGF0YToKICBkb2NrZXJmaWxlOiB8CiQocHJpbnRmICclc1xuJyAiJGttbV9kb2NrZXJmaWxlIiB8IGF3ayAne3ByaW50ICIgICAgIiAkMH0nKQpFT0YKCiAgICBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgPDwnTU9EVUxFX1NQRUMnCmFwaVZlcnNpb246IGttbS5zaWdzLngtazhzLmlvL3YxYmV0YTEKa2luZDogTW9kdWxlCm1ldGFkYXRhOgogIG5hbWU6IGRyYmQta21vZAogIG5hbWVzcGFjZTogb3BlbnNoaWZ0LWttbQpzcGVjOgogIG1vZHVsZUxvYWRlcjoKICAgIGNvbnRhaW5lcjoKICAgICAgbW9kcHJvYmU6CiAgICAgICAgbW9kdWxlTmFtZTogZHJiZF90cmFuc3BvcnRfdGNwCiAgICAgICAgZGlyTmFtZTogL29wdAogICAgICBrZXJuZWxNYXBwaW5nczoKICAgICAgICAtIHJlZ2V4cDogJ14uKlwueDg2XzY0JCcKICAgICAgICAgIGNvbnRhaW5lckltYWdlOiAnaW1hZ2UtcmVnaXN0cnkub3BlbnNoaWZ0LWltYWdlLXJlZ2lzdHJ5LnN2Yzo1MDAwL29wZW5zaGlmdC1rbW0vZHJiZF9jb21wYXRfa21vZDoke0tFUk5FTF9GVUxMX1ZFUlNJT059JwogICAgICAgICAgYnVpbGQ6CiAgICAgICAgICAgIGRvY2tlcmZpbGVDb25maWdNYXA6CiAgICAgICAgICAgICAgbmFtZTogZHJiZC1rbW9kLWRvY2tlcmZpbGUKICBzZWxlY3Rvcjoge30KTU9EVUxFX1NQRUMKICAgIG1zZyAiS01NIE1vZHVsZSBhbmQgQ29uZmlnTWFwIGFwcGxpZWQuIgp9CgojIGNoZWNrIGlmIHRoZSBEUkJEIGtlcm5lbCBtb2R1bGVzIGFyZSBsb2FkZWQgb24gdGhlIG5vZGUKbm9kZV9oYXNfZHJiZF9rbW9kcygpIHsKICAgIGxvY2FsIG5vZGU9IiQxIgogICAgbG9jYWwgb3V0CiAgICBpZiAhIG91dD0kKG9jIGRlYnVnIC1xICJub2RlLyRub2RlIiAtLSBjaHJvb3QgL2hvc3QgY2F0IC9wcm9jL21vZHVsZXMgMj4vZGV2L251bGwpOyB0aGVuCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiAhIGVjaG8gIiRvdXQiIHwgZ3JlcCAtcUUgJ15kcmJkW1s6c3BhY2U6XV0nOyB0aGVuCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiAhIGVjaG8gIiRvdXQiIHwgZ3JlcCAtcUUgJ15kcmJkX3RyYW5zcG9ydF90Y3BbWzpzcGFjZTpdXSc7IHRoZW4KICAgICAgICByZXR1cm4gMQogICAgZmkKICAgIHJldHVybiAwCn0KCiMgd2FpdCBmb3IgdGhlIERSQkQga2VybmVsIG1vZHVsZXMgdG8gbG9hZCBvbiBib3RoIG5vZGVzCndhaXRfZm9yX21vZHVsZXMoKSB7CiAgICBpZiBub2RlX2hhc19kcmJkX2ttb2RzICIkTk9ERV8wIiAmJiBub2RlX2hhc19kcmJkX2ttb2RzICIkTk9ERV8xIjsgdGhlbgogICAgICAgIG1zZyAiRFJCRCBrZXJuZWwgbW9kdWxlcyBhcmUgYWxyZWFkeSBsb2FkZWQgb24gYm90aCBub2Rlcy4iCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgIyBTdWNjZXNzOiAvcHJvYy9tb2R1bGVzIG9uIGVhY2ggbm9kZSBjb250YWlucyBkcmJkIGFuZCBkcmJkX3RyYW5zcG9ydF90Y3AgbGluZXMgKHNlZSBub2RlX2hhc19kcmJkX2ttb2RzKS4KICAgIG1zZyAiV2FpdGluZyBmb3IgRFJCRCBrZXJuZWwgbW9kdWxlcyB0byBsb2FkIG9uIGJvdGggbm9kZXMgKHVwIHRvIDEwIG1pbikuLi4iCiAgICBfd2FpdF9iZWdpbgogICAgbG9jYWwgaQogICAgZm9yIGkgaW4gJChzZXEgMSA2MCk7IGRvCiAgICAgICAgaWYgbm9kZV9oYXNfZHJiZF9rbW9kcyAiJE5PREVfMCIgJiYgbm9kZV9oYXNfZHJiZF9rbW9kcyAiJE5PREVfMSI7IHRoZW4KICAgICAgICAgICAgX3dhaXRfc3VjY2VlZGVkICJEUkJEIGtlcm5lbCBtb2R1bGVzIGFyZSBsb2FkZWQgb24gYm90aCBub2RlcyIKICAgICAgICAgICAgcmV0dXJuIDAKICAgICAgICBmaQogICAgICAgIGlmIFtbICIkaSIgLWVxIDYwIF1dOyB0aGVuCiAgICAgICAgICAgIGRpZSAiRFJCRCBtb2R1bGVzIGZhaWxlZCB0byBsb2FkIGFmdGVyIDEwIG1pbnV0ZXMuIENoZWNrOiBvYyBnZXQgbW9kdWxlLHBvZHMgLW4gb3BlbnNoaWZ0LWttbTsgb2MgZGVidWcgLXEgbm9kZS8ke05PREVfMH0gLS0gY2hyb290IC9ob3N0IGNhdCAvcHJvYy9tb2R1bGVzIHwgZ3JlcCAtRSAnXmRyYmR8ZHJiZF90cmFuc3BvcnQnIgogICAgICAgIGZpCiAgICAgICAgc2xlZXAgMTAKICAgIGRvbmUKfQoKIyBSdW4gZHJiZGFkbSBvbiBhIG5vZGUgdmlhIHBvZG1hbiB1c2luZyB0aGUgRFJCRCBpbWFnZTsgbW91bnRzIGhvc3QgZHJiZC5jb25mIGFuZCBkcmJkLmQuCmRyYmRjdGwoKSB7CiAgICBsb2NhbCBub2RlPSIkMSIKICAgIHNoaWZ0CiAgICBpZiAhIG9jIGRlYnVnIC1xICJub2RlLyRub2RlIiAtLSBjaHJvb3QgL2hvc3QgXAogICAgICAgIHBvZG1hbiBydW4gLS1ybSAtLXByaXZpbGVnZWQgXAogICAgICAgIC12IC9kZXY6L2RldiBcCiAgICAgICAgLXYgIiR7RFJCRF9DT05GX1BBVEh9OiR7RFJCRF9DT05GX1BBVEh9IiBcCiAgICAgICAgLXYgIiR7RFJCRF9ESVJfUEFUSH06JHtEUkJEX0RJUl9QQVRIfSIgXAogICAgICAgIC0taG9zdG5hbWUgIiRub2RlIiBcCiAgICAgICAgLS1uZXQgaG9zdCBcCiAgICAgICAgIiR7RFJCRF9JTUFHRX0iIFwKICAgICAgICBkcmJkYWRtIC1jICIke0RSQkRfQ09ORl9QQVRIfSIgIiRAIjsgdGhlbgogICAgICAgIGVjaG8gIkRSQkQgY29tbWFuZCBmYWlsZWQgb24gbm9kZSAkbm9kZTogZHJiZGFkbSAkKiIgPiYyCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCn0KCiMgVHJ1ZSB3aGVuIHRoZSBub2RlIGhhcyBhIHJvbGUgKFByaW1hcnkvU2Vjb25kYXJ5KSBmb3IgdGhlIERSQkQgcmVzb3VyY2UuCmRyYmRfbm9kZV9oYXNfcm9sZSgpIHsKICAgIGxvY2FsIG5vZGU9IiQxIiBzdGF0dXNfb3V0CiAgICBpZiAhIHN0YXR1c19vdXQ9JChkcmJkY3RsICIkbm9kZSIgc3RhdHVzICIke0RSQkRfUkVTT1VSQ0V9IiAyPiYxKTsgdGhlbgogICAgICAgIHJldHVybiAxCiAgICBmaQogICAgZWNobyAiJHN0YXR1c19vdXQiIHwgZ3JlcCAtcWlFICdyb2xlOltbOnNwYWNlOl1dKihQcmltYXJ5fFNlY29uZGFyeSknCn0KCiMgVHJ1ZSB3aGVuIGJvdGggbm9kZXMgc2hvdyBhIHJvbGUgKFByaW1hcnkvU2Vjb25kYXJ5KSBmb3IgdGhlIERSQkQgcmVzb3VyY2UuCmRyYmRfcmVzb3VyY2VfdXBfb25fYm90aF9ub2RlcygpIHsKICAgIGRyYmRfbm9kZV9oYXNfcm9sZSAiJE5PREVfMCIgJiYgZHJiZF9ub2RlX2hhc19yb2xlICIkTk9ERV8xIgp9CgojIGNvbmZpZ3VyZSB0aGUgRFJCRCByZXNvdXJjZSBvbiBib3RoIG5vZGVzCmNvbmZpZ3VyZV9kcmJkKCkgewogICAgaWYgZHJiZF9yZXNvdXJjZV91cF9vbl9ib3RoX25vZGVzOyB0aGVuCiAgICAgICAgbXNnICJEUkJEIHJlc291cmNlIGlzIGFscmVhZHkgdXAgb24gYm90aCBub2RlcyIKICAgICAgICByZXR1cm4gMAogICAgZmkKCiAgICBtc2cgIkNvbmZpZ3VyaW5nIERSQkQgcmVzb3VyY2UgXCIke0RSQkRfUkVTT1VSQ0V9XCIgb24gJHtOT0RFXzB9IGFuZCAke05PREVfMX0uIgogICAgbG9jYWwgRFJCRF9SRVNfQk9EWSBEUkJEX1JFU19CNjQgRFJCRF9NQUlOX0I2NAogICAgRFJCRF9SRVNfQk9EWT0iZ2xvYmFsIHsgdXNhZ2UtY291bnQgbm87IH0KY29tbW9uIHsKICAgIG5ldCB7IHByb3RvY29sIEM7IGFmdGVyLXNiLTBwcmkgZGlzY2FyZC16ZXJvLWNoYW5nZXM7IGFmdGVyLXNiLTFwcmkgZGlzY2FyZC1zZWNvbmRhcnk7IH0KICAgIGRpc2sgeyBvbi1pby1lcnJvciBwYXNzX29uOyB9CiAgICBvcHRpb25zIHsgb24tbm8tZGF0YS1hY2Nlc3NpYmxlIHN1c3BlbmQtaW87IH0KfQpyZXNvdXJjZSAke0RSQkRfUkVTT1VSQ0V9IHsKICAgIG9uICR7Tk9ERV8wfSB7CiAgICAgICAgZGV2aWNlICR7RFJCRF9ERVZJQ0V9OwogICAgICAgIGRpc2sgJHtESVNLX1JFU09MVkVEX05PREUwfTsKICAgICAgICBhZGRyZXNzICR7Tk9ERV8wX0lQfToke0RSQkRfUE9SVH07CiAgICAgICAgbm9kZS1pZCAwOwogICAgICAgIG1ldGEtZGlzayBpbnRlcm5hbDsKICAgIH0KICAgIG9uICR7Tk9ERV8xfSB7CiAgICAgICAgZGV2aWNlICR7RFJCRF9ERVZJQ0V9OwogICAgICAgIGRpc2sgJHtESVNLX1JFU09MVkVEX05PREUxfTsKICAgICAgICBhZGRyZXNzICR7Tk9ERV8xX0lQfToke0RSQkRfUE9SVH07CiAgICAgICAgbm9kZS1pZCAxOwogICAgICAgIG1ldGEtZGlzayBpbnRlcm5hbDsKICAgIH0KfSIKCiAgICBEUkJEX1JFU19CNjQ9JChwcmludGYgJyVzJyAiJERSQkRfUkVTX0JPRFkiIHwgYmFzZTY0IHwgdHIgLWQgJ1xuJykKICAgIERSQkRfTUFJTl9CNjQ9JChwcmludGYgJyVzJyAiaW5jbHVkZSBcIiR7RFJCRF9ESVJfUEFUSH0vKi5yZXNcIjsiIHwgYmFzZTY0IHwgdHIgLWQgJ1xuJykKCiAgICBsb2NhbCBub2RlIHJlc19wYXRoCiAgICByZXNfcGF0aD0iJHtEUkJEX0RJUl9QQVRIfS8ke0RSQkRfUkVTT1VSQ0V9LnJlcyIKICAgIGZvciBub2RlIGluICIkTk9ERV8wIiAiJE5PREVfMSI7IGRvCiAgICAgICAgbXNnICJOb2RlICR7bm9kZX06IHdyaXRpbmcgRFJCRCBjb25maWcgZmlsZXMgdG8gdGhlIGhvc3QuLi4iCiAgICAgICAgaWYgISBvYyBkZWJ1ZyAtcSAibm9kZS8kbm9kZSIgLS0gY2hyb290IC9ob3N0IGJhc2ggLWMgIgpta2RpciAtcCBcIiQoZGlybmFtZSAiJHtEUkJEX0NPTkZfUEFUSH0iKVwiICcke0RSQkRfRElSX1BBVEh9JyAvdmFyL2xpYi9kcmJkCmVjaG8gJyR7RFJCRF9SRVNfQjY0fScgfCBiYXNlNjQgLWQgPiAnJHtyZXNfcGF0aH0nCmVjaG8gJyR7RFJCRF9NQUlOX0I2NH0nIHwgYmFzZTY0IC1kID4gJyR7RFJCRF9DT05GX1BBVEh9JwoiOyB0aGVuCiAgICAgICAgICAgIGRpZSAiZmFpbGVkIHRvIHdyaXRlIERSQkQgY29uZmlnIG9uICRub2RlIgogICAgICAgIGZpCgogICAgICAgIGlmIGRyYmRfbm9kZV9oYXNfcm9sZSAiJG5vZGUiOyB0aGVuCiAgICAgICAgICAgIG1zZyAiTm9kZSAke25vZGV9OiByZXNvdXJjZSBhbHJlYWR5IGhhcyBhIHJvbGUgb24gdGhpcyBob3N0OyBydW5uaW5nIGRyYmRhZG0gYWRqdXN0Li4uIgogICAgICAgICAgICBpZiAhIGRyYmRjdGwgIiRub2RlIiBhZGp1c3QgIiR7RFJCRF9SRVNPVVJDRX0iOyB0aGVuCiAgICAgICAgICAgICAgICBkaWUgImRyYmRhZG0gYWRqdXN0IGZhaWxlZCBvbiAkbm9kZSIKICAgICAgICAgICAgZmkKICAgICAgICBlbHNlCiAgICAgICAgICAgIG1zZyAiTm9kZSAke25vZGV9OiBjcmVhdGluZyBEUkJEIG1ldGFkYXRhIHRoZW4gZHJiZGFkbSB1cC4uLiIKICAgICAgICAgICAgaWYgISBkcmJkY3RsICIkbm9kZSIgY3JlYXRlLW1kICIke0RSQkRfUkVTT1VSQ0V9IiAtLWZvcmNlOyB0aGVuCiAgICAgICAgICAgICAgICBkaWUgImRyYmRhZG0gY3JlYXRlLW1kIGZhaWxlZCBvbiAkbm9kZSIKICAgICAgICAgICAgZmkKICAgICAgICAgICAgaWYgISBkcmJkY3RsICIkbm9kZSIgdXAgIiR7RFJCRF9SRVNPVVJDRX0iOyB0aGVuCiAgICAgICAgICAgICAgICBkaWUgImRyYmRhZG0gdXAgZmFpbGVkIG9uICRub2RlIgogICAgICAgICAgICBmaQogICAgICAgIGZpCiAgICBkb25lCiAgICBtc2cgIkRSQkQgcmVzb3VyY2UgaXMgY29uZmlndXJlZCBhbmQgdGhlIHJlcGxpY2F0aW9uIGxpbmsgaXMgdXAuIgp9CgojIGNoZWNrIGlmIHRoZSBEUkJEIHJlc291cmNlIGlzIGZ1bGx5IHJlcGxpY2F0ZWQgb24gYm90aCBub2RlcwpkcmJkX3Jlc291cmNlX2Z1bGx5X3JlcGxpY2F0ZWQoKSB7CiAgICBsb2NhbCBuIHN0YXR1c19vdXQKICAgIGZvciBuIGluICIkTk9ERV8wIiAiJE5PREVfMSI7IGRvCiAgICAgICAgaWYgISBzdGF0dXNfb3V0PSQoZHJiZGN0bCAiJG4iIHN0YXR1cyAiJHtEUkJEX1JFU09VUkNFfSIgMj4mMSk7IHRoZW4KICAgICAgICAgICAgcmV0dXJuIDEKICAgICAgICBmaQogICAgICAgIGlmICEgZWNobyAiJHN0YXR1c19vdXQiIHwgZ3JlcCAtcSAiZGlzazpVcFRvRGF0ZSI7IHRoZW4KICAgICAgICAgICAgcmV0dXJuIDEKICAgICAgICBmaQogICAgICAgIGlmICEgZWNobyAiJHN0YXR1c19vdXQiIHwgZ3JlcCAtcSAicGVlci1kaXNrOlVwVG9EYXRlIjsgdGhlbgogICAgICAgICAgICByZXR1cm4gMQogICAgICAgIGZpCiAgICBkb25lCiAgICByZXR1cm4gMAp9CgojIENoZWNrIHN0YXR1cyBvZiByZXBsaWNhdGlvbiBlYWNoIDMwcyBhbmQgd2FpdCBmb3IgaXQgdG8gY29tcGxldGUuCnN5bmNfZHJiZCgpIHsKICAgICMgVHJhbnNpZW50IFByaW1hcnkgb24gZmlyc3Qgc29ydGVkIG5vZGUgZm9yIHN5bmM7IHRoZW4gZGVtb3RlIHRvIFNlY29uZGFyeSBvbiBib3RoIG5vZGVzLgogICAgbG9jYWwgUFJJTUFSWV9OT0RFPSIkTk9ERV8wIgogICAgRFJCRF9QUk9NT1RFRF9NQVNURVIwX1RISVNfUlVOPTAKCiAgICBpZiBkcmJkX3Jlc291cmNlX2Z1bGx5X3JlcGxpY2F0ZWQ7IHRoZW4KICAgICAgICBtc2cgIkRSQkQgZGF0YSBpcyBhbHJlYWR5IGZ1bGx5IHJlcGxpY2F0ZWQgKFVwVG9EYXRlIG9uIGJvdGggbm9kZXMpOyBza2lwcGluZyBwcmltYXJ5L3N5bmMgd2FpdC4iCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgbXNnICJQcm9tb3RpbmcgJFBSSU1BUllfTk9ERSB0byBQcmltYXJ5IHRvIHJ1biBpbml0aWFsIHJlcGxpY2F0aW9uLi4uIgogICAgaWYgISBkcmJkY3RsICIkUFJJTUFSWV9OT0RFIiBwcmltYXJ5IC0tZm9yY2UgIiREUkJEX1JFU09VUkNFIjsgdGhlbgogICAgICAgIGRpZSAiZHJiZGFkbSBwcmltYXJ5IGZhaWxlZCBvbiAkUFJJTUFSWV9OT0RFIgogICAgZmkKICAgIERSQkRfUFJPTU9URURfTUFTVEVSMF9USElTX1JVTj0xCgogICAgIyBQb2xsIGRyYmRhZG0gc3RhdHVzIG9uIHRoZSB0cmFuc2llbnQgcHJpbWFyeSB1bnRpbCBwZWVyLWRpc2s6VXBUb0RhdGUgKGZ1bGwgc3luYykuIEV4YW1wbGUKICAgICMgZnJhZ21lbnQgd2hpbGUgc3luY2luZzogbGluZXMgd2l0aCBkaXNrOi9wZWVyLWRpc2s6IGFuZCBwb3NzaWJseSBkb25lOjEyLjM0JSBmb3IgcHJvZ3Jlc3MuCiAgICBtc2cgIldhaXRpbmcgZm9yIGZ1bGwgRFJCRCBzeW5jICh1cCB0byAzMCBtaW47IHByb2dyZXNzIGV2ZXJ5IDMwcyB3aGVuIGF2YWlsYWJsZSkuLi4iCiAgICBfd2FpdF9iZWdpbgogICAgbG9jYWwgaSBTVEFUVVMgUFJPR1JFU1MKICAgIGZvciBpIGluICQoc2VxIDEgNjApOyBkbwogICAgICAgIFNUQVRVUz0kKGRyYmRjdGwgIiRQUklNQVJZX05PREUiIHN0YXR1cyAiJERSQkRfUkVTT1VSQ0UiIDI+L2Rldi9udWxsKQogICAgICAgIGlmIGVjaG8gIiRTVEFUVVMiIHwgZ3JlcCAtcSAicGVlci1kaXNrOlVwVG9EYXRlIjsgdGhlbgogICAgICAgICAgICBfd2FpdF9zdWNjZWVkZWQgIkluaXRpYWwgcmVwbGljYXRpb24gZmluaXNoZWQ7IGJvdGggbm9kZXMgcmVwb3J0IFVwVG9EYXRlIgogICAgICAgICAgICByZXR1cm4gMAogICAgICAgIGZpCiAgICAgICAgUFJPR1JFU1M9JChlY2hvICIkU1RBVFVTIiB8IGdyZXAgLW8gJ2RvbmU6WzAtOS5dKicgfCBoZWFkIC0xIHwgY3V0IC1kOiAtZjIpCiAgICAgICAgaWYgW1sgLW4gIiRQUk9HUkVTUyIgXV07IHRoZW4KICAgICAgICAgICAgbXNnICJSZXBsaWNhdGlvbiBwcm9ncmVzczogJHtQUk9HUkVTU30lIgogICAgICAgIGZpCiAgICAgICAgaWYgW1sgIiRpIiAtZXEgNjAgXV07IHRoZW4KICAgICAgICAgICAgZGllICJEUkJEIHN5bmMgdGltZWQgb3V0IGFmdGVyIDMwbS4gU3RhdHVzOiAkU1RBVFVTIgogICAgICAgIGZpCiAgICAgICAgc2xlZXAgMzAKICAgIGRvbmUKfQoKIyBjcmVhdGUgdGhlIGZpbGVzeXN0ZW0gb3ZlciB0aGUgRFJCRCBkZXZpY2UKY3JlYXRlX2ZpbGVzeXN0ZW1fb3Zlcl9kcmJkKCkgewogICAgbG9jYWwgUFJJTUFSWV9OT0RFPSIkTk9ERV8wIgogICAgbG9jYWwgZnN0eXBlCiAgICBpZiAhIGZzdHlwZT0kKG9jIGRlYnVnIC1xICJub2RlLyRQUklNQVJZX05PREUiIC0tIGNocm9vdCAvaG9zdCBibGtpZCAtcyBUWVBFIC1vIHZhbHVlICIke0RSQkRfREVWSUNFfSIgMj4vZGV2L251bGwgfCB0ciAtZCAnIFxuJyk7IHRoZW4KICAgICAgICBmc3R5cGU9IiIKICAgIGZpCiAgICBpZiBbWyAiJGZzdHlwZSIgPT0gInhmcyIgXV07IHRoZW4KICAgICAgICBtc2cgIiR7RFJCRF9ERVZJQ0V9IGFscmVhZHkgaGFzIFhGUzsgc2tpcHBpbmcgbWtmcyAocmUtcnVuIHNhZmUpLiIKICAgICAgICByZXR1cm4gMAogICAgZmkKCiAgICBtc2cgIkZvcm1hdHRpbmcgJHtEUkJEX0RFVklDRX0gd2l0aCBYRlMgKG1rZnMueGZzIC1mOyBvdmVyd3JpdGVzIGFueSBleGlzdGluZyBzaWduYXR1cmUpLi4uIgogICAgb2MgZGVidWcgLXEgIm5vZGUvJFBSSU1BUllfTk9ERSIgLS0gY2hyb290IC9ob3N0IHN1ZG8gbWtmcy54ZnMgLWYgIiR7RFJCRF9ERVZJQ0V9IgogICAgbXNnICJYRlMgY3JlYXRlZCBvbiAke0RSQkRfREVWSUNFfS4iCn0KCiMgRGVtb3RlIHRoZSB0cmFuc2llbnQgcHJpbWFyeSB1c2VkIGZvciBpbml0aWFsIHN5bmMgYmFjayB0byBTZWNvbmRhcnkuCm1ha2VfYm90aF9ub2RlX3NlY29uZGFyeSgpIHsKICAgIGlmIFtbICIke0RSQkRfUFJPTU9URURfTUFTVEVSMF9USElTX1JVTjotMH0iIC1uZSAxIF1dOyB0aGVuCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgbG9jYWwgUFJJTUFSWV9OT0RFPSIkTk9ERV8wIgogICAgbG9jYWwgaSBST0xFCgogICAgUk9MRT0kKGRyYmRjdGwgIiRQUklNQVJZX05PREUiIHJvbGUgIiR7RFJCRF9SRVNPVVJDRX0iIDI+L2Rldi9udWxsIHwgY3V0IC1kLyAtZjEpCiAgICBpZiBbWyAiJFJPTEUiID09ICJTZWNvbmRhcnkiIF1dOyB0aGVuCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgbXNnICJEZW1vdGluZyAkUFJJTUFSWV9OT0RFIHRvIFNlY29uZGFyeS4iCiAgICBpZiAhIGRyYmRjdGwgIiRQUklNQVJZX05PREUiIHNlY29uZGFyeSAiJERSQkRfUkVTT1VSQ0UiOyB0aGVuCiAgICAgICAgZGllICJkcmJkYWRtIHNlY29uZGFyeSBmYWlsZWQgb24gJFBSSU1BUllfTk9ERSIKICAgIGZpCgogICAgbXNnICJXYWl0aW5nIGZvciAkUFJJTUFSWV9OT0RFIHRvIHJlcG9ydCBTZWNvbmRhcnkgcm9sZSAodXAgdG8gNDBzKS4uLiIKICAgIF93YWl0X2JlZ2luCiAgICBmb3IgaSBpbiAkKHNlcSAxIDIwKTsgZG8KICAgICAgICBST0xFPSQoZHJiZGN0bCAiJFBSSU1BUllfTk9ERSIgcm9sZSAiJHtEUkJEX1JFU09VUkNFfSIgMj4vZGV2L251bGwgfCBjdXQgLWQvIC1mMSkKICAgICAgICBpZiBbWyAiJFJPTEUiID09ICJTZWNvbmRhcnkiIF1dOyB0aGVuCiAgICAgICAgICAgIF93YWl0X3N1Y2NlZWRlZCAiJFBSSU1BUllfTk9ERSBpcyBub3cgU2Vjb25kYXJ5IgogICAgICAgICAgICByZXR1cm4gMAogICAgICAgIGZpCiAgICAgICAgc2xlZXAgMgogICAgZG9uZQogICAgZGllICJOb2RlICRQUklNQVJZX05PREUgZGlkIG5vdCBiZWNvbWUgU2Vjb25kYXJ5Igp9CgojIHNldHVwIHRoZSBEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0IHRvIGtlZXAgdGhlIERSQkQgcmVzb3VyY2UgdXAgb24gYm90aCBub2RlcwpzZXR1cF9kcmJkX2F1dG9zdGFydCgpIHsKICAgIGlmIG9jIGdldCBkYWVtb25zZXQgIiR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OQU1FfSIgLW4gIiR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OU30iICY+L2Rldi9udWxsOyB0aGVuCiAgICAgICAgbXNnICJEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0IGFscmVhZHkgZXhpc3RzLiIKICAgICAgICByZXR1cm4gMAogICAgZmkKCiAgICBtc2cgIkNyZWF0aW5nIERSQkQgYXV0by1zdGFydCBEYWVtb25TZXQgaW4gbmFtZXNwYWNlICR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OU30uLi4iCiAgICBvYyBjcmVhdGUgbmFtZXNwYWNlICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9IiAtLWRyeS1ydW49Y2xpZW50IC1vIHlhbWwgfCBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgMj4mMQogICAgb2MgY3JlYXRlIHNlcnZpY2VhY2NvdW50IGRyYmQtYXV0b3N0YXJ0IC1uICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9IiAtLWRyeS1ydW49Y2xpZW50IC1vIHlhbWwgfCBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgMj4mMQogICAgb2MgYWRtIHBvbGljeSBhZGQtc2NjLXRvLXVzZXIgcHJpdmlsZWdlZCAteiBkcmJkLWF1dG9zdGFydCAtbiAiJHtBVVRPU1RBUlRfREFFTU9OU0VUX05TfSIgPi9kZXYvbnVsbAoKICAgIG9jIGFwcGx5IC1mIC0gPi9kZXYvbnVsbCA8PEVPRgphcGlWZXJzaW9uOiB2MQpraW5kOiBDb25maWdNYXAKbWV0YWRhdGE6CiAgbmFtZTogZHJiZC1hdXRvc3RhcnQtc2NyaXB0CiAgbmFtZXNwYWNlOiAke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9CmRhdGE6CiAgc3RhcnQuc2g6IHwKICAgICMhL2Jpbi9iYXNoCiAgICB3aGlsZSB0cnVlOyBkbwogICAgICAgIGlmIGRyYmRhZG0gLWMgIiR7RFJCRF9DT05GX1BBVEh9IiBzdGF0dXMgJHtEUkJEX1JFU09VUkNFfSAmPi9kZXYvbnVsbDsgdGhlbgogICAgICAgICAgICBlY2hvICJEUkJEIHJlc291cmNlICR7RFJCRF9SRVNPVVJDRX0gaXMgYWxyZWFkeSB1cCIKICAgICAgICBlbHNlCiAgICAgICAgICAgIGVjaG8gIlN0YXJ0aW5nIERSQkQgcmVzb3VyY2UgJHtEUkJEX1JFU09VUkNFfS4uLiIKICAgICAgICAgICAgaWYgISBkcmJkYWRtIC1jICIke0RSQkRfQ09ORl9QQVRIfSIgdXAgJHtEUkJEX1JFU09VUkNFfTsgdGhlbgogICAgICAgICAgICAgICAgZWNobyAiV2FybmluZzogZHJiZGFkbSB1cCBmYWlsZWQsIHdpbGwgcmV0cnkiCiAgICAgICAgICAgIGZpCiAgICAgICAgZmkKICAgICAgICBpZiAhIGRyYmRhZG0gLWMgIiR7RFJCRF9DT05GX1BBVEh9IiBzdGF0dXMgJHtEUkJEX1JFU09VUkNFfTsgdGhlbgogICAgICAgICAgICA6CiAgICAgICAgZmkKICAgICAgICBzbGVlcCA2MAogICAgZG9uZQpFT0YKCiAgICBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgPDxFT0YKYXBpVmVyc2lvbjogYXBwcy92MQpraW5kOiBEYWVtb25TZXQKbWV0YWRhdGE6CiAgbmFtZTogJHtBVVRPU1RBUlRfREFFTU9OU0VUX05BTUV9CiAgbmFtZXNwYWNlOiAke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9CiAgbGFiZWxzOgogICAgYXBwOiAke0FVVE9TVEFSVF9EQUVNT05TRVRfTkFNRX0Kc3BlYzoKICBzZWxlY3RvcjoKICAgIG1hdGNoTGFiZWxzOgogICAgICBhcHA6ICR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OQU1FfQogIHRlbXBsYXRlOgogICAgbWV0YWRhdGE6CiAgICAgIGxhYmVsczoKICAgICAgICBhcHA6ICR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OQU1FfQogICAgc3BlYzoKICAgICAgc2VydmljZUFjY291bnROYW1lOiBkcmJkLWF1dG9zdGFydAogICAgICBob3N0TmV0d29yazogdHJ1ZQogICAgICBob3N0UElEOiB0cnVlCiAgICAgIGNvbnRhaW5lcnM6CiAgICAgIC0gbmFtZTogZHJiZC1zdGFydGVyCiAgICAgICAgaW1hZ2U6ICR7RFJCRF9JTUFHRX0KICAgICAgICBjb21tYW5kOiBbIi9iaW4vYmFzaCIsICIvc2NyaXB0cy9zdGFydC5zaCJdCiAgICAgICAgc2VjdXJpdHlDb250ZXh0OgogICAgICAgICAgcHJpdmlsZWdlZDogdHJ1ZQogICAgICAgICAgY2FwYWJpbGl0aWVzOgogICAgICAgICAgICBhZGQ6CiAgICAgICAgICAgIC0gU1lTX0FETUlOCiAgICAgICAgICAgIC0gU1lTX01PRFVMRQogICAgICAgICAgICAtIE5FVF9BRE1JTgogICAgICAgIHZvbHVtZU1vdW50czoKICAgICAgICAtIG5hbWU6IHNjcmlwdHMKICAgICAgICAgIG1vdW50UGF0aDogL3NjcmlwdHMKICAgICAgICAgIHJlYWRPbmx5OiB0cnVlCiAgICAgICAgLSBuYW1lOiBkcmJkLWNvbmYKICAgICAgICAgIG1vdW50UGF0aDogJHtEUkJEX0NPTkZfUEFUSH0KICAgICAgICAtIG5hbWU6IGRyYmQtZGlyCiAgICAgICAgICBtb3VudFBhdGg6ICR7RFJCRF9ESVJfUEFUSH0KICAgICAgICAtIG5hbWU6IGRldgogICAgICAgICAgbW91bnRQYXRoOiAvZGV2CiAgICAgICAgcmVzb3VyY2VzOgogICAgICAgICAgcmVxdWVzdHM6CiAgICAgICAgICAgIGNwdTogMTBtCiAgICAgICAgICAgIG1lbW9yeTogMzJNaQogICAgICAgICAgbGltaXRzOgogICAgICAgICAgICBjcHU6IDEwMG0KICAgICAgICAgICAgbWVtb3J5OiA2NE1pCiAgICAgIHZvbHVtZXM6CiAgICAgIC0gbmFtZTogc2NyaXB0cwogICAgICAgIGNvbmZpZ01hcDoKICAgICAgICAgIG5hbWU6IGRyYmQtYXV0b3N0YXJ0LXNjcmlwdAogICAgICAgICAgZGVmYXVsdE1vZGU6IDA3NTUKICAgICAgLSBuYW1lOiBkcmJkLWNvbmYKICAgICAgICBob3N0UGF0aDoKICAgICAgICAgIHBhdGg6ICR7RFJCRF9DT05GX1BBVEh9CiAgICAgICAgICB0eXBlOiBGaWxlCiAgICAgIC0gbmFtZTogZHJiZC1kaXIKICAgICAgICBob3N0UGF0aDoKICAgICAgICAgIHBhdGg6ICR7RFJCRF9ESVJfUEFUSH0KICAgICAgICAgIHR5cGU6IERpcmVjdG9yeQogICAgICAtIG5hbWU6IGRldgogICAgICAgIGhvc3RQYXRoOgogICAgICAgICAgcGF0aDogL2RldgogICAgICAgICAgdHlwZTogRGlyZWN0b3J5CiAgICAgIHRvbGVyYXRpb25zOgogICAgICAtIG9wZXJhdG9yOiBFeGlzdHMKICAgICAgICBlZmZlY3Q6IE5vU2NoZWR1bGUKICAgICAgLSBvcGVyYXRvcjogRXhpc3RzCiAgICAgICAgZWZmZWN0OiBOb0V4ZWN1dGUKRU9GCgogICAgbXNnICJXYWl0aW5nIGZvciBEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0IHBvZHMgb24gYm90aCBub2RlcyAodXAgdG8gNSBtaW4pLi4uIgogICAgX3dhaXRfYmVnaW4KICAgIGxvY2FsIGkgUkVBRFlfQ09VTlQKICAgIGZvciBpIGluICQoc2VxIDEgNjApOyBkbwogICAgICAgIGlmICEgUkVBRFlfQ09VTlQ9JChvYyBnZXQgZGFlbW9uc2V0ICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTkFNRX0iIC1uICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9IiAtbyBqc29ucGF0aD0ney5zdGF0dXMubnVtYmVyUmVhZHl9JyAyPi9kZXYvbnVsbCk7IHRoZW4KICAgICAgICAgICAgUkVBRFlfQ09VTlQ9MAogICAgICAgIGZpCiAgICAgICAgaWYgW1sgLXogIiRSRUFEWV9DT1VOVCIgXV07IHRoZW4KICAgICAgICAgICAgUkVBRFlfQ09VTlQ9MAogICAgICAgIGZpCiAgICAgICAgUkVBRFlfQ09VTlQ9JCgoMCArIFJFQURZX0NPVU5UKSkKICAgICAgICBpZiBbWyAiJFJFQURZX0NPVU5UIiAtZXEgMiBdXTsgdGhlbgogICAgICAgICAgICBfd2FpdF9zdWNjZWVkZWQgIkRSQkQgYXV0by1zdGFydCBEYWVtb25TZXQgaXMgcnVubmluZyBvbiBib3RoIG5vZGVzIgogICAgICAgICAgICByZXR1cm4gMAogICAgICAgIGZpCiAgICAgICAgaWYgW1sgIiRpIiAtZXEgNjAgXV07IHRoZW4KICAgICAgICAgICAgZGllICJEYWVtb25TZXQgbm90IHJlYWR5IChvYyBnZXQgZHMscG9kcyAtbiAke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9KSIKICAgICAgICBmaQogICAgICAgIHNsZWVwIDUKICAgIGRvbmUKfQoKIyBjcmVhdGUgdGhlIHN1Y2Nlc3MgQ29uZmlnTWFwIHRvIHNhdmUgdGhlIHNldHVwIHN1bW1hcnkgZm9yIGZ1cnRoZXIgY29uc3VtcHRpb24uCmNyZWF0ZV9zdWNjZXNzX2NvbmZpZ21hcCgpIHsKICAgIG1zZyAiU2F2aW5nIHNldHVwIHN1bW1hcnkgdG8gQ29uZmlnTWFwICR7T1VUUFVUX0NNX05TfS8ke09VVFBVVF9DTV9OQU1FfSIKICAgIGlmICEgb2MgY3JlYXRlIG5hbWVzcGFjZSAiJHtPVVRQVVRfQ01fTlN9IiAtLWRyeS1ydW49Y2xpZW50IC1vIHlhbWwgfCBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgMj4mMTsgdGhlbgogICAgICAgIDoKICAgIGZpCgogICAgbG9jYWwgYmQwIGJkMQogICAgaWYgW1sgLW4gIiRCQUNLSU5HX1BBVEgiIF1dOyB0aGVuCiAgICAgICAgYmQwPSIkQkFDS0lOR19QQVRIIgogICAgICAgIGJkMT0iJEJBQ0tJTkdfUEFUSCIKICAgIGVsc2UKICAgICAgICBiZDA9IiRCQUNLSU5HX1BBVEhfTk9ERTAiCiAgICAgICAgYmQxPSIkQkFDS0lOR19QQVRIX05PREUxIgogICAgZmkKCiAgICBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgPDxFT0YKYXBpVmVyc2lvbjogdjEKa2luZDogQ29uZmlnTWFwCm1ldGFkYXRhOgogIG5hbWU6ICR7T1VUUFVUX0NNX05BTUV9CiAgbmFtZXNwYWNlOiAke09VVFBVVF9DTV9OU30KICBsYWJlbHM6CiAgICBhcHAua3ViZXJuZXRlcy5pby9uYW1lOiBkcmJkLXNldHVwCiAgICBhcHAua3ViZXJuZXRlcy5pby9jb21wb25lbnQ6IHN0b3JhZ2UKZGF0YToKICBOT0RFXzBfTkFNRTogIiR7Tk9ERV8wfSIKICBOT0RFXzFfTkFNRTogIiR7Tk9ERV8xfSIKICBOT0RFXzBfSVA6ICIke05PREVfMF9JUH0iCiAgTk9ERV8xX0lQOiAiJHtOT0RFXzFfSVB9IgogIEJMT0NLX0RFVklDRV9QQVRIX05PREVfMDogIiR7YmQwfSIKICBCTE9DS19ERVZJQ0VfUEFUSF9OT0RFXzE6ICIke2JkMX0iCiAgRElTS19CWV9JRF9OT0RFXzA6ICIke0RJU0tfUkVTT0xWRURfTk9ERTB9IgogIERJU0tfQllfSURfTk9ERV8xOiAiJHtESVNLX1JFU09MVkVEX05PREUxfSIKICBEUkJEX0NPTkZfUEFUSDogIiR7RFJCRF9DT05GX1BBVEh9IgogIERSQkRfRElSX1BBVEg6ICIke0RSQkRfRElSX1BBVEh9IgogIERSQkRfREVWSUNFX05BTUU6ICIke0RSQkRfREVWSUNFfSIKICBEUkJEX1JFU09VUkNFX05BTUU6ICIke0RSQkRfUkVTT1VSQ0V9IgogIERSQkRfUE9SVDogIiR7RFJCRF9QT1JUfSIKICBEUkJEX1VUSUxTX0lNQUdFOiAiJHtEUkJEX0lNQUdFfSIKICBEUkJEX1ZFUlNJT046ICIke0RSQkRfVkVSU0lPTn0iCiAgU0VUVVBfVElNRVNUQU1QOiAiJChkYXRlIC11ICslWS0lbS0lZFQlSDolTTolU1opIgpFT0YKfQoKcHJpbnRfc3VjY2VzcygpIHsKICAgIGVjaG8gIiIKICAgIGVjaG8gIiAgLS0+IERSQkQgc2V0dXAgY29tcGxldGVkIHN1Y2Nlc3NmdWxseSA8LS0iCiAgICBlY2hvICIiCiAgICBlY2hvICJQb3N0LWluc3RhbGwgRFJCRCBzdGF0dXMgb24gJHtOT0RFXzB9IChyZXBlYXQgd2l0aCAke05PREVfMX0pOiIKICAgIGVjaG8gIiAgb2MgZGVidWcgLXEgbm9kZS8ke05PREVfMH0gLS0gY2hyb290IC9ob3N0IHBvZG1hbiBydW4gLS1ybSAtLXByaXZpbGVnZWQgXFwiCiAgICBlY2hvICIgICAgLXYgL2RldjovZGV2IC12ICR7RFJCRF9DT05GX1BBVEh9OiR7RFJCRF9DT05GX1BBVEh9IC12ICR7RFJCRF9ESVJfUEFUSH06JHtEUkJEX0RJUl9QQVRIfSBcXCIKICAgIGVjaG8gIiAgICAtLWhvc3RuYW1lICR7Tk9ERV8wfSAtLW5ldCBob3N0ICR7RFJCRF9JTUFHRX0gZHJiZGFkbSAtYyAke0RSQkRfQ09ORl9QQVRIfSBzdGF0dXMgJHtEUkJEX1JFU09VUkNFfSIKICAgIGVjaG8gIiIKfQoKbWFpbigpIHsKICAgIHBhcnNlX2FyZ3MgIiRAIgogICAgY2hlY2tfcHJlcmVxdWlzaXRlcyAjIGNoZWNrIGlmIHRoZSBwcmVyZXF1aXNpdGVzIGFyZSBtZXQKICAgIGRldGVjdF9ub2RlcyAjIGRldGVjdCB0aGUgbm9kZXMgaW4gdGhlIGNsdXN0ZXIKCiAgICBpZiBbWyAiJExJU1RfREVWSUNFU19PTkxZIiAtZXEgMSBdXTsgdGhlbgogICAgICAgIGxpc3RfZGV2aWNlcyAjIGxpc3QgdGhlIGJsb2NrIGRldmljZXMgb24gdGhlIG5vZGVzCiAgICAgICAgZXhpdCAwCiAgICBmaQoKICAgIHByaW50X2NvbmZpZyAjIHByaW50IHRoZSBjb25maWd1cmF0aW9uCiAgICB2YWxpZGF0ZV9hbmRfcmVzb2x2ZV9kaXNrcyAjIHZhbGlkYXRlIHRoZSBkaXNrcyBhbmQgcmVzb2x2ZSB0aGUgZGlzayBieS1pZCBzeW1saW5rIGZvciBEUkJEIGNvbmZpZyBvbiB0aGF0IG5vZGUKICAgIHNldHVwX2ttbV9vcGVyYXRvciAjIHNldHVwIHRoZSBLTU0gb3BlcmF0b3IKICAgIHNldHVwX2ltYWdlX3JlZ2lzdHJ5X29wZXJhdG9yICMgc2V0dXAgdGhlIGltYWdlIHJlZ2lzdHJ5IG9wZXJhdG9yCiAgICBrbW1faW1hZ2VfYnVpbGRfd2FpdHMgIyB3YWl0IGZvciB0aGUgU2VydmljZUFjY291bnQgYnVpbGRlciBhbmQgdGhlIGJ1aWxkZXIgZG9ja2VyY2ZnIFNlY3JldCB0byBiZSBwb3B1bGF0ZWQKICAgIGNyZWF0ZV9kcmJkX21vZHVsZSAjIGNyZWF0ZSB0aGUgS01NIE1vZHVsZSBDUiBhbmQgZG9ja2VyZmlsZSBDb25maWdNYXAgdG8gYnVpbGQgYW5kIGxvYWQgRFJCRCBrZXJuZWwgbW9kdWxlcyBvbiB0aGUgbm9kZXMKICAgIHdhaXRfZm9yX21vZHVsZXMgIyB3YWl0IGZvciB0aGUgRFJCRCBrZXJuZWwgbW9kdWxlcyB0byBsb2FkIG9uIGJvdGggbm9kZXMKICAgIGNvbmZpZ3VyZV9kcmJkICMgY29uZmlndXJlIHRoZSBEUkJEIHJlc291cmNlIG9uIGJvdGggbm9kZXMKICAgIHN5bmNfZHJiZCAjIHN5bmMgdGhlIERSQkQgcmVzb3VyY2Ugb24gYm90aCBub2RlcwogICAgY3JlYXRlX2ZpbGVzeXN0ZW1fb3Zlcl9kcmJkICMgY3JlYXRlIHRoZSBmaWxlc3lzdGVtIG92ZXIgdGhlIERSQkQgZGV2aWNlCiAgICBtYWtlX2JvdGhfbm9kZV9zZWNvbmRhcnkgIyBtYWtlIGJvdGggbm9kZXMgc2Vjb25kYXJ5CiAgICBzZXR1cF9kcmJkX2F1dG9zdGFydCAjIHNldHVwIHRoZSBEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0IHRvIGtlZXAgdGhlIERSQkQgcmVzb3VyY2UgdXAgb24gYm90aCBub2RlcwogICAgY3JlYXRlX3N1Y2Nlc3NfY29uZmlnbWFwICMgY3JlYXRlIHRoZSBzdWNjZXNzIENvbmZpZ01hcCB0byBzYXZlIHRoZSBzZXR1cCBzdW1tYXJ5IGZvciBmdXJ0aGVyIGNvbnN1bXB0aW9uCiAgICBwcmludF9zdWNjZXNzICMgcHJpbnQgdGhlIHN1Y2Nlc3MgbWVzc2FnZQp9CgptYWluICIkQCIK" + script: "IyEvYmluL2Jhc2gKIwojIENvcHlyaWdodCAyMDI2IFRoZSBSb29rIEF1dGhvcnMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKIyBEUkJEIFNldHVwIFNjcmlwdCBmb3IgVHdvLU5vZGUgT3BlblNoaWZ0IENsdXN0ZXIsIFNhZmUgdG8gcmUtcnVuKCBpZGVtcG90ZW50ICkuCiMgVGhlIHNjcmlwdCBjYW4gc2tpcCBzdWNjZXNzZnVsIHN0ZXBzICYgcnVuIG9ubHkgdGhlIHJlcXVpcmVkIHN0ZXBzLgojCiMgUHJlcmVxdWlzaXRlczoKIyAgIC0gTm9kZXMgY2FuIHB1bGwgJHtEUkJEX0lNQUdFfTsKIyAgIC0gJHtEUkJEX1BPUlR9L3RjcCBvcGVuIGJldHdlZW4gbm9kZXMuCiMKc2V0IC1ldW8gcGlwZWZhaWwKCmRpZSgpIHsKICAgIGVjaG8gIkVycm9yOiAkKiIgPiYyCiAgICBlY2hvICJQbGVhc2UgdHJ5IHJlLXJ1bm5pbmcgdGhlIHNjcmlwdC4iID4mMgogICAgZXhpdCAxCn0KbXNnKCkgeyBlY2hvICJEUkJEOiAkKiI7IH0KCiMgV2FsbC1jbG9jayB3YWl0IGhlbHBlcnM6IGNhbGwgX3dhaXRfYmVnaW4gaW1tZWRpYXRlbHkgYmVmb3JlIGEgcG9sbGluZyBsb29wOyBvbiBzdWNjZXNzIGNhbGwgX3dhaXRfc3VjY2VlZGVkICJtZXNzYWdlIi4KX3dhaXRfYmVnaW4oKSB7IF9XQUlUX1QwPSQoZGF0ZSArJXMpOyB9Cgpfd2FpdF9zdWNjZWVkZWQoKSB7CiAgICBsb2NhbCBkPSQoKCAkKGRhdGUgKyVzKSAtIF9XQUlUX1QwICkpCiAgICBpZiAoKCBkIDwgNjAgKSk7IHRoZW4KICAgICAgICBtc2cgIiQxIChpbiAke2R9cykiCiAgICBlbGlmICgoIGQgPCAzNjAwICkpOyB0aGVuCiAgICAgICAgbXNnICIkMSAoaW4gJCgoZCAvIDYwKSkgbWluICQoKGQgJSA2MCkpcykiCiAgICBlbHNlCiAgICAgICAgbXNnICIkMSAoaW4gJCgoZCAvIDYwKSkgbWluKSIKICAgIGZpCn0KCiMgVE9ETzogYnVtcCBkZWZhdWx0IGltYWdlIHRhZyB3aGVuIGEgbmV3IG9uZSBpcyBwdWJsaXNoZWQuCkRSQkRfSU1BR0U9IiR7RFJCRF9JTUFHRTotcXVheS5pby9yaGNlcGgtZGV2L29kZjQtb2RmLWRyYmQtcmhlbDk6djQuMjIuMH0iICMgT0RGIERSQkQgaW1hZ2UgKGRyYmRhZG0gKyBzb3VyY2VzKQojIFRPRE86IGJ1bXAgd2hlbiB0YXJiYWxsIGluc2lkZSB0aGUgaW1hZ2UgY2hhbmdlcy4KRFJCRF9WRVJTSU9OPSIke0RSQkRfVkVSU0lPTjotOS4yLjE4fSIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTXVzdCBtYXRjaCBEUkJEIHNvdXJjZSB2ZXJzaW9uIGluIERSQkRfSU1BR0UKCkRSQkRfQ09ORl9QQVRIPSIke0RSQkRfQ09ORl9QQVRIOi0vZXRjL2RyYmQuY29uZn0iICAgICAgICAgICAgICAgIyBNYWluIGZpbGU6IGluY2x1ZGUgb2YgJHtEUkJEX0RJUl9QQVRIfS8qLnJlcyBvbmx5CkRSQkRfRElSX1BBVEg9IiR7RFJCRF9ESVJfUEFUSDotL2V0Yy9kcmJkLmR9IiAgICAgICAgICAgICAgICAgICAgIyBQZXItcmVzb3VyY2UgLnJlcyBmaWxlcyAoYWN0dWFsIERSQkQgZGVmaW5pdGlvbikKRFJCRF9SRVNPVVJDRT0iJHtEUkJEX1JFU09VUkNFOi1yMH0iICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIERSQkQgcmVzb3VyY2UgbmFtZSAoZS5nLiByMCkKRFJCRF9ERVZJQ0U9IiR7RFJCRF9ERVZJQ0U6LS9kZXYvZHJiZDB9IiAgICAgICAgICAgICAgICAgICAgICAgICAjIERSQkQgYmxvY2sgZGV2aWNlIHBhdGggb24gbm9kZXMgKGUuZy4gL2Rldi9kcmJkMCkKRFJCRF9QT1JUPSIke0RSQkRfUE9SVDotNzc5NH0iICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIERSQkQgcmVwbGljYXRpb24gVENQIHBvcnQgKGUuZy4gNzc5NCkKCkFVVE9TVEFSVF9EQUVNT05TRVRfTkFNRT0iJHtBVVRPU1RBUlRfREFFTU9OU0VUX05BTUU6LWRyYmQtYXV0b3N0YXJ0fSIgIyBEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0IG5hbWUKQVVUT1NUQVJUX0RBRU1PTlNFVF9OUz0iJHtBVVRPU1RBUlRfREFFTU9OU0VUX05TOi1vcGVuc2hpZnQta21tfSIgICAgICAjIERSQkQgYXV0by1zdGFydCBEYWVtb25TZXQgbmFtZXNwYWNlCgpPVVRQVVRfQ01fTkFNRT0iJHtPVVRQVVRfQ01fTkFNRTotZHJiZC1jb25maWd1cmV9IiAgICAgICAgICAgICAgICMgTmFtZSBmb3IgdGhlIHNldHVwIHN1bW1hcnkgQ29uZmlnTWFwCgojIE9wZW5TaGlmdCBuYW1lc3BhY2UgZm9yIERSQkQgc3VtbWFyeSBDb25maWdNYXAsIENlcGhDbHVzdGVyLCBhbmQgZmxvYXRpbmcgbW9uIChkZWZhdWx0IE9wZW5TaGlmdCBPREYpLgpPREZfTkFNRVNQQUNFPSIke09ERl9OQU1FU1BBQ0U6LW9wZW5zaGlmdC1zdG9yYWdlfSIKCiMgaW5zdGFsbCB8IHVwZ3JhZGUgKHNldCBpbiBwYXJzZV9hcmdzOyBkZWZhdWx0IGluc3RhbGwpCk1PREU9IiIKCiMgQXBwcm94aW1hdGUgd2FpdCBjZWlsaW5ncyBpbiB0aGlzIHNjcmlwdDogS01NIG9wZXJhdG9yIH41bSAoNjDDlzVzKTsgRFJCRCBtb2R1bGVzIH4xMG0gKDYww5cxMHMpOwojIGluaXRpYWwgc3luYyB+MzBtICg2MMOXMzBzKTsgYXV0b3N0YXJ0IERhZW1vblNldCB+NW0gKDYww5c1cykuCgojIFVzZXIgaW5wdXQ6IGJhY2tpbmcgcGF0aHMgKGUuZy4gL2Rldi9zZGIpLiAtZCA9IHNhbWUgb24gYm90aCBub2RlczsgZWxzZSAtZDAgLyAtZDEgcGVyIG5vZGUuCkJBQ0tJTkdfUEFUSD0iIgpCQUNLSU5HX1BBVEhfTk9ERTA9IiIKQkFDS0lOR19QQVRIX05PREUxPSIiCkRJU0tfUkVTT0xWRURfTk9ERTA9IiIKRElTS19SRVNPTFZFRF9OT0RFMT0iIgoKTElTVF9ERVZJQ0VTX09OTFk9MAoKIyBOb2RlIGluZm8gKHBvcHVsYXRlZCBieSBkZXRlY3Rfbm9kZXMpCk5PREVfMD0iIgpOT0RFXzE9IiIKTk9ERV8wX0lQPSIiCk5PREVfMV9JUD0iIgoKIy0tLSBGdW5jdGlvbnMgLS0tIwoKdXNhZ2UoKSB7CiAgICBjYXQgPDxVU0FHRQpVc2FnZSBleGFtcGxlczoKICAkMCAtbCB8ICQwIC1kIDxwYXRoPiB8ICQwIC1kMCA8cGF0aD4gLWQxIDxwYXRoPiB8ICQwIHVwZ3JhZGUgfCAkMCBoZWxwCgpEZWZhdWx0IE1vZGUgKGluc3RhbGwpIOKAlAoKUmVxdWlyZWQgKG9uZSBvZik6CiAgLWwgICAgICAgICAgICAgICAgICBMaXN0IGJsb2NrIGRldmljZXMgb24gZWFjaCBub2RlIChOQU1FLCBQQVRILCBTSVpFLCBST1RBLCBUWVBFLCBGU1RZUEUpLgogIC1kIFBBVEggICAgICAgICAgICAgQmFja2luZyBibG9jayBkZXZpY2UsIHNhbWUgcGF0aCAmIHNpemUgb24gYm90aCBub2RlcyAoZS5nLiAvZGV2L3NkYikuCiAgLWQwIFBBVEggLWQxIFBBVEggICBQZXItbm9kZSBiYWNraW5nIHBhdGhzIChub2RlIG9yZGVyID0gc29ydGVkIGNsdXN0ZXIgbm9kZSBuYW1lcykuCgpPcHRpb25hbDoKICAtLWRyYmQtY29uZi1wYXRoIFBBVEggICBIb3N0IHBhdGggdG8gZHJiZC5jb25mIChkZWZhdWx0ICR7RFJCRF9DT05GX1BBVEh9KQogIC0tZHJiZC1kaXItcGF0aCBQQVRIICAgIEhvc3QgZGlyIGZvciByZXNvdXJjZSBzbmlwcGV0cyAoZGVmYXVsdCAke0RSQkRfRElSX1BBVEh9KQogIC0tZHJiZC1yZXNvdXJjZSBOQU1FICAgIFJlc291cmNlIG5hbWUgaW4gY29uZmlnIChkZWZhdWx0ICR7RFJCRF9SRVNPVVJDRX0pCiAgLS1kcmJkLWRldmljZSBQQVRIICAgICAgVXBwZXIgRFJCRCBkZXZpY2UgKGRlZmF1bHQgJHtEUkJEX0RFVklDRX0pCiAgLS1kcmJkLXBvcnQgTiAgICAgICAgICAgVENQIHJlcGxpY2F0aW9uIHBvcnQgKGRlZmF1bHQgJHtEUkJEX1BPUlR9KQoKQmFja2luZyBwYXRocyBhcmUgcmF3IGJsb2NrIGRldmljZSBwYXRocyAoZS5nLiAvZGV2L3NkYikuIFVzZSB0aGUgUEFUSCBjb2x1bW4gZnJvbSAtbC4KRGlza3MgbXVzdCBiZSBTU0QtY2xhc3MgKFJPVEEgMCkgYW5kIHNhbWUgc2l6ZSBvbiBib3RoIG5vZGVzLgoKV2hhdCBpbnN0YWxsIGRvZXM6IHNldHVwIEtNTSBvcGVyYXRvciwgc2V0dXAgaW1hZ2UgcmVnaXN0cnkgb3BlcmF0b3IsCmJ1aWxkIGFuZCBsb2FkIERSQkQga21vZHMsIGNvbmZpZ3VyZSAmIHN5bmMgRFJCRCwgY3JlYXRlIHRoZSBmaWxlc3lzdGVtIG92ZXIgdGhlIERSQkQgZGV2aWNlLApzZXR1cCB0aGUgRFJCRCBhdXRvLXN0YXJ0IERhZW1vblNldCAmIGNyZWF0ZSB0aGUgc3VjY2VzcyBDb25maWdNYXAuCgpVcGdyYWRlIE1vZGUg4oCUCgoobm8gZGlzayBmbGFncyDigJQgRElTS19CWV9JRF9OT0RFXzAvMSBhcmUgcmVhZCBmcm9tIENvbmZpZ01hcCAke09ERl9OQU1FU1BBQ0V9LyR7T1VUUFVUX0NNX05BTUV9KQoKV2hhdCB1cGdyYWRlIGRvZXM6IHNjYWxlIGZsb2F0aW5nIENlcGggbW9uLCByZW1vdmUgYXV0b3N0YXJ0IERhZW1vblNldCwgZHJiZGFkbSBkb3duLApkZWxldGUgYW5kIHJlLWFwcGx5IEtNTSBNb2R1bGUgKyBEb2NrZXJmaWxlLCB3YWl0IGZvciBuZXcga21vZHMsIGRyYmRhZG0gdXAsIHN5bmMgaWYgbmVlZGVkLApyZWNyZWF0ZSBhdXRvc3RhcnQgRGFlbW9uU2V0LCBzY2FsZSBtb24gYmFjay4KCkdlbmVyYWw6CiAgLWgsIC0taGVscCAgIFNob3cgdGhpcyB0ZXh0LgoKVVNBR0UKfQoKX3BhcnNlX2luc3RhbGxfb3B0aW9ucygpIHsKICAgIHdoaWxlIFtbICQjIC1ndCAwIF1dOyBkbwogICAgICAgIGNhc2UgIiQxIiBpbgogICAgICAgICAgICAtaHwtLWhlbHApCiAgICAgICAgICAgICAgICB1c2FnZQogICAgICAgICAgICAgICAgZXhpdCAwCiAgICAgICAgICAgICAgICA7OwogICAgICAgICAgICAtZDApCiAgICAgICAgICAgICAgICBpZiBbWyAteiAiJHsyOi19IiBdXTsgdGhlbgogICAgICAgICAgICAgICAgICAgIGRpZSAiLWQwIHJlcXVpcmVzIGEgcGF0aCAoZS5nLiAvZGV2L3NkYikiCiAgICAgICAgICAgICAgICBmaQogICAgICAgICAgICAgICAgQkFDS0lOR19QQVRIX05PREUwPSIkMiIKICAgICAgICAgICAgICAgIHNoaWZ0IDIKICAgICAgICAgICAgICAgIDs7CiAgICAgICAgICAgIC1kMSkKICAgICAgICAgICAgICAgIGlmIFtbIC16ICIkezI6LX0iIF1dOyB0aGVuCiAgICAgICAgICAgICAgICAgICAgZGllICItZDEgcmVxdWlyZXMgYSBwYXRoIChlLmcuIC9kZXYvc2RiKSIKICAgICAgICAgICAgICAgIGZpCiAgICAgICAgICAgICAgICBCQUNLSU5HX1BBVEhfTk9ERTE9IiQyIgogICAgICAgICAgICAgICAgc2hpZnQgMgogICAgICAgICAgICAgICAgOzsKICAgICAgICAgICAgLWQpCiAgICAgICAgICAgICAgICBpZiBbWyAteiAiJHsyOi19IiBdXTsgdGhlbgogICAgICAgICAgICAgICAgICAgIGRpZSAiLWQgcmVxdWlyZXMgYSBwYXRoIChlLmcuIC9kZXYvc2RiKSIKICAgICAgICAgICAgICAgIGZpCiAgICAgICAgICAgICAgICBCQUNLSU5HX1BBVEg9IiQyIgogICAgICAgICAgICAgICAgc2hpZnQgMgogICAgICAgICAgICAgICAgOzsKICAgICAgICAgICAgLWwpCiAgICAgICAgICAgICAgICBMSVNUX0RFVklDRVNfT05MWT0xCiAgICAgICAgICAgICAgICBzaGlmdAogICAgICAgICAgICAgICAgOzsKICAgICAgICAgICAgLS1kcmJkLWNvbmYtcGF0aCkKICAgICAgICAgICAgICAgIGlmIFtbIC16ICIkezI6LX0iIF1dOyB0aGVuCiAgICAgICAgICAgICAgICAgICAgZGllICItLWRyYmQtY29uZi1wYXRoIHJlcXVpcmVzIGFuIGFic29sdXRlIHBhdGggdG8gZHJiZC5jb25mIgogICAgICAgICAgICAgICAgZmkKICAgICAgICAgICAgICAgIERSQkRfQ09ORl9QQVRIPSIkMiIKICAgICAgICAgICAgICAgIHNoaWZ0IDIKICAgICAgICAgICAgICAgIDs7CiAgICAgICAgICAgIC0tZHJiZC1kaXItcGF0aCkKICAgICAgICAgICAgICAgIGlmIFtbIC16ICIkezI6LX0iIF1dOyB0aGVuCiAgICAgICAgICAgICAgICAgICAgZGllICItLWRyYmQtZGlyLXBhdGggcmVxdWlyZXMgYW4gYWJzb2x1dGUgZGlyZWN0b3J5IHBhdGggKGUuZy4gL2V0Yy9kcmJkLmQpIgogICAgICAgICAgICAgICAgZmkKICAgICAgICAgICAgICAgIERSQkRfRElSX1BBVEg9IiQyIgogICAgICAgICAgICAgICAgc2hpZnQgMgogICAgICAgICAgICAgICAgOzsKICAgICAgICAgICAgLS1kcmJkLXJlc291cmNlKQogICAgICAgICAgICAgICAgaWYgW1sgLXogIiR7MjotfSIgXV07IHRoZW4KICAgICAgICAgICAgICAgICAgICBkaWUgIi0tZHJiZC1yZXNvdXJjZSByZXF1aXJlcyBhIG5hbWUiCiAgICAgICAgICAgICAgICBmaQogICAgICAgICAgICAgICAgRFJCRF9SRVNPVVJDRT0iJDIiCiAgICAgICAgICAgICAgICBzaGlmdCAyCiAgICAgICAgICAgICAgICA7OwogICAgICAgICAgICAtLWRyYmQtZGV2aWNlKQogICAgICAgICAgICAgICAgaWYgW1sgLXogIiR7MjotfSIgXV07IHRoZW4KICAgICAgICAgICAgICAgICAgICBkaWUgIi0tZHJiZC1kZXZpY2UgcmVxdWlyZXMgYSBwYXRoIChlLmcuIC9kZXYvZHJiZDApIgogICAgICAgICAgICAgICAgZmkKICAgICAgICAgICAgICAgIERSQkRfREVWSUNFPSIkMiIKICAgICAgICAgICAgICAgIHNoaWZ0IDIKICAgICAgICAgICAgICAgIDs7CiAgICAgICAgICAgIC0tZHJiZC1wb3J0KQogICAgICAgICAgICAgICAgaWYgW1sgLXogIiR7MjotfSIgXV07IHRoZW4KICAgICAgICAgICAgICAgICAgICBkaWUgIi0tZHJiZC1wb3J0IHJlcXVpcmVzIGEgVENQIHBvcnQgbnVtYmVyIgogICAgICAgICAgICAgICAgZmkKICAgICAgICAgICAgICAgIERSQkRfUE9SVD0iJDIiCiAgICAgICAgICAgICAgICBzaGlmdCAyCiAgICAgICAgICAgICAgICA7OwogICAgICAgICAgICAqKQogICAgICAgICAgICAgICAgZGllICJVbmtub3duIG9wdGlvbjogJDEgKHVzZSAtaCkiCiAgICAgICAgICAgICAgICA7OwogICAgICAgIGVzYWMKICAgIGRvbmUKfQoKcGFyc2VfYXJncygpIHsKICAgIGlmIFtbICIkezE6LX0iID09ICItaCIgfHwgIiR7MTotfSIgPT0gIi0taGVscCIgXV07IHRoZW4KICAgICAgICB1c2FnZQogICAgICAgIGV4aXQgMAogICAgZmkKCiAgICBpZiBbWyAkIyAtZXEgMCBdXTsgdGhlbgogICAgICAgIE1PREU9Imluc3RhbGwiCiAgICBlbGlmIFtbICIkMSIgPT0gImhlbHAiIF1dOyB0aGVuCiAgICAgICAgdXNhZ2UKICAgICAgICBleGl0IDAKICAgIGVsaWYgW1sgIiQxIiA9PSAidXBncmFkZSIgXV07IHRoZW4KICAgICAgICBNT0RFPSJ1cGdyYWRlIgogICAgICAgIHNoaWZ0CiAgICAgICAgaWYgW1sgJCMgLWVxIDAgXV07IHRoZW4KICAgICAgICAgICAgOgogICAgICAgIGVsaWYgW1sgIiQxIiA9PSAiLWgiIHx8ICIkMSIgPT0gIi0taGVscCIgXV07IHRoZW4KICAgICAgICAgICAgdXNhZ2UKICAgICAgICAgICAgZXhpdCAwCiAgICAgICAgZWxzZQogICAgICAgICAgICBkaWUgInVwZ3JhZGUgYWNjZXB0cyBubyBhcmd1bWVudHMgKGdvdCAnJDEnKS4gU2VlOiAkMCB1cGdyYWRlIC1oIgogICAgICAgIGZpCiAgICBlbGlmIFtbICIkMSIgPT0gImluc3RhbGwiIF1dOyB0aGVuCiAgICAgICAgTU9ERT0iaW5zdGFsbCIKICAgICAgICBzaGlmdAogICAgICAgIF9wYXJzZV9pbnN0YWxsX29wdGlvbnMgIiRAIgogICAgZWxzZQogICAgICAgIE1PREU9Imluc3RhbGwiCiAgICAgICAgX3BhcnNlX2luc3RhbGxfb3B0aW9ucyAiJEAiCiAgICBmaQoKICAgIGlmIFtbICIkTElTVF9ERVZJQ0VTX09OTFkiIC1lcSAxIF1dOyB0aGVuCiAgICAgICAgaWYgW1sgIiRNT0RFIiA9PSAidXBncmFkZSIgXV07IHRoZW4KICAgICAgICAgICAgZGllICJ1cGdyYWRlIGRvZXMgbm90IHN1cHBvcnQgLWwgKHVzZTogJDAgLWwgZm9yIGRldmljZSBkaXNjb3ZlcnkpIgogICAgICAgIGZpCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgaWYgW1sgIiRNT0RFIiA9PSAidXBncmFkZSIgXV07IHRoZW4KICAgICAgICBpZiBbWyAtbiAiJEJBQ0tJTkdfUEFUSCIgfHwgLW4gIiRCQUNLSU5HX1BBVEhfTk9ERTAiIHx8IC1uICIkQkFDS0lOR19QQVRIX05PREUxIiBdXTsgdGhlbgogICAgICAgICAgICBkaWUgInVwZ3JhZGUgZG9lcyBub3QgdXNlIC1kLy1kMC8tZDE7IHVzZSBDb25maWdNYXAgJHtPREZfTkFNRVNQQUNFfS8ke09VVFBVVF9DTV9OQU1FfSAoZnJvbSBkZWZhdWx0IHNldHVwKS4gUnVuOiAkMCB1cGdyYWRlIgogICAgICAgIGZpCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgaWYgW1sgLW4gIiRCQUNLSU5HX1BBVEgiICYmICggLW4gIiRCQUNLSU5HX1BBVEhfTk9ERTAiIHx8IC1uICIkQkFDS0lOR19QQVRIX05PREUxIiApIF1dOyB0aGVuCiAgICAgICAgZGllICJVc2UgZWl0aGVyIC1kIG9yIGJvdGggLWQwIGFuZCAtZDEgKG5vZGUwL25vZGUxIHBhdGhzKSwgbm90IGJvdGgiCiAgICBmaQogICAgaWYgW1sgLW4gIiRCQUNLSU5HX1BBVEhfTk9ERTAiIHx8IC1uICIkQkFDS0lOR19QQVRIX05PREUxIiBdXTsgdGhlbgogICAgICAgIGlmIFtbIC16ICIkQkFDS0lOR19QQVRIX05PREUwIiB8fCAteiAiJEJBQ0tJTkdfUEFUSF9OT0RFMSIgXV07IHRoZW4KICAgICAgICAgICAgZGllICJCb3RoIC1kMCBhbmQgLWQxIGFyZSByZXF1aXJlZCB3aGVuIHVzaW5nIHBlci1ub2RlIHBhdGhzIgogICAgICAgIGZpCiAgICBmaQogICAgaWYgW1sgLXogIiRCQUNLSU5HX1BBVEgiICYmIC16ICIkQkFDS0lOR19QQVRIX05PREUwIiBdXTsgdGhlbgogICAgICAgIGRpZSAiU3BlY2lmeSBiYWNraW5nIHBhdGgocyk6IC1kLCBvciAtZDAgYW5kIC1kMSwgb3IgLWwgdG8gbGlzdCBkZXZpY2VzIChzZWUgLWgpIgogICAgZmkKfQoKIyBPcGVuU2hpZnQgbG9naW4sIHR3by1ub2RlIGNsdXN0ZXIsIGFuZCBUTkYgY29udHJvbC1wbGFuZSB0b3BvbG9neSAoRHVhbFJlcGxpY2EpLgpjaGVja19wcmVyZXF1aXNpdGVzKCkgewogICAgaWYgISBvYyB3aG9hbWkgJj4vZGV2L251bGw7IHRoZW4KICAgICAgICBkaWUgIm5vdCBsb2dnZWQgaW50byBPcGVuU2hpZnQgKG9jIHdob2FtaSkiCiAgICBmaQoKICAgIGxvY2FsIG5vZGVfY291bnQgdG9wb2xvZ3kKICAgIG5vZGVfY291bnQ9JChvYyBnZXQgbm9kZXMgLS1uby1oZWFkZXJzIDI+L2Rldi9udWxsIHwgd2MgLWwgfCB0ciAtZCAnICcpCiAgICBpZiBbWyAiJG5vZGVfY291bnQiIC1uZSAyIF1dOyB0aGVuCiAgICAgICAgZGllICJleHBlY3RlZCAyIG5vZGVzIGZvciBUTkYsIGZvdW5kICRub2RlX2NvdW50IgogICAgZmkKCiAgICBpZiAhIHRvcG9sb2d5PSQob2MgZ2V0IGluZnJhc3RydWN0dXJlIGNsdXN0ZXIgLW8ganNvbnBhdGg9J3suc3RhdHVzLmNvbnRyb2xQbGFuZVRvcG9sb2d5fScgMj4vZGV2L251bGwpOyB0aGVuCiAgICAgICAgdG9wb2xvZ3k9IiIKICAgIGZpCiAgICBpZiBbWyAteiAiJHRvcG9sb2d5IiBdXTsgdGhlbgogICAgICAgIGRpZSAiY291bGQgbm90IHJlYWQgaW5mcmFzdHJ1Y3R1cmUgQ1IiCiAgICBmaQogICAgaWYgW1sgIiR0b3BvbG9neSIgIT0gIkR1YWxSZXBsaWNhIiBdXTsgdGhlbgogICAgICAgIGRpZSAiZXhwZWN0ZWQgc3RhdHVzLmNvbnRyb2xQbGFuZVRvcG9sb2d5IER1YWxSZXBsaWNhICh0d28tbm9kZSBjb250cm9sIHBsYW5lKSwgZ290ICcke3RvcG9sb2d5fSciCiAgICBmaQp9CgojIFJlc29sdmUgdGhlIHR3byBjbHVzdGVyIG5vZGUgbmFtZXMgKHNvcnRlZCBhc2NlbmRpbmcpIGFuZCBlYWNoIG5vZGUncyBJbnRlcm5hbElQIGZvciBEUkJEIGVuZHBvaW50cy4KZGV0ZWN0X25vZGVzKCkgewogICAgbG9jYWwgbm9kZXNfc29ydGVkCgogICAgbm9kZXNfc29ydGVkPSQob2MgZ2V0IG5vZGVzIC1vIGpzb25wYXRoPSd7cmFuZ2UgLml0ZW1zWypdfXsubWV0YWRhdGEubmFtZX17IlxuIn17ZW5kfScgfCBzb3J0KQogICAgTk9ERV8wPSQocHJpbnRmICclc1xuJyAiJG5vZGVzX3NvcnRlZCIgfCBoZWFkIC1uIDEpCiAgICBOT0RFXzE9JChwcmludGYgJyVzXG4nICIkbm9kZXNfc29ydGVkIiB8IGhlYWQgLW4gMiB8IHRhaWwgLW4gMSkKICAgIGlmIFtbIC16ICIkTk9ERV8wIiB8fCAteiAiJE5PREVfMSIgXV07IHRoZW4KICAgICAgICBkaWUgImNvdWxkIG5vdCByZXNvbHZlIHR3byBub2RlIG5hbWVzIgogICAgZmkKCiAgICBOT0RFXzBfSVA9JChvYyBnZXQgbm9kZSAiJE5PREVfMCIgLW8ganNvbnBhdGg9J3suc3RhdHVzLmFkZHJlc3Nlc1s/KEAudHlwZT09IkludGVybmFsSVAiKV0uYWRkcmVzc30nKQogICAgTk9ERV8xX0lQPSQob2MgZ2V0IG5vZGUgIiROT0RFXzEiIC1vIGpzb25wYXRoPSd7LnN0YXR1cy5hZGRyZXNzZXNbPyhALnR5cGU9PSJJbnRlcm5hbElQIildLmFkZHJlc3N9JykKICAgIGlmIFtbIC16ICIkTk9ERV8wX0lQIiB8fCAteiAiJE5PREVfMV9JUCIgXV07IHRoZW4KICAgICAgICBkaWUgImNvdWxkIG5vdCByZWFkIEludGVybmFsSVAgKE5PREVfMD0kTk9ERV8wIE5PREVfMT0kTk9ERV8xKSIKICAgIGZpCn0KCiMgbGlzdCBibG9jayBkZXZpY2VzIG9uIGJvdGggbm9kZXMgd2l0aCBsc2JsawpsaXN0X2RldmljZXMoKSB7CiAgICBlY2hvICI9PT0gQmxvY2sgZGV2aWNlcyAobm9kZTA9JE5PREVfMCwgbm9kZTE9JE5PREVfMSkgPT09IgogICAgZWNobyAiVXNlIHRoZSBQQVRIIGNvbHVtbiAoZS5nLiAtZCAvZGV2L3NkYiBvciAtZDAgLyAtZDEgcGVyLW5vZGUgcGF0aHMpLiIKICAgIGVjaG8gIiIKICAgIGZvciBuIGluICIkTk9ERV8wIiAiJE5PREVfMSI7IGRvCiAgICAgICAgZWNobyAiLS0tICRuIC0tLSIKICAgICAgICBpZiAhIG9jIC0tcmVxdWVzdC10aW1lb3V0PTEyMHMgZGVidWcgLXEgIm5vZGUvJG4iIC0tIGNocm9vdCAvaG9zdCBsc2JsayAtbyBOQU1FLFBBVEgsU0laRSxST1RBLFRZUEUsRlNUWVBFOyB0aGVuCiAgICAgICAgICAgIGVjaG8gIiAgQ291bGQgbm90IGxpc3QgYmxvY2sgZGV2aWNlcyBvbiAkbiAob2MgZGVidWcgZmFpbGVkKS4gQ2hlY2sgY2x1c3RlciBhY2Nlc3MsIHRoZW4gcmUtcnVuOiAkMCAtbCIgPiYyCiAgICAgICAgZmkKICAgICAgICBlY2hvICIiCiAgICBkb25lCiAgICBlY2hvICJTYW1lIHBhdGggb24gYm90aCBub2RlczogLWQgPHBhdGg+IgogICAgZWNobyAiRGlmZmVyZW50IHBhdGhzIChzYW1lIHNpemUpOiAtZDAgPHBhdGgwPiAtZDEgPHBhdGgxPiIKfQoKIyBNYXAgdXNlciBkZXZpY2UgcGF0aCAtPiBzdGFibGUgZGlzayBieS1pZCBzeW1saW5rIGZvciBEUkJEIGNvbmZpZyBvbiB0aGF0IG5vZGUuCiMgTXVsdGlwbGUgYnktaWQgbmFtZXMgY2FuIHJlc29sdmUgdG8gdGhlIHNhbWUgY2Fub25pY2FsIGRldmljZTsgc29ydHxoZWFkIC0xIHBpY2tzIG9uZSBkZXRlcm1pbmlzdGljYWxseS4KcmVzb2x2ZV9kaXNrX3BhdGhfb25fbm9kZSgpIHsKICAgIGxvY2FsIG5vZGU9IiQxIiBkZXZpY2VfcGF0aD0iJDIiCiAgICBvYyBkZWJ1ZyAtcSAibm9kZS8kbm9kZSIgLS0gY2hyb290IC9ob3N0IGVudiAiRFJCRF9CTE9DS19ERVY9JHtkZXZpY2VfcGF0aH0iIGJhc2ggLWMgJwppZiAhIENBTk9OPSQocmVhZGxpbmsgLWYgIiREUkJEX0JMT0NLX0RFViIgMj4vZGV2L251bGwpOyB0aGVuCiAgQ0FOT049IiREUkJEX0JMT0NLX0RFViIKZmkKZm9yIGlkIGluIC9kZXYvZGlzay9ieS1pZC8qOyBkbwogIGlmIFtbICEgLWUgIiRpZCIgXV07IHRoZW4KICAgIGNvbnRpbnVlCiAgZmkKICBpZiBbWyAiJChyZWFkbGluayAtZiAiJGlkIiAyPi9kZXYvbnVsbCkiID09ICIkQ0FOT04iIF1dOyB0aGVuIGVjaG8gIiRpZCI7IGZpCmRvbmUgfCBzb3J0IC11IHwgaGVhZCAtbiAxCicgMj4vZGV2L251bGwgfCB0YWlsIC1uIDEKfQoKIyBWYWxpZGF0ZSB1cGdyYWRlIENvbmZpZ01hcCBhbmQgbG9hZCBvbmx5IERSQkQgbG93ZXItbGF5ZXIgYnktaWQgbWFwcGluZy4KdmFsaWRhdGVfdXBncmFkZV9jb25maWdtYXBfYW5kX2xvYWRfZGlza19pZHMoKSB7CiAgICBtc2cgIlZhbGlkYXRpbmcgQ29uZmlnTWFwICR7T0RGX05BTUVTUEFDRX0vJHtPVVRQVVRfQ01fTkFNRX0gYW5kIGxvYWRpbmcgRElTS19CWV9JRCBtYXBwaW5nLi4uIgogICAgaWYgISBvYyBnZXQgY29uZmlnbWFwICIke09VVFBVVF9DTV9OQU1FfSIgLW4gIiR7T0RGX05BTUVTUEFDRX0iICY+L2Rldi9udWxsOyB0aGVuCiAgICAgICAgZGllICJDb25maWdNYXAgJHtPREZfTkFNRVNQQUNFfS8ke09VVFBVVF9DTV9OQU1FfSBub3QgZm91bmQuIFJ1biBkZWZhdWx0IHNldHVwIGZpcnN0OiAkMCAtZCA8cGF0aD4iCiAgICBmaQoKICAgIERJU0tfUkVTT0xWRURfTk9ERTA9JChvYyBnZXQgY29uZmlnbWFwICIke09VVFBVVF9DTV9OQU1FfSIgLW4gIiR7T0RGX05BTUVTUEFDRX0iIFwKICAgICAgICAtbyBqc29ucGF0aD0ney5kYXRhLkRJU0tfQllfSURfTk9ERV8wfScgfCB0ciAtZCAnXHJcbicpIFwKICAgICAgICB8fCBkaWUgImZhaWxlZCByZWFkaW5nIERJU0tfQllfSURfTk9ERV8wIGZyb20gQ29uZmlnTWFwICR7T1VUUFVUX0NNX05BTUV9IgogICAgRElTS19SRVNPTFZFRF9OT0RFMT0kKG9jIGdldCBjb25maWdtYXAgIiR7T1VUUFVUX0NNX05BTUV9IiAtbiAiJHtPREZfTkFNRVNQQUNFfSIgXAogICAgICAgIC1vIGpzb25wYXRoPSd7LmRhdGEuRElTS19CWV9JRF9OT0RFXzF9JyB8IHRyIC1kICdcclxuJykgXAogICAgICAgIHx8IGRpZSAiZmFpbGVkIHJlYWRpbmcgRElTS19CWV9JRF9OT0RFXzEgZnJvbSBDb25maWdNYXAgJHtPVVRQVVRfQ01fTkFNRX0iCiAgICBpZiBbWyAteiAiJERJU0tfUkVTT0xWRURfTk9ERTAiIHx8IC16ICIkRElTS19SRVNPTFZFRF9OT0RFMSIgXV07IHRoZW4KICAgICAgICBkaWUgIkNvbmZpZ01hcCAke09VVFBVVF9DTV9OQU1FfTogbWlzc2luZyBESVNLX0JZX0lEX05PREVfMCBvciBESVNLX0JZX0lEX05PREVfMSIKICAgIGZpCn0KCnByaW50X2NvbmZpZygpIHsKICAgIGVjaG8gIiIKICAgIG1zZyAiQ29uZmlndXJhdGlvbiIKICAgIGxvY2FsIF9sdz0xOAogICAgaWYgW1sgIiRNT0RFIiA9PSAidXBncmFkZSIgXV07IHRoZW4KICAgICAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIk1vZGU6IiAidXBncmFkZSAoS01NIGttb2QgcmVmcmVzaDsgcHJlc2VydmUgRFJCRCBtZXRhZGF0YSkiCiAgICBlbHNlCiAgICAgICAgcHJpbnRmICcgICUtKnMgJXNcbicgIiRfbHciICJNb2RlOiIgImluc3RhbGwgKEtNTSArIERSQkQgcmVzb3VyY2UgKyBzdWNjZXNzIENvbmZpZ01hcCkiCiAgICBmaQogICAgcHJpbnRmICcgICUtKnMgJXNcbicgIiRfbHciICJOb2RlczoiICIkTk9ERV8wICgkTk9ERV8wX0lQKSwgJE5PREVfMSAoJE5PREVfMV9JUCkiCiAgICBpZiBbWyAiJE1PREUiID09ICJ1cGdyYWRlIiBdXTsgdGhlbgogICAgICAgIHByaW50ZiAnICAlLSpzICVzOiAlc1xuJyAiJF9sdyIgIkRSQkQgZGlza3MgYnkgaWQ6IiAiJE5PREVfMCIgIiRESVNLX1JFU09MVkVEX05PREUwIgogICAgICAgIHByaW50ZiAnICAlLSpzICVzOiAlc1xuJyAiJF9sdyIgIihmcm9tIENvbmZpZ01hcCkiICIkTk9ERV8xIiAiJERJU0tfUkVTT0xWRURfTk9ERTEiCiAgICBlbGlmIFtbIC1uICIkQkFDS0lOR19QQVRIIiBdXTsgdGhlbgogICAgICAgIHByaW50ZiAnICAlLSpzICVzIChzYW1lIHBhdGggb24gYm90aCBub2RlcylcbicgIiRfbHciICJCYWNraW5nIGRldmljZToiICIkQkFDS0lOR19QQVRIIgogICAgZWxzZQogICAgICAgIHByaW50ZiAnICAlLSpzICVzXG4nICIkX2x3IiAiQmFja2luZyBkZXZpY2VzOiIgInBlci1ub2RlIHBhdGhzIgogICAgICAgIHByaW50ZiAnICAlLSpzICVzOiAlc1xuJyAiJF9sdyIgIiIgIiROT0RFXzAiICIkQkFDS0lOR19QQVRIX05PREUwIgogICAgICAgIHByaW50ZiAnICAlLSpzICVzOiAlc1xuJyAiJF9sdyIgIiIgIiROT0RFXzEiICIkQkFDS0lOR19QQVRIX05PREUxIgogICAgZmkKICAgIHByaW50ZiAnICAlLSpzICVzXG4nICIkX2x3IiAiRFJCRCBDb25maWcgcGF0aDoiICIkRFJCRF9DT05GX1BBVEgiCiAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIkRSQkQgRGlyIHBhdGg6IiAiJERSQkRfRElSX1BBVEgiCiAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIkRSQkQgUmVzb3VyY2U6IiAiJERSQkRfUkVTT1VSQ0UiCiAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIkRSQkQgRGV2aWNlOiIgIiREUkJEX0RFVklDRSIKICAgIHByaW50ZiAnICAlLSpzICVzXG4nICIkX2x3IiAiRFJCRCBQb3J0OiIgIiREUkJEX1BPUlQiCiAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIkRSQkRfSU1BR0U6IiAiJERSQkRfSU1BR0UiCiAgICBwcmludGYgJyAgJS0qcyAlc1xuJyAiJF9sdyIgIkRSQkRfVkVSU0lPTjoiICIkRFJCRF9WRVJTSU9OIgogICAgZWNobyAiIgp9CgoKX2xzYmxrX29uZV9saW5lKCkgewogICAgbG9jYWwgbm9kZT0iJDEiIGRldmljZV9wYXRoPSIkMiIKICAgIG9jIGRlYnVnIC1xICJub2RlLyRub2RlIiAtLSBjaHJvb3QgL2hvc3QgbHNibGsgLW5kbyBTSVpFLFJPLFJPVEEgIiRkZXZpY2VfcGF0aCIgMj4vZGV2L251bGwgfCB0ciAtcyAnICcgfCBoZWFkIC0xCn0KCiMgdmFsaWRhdGUgdGhlIGJhY2tpbmcgZGV2aWNlIHBhdGhzIGFuZCByZXNvbHZlIHRoZSBkaXNrIGJ5LWlkIHN5bWxpbmsgZm9yIERSQkQgY29uZmlnIG9uIHRoYXQgbm9kZS4KdmFsaWRhdGVfYW5kX3Jlc29sdmVfZGlza3MoKSB7CiAgICBsb2NhbCBwMCBwMSByb3cwIHJvdzEgc2l6ZTAgcm8wIHJvdGEwIHNpemUxIHJvMSByb3RhMQogICAgaWYgW1sgLW4gIiRCQUNLSU5HX1BBVEgiIF1dOyB0aGVuCiAgICAgICAgcDA9IiRCQUNLSU5HX1BBVEgiCiAgICAgICAgcDE9IiRCQUNLSU5HX1BBVEgiCiAgICBlbHNlCiAgICAgICAgcDA9IiRCQUNLSU5HX1BBVEhfTk9ERTAiCiAgICAgICAgcDE9IiRCQUNLSU5HX1BBVEhfTk9ERTEiCiAgICBmaQoKICAgIG1zZyAiQ2hlY2tpbmcgYmFja2luZyBkZXZpY2UgcGF0aHMuLi4iCiAgICByb3cwPSQoX2xzYmxrX29uZV9saW5lICIkTk9ERV8wIiAiJHAwIikKICAgIHJvdzE9JChfbHNibGtfb25lX2xpbmUgIiROT0RFXzEiICIkcDEiKQogICAgaWYgW1sgLXogIiRyb3cwIiBdXTsgdGhlbgogICAgICAgIGRpZSAiZGV2aWNlIHBhdGggJHAwIG5vdCBmb3VuZCBvbiAkTk9ERV8wIgogICAgZmkKICAgIGlmIFtbIC16ICIkcm93MSIgXV07IHRoZW4KICAgICAgICBkaWUgImRldmljZSBwYXRoICRwMSBub3QgZm91bmQgb24gJE5PREVfMSIKICAgIGZpCgogICAgcmVhZCAtciBzaXplMCBybzAgcm90YTAgPDw8IiRyb3cwIgogICAgcmVhZCAtciBzaXplMSBybzEgcm90YTEgPDw8IiRyb3cxIgogICAgaWYgW1sgIiRybzAiICE9ICIwIiBdXTsgdGhlbgogICAgICAgIGRpZSAiZGV2aWNlIHBhdGggJHAwIG9uICROT0RFXzAgaXMgcmVhZC1vbmx5IgogICAgZmkKICAgIGlmIFtbICIkcm8xIiAhPSAiMCIgXV07IHRoZW4KICAgICAgICBkaWUgImRldmljZSBwYXRoICRwMSBvbiAkTk9ERV8xIGlzIHJlYWQtb25seSIKICAgIGZpCiAgICBpZiBbWyAiJHJvdGEwIiAhPSAiMCIgXV07IHRoZW4KICAgICAgICBkaWUgImRldmljZSBwYXRoICRwMCBvbiAkTk9ERV8wIG11c3QgYmUgbm9uLXJvdGF0aW9uYWwgKFNTRC9OVk1lOyBsc2JsayBST1RBIDApLCBub3Qgcm90YXRpb25hbCBIREQgKFJPVEE9JHtyb3RhMDotP30pIgogICAgZmkKICAgIGlmIFtbICIkcm90YTEiICE9ICIwIiBdXTsgdGhlbgogICAgICAgIGRpZSAiZGV2aWNlIHBhdGggJHAxIG9uICROT0RFXzEgbXVzdCBiZSBub24tcm90YXRpb25hbCAoU1NEL05WTWU7IGxzYmxrIFJPVEEgMCksIG5vdCByb3RhdGlvbmFsIEhERCAoUk9UQT0ke3JvdGExOi0/fSkiCiAgICBmaQogICAgaWYgW1sgIiRzaXplMCIgIT0gIiRzaXplMSIgXV07IHRoZW4KICAgICAgICBkaWUgImJhY2tpbmcgZGV2aWNlIHBhdGggc2l6ZSBtaXNtYXRjaDogJE5PREVfMCAkc2l6ZTAgdnMgJE5PREVfMSAkc2l6ZTEiCiAgICBmaQoKICAgIGVjaG8gIiAgJE5PREVfMDogJHAwICAkc2l6ZTAiCiAgICBlY2hvICIgICROT0RFXzE6ICRwMSAgJHNpemUxIgogICAgbXNnICJCYWNraW5nIGRldmljZSBwYXRocyBPSy4iCgogICAgbXNnICJSZXNvbHZpbmcgZGV2aWNlIHBhdGhzIHRvIC9kZXYvZGlzay9ieS1pZCBmb3IgRFJCRCBjb25maWciCiAgICBESVNLX1JFU09MVkVEX05PREUwPSQocmVzb2x2ZV9kaXNrX3BhdGhfb25fbm9kZSAiJE5PREVfMCIgIiRwMCIpCiAgICBESVNLX1JFU09MVkVEX05PREUxPSQocmVzb2x2ZV9kaXNrX3BhdGhfb25fbm9kZSAiJE5PREVfMSIgIiRwMSIpCiAgICBpZiBbWyAteiAiJERJU0tfUkVTT0xWRURfTk9ERTAiIF1dOyB0aGVuCiAgICAgICAgZGllICJubyAvZGV2L2Rpc2svYnktaWQgc3ltbGluayBmb3IgZGV2aWNlIHBhdGggJHAwIG9uICROT0RFXzAiCiAgICBmaQogICAgaWYgW1sgLXogIiRESVNLX1JFU09MVkVEX05PREUxIiBdXTsgdGhlbgogICAgICAgIGRpZSAibm8gL2Rldi9kaXNrL2J5LWlkIHN5bWxpbmsgZm9yIGRldmljZSBwYXRoICRwMSBvbiAkTk9ERV8xIgogICAgZmkKICAgIGVjaG8gIiAgJE5PREVfMDogJHAwICAtPiAgJERJU0tfUkVTT0xWRURfTk9ERTAiCiAgICBlY2hvICIgICROT0RFXzE6ICRwMSAgLT4gICRESVNLX1JFU09MVkVEX05PREUxIgp9CgojIGluc3RhbGwgdGhlIEtNTSAoS2VybmVsIE1vZHVsZSBNYW5hZ2VtZW50KSBvcGVyYXRvcgpzZXR1cF9rbW1fb3BlcmF0b3IoKSB7CiAgICBpZiBvYyBnZXQgY3N2IC1uIG9wZW5zaGlmdC1rbW0gMj4vZGV2L251bGwgfCBncmVwIC1xIFN1Y2NlZWRlZDsgdGhlbgogICAgICAgIG1zZyAiS01NIChLZXJuZWwgTW9kdWxlIE1hbmFnZW1lbnQpIG9wZXJhdG9yIGlzIGFscmVhZHkgaW5zdGFsbGVkLiIKICAgICAgICByZXR1cm4gMAogICAgZmkKCiAgICBtc2cgIkluc3RhbGxpbmcgS01NIChLZXJuZWwgTW9kdWxlIE1hbmFnZW1lbnQpIG9wZXJhdG9yLi4uIgogICAgb2MgYXBwbHkgLWYgLSA+L2Rldi9udWxsIDw8RU9GCmFwaVZlcnNpb246IHYxCmtpbmQ6IE5hbWVzcGFjZQptZXRhZGF0YToKICBuYW1lOiBvcGVuc2hpZnQta21tCi0tLQphcGlWZXJzaW9uOiBvcGVyYXRvcnMuY29yZW9zLmNvbS92MQpraW5kOiBPcGVyYXRvckdyb3VwCm1ldGFkYXRhOgogIG5hbWU6IGtlcm5lbC1tb2R1bGUtbWFuYWdlbWVudAogIG5hbWVzcGFjZTogb3BlbnNoaWZ0LWttbQotLS0KYXBpVmVyc2lvbjogb3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEKa2luZDogU3Vic2NyaXB0aW9uCm1ldGFkYXRhOgogIG5hbWU6IGtlcm5lbC1tb2R1bGUtbWFuYWdlbWVudAogIG5hbWVzcGFjZTogb3BlbnNoaWZ0LWttbQpzcGVjOgogIGNoYW5uZWw6IHN0YWJsZQogIGluc3RhbGxQbGFuQXBwcm92YWw6IEF1dG9tYXRpYwogIG5hbWU6IGtlcm5lbC1tb2R1bGUtbWFuYWdlbWVudAogIHNvdXJjZTogcmVkaGF0LW9wZXJhdG9ycwogIHNvdXJjZU5hbWVzcGFjZTogb3BlbnNoaWZ0LW1hcmtldHBsYWNlCkVPRgoKICAgICMgUG9sbCB1bnRpbCBhIENsdXN0ZXJTZXJ2aWNlVmVyc2lvbiBpbiBvcGVuc2hpZnQta21tIHJlYWNoZXMgUGhhc2UgU3VjY2VlZGVkLCBlLmcuIGEgbGluZSBsaWtlOgogICAgIyAgIGtlcm5lbC1tb2R1bGUtbWFuYWdlbWVudC52WC5ZLlogICBrdWJlLWFwaXNlcnZlciAgIFN1Y2NlZWRlZAogICAgbXNnICJXYWl0aW5nIGZvciBLTU0gb3BlcmF0b3IgdG8gYmVjb21lIHJlYWR5ICh1cCB0byA1IG1pbikuLi4iCiAgICBfd2FpdF9iZWdpbgogICAgbG9jYWwgaQogICAgZm9yIGkgaW4gJChzZXEgMSA2MCk7IGRvCiAgICAgICAgaWYgb2MgZ2V0IGNzdiAtbiBvcGVuc2hpZnQta21tIDI+L2Rldi9udWxsIHwgZ3JlcCAtcSBTdWNjZWVkZWQ7IHRoZW4KICAgICAgICAgICAgX3dhaXRfc3VjY2VlZGVkICJLTU0gb3BlcmF0b3IgaXMgcmVhZHkiCiAgICAgICAgICAgIHJldHVybiAwCiAgICAgICAgZmkKICAgICAgICBpZiBbWyAiJGkiIC1lcSA2MCBdXTsgdGhlbgogICAgICAgICAgICBkaWUgIktNTSBvcGVyYXRvciBub3QgcmVhZHkgYWZ0ZXIgNSBtaW51dGVzIgogICAgICAgIGZpCiAgICAgICAgc2xlZXAgNQogICAgZG9uZQp9CgojIGNoZWNrIGlmIHRoZSBpbWFnZSByZWdpc3RyeSBvcGVyYXRvciBpcyByZWFkeQojIFllcyB3aGVuOgojIC0gbWFuYWdlbWVudFN0YXRlIGlzIE1hbmFnZWQKIyAtIEF2YWlsYWJsZSBpcyBUcnVlCiMgLSByZWFkeVJlcGxpY2FzID4gMAppbWFnZV9yZWdpc3RyeV9vcGVyYXRvcl9hdmFpbGFibGUoKSB7CiAgICBsb2NhbCBzdGF0dXNfbGluZSBtYW5hZ2VtZW50X3N0YXRlIGF2YWlsYWJsZV9zdGF0dXMgcmVhZHlfcmVwbGljYXMKICAgIGlmICEgc3RhdHVzX2xpbmU9JChvYyBnZXQgY29uZmlncy5pbWFnZXJlZ2lzdHJ5Lm9wZXJhdG9yLm9wZW5zaGlmdC5pbyBjbHVzdGVyIC1vIGpzb25wYXRoPSd7LnNwZWMubWFuYWdlbWVudFN0YXRlfXsiXHQifXsuc3RhdHVzLmNvbmRpdGlvbnNbPyhALnR5cGU9PSJBdmFpbGFibGUiKV0uc3RhdHVzfXsiXHQifXsuc3RhdHVzLnJlYWR5UmVwbGljYXN9JyAyPi9kZXYvbnVsbCk7IHRoZW4KICAgICAgICBzdGF0dXNfbGluZT0iIgogICAgZmkKICAgIElGUz0kJ1x0JyByZWFkIC1yIG1hbmFnZW1lbnRfc3RhdGUgYXZhaWxhYmxlX3N0YXR1cyByZWFkeV9yZXBsaWNhcyA8PDwiJHN0YXR1c19saW5lIgogICAgaWYgW1sgIiRtYW5hZ2VtZW50X3N0YXRlIiAhPSAiTWFuYWdlZCIgXV07IHRoZW4KICAgICAgICByZXR1cm4gMQogICAgZmkKICAgIGlmIFtbICIkYXZhaWxhYmxlX3N0YXR1cyIgIT0gIlRydWUiIF1dOyB0aGVuCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiBbWyAteiAiJHJlYWR5X3JlcGxpY2FzIiB8fCAhICIkcmVhZHlfcmVwbGljYXMiID1+IF5bMC05XSskIHx8ICIkcmVhZHlfcmVwbGljYXMiIC1sZSAwIF1dOyB0aGVuCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICByZXR1cm4gMAp9CgpwYXRjaF9pbWFnZV9yZWdpc3RyeV90b19lbXB0eWRpcigpIHsKICAgIGxvY2FsIHBhdGNoX3lhbWwKICAgIHBhdGNoX3lhbWw9JChjYXQgPDwnUEFUQ0gnCnNwZWM6CiAgbWFuYWdlbWVudFN0YXRlOiBNYW5hZ2VkCiAgc3RvcmFnZToKICAgIGVtcHR5RGlyOiB7fQpQQVRDSAopCiAgICBpZiAhIG9jIHBhdGNoIGNvbmZpZ3MuaW1hZ2VyZWdpc3RyeS5vcGVyYXRvci5vcGVuc2hpZnQuaW8gY2x1c3RlciAtLXR5cGUgbWVyZ2UgLS1wYXRjaCAiJHBhdGNoX3lhbWwiID4vZGV2L251bGw7IHRoZW4KICAgICAgICBkaWUgImZhaWxlZCB0byBwYXRjaCBpbWFnZSByZWdpc3RyeSBjb25maWciCiAgICBmaQp9CgojIElmIHRoZSBpbWFnZSByZWdpc3RyeSBvcGVyYXRvciBpcyBub3QgYWxyZWFkeSBhdmFpbGFibGUsIGNvbmZpZ3VyZSBpdCB3aXRoIGVtcHR5RGlyIHN0b3JhZ2UuCnNldHVwX2ltYWdlX3JlZ2lzdHJ5X29wZXJhdG9yKCkgewogICAgaWYgaW1hZ2VfcmVnaXN0cnlfb3BlcmF0b3JfYXZhaWxhYmxlOyB0aGVuCiAgICAgICAgbXNnICJJbWFnZSByZWdpc3RyeSBvcGVyYXRvciBpcyBhbHJlYWR5IHJlYWR5LiIKICAgICAgICByZXR1cm4gMAogICAgZmkKICAgIG1zZyAiQ29uZmlndXJpbmcgaW4tY2x1c3RlciBpbWFnZSByZWdpc3RyeSB3aXRoIGVtcHR5RGlyIHN0b3JhZ2UuIgogICAgcGF0Y2hfaW1hZ2VfcmVnaXN0cnlfdG9fZW1wdHlkaXIKICAgIHdhaXRfdW50aWxfaW1hZ2VfcmVnaXN0cnlfb3BlcmF0b3JfYXZhaWxhYmxlCn0KCiMgV2FpdCB1bnRpbCBpbWFnZV9yZWdpc3RyeV9vcGVyYXRvcl9hdmFpbGFibGU6IGFmdGVyIHBhdGNoaW5nIGVtcHR5RGlyIHRoZSBvcGVyYXRvciByZWNvbmNpbGVzIGFuZAojIHJlZ2lzdHJ5IHBvZHMgcm9sbCBvdXQ7IHdlIG5lZWQgTWFuYWdlZCArIEF2YWlsYWJsZT1UcnVlICsgcmVhZHlSZXBsaWNhcz4wIGJlZm9yZSBLTU0gY2FuIHB1c2gKIyB0aGUgbW9kdWxlIGltYWdlIHRvIHRoZSBpbnRlcm5hbCByZWdpc3RyeS4Kd2FpdF91bnRpbF9pbWFnZV9yZWdpc3RyeV9vcGVyYXRvcl9hdmFpbGFibGUoKSB7CiAgICBsb2NhbCBpCiAgICBtc2cgIldhaXRpbmcgZm9yIGltYWdlIHJlZ2lzdHJ5IG9wZXJhdG9yIHRvIGJlY29tZSByZWFkeSAodXAgdG8gMTUgbWluKS4uLiIKICAgIF93YWl0X2JlZ2luCiAgICBmb3IgaSBpbiAkKHNlcSAxIDE4MCk7IGRvCiAgICAgICAgaWYgaW1hZ2VfcmVnaXN0cnlfb3BlcmF0b3JfYXZhaWxhYmxlOyB0aGVuCiAgICAgICAgICAgIF93YWl0X3N1Y2NlZWRlZCAiSW1hZ2UgcmVnaXN0cnkgb3BlcmF0b3IgaXMgcmVhZHkiCiAgICAgICAgICAgIHJldHVybiAwCiAgICAgICAgZmkKICAgICAgICBpZiBbWyAiJGkiIC1lcSAxODAgXV07IHRoZW4KICAgICAgICAgICAgZGllICJ0aW1lb3V0OiBpbWFnZSByZWdpc3RyeSBvcGVyYXRvciBub3QgcmVhZHkgYWZ0ZXIgMTUgbWludXRlcyAoZXhwZWN0IE1hbmFnZWQsIEF2YWlsYWJsZT1UcnVlLCBzdGF0dXMucmVhZHlSZXBsaWNhcz4wOyBjaGVjazogb2MgZ2V0IGNvbmZpZ3MuaW1hZ2VyZWdpc3RyeS5vcGVyYXRvci5vcGVuc2hpZnQuaW8gY2x1c3RlciAtbyB5YW1sOyBvYyBnZXQgcG9kcyAtbiBvcGVuc2hpZnQtaW1hZ2UtcmVnaXN0cnkpIgogICAgICAgIGZpCiAgICAgICAgaWYgW1sgJCgoaSAlIDEyKSkgLWVxIDAgXV07IHRoZW4KICAgICAgICAgICAgbXNnICJTdGlsbCB3YWl0aW5nIGZvciBpbWFnZSByZWdpc3RyeSBvcGVyYXRvciAoJCgoaSAqIDUpKXMgZWxhcHNlZCkuLi4iCiAgICAgICAgZmkKICAgICAgICBzbGVlcCA1CiAgICBkb25lCn0KCiMgVHJ1ZSB3aGVuIG9wZW5zaGlmdC1rbW0gaGFzIGEgYnVpbGRlci1kb2NrZXJjZmctKiBTZWNyZXQgd2l0aCB1c2FibGUgcHVsbC9wdXNoIGNyZWRlbnRpYWxzLgprbW1fYnVpbGRlcl9kb2NrZXJjZmdfcmVhZHkoKSB7CiAgICBsb2NhbCBzZWMgYjY0CiAgICBzZWM9JChvYyBnZXQgc2VjcmV0cyAtbiBvcGVuc2hpZnQta21tIC0tbm8taGVhZGVycyAyPi9kZXYvbnVsbCB8IGF3ayAnL15idWlsZGVyLWRvY2tlcmNmZy0vIHtwcmludCAkMTsgZXhpdH0nKQogICAgaWYgW1sgLXogIiRzZWMiIF1dOyB0aGVuCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiAhIGI2ND0kKG9jIGdldCBzZWNyZXQgIiRzZWMiIC1uIG9wZW5zaGlmdC1rbW0gLW8ganNvbnBhdGg9J3suZGF0YS5cLmRvY2tlcmNmZ30nIDI+L2Rldi9udWxsKTsgdGhlbgogICAgICAgIGI2ND0iIgogICAgZmkKICAgIGlmIFtbIC16ICIkYjY0IiBdXTsgdGhlbgogICAgICAgIGlmICEgYjY0PSQob2MgZ2V0IHNlY3JldCAiJHNlYyIgLW4gb3BlbnNoaWZ0LWttbSAtbyBqc29ucGF0aD0ney5kYXRhLlwuZG9ja2VyY29uZmlnanNvbn0nIDI+L2Rldi9udWxsKTsgdGhlbgogICAgICAgICAgICBiNjQ9IiIKICAgICAgICBmaQogICAgZmkKICAgICMgU2VjcmV0IGNhbiBleGlzdCBiZWZvcmUgZGF0YSBpcyBwb3B1bGF0ZWQ7IHJlYWwgZG9ja2VyY2ZnL2RvY2tlcmNvbmZpZ2pzb24gYmFzZTY0IGlzIHVzdWFsbHkgPj44MCBjaGFycy4KICAgIGlmIFtbICR7I2I2NH0gLWx0IDgwIF1dOyB0aGVuCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICByZXR1cm4gMAp9CgojIFdhaXQgZm9yIFNlcnZpY2VBY2NvdW50IGJ1aWxkZXIgYW5kIGRvY2tlcmNmZyBTZWNyZXQgb25seSB3aGVuIG1pc3NpbmcgKEtNTSBpbWFnZSBidWlsZCBuZWVkcyB0aGVtKS4Ka21tX2ltYWdlX2J1aWxkX3dhaXRzKCkgewogICAgbG9jYWwgaQogICAgaWYgb2MgZ2V0IHNhIGJ1aWxkZXIgLW4gb3BlbnNoaWZ0LWttbSAmPi9kZXYvbnVsbDsgdGhlbgogICAgICAgIG1zZyAiU2VydmljZUFjY291bnQgYnVpbGRlciBhbHJlYWR5IHByZXNlbnQgaW4gb3BlbnNoaWZ0LWttbS4iCiAgICBlbHNlCiAgICAgICAgbXNnICJXYWl0aW5nIGZvciBTZXJ2aWNlQWNjb3VudCBidWlsZGVyIGluIG9wZW5zaGlmdC1rbW0gKHVwIHRvIDMgbWluKS4uLiIKICAgICAgICBfd2FpdF9iZWdpbgogICAgICAgIGZvciBpIGluICQoc2VxIDEgMzYpOyBkbwogICAgICAgICAgICBpZiBvYyBnZXQgc2EgYnVpbGRlciAtbiBvcGVuc2hpZnQta21tICY+L2Rldi9udWxsOyB0aGVuCiAgICAgICAgICAgICAgICBfd2FpdF9zdWNjZWVkZWQgIlNlcnZpY2VBY2NvdW50IGJ1aWxkZXIgaXMgcHJlc2VudCBpbiBvcGVuc2hpZnQta21tIgogICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgZmkKICAgICAgICAgICAgaWYgW1sgIiRpIiAtZXEgMzYgXV07IHRoZW4KICAgICAgICAgICAgICAgIGRpZSAidGltZW91dDogYnVpbGRlciBTZXJ2aWNlQWNjb3VudCBtaXNzaW5nIGluIG9wZW5zaGlmdC1rbW0iCiAgICAgICAgICAgIGZpCiAgICAgICAgICAgIHNsZWVwIDUKICAgICAgICBkb25lCiAgICBmaQoKICAgIGlmIGttbV9idWlsZGVyX2RvY2tlcmNmZ19yZWFkeTsgdGhlbgogICAgICAgIG1zZyAiQnVpbGRlciBkb2NrZXJjZmcgU2VjcmV0IGFscmVhZHkgcG9wdWxhdGVkLiIKICAgIGVsc2UKICAgICAgICBtc2cgIldhaXRpbmcgZm9yIGJ1aWxkZXIgZG9ja2VyY2ZnIFNlY3JldCB3aXRoIHBvcHVsYXRlZCByZWdpc3RyeSBjcmVkZW50aWFscyAodXAgdG8gNSBtaW4pLi4uIgogICAgICAgIF93YWl0X2JlZ2luCiAgICAgICAgZm9yIGkgaW4gJChzZXEgMSA2MCk7IGRvCiAgICAgICAgICAgIGlmIGttbV9idWlsZGVyX2RvY2tlcmNmZ19yZWFkeTsgdGhlbgogICAgICAgICAgICAgICAgX3dhaXRfc3VjY2VlZGVkICJCdWlsZGVyIGRvY2tlcmNmZyBTZWNyZXQgaXMgcG9wdWxhdGVkIgogICAgICAgICAgICAgICAgcmV0dXJuIDAKICAgICAgICAgICAgZmkKICAgICAgICAgICAgaWYgW1sgIiRpIiAtZXEgNjAgXV07IHRoZW4KICAgICAgICAgICAgICAgIGRpZSAidGltZW91dDogYnVpbGRlciBkb2NrZXJjZmcgbm90IHBvcHVsYXRlZCBpbiBvcGVuc2hpZnQta21tIgogICAgICAgICAgICBmaQogICAgICAgICAgICBzbGVlcCA1CiAgICAgICAgZG9uZQogICAgZmkKfQoKIyBMb3dlcmNhc2UgRFJCRF9WRVJTSU9OIHdpdGggZG90cy9wbHVzZXMgdHVybmVkIGludG8gZGFzaGVzIGZvciBhIGRpc3RpbmN0IGluLXJlZ2lzdHJ5IGttb2QgaW1hZ2UgdGFnIHBlciByZWxlYXNlLgpkcmJkX2ttb2RfaW1hZ2VfdGFnX3ZlcnNpb25fZnJhZ21lbnQoKSB7CiAgICBwcmludGYgJyVzJyAiJERSQkRfVkVSU0lPTiIgfCB0ciAnWzp1cHBlcjpdJyAnWzpsb3dlcjpdJyB8IHRyICcuKycgJy0tJwp9CgojIEJ1aWxkIHRoZSBLTU0gRG9ja2VyZmlsZSBib2R5IChEUkJEX1ZFUlNJT04gLyBEUkJEX0lNQUdFIHN1YnN0aXR1dGVkKS4KcmVuZGVyX2RyYmRfa21tX2RvY2tlcmZpbGUoKSB7CiAgICBsb2NhbCBrbW1fZG9ja2VyZmlsZQogICAga21tX2RvY2tlcmZpbGU9JChjYXQgPDwnRE9DS0VSRklMRV9URU1QTEFURScKICAgIEFSRyBEVEtfQVVUTwogICAgQVJHIEtFUk5FTF9GVUxMX1ZFUlNJT04KICAgIEFSRyBEUkJEX1ZFUlNJT049X19EUkJEX1ZFUlNJT05fXwoKICAgIEZST00gX19EUkJEX0lNQUdFX18gQVMgZHJiZC1zcmMKCiAgICBGUk9NICR7RFRLX0FVVE99IEFTIGJ1aWxkZXIKICAgIEFSRyBLRVJORUxfRlVMTF9WRVJTSU9OCiAgICBBUkcgRFJCRF9WRVJTSU9OCgogICAgV09SS0RJUiAvdG1wL2RyYmRfYnVpbGQKCiAgICBDT1BZIC0tZnJvbT1kcmJkLXNyYyAvZHJiZC0ke0RSQkRfVkVSU0lPTn0udGFyLmd6IC4KICAgIFJVTiB0YXIgLXh2emYgZHJiZC0ke0RSQkRfVkVSU0lPTn0udGFyLmd6CgogICAgV09SS0RJUiAvdG1wL2RyYmRfYnVpbGQvZHJiZC0ke0RSQkRfVkVSU0lPTn0KICAgIFJVTiBtYWtlIEtWRVI9JHtLRVJORUxfRlVMTF9WRVJTSU9OfSAtaiQobnByb2MpCiAgICBSVU4gbWtkaXIgLXAgL2luc3RhbGwvbGliL21vZHVsZXMvJHtLRVJORUxfRlVMTF9WRVJTSU9OfS9leHRyYQogICAgUlVOIGNwIGRyYmQvYnVpbGQtY3VycmVudC9kcmJkLmtvIGRyYmQvYnVpbGQtY3VycmVudC9kcmJkX3RyYW5zcG9ydF90Y3Aua28gL2luc3RhbGwvbGliL21vZHVsZXMvJHtLRVJORUxfRlVMTF9WRVJTSU9OfS9leHRyYS8KICAgIFJVTiBkZXBtb2QgLWIgL2luc3RhbGwgJHtLRVJORUxfRlVMTF9WRVJTSU9OfQogICAgRlJPTSByZWdpc3RyeS5yZWRoYXQuaW8vdWJpOS91YmktbWluaW1hbAogICAgQVJHIEtFUk5FTF9GVUxMX1ZFUlNJT04KICAgIENPUFkgLS1mcm9tPWJ1aWxkZXIgL2luc3RhbGwvbGliL21vZHVsZXMvIC9vcHQvbGliL21vZHVsZXMvCkRPQ0tFUkZJTEVfVEVNUExBVEUKKQogICAga21tX2RvY2tlcmZpbGU9IiR7a21tX2RvY2tlcmZpbGUvL19fRFJCRF9WRVJTSU9OX18vJHtEUkJEX1ZFUlNJT059fSIKICAgIGttbV9kb2NrZXJmaWxlPSIke2ttbV9kb2NrZXJmaWxlLy9fX0RSQkRfSU1BR0VfXy8ke0RSQkRfSU1BR0V9fSIKICAgIHByaW50ZiAnJXNcbicgIiRrbW1fZG9ja2VyZmlsZSIKfQoKIyBDcmVhdGUgdGhlIEtNTSBNb2R1bGUgQ1IgYW5kIGRvY2tlcmZpbGUgQ29uZmlnTWFwIHRvIGJ1aWxkIGFuZCBsb2FkIERSQkQga2VybmVsIG1vZHVsZXMgb24gdGhlIG5vZGVzLgpjcmVhdGVfZHJiZF9tb2R1bGUoKSB7CiAgICBpZiBvYyBnZXQgbW9kdWxlIGRyYmQta21vZCAtbiBvcGVuc2hpZnQta21tICY+L2Rldi9udWxsOyB0aGVuCiAgICAgICAgbXNnICJLTU0gTW9kdWxlIGRyYmQta21vZCBhbHJlYWR5IGV4aXN0cy4iCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgbG9jYWwga21tX2RvY2tlcmZpbGUgZHJiZF90YWdfZnJhZwogICAga21tX2RvY2tlcmZpbGU9JChyZW5kZXJfZHJiZF9rbW1fZG9ja2VyZmlsZSkKICAgIGRyYmRfdGFnX2ZyYWc9JChkcmJkX2ttb2RfaW1hZ2VfdGFnX3ZlcnNpb25fZnJhZ21lbnQpCgogICAgbXNnICJDcmVhdGluZyBLTU0gTW9kdWxlIGRyYmQta21vZCIKCiAgICBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgPDxFT0YKYXBpVmVyc2lvbjogdjEKa2luZDogQ29uZmlnTWFwCm1ldGFkYXRhOgogIG5hbWU6IGRyYmQta21vZC1kb2NrZXJmaWxlCiAgbmFtZXNwYWNlOiBvcGVuc2hpZnQta21tCmRhdGE6CiAgZG9ja2VyZmlsZTogfAokKHByaW50ZiAnJXNcbicgIiRrbW1fZG9ja2VyZmlsZSIgfCBhd2sgJ3twcmludCAiICAgICIgJDB9JykKRU9GCgogICAgIyBJbmNsdWRlIERSQkQgdmVyc2lvbiBpbiB0aGUgaW1hZ2UgdGFnIHNvIG9sZCBpbWFnZXMgYXJlIG5vdCByZXVzZWQuCiAgICBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgPDxFT0YKYXBpVmVyc2lvbjoga21tLnNpZ3MueC1rOHMuaW8vdjFiZXRhMQpraW5kOiBNb2R1bGUKbWV0YWRhdGE6CiAgbmFtZTogZHJiZC1rbW9kCiAgbmFtZXNwYWNlOiBvcGVuc2hpZnQta21tCnNwZWM6CiAgbW9kdWxlTG9hZGVyOgogICAgY29udGFpbmVyOgogICAgICBtb2Rwcm9iZToKICAgICAgICBtb2R1bGVOYW1lOiBkcmJkX3RyYW5zcG9ydF90Y3AKICAgICAgICBkaXJOYW1lOiAvb3B0CiAgICAgIGtlcm5lbE1hcHBpbmdzOgogICAgICAgIC0gcmVnZXhwOiAnXi4qXC54ODZfNjQkJwogICAgICAgICAgY29udGFpbmVySW1hZ2U6ICJpbWFnZS1yZWdpc3RyeS5vcGVuc2hpZnQtaW1hZ2UtcmVnaXN0cnkuc3ZjOjUwMDAvb3BlbnNoaWZ0LWttbS9kcmJkX2NvbXBhdF9rbW9kOlwke0tFUk5FTF9GVUxMX1ZFUlNJT059LWRyYmQtJHtkcmJkX3RhZ19mcmFnfSIKICAgICAgICAgIGJ1aWxkOgogICAgICAgICAgICBkb2NrZXJmaWxlQ29uZmlnTWFwOgogICAgICAgICAgICAgIG5hbWU6IGRyYmQta21vZC1kb2NrZXJmaWxlCiAgc2VsZWN0b3I6IHt9CkVPRgogICAgbXNnICJLTU0gTW9kdWxlIGFuZCBDb25maWdNYXAgYXBwbGllZC4iCn0KCiMgUmVtb3ZlIEtNTSBvYmplY3RzIHNvIHRoZSBuZXh0IGFwcGx5IHRyaWdnZXJzIGEgcmVidWlsZCAodXBncmFkZSBwYXRoKS4KZGVsZXRlX2RyYmRfa21tX21vZHVsZV9yZXNvdXJjZXMoKSB7CiAgICBtc2cgIkRlbGV0aW5nIEtNTSBNb2R1bGUgZHJiZC1rbW9kIGFuZCBEb2NrZXJmaWxlIENvbmZpZ01hcCIKICAgIG9jIGRlbGV0ZSBtb2R1bGUgZHJiZC1rbW9kIC1uIG9wZW5zaGlmdC1rbW0gLS1pZ25vcmUtbm90LWZvdW5kID4vZGV2L251bGwKICAgIG9jIGRlbGV0ZSBjb25maWdtYXAgZHJiZC1rbW9kLWRvY2tlcmZpbGUgLW4gb3BlbnNoaWZ0LWttbSAtLWlnbm9yZS1ub3QtZm91bmQgPi9kZXYvbnVsbAp9CgojIGNoZWNrIGlmIHRoZSBEUkJEIGtlcm5lbCBtb2R1bGVzIGFyZSBsb2FkZWQgb24gdGhlIG5vZGUKbm9kZV9oYXNfZHJiZF9rbW9kcygpIHsKICAgIGxvY2FsIG5vZGU9IiQxIgogICAgbG9jYWwgb3V0CiAgICBpZiAhIG91dD0kKG9jIGRlYnVnIC1xICJub2RlLyRub2RlIiAtLSBjaHJvb3QgL2hvc3QgY2F0IC9wcm9jL21vZHVsZXMgMj4vZGV2L251bGwpOyB0aGVuCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiAhIGVjaG8gIiRvdXQiIHwgZ3JlcCAtcUUgJ15kcmJkW1s6c3BhY2U6XV0nOyB0aGVuCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiAhIGVjaG8gIiRvdXQiIHwgZ3JlcCAtcUUgJ15kcmJkX3RyYW5zcG9ydF90Y3BbWzpzcGFjZTpdXSc7IHRoZW4KICAgICAgICByZXR1cm4gMQogICAgZmkKICAgIHJldHVybiAwCn0KCiMgd2FpdCBmb3IgdGhlIERSQkQga2VybmVsIG1vZHVsZXMgdG8gbG9hZCBvbiBib3RoIG5vZGVzCndhaXRfZm9yX21vZHVsZXMoKSB7CiAgICBpZiBub2RlX2hhc19kcmJkX2ttb2RzICIkTk9ERV8wIiAmJiBub2RlX2hhc19kcmJkX2ttb2RzICIkTk9ERV8xIjsgdGhlbgogICAgICAgIG1zZyAiRFJCRCBrZXJuZWwgbW9kdWxlcyBhcmUgYWxyZWFkeSBsb2FkZWQgb24gYm90aCBub2Rlcy4iCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgIyBTdWNjZXNzOiAvcHJvYy9tb2R1bGVzIG9uIGVhY2ggbm9kZSBjb250YWlucyBkcmJkIGFuZCBkcmJkX3RyYW5zcG9ydF90Y3AgbGluZXMKICAgIG1zZyAiV2FpdGluZyBmb3IgRFJCRCBrZXJuZWwgbW9kdWxlcyB0byBsb2FkIG9uIGJvdGggbm9kZXMgKHVwIHRvIDEwIG1pbikuLi4iCiAgICBfd2FpdF9iZWdpbgogICAgbG9jYWwgaQogICAgZm9yIGkgaW4gJChzZXEgMSA2MCk7IGRvCiAgICAgICAgaWYgbm9kZV9oYXNfZHJiZF9rbW9kcyAiJE5PREVfMCIgJiYgbm9kZV9oYXNfZHJiZF9rbW9kcyAiJE5PREVfMSI7IHRoZW4KICAgICAgICAgICAgX3dhaXRfc3VjY2VlZGVkICJEUkJEIGtlcm5lbCBtb2R1bGVzIGFyZSBsb2FkZWQgb24gYm90aCBub2RlcyIKICAgICAgICAgICAgcmV0dXJuIDAKICAgICAgICBmaQogICAgICAgIGlmIFtbICIkaSIgLWVxIDYwIF1dOyB0aGVuCiAgICAgICAgICAgIGRpZSAiRFJCRCBtb2R1bGVzIGZhaWxlZCB0byBsb2FkIGFmdGVyIDEwIG1pbnV0ZXMuIENoZWNrOiBvYyBnZXQgbW9kdWxlLHBvZHMgLW4gb3BlbnNoaWZ0LWttbTsgb2MgZGVidWcgLXEgbm9kZS8ke05PREVfMH0gLS0gY2hyb290IC9ob3N0IGNhdCAvcHJvYy9tb2R1bGVzIHwgZ3JlcCAtRSAnXmRyYmR8ZHJiZF90cmFuc3BvcnQnIgogICAgICAgIGZpCiAgICAgICAgc2xlZXAgMTAKICAgIGRvbmUKfQoKIyBWYWxpZGF0ZSBsb2FkZWQgL3N5cy9tb2R1bGUvZHJiZC92ZXJzaW9uIGFnYWluc3QgRFJCRF9WRVJTSU9OIG9uIGJvdGggbm9kZXMuCnZhbGlkYXRlX2RyYmRfbW9kdWxlX3ZlcnNpb24oKSB7CiAgICBsb2NhbCB2MCB2MQogICAgdjA9JChvYyBkZWJ1ZyAtcSAibm9kZS8kTk9ERV8wIiAtLSBjaHJvb3QgL2hvc3QgY2F0IC9zeXMvbW9kdWxlL2RyYmQvdmVyc2lvbiAyPi9kZXYvbnVsbCB8IHRyIC1kICdbOnNwYWNlOl0nIHx8IHRydWUpCiAgICB2MT0kKG9jIGRlYnVnIC1xICJub2RlLyROT0RFXzEiIC0tIGNocm9vdCAvaG9zdCBjYXQgL3N5cy9tb2R1bGUvZHJiZC92ZXJzaW9uIDI+L2Rldi9udWxsIHwgdHIgLWQgJ1s6c3BhY2U6XScgfHwgdHJ1ZSkKICAgIGlmIFtbICIkdjAiICE9ICIkRFJCRF9WRVJTSU9OIiB8fCAiJHYxIiAhPSAiJERSQkRfVkVSU0lPTiIgXV07IHRoZW4KICAgICAgICBkaWUgImxvYWRlZCBEUkJEIGttb2QgdmVyc2lvbiBtaXNtYXRjaCBhZnRlciBtb2R1bGUgbG9hZDogZXhwZWN0ZWQgJHtEUkJEX1ZFUlNJT059LCBnb3QgJHtOT0RFXzB9PScke3YwfScgJHtOT0RFXzF9PScke3YxfScuIgogICAgZmkKICAgIG1zZyAiTG9hZGVkIERSQkQga21vZCB2ZXJzaW9uIG1hdGNoZXMgdGFyZ2V0IHZlcnNpb24gKCR7RFJCRF9WRVJTSU9OfSkgb24gYm90aCBub2Rlcy4iCn0KCiMgUnVuIGRyYmRhZG0gb24gYSBub2RlIHZpYSBwb2RtYW4gdXNpbmcgdGhlIERSQkQgaW1hZ2U7IG1vdW50cyBob3N0IGRyYmQuY29uZiBhbmQgZHJiZC5kLgpkcmJkY3RsKCkgewogICAgbG9jYWwgbm9kZT0iJDEiCiAgICBzaGlmdAogICAgaWYgISBvYyBkZWJ1ZyAtcSAibm9kZS8kbm9kZSIgLS0gY2hyb290IC9ob3N0IFwKICAgICAgICBwb2RtYW4gcnVuIC0tcm0gLS1wcml2aWxlZ2VkIFwKICAgICAgICAtdiAvZGV2Oi9kZXYgXAogICAgICAgIC12ICIke0RSQkRfQ09ORl9QQVRIfToke0RSQkRfQ09ORl9QQVRIfSIgXAogICAgICAgIC12ICIke0RSQkRfRElSX1BBVEh9OiR7RFJCRF9ESVJfUEFUSH0iIFwKICAgICAgICAtLWhvc3RuYW1lICIkbm9kZSIgXAogICAgICAgIC0tbmV0IGhvc3QgXAogICAgICAgICIke0RSQkRfSU1BR0V9IiBcCiAgICAgICAgZHJiZGFkbSAtYyAiJHtEUkJEX0NPTkZfUEFUSH0iICIkQCI7IHRoZW4KICAgICAgICBlY2hvICJEUkJEIGNvbW1hbmQgZmFpbGVkIG9uIG5vZGUgJG5vZGU6IGRyYmRhZG0gJCoiID4mMgogICAgICAgIHJldHVybiAxCiAgICBmaQp9CgojIFRydWUgd2hlbiB0aGUgbm9kZSBoYXMgYSByb2xlIChQcmltYXJ5L1NlY29uZGFyeSkgZm9yIHRoZSBEUkJEIHJlc291cmNlLgpkcmJkX25vZGVfaGFzX3JvbGUoKSB7CiAgICBsb2NhbCBub2RlPSIkMSIgcm9sZQogICAgcm9sZT0kKGRyYmRjdGwgIiRub2RlIiByb2xlICIke0RSQkRfUkVTT1VSQ0V9IiAyPi9kZXYvbnVsbCB8fCB0cnVlKQogICAgW1sgIiRyb2xlIiA9PSAiUHJpbWFyeSIgfHwgIiRyb2xlIiA9PSAiU2Vjb25kYXJ5IiB8fCAiJHJvbGUiID09IFByaW1hcnkvKiB8fCAiJHJvbGUiID09IFNlY29uZGFyeS8qIF1dCn0KCiMgVHJ1ZSB3aGVuIGJvdGggbm9kZXMgc2hvdyBhIHJvbGUgKFByaW1hcnkvU2Vjb25kYXJ5KSBmb3IgdGhlIERSQkQgcmVzb3VyY2UuCmRyYmRfcmVzb3VyY2VfdXBfb25fYm90aF9ub2RlcygpIHsKICAgIGxvY2FsIG5vZGUKICAgIGZvciBub2RlIGluICIkTk9ERV8wIiAiJE5PREVfMSI7IGRvCiAgICAgICAgaWYgISBkcmJkX25vZGVfaGFzX3JvbGUgIiRub2RlIjsgdGhlbgogICAgICAgICAgICByZXR1cm4gMQogICAgICAgIGZpCiAgICBkb25lCiAgICByZXR1cm4gMAp9CgojIGNvbmZpZ3VyZSB0aGUgRFJCRCByZXNvdXJjZSBvbiBib3RoIG5vZGVzCmNvbmZpZ3VyZV9kcmJkKCkgewogICAgaWYgZHJiZF9yZXNvdXJjZV91cF9vbl9ib3RoX25vZGVzOyB0aGVuCiAgICAgICAgbXNnICJEUkJEIHJlc291cmNlIGlzIGFscmVhZHkgdXAgb24gYm90aCBub2RlcyIKICAgICAgICByZXR1cm4gMAogICAgZmkKCiAgICBtc2cgIkNvbmZpZ3VyaW5nIERSQkQgcmVzb3VyY2UgXCIke0RSQkRfUkVTT1VSQ0V9XCIgb24gJHtOT0RFXzB9IGFuZCAke05PREVfMX0uIgogICAgbG9jYWwgRFJCRF9SRVNfQk9EWSBEUkJEX1JFU19CNjQgRFJCRF9NQUlOX0I2NAogICAgRFJCRF9SRVNfQk9EWT0iZ2xvYmFsIHsgdXNhZ2UtY291bnQgbm87IH0KY29tbW9uIHsKICAgIG5ldCB7IHByb3RvY29sIEM7IGFmdGVyLXNiLTBwcmkgZGlzY2FyZC16ZXJvLWNoYW5nZXM7IGFmdGVyLXNiLTFwcmkgZGlzY2FyZC1zZWNvbmRhcnk7IH0KICAgIGRpc2sgeyBvbi1pby1lcnJvciBwYXNzX29uOyB9CiAgICBvcHRpb25zIHsgb24tbm8tZGF0YS1hY2Nlc3NpYmxlIHN1c3BlbmQtaW87IH0KfQpyZXNvdXJjZSAke0RSQkRfUkVTT1VSQ0V9IHsKICAgIG9uICR7Tk9ERV8wfSB7CiAgICAgICAgZGV2aWNlICR7RFJCRF9ERVZJQ0V9OwogICAgICAgIGRpc2sgJHtESVNLX1JFU09MVkVEX05PREUwfTsKICAgICAgICBhZGRyZXNzICR7Tk9ERV8wX0lQfToke0RSQkRfUE9SVH07CiAgICAgICAgbm9kZS1pZCAwOwogICAgICAgIG1ldGEtZGlzayBpbnRlcm5hbDsKICAgIH0KICAgIG9uICR7Tk9ERV8xfSB7CiAgICAgICAgZGV2aWNlICR7RFJCRF9ERVZJQ0V9OwogICAgICAgIGRpc2sgJHtESVNLX1JFU09MVkVEX05PREUxfTsKICAgICAgICBhZGRyZXNzICR7Tk9ERV8xX0lQfToke0RSQkRfUE9SVH07CiAgICAgICAgbm9kZS1pZCAxOwogICAgICAgIG1ldGEtZGlzayBpbnRlcm5hbDsKICAgIH0KfSIKCiAgICBEUkJEX1JFU19CNjQ9JChwcmludGYgJyVzJyAiJERSQkRfUkVTX0JPRFkiIHwgYmFzZTY0IHwgdHIgLWQgJ1xuJykKICAgIERSQkRfTUFJTl9CNjQ9JChwcmludGYgJyVzJyAiaW5jbHVkZSBcIiR7RFJCRF9ESVJfUEFUSH0vKi5yZXNcIjsiIHwgYmFzZTY0IHwgdHIgLWQgJ1xuJykKCiAgICBsb2NhbCBub2RlIHJlc19wYXRoCiAgICByZXNfcGF0aD0iJHtEUkJEX0RJUl9QQVRIfS8ke0RSQkRfUkVTT1VSQ0V9LnJlcyIKCiAgICAjIFdyaXRlIERSQkQgY29uZmlnIGZpbGVzIG9uIGJvdGggaG9zdHMgYmVmb3JlIGFueSBkcmJkYWRtIG11dGF0ZQogICAgZm9yIG5vZGUgaW4gIiROT0RFXzAiICIkTk9ERV8xIjsgZG8KICAgICAgICBtc2cgIk5vZGUgJHtub2RlfTogd3JpdGluZyBEUkJEIGNvbmZpZyBmaWxlcyB0byB0aGUgaG9zdC4uLiIKICAgICAgICBpZiAhIG9jIGRlYnVnIC1xICJub2RlLyRub2RlIiAtLSBjaHJvb3QgL2hvc3QgYmFzaCAtYyAiCiAgICAgICAgICAgIG1rZGlyIC1wIFwiJChkaXJuYW1lICIke0RSQkRfQ09ORl9QQVRIfSIpXCIgJyR7RFJCRF9ESVJfUEFUSH0nIC92YXIvbGliL2RyYmQKICAgICAgICAgICAgZWNobyAnJHtEUkJEX1JFU19CNjR9JyB8IGJhc2U2NCAtZCA+ICcke3Jlc19wYXRofScKICAgICAgICAgICAgZWNobyAnJHtEUkJEX01BSU5fQjY0fScgfCBiYXNlNjQgLWQgPiAnJHtEUkJEX0NPTkZfUEFUSH0nCiAgICAgICAgIjsgdGhlbgogICAgICAgICAgICBkaWUgImZhaWxlZCB0byB3cml0ZSBEUkJEIGNvbmZpZyBvbiAkbm9kZSIKICAgICAgICBmaQogICAgZG9uZQoKICAgICMgVXBncmFkZTogbWV0YWRhdGEgYWxyZWFkeSBleGlzdHMKICAgIGZvciBub2RlIGluICIkTk9ERV8wIiAiJE5PREVfMSI7IGRvCiAgICAgICAgaWYgZHJiZF9ub2RlX2hhc19yb2xlICIkbm9kZSI7IHRoZW4KICAgICAgICAgICAgY29udGludWUKICAgICAgICBmaQogICAgICAgIGlmIFtbICIkTU9ERSIgPT0gInVwZ3JhZGUiIF1dOyB0aGVuCiAgICAgICAgICAgIG1zZyAiTm9kZSAke25vZGV9OiBkcmJkYWRtIHVwIgogICAgICAgICAgICBpZiAhIGRyYmRjdGwgIiRub2RlIiB1cCAiJHtEUkJEX1JFU09VUkNFfSI7IHRoZW4KICAgICAgICAgICAgICAgIGRpZSAiZHJiZGFkbSB1cCBmYWlsZWQgb24gJG5vZGUiCiAgICAgICAgICAgIGZpCiAgICAgICAgZWxzZQogICAgICAgICAgICBtc2cgIk5vZGUgJHtub2RlfTogZHJiZGFkbSBjcmVhdGUtbWQiCiAgICAgICAgICAgIGlmICEgZHJiZGN0bCAiJG5vZGUiIGNyZWF0ZS1tZCAiJHtEUkJEX1JFU09VUkNFfSIgLS1mb3JjZTsgdGhlbgogICAgICAgICAgICAgICAgZGllICJkcmJkYWRtIGNyZWF0ZS1tZCBmYWlsZWQgb24gJG5vZGUiCiAgICAgICAgICAgIGZpCiAgICAgICAgICAgIG1zZyAiTm9kZSAke25vZGV9OiBkcmJkYWRtIHVwIgogICAgICAgICAgICBpZiAhIGRyYmRjdGwgIiRub2RlIiB1cCAiJHtEUkJEX1JFU09VUkNFfSI7IHRoZW4KICAgICAgICAgICAgICAgIG1zZyAiTm9kZSAke25vZGV9OiBkcmJkYWRtIHVwIGZhaWxlZDsgcmV0cnlpbmcgYWZ0ZXIgZHJiZGFkbSBkb3duLi4uIgogICAgICAgICAgICAgICAgZHJiZGN0bCAiJG5vZGUiIGRvd24gIiR7RFJCRF9SRVNPVVJDRX0iIDI+L2Rldi9udWxsIHx8IHRydWUKICAgICAgICAgICAgICAgIGlmICEgZHJiZGN0bCAiJG5vZGUiIHVwICIke0RSQkRfUkVTT1VSQ0V9IjsgdGhlbgogICAgICAgICAgICAgICAgICAgIGRpZSAiZHJiZGFkbSB1cCBmYWlsZWQgb24gJG5vZGUiCiAgICAgICAgICAgICAgICBmaQogICAgICAgICAgICBmaQogICAgICAgIGZpCiAgICBkb25lCgogICAgIyBSdW5uaW5nIGFkanVzdCBvbiBib3RoIG5vZGVzIHJlYXBwbGllcyAucmVzIHRvIHRoZSBydW5uaW5nIHJlc291cmNlCiAgICBmb3Igbm9kZSBpbiAiJE5PREVfMCIgIiROT0RFXzEiOyBkbwogICAgICAgIGlmIGRyYmRfbm9kZV9oYXNfcm9sZSAiJG5vZGUiOyB0aGVuCiAgICAgICAgICAgIG1zZyAiTm9kZSAke25vZGV9OiBkcmJkYWRtIGFkanVzdCIKICAgICAgICAgICAgaWYgISBkcmJkY3RsICIkbm9kZSIgYWRqdXN0ICIke0RSQkRfUkVTT1VSQ0V9IjsgdGhlbgogICAgICAgICAgICAgICAgZGllICJkcmJkYWRtIGFkanVzdCBmYWlsZWQgb24gJG5vZGUiCiAgICAgICAgICAgIGZpCiAgICAgICAgZmkKICAgIGRvbmUKICAgIG1zZyAiRFJCRCByZXNvdXJjZSBpcyBjb25maWd1cmVkIGFuZCB0aGUgcmVwbGljYXRpb24gbGluayBpcyB1cC4iCn0KCiMgY2hlY2sgaWYgdGhlIERSQkQgcmVzb3VyY2UgaXMgZnVsbHkgcmVwbGljYXRlZCBvbiBib3RoIG5vZGVzCmRyYmRfcmVzb3VyY2VfZnVsbHlfcmVwbGljYXRlZCgpIHsKICAgIGxvY2FsIG4gc3RhdHVzX291dAogICAgZm9yIG4gaW4gIiROT0RFXzAiICIkTk9ERV8xIjsgZG8KICAgICAgICBpZiAhIHN0YXR1c19vdXQ9JChkcmJkY3RsICIkbiIgc3RhdHVzICIke0RSQkRfUkVTT1VSQ0V9IiAyPiYxKTsgdGhlbgogICAgICAgICAgICByZXR1cm4gMQogICAgICAgIGZpCiAgICAgICAgaWYgISBlY2hvICIkc3RhdHVzX291dCIgfCBncmVwIC1xICJkaXNrOlVwVG9EYXRlIjsgdGhlbgogICAgICAgICAgICByZXR1cm4gMQogICAgICAgIGZpCiAgICAgICAgaWYgISBlY2hvICIkc3RhdHVzX291dCIgfCBncmVwIC1xICJwZWVyLWRpc2s6VXBUb0RhdGUiOyB0aGVuCiAgICAgICAgICAgIHJldHVybiAxCiAgICAgICAgZmkKICAgIGRvbmUKICAgIHJldHVybiAwCn0KCiMgQ2hlY2sgc3RhdHVzIG9mIHJlcGxpY2F0aW9uIGVhY2ggMzBzIGFuZCB3YWl0IGZvciBpdCB0byBjb21wbGV0ZS4Kc3luY19kcmJkKCkgewogICAgIyBUcmFuc2llbnQgUHJpbWFyeSBvbiBmaXJzdCBzb3J0ZWQgbm9kZSBmb3Igc3luYzsgdGhlbiBkZW1vdGUgdG8gU2Vjb25kYXJ5IG9uIGJvdGggbm9kZXMuCiAgICBsb2NhbCBQUklNQVJZX05PREU9IiROT0RFXzAiCiAgICBEUkJEX1BST01PVEVEX01BU1RFUjBfVEhJU19SVU49MAoKICAgIGlmIGRyYmRfcmVzb3VyY2VfZnVsbHlfcmVwbGljYXRlZDsgdGhlbgogICAgICAgIG1zZyAiRFJCRCBkYXRhIGlzIGFscmVhZHkgZnVsbHkgcmVwbGljYXRlZCAoVXBUb0RhdGUgb24gYm90aCBub2Rlcyk7IHNraXBwaW5nIHByaW1hcnkvc3luYyB3YWl0LiIKICAgICAgICByZXR1cm4gMAogICAgZmkKCiAgICBtc2cgIlByb21vdGluZyAkUFJJTUFSWV9OT0RFIHRvIFByaW1hcnkgdG8gcnVuIGluaXRpYWwgcmVwbGljYXRpb24uLi4iCiAgICBpZiAhIGRyYmRjdGwgIiRQUklNQVJZX05PREUiIHByaW1hcnkgLS1mb3JjZSAiJERSQkRfUkVTT1VSQ0UiOyB0aGVuCiAgICAgICAgZGllICJkcmJkYWRtIHByaW1hcnkgZmFpbGVkIG9uICRQUklNQVJZX05PREUiCiAgICBmaQogICAgRFJCRF9QUk9NT1RFRF9NQVNURVIwX1RISVNfUlVOPTEKCiAgICAjIFBvbGwgZHJiZGFkbSBzdGF0dXMgb24gdGhlIHRyYW5zaWVudCBwcmltYXJ5IHVudGlsIHBlZXItZGlzazpVcFRvRGF0ZSAoZnVsbCBzeW5jKS4gRXhhbXBsZQogICAgIyBmcmFnbWVudCB3aGlsZSBzeW5jaW5nOiBsaW5lcyB3aXRoIGRpc2s6L3BlZXItZGlzazogYW5kIHBvc3NpYmx5IGRvbmU6MTIuMzQlIGZvciBwcm9ncmVzcy4KICAgIG1zZyAiV2FpdGluZyBmb3IgZnVsbCBEUkJEIHN5bmMgKHVwIHRvIDMwIG1pbjsgcHJvZ3Jlc3MgZXZlcnkgMzBzIHdoZW4gYXZhaWxhYmxlKS4uLiIKICAgIF93YWl0X2JlZ2luCiAgICBsb2NhbCBpIFNUQVRVUyBQUk9HUkVTUwogICAgZm9yIGkgaW4gJChzZXEgMSA2MCk7IGRvCiAgICAgICAgU1RBVFVTPSQoZHJiZGN0bCAiJFBSSU1BUllfTk9ERSIgc3RhdHVzICIkRFJCRF9SRVNPVVJDRSIgMj4vZGV2L251bGwpCiAgICAgICAgaWYgZWNobyAiJFNUQVRVUyIgfCBncmVwIC1xICJwZWVyLWRpc2s6VXBUb0RhdGUiOyB0aGVuCiAgICAgICAgICAgIF93YWl0X3N1Y2NlZWRlZCAiSW5pdGlhbCByZXBsaWNhdGlvbiBmaW5pc2hlZDsgYm90aCBub2RlcyByZXBvcnQgVXBUb0RhdGUiCiAgICAgICAgICAgIHJldHVybiAwCiAgICAgICAgZmkKICAgICAgICBQUk9HUkVTUz0kKGVjaG8gIiRTVEFUVVMiIHwgZ3JlcCAtbyAnZG9uZTpbMC05Ll0qJyB8IGhlYWQgLTEgfCBjdXQgLWQ6IC1mMikKICAgICAgICBpZiBbWyAtbiAiJFBST0dSRVNTIiBdXTsgdGhlbgogICAgICAgICAgICBtc2cgIlJlcGxpY2F0aW9uIHByb2dyZXNzOiAke1BST0dSRVNTfSUiCiAgICAgICAgZmkKICAgICAgICBpZiBbWyAiJGkiIC1lcSA2MCBdXTsgdGhlbgogICAgICAgICAgICBkaWUgIkRSQkQgc3luYyB0aW1lZCBvdXQgYWZ0ZXIgMzBtLiBTdGF0dXM6ICRTVEFUVVMiCiAgICAgICAgZmkKICAgICAgICBzbGVlcCAzMAogICAgZG9uZQp9CgojIGNyZWF0ZSB0aGUgZmlsZXN5c3RlbSBvdmVyIHRoZSBEUkJEIGRldmljZQpjcmVhdGVfZmlsZXN5c3RlbV9vdmVyX2RyYmQoKSB7CiAgICBsb2NhbCBQUklNQVJZX05PREU9IiROT0RFXzAiCiAgICBsb2NhbCBmc3R5cGUKICAgIGlmICEgZnN0eXBlPSQob2MgZGVidWcgLXEgIm5vZGUvJFBSSU1BUllfTk9ERSIgLS0gY2hyb290IC9ob3N0IGJsa2lkIC1zIFRZUEUgLW8gdmFsdWUgIiR7RFJCRF9ERVZJQ0V9IiAyPi9kZXYvbnVsbCB8IHRyIC1kICcgXG4nKTsgdGhlbgogICAgICAgIGZzdHlwZT0iIgogICAgZmkKICAgIGlmIFtbICIkZnN0eXBlIiA9PSAieGZzIiBdXTsgdGhlbgogICAgICAgIG1zZyAiJHtEUkJEX0RFVklDRX0gYWxyZWFkeSBoYXMgWEZTOyBza2lwcGluZyBta2ZzLiIKICAgICAgICByZXR1cm4gMAogICAgZmkKCiAgICBtc2cgIkZvcm1hdHRpbmcgJHtEUkJEX0RFVklDRX0gd2l0aCBYRlMgKG1rZnMueGZzIC1mOyBvdmVyd3JpdGVzIGFueSBleGlzdGluZyBzaWduYXR1cmUpLi4uIgogICAgb2MgZGVidWcgLXEgIm5vZGUvJFBSSU1BUllfTk9ERSIgLS0gY2hyb290IC9ob3N0IHN1ZG8gbWtmcy54ZnMgLWYgIiR7RFJCRF9ERVZJQ0V9IgogICAgbXNnICJYRlMgY3JlYXRlZCBvbiAke0RSQkRfREVWSUNFfS4iCn0KCiMgRGVtb3RlIHRoZSB0cmFuc2llbnQgcHJpbWFyeSB1c2VkIGZvciBpbml0aWFsIHN5bmMgYmFjayB0byBTZWNvbmRhcnkuCm1ha2VfYm90aF9ub2RlX3NlY29uZGFyeSgpIHsKICAgIGlmIFtbICIke0RSQkRfUFJPTU9URURfTUFTVEVSMF9USElTX1JVTjotMH0iIC1uZSAxIF1dOyB0aGVuCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgbG9jYWwgUFJJTUFSWV9OT0RFPSIkTk9ERV8wIgogICAgbG9jYWwgaSBST0xFCgogICAgUk9MRT0kKGRyYmRjdGwgIiRQUklNQVJZX05PREUiIHJvbGUgIiR7RFJCRF9SRVNPVVJDRX0iIDI+L2Rldi9udWxsIHwgY3V0IC1kLyAtZjEpCiAgICBpZiBbWyAiJFJPTEUiID09ICJTZWNvbmRhcnkiIF1dOyB0aGVuCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCgogICAgbXNnICJEZW1vdGluZyAkUFJJTUFSWV9OT0RFIHRvIFNlY29uZGFyeS4iCiAgICBpZiAhIGRyYmRjdGwgIiRQUklNQVJZX05PREUiIHNlY29uZGFyeSAiJERSQkRfUkVTT1VSQ0UiOyB0aGVuCiAgICAgICAgZGllICJkcmJkYWRtIHNlY29uZGFyeSBmYWlsZWQgb24gJFBSSU1BUllfTk9ERSIKICAgIGZpCgogICAgbXNnICJXYWl0aW5nIGZvciAkUFJJTUFSWV9OT0RFIHRvIHJlcG9ydCBTZWNvbmRhcnkgcm9sZSAodXAgdG8gNDBzKS4uLiIKICAgIF93YWl0X2JlZ2luCiAgICBmb3IgaSBpbiAkKHNlcSAxIDIwKTsgZG8KICAgICAgICBST0xFPSQoZHJiZGN0bCAiJFBSSU1BUllfTk9ERSIgcm9sZSAiJHtEUkJEX1JFU09VUkNFfSIgMj4vZGV2L251bGwgfCBjdXQgLWQvIC1mMSkKICAgICAgICBpZiBbWyAiJFJPTEUiID09ICJTZWNvbmRhcnkiIF1dOyB0aGVuCiAgICAgICAgICAgIF93YWl0X3N1Y2NlZWRlZCAiJFBSSU1BUllfTk9ERSBpcyBub3cgU2Vjb25kYXJ5IgogICAgICAgICAgICByZXR1cm4gMAogICAgICAgIGZpCiAgICAgICAgc2xlZXAgMgogICAgZG9uZQogICAgZGllICJOb2RlICRQUklNQVJZX05PREUgZGlkIG5vdCBiZWNvbWUgU2Vjb25kYXJ5Igp9CgojIHNldHVwIHRoZSBEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0IHRvIGtlZXAgdGhlIERSQkQgcmVzb3VyY2UgdXAgb24gYm90aCBub2RlcwpzZXR1cF9kcmJkX2F1dG9zdGFydCgpIHsKICAgIGlmIG9jIGdldCBkYWVtb25zZXQgIiR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OQU1FfSIgLW4gIiR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OU30iICY+L2Rldi9udWxsOyB0aGVuCiAgICAgICAgbXNnICJEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0IGFscmVhZHkgZXhpc3RzLiIKICAgICAgICByZXR1cm4gMAogICAgZmkKCiAgICBtc2cgIkNyZWF0aW5nIERSQkQgYXV0by1zdGFydCBEYWVtb25TZXQgaW4gbmFtZXNwYWNlICR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OU30uLi4iCiAgICBvYyBjcmVhdGUgbmFtZXNwYWNlICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9IiAtLWRyeS1ydW49Y2xpZW50IC1vIHlhbWwgfCBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgMj4mMQogICAgb2MgY3JlYXRlIHNlcnZpY2VhY2NvdW50IGRyYmQtYXV0b3N0YXJ0IC1uICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9IiAtLWRyeS1ydW49Y2xpZW50IC1vIHlhbWwgfCBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgMj4mMQogICAgb2MgYWRtIHBvbGljeSBhZGQtc2NjLXRvLXVzZXIgcHJpdmlsZWdlZCAteiBkcmJkLWF1dG9zdGFydCAtbiAiJHtBVVRPU1RBUlRfREFFTU9OU0VUX05TfSIgPi9kZXYvbnVsbAoKICAgIG9jIGFwcGx5IC1mIC0gPi9kZXYvbnVsbCA8PEVPRgphcGlWZXJzaW9uOiB2MQpraW5kOiBDb25maWdNYXAKbWV0YWRhdGE6CiAgbmFtZTogZHJiZC1hdXRvc3RhcnQtc2NyaXB0CiAgbmFtZXNwYWNlOiAke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9CmRhdGE6CiAgc3RhcnQuc2g6IHwKICAgICMhL2Jpbi9iYXNoCiAgICB3aGlsZSB0cnVlOyBkbwogICAgICAgIGlmIGRyYmRhZG0gLWMgIiR7RFJCRF9DT05GX1BBVEh9IiBzdGF0dXMgJHtEUkJEX1JFU09VUkNFfSAmPi9kZXYvbnVsbDsgdGhlbgogICAgICAgICAgICBlY2hvICJEUkJEIHJlc291cmNlICR7RFJCRF9SRVNPVVJDRX0gaXMgYWxyZWFkeSB1cCIKICAgICAgICBlbHNlCiAgICAgICAgICAgIGVjaG8gIlN0YXJ0aW5nIERSQkQgcmVzb3VyY2UgJHtEUkJEX1JFU09VUkNFfS4uLiIKICAgICAgICAgICAgaWYgISBkcmJkYWRtIC1jICIke0RSQkRfQ09ORl9QQVRIfSIgdXAgJHtEUkJEX1JFU09VUkNFfTsgdGhlbgogICAgICAgICAgICAgICAgZWNobyAiV2FybmluZzogZHJiZGFkbSB1cCBmYWlsZWQsIHdpbGwgcmV0cnkiCiAgICAgICAgICAgIGZpCiAgICAgICAgZmkKICAgICAgICBpZiAhIGRyYmRhZG0gLWMgIiR7RFJCRF9DT05GX1BBVEh9IiBzdGF0dXMgJHtEUkJEX1JFU09VUkNFfTsgdGhlbgogICAgICAgICAgICA6CiAgICAgICAgZmkKICAgICAgICBzbGVlcCA2MAogICAgZG9uZQpFT0YKCiAgICBvYyBhcHBseSAtZiAtID4vZGV2L251bGwgPDxFT0YKYXBpVmVyc2lvbjogYXBwcy92MQpraW5kOiBEYWVtb25TZXQKbWV0YWRhdGE6CiAgbmFtZTogJHtBVVRPU1RBUlRfREFFTU9OU0VUX05BTUV9CiAgbmFtZXNwYWNlOiAke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9CiAgbGFiZWxzOgogICAgYXBwOiAke0FVVE9TVEFSVF9EQUVNT05TRVRfTkFNRX0Kc3BlYzoKICBzZWxlY3RvcjoKICAgIG1hdGNoTGFiZWxzOgogICAgICBhcHA6ICR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OQU1FfQogIHRlbXBsYXRlOgogICAgbWV0YWRhdGE6CiAgICAgIGxhYmVsczoKICAgICAgICBhcHA6ICR7QVVUT1NUQVJUX0RBRU1PTlNFVF9OQU1FfQogICAgc3BlYzoKICAgICAgc2VydmljZUFjY291bnROYW1lOiBkcmJkLWF1dG9zdGFydAogICAgICBob3N0TmV0d29yazogdHJ1ZQogICAgICBob3N0UElEOiB0cnVlCiAgICAgIGNvbnRhaW5lcnM6CiAgICAgIC0gbmFtZTogZHJiZC1zdGFydGVyCiAgICAgICAgaW1hZ2U6ICR7RFJCRF9JTUFHRX0KICAgICAgICBjb21tYW5kOiBbIi9iaW4vYmFzaCIsICIvc2NyaXB0cy9zdGFydC5zaCJdCiAgICAgICAgc2VjdXJpdHlDb250ZXh0OgogICAgICAgICAgcHJpdmlsZWdlZDogdHJ1ZQogICAgICAgICAgY2FwYWJpbGl0aWVzOgogICAgICAgICAgICBhZGQ6CiAgICAgICAgICAgIC0gU1lTX0FETUlOCiAgICAgICAgICAgIC0gU1lTX01PRFVMRQogICAgICAgICAgICAtIE5FVF9BRE1JTgogICAgICAgIHZvbHVtZU1vdW50czoKICAgICAgICAtIG5hbWU6IHNjcmlwdHMKICAgICAgICAgIG1vdW50UGF0aDogL3NjcmlwdHMKICAgICAgICAgIHJlYWRPbmx5OiB0cnVlCiAgICAgICAgLSBuYW1lOiBkcmJkLWNvbmYKICAgICAgICAgIG1vdW50UGF0aDogJHtEUkJEX0NPTkZfUEFUSH0KICAgICAgICAtIG5hbWU6IGRyYmQtZGlyCiAgICAgICAgICBtb3VudFBhdGg6ICR7RFJCRF9ESVJfUEFUSH0KICAgICAgICAtIG5hbWU6IGRldgogICAgICAgICAgbW91bnRQYXRoOiAvZGV2CiAgICAgICAgcmVzb3VyY2VzOgogICAgICAgICAgcmVxdWVzdHM6CiAgICAgICAgICAgIGNwdTogMTBtCiAgICAgICAgICAgIG1lbW9yeTogMzJNaQogICAgICAgICAgbGltaXRzOgogICAgICAgICAgICBjcHU6IDEwMG0KICAgICAgICAgICAgbWVtb3J5OiA2NE1pCiAgICAgIHZvbHVtZXM6CiAgICAgIC0gbmFtZTogc2NyaXB0cwogICAgICAgIGNvbmZpZ01hcDoKICAgICAgICAgIG5hbWU6IGRyYmQtYXV0b3N0YXJ0LXNjcmlwdAogICAgICAgICAgZGVmYXVsdE1vZGU6IDA3NTUKICAgICAgLSBuYW1lOiBkcmJkLWNvbmYKICAgICAgICBob3N0UGF0aDoKICAgICAgICAgIHBhdGg6ICR7RFJCRF9DT05GX1BBVEh9CiAgICAgICAgICB0eXBlOiBGaWxlCiAgICAgIC0gbmFtZTogZHJiZC1kaXIKICAgICAgICBob3N0UGF0aDoKICAgICAgICAgIHBhdGg6ICR7RFJCRF9ESVJfUEFUSH0KICAgICAgICAgIHR5cGU6IERpcmVjdG9yeQogICAgICAtIG5hbWU6IGRldgogICAgICAgIGhvc3RQYXRoOgogICAgICAgICAgcGF0aDogL2RldgogICAgICAgICAgdHlwZTogRGlyZWN0b3J5CiAgICAgIHRvbGVyYXRpb25zOgogICAgICAtIG9wZXJhdG9yOiBFeGlzdHMKICAgICAgICBlZmZlY3Q6IE5vU2NoZWR1bGUKICAgICAgLSBvcGVyYXRvcjogRXhpc3RzCiAgICAgICAgZWZmZWN0OiBOb0V4ZWN1dGUKRU9GCgogICAgbXNnICJXYWl0aW5nIGZvciBEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0IHBvZHMgb24gYm90aCBub2RlcyAodXAgdG8gNSBtaW4pLi4uIgogICAgX3dhaXRfYmVnaW4KICAgIGxvY2FsIGkgUkVBRFlfQ09VTlQKICAgIGZvciBpIGluICQoc2VxIDEgNjApOyBkbwogICAgICAgIGlmICEgUkVBRFlfQ09VTlQ9JChvYyBnZXQgZGFlbW9uc2V0ICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTkFNRX0iIC1uICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9IiAtbyBqc29ucGF0aD0ney5zdGF0dXMubnVtYmVyUmVhZHl9JyAyPi9kZXYvbnVsbCk7IHRoZW4KICAgICAgICAgICAgUkVBRFlfQ09VTlQ9MAogICAgICAgIGZpCiAgICAgICAgaWYgW1sgLXogIiRSRUFEWV9DT1VOVCIgXV07IHRoZW4KICAgICAgICAgICAgUkVBRFlfQ09VTlQ9MAogICAgICAgIGZpCiAgICAgICAgUkVBRFlfQ09VTlQ9JCgoMCArIFJFQURZX0NPVU5UKSkKICAgICAgICBpZiBbWyAiJFJFQURZX0NPVU5UIiAtZXEgMiBdXTsgdGhlbgogICAgICAgICAgICBfd2FpdF9zdWNjZWVkZWQgIkRSQkQgYXV0by1zdGFydCBEYWVtb25TZXQgaXMgcnVubmluZyBvbiBib3RoIG5vZGVzIgogICAgICAgICAgICByZXR1cm4gMAogICAgICAgIGZpCiAgICAgICAgaWYgW1sgIiRpIiAtZXEgNjAgXV07IHRoZW4KICAgICAgICAgICAgZGllICJEYWVtb25TZXQgbm90IHJlYWR5IChvYyBnZXQgZHMscG9kcyAtbiAke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9KSIKICAgICAgICBmaQogICAgICAgIHNsZWVwIDUKICAgIGRvbmUKfQoKIyBMYWJlbCBvbiB0aGUgZmxvYXRpbmcgbW9uIERlcGxveW1lbnQgc28gdGhlIFJvb2sgb3BlcmF0b3IgZG9lcyBub3QgcmVjb25jaWxlIGl0IHdoaWxlIHNjYWxlZCBkb3duIGZvciBEUkJEIHVwZ3JhZGUuCkZMT0FUSU5HX01PTl9OT19SRUNPTkNJTEVfTEFCRUxfS0VZPSIke0ZMT0FUSU5HX01PTl9OT19SRUNPTkNJTEVfTEFCRUxfS0VZOi1jZXBoLnJvb2suaW8vZG8tbm90LXJlY29uY2lsZX0iCkZMT0FUSU5HX01PTl9OT19SRUNPTkNJTEVfTEFCRUxfVkFMVUU9IiR7RkxPQVRJTkdfTU9OX05PX1JFQ09OQ0lMRV9MQUJFTF9WQUxVRTotdHJ1ZX0iCgojIFJldHVybiBkZXBsb3ltZW50IG5hbWUgcm9vay1jZXBoLW1vbi08ZmxvYXRpbmdNb24+IG9yIGVtcHR5IGlmIG5vdCBhcHBsaWNhYmxlLgpmbG9hdGluZ19tb25fZGVwbG95bWVudF9uYW1lKCkgewogICAgbG9jYWwgbmFtZQogICAgbmFtZT0kKG9jIGdldCBjZXBoY2x1c3RlciAtbiAiJHtPREZfTkFNRVNQQUNFfSIgLW8ganNvbnBhdGg9J3suaXRlbXNbMF0uc3BlYy5tb24uZmxvYXRpbmdNb24ubmFtZX0nIDI+L2Rldi9udWxsIHx8IHRydWUpCiAgICBpZiBbWyAteiAiJG5hbWUiIF1dOyB0aGVuCiAgICAgICAgZWNobyAiIgogICAgICAgIHJldHVybiAxCiAgICBmaQogICAgZWNobyAicm9vay1jZXBoLW1vbi0ke25hbWV9Igp9CgojIFNjYWxlIHRoZSBmbG9hdGluZyBtb24gZGVwbG95bWVudCB0byB0aGUgZ2l2ZW4gbnVtYmVyIG9mIHJlcGxpY2FzLgojIEJlZm9yZSBzY2FsZSB0byAwOiBzZXQgY2VwaC5yb29rLmlvL2RvLW5vdC1yZWNvbmNpbGU9dHJ1ZSBvbiB0aGUgRGVwbG95bWVudCBzbyBSb29rIGRvZXMgbm90IGZpZ2h0IHRoZSBzY2FsZS4KIyBCZWZvcmUgc2NhbGUgdXAgKHJlcGxpY2FzID4gMCk6IHJlbW92ZSB0aGF0IGxhYmVsLCB0aGVuIHNjYWxlLgpzY2FsZV9mbG9hdGluZ19tb25fZGVwbG95bWVudCgpIHsKICAgIGxvY2FsIHJlcGxpY2FzPSIkMSIgZGVwCiAgICBkZXA9JChmbG9hdGluZ19tb25fZGVwbG95bWVudF9uYW1lIHx8IHRydWUpCiAgICBpZiBbWyAteiAiJGRlcCIgXV07IHRoZW4KICAgICAgICBtc2cgIk5vIENlcGhDbHVzdGVyIGZsb2F0aW5nIG1vbiBpbiAke09ERl9OQU1FU1BBQ0V9OyBza2lwcGluZyBtb24gZGVwbG95bWVudCBzY2FsZS4iCiAgICAgICAgcmV0dXJuIDAKICAgIGZpCiAgICBpZiAhIG9jIGdldCBkZXBsb3ltZW50ICIkZGVwIiAtbiAiJHtPREZfTkFNRVNQQUNFfSIgJj4vZGV2L251bGw7IHRoZW4KICAgICAgICBtc2cgIkRlcGxveW1lbnQgJHtPREZfTkFNRVNQQUNFfS8ke2RlcH0gbm90IGZvdW5kOyBza2lwcGluZyBtb24gc2NhbGUuIgogICAgICAgIHJldHVybiAwCiAgICBmaQogICAgaWYgW1sgIiR7cmVwbGljYXN9IiAtZXEgMCBdXTsgdGhlbgogICAgICAgIG1zZyAiTGFiZWxpbmcgZGVwbG95bWVudCAke09ERl9OQU1FU1BBQ0V9LyR7ZGVwfSAke0ZMT0FUSU5HX01PTl9OT19SRUNPTkNJTEVfTEFCRUxfS0VZfT0ke0ZMT0FUSU5HX01PTl9OT19SRUNPTkNJTEVfTEFCRUxfVkFMVUV9IChkbyBub3QgcmVjb25jaWxlKS4uLiIKICAgICAgICBvYyBsYWJlbCBkZXBsb3ltZW50ICIkZGVwIiAtbiAiJHtPREZfTkFNRVNQQUNFfSIgXAogICAgICAgICAgICAiJHtGTE9BVElOR19NT05fTk9fUkVDT05DSUxFX0xBQkVMX0tFWX09JHtGTE9BVElOR19NT05fTk9fUkVDT05DSUxFX0xBQkVMX1ZBTFVFfSIgLS1vdmVyd3JpdGUKICAgIGVsc2UKICAgICAgICBtc2cgIlJlbW92aW5nIGxhYmVsICR7RkxPQVRJTkdfTU9OX05PX1JFQ09OQ0lMRV9MQUJFTF9LRVl9IGZyb20gZGVwbG95bWVudCAke09ERl9OQU1FU1BBQ0V9LyR7ZGVwfS4uLiIKICAgICAgICBvYyBsYWJlbCBkZXBsb3ltZW50ICIkZGVwIiAtbiAiJHtPREZfTkFNRVNQQUNFfSIgIiR7RkxPQVRJTkdfTU9OX05PX1JFQ09OQ0lMRV9MQUJFTF9LRVl9LSIgMj4vZGV2L251bGwgfHwgdHJ1ZQogICAgZmkKICAgIG1zZyAiU2NhbGluZyBkZXBsb3ltZW50ICR7T0RGX05BTUVTUEFDRX0vJHtkZXB9IHRvICR7cmVwbGljYXN9IHJlcGxpY2EocykuLi4iCiAgICBvYyBzY2FsZSBkZXBsb3ltZW50ICIkZGVwIiAtbiAiJHtPREZfTkFNRVNQQUNFfSIgLS1yZXBsaWNhcz0iJHtyZXBsaWNhc30iCn0KCiMgRGVsZXRlIHRoZSBEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0LgpkZWxldGVfZHJiZF9hdXRvc3RhcnRfZGFlbW9uc2V0KCkgewogICAgaWYgISBvYyBnZXQgZGFlbW9uc2V0ICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTkFNRX0iIC1uICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9IiAmPi9kZXYvbnVsbDsgdGhlbgogICAgICAgIHJldHVybiAwCiAgICBmaQogICAgbXNnICJEZWxldGluZyBEYWVtb25TZXQgJHtBVVRPU1RBUlRfREFFTU9OU0VUX05TfS8ke0FVVE9TVEFSVF9EQUVNT05TRVRfTkFNRX0uLi4iCiAgICBvYyBkZWxldGUgZGFlbW9uc2V0ICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTkFNRX0iIC1uICIke0FVVE9TVEFSVF9EQUVNT05TRVRfTlN9IiAtLWlnbm9yZS1ub3QtZm91bmQgPi9kZXYvbnVsbAp9CgojIERlbW90ZSBhbmQgZG93biB0aGUgRFJCRCByZXNvdXJjZSBvbiBib3RoIG5vZGVzLgpkcmJkX2RlbW90ZV9hbmRfZG93bl9hbGwoKSB7CiAgICBsb2NhbCBub2RlIHJvbGUKICAgIG1zZyAiU3RvcHBpbmcgRFJCRCByZXNvdXJjZSBvbiBib3RoIG5vZGVzIgogICAgZm9yIG5vZGUgaW4gIiROT0RFXzAiICIkTk9ERV8xIjsgZG8KICAgICAgICByb2xlPSQoZHJiZGN0bCAiJG5vZGUiIHJvbGUgIiR7RFJCRF9SRVNPVVJDRX0iIDI+L2Rldi9udWxsIHwgY3V0IC1kLyAtZjEgfCB0ciAtZCAnWzpzcGFjZTpdJyB8fCB0cnVlKQogICAgICAgIGlmIFtbICIkcm9sZSIgPT0gIlByaW1hcnkiIF1dOyB0aGVuCiAgICAgICAgICAgIG1zZyAiTm9kZSAke25vZGV9OiBkZW1vdGluZyBQcmltYXJ5IGJlZm9yZSBkcmJkYWRtIGRvd24uLi4iCiAgICAgICAgICAgIGRyYmRjdGwgIiRub2RlIiBzZWNvbmRhcnkgIiR7RFJCRF9SRVNPVVJDRX0iIHx8IHRydWUKICAgICAgICBmaQogICAgICAgIG1zZyAiTm9kZSAke25vZGV9OiBkcmJkYWRtIGRvd24gJHtEUkJEX1JFU09VUkNFfS4uLiIKICAgICAgICBkcmJkY3RsICIkbm9kZSIgZG93biAiJHtEUkJEX1JFU09VUkNFfSIgfHwgdHJ1ZQogICAgZG9uZQp9CgojIGNyZWF0ZSB0aGUgc3VjY2VzcyBDb25maWdNYXAgdG8gc2F2ZSB0aGUgc2V0dXAgc3VtbWFyeSBmb3IgZnVydGhlciBjb25zdW1wdGlvbi4KY3JlYXRlX3N1Y2Nlc3NfY29uZmlnbWFwKCkgewogICAgbXNnICJTYXZpbmcgc2V0dXAgc3VtbWFyeSB0byBDb25maWdNYXAgJHtPREZfTkFNRVNQQUNFfS8ke09VVFBVVF9DTV9OQU1FfSIKICAgIGlmICEgb2MgY3JlYXRlIG5hbWVzcGFjZSAiJHtPREZfTkFNRVNQQUNFfSIgLS1kcnktcnVuPWNsaWVudCAtbyB5YW1sIHwgb2MgYXBwbHkgLWYgLSA+L2Rldi9udWxsIDI+JjE7IHRoZW4KICAgICAgICA6CiAgICBmaQoKICAgIGxvY2FsIGJkMCBiZDEKICAgIGlmIFtbIC1uICIkQkFDS0lOR19QQVRIIiBdXTsgdGhlbgogICAgICAgIGJkMD0iJEJBQ0tJTkdfUEFUSCIKICAgICAgICBiZDE9IiRCQUNLSU5HX1BBVEgiCiAgICBlbHNlCiAgICAgICAgYmQwPSIkQkFDS0lOR19QQVRIX05PREUwIgogICAgICAgIGJkMT0iJEJBQ0tJTkdfUEFUSF9OT0RFMSIKICAgIGZpCgogICAgb2MgYXBwbHkgLWYgLSA+L2Rldi9udWxsIDw8RU9GCmFwaVZlcnNpb246IHYxCmtpbmQ6IENvbmZpZ01hcAptZXRhZGF0YToKICBuYW1lOiAke09VVFBVVF9DTV9OQU1FfQogIG5hbWVzcGFjZTogJHtPREZfTkFNRVNQQUNFfQogIGxhYmVsczoKICAgIGFwcC5rdWJlcm5ldGVzLmlvL25hbWU6IGRyYmQtc2V0dXAKICAgIGFwcC5rdWJlcm5ldGVzLmlvL2NvbXBvbmVudDogc3RvcmFnZQpkYXRhOgogIE5PREVfMF9OQU1FOiAiJHtOT0RFXzB9IgogIE5PREVfMV9OQU1FOiAiJHtOT0RFXzF9IgogIE5PREVfMF9JUDogIiR7Tk9ERV8wX0lQfSIKICBOT0RFXzFfSVA6ICIke05PREVfMV9JUH0iCiAgQkxPQ0tfREVWSUNFX1BBVEhfTk9ERV8wOiAiJHtiZDB9IgogIEJMT0NLX0RFVklDRV9QQVRIX05PREVfMTogIiR7YmQxfSIKICBESVNLX0JZX0lEX05PREVfMDogIiR7RElTS19SRVNPTFZFRF9OT0RFMH0iCiAgRElTS19CWV9JRF9OT0RFXzE6ICIke0RJU0tfUkVTT0xWRURfTk9ERTF9IgogIERSQkRfQ09ORl9QQVRIOiAiJHtEUkJEX0NPTkZfUEFUSH0iCiAgRFJCRF9ESVJfUEFUSDogIiR7RFJCRF9ESVJfUEFUSH0iCiAgRFJCRF9ERVZJQ0VfTkFNRTogIiR7RFJCRF9ERVZJQ0V9IgogIERSQkRfUkVTT1VSQ0VfTkFNRTogIiR7RFJCRF9SRVNPVVJDRX0iCiAgRFJCRF9QT1JUOiAiJHtEUkJEX1BPUlR9IgogIERSQkRfVVRJTFNfSU1BR0U6ICIke0RSQkRfSU1BR0V9IgogIERSQkRfVkVSU0lPTjogIiR7RFJCRF9WRVJTSU9OfSIKICBTRVRVUF9USU1FU1RBTVA6ICIkKGRhdGUgLXUgKyVZLSVtLSVkVCVIOiVNOiVTWikiCkVPRgp9CgpwcmludF9zdWNjZXNzKCkgewogICAgZWNobyAiIgogICAgaWYgW1sgIiRNT0RFIiA9PSAidXBncmFkZSIgXV07IHRoZW4KICAgICAgICBlY2hvICIgIC0tPiBEUkJEIHVwZ3JhZGUgY29tcGxldGVkIHN1Y2Nlc3NmdWxseSA8LS0iCiAgICBlbHNlCiAgICAgICAgZWNobyAiICAtLT4gRFJCRCBpbnN0YWxsIGNvbXBsZXRlZCBzdWNjZXNzZnVsbHkgPC0tIgogICAgZmkKICAgIGVjaG8gIiIKICAgIGVjaG8gIkNoZWNrIERSQkQgc3RhdHVzIG9uICR7Tk9ERV8wfSAocmVwZWF0IHdpdGggJHtOT0RFXzF9KToiCiAgICBlY2hvICIgIG9jIGRlYnVnIC1xIG5vZGUvJHtOT0RFXzB9IC0tIGNocm9vdCAvaG9zdCBwb2RtYW4gcnVuIC0tcm0gLS1wcml2aWxlZ2VkIFxcIgogICAgZWNobyAiICAgIC12IC9kZXY6L2RldiAtdiAke0RSQkRfQ09ORl9QQVRIfToke0RSQkRfQ09ORl9QQVRIfSAtdiAke0RSQkRfRElSX1BBVEh9OiR7RFJCRF9ESVJfUEFUSH0gXFwiCiAgICBlY2hvICIgICAgLS1ob3N0bmFtZSAke05PREVfMH0gLS1uZXQgaG9zdCAke0RSQkRfSU1BR0V9IGRyYmRhZG0gLWMgJHtEUkJEX0NPTkZfUEFUSH0gc3RhdHVzICR7RFJCRF9SRVNPVVJDRX0iCiAgICBlY2hvICIiCn0KCm1haW4oKSB7CiAgICBwYXJzZV9hcmdzICIkQCIKICAgIGNoZWNrX3ByZXJlcXVpc2l0ZXMgIyBjaGVjayBpZiB0aGUgcHJlcmVxdWlzaXRlcyBhcmUgbWV0CiAgICBkZXRlY3Rfbm9kZXMgIyBkZXRlY3QgdGhlIG5vZGVzIGluIHRoZSBjbHVzdGVyCgogICAgaWYgW1sgIiRMSVNUX0RFVklDRVNfT05MWSIgLWVxIDEgXV07IHRoZW4KICAgICAgICBsaXN0X2RldmljZXMgIyBsaXN0IHRoZSBibG9jayBkZXZpY2VzIG9uIHRoZSBub2RlcwogICAgICAgIGV4aXQgMAogICAgZmkKCiAgICBpZiBbWyAiJE1PREUiID09ICJ1cGdyYWRlIiBdXTsgdGhlbgogICAgICAgIHZhbGlkYXRlX3VwZ3JhZGVfY29uZmlnbWFwX2FuZF9sb2FkX2Rpc2tfaWRzICMgdXBncmFkZSBvbmx5OiB2YWxpZGF0ZSBvdXRwdXQgQ29uZmlnTWFwIHByZXNlbmNlIGFuZCBsb2FkIERSQkQgZGlzayBieS1pZCBtYXBwaW5nCiAgICBlbHNlCiAgICAgICAgdmFsaWRhdGVfYW5kX3Jlc29sdmVfZGlza3MgIyBpbnN0YWxsIG9ubHk6IHZhbGlkYXRlIHBhdGhzIGFuZCByZXNvbHZlIHRvIC9kZXYvZGlzay9ieS1pZAogICAgZmkKCiAgICBwcmludF9jb25maWcgIyBwcmludCB0aGUgY29uZmlndXJhdGlvbgogICAgc2V0dXBfa21tX29wZXJhdG9yICMgc2V0dXAgdGhlIEtlcm5lbCBNb2R1bGUgTWFuYWdlbWVudCBvcGVyYXRvcgogICAgc2V0dXBfaW1hZ2VfcmVnaXN0cnlfb3BlcmF0b3IgIyBzZXR1cCB0aGUgSW1hZ2UgUmVnaXN0cnkgb3BlcmF0b3IKICAgIGttbV9pbWFnZV9idWlsZF93YWl0cyAjIHdhaXQgZm9yIGJ1aWxkZXIgU0EgKyBkb2NrZXJjZmcgc2VjcmV0CgogICAgaWYgW1sgIiRNT0RFIiA9PSAidXBncmFkZSIgXV07IHRoZW4KICAgICAgICAjIEFkZCBkbyBub3QgcmVjb25jaWxlIGZsYWcKICAgICAgICBzY2FsZV9mbG9hdGluZ19tb25fZGVwbG95bWVudCAwICMgc2NhbGUgdGhlIGZsb2F0aW5nIG1vbiBkZXBsb3ltZW50IGRvd24gdG8gMCByZXBsaWNhcwogICAgICAgIG1zZyAiV2FpdGluZyAxMHMgYWZ0ZXIgc2NhbGluZyBmbG9hdGluZyBtb24gKEkvTyBkcmFpbikuLi4iCiAgICAgICAgc2xlZXAgMTAKICAgICAgICBkZWxldGVfZHJiZF9hdXRvc3RhcnRfZGFlbW9uc2V0ICMgZGVsZXRlIHRoZSBEUkJEIGF1dG8tc3RhcnQgRGFlbW9uU2V0CiAgICAgICAgZHJiZF9kZW1vdGVfYW5kX2Rvd25fYWxsICMgZGVtb3RlIGFuZCBkb3duIHRoZSBEUkJEIHJlc291cmNlIG9uIGJvdGggbm9kZXMKICAgICAgICBkZWxldGVfZHJiZF9rbW1fbW9kdWxlX3Jlc291cmNlcyAjIGRlbGV0ZSB0aGUgS01NIE1vZHVsZSBhbmQgRG9ja2VyZmlsZSBDb25maWdNYXAKICAgIGZpCgogICAgY3JlYXRlX2RyYmRfbW9kdWxlICMgY29tbW9uIHBhdGg6IGNyZWF0ZSBLTU0gTW9kdWxlICsgRG9ja2VyZmlsZSBDb25maWdNYXAKICAgIHdhaXRfZm9yX21vZHVsZXMgIyB3YWl0IGZvciBEUkJEIGtlcm5lbCBtb2R1bGVzIHRvIGxvYWQgb24gYm90aCBub2RlcwogICAgdmFsaWRhdGVfZHJiZF9tb2R1bGVfdmVyc2lvbiAjIGNvbXBhcmUgL3N5cy9tb2R1bGUvZHJiZC92ZXJzaW9uIHRvIERSQkRfVkVSU0lPTgogICAgY29uZmlndXJlX2RyYmQgIyBjb25maWd1cmUgdGhlIERSQkQgcmVzb3VyY2Ugb24gYm90aCBub2RlcwogICAgc3luY19kcmJkICMgc3luYyB0aGUgRFJCRCByZXNvdXJjZSBvbiBib3RoIG5vZGVzCiAgICBjcmVhdGVfZmlsZXN5c3RlbV9vdmVyX2RyYmQgIyBjcmVhdGUgdGhlIGZpbGVzeXN0ZW0gb3ZlciB0aGUgRFJCRCBkZXZpY2UKICAgIG1ha2VfYm90aF9ub2RlX3NlY29uZGFyeSAjIG1ha2UgYm90aCBub2RlcyBzZWNvbmRhcnkKICAgIHNldHVwX2RyYmRfYXV0b3N0YXJ0ICMgc2V0dXAgdGhlIERSQkQgYXV0by1zdGFydCBEYWVtb25TZXQgdG8ga2VlcCB0aGUgRFJCRCByZXNvdXJjZSB1cCBvbiBib3RoIG5vZGVzCgogICAgaWYgW1sgIiRNT0RFIiA9PSAidXBncmFkZSIgXV07IHRoZW4KICAgICAgICBzY2FsZV9mbG9hdGluZ19tb25fZGVwbG95bWVudCAxCiAgICBmaQoKICAgIGNyZWF0ZV9zdWNjZXNzX2NvbmZpZ21hcCAjIGNyZWF0ZSB0aGUgc3VjY2VzcyBDb25maWdNYXAgdG8gc2F2ZSB0aGUgc2V0dXAgc3VtbWFyeSBmb3IgZnVydGhlciBjb25zdW1wdGlvbgogICAgcHJpbnRfc3VjY2VzcyAjIHByaW50IHRoZSBzdWNjZXNzIG1lc3NhZ2UKfQoKbWFpbiAiJEAiCg==" kind: ConfigMap metadata: name: rook-ceph-drbd-setup-script diff --git a/deploy/examples/drbd-setup.sh b/deploy/examples/drbd-setup.sh index c1c269aa3ac7..e965b226865a 100755 --- a/deploy/examples/drbd-setup.sh +++ b/deploy/examples/drbd-setup.sh @@ -17,11 +17,9 @@ # DRBD Setup Script for Two-Node OpenShift Cluster, Safe to re-run( idempotent ). # The script can skip successful steps & run only the required steps. # -# CLI overrides env for: --drbd-conf-path, --drbd-dir-path, --drbd-resource, --drbd-device, --drbd-port -# # Prerequisites: -# - Nodes can pull ${DRBD_IMAGE}; ${DRBD_PORT}/tcp open between nodes. -# - Image registry: the in-cluster OpenShift registry with emptyDir storage +# - Nodes can pull ${DRBD_IMAGE}; +# - ${DRBD_PORT}/tcp open between nodes. # set -euo pipefail @@ -47,9 +45,9 @@ _wait_succeeded() { } # TODO: bump default image tag when a new one is published. -DRBD_IMAGE="${DRBD_IMAGE:-quay.io/rhceph-dev/odf4-odf-drbd-rhel9:v4.22}" # ODF DRBD image (drbdadm + sources) +DRBD_IMAGE="${DRBD_IMAGE:-quay.io/rhceph-dev/odf4-odf-drbd-rhel9:v4.22.0}" # ODF DRBD image (drbdadm + sources) # TODO: bump when tarball inside the image changes. -DRBD_VERSION="${DRBD_VERSION:-9.2.17}" # Must match DRBD source version in DRBD_IMAGE +DRBD_VERSION="${DRBD_VERSION:-9.2.18}" # Must match DRBD source version in DRBD_IMAGE DRBD_CONF_PATH="${DRBD_CONF_PATH:-/etc/drbd.conf}" # Main file: include of ${DRBD_DIR_PATH}/*.res only DRBD_DIR_PATH="${DRBD_DIR_PATH:-/etc/drbd.d}" # Per-resource .res files (actual DRBD definition) @@ -60,9 +58,14 @@ DRBD_PORT="${DRBD_PORT:-7794}" # DRBD replicat AUTOSTART_DAEMONSET_NAME="${AUTOSTART_DAEMONSET_NAME:-drbd-autostart}" # DRBD auto-start DaemonSet name AUTOSTART_DAEMONSET_NS="${AUTOSTART_DAEMONSET_NS:-openshift-kmm}" # DRBD auto-start DaemonSet namespace -OUTPUT_CM_NS="${OUTPUT_CM_NS:-openshift-storage}" # Namespace for setup summary ConfigMap OUTPUT_CM_NAME="${OUTPUT_CM_NAME:-drbd-configure}" # Name for the setup summary ConfigMap +# OpenShift namespace for DRBD summary ConfigMap, CephCluster, and floating mon (default OpenShift ODF). +ODF_NAMESPACE="${ODF_NAMESPACE:-openshift-storage}" + +# install | upgrade (set in parse_args; default install) +MODE="" + # Approximate wait ceilings in this script: KMM operator ~5m (60×5s); DRBD modules ~10m (60×10s); # initial sync ~30m (60×30s); autostart DaemonSet ~5m (60×5s). @@ -85,46 +88,51 @@ NODE_1_IP="" usage() { cat < - $0 -d0 -d1 - $0 -l +Usage examples: + $0 -l | $0 -d | $0 -d0 -d1 | $0 upgrade | $0 help + +Default Mode (install) — + +Required (one of): + -l List block devices on each node (NAME, PATH, SIZE, ROTA, TYPE, FSTYPE). + -d PATH Backing block device, same path & size on both nodes (e.g. /dev/sdb). + -d0 PATH -d1 PATH Per-node backing paths (node order = sorted cluster node names). + +Optional: + --drbd-conf-path PATH Host path to drbd.conf (default ${DRBD_CONF_PATH}) + --drbd-dir-path PATH Host dir for resource snippets (default ${DRBD_DIR_PATH}) + --drbd-resource NAME Resource name in config (default ${DRBD_RESOURCE}) + --drbd-device PATH Upper DRBD device (default ${DRBD_DEVICE}) + --drbd-port N TCP replication port (default ${DRBD_PORT}) Backing paths are raw block device paths (e.g. /dev/sdb). Use the PATH column from -l. Disks must be SSD-class (ROTA 0) and same size on both nodes. - -d PATH - One path used on both nodes. Choose this when each machine has the replica disk at the - same device name (both nodes use e.g. /dev/sdb for the DRBD lower layer). +What install does: setup KMM operator, setup image registry operator, +build and load DRBD kmods, configure & sync DRBD, create the filesystem over the DRBD device, +setup the DRBD auto-start DaemonSet & create the success ConfigMap. -Use -d0/-d1 when the two nodes use different paths; do not combine -d with -d0/-d1. +Upgrade Mode — - -d0 PATH Path on node 0 only (first node name after sorting all cluster nodes). - -d1 PATH Path on node 1 only (second node). +(no disk flags — DISK_BY_ID_NODE_0/1 are read from ConfigMap ${ODF_NAMESPACE}/${OUTPUT_CM_NAME}) -Discovery: - -l List block devices on each node (NAME, PATH, SIZE, ROTA, TYPE, FSTYPE). - -DRBD options: - --drbd-conf-path PATH Host path to drbd.conf (default ${DRBD_CONF_PATH}) - --drbd-dir-path PATH Host dir for resource snippets (default ${DRBD_DIR_PATH}) - --drbd-resource NAME Logical DRBD resource name in config (default ${DRBD_RESOURCE}) - --drbd-device PATH DRBD upper device node path, same on both nodes (default ${DRBD_DEVICE}) - --drbd-port N TCP port for DRBD replication (default ${DRBD_PORT}) +What upgrade does: scale floating Ceph mon, remove autostart DaemonSet, drbdadm down, +delete and re-apply KMM Module + Dockerfile, wait for new kmods, drbdadm up, sync if needed, +recreate autostart DaemonSet, scale mon back. General: - -h Show this help and exit - -Environment: - Defaults are documented on each assignment near the top of this script. - OUTPUT_CM_NS / OUTPUT_CM_NAME — namespace and name of the summary ConfigMap (floating mon). + -h, --help Show this text. USAGE } -parse_args() { +_parse_install_options() { while [[ $# -gt 0 ]]; do case "$1" in + -h|--help) + usage + exit 0 + ;; -d0) if [[ -z "${2:-}" ]]; then die "-d0 requires a path (e.g. /dev/sdb)" @@ -185,17 +193,55 @@ parse_args() { DRBD_PORT="$2" shift 2 ;; - -h) - usage - exit 0 - ;; *) die "Unknown option: $1 (use -h)" ;; esac done +} + +parse_args() { + if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 + fi + + if [[ $# -eq 0 ]]; then + MODE="install" + elif [[ "$1" == "help" ]]; then + usage + exit 0 + elif [[ "$1" == "upgrade" ]]; then + MODE="upgrade" + shift + if [[ $# -eq 0 ]]; then + : + elif [[ "$1" == "-h" || "$1" == "--help" ]]; then + usage + exit 0 + else + die "upgrade accepts no arguments (got '$1'). See: $0 upgrade -h" + fi + elif [[ "$1" == "install" ]]; then + MODE="install" + shift + _parse_install_options "$@" + else + MODE="install" + _parse_install_options "$@" + fi if [[ "$LIST_DEVICES_ONLY" -eq 1 ]]; then + if [[ "$MODE" == "upgrade" ]]; then + die "upgrade does not support -l (use: $0 -l for device discovery)" + fi + return 0 + fi + + if [[ "$MODE" == "upgrade" ]]; then + if [[ -n "$BACKING_PATH" || -n "$BACKING_PATH_NODE0" || -n "$BACKING_PATH_NODE1" ]]; then + die "upgrade does not use -d/-d0/-d1; use ConfigMap ${ODF_NAMESPACE}/${OUTPUT_CM_NAME} (from default setup). Run: $0 upgrade" + fi return 0 fi @@ -286,12 +332,38 @@ done | sort -u | head -n 1 ' 2>/dev/null | tail -n 1 } +# Validate upgrade ConfigMap and load only DRBD lower-layer by-id mapping. +validate_upgrade_configmap_and_load_disk_ids() { + msg "Validating ConfigMap ${ODF_NAMESPACE}/${OUTPUT_CM_NAME} and loading DISK_BY_ID mapping..." + if ! oc get configmap "${OUTPUT_CM_NAME}" -n "${ODF_NAMESPACE}" &>/dev/null; then + die "ConfigMap ${ODF_NAMESPACE}/${OUTPUT_CM_NAME} not found. Run default setup first: $0 -d " + fi + + DISK_RESOLVED_NODE0=$(oc get configmap "${OUTPUT_CM_NAME}" -n "${ODF_NAMESPACE}" \ + -o jsonpath='{.data.DISK_BY_ID_NODE_0}' | tr -d '\r\n') \ + || die "failed reading DISK_BY_ID_NODE_0 from ConfigMap ${OUTPUT_CM_NAME}" + DISK_RESOLVED_NODE1=$(oc get configmap "${OUTPUT_CM_NAME}" -n "${ODF_NAMESPACE}" \ + -o jsonpath='{.data.DISK_BY_ID_NODE_1}' | tr -d '\r\n') \ + || die "failed reading DISK_BY_ID_NODE_1 from ConfigMap ${OUTPUT_CM_NAME}" + if [[ -z "$DISK_RESOLVED_NODE0" || -z "$DISK_RESOLVED_NODE1" ]]; then + die "ConfigMap ${OUTPUT_CM_NAME}: missing DISK_BY_ID_NODE_0 or DISK_BY_ID_NODE_1" + fi +} + print_config() { echo "" msg "Configuration" local _lw=18 + if [[ "$MODE" == "upgrade" ]]; then + printf ' %-*s %s\n' "$_lw" "Mode:" "upgrade (KMM kmod refresh; preserve DRBD metadata)" + else + printf ' %-*s %s\n' "$_lw" "Mode:" "install (KMM + DRBD resource + success ConfigMap)" + fi printf ' %-*s %s\n' "$_lw" "Nodes:" "$NODE_0 ($NODE_0_IP), $NODE_1 ($NODE_1_IP)" - if [[ -n "$BACKING_PATH" ]]; then + if [[ "$MODE" == "upgrade" ]]; then + printf ' %-*s %s: %s\n' "$_lw" "DRBD disks by id:" "$NODE_0" "$DISK_RESOLVED_NODE0" + printf ' %-*s %s: %s\n' "$_lw" "(from ConfigMap)" "$NODE_1" "$DISK_RESOLVED_NODE1" + elif [[ -n "$BACKING_PATH" ]]; then printf ' %-*s %s (same path on both nodes)\n' "$_lw" "Backing device:" "$BACKING_PATH" else printf ' %-*s %s\n' "$_lw" "Backing devices:" "per-node paths" @@ -303,6 +375,8 @@ print_config() { printf ' %-*s %s\n' "$_lw" "DRBD Resource:" "$DRBD_RESOURCE" printf ' %-*s %s\n' "$_lw" "DRBD Device:" "$DRBD_DEVICE" printf ' %-*s %s\n' "$_lw" "DRBD Port:" "$DRBD_PORT" + printf ' %-*s %s\n' "$_lw" "DRBD_IMAGE:" "$DRBD_IMAGE" + printf ' %-*s %s\n' "$_lw" "DRBD_VERSION:" "$DRBD_VERSION" echo "" } @@ -548,15 +622,13 @@ kmm_image_build_waits() { fi } -# create the KMM Module CR and dockerfile ConfigMap to build and load DRBD kernel modules on the nodes. -create_drbd_module() { - if oc get module drbd-kmod -n openshift-kmm &>/dev/null; then - msg "KMM Module drbd-kmod already exists." - return 0 - fi - - msg "Creating KMM Module drbd-kmod" +# Lowercase DRBD_VERSION with dots/pluses turned into dashes for a distinct in-registry kmod image tag per release. +drbd_kmod_image_tag_version_fragment() { + printf '%s' "$DRBD_VERSION" | tr '[:upper:]' '[:lower:]' | tr '.+' '--' +} +# Build the KMM Dockerfile body (DRBD_VERSION / DRBD_IMAGE substituted). +render_drbd_kmm_dockerfile() { local kmm_dockerfile kmm_dockerfile=$(cat <<'DOCKERFILE_TEMPLATE' ARG DTK_AUTO @@ -586,6 +658,21 @@ DOCKERFILE_TEMPLATE ) kmm_dockerfile="${kmm_dockerfile//__DRBD_VERSION__/${DRBD_VERSION}}" kmm_dockerfile="${kmm_dockerfile//__DRBD_IMAGE__/${DRBD_IMAGE}}" + printf '%s\n' "$kmm_dockerfile" +} + +# Create the KMM Module CR and dockerfile ConfigMap to build and load DRBD kernel modules on the nodes. +create_drbd_module() { + if oc get module drbd-kmod -n openshift-kmm &>/dev/null; then + msg "KMM Module drbd-kmod already exists." + return 0 + fi + + local kmm_dockerfile drbd_tag_frag + kmm_dockerfile=$(render_drbd_kmm_dockerfile) + drbd_tag_frag=$(drbd_kmod_image_tag_version_fragment) + + msg "Creating KMM Module drbd-kmod" oc apply -f - >/dev/null </dev/null <<'MODULE_SPEC' + # Include DRBD version in the image tag so old images are not reused. + oc apply -f - >/dev/null </dev/null + oc delete configmap drbd-kmod-dockerfile -n openshift-kmm --ignore-not-found >/dev/null +} + # check if the DRBD kernel modules are loaded on the node node_has_drbd_kmods() { local node="$1" @@ -644,7 +739,7 @@ wait_for_modules() { return 0 fi - # Success: /proc/modules on each node contains drbd and drbd_transport_tcp lines (see node_has_drbd_kmods). + # Success: /proc/modules on each node contains drbd and drbd_transport_tcp lines msg "Waiting for DRBD kernel modules to load on both nodes (up to 10 min)..." _wait_begin local i @@ -660,6 +755,17 @@ wait_for_modules() { done } +# Validate loaded /sys/module/drbd/version against DRBD_VERSION on both nodes. +validate_drbd_module_version() { + local v0 v1 + v0=$(oc debug -q "node/$NODE_0" -- chroot /host cat /sys/module/drbd/version 2>/dev/null | tr -d '[:space:]' || true) + v1=$(oc debug -q "node/$NODE_1" -- chroot /host cat /sys/module/drbd/version 2>/dev/null | tr -d '[:space:]' || true) + if [[ "$v0" != "$DRBD_VERSION" || "$v1" != "$DRBD_VERSION" ]]; then + die "loaded DRBD kmod version mismatch after module load: expected ${DRBD_VERSION}, got ${NODE_0}='${v0}' ${NODE_1}='${v1}'." + fi + msg "Loaded DRBD kmod version matches target version (${DRBD_VERSION}) on both nodes." +} + # Run drbdadm on a node via podman using the DRBD image; mounts host drbd.conf and drbd.d. drbdctl() { local node="$1" @@ -680,16 +786,20 @@ drbdctl() { # True when the node has a role (Primary/Secondary) for the DRBD resource. drbd_node_has_role() { - local node="$1" status_out - if ! status_out=$(drbdctl "$node" status "${DRBD_RESOURCE}" 2>&1); then - return 1 - fi - echo "$status_out" | grep -qiE 'role:[[:space:]]*(Primary|Secondary)' + local node="$1" role + role=$(drbdctl "$node" role "${DRBD_RESOURCE}" 2>/dev/null || true) + [[ "$role" == "Primary" || "$role" == "Secondary" || "$role" == Primary/* || "$role" == Secondary/* ]] } # True when both nodes show a role (Primary/Secondary) for the DRBD resource. drbd_resource_up_on_both_nodes() { - drbd_node_has_role "$NODE_0" && drbd_node_has_role "$NODE_1" + local node + for node in "$NODE_0" "$NODE_1"; do + if ! drbd_node_has_role "$node"; then + return 1 + fi + done + return 0 } # configure the DRBD resource on both nodes @@ -729,28 +839,51 @@ resource ${DRBD_RESOURCE} { local node res_path res_path="${DRBD_DIR_PATH}/${DRBD_RESOURCE}.res" + + # Write DRBD config files on both hosts before any drbdadm mutate for node in "$NODE_0" "$NODE_1"; do msg "Node ${node}: writing DRBD config files to the host..." if ! oc debug -q "node/$node" -- chroot /host bash -c " -mkdir -p \"$(dirname "${DRBD_CONF_PATH}")\" '${DRBD_DIR_PATH}' /var/lib/drbd -echo '${DRBD_RES_B64}' | base64 -d > '${res_path}' -echo '${DRBD_MAIN_B64}' | base64 -d > '${DRBD_CONF_PATH}' -"; then + mkdir -p \"$(dirname "${DRBD_CONF_PATH}")\" '${DRBD_DIR_PATH}' /var/lib/drbd + echo '${DRBD_RES_B64}' | base64 -d > '${res_path}' + echo '${DRBD_MAIN_B64}' | base64 -d > '${DRBD_CONF_PATH}' + "; then die "failed to write DRBD config on $node" fi + done + # Upgrade: metadata already exists + for node in "$NODE_0" "$NODE_1"; do if drbd_node_has_role "$node"; then - msg "Node ${node}: resource already has a role on this host; running drbdadm adjust..." - if ! drbdctl "$node" adjust "${DRBD_RESOURCE}"; then - die "drbdadm adjust failed on $node" + continue + fi + if [[ "$MODE" == "upgrade" ]]; then + msg "Node ${node}: drbdadm up" + if ! drbdctl "$node" up "${DRBD_RESOURCE}"; then + die "drbdadm up failed on $node" fi else - msg "Node ${node}: creating DRBD metadata then drbdadm up..." + msg "Node ${node}: drbdadm create-md" if ! drbdctl "$node" create-md "${DRBD_RESOURCE}" --force; then die "drbdadm create-md failed on $node" fi + msg "Node ${node}: drbdadm up" if ! drbdctl "$node" up "${DRBD_RESOURCE}"; then - die "drbdadm up failed on $node" + msg "Node ${node}: drbdadm up failed; retrying after drbdadm down..." + drbdctl "$node" down "${DRBD_RESOURCE}" 2>/dev/null || true + if ! drbdctl "$node" up "${DRBD_RESOURCE}"; then + die "drbdadm up failed on $node" + fi + fi + fi + done + + # Running adjust on both nodes reapplies .res to the running resource + for node in "$NODE_0" "$NODE_1"; do + if drbd_node_has_role "$node"; then + msg "Node ${node}: drbdadm adjust" + if ! drbdctl "$node" adjust "${DRBD_RESOURCE}"; then + die "drbdadm adjust failed on $node" fi fi done @@ -821,7 +954,7 @@ create_filesystem_over_drbd() { fstype="" fi if [[ "$fstype" == "xfs" ]]; then - msg "${DRBD_DEVICE} already has XFS; skipping mkfs (re-run safe)." + msg "${DRBD_DEVICE} already has XFS; skipping mkfs." return 0 fi @@ -993,10 +1126,75 @@ EOF done } +# Label on the floating mon Deployment so the Rook operator does not reconcile it while scaled down for DRBD upgrade. +FLOATING_MON_NO_RECONCILE_LABEL_KEY="${FLOATING_MON_NO_RECONCILE_LABEL_KEY:-ceph.rook.io/do-not-reconcile}" +FLOATING_MON_NO_RECONCILE_LABEL_VALUE="${FLOATING_MON_NO_RECONCILE_LABEL_VALUE:-true}" + +# Return deployment name rook-ceph-mon- or empty if not applicable. +floating_mon_deployment_name() { + local name + name=$(oc get cephcluster -n "${ODF_NAMESPACE}" -o jsonpath='{.items[0].spec.mon.floatingMon.name}' 2>/dev/null || true) + if [[ -z "$name" ]]; then + echo "" + return 1 + fi + echo "rook-ceph-mon-${name}" +} + +# Scale the floating mon deployment to the given number of replicas. +# Before scale to 0: set ceph.rook.io/do-not-reconcile=true on the Deployment so Rook does not fight the scale. +# Before scale up (replicas > 0): remove that label, then scale. +scale_floating_mon_deployment() { + local replicas="$1" dep + dep=$(floating_mon_deployment_name || true) + if [[ -z "$dep" ]]; then + msg "No CephCluster floating mon in ${ODF_NAMESPACE}; skipping mon deployment scale." + return 0 + fi + if ! oc get deployment "$dep" -n "${ODF_NAMESPACE}" &>/dev/null; then + msg "Deployment ${ODF_NAMESPACE}/${dep} not found; skipping mon scale." + return 0 + fi + if [[ "${replicas}" -eq 0 ]]; then + msg "Labeling deployment ${ODF_NAMESPACE}/${dep} ${FLOATING_MON_NO_RECONCILE_LABEL_KEY}=${FLOATING_MON_NO_RECONCILE_LABEL_VALUE} (do not reconcile)..." + oc label deployment "$dep" -n "${ODF_NAMESPACE}" \ + "${FLOATING_MON_NO_RECONCILE_LABEL_KEY}=${FLOATING_MON_NO_RECONCILE_LABEL_VALUE}" --overwrite + else + msg "Removing label ${FLOATING_MON_NO_RECONCILE_LABEL_KEY} from deployment ${ODF_NAMESPACE}/${dep}..." + oc label deployment "$dep" -n "${ODF_NAMESPACE}" "${FLOATING_MON_NO_RECONCILE_LABEL_KEY}-" 2>/dev/null || true + fi + msg "Scaling deployment ${ODF_NAMESPACE}/${dep} to ${replicas} replica(s)..." + oc scale deployment "$dep" -n "${ODF_NAMESPACE}" --replicas="${replicas}" +} + +# Delete the DRBD auto-start DaemonSet. +delete_drbd_autostart_daemonset() { + if ! oc get daemonset "${AUTOSTART_DAEMONSET_NAME}" -n "${AUTOSTART_DAEMONSET_NS}" &>/dev/null; then + return 0 + fi + msg "Deleting DaemonSet ${AUTOSTART_DAEMONSET_NS}/${AUTOSTART_DAEMONSET_NAME}..." + oc delete daemonset "${AUTOSTART_DAEMONSET_NAME}" -n "${AUTOSTART_DAEMONSET_NS}" --ignore-not-found >/dev/null +} + +# Demote and down the DRBD resource on both nodes. +drbd_demote_and_down_all() { + local node role + msg "Stopping DRBD resource on both nodes" + for node in "$NODE_0" "$NODE_1"; do + role=$(drbdctl "$node" role "${DRBD_RESOURCE}" 2>/dev/null | cut -d/ -f1 | tr -d '[:space:]' || true) + if [[ "$role" == "Primary" ]]; then + msg "Node ${node}: demoting Primary before drbdadm down..." + drbdctl "$node" secondary "${DRBD_RESOURCE}" || true + fi + msg "Node ${node}: drbdadm down ${DRBD_RESOURCE}..." + drbdctl "$node" down "${DRBD_RESOURCE}" || true + done +} + # create the success ConfigMap to save the setup summary for further consumption. create_success_configmap() { - msg "Saving setup summary to ConfigMap ${OUTPUT_CM_NS}/${OUTPUT_CM_NAME}" - if ! oc create namespace "${OUTPUT_CM_NS}" --dry-run=client -o yaml | oc apply -f - >/dev/null 2>&1; then + msg "Saving setup summary to ConfigMap ${ODF_NAMESPACE}/${OUTPUT_CM_NAME}" + if ! oc create namespace "${ODF_NAMESPACE}" --dry-run=client -o yaml | oc apply -f - >/dev/null 2>&1; then : fi @@ -1014,7 +1212,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: ${OUTPUT_CM_NAME} - namespace: ${OUTPUT_CM_NS} + namespace: ${ODF_NAMESPACE} labels: app.kubernetes.io/name: drbd-setup app.kubernetes.io/component: storage @@ -1040,9 +1238,13 @@ EOF print_success() { echo "" - echo " --> DRBD setup completed successfully <--" + if [[ "$MODE" == "upgrade" ]]; then + echo " --> DRBD upgrade completed successfully <--" + else + echo " --> DRBD install completed successfully <--" + fi echo "" - echo "Post-install DRBD status on ${NODE_0} (repeat with ${NODE_1}):" + echo "Check DRBD status on ${NODE_0} (repeat with ${NODE_1}):" echo " oc debug -q node/${NODE_0} -- chroot /host podman run --rm --privileged \\" echo " -v /dev:/dev -v ${DRBD_CONF_PATH}:${DRBD_CONF_PATH} -v ${DRBD_DIR_PATH}:${DRBD_DIR_PATH} \\" echo " --hostname ${NODE_0} --net host ${DRBD_IMAGE} drbdadm -c ${DRBD_CONF_PATH} status ${DRBD_RESOURCE}" @@ -1059,18 +1261,40 @@ main() { exit 0 fi + if [[ "$MODE" == "upgrade" ]]; then + validate_upgrade_configmap_and_load_disk_ids # upgrade only: validate output ConfigMap presence and load DRBD disk by-id mapping + else + validate_and_resolve_disks # install only: validate paths and resolve to /dev/disk/by-id + fi + print_config # print the configuration - validate_and_resolve_disks # validate the disks and resolve the disk by-id symlink for DRBD config on that node - setup_kmm_operator # setup the KMM operator - setup_image_registry_operator # setup the image registry operator - kmm_image_build_waits # wait for the ServiceAccount builder and the builder dockercfg Secret to be populated - create_drbd_module # create the KMM Module CR and dockerfile ConfigMap to build and load DRBD kernel modules on the nodes - wait_for_modules # wait for the DRBD kernel modules to load on both nodes + setup_kmm_operator # setup the Kernel Module Management operator + setup_image_registry_operator # setup the Image Registry operator + kmm_image_build_waits # wait for builder SA + dockercfg secret + + if [[ "$MODE" == "upgrade" ]]; then + # Add do not reconcile flag + scale_floating_mon_deployment 0 # scale the floating mon deployment down to 0 replicas + msg "Waiting 10s after scaling floating mon (I/O drain)..." + sleep 10 + delete_drbd_autostart_daemonset # delete the DRBD auto-start DaemonSet + drbd_demote_and_down_all # demote and down the DRBD resource on both nodes + delete_drbd_kmm_module_resources # delete the KMM Module and Dockerfile ConfigMap + fi + + create_drbd_module # common path: create KMM Module + Dockerfile ConfigMap + wait_for_modules # wait for DRBD kernel modules to load on both nodes + validate_drbd_module_version # compare /sys/module/drbd/version to DRBD_VERSION configure_drbd # configure the DRBD resource on both nodes sync_drbd # sync the DRBD resource on both nodes create_filesystem_over_drbd # create the filesystem over the DRBD device make_both_node_secondary # make both nodes secondary setup_drbd_autostart # setup the DRBD auto-start DaemonSet to keep the DRBD resource up on both nodes + + if [[ "$MODE" == "upgrade" ]]; then + scale_floating_mon_deployment 1 + fi + create_success_configmap # create the success ConfigMap to save the setup summary for further consumption print_success # print the success message }