PD9waHAKCm5hbWVzcGFjZSBBcHBcTW9kZWxzOwoKdXNlIEFwcFxEb21haW5cSW1wb3J0c1xTdXBwb3J0XE5vcm1hbGlzZTsKdXNlIEFwcFxFdmVudHNcSm9iRXhwaXJlZDsKdXNlIEFwcFxFdmVudHNcSm9iUHVibGlzaGVkOwp1c2UgQXBwXFNlcnZpY2VzXFRyYW5zYWN0aW9uYWxNYWlsZXI7CnVzZSBBcHBcU3VwcG9ydFxIdG1sQ2xlYW5lcjsKdXNlIElsbHVtaW5hdGVcRGF0YWJhc2VcRWxvcXVlbnRcQnVpbGRlcjsKdXNlIElsbHVtaW5hdGVcRGF0YWJhc2VcRWxvcXVlbnRcRmFjdG9yaWVzXEhhc0ZhY3Rvcnk7CnVzZSBJbGx1bWluYXRlXERhdGFiYXNlXEVsb3F1ZW50XE1vZGVsOwp1c2UgSWxsdW1pbmF0ZVxEYXRhYmFzZVxFbG9xdWVudFxSZWxhdGlvbnNcQmVsb25nc1RvOwp1c2UgSWxsdW1pbmF0ZVxEYXRhYmFzZVxFbG9xdWVudFxSZWxhdGlvbnNcQmVsb25nc1RvTWFueTsKdXNlIElsbHVtaW5hdGVcRGF0YWJhc2VcRWxvcXVlbnRcUmVsYXRpb25zXEhhc01hbnk7CnVzZSBJbGx1bWluYXRlXERhdGFiYXNlXEVsb3F1ZW50XFNvZnREZWxldGVzOwp1c2UgSWxsdW1pbmF0ZVxTdXBwb3J0XENhcmJvbjsKdXNlIElsbHVtaW5hdGVcU3VwcG9ydFxGYWNhZGVzXExvZzsKdXNlIElsbHVtaW5hdGVcU3VwcG9ydFxTdHI7CnVzZSBMYXJhdmVsXFNjb3V0XFNlYXJjaGFibGU7CnVzZSBTcGF0aWVcU2x1Z2dhYmxlXEhhc1NsdWc7CnVzZSBTcGF0aWVcU2x1Z2dhYmxlXFNsdWdPcHRpb25zOwoKLyoqCiAqIEBwcm9wZXJ0eSBDYXJib258bnVsbCAkcHVibGlzaGVkX2F0CiAqIEBwcm9wZXJ0eSBDYXJib258bnVsbCAkc291cmNlX3Bvc3RlZF9hdAogKiBAcHJvcGVydHkgQ2FyYm9ufG51bGwgJGV4cGlyZXNfYXQKICogQHByb3BlcnR5IENhcmJvbnxudWxsICRzb3VyY2VfY2xvc2luZ19kYXRlIEVtcGxveWVyLXByb3ZpZGVkIGNsb3NpbmcgZGF0ZSAobnVsbCA9IG5vdCBwcm92aWRlZCBieSBzb3VyY2UpCiAqIEBwcm9wZXJ0eSBDYXJib258bnVsbCAkaGVhbHRoX2NoZWNrZWRfYXQgV2hlbiB0aGUgZXh0ZXJuYWxfYXBwbHlfdXJsIHdhcyBsYXN0IEhFQUQtY2hlY2tlZAogKiBAcHJvcGVydHkgQ2FyYm9ufG51bGwgJGNsb3NlZF9hdAogKiBAcHJvcGVydHkgQ2FyYm9ufG51bGwgJHN1Ym1pdHRlZF9hdAogKiBAcHJvcGVydHkgQ2FyYm9ufG51bGwgJHJldmlld2VkX2F0CiAqIEBwcm9wZXJ0eSBDYXJib258bnVsbCAkYXBwcm92ZWRfYXQKICogQHByb3BlcnR5IENhcmJvbnxudWxsICRnb29nbGVfaW5kZXhlZF9hdAogKgogKiBUaGUgdW5kZXJseWluZyB0YWJsZSBpcyBgam9iX3Bvc3RpbmdzYCByYXRoZXIgdGhhbiBgam9ic2AgdG8gYXZvaWQKICogY29uZmxpY3Rpbmcgd2l0aCBMYXJhdmVsJ3MgYnVpbHQtaW4gYGpvYnNgIHF1ZXVlIHRhYmxlLgogKi8KY2xhc3MgSm9iIGV4dGVuZHMgTW9kZWwKewogICAgdXNlIEhhc0ZhY3Rvcnk7CiAgICB1c2UgSGFzU2x1ZzsKICAgIHVzZSBTZWFyY2hhYmxlOwogICAgdXNlIFNvZnREZWxldGVzOwoKICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIC8vIFRhYmxlICYgc3RhdHVzIGNvbnN0YW50cwogICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKICAgIC8qKgogICAgICogQXZvaWQgY29sbGlzaW9uIHdpdGggTGFyYXZlbCdzIHF1ZXVlIGBqb2JzYCB0YWJsZS4KICAgICAqCiAgICAgKiBAdmFyIHN0cmluZwogICAgICovCiAgICBwcm90ZWN0ZWQgJHRhYmxlID0gJ2pvYl9wb3N0aW5ncyc7CgogICAgcHVibGljIGNvbnN0IFNUQVRVU19EUkFGVCA9ICdkcmFmdCc7CgogICAgcHVibGljIGNvbnN0IFNUQVRVU19TVUJNSVRURUQgPSAnc3VibWl0dGVkJzsKCiAgICBwdWJsaWMgY29uc3QgU1RBVFVTX1VOREVSX1JFVklFVyA9ICd1bmRlcl9yZXZpZXcnOwoKICAgIHB1YmxpYyBjb25zdCBTVEFUVVNfUFVCTElTSEVEID0gJ3B1Ymxpc2hlZCc7CgogICAgcHVibGljIGNvbnN0IFNUQVRVU19FWFBJUkVEID0gJ2V4cGlyZWQnOwoKICAgIHB1YmxpYyBjb25zdCBTVEFUVVNfQ0xPU0VEID0gJ2Nsb3NlZCc7CgogICAgcHVibGljIGNvbnN0IFNUQVRVU19SRUpFQ1RFRCA9ICdyZWplY3RlZCc7CgogICAgcHVibGljIGNvbnN0IFNUQVRVU19TVVNQRU5ERUQgPSAnc3VzcGVuZGVkJzsKCiAgICAvKioKICAgICAqIE1hdGNoZXMgYSAqdHJhaWxpbmcqIHN0YW5kYWxvbmUgam9iL3JlZmVyZW5jZSBjb2RlIHN1Y2ggYXMgdGhlICIgMjk4MDU5IgogICAgICogaW4gIkRlcHV0eSBTZXJ2aWNlIE1hbmFnZXIgMjk4MDU5IiDigJQgc29tZSBzb3VyY2UgZmVlZHMgYXBwZW5kIHRoZWlyCiAgICAgKiBpbnRlcm5hbCB2YWNhbmN5IElEIHN0cmFpZ2h0IG9udG8gdGhlIHRpdGxlLiBHb29nbGUgcmVxdWlyZXMgdGhlIGpvYgogICAgICogdGl0bGUgb25seSwgc28gdGhpcyBpcyBzdHJpcHBlZCBmb3Igc2NoZW1hLm9yZyBvdXRwdXQgKHNlZQogICAgICogc2NoZW1hVGl0bGUoKSkgd2l0aG91dCB0b3VjaGluZyB0aGUgc3RvcmVkIHRpdGxlIHVzZWQgZWxzZXdoZXJlIG9uCiAgICAgKiB0aGUgc2l0ZS4KICAgICAqCiAgICAgKiBEZWxpYmVyYXRlbHkgbmFycm93OiBpdCBvbmx5IG1hdGNoZXMgYSBydW4gb2YgNSsgY29uc2VjdXRpdmUgZGlnaXRzCiAgICAgKiAob3B0aW9uYWxseSBwcmVjZWRlZCBieSBhIGRhc2gvaGFzaC9vcGVuaW5nIGJyYWNrZXQpIGFuY2hvcmVkIHRvIHRoZQogICAgICogdmVyeSBlbmQgb2YgdGhlIHN0cmluZy4gR2VudWluZSB0aXRsZSBzdWZmaXhlcyBwZW9wbGUgYWN0dWFsbHkgdXNlIOKAlAogICAgICogIlN1cHBvcnQgV29ya2VyIEJhbmQgNSIsICJUZWFtIExlYWRlciBYMyIsICJHcmFkZSA3IiDigJQgYXJlIHNob3J0LAogICAgICogb2Z0ZW4gbWl4ZWQgd2l0aCBsZXR0ZXJzLCBhbmQgbmV2ZXIgcmVhY2ggZml2ZSBjb25zZWN1dGl2ZSBkaWdpdHMsIHNvCiAgICAgKiB0aGV5IGFyZSBsZWZ0IHVudG91Y2hlZC4gQSBjb2RlIHRoYXQgbWl4ZXMgbGV0dGVycyBhbmQgZGlnaXRzIChlLmcuCiAgICAgKiAiUkVRMTIzNDUiKSBpcyBkZWxpYmVyYXRlbHkgbGVmdCBvdXQgb2Ygc2NvcGU6IG9ubHkgYSB0cmFpbGluZwogICAgICogYWxsLWRpZ2l0IHJ1biBpcyB1bmFtYmlndW91cyBlbm91Z2ggdG8gc3RyaXAgc2FmZWx5LgogICAgICovCiAgICBwcml2YXRlIGNvbnN0IFRSQUlMSU5HX0pPQl9DT0RFX1BBVFRFUk4gPSAnL1tcc1wt4oCT4oCUIyhdKlxkezUsfVwpP1xzKiQvdSc7CgogICAgLyoqCiAgICAgKiBNYXRjaGVzIGEgKmxlYWRpbmcqIHNjcmFwZXIgZmllbGQgbGFiZWwgc3VjaCBhcyAiVmFjYW5jeVRpdGxlOiAiIG9yCiAgICAgKiAiTG9jYXRpb246ICIgdGhhdCBzb21lIEFUUyBmZWVkcyAoTmV0d29yeCAvIFlNQ0EpIGxlYXZlIGJha2VkIGludG8gYQogICAgICogdmFsdWUuIFVzZWQgc28gYSBzbHVnIGlzIG5ldmVyIGdlbmVyYXRlZCBmcm9tIHRoZSBsYWJlbCDigJQgdGhlCiAgICAgKiAidmFjYW5jeXRpdGxlLXN0b3JlLWFzc2lzdGFudC00IiBVUkxzIHRoaXMgcHJvZHVjZWQgd2VyZSBmaXhlZCBieQogICAgICogMjAyNl8wOV8xOV8wMzAxMDBfcmVnZW5lcmF0ZV92YWNhbmN5dGl0bGVfam9iX3NsdWdzIGFuZCBtdXN0IG5vdAogICAgICogcmVjdXIuIEtlcHQgaW4gc3luYyB3aXRoIHRoYXQgbWlncmF0aW9uJ3MgaW5saW5lIHBhdHRlcm4uCiAgICAgKi8KICAgIHB1YmxpYyBjb25zdCBMQUJFTF9QUkVGSVhfUEFUVEVSTiA9ICcvXlxzKig/OlZhY2FuY3lUaXRsZXxWYWNhbmN5XHMqVGl0bGV8Sm9iXHMqVGl0bGV8VGl0bGV8TG9jYXRpb24pXHMqOlxzKi9pdSc7CgogICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgLy8gTWFzcyBhc3NpZ25tZW50CiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgogICAgLyoqCiAgICAgKiBUaGUgYXR0cmlidXRlcyB0aGF0IGFyZSBtYXNzIGFzc2lnbmFibGUuCiAgICAgKgogICAgICogQHZhciBsaXN0PHN0cmluZz4KICAgICAqLwogICAgcHJvdGVjdGVkICRmaWxsYWJsZSA9IFsKICAgICAgICAnY29tcGFueV9pZCcsCiAgICAgICAgJ3NvdXJjZV9pZCcsCiAgICAgICAgJ2pvYl90eXBlX2lkJywKICAgICAgICAndGl0bGUnLAogICAgICAgICdzbHVnJywKICAgICAgICAnZGVzY3JpcHRpb24nLAogICAgICAgICdkZXNjcmlwdGlvbl9odG1sJywKICAgICAgICAncmVzcG9uc2liaWxpdGllcycsCiAgICAgICAgJ3JlcXVpcmVtZW50cycsCiAgICAgICAgJ3N0YXR1cycsCiAgICAgICAgJ3Zpc2liaWxpdHknLAogICAgICAgICdlbXBsb3ltZW50X3R5cGUnLAogICAgICAgICd3b3JrX2FycmFuZ2VtZW50JywKICAgICAgICAnc2FsYXJ5X21pbicsCiAgICAgICAgJ3NhbGFyeV9tYXgnLAogICAgICAgICdzYWxhcnlfY3VycmVuY3knLAogICAgICAgICdzYWxhcnlfcGVyaW9kJywKICAgICAgICAnc2FsYXJ5X2Rpc3BsYXlfdGV4dCcsCiAgICAgICAgJ2FwcGx5X21ldGhvZCcsCiAgICAgICAgJ2V4dGVybmFsX2FwcGx5X3VybCcsCiAgICAgICAgJ2FwcGx5X2VtYWlsJywKICAgICAgICAnaXNfZmVhdHVyZWQnLAogICAgICAgICdpc19pbXBvcnRlZCcsCiAgICAgICAgJ3Byb3ZlbmFuY2UnLAogICAgICAgICdleHRlcm5hbF9pZCcsCiAgICAgICAgJ3B1Ymxpc2hlZF9hdCcsCiAgICAgICAgJ3NvdXJjZV9wb3N0ZWRfYXQnLAogICAgICAgICdleHBpcmVzX2F0JywKICAgICAgICAvLyBGMDI6IGVtcGxveWVyLXByb3ZpZGVkIGNsb3NpbmcgZGF0ZSAoZGlzdGluY3QgZnJvbSBleHBpcmVzX2F0IHdoaWNoIGlzIGEgc3lzdGVtIHJldGVudGlvbiBkYXRlKQogICAgICAgICdzb3VyY2VfY2xvc2luZ19kYXRlJywKICAgICAgICAvLyBGMDI6IHRpbWVzdGFtcCBvZiBsYXN0IGV4dGVybmFsIFVSTCBoZWFsdGgtY2hlY2sgYnkgam9iczpjaGVjay1oZWFsdGgKICAgICAgICAnaGVhbHRoX2NoZWNrZWRfYXQnLAogICAgICAgICdjbG9zZWRfYXQnLAogICAgICAgICdzdWJtaXR0ZWRfYXQnLAogICAgICAgICdyZXZpZXdlZF9hdCcsCiAgICAgICAgJ3Jldmlld2VkX2J5JywKICAgICAgICAnYXBwcm92ZWRfYXQnLAogICAgICAgICdhcHByb3ZlZF9ieScsCiAgICAgICAgJ2dvb2dsZV9pbmRleGVkX2F0JywKICAgICAgICAnZ29vZ2xlX2luZGV4aW5nX3N0YXR1cycsCiAgICAgICAgJ2dvb2dsZV9pbmRleGluZ19lcnJvcicsCiAgICBdOwoKICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIC8vIENhc3RzCiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgogICAgLyoqCiAgICAgKiBHZXQgdGhlIGF0dHJpYnV0ZXMgdGhhdCBzaG91bGQgYmUgY2FzdC4KICAgICAqCiAgICAgKiBAcmV0dXJuIGFycmF5PHN0cmluZywgc3RyaW5nPgogICAgICovCiAgICBwcm90ZWN0ZWQgZnVuY3Rpb24gY2FzdHMoKTogYXJyYXkKICAgIHsKICAgICAgICByZXR1cm4gWwogICAgICAgICAgICAvLyBzYWxhcnlfbWluIC8gc2FsYXJ5X21heCBhcmUgc3RvcmVkIGFzIGRlY2ltYWwoMTAsMikgcG91bmRzIChub3QgcGVuY2UpLgogICAgICAgICAgICAvLyBVc2luZyAnZGVjaW1hbDoyJyBlbnN1cmVzIHRoZXkgYXJlIHJldHVybmVkIGFzIHN0cmluZ3Mgd2l0aCAyIGQucC4gYnkKICAgICAgICAgICAgLy8gRWxvcXVlbnQsIHByZXZlbnRpbmcgZmxvYXRpbmctcG9pbnQgcm91bmRpbmcgc3VycHJpc2VzIGluIGFyaXRobWV0aWMuCiAgICAgICAgICAgICdzYWxhcnlfbWluJyA9PiAnZGVjaW1hbDoyJywKICAgICAgICAgICAgJ3NhbGFyeV9tYXgnID0+ICdkZWNpbWFsOjInLAogICAgICAgICAgICAncHVibGlzaGVkX2F0JyA9PiAnZGF0ZXRpbWUnLAogICAgICAgICAgICAnc291cmNlX3Bvc3RlZF9hdCcgPT4gJ2RhdGV0aW1lJywKICAgICAgICAgICAgJ2V4cGlyZXNfYXQnID0+ICdkYXRldGltZScsCiAgICAgICAgICAgIC8vIEYwMjogZW1wbG95ZXItcHJvdmlkZWQgY2xvc2luZyBkYXRlOyBudWxsIHdoZW4gc291cmNlIGRpZCBub3Qgc3VwcGx5IG9uZQogICAgICAgICAgICAnc291cmNlX2Nsb3NpbmdfZGF0ZScgPT4gJ2RhdGV0aW1lJywKICAgICAgICAgICAgLy8gRjAyOiBsYXN0IHRpbWUgZXh0ZXJuYWxfYXBwbHlfdXJsIHdhcyB2ZXJpZmllZCBieSBqb2JzOmNoZWNrLWhlYWx0aAogICAgICAgICAgICAnaGVhbHRoX2NoZWNrZWRfYXQnID0+ICdkYXRldGltZScsCiAgICAgICAgICAgICdjbG9zZWRfYXQnID0+ICdkYXRldGltZScsCiAgICAgICAgICAgICdzdWJtaXR0ZWRfYXQnID0+ICdkYXRldGltZScsCiAgICAgICAgICAgICdyZXZpZXdlZF9hdCcgPT4gJ2RhdGV0aW1lJywKICAgICAgICAgICAgJ2FwcHJvdmVkX2F0JyA9PiAnZGF0ZXRpbWUnLAogICAgICAgICAgICAnZ29vZ2xlX2luZGV4ZWRfYXQnID0+ICdkYXRldGltZScsCiAgICAgICAgICAgICdtZXRhJyA9PiAnYXJyYXknLAogICAgICAgICAgICAnaXNfaW1wb3J0ZWQnID0+ICdib29sZWFuJywKICAgICAgICAgICAgJ2lzX2ZlYXR1cmVkJyA9PiAnYm9vbGVhbicsCiAgICAgICAgXTsKICAgIH0KCiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAvLyBTbHVnCiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgogICAgcHVibGljIGZ1bmN0aW9uIGdldFNsdWdPcHRpb25zKCk6IFNsdWdPcHRpb25zCiAgICB7CiAgICAgICAgLy8gU2x1ZyBmcm9tIHRoZSB0aXRsZSB3aXRoIGFueSBsZWFkaW5nIHNjcmFwZXIgbGFiZWwgKCJWYWNhbmN5VGl0bGU6ICIpCiAgICAgICAgLy8gcmVtb3ZlZC4gVGhlIHN0b3JlZCB0aXRsZSBpdHNlbGYgaXMgbGVmdCB1bnRvdWNoZWQgaGVyZSDigJQgY2xlYW5pbmcKICAgICAgICAvLyBpdCBiZWxvbmdzIHRvIHRoZSBpbXBvcnQgcGlwZWxpbmUg4oCUIGJ1dCB0aGUgVVJMIG11c3QgbmV2ZXIgY2FycnkKICAgICAgICAvLyB0aGUgbGFiZWwgYWdhaW4uIEV2ZXJ5dGhpbmcgZWxzZSAodW5pcXVlICItMSIvIi0yIiBzdWZmaXhlcywgbm8KICAgICAgICAvLyByZWdlbmVyYXRpb24gb24gdXBkYXRlKSBpcyB0aGUgcGFja2FnZSBkZWZhdWx0LgogICAgICAgIHJldHVybiBTbHVnT3B0aW9uczo6Y3JlYXRlKCkKICAgICAgICAgICAgLT5nZW5lcmF0ZVNsdWdzRnJvbShmbiAoc2VsZiAkam9iKTogc3RyaW5nID0+IHNlbGY6OnN0cmlwTGFiZWxQcmVmaXgoJGpvYi0+dGl0bGUpKQogICAgICAgICAgICAtPnNhdmVTbHVnc1RvKCdzbHVnJykKICAgICAgICAgICAgLT5kb05vdEdlbmVyYXRlU2x1Z3NPblVwZGF0ZSgpOwogICAgfQoKICAgIC8qKgogICAgICogUmVtb3ZlIGEgbGVhZGluZyAiVmFjYW5jeVRpdGxlOiIgLyAiTG9jYXRpb246IiBzdHlsZSBmaWVsZCBsYWJlbC4KICAgICAqIFJldHVybnMgdGhlIHRyaW1tZWQgb3JpZ2luYWwgd2hlbiBzdHJpcHBpbmcgd291bGQgbGVhdmUgbm90aGluZywKICAgICAqIHNvIGEgdmFsdWUgdGhhdCBpcyAqb25seSogYSBsYWJlbCBzdGlsbCBwcm9kdWNlcyBhIHVzYWJsZSBzdHJpbmcuCiAgICAgKi8KICAgIHB1YmxpYyBzdGF0aWMgZnVuY3Rpb24gc3RyaXBMYWJlbFByZWZpeCg/c3RyaW5nICR2YWx1ZSk6IHN0cmluZwogICAgewogICAgICAgICRvcmlnaW5hbCA9IHRyaW0oKHN0cmluZykgJHZhbHVlKTsKICAgICAgICAkY2xlYW5lZCA9IHRyaW0oKHN0cmluZykgcHJlZ19yZXBsYWNlKHNlbGY6OkxBQkVMX1BSRUZJWF9QQVRURVJOLCAnJywgJG9yaWdpbmFsKSk7CgogICAgICAgIHJldHVybiAkY2xlYW5lZCAhPT0gJycgPyAkY2xlYW5lZCA6ICRvcmlnaW5hbDsKICAgIH0KCiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAvLyBTY291dCBzZWFyY2gKICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiAgICAvKioKICAgICAqIE9ubHkgcHVibGlzaGVkIGpvYnMgZ28gaW50byB0aGUgc2VhcmNoIGluZGV4LgogICAgICovCiAgICBwdWJsaWMgZnVuY3Rpb24gc2hvdWxkQmVTZWFyY2hhYmxlKCk6IGJvb2wKICAgIHsKICAgICAgICByZXR1cm4gJHRoaXMtPnN0YXR1cyA9PT0gc2VsZjo6U1RBVFVTX1BVQkxJU0hFRDsKICAgIH0KCiAgICAvKioKICAgICAqIEZpZWxkcyBleHBvc2VkIHRvIHRoZSBzZWFyY2ggaW5kZXguCiAgICAgKgogICAgICogQHJldHVybiBhcnJheTxzdHJpbmcsIG1peGVkPgogICAgICovCiAgICBwdWJsaWMgZnVuY3Rpb24gdG9TZWFyY2hhYmxlQXJyYXkoKTogYXJyYXkKICAgIHsKICAgICAgICAkdGhpcy0+bG9hZE1pc3NpbmcoWydjb21wYW55JywgJ2xvY2F0aW9ucyddKTsKCiAgICAgICAgcmV0dXJuIFsKICAgICAgICAgICAgJ3RpdGxlJyA9PiAkdGhpcy0+dGl0bGUsCiAgICAgICAgICAgICdkZXNjcmlwdGlvbicgPT4gc3RyaXBfdGFncygkdGhpcy0+ZGVzY3JpcHRpb24gPz8gJycpLAogICAgICAgICAgICAnZW1wbG95bWVudF90eXBlJyA9PiAkdGhpcy0+ZW1wbG95bWVudF90eXBlLAogICAgICAgICAgICAnd29ya19hcnJhbmdlbWVudCcgPT4gJHRoaXMtPndvcmtfYXJyYW5nZW1lbnQsCiAgICAgICAgICAgICdzYWxhcnlfdGV4dCcgPT4gJHRoaXMtPnNhbGFyeV9kaXNwbGF5X3RleHQsCiAgICAgICAgICAgIC8vIFVzZSBkaXNwbGF5X25hbWUgc28gdGhlIGluZGV4IG5ldmVyIGNhcnJpZXMgYSByYXcgIkNhcmVlcnMiIHN1ZmZpeAogICAgICAgICAgICAvLyBvciBhIGJhcmUgZG9tYWluIOKAlCBtYXRjaGluZyB3aGF0IGNhbmRpZGF0ZXMgc2VlIG9uIHRoZSBzaXRlLgogICAgICAgICAgICAnY29tcGFueV9uYW1lJyA9PiAkdGhpcy0+Y29tcGFueT8tPmRpc3BsYXlfbmFtZSA/OiBudWxsLAogICAgICAgICAgICAnY2l0eScgPT4gJHRoaXMtPmxvY2F0aW9ucy0+Zmlyc3QoKT8tPmNpdHksCiAgICAgICAgICAgICdyZWdpb24nID0+ICR0aGlzLT5sb2NhdGlvbnMtPmZpcnN0KCk/LT5yZWdpb24sCiAgICAgICAgXTsKICAgIH0KCiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAvLyBMaWZlY3ljbGUKICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiAgICBwcm90ZWN0ZWQgc3RhdGljIGZ1bmN0aW9uIGJvb3RlZCgpOiB2b2lkCiAgICB7CiAgICAgICAgc3RhdGljOjpjcmVhdGluZyhmdW5jdGlvbiAoc2VsZiAkam9iKTogdm9pZCB7CiAgICAgICAgICAgICRqb2ItPnVsaWQgPz89IChzdHJpbmcpIFN0cjo6dWxpZCgpOwogICAgICAgIH0pOwoKICAgICAgICAvLyBTZWFyY2gtZW5naW5lIGluZGV4aW5nIGV2ZW50cyAoR29vZ2xlIEluZGV4aW5nIEFQSSArIEluZGV4Tm93KS4KICAgICAgICAvLwogICAgICAgIC8vIEpvYlB1Ymxpc2hlZCAvIEpvYkV4cGlyZWQgaW1wbGVtZW50IFNob3VsZERpc3BhdGNoQWZ0ZXJDb21taXQ6IHdoZW4KICAgICAgICAvLyB0aGUgc2F2ZSBydW5zIGluc2lkZSBhIERCOjp0cmFuc2FjdGlvbigpIChpbXBvcnRzLCBtb2RlcmF0aW9uKSB0aGUKICAgICAgICAvLyBsaXN0ZW5lcnMgb25seSBydW4gb25jZSB0aGUgcm93IGlzIGNvbW1pdHRlZC4gVGhlIGxpc3RlbmVycyBhcmUKICAgICAgICAvLyBxdWV1ZWQsIGRlY2xpbmUgdG8gcXVldWUgYXQgYWxsIHdoZW4gbm8gaW5kZXhpbmcgY3JlZGVudGlhbHMgYXJlCiAgICAgICAgLy8gY29uZmlndXJlZCwgYW5kIG5ldmVyIGxldCBhbiBlcnJvciBlc2NhcGUg4oCUIHNvIGEgc2F2ZSBjYW4gbmV2ZXIgYmUKICAgICAgICAvLyBmYWlsZWQgYnkgYW4gaW5kZXhpbmcgcHJvYmxlbS4KICAgICAgICAvLwogICAgICAgIC8vIEltcG9ydFJ1bm5lcjo6Y3JlYXRlSm9iKCkgYXBwbGllcyBTVEFUVVNfUFVCTElTSEVEICpiZWZvcmUqIHRoZQogICAgICAgIC8vIHNpbmdsZSBJTlNFUlQsIHNvIGEgam9iIGJvcm4gcHVibGlzaGVkIGlzIGEgYGNyZWF0ZWRgIGV2ZW50LCBuZXZlcgogICAgICAgIC8vIGFuIGB1cGRhdGVkYCBvbmUg4oCUIGhlbmNlIGJvdGggaG9va3MuCiAgICAgICAgc3RhdGljOjpjcmVhdGVkKGZ1bmN0aW9uIChzZWxmICRqb2IpOiB2b2lkIHsKICAgICAgICAgICAgaWYgKCRqb2ItPnN0YXR1cyA9PT0gc2VsZjo6U1RBVFVTX1BVQkxJU0hFRCkgewogICAgICAgICAgICAgICAgSm9iUHVibGlzaGVkOjpkaXNwYXRjaCgkam9iKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBBIGpvYiBjcmVhdGVkIHN0cmFpZ2h0IGludG8gZXhwaXJlZC9jbG9zZWQgaGFzIG5ldmVyIGhhZCBhCiAgICAgICAgICAgIC8vIHB1YmxpYyBVUkwsIHNvIHRoZXJlIGlzIG5vdGhpbmcgZm9yIGEgc2VhcmNoIGVuZ2luZSB0byBkZWxldGU6CiAgICAgICAgICAgIC8vIG5vIEpvYkV4cGlyZWQgaGVyZSAoaXQgdXNlZCB0byBmaXJlIGFuZCBidXJuIGEgcXVvdGEgdW5pdCkuCiAgICAgICAgfSk7CgogICAgICAgIHN0YXRpYzo6dXBkYXRlZChmdW5jdGlvbiAoc2VsZiAkam9iKTogdm9pZCB7CiAgICAgICAgICAgIC8vIE9ubHkgYSByZWFsIHN0YXR1cyB0cmFuc2l0aW9uIGlzIGludGVyZXN0aW5nLiB3YXNDaGFuZ2VkKCkgaXMKICAgICAgICAgICAgLy8gcG9wdWxhdGVkIGJ5IHN5bmNDaGFuZ2VzKCkgaW1tZWRpYXRlbHkgYmVmb3JlIGB1cGRhdGVkYCBmaXJlcywKICAgICAgICAgICAgLy8gYW5kIGdldE9yaWdpbmFsKCkgc3RpbGwgaG9sZHMgdGhlIHByZS1zYXZlIHZhbHVlIGJlY2F1c2UKICAgICAgICAgICAgLy8gc3luY09yaWdpbmFsKCkgb25seSBydW5zIGFmdGVyIHRoZSBldmVudC4gQSByZS1zYXZlIHdpdGggdGhlCiAgICAgICAgICAgIC8vIHNhbWUgc3RhdHVzIOKAlCBpbmNsdWRpbmcgYSBzZWNvbmQgc2F2ZSBvZiBhIGpvYiBjcmVhdGVkCiAgICAgICAgICAgIC8vIGVhcmxpZXIgaW4gdGhlIHNhbWUgcmVxdWVzdCDigJQgdGhlcmVmb3JlIGRpc3BhdGNoZXMgbm90aGluZywKICAgICAgICAgICAgLy8gd2hpY2ggaXMgd2h5IG5vIGB3YXNSZWNlbnRseUNyZWF0ZWRgIGd1YXJkIGlzIG5lZWRlZCAodGhhdAogICAgICAgICAgICAvLyBndWFyZCBhbHNvIHN3YWxsb3dlZCBhIGdlbnVpbmUgZHJhZnQgLT4gcHVibGlzaGVkIHRyYW5zaXRpb24KICAgICAgICAgICAgLy8gbWFkZSBpbiB0aGUgc2FtZSByZXF1ZXN0IGFzIHRoZSBJTlNFUlQpLgogICAgICAgICAgICBpZiAoISAkam9iLT53YXNDaGFuZ2VkKCdzdGF0dXMnKSkgewogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CgogICAgICAgICAgICAkZnJvbSA9ICRqb2ItPmdldE9yaWdpbmFsKCdzdGF0dXMnKTsKICAgICAgICAgICAgJHRvID0gJGpvYi0+c3RhdHVzOwoKICAgICAgICAgICAgaWYgKCR0byA9PT0gc2VsZjo6U1RBVFVTX1BVQkxJU0hFRCkgewogICAgICAgICAgICAgICAgSm9iUHVibGlzaGVkOjpkaXNwYXRjaCgkam9iKTsKICAgICAgICAgICAgfSBlbHNlaWYgKAogICAgICAgICAgICAgICAgJGZyb20gPT09IHNlbGY6OlNUQVRVU19QVUJMSVNIRUQKICAgICAgICAgICAgICAgICYmIGluX2FycmF5KCR0bywgW3NlbGY6OlNUQVRVU19FWFBJUkVELCBzZWxmOjpTVEFUVVNfQ0xPU0VEXSwgdHJ1ZSkKICAgICAgICAgICAgKSB7CiAgICAgICAgICAgICAgICAvLyBPbmx5IGEgbGlzdGluZyB0aGF0IHdhcyBsaXZlIGhhcyBhIFVSTCBhIHNlYXJjaCBlbmdpbmUKICAgICAgICAgICAgICAgIC8vIG1heSBob2xkOyBkcmFmdC9zdWJtaXR0ZWQgLT4gY2xvc2VkIGhhcyBub3RoaW5nIHRvIGRlbGV0ZS4KICAgICAgICAgICAgICAgIEpvYkV4cGlyZWQ6OmRpc3BhdGNoKCRqb2IpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAcmV0dXJuIGFycmF5PHN0cmluZywgc3RyaW5nPgogICAgICovCiAgICBwdWJsaWMgc3RhdGljIGZ1bmN0aW9uIHN0YXR1c09wdGlvbnMoKTogYXJyYXkKICAgIHsKICAgICAgICByZXR1cm4gWwogICAgICAgICAgICBzZWxmOjpTVEFUVVNfRFJBRlQgPT4gJ0RyYWZ0JywKICAgICAgICAgICAgc2VsZjo6U1RBVFVTX1NVQk1JVFRFRCA9PiAnU3VibWl0dGVkJywKICAgICAgICAgICAgc2VsZjo6U1RBVFVTX1VOREVSX1JFVklFVyA9PiAnVW5kZXIgcmV2aWV3JywKICAgICAgICAgICAgc2VsZjo6U1RBVFVTX1BVQkxJU0hFRCA9PiAnUHVibGlzaGVkJywKICAgICAgICAgICAgc2VsZjo6U1RBVFVTX0VYUElSRUQgPT4gJ0V4cGlyZWQnLAogICAgICAgICAgICBzZWxmOjpTVEFUVVNfQ0xPU0VEID0+ICdDbG9zZWQnLAogICAgICAgICAgICBzZWxmOjpTVEFUVVNfUkVKRUNURUQgPT4gJ1JlamVjdGVkJywKICAgICAgICAgICAgc2VsZjo6U1RBVFVTX1NVU1BFTkRFRCA9PiAnU3VzcGVuZGVkJywKICAgICAgICBdOwogICAgfQoKICAgIC8qKgogICAgICogVGFpbHdpbmQgY2xhc3NlcyBmb3IgYSBzdGF0dXMgYmFkZ2Ugb24gZW1wbG95ZXIgcGFnZXMuCiAgICAgKiBVc2VzIGFycmF5IGxvb2t1cCBpbnN0ZWFkIG9mIG1hdGNoIHRvIGF2b2lkIE9QY2FjaGUgZWRnZSBjYXNlcy4KICAgICAqLwogICAgcHVibGljIHN0YXRpYyBmdW5jdGlvbiBzdGF0dXNCYWRnZUNsYXNzZXMoc3RyaW5nICRzdGF0dXMpOiBzdHJpbmcKICAgIHsKICAgICAgICAkbWFwID0gWwogICAgICAgICAgICBzZWxmOjpTVEFUVVNfU1VCTUlUVEVEID0+ICdiZy15ZWxsb3ctMTAwIHRleHQteWVsbG93LTgwMCcsCiAgICAgICAgICAgIHNlbGY6OlNUQVRVU19VTkRFUl9SRVZJRVcgPT4gJ2JnLWJsdWUtMTAwIHRleHQtYmx1ZS04MDAnLAogICAgICAgICAgICBzZWxmOjpTVEFUVVNfUFVCTElTSEVEID0+ICdiZy1ncmVlbi0xMDAgdGV4dC1ncmVlbi04MDAnLAogICAgICAgICAgICBzZWxmOjpTVEFUVVNfRVhQSVJFRCA9PiAnYmctZ3JheS0xMDAgdGV4dC1ncmF5LTUwMCcsCiAgICAgICAgICAgIHNlbGY6OlNUQVRVU19DTE9TRUQgPT4gJ2JnLWdyYXktMTAwIHRleHQtZ3JheS01MDAnLAogICAgICAgICAgICBzZWxmOjpTVEFUVVNfUkVKRUNURUQgPT4gJ2JnLXJlZC0xMDAgdGV4dC1yZWQtNzAwJywKICAgICAgICAgICAgc2VsZjo6U1RBVFVTX1NVU1BFTkRFRCA9PiAnYmctcmVkLTEwMCB0ZXh0LXJlZC03MDAnLAogICAgICAgIF07CgogICAgICAgIHJldHVybiAkbWFwWyRzdGF0dXNdID8/ICdiZy1ncmF5LTEwMCB0ZXh0LWdyYXktNzAwJzsKICAgIH0KCiAgICAvKioKICAgICAqIEByZXR1cm4gYXJyYXk8c3RyaW5nLCBzdHJpbmc+CiAgICAgKi8KICAgIHB1YmxpYyBzdGF0aWMgZnVuY3Rpb24gZW1wbG95bWVudFR5cGVPcHRpb25zKCk6IGFycmF5CiAgICB7CiAgICAgICAgcmV0dXJuIFsKICAgICAgICAgICAgJ2Z1bGxfdGltZScgPT4gJ0Z1bGwtdGltZScsCiAgICAgICAgICAgICdwYXJ0X3RpbWUnID0+ICdQYXJ0LXRpbWUnLAogICAgICAgICAgICAnY29udHJhY3QnID0+ICdDb250cmFjdCcsCiAgICAgICAgICAgICd0ZW1wb3JhcnknID0+ICdUZW1wb3JhcnknLAogICAgICAgICAgICAndm9sdW50ZWVyJyA9PiAnVm9sdW50ZWVyJywKICAgICAgICAgICAgJ2FwcHJlbnRpY2VzaGlwJyA9PiAnQXBwcmVudGljZXNoaXAnLAogICAgICAgICAgICAnaW50ZXJuc2hpcCcgPT4gJ0ludGVybnNoaXAnLAogICAgICAgIF07CiAgICB9CgogICAgLyoqCiAgICAgKiBAcmV0dXJuIGFycmF5PHN0cmluZywgc3RyaW5nPgogICAgICovCiAgICBwdWJsaWMgc3RhdGljIGZ1bmN0aW9uIHdvcmtBcnJhbmdlbWVudE9wdGlvbnMoKTogYXJyYXkKICAgIHsKICAgICAgICByZXR1cm4gWwogICAgICAgICAgICAnb25fc2l0ZScgPT4gJ09uLXNpdGUnLAogICAgICAgICAgICAnaHlicmlkJyA9PiAnSHlicmlkJywKICAgICAgICAgICAgJ3JlbW90ZScgPT4gJ1JlbW90ZScsCiAgICAgICAgXTsKICAgIH0KCiAgICAvKioKICAgICAqIEFsd2F5cyBzYW5pdGlzZSBzdG9yZWQgSFRNTDogZGVzY3JpcHRpb25zIGNvbWUgZnJvbSBlbXBsb3llcnMgYW5kCiAgICAgKiB0aGlyZC1wYXJ0eSBzaXRlcyBhbmQgYXJlIHJlbmRlcmVkIHVuZXNjYXBlZCBvbiB0aGUgam9iIHBhZ2UuCiAgICAgKi8KICAgIHB1YmxpYyBmdW5jdGlvbiBzZXREZXNjcmlwdGlvbkh0bWxBdHRyaWJ1dGUoP3N0cmluZyAkdmFsdWUpOiB2b2lkCiAgICB7CiAgICAgICAgJHRoaXMtPmF0dHJpYnV0ZXNbJ2Rlc2NyaXB0aW9uX2h0bWwnXSA9IEh0bWxDbGVhbmVyOjpjbGVhbigkdmFsdWUpOwogICAgfQoKICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIC8vIE1vZGVyYXRpb24gd29ya2Zsb3cKICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiAgICBwdWJsaWMgZnVuY3Rpb24gaXNBd2FpdGluZ01vZGVyYXRpb24oKTogYm9vbAogICAgewogICAgICAgIHJldHVybiBpbl9hcnJheSgkdGhpcy0+c3RhdHVzLCBbc2VsZjo6U1RBVFVTX1NVQk1JVFRFRCwgc2VsZjo6U1RBVFVTX1VOREVSX1JFVklFV10sIHRydWUpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiBzdWJtaXRGb3JSZXZpZXcoKTogdm9pZAogICAgewogICAgICAgICR0aGlzLT5mb3JjZUZpbGwoWwogICAgICAgICAgICAnc3RhdHVzJyA9PiBzZWxmOjpTVEFUVVNfU1VCTUlUVEVELAogICAgICAgICAgICAnc3VibWl0dGVkX2F0JyA9PiBub3coKSwKICAgICAgICBdKS0+c2F2ZSgpOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiBhcHByb3ZlKD9Vc2VyICRtb2RlcmF0b3IgPSBudWxsKTogdm9pZAogICAgewogICAgICAgICR3YXNQdWJsaXNoZWQgPSAkdGhpcy0+c3RhdHVzID09PSBzZWxmOjpTVEFUVVNfUFVCTElTSEVEOwoKICAgICAgICAkdGhpcy0+Zm9yY2VGaWxsKFsKICAgICAgICAgICAgJ3N0YXR1cycgPT4gc2VsZjo6U1RBVFVTX1BVQkxJU0hFRCwKICAgICAgICAgICAgJ3Zpc2liaWxpdHknID0+ICdwdWJsaWMnLAogICAgICAgICAgICAncHVibGlzaGVkX2F0JyA9PiAkdGhpcy0+cHVibGlzaGVkX2F0ID8/IG5vdygpLAogICAgICAgICAgICAncmV2aWV3ZWRfYXQnID0+IG5vdygpLAogICAgICAgICAgICAncmV2aWV3ZWRfYnknID0+ICRtb2RlcmF0b3I/LT5pZCwKICAgICAgICBdKS0+c2F2ZSgpOwoKICAgICAgICAvLyBUZWxsIHRoZSBlbXBsb3llciB0aGVpciBqb2IgaXMgbGl2ZS4gT25seSBvbiBhIHJlYWwgdHJhbnNpdGlvbiBpbnRvCiAgICAgICAgLy8gInB1Ymxpc2hlZCIgKHJlLWFwcHJvdmluZyBhbiBhbHJlYWR5LWxpdmUgam9iIG11c3Qgbm90IHJlLW1haWwpLCBhbmQKICAgICAgICAvLyBuZXZlciBmYXRhbDogVHJhbnNhY3Rpb25hbE1haWxlciB3cmFwcyB0aGUgc2VuZCBpbiB0cnkvY2F0Y2gsIGxvZ3MgYQogICAgICAgIC8vIHdhcm5pbmcgb24gZmFpbHVyZSBhbmQgcmVjb3JkcyB0aGUgYXR0ZW1wdCBpbiBlbWFpbF9sb2dzLgogICAgICAgIGlmICghICR3YXNQdWJsaXNoZWQpIHsKICAgICAgICAgICAgVHJhbnNhY3Rpb25hbE1haWxlcjo6am9iQXBwcm92ZWQoJHRoaXMpOwogICAgICAgIH0KICAgIH0KCiAgICBwdWJsaWMgZnVuY3Rpb24gcmVqZWN0KD9Vc2VyICRtb2RlcmF0b3IgPSBudWxsKTogdm9pZAogICAgewogICAgICAgICR0aGlzLT5mb3JjZUZpbGwoWwogICAgICAgICAgICAnc3RhdHVzJyA9PiBzZWxmOjpTVEFUVVNfUkVKRUNURUQsCiAgICAgICAgICAgICdyZXZpZXdlZF9hdCcgPT4gbm93KCksCiAgICAgICAgICAgICdyZXZpZXdlZF9ieScgPT4gJG1vZGVyYXRvcj8tPmlkLAogICAgICAgIF0pLT5zYXZlKCk7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIHN1c3BlbmQoP1VzZXIgJG1vZGVyYXRvciA9IG51bGwpOiB2b2lkCiAgICB7CiAgICAgICAgJHRoaXMtPmZvcmNlRmlsbChbCiAgICAgICAgICAgICdzdGF0dXMnID0+IHNlbGY6OlNUQVRVU19TVVNQRU5ERUQsCiAgICAgICAgICAgICdyZXZpZXdlZF9hdCcgPT4gbm93KCksCiAgICAgICAgICAgICdyZXZpZXdlZF9ieScgPT4gJG1vZGVyYXRvcj8tPmlkLAogICAgICAgIF0pLT5zYXZlKCk7CiAgICB9CgogICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgLy8gUmVsYXRpb25zaGlwcwogICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKICAgIC8qKgogICAgICogQHJldHVybiBCZWxvbmdzVG88Q29tcGFueSwgJHRoaXM+CiAgICAgKi8KICAgIHB1YmxpYyBmdW5jdGlvbiBjb21wYW55KCk6IEJlbG9uZ3NUbwogICAgewogICAgICAgIHJldHVybiAkdGhpcy0+YmVsb25nc1RvKENvbXBhbnk6OmNsYXNzKTsKICAgIH0KCiAgICAvKioKICAgICAqIEByZXR1cm4gQmVsb25nc1RvPFNvdXJjZSwgJHRoaXM+CiAgICAgKi8KICAgIHB1YmxpYyBmdW5jdGlvbiBzb3VyY2UoKTogQmVsb25nc1RvCiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT5iZWxvbmdzVG8oU291cmNlOjpjbGFzcyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAcmV0dXJuIEJlbG9uZ3NUbzxKb2JUeXBlLCAkdGhpcz4KICAgICAqLwogICAgcHVibGljIGZ1bmN0aW9uIGpvYlR5cGUoKTogQmVsb25nc1RvCiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT5iZWxvbmdzVG8oSm9iVHlwZTo6Y2xhc3MpOwogICAgfQoKICAgIC8qKgogICAgICogQHJldHVybiBIYXNNYW55PEpvYkxvY2F0aW9uLCAkdGhpcz4KICAgICAqLwogICAgcHVibGljIGZ1bmN0aW9uIGxvY2F0aW9ucygpOiBIYXNNYW55CiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT5oYXNNYW55KEpvYkxvY2F0aW9uOjpjbGFzcyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAcmV0dXJuIEhhc01hbnk8Sm9iUmV2aXNpb24sICR0aGlzPgogICAgICovCiAgICBwdWJsaWMgZnVuY3Rpb24gcmV2aXNpb25zKCk6IEhhc01hbnkKICAgIHsKICAgICAgICByZXR1cm4gJHRoaXMtPmhhc01hbnkoSm9iUmV2aXNpb246OmNsYXNzKTsKICAgIH0KCiAgICAvKioKICAgICAqIFNsdWdzIHRoaXMgam9iIHVzZWQgdG8gYmUgcmVhY2hhYmxlIGF0IChzZWUgSm9iQ29udHJvbGxlcjo6c2hvdygpKS4KICAgICAqCiAgICAgKiBAcmV0dXJuIEhhc01hbnk8Sm9iU2x1Z1JlZGlyZWN0LCAkdGhpcz4KICAgICAqLwogICAgcHVibGljIGZ1bmN0aW9uIHNsdWdSZWRpcmVjdHMoKTogSGFzTWFueQogICAgewogICAgICAgIHJldHVybiAkdGhpcy0+aGFzTWFueShKb2JTbHVnUmVkaXJlY3Q6OmNsYXNzKTsKICAgIH0KCiAgICAvKioKICAgICAqIEByZXR1cm4gQmVsb25nc1RvTWFueTxDYXRlZ29yeSwgJHRoaXM+CiAgICAgKi8KICAgIHB1YmxpYyBmdW5jdGlvbiBjYXRlZ29yaWVzKCk6IEJlbG9uZ3NUb01hbnkKICAgIHsKICAgICAgICByZXR1cm4gJHRoaXMtPmJlbG9uZ3NUb01hbnkoQ2F0ZWdvcnk6OmNsYXNzLCAnY2F0ZWdvcnlfam9iJyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAcmV0dXJuIEJlbG9uZ3NUb01hbnk8VGFnLCAkdGhpcz4KICAgICAqLwogICAgcHVibGljIGZ1bmN0aW9uIHRhZ3MoKTogQmVsb25nc1RvTWFueQogICAgewogICAgICAgIHJldHVybiAkdGhpcy0+YmVsb25nc1RvTWFueShUYWc6OmNsYXNzLCAnam9iX3RhZycpOwogICAgfQoKICAgIC8qKgogICAgICogQHJldHVybiBIYXNNYW55PEFwcGxpY2F0aW9uLCAkdGhpcz4KICAgICAqLwogICAgcHVibGljIGZ1bmN0aW9uIGFwcGxpY2F0aW9ucygpOiBIYXNNYW55CiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT5oYXNNYW55KEFwcGxpY2F0aW9uOjpjbGFzcyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAcmV0dXJuIEhhc01hbnk8U2F2ZWRKb2IsICR0aGlzPgogICAgICovCiAgICBwdWJsaWMgZnVuY3Rpb24gc2F2ZWRKb2JzKCk6IEhhc01hbnkKICAgIHsKICAgICAgICByZXR1cm4gJHRoaXMtPmhhc01hbnkoU2F2ZWRKb2I6OmNsYXNzKTsKICAgIH0KCiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAvLyBTdHJ1Y3R1cmVkIGRhdGEKICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiAgICAvKioKICAgICAqIFRoZSBqb2IgdGl0bGUgYXMgaXQgc2hvdWxkIGFwcGVhciBpbiBKb2JQb3N0aW5nIEpTT04tTEQ6IEdvb2dsZQogICAgICogcmVxdWlyZXMgdGhlIHRpdGxlIG9ubHksIHdpdGggbm8gY29kZXMsIGRhdGVzLCBsb2NhdGlvbnMgb3Igc2FsYXJpZXMuCiAgICAgKiBTdHJpcHMgYSB0cmFpbGluZyBzdGFuZGFsb25lIGpvYi9yZWZlcmVuY2UgY29kZSDigJQgc2VlCiAgICAgKiBUUkFJTElOR19KT0JfQ09ERV9QQVRURVJOIOKAlCB3aXRob3V0IHRvdWNoaW5nIHRoZSBzdG9yZWQgJHRpdGxlIHVzZWQKICAgICAqIGZvciB0aGUgcGFnZSBoZWFkaW5nLCBzbHVnLCBicmVhZGNydW1icywgZXRjLgogICAgICovCiAgICBwcml2YXRlIGZ1bmN0aW9uIHNjaGVtYVRpdGxlKCk6IHN0cmluZwogICAgewogICAgICAgICRjbGVhbmVkID0gdHJpbSgoc3RyaW5nKSBwcmVnX3JlcGxhY2Uoc2VsZjo6VFJBSUxJTkdfSk9CX0NPREVfUEFUVEVSTiwgJycsIChzdHJpbmcpICR0aGlzLT50aXRsZSkpOwoKICAgICAgICByZXR1cm4gJGNsZWFuZWQgIT09ICcnID8gJGNsZWFuZWQgOiAkdGhpcy0+dGl0bGU7CiAgICB9CgogICAgLyoqCiAgICAgKiBzY2hlbWEub3JnIEpvYlBvc3RpbmcgZGF0YSBmb3IgR29vZ2xlIGZvciBKb2JzLgogICAgICoKICAgICAqIEByZXR1cm4gYXJyYXk8c3RyaW5nLCBtaXhlZD4KICAgICAqLwogICAgcHVibGljIGZ1bmN0aW9uIGpvYlBvc3RpbmdTY2hlbWEoKTogYXJyYXkKICAgIHsKICAgICAgICAkdGhpcy0+bG9hZE1pc3NpbmcoWydjb21wYW55JywgJ2xvY2F0aW9ucycsICdqb2JUeXBlJ10pOwoKICAgICAgICAvLyBQcmVmZXIgdGhlIGxpbmtlZCBKb2JUeXBlJ3MgZ29vZ2xlX3NjaGVtYV92YWx1ZTsgZmFsbCBiYWNrIHRvIHRoZQogICAgICAgIC8vIGxlZ2FjeSBlbXBsb3ltZW50X3R5cGUgZW51bSBtYXBwZWQgaW5saW5lOyBhbmQgaWYgbmVpdGhlciBpcyBzZXQKICAgICAgICAvLyDigJQgY29tbW9uIGZvciBpbXBvcnRlZCBqb2JzIHdob3NlIHNvdXJjZSBBVFMgbmV2ZXIgcG9wdWxhdGVzIGEKICAgICAgICAvLyBkZWRpY2F0ZWQgZW1wbG95bWVudC10eXBlIGZpZWxkIOKAlCBmYWxsIGJhY2sgdG8gYSBjbGVhcmx5IGxhYmVsbGVkCiAgICAgICAgLy8gbGluZSBpbiB0aGUgZGVzY3JpcHRpb24gKGUuZy4gIkNvbnRyYWN0OiBQZXJtYW5lbnQsIEZ1bGwtVGltZSIpLgogICAgICAgIC8vIFNlZSBOb3JtYWxpc2U6OmVtcGxveW1lbnRUeXBlRnJvbUxhYmVsbGVkVGV4dCgpOiBpdCBvbmx5IGV2ZXIKICAgICAgICAvLyBtYXRjaGVzIGFuIGV4cGxpY2l0IGxhYmVsLCBuZXZlciBhbiB1bmxhYmVsbGVkIGd1ZXNzLCBzbyBhIGpvYgogICAgICAgIC8vIHdpdGggbm8gcmVhbCBzaWduYWwgc3RpbGwgb21pdHMgZW1wbG95bWVudFR5cGUgcmF0aGVyIHRoYW4KICAgICAgICAvLyBlbWl0dGluZyBhIHdyb25nIG9uZS4KICAgICAgICAkZW1wbG95bWVudFR5cGVNYXAgPSBbCiAgICAgICAgICAgICdmdWxsX3RpbWUnID0+ICdGVUxMX1RJTUUnLAogICAgICAgICAgICAncGFydF90aW1lJyA9PiAnUEFSVF9USU1FJywKICAgICAgICAgICAgJ2NvbnRyYWN0JyA9PiAnQ09OVFJBQ1RPUicsCiAgICAgICAgICAgICd0ZW1wb3JhcnknID0+ICdURU1QT1JBUlknLAogICAgICAgICAgICAndm9sdW50ZWVyJyA9PiAnVk9MVU5URUVSJywKICAgICAgICAgICAgJ2ludGVybnNoaXAnID0+ICdJTlRFUk4nLAogICAgICAgICAgICAnYXBwcmVudGljZXNoaXAnID0+ICdPVEhFUicsCiAgICAgICAgXTsKCiAgICAgICAgJHJhd0VtcGxveW1lbnRUeXBlID0gJHRoaXMtPmVtcGxveW1lbnRfdHlwZQogICAgICAgICAgICA/PyBOb3JtYWxpc2U6OmVtcGxveW1lbnRUeXBlRnJvbUxhYmVsbGVkVGV4dCgkdGhpcy0+ZGVzY3JpcHRpb25faHRtbCA/OiAkdGhpcy0+ZGVzY3JpcHRpb24pOwoKICAgICAgICAkc2NoZW1hRW1wbG95bWVudFR5cGUgPSAkdGhpcy0+am9iVHlwZT8tPmdvb2dsZV9zY2hlbWFfdmFsdWUgPz8gJGVtcGxveW1lbnRUeXBlTWFwWyRyYXdFbXBsb3ltZW50VHlwZV0gPz8gbnVsbDsKCiAgICAgICAgLy8gTWFwIHNhbGFyeV9wZXJpb2Qgc2x1Z3MgdG8gc2NoZW1hLm9yZyB1bml0VGV4dCB2YWx1ZXMuCiAgICAgICAgJHNhbGFyeVBlcmlvZE1hcCA9IFsKICAgICAgICAgICAgJ2hvdXJseScgPT4gJ0hPVVInLAogICAgICAgICAgICAnZGFpbHknID0+ICdEQVknLAogICAgICAgICAgICAnd2Vla2x5JyA9PiAnV0VFSycsCiAgICAgICAgICAgICdtb250aGx5JyA9PiAnTU9OVEgnLAogICAgICAgICAgICAnYW5udWFsJyA9PiAnWUVBUicsCiAgICAgICAgICAgICdwcm9fcmF0YScgPT4gJ1lFQVInLAogICAgICAgIF07CgogICAgICAgIC8vIFVzZSB0aGUgb3JpZ2luYWwgc291cmNlIHBvc3RpbmcgZGF0ZSBmb3Igc2NoZW1hLm9yZyBkYXRlUG9zdGVkIHdoZW4gYXZhaWxhYmxlLgogICAgICAgIC8vIEZhbGxzIGJhY2sgdG8gcHVibGlzaGVkX2F0LCB0aGVuIGNyZWF0ZWRfYXQgdG8gZW5zdXJlIGRhdGVQb3N0ZWQgaXMgbmV2ZXIgbnVsbC4KICAgICAgICAkZGF0ZVBvc3RlZCA9ICR0aGlzLT5zb3VyY2VfcG9zdGVkX2F0ID8/ICR0aGlzLT5wdWJsaXNoZWRfYXQgPz8gJHRoaXMtPmNyZWF0ZWRfYXQ7CgogICAgICAgIC8vIFVzZSBkaXNwbGF5X25hbWUgc28gdGhlIHN0cnVjdHVyZWQgZGF0YSBtYXRjaGVzIHdoYXQgY2FuZGlkYXRlcyBzZWU6CiAgICAgICAgLy8gdHJhaWxpbmcgIiBDYXJlZXJzIC8gSm9icyAvIFZhY2FuY2llcyAvIFJlY3J1aXRtZW50IiBzdWZmaXhlcyBhcmUgc3RyaXBwZWQsCiAgICAgICAgLy8gYmFyZS1kb21haW4gYW5kIGFnZ3JlZ2F0b3IgY29tcGFueSBuYW1lcyBiZWNvbWUgJycgKHRyZWF0ZWQgYXMgbnVsbCBiZWxvdykuCiAgICAgICAgLy8gVGhlIGRvbWFpbi1saWtlIGNoZWNrIGlzIGEgc2FmZXR5IG5ldCBmb3IgYW55IGVkZ2UtY2FzZXMgdGhlIGFjY2Vzc29yIG1pc3Nlcy4KICAgICAgICAkcmF3Q29tcGFueU5hbWUgPSAkdGhpcy0+Y29tcGFueT8tPmRpc3BsYXlfbmFtZSA/OiBudWxsOwogICAgICAgICRpc0RvbWFpbkxpa2UgPSAkcmF3Q29tcGFueU5hbWUKICAgICAgICAgICAgJiYgISBzdHJfY29udGFpbnMoJHJhd0NvbXBhbnlOYW1lLCAnICcpCiAgICAgICAgICAgICYmIChib29sKSBwcmVnX21hdGNoKCcvXC5bYS16XXsyLH0vaScwICRyYXdDb21wYW55TmFtZSk7CiAgICAgICAgJHNjaGVtYUNvbXBhbnlOYW1lID0gJGlzRG9tYWluTGlrZSA/IG51bGwgOiAkcmF3Q29tcGFueU5hbWU7CgogICAgICAgICRzY2hlbWEgPSBbCiAgICAgICAgICAgICdAY29udGV4dCcgPT4gJ2h0dHBzOi8vc2NoZW1hLm9yZy8nLAogICAgICAgICAgICAnQHR5cGUnID0+ICdKb2JQb3N0aW5nJywKICAgICAgICAgICAgJ3RpdGxlJyA9PiAkdGhpcy0+c2NoZW1hVGl0bGUoKSwKICAgICAgICAgICAgJ2Rlc2NyaXB0aW9uJyA9PiAkdGhpcy0+ZGVzY3JpcHRpb25faHRtbCA/OiBubDJicihleygkdGhpcy0+ZGVzY3JpcHRpb24gPz8gJycpKSwKICAgICAgICAgICAgJ2lkZW50aWZpZXInID0+IFsKICAgICAgICAgICAgICAgICdAdHlwZScgPT4gJ1Byb3BlcnR5VmFsdWUnLAogICAgICAgICAgICAgICAgJ25hbWUnID0+ICdISEonLAogICAgICAgICAgICAgICAgJ3ZhbHVlJyA9PiAoc3RyaW5nKSAkdGhpcy0+aWQsCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICdkYXRlUG9zdGVkJyA9PiAkZGF0ZVBvc3RlZD8tPnRvSXNvODYwMVN0cmluZygpLAogICAgICAgICAgICAvLyBGMDI6IFVzZSB0aGUgZW1wbG95ZXItcHJvdmlkZWQgY2xvc2luZyBkYXRlIChzb3VyY2VfY2xvc2luZ19kYXRlKSBmb3IKICAgICAgICAgICAgLy8gdmFsaWRUaHJvdWdoIHdoZW4gYXZhaWxhYmxlIOKAlCB0aGlzIGlzIHRoZSBhY3R1YWwgYXBwbGljYXRpb24gZGVhZGxpbmUuCiAgICAgICAgICAgIC8vIEZhbGxzIGJhY2sgdG8gZXhwaXJlc19hdCAodGhlIHN5c3RlbSByZXRlbnRpb24vZXhwaXJ5IGRhdGUpIHNvIEdvb2dsZQogICAgICAgICAgICAvLyBhbHdheXMgcmVjZWl2ZXMgYSB2YWxpZFRocm91Z2ggc2lnbmFsIHdoZW4gYW55IGVuZCBkYXRlIGV4aXN0cy4KICAgICAgICAgICAgLy8gV2hlbiBib3RoIGFyZSBudWxsIHdlIG9taXQgdmFsaWRUaHJvdWdoIGVudGlyZWx5IHZpYSBhcnJheV9maWx0ZXIgYmVsb3cuCiAgICAgICAgICAgICd2YWxpZFRocm91Z2gnID0+ICgkdGhpcy0+c291cmNlX2Nsb3NpbmdfZGF0ZSA/PyAkdGhpcy0+ZXhwaXJlc19hdCk/LT50b0lzbzg2MDFTdHJpbmcoKSwKICAgICAgICAgICAgJ2VtcGxveW1lbnRUeXBlJyA9PiAkc2NoZW1hRW1wbG95bWVudFR5cGUsCiAgICAgICAgICAgICdkaXJlY3RBcHBseScgPT4gJHRoaXMtPmFwcGx5X21ldGhvZCA9PT0gJ3BsYXRmb3JtJywKICAgICAgICAgICAgJ2hpcmluZ09yZ2FuaXphdGlvbicgPT4gJHNjaGVtYUNvbXBhbnlOYW1lID8gYXJyYXlfZmlsdGVyKFsKICAgICAgICAgICAgICAgICdAdHlwZScgPT4gJ09yZ2FuaXphdGlvbicsCiAgICAgICAgICAgICAgICAnbmFtZScgPT4gJHNjaGVtYUNvbXBhbnlOYW1lLAogICAgICAgICAgICAgICAgJ3VybCcgPT4gJHRoaXMtPmNvbXBhbnk/LT53ZWJzaXRlID86IG51bGwsCiAgICAgICAgICAgICAgICAnbG9nbycgPT4gJHRoaXMtPmNvbXBhbnk/LT5sb2dvX3VybCA/OiBudWxsLAogICAgICAgICAgICAgICAgJ3NhbWVBcycgPT4gJHRoaXMtPmNvbXBhbnk/LT53ZWJzaXRlID86IG51bGwsCiAgICAgICAgICAgIF0pIDogWydAdHlwZScgPT4gJ09yZ2FuaXphdGlvbicsICduYW1lJyA9PiAnVW5rbm93biBFbXBsb3llciddLAogICAgICAgIF07CgogICAgICAgICRsb2NhdGlvbiA9ICR0aGlzLT5sb2NhdGlvbnMtPmZpcnN0KCk7CgogICAgICAgIC8vIE9ubHkgZW1pdCBqb2JMb2NhdGlvblR5cGU9VEVMRUNPTU1VVEUgZm9yIGV4Y2x1c2l2ZWx5IHJlbW90ZSBqb2JzLgogICAgICAgIC8vIEdvb2dsZSdzIGRlZmluaXRpb24gcmVxdWlyZXMgdGhhdCBOTyBwaHlzaWNhbCBhdHRlbmRhbmNlIGlzIG5lZWRlZC4KICAgICAgICAvLyBBIGpvYiBpcyBleGNsdXNpdmVseSByZW1vdGUgb25seSB3aGVuIHdvcmtfYXJyYW5nZW1lbnQgaXMgJ3JlbW90ZScKICAgICAgICAvLyBBTkQgaXQgaGFzIG5vIGFzc29jaWF0ZWQgcGh5c2ljYWwgbG9jYXRpb24gcmVjb3JkLiAgQSBqb2IgdGhhdAogICAgICAgIC8vIGNhcnJpZXMgYW55IFBsYWNlIChldmVuIG9uZSB0aGF0IGFsc28gb2ZmZXJzIFdGSCBmbGV4aWJpbGl0eSwgb3Igb25lCiAgICAgICAgLy8gd2hvc2Ugd29ya19hcnJhbmdlbWVudCB3YXMgaW5jb3JyZWN0bHkgc2NyYXBlZCBhcyAncmVtb3RlJykgZG9lcyBOT1QKICAgICAgICAvLyBxdWFsaWZ5IOKAlCBlbWl0dGluZyBURUxFQ09NTVVURSB0byBpdCB3b3VsZCB0cmlnZ2VyIGEgR29vZ2xlIFJpY2gKICAgICAgICAvLyBSZXN1bHRzIHZhbGlkYXRpb24gZXJyb3IuICBIeWJyaWQgam9icyAoJ2h5YnJpZCcpIG5ldmVyIHF1YWxpZnkKICAgICAgICAvLyByZWdhcmRsZXNzIG9mIHdoZXRoZXIgYSBsb2NhdGlvbiByZWNvcmQgZXhpc3RzLgogICAgICAgICRpc0V4Y2x1c2l2ZWx5UmVtb3RlID0gJHRoaXMtPndvcmtfYXJyYW5nZW1lbnQgPT09ICdyZW1vdGUnCiAgICAgICAgICAgICYmICR0aGlzLT5sb2NhdGlvbnMtPmlzRW1wdHkoKTsKCiAgICAgICAgaWYgKCRpc0V4Y2x1c2l2ZWx5UmVtb3RlKSB7CiAgICAgICAgICAgICRzY2hlbWFbJ2pvYkxvY2F0aW9uVHlwZSddID0gJ1RFTEVDT01NVVRFJzsKICAgICAgICAgICAgJHNjaGVtYVsnYXBwbGljYW50TG9jYXRpb25SZXF1aXJlbWVudHMnXSA9IFsnQHR5cGUnID0+ICdDb3VudHJ5JywgJ25hbWUnID0+ICdHQiddOwogICAgICAgIH0KCiAgICAgICAgaWYgKCRsb2NhdGlvbikgewogICAgICAgICAgICAvLyBTb21lIHNvdXJjZSBBVFNzIHB1dCB0aGUgY291bnRyeSBuYW1lIGluIGNpdHkvcmVnaW9uLCBvcgogICAgICAgICAgICAvLyByZXBlYXQgdGhlIHRvd24gaW4gYm90aCAoZS5nLiAiVW5pdGVkIEtpbmdkb20iIGluIGJvdGggZmllbGRzLAogICAgICAgICAgICAvLyBvciAiU291dGhlbmQtb24tU2VhIiBhcyBib3RoIGxvY2FsaXR5IGFuZCByZWdpb24pLiBDbGVhbiB0aGUKICAgICAgICAgICAgLy8gcGFpciBhcyBhIHNlY29uZCBsaW5lIG9mIGRlZmVuY2Ug4oCUIHRoaXMgaXMgdXAgb24gdG9wIG9mIHRoZSBpbXBvcnQtCiAgICAgICAgICAgIC8vIHRpbWUgY2xlYW5pbmcgaW4gSW1wb3J0UnVubmVyOjpzeW5jTG9jYXRpb24oKSDigJQgc28gcm93cyB3cml0dGVuCiAgICAgICAgICAgIC8vIGJlZm9yZSB0aGF0IGZpeCAob3IgZW50ZXJlZCBieSBoYW5kKSBuZXZlciBzdXJmYWNlIGEgd3JvbmcKICAgICAgICAgICAgLy8gcGxhY2UgbmFtZSB0byBHb29nbGUuIEFuIG9taXR0ZWQgcHJvcGVydHkgaXMgZmFyIGJldHRlciB0aGFuCiAgICAgICAgICAgIC8vIGEgd3Jvbmcgb25lLgogICAgICAgICAgICAvLyBOb3JtYWxpc2U6OnBsYWNlUGFpcigpIGFsc28gc3RyaXBzIHBsYWNlaG9sZGVyIHZhbHVlcyAoIk90aGVyIiwKICAgICAgICAgICAgLy8gIlZhcmlvdXMiLCBldGMuKSBhbmQgaW50ZXJuYWwgb2ZmaWNlIGxhYmVscy4gT25seSBlbWl0CiAgICAgICAgICAgIC8vIGpvYkxvY2F0aW9uIHdoZW4gdGhlcmUgaXMgYXQgbGVhc3Qgb25lIHVzYWJsZSBhZGRyZXNzIGNvbXBvbmVudDsKICAgICAgICAgICAgLy8gYSBibG9jayBjb250YWluaW5nIG9ubHkgYWRkcmVzc0NvdW50cnk6IEdCIGdpdmVzIEdvb2dsZSBubwogICAgICAgICAgICAvLyBnZW9jb2RhYmxlIHNpZ25hbCBhbmQgd2FzdGVzIGEgc3RydWN0dXJlZC1kYXRhIHNsb3QuCiAgICAgICAgICAgIFskbG9jYWxpdHksICRyZWdpb25dID0gTm9ybWFsaXNlOjpwbGFjZVBhaXIoJGxvY2F0aW9uLT5jaXR5LCAkbG9jYXRpb24tPnJlZ2lvbik7CgogICAgICAgICAgICBpZiAoJGxvY2FsaXR5IHx8ICRyZWdpb24gfHwgJGxvY2F0aW9uLT5wb3N0Y29kZSB8fCAkbG9jYXRpb24tPnN0cmVldF9hZGRyZXNzKSB7CiAgICAgICAgICAgICAgICAkc2NoZW1hWydqb2JMb2NhdGlvbiddID0gWwogICAgICAgICAgICAgICAgICAgICdAdHlwZScgPT4gJ1BsYWNlJywKICAgICAgICAgICAgICAgICAgICAnYWRkcmVzcycgPT4gYXJyYXlfZmlsdGVyKFsKICAgICAgICAgICAgICAgICAgICAgICAgJ0B0eXBlJyA9PiAnUG9zdGFsQWRkcmVzcycsCiAgICAgICAgICAgICAgICAgICAgICAgICdzdHJlZXRBZGRyZXNzJyA9PiAkbG9jYXRpb24tPnN0cmVldF9hZGRyZXNzLAogICAgICAgICAgICAgICAgICAgICAgICAnYWRkcmVzc0xvY2FsaXR5JyA9PiAkbG9jYWxpdHksCiAgICAgICAgICAgICAgICAgICAgICAgICdhZGRyZXNzUmVnaW9uJyA9PiAkcmVnaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAncG9zdGFsQ29kZScgPT4gJGxvY2F0aW9uLT5wb3N0Y29kZSwKICAgICAgICAgICAgICAgICAgICAgICAgJ2FkZHJlc3NDb3VudHJ5JyA9PiAkbG9jYXRpb24tPmNvdW50cnlfY29kZSA/OiAnR0InLAogICAgICAgICAgICAgICAgICAgIF0pLAogICAgICAgICAgICAgICAgXTsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy8gc2FsYXJ5X21pbiAvIHNhbGFyeV9tYXggYXJlIHN0b3JlZCBhcyBkZWNpbWFsIHBvdW5kcyAoZS5nLiAxMy41MCwgMTQuMDApLgogICAgICAgIC8vIENhc3QgdG8gZmxvYXQgZm9yIHNjaGVtYS5vcmcgb3V0cHV0IHNvIEdvb2dsZSBzZWVzIHRoZSBjb3JyZWN0IG1vbmV0YXJ5IHZhbHVlLgogICAgICAgICRzYWxhcnlNaW4gPSAkdGhpcy0+c2FsYXJ5X21pbiAhPT0gbnVsbCA/IChmbG9hdCkgJHRoaXMtPnNhbGFyeV9taW4gOiBudWxsOwogICAgICAgICRzYWxhcnlNYXggPSAkdGhpcy0+c2FsYXJ5X21heCAhPT0gbnVsbCA/IChmbG9hdCkgJHRoaXMtPnNhbGFyeV9tYXggOiBudWxsOwoKICAgICAgICBpZiAoJHNhbGFyeU1pbiB8fCAkc2FsYXJ5TWF4KSB7CiAgICAgICAgICAgICR1bml0VGV4dCA9ICRzYWxhcnlQZXJpb2RNYXBbJHRoaXMtPnNhbGFyeV9wZXJpb2RdID8/ICdZRUFSJzsKCiAgICAgICAgICAgIC8vIOKUgOKUgCBPdXRwdXQtc2lkZSBtYWduaXR1ZGUgZ3VhcmQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA // For jobs imported before the input-side fix (StructuredData::salary()), // guard against stored salary_period values that are inconsistent with // the numeric amounts. Prevents incorrect baseSalary schema being emitted // to Google Rich Results for already-stored jobs. $guardValue = (float) ($salaryMin ?? $salaryMax ?? 0); if ($unitText === 'HOUR' && $guardValue > 200) { $unitText = 'YEAR'; try { Log::warning('Job schema: salary unitText corrected on output', [ 'job_id' => $this->id, 'stored_period' => $this->salary_period, 'salary_min' => $salaryMin, 'corrected_unit' => $unitText, ]); } catch (\Throwable) { // Silently skip if Log unavailable. } } elseif ($unitText === 'DAY' && $guardValue > 2_000) { $unitText = 'YEAR'; } elseif ($unitText === 'YEAR' && $guardValue > 0 && $guardValue < 100) { $unitText = 'HOUR'; } // ────────────────────────────────────────────────────────────────────── $schema['baseSalary'] = [ '@type' => 'MonetaryAmount', 'currency' => $this->salary_currency ?: 'GBP', 'value' => array_filter([ '@type' => 'QuantitativeValue', 'minValue' => $salaryMin, 'maxValue' => $salaryMax, 'unitText' => $unitText, ], fn ($v) => $v !== null), ]; } return array_filter($schema, fn ($v) => $v !== null); } // ------------------------------------------------------------------------- // Scopes // ------------------------------------------------------------------------- public function scopePublished(Builder $query): Builder { return $query->where('status', self::STATUS_PUBLISHED); } public function scopeExpired(Builder $query): Builder { return $query->where('status', self::STATUS_EXPIRED); } /** * Active = published AND not yet expired (expires_at is null or in the future). */ public function scopeActive(Builder $query): Builder { return $query->where('status', self::STATUS_PUBLISHED) ->where(function (Builder $q): void { $q->whereNull('expires_at') ->orWhere('expires_at', '>', now()); }); } }